上传文件至 /
This commit is contained in:
parent
114ccbd02d
commit
aa30677d15
|
@ -0,0 +1,70 @@
|
|||
package com.example.myapplication.Tool;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.os.Handler;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
//测试时使用
|
||||
public class ErrorDisplayUtil {
|
||||
|
||||
// 显示全量错误信息的对话框
|
||||
public static void showErrorDialog(Activity activity, String title, String errorDetail) {
|
||||
activity.runOnUiThread(() -> {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setTitle(title)
|
||||
.setMessage(errorDetail)
|
||||
.setPositiveButton("复制错误", (dialog, which) -> {
|
||||
ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText("错误详情", errorDetail);
|
||||
clipboard.setPrimaryClip(clip);
|
||||
Toast.makeText(activity, "已复制到剪贴板", Toast.LENGTH_SHORT).show();
|
||||
})
|
||||
.setNegativeButton("关闭", null)
|
||||
.show();
|
||||
});
|
||||
}
|
||||
|
||||
// 在界面上固定位置显示错误面板(建议放在登录按钮下方)
|
||||
public static void showErrorPanel(Activity activity, String errorType, String solution) {
|
||||
activity.runOnUiThread(() -> {
|
||||
ViewGroup rootView = activity.findViewById(android.R.id.content);
|
||||
|
||||
// 创建错误面板
|
||||
LinearLayout errorPanel = new LinearLayout(activity);
|
||||
errorPanel.setOrientation(LinearLayout.VERTICAL);
|
||||
errorPanel.setBackgroundColor(0x22FF0000); // 半透明红色背景
|
||||
errorPanel.setPadding(16, 16, 16, 16);
|
||||
|
||||
TextView errorView = new TextView(activity);
|
||||
errorView.setTextColor(Color.RED);
|
||||
errorView.setText("⚠️ 错误类型: " + errorType);
|
||||
|
||||
TextView solutionView = new TextView(activity);
|
||||
solutionView.setTextColor(Color.BLACK);
|
||||
solutionView.setText("💡 解决方案: " + solution);
|
||||
|
||||
Button detailBtn = new Button(activity);
|
||||
detailBtn.setText("查看技术详情");
|
||||
detailBtn.setOnClickListener(v -> showErrorDialog(activity, "技术详情", errorType + "\n\n" + solution));
|
||||
|
||||
errorPanel.addView(errorView);
|
||||
errorPanel.addView(solutionView);
|
||||
errorPanel.addView(detailBtn);
|
||||
|
||||
// 添加到界面底部
|
||||
rootView.addView(errorPanel);
|
||||
|
||||
// 5秒后自动隐藏
|
||||
new Handler().postDelayed(() -> rootView.removeView(errorPanel), 5000);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package com.example.myapplication.Tool;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.GridView;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.example.myapplication.model.ImageInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ImageAdapter extends BaseAdapter {
|
||||
private final Context context;
|
||||
private final List<ImageInfo> imageList;
|
||||
private final SparseBooleanArray selectedItems;
|
||||
|
||||
public ImageAdapter(Context context, List<ImageInfo> imageList) {
|
||||
this.context = context;
|
||||
this.imageList = imageList;
|
||||
this.selectedItems = new SparseBooleanArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return imageList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return imageList.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
ImageView imageView;
|
||||
if (convertView == null) {
|
||||
imageView = new ImageView(context);
|
||||
imageView.setLayoutParams(new GridView.LayoutParams(200, 200));
|
||||
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
|
||||
imageView.setPadding(5, 5, 5, 5);
|
||||
} else {
|
||||
imageView = (ImageView) convertView;
|
||||
}
|
||||
|
||||
ImageInfo imageInfo = imageList.get(position);
|
||||
imageView.setImageBitmap(imageInfo.thumbnail);
|
||||
|
||||
// 设置选中状态
|
||||
if (selectedItems.get(position, false)) {
|
||||
imageView.setBackgroundColor(Color.BLUE);
|
||||
} else {
|
||||
imageView.setBackgroundColor(Color.TRANSPARENT);
|
||||
}
|
||||
|
||||
imageView.setOnClickListener(v -> {
|
||||
if (selectedItems.get(position, false)) {
|
||||
selectedItems.delete(position);
|
||||
imageView.setBackgroundColor(Color.TRANSPARENT);
|
||||
} else {
|
||||
selectedItems.put(position, true);
|
||||
imageView.setBackgroundColor(Color.BLUE);
|
||||
}
|
||||
});
|
||||
|
||||
return imageView;
|
||||
}
|
||||
|
||||
public List<ImageInfo> getSelectedImages() {
|
||||
List<ImageInfo> selected = new ArrayList<>();
|
||||
for (int i = 0; i < imageList.size(); i++) {
|
||||
if (selectedItems.get(i, false)) {
|
||||
selected.add(imageList.get(i));
|
||||
}
|
||||
}
|
||||
return selected;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,282 @@
|
|||
package com.example.myapplication.Tool;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
|
||||
import com.example.myapplication.DataBase.DatabaseHelper;
|
||||
import com.example.myapplication.api.PartService;
|
||||
import com.example.myapplication.model.ApiResponse;
|
||||
import com.example.myapplication.model.PartResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Response;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
|
||||
public class PartListFetcher {
|
||||
private final Context context;
|
||||
private final String token;
|
||||
private final String projectId;
|
||||
|
||||
private final PartService partService;
|
||||
private final DatabaseHelper dbHelper;
|
||||
|
||||
public PartListFetcher(Context context, String token, String projectId) {
|
||||
this.context = context;
|
||||
this.token = token;
|
||||
this.projectId = projectId;
|
||||
|
||||
this.dbHelper = new DatabaseHelper(context);
|
||||
|
||||
// 初始化Retrofit
|
||||
OkHttpClient okHttpClient = new OkHttpClient.Builder()
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.writeTimeout(30, TimeUnit.SECONDS)
|
||||
.build();
|
||||
|
||||
Retrofit retrofit = RetrofitClient.getClient(token);
|
||||
|
||||
this.partService = retrofit.create(PartService.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步获取部件列表
|
||||
* @return 部件列表
|
||||
* @throws IOException 网络异常
|
||||
* @throws ApiException API异常
|
||||
*/
|
||||
public List<PartResponse> fetchPartListSync() throws IOException, ApiException {
|
||||
if (isNetworkAvailable()) {
|
||||
// 有网络时从服务器获取并更新数据库
|
||||
List<PartResponse> serverParts = fetchFromServer();
|
||||
dbHelper.saveParts(serverParts);
|
||||
return serverParts;
|
||||
} else {
|
||||
// 无网络时从数据库获取
|
||||
return dbHelper.getAllParts();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步获取部件列表
|
||||
* @param callback 回调接口
|
||||
*/
|
||||
public void fetchPartListAsync(final PartListCallback callback) {
|
||||
// 先从数据库获取数据快速显示
|
||||
List<PartResponse> cachedParts = dbHelper.getAllParts();
|
||||
if (!cachedParts.isEmpty()) {
|
||||
callback.onSuccess(cachedParts);
|
||||
}
|
||||
|
||||
// 检查网络连接
|
||||
if (isNetworkAvailable()) {
|
||||
// 有网络时从服务器获取并更新数据库
|
||||
fetchFromServerAsync(new PartListCallback() {
|
||||
@Override
|
||||
public void onSuccess(List<PartResponse> partList) {
|
||||
dbHelper.saveParts(partList);
|
||||
callback.onSuccess(partList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
// 服务器获取失败,如果之前有缓存数据则不报错
|
||||
if (cachedParts.isEmpty()) {
|
||||
callback.onFailure(t);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (cachedParts.isEmpty()) {
|
||||
// 无网络且无缓存数据
|
||||
callback.onFailure(new IOException("无网络连接且无缓存数据"));
|
||||
}
|
||||
}
|
||||
public String getPartIdByName(String partName) {
|
||||
// 先从数据库查询
|
||||
String partId = dbHelper.getPartIdByName(partName);
|
||||
if (partId != null) {
|
||||
return partId;
|
||||
}
|
||||
|
||||
// 数据库中没有则尝试从服务器获取
|
||||
if (isNetworkAvailable()) {
|
||||
try {
|
||||
List<PartResponse> parts = fetchFromServer();
|
||||
dbHelper.saveParts(parts);
|
||||
// 再次从数据库查询
|
||||
return dbHelper.getPartIdByName(partName);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
private List<PartResponse> fetchFromServer() throws IOException, ApiException {
|
||||
Call<ApiResponse<List<PartResponse>>> call = partService.getPartList(
|
||||
projectId,
|
||||
|
||||
null, null, null, null
|
||||
|
||||
);
|
||||
|
||||
Response<ApiResponse<List<PartResponse>>> response = call.execute();
|
||||
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
ApiResponse<List<PartResponse>> apiResponse = response.body();
|
||||
if (apiResponse.isSuccess()) {
|
||||
return apiResponse.getData();
|
||||
} else {
|
||||
throw new ApiException(apiResponse.getCode(), apiResponse.getMsg());
|
||||
}
|
||||
} else {
|
||||
throw new IOException("请求失败,状态码: " + response.code());
|
||||
}
|
||||
}
|
||||
private void fetchFromServerAsync(final PartListCallback callback) {
|
||||
Call<ApiResponse<List<PartResponse>>> call = partService.getPartList(
|
||||
projectId,
|
||||
|
||||
null, null, null, null
|
||||
|
||||
);
|
||||
|
||||
call.enqueue(new retrofit2.Callback<ApiResponse<List<PartResponse>>>() {
|
||||
@Override
|
||||
public void onResponse(Call<ApiResponse<List<PartResponse>>> call,
|
||||
Response<ApiResponse<List<PartResponse>>> response) {
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
ApiResponse<List<PartResponse>> apiResponse = response.body();
|
||||
if (apiResponse.isSuccess()) {
|
||||
callback.onSuccess(apiResponse.getData());
|
||||
} else {
|
||||
callback.onFailure(new ApiException(apiResponse.getCode(), apiResponse.getMsg()));
|
||||
}
|
||||
} else {
|
||||
callback.onFailure(new IOException("请求失败,状态码: " + response.code()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<ApiResponse<List<PartResponse>>> call, Throwable t) {
|
||||
callback.onFailure(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isNetworkAvailable() {
|
||||
ConnectivityManager connectivityManager =
|
||||
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
if (connectivityManager != null) {
|
||||
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
|
||||
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* 带筛选条件的异步获取部件列表
|
||||
* @param keyword 关键字
|
||||
* @param manufacturer 厂商
|
||||
* @param model 型号
|
||||
* @param type 类型
|
||||
* @param callback 回调接口
|
||||
*/
|
||||
public void fetchPartListWithFilterAsync(String keyword, String manufacturer,
|
||||
String model, String type,
|
||||
PartListCallback callback) {
|
||||
Call<ApiResponse<List<PartResponse>>> call = partService.getPartList(
|
||||
projectId,
|
||||
|
||||
keyword,
|
||||
manufacturer,
|
||||
model,
|
||||
type
|
||||
);
|
||||
|
||||
call.enqueue(new retrofit2.Callback<ApiResponse<List<PartResponse>>>() {
|
||||
@Override
|
||||
public void onResponse(Call<ApiResponse<List<PartResponse>>> call,
|
||||
Response<ApiResponse<List<PartResponse>>> response) {
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
ApiResponse<List<PartResponse>> apiResponse = response.body();
|
||||
if (apiResponse.isSuccess()) {
|
||||
callback.onSuccess(apiResponse.getData());
|
||||
} else {
|
||||
callback.onFailure(new ApiException(apiResponse.getCode(), apiResponse.getMsg()));
|
||||
}
|
||||
} else {
|
||||
callback.onFailure(new IOException("请求失败,状态码: " + response.code()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<ApiResponse<List<PartResponse>>> call, Throwable t) {
|
||||
callback.onFailure(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public interface PartListCallback {
|
||||
void onSuccess(List<PartResponse> partList);
|
||||
void onFailure(Throwable t);
|
||||
}
|
||||
public String getPartIdByNameSync(String partName) throws IOException, ApiException {
|
||||
List<PartResponse> partList = fetchPartListSync();
|
||||
for (PartResponse part : partList) {
|
||||
if (partName.equals(part.getPartName())) {
|
||||
return part.getPartId();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步根据部件名称获取部件ID
|
||||
* @param partName 要查找的部件名称
|
||||
* @param callback 回调接口
|
||||
*/
|
||||
public void getPartIdByNameAsync(String partName, PartIdCallback callback) {
|
||||
fetchPartListAsync(new PartListCallback() {
|
||||
@Override
|
||||
public void onSuccess(List<PartResponse> partList) {
|
||||
for (PartResponse part : partList) {
|
||||
if (partName.equals(part.getPartName())) {
|
||||
callback.onSuccess(part.getPartId());
|
||||
return;
|
||||
}
|
||||
}
|
||||
callback.onSuccess(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
callback.onFailure(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public interface PartIdCallback {
|
||||
void onSuccess(String partId);
|
||||
void onFailure(Throwable t);
|
||||
}
|
||||
public static class ApiException extends Exception {
|
||||
private final int code;
|
||||
|
||||
public ApiException(int code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package com.example.myapplication.Tool;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
public class PermissionUtils {
|
||||
// 请求码
|
||||
public static final int REQUEST_STORAGE_PERMISSION = 101;
|
||||
public static final int REQUEST_MEDIA_PERMISSION = 102; // Android 13+ 媒体权限
|
||||
|
||||
// 检查并请求所有必要权限
|
||||
public static boolean checkAndRequestPermissions(Activity activity) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
// Android 14+ 需要检查媒体权限(如果要访问媒体文件)
|
||||
return checkMediaPermissions(activity);
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
// Android 10-13 使用 SAF 或 MediaStore,不需要存储权限
|
||||
return true;
|
||||
} else {
|
||||
// Android 9 及以下需要传统存储权限
|
||||
return checkLegacyStoragePermission(activity);
|
||||
}
|
||||
}
|
||||
|
||||
// Android 14+ 媒体权限检查
|
||||
private static boolean checkMediaPermissions(Activity activity) {
|
||||
String[] permissions;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
permissions = new String[]{
|
||||
Manifest.permission.READ_MEDIA_IMAGES,
|
||||
Manifest.permission.READ_MEDIA_VIDEO,
|
||||
Manifest.permission.READ_MEDIA_AUDIO
|
||||
};
|
||||
} else {
|
||||
permissions = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE};
|
||||
}
|
||||
|
||||
boolean allGranted = true;
|
||||
for (String perm : permissions) {
|
||||
if (ContextCompat.checkSelfPermission(activity, perm) != PackageManager.PERMISSION_GRANTED) {
|
||||
allGranted = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!allGranted) {
|
||||
ActivityCompat.requestPermissions(activity, permissions, REQUEST_MEDIA_PERMISSION);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Android 9 及以下传统存储权限
|
||||
private static boolean checkLegacyStoragePermission(Activity activity) {
|
||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(activity,
|
||||
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||
REQUEST_STORAGE_PERMISSION);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 处理权限请求结果
|
||||
public static boolean handlePermissionResult(int requestCode,
|
||||
String[] permissions, int[] grantResults) {
|
||||
if (grantResults.length == 0) return false;
|
||||
|
||||
if (requestCode == REQUEST_STORAGE_PERMISSION ||
|
||||
requestCode == REQUEST_MEDIA_PERMISSION) {
|
||||
for (int result : grantResults) {
|
||||
if (result != PackageManager.PERMISSION_GRANTED) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package com.example.myapplication.Tool;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.chaquo.python.Python;
|
||||
import com.chaquo.python.android.AndroidPlatform;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ReportGeneratorHelper {
|
||||
|
||||
private Context context;
|
||||
|
||||
public ReportGeneratorHelper(Context context) {
|
||||
this.context = context;
|
||||
if (!Python.isStarted()) {
|
||||
Python.start(new AndroidPlatform(context));
|
||||
}
|
||||
}
|
||||
|
||||
public void generateReport(String templateContent, String outputPath,
|
||||
String turbineId, String testDate,
|
||||
List<ImageData> imageDataList,
|
||||
String weather, String temperature, String humidity,
|
||||
String startDate, String endDate,
|
||||
ReportGenerationCallback callback) {
|
||||
try {
|
||||
Python py = Python.getInstance();
|
||||
|
||||
// 转换Java的ImageData列表为Python可接受的格式
|
||||
List<List<Object>> pyImageData = new ArrayList<>();
|
||||
for (ImageData data : imageDataList) {
|
||||
List<Object> item = new ArrayList<>();
|
||||
item.add(data.getImagePath());
|
||||
item.add(data.getResistance());
|
||||
pyImageData.add(item);
|
||||
}
|
||||
|
||||
// 准备配置字典
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.put("template_content", templateContent);
|
||||
config.put("output_path", outputPath);
|
||||
config.put("turbine_id", turbineId);
|
||||
config.put("test_date", testDate);
|
||||
config.put("image_data", pyImageData);
|
||||
config.put("weather", weather);
|
||||
config.put("temperature", temperature);
|
||||
config.put("humidity", humidity);
|
||||
config.put("start_date", startDate);
|
||||
config.put("end_date", endDate);
|
||||
String jsonConfig = new Gson().toJson(config);
|
||||
// 调用Python模块
|
||||
py.getModule("report_generator")
|
||||
.callAttr("generate_report_from_java", jsonConfig);
|
||||
// 成功回调
|
||||
callback.onSuccess(outputPath);
|
||||
|
||||
} catch (Exception e) {
|
||||
callback.onError(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public interface ReportGenerationCallback {
|
||||
void onSuccess(String outputPath);
|
||||
void onError(String errorMessage);
|
||||
}
|
||||
|
||||
public static class ImageData {
|
||||
private String imagePath;
|
||||
private String resistance;
|
||||
|
||||
public ImageData(String imagePath, String resistance) {
|
||||
this.imagePath = imagePath;
|
||||
this.resistance = resistance;
|
||||
}
|
||||
|
||||
public String getImagePath() {
|
||||
return imagePath;
|
||||
}
|
||||
|
||||
public String getResistance() {
|
||||
return resistance;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue