上传文件至 /

This commit is contained in:
XuYuqi 2025-07-11 18:32:05 +08:00
parent 114ccbd02d
commit aa30677d15
5 changed files with 614 additions and 0 deletions

70
ErrorDisplayUtil.java Normal file
View File

@ -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);
});
}
}

87
ImageAdapter.java Normal file
View File

@ -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;
}
}

282
PartListFetcher.java Normal file
View File

@ -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;
}
}
}

86
PermissionUtils.java Normal file
View File

@ -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;
}
}

View File

@ -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;
}
}
}