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

@@ -0,0 +1,78 @@
package com.youlai.boot.device.controller;
import com.youlai.boot.common.annotation.Log;
import com.youlai.boot.common.enums.ActionTypeEnum;
import com.youlai.boot.common.enums.LogModuleEnum;
import com.youlai.boot.common.result.Result;
import com.youlai.boot.device.model.vo.AppIconVO;
import com.youlai.boot.device.service.AppIconService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* 应用图标库控制层
*
* @author TTSTD
* @since 2026-08-05
*/
@Tag(name = "应用图标库")
@RestController
@RequestMapping("/api/v1/app-icons")
@RequiredArgsConstructor
public class AppIconController {
private final AppIconService appIconService;
@Operation(summary = "获取应用当前生效图标信息")
@GetMapping("/{packageName}")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.VIEW)
public Result<AppIconVO> getCurrentIcon(@PathVariable String packageName) {
return Result.success(appIconService.getCurrentIcon(packageName));
}
@Operation(summary = "获取应用图标历史版本列表(含当前,按版本倒序)")
@GetMapping("/{packageName}/history")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.LIST)
public Result<List<AppIconVO>> getHistory(@PathVariable String packageName) {
return Result.success(appIconService.getHistory(packageName));
}
@Operation(summary = "选取历史版本并锁定")
@PostMapping("/{packageName}/lock")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.LOCK_APP_ICON)
public Result<?> lock(
@Parameter(description = "应用包名") @PathVariable String packageName,
@Parameter(description = "选中图标记录ID") @RequestParam Long iconId
) {
return Result.judge(appIconService.lockIcon(packageName, iconId));
}
@Operation(summary = "解锁当前图标")
@PostMapping("/{packageName}/unlock")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.UNLOCK_APP_ICON)
public Result<?> unlock(@Parameter(description = "应用包名") @PathVariable String packageName) {
return Result.judge(appIconService.unlockIcon(packageName));
}
@Operation(summary = "上传应用图标(全局库)")
@PostMapping("/{packageName}/upload")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.UPLOAD_APP_ICON)
public Result<String> upload(
@Parameter(description = "应用包名") @PathVariable String packageName,
@Parameter(description = "图标文件jpg/jpeg/png/webp") @RequestPart(value = "file") MultipartFile file
) {
return Result.success(appIconService.uploadIcon(packageName, file, "admin"));
}
}