feat(device): 重构应用图标功能,新增停止应用操作

- 静态资源路径从 /api/v1/device/app_icon 迁移至 /static/app_icon,避免与 Controller 路径冲突,并添加 immutable 长缓存策略
- 数据库及实体新增 app_name 字段,支持图标上报时同步应用名称
- 图标锁定场景改用 BusinessException(APP_ICON_LOCKED) 明确业务拒绝码,设备端可识别为终态
- 新增 STOP_APP 操作类型及对应推送接口
- 安全配置放行 /static/** 静态资源路径
This commit is contained in:
2026-08-05 16:25:33 +08:00
committed by TongTongStudio
parent 749cf44754
commit 157e708a5b
18 changed files with 864 additions and 26 deletions

View File

@@ -59,6 +59,7 @@ public class MobileController {
private final LocationService locationService;
private final DeveloperService developerService;
private final ApkInstallService apkInstallService;
private final AppIconService appIconService;
private final SystemInfoService systemInfoService;
private final HardwareInfoService hardwareInfoService;
private final NetworkInfoService networkInfoService;
@@ -89,7 +90,7 @@ public class MobileController {
@Operation(summary = "上传设备硬件信息")
@PostMapping("/update_system_info")
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.DEVELOPER)
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.UPDATE_SYSTEM_INFO)
public Result<Void> updateSystemInfo(
@RequestHeader(value = "X-Device-SN") String sn,
@RequestBody SnSystemInfoReq snSystemInfoReq
@@ -136,7 +137,7 @@ public class MobileController {
@Operation(summary = "上传设备其他信息")
@PostMapping("/update_other_info")
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.DEVELOPER)
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.UPDATE_OTHER_INFO)
public Result<Void> updateOtherInfo(
@RequestHeader(value = "X-Device-SN") String sn,
@RequestBody SnOtherInfoReq snOtherInfoReq
@@ -183,7 +184,7 @@ public class MobileController {
@Operation(summary = "上传设备硬件信息")
@PostMapping("/update_hardware_info")
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.DEVELOPER)
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.UPDATE_HARDWARE_INFO)
public Result<Void> updateHardwareInfo(
@RequestHeader(value = "X-Device-SN") String sn,
@RequestBody SnHardwareInfoReq snHardwareInfoReq
@@ -230,7 +231,7 @@ public class MobileController {
@Operation(summary = "上传设备网络信息")
@PostMapping("/update_network_info")
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.DEVELOPER)
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.UPDATE_NETWORK_INFO)
public Result<Void> updateNetworkInfo(
@RequestHeader(value = "X-Device-SN") String sn,
@RequestBody SnNetworkInfoReq snNetworkInfoReq
@@ -277,7 +278,7 @@ public class MobileController {
@Operation(summary = "上传设备安全信息")
@PostMapping("/update_security_info")
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.DEVELOPER)
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.UPDATE_SECURITY_INFO)
public Result<Void> updateSecurityInfo(
@RequestHeader(value = "X-Device-SN") String sn,
@RequestBody SnSecurityInfoReq snSecurityInfoReq
@@ -432,7 +433,7 @@ public class MobileController {
@Operation(summary = "获取开发者选项开关")
@GetMapping("/get_developer_options")
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.DEVELOPER)
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.VIEW_DEVELOPER_OPTIONS)
public Result<DeveloperOptionsVO> getDeveloperOptions(@RequestHeader(value = "X-Device-SN") String sn) {
try {
if (sn == null || sn.trim().isEmpty()) {
@@ -453,7 +454,7 @@ public class MobileController {
@Operation(summary = "上传设备已安装应用列表")
@PostMapping("/upload_install_apks")
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.DEVELOPER)
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.UPLOAD_APK_LIST)
public Result<Void> uploadInstallApks(
@RequestHeader(value = "X-Device-SN") String sn,
@RequestBody List<ApkInstallInfoReq> apkInfos
@@ -482,23 +483,26 @@ public class MobileController {
}
}
@Operation(summary = "获取设备已安装应用列表")
@GetMapping("/get_install_apks")
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.DEVELOPER)
public Result<List<ApkInstallInfoReq>> getInstallApks(@RequestHeader(value = "X-Device-SN") String sn) {
@Operation(summary = "上传应用图标")
@PostMapping("/upload_app_icon")
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.UPLOAD_APP_ICON)
public Result<String> uploadAppIcon(
@RequestHeader(value = "X-Device-SN") String sn,
@RequestParam String packageName,
@RequestPart(value = "file") MultipartFile file
) {
try {
if (sn == null || sn.trim().isEmpty()) {
return Result.failed("设备序列号不能为空");
}
List<ApkInstallInfoReq> apkInfos = apkInstallService.getDeviceApkInfo(sn);
logger.info("获取应用列表成功, sn: {}, count: {}", sn, apkInfos.size());
return Result.success(apkInfos);
if (packageName == null || packageName.trim().isEmpty()) {
return Result.failed("应用包名不能为空");
}
String iconUrl = appIconService.uploadIcon(packageName, file, "device");
return Result.success(iconUrl);
} catch (Exception e) {
logger.error("getInstallApks error, sn: {}", sn, e);
return Result.failed("获取应用列表失败: " + e.getMessage());
logger.error("uploadAppIcon error, sn: {}", sn, e);
return Result.failed("上传应用图标失败: " + e.getMessage());
}
}
}