Commit ecf6a4a8463d416dc5a6b8b1d143458f4b98dd89

Authored by YunaiV
1 parent 4749d93d

feat:【IoT 物联网】增加 OTA 升级任务的实现

Showing 23 changed files with 277 additions and 448 deletions
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskRecordController.java
@@ -9,12 +9,16 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO; @@ -9,12 +9,16 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO;
9 import cn.iocoder.yudao.module.iot.service.ota.IotOtaTaskRecordService; 9 import cn.iocoder.yudao.module.iot.service.ota.IotOtaTaskRecordService;
10 import io.swagger.v3.oas.annotations.Operation; 10 import io.swagger.v3.oas.annotations.Operation;
11 import io.swagger.v3.oas.annotations.Parameter; 11 import io.swagger.v3.oas.annotations.Parameter;
  12 +import io.swagger.v3.oas.annotations.Parameters;
12 import io.swagger.v3.oas.annotations.tags.Tag; 13 import io.swagger.v3.oas.annotations.tags.Tag;
13 import jakarta.annotation.Resource; 14 import jakarta.annotation.Resource;
14 import jakarta.validation.Valid; 15 import jakarta.validation.Valid;
15 import org.springframework.security.access.prepost.PreAuthorize; 16 import org.springframework.security.access.prepost.PreAuthorize;
16 import org.springframework.validation.annotation.Validated; 17 import org.springframework.validation.annotation.Validated;
17 -import org.springframework.web.bind.annotation.*; 18 +import org.springframework.web.bind.annotation.GetMapping;
  19 +import org.springframework.web.bind.annotation.RequestMapping;
  20 +import org.springframework.web.bind.annotation.RequestParam;
  21 +import org.springframework.web.bind.annotation.RestController;
18 22
19 import java.util.Map; 23 import java.util.Map;
20 24
@@ -22,31 +26,29 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -22,31 +26,29 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
22 26
23 @Tag(name = "管理后台 - IoT OTA 升级任务记录") 27 @Tag(name = "管理后台 - IoT OTA 升级任务记录")
24 @RestController 28 @RestController
25 -@RequestMapping("/iot/ota/task-record") 29 +@RequestMapping("/iot/ota/task/record")
26 @Validated 30 @Validated
27 public class IotOtaTaskRecordController { 31 public class IotOtaTaskRecordController {
28 32
29 @Resource 33 @Resource
30 private IotOtaTaskRecordService otaTaskRecordService; 34 private IotOtaTaskRecordService otaTaskRecordService;
31 35
32 - @GetMapping("/get-statistics")  
33 - @Operation(summary = "固件升级设备统计") 36 + @GetMapping("/get-status-count")
  37 + @Operation(summary = "获得 OTA 升级记录状态统计")
  38 + @Parameters({
  39 + @Parameter(name = "firmwareId", description = "固件编号", example = "1024"),
  40 + @Parameter(name = "taskId", description = "升级任务编号", example = "2048")
  41 + })
34 @PreAuthorize("@ss.hasPermission('iot:ota-task-record:query')") 42 @PreAuthorize("@ss.hasPermission('iot:ota-task-record:query')")
35 - @Parameter(name = "firmwareId", description = "固件编号", required = true, example = "1024")  
36 - public CommonResult<Map<Integer, Long>> getOtaTaskRecordStatistics(@RequestParam(value = "firmwareId") Long firmwareId) {  
37 - return success(otaTaskRecordService.getOtaTaskRecordStatistics(firmwareId));  
38 - }  
39 -  
40 - @GetMapping("/get-count")  
41 - @Operation(summary = "获得升级记录分页 tab 数量")  
42 - @PreAuthorize("@ss.hasPermission('iot:ota-task-record:query')")  
43 - public CommonResult<Map<Integer, Long>> getOtaTaskRecordCount(@Valid IotOtaTaskRecordPageReqVO pageReqVO) {  
44 - return success(otaTaskRecordService.getOtaTaskRecordCount(pageReqVO)); 43 + public CommonResult<Map<Integer, Long>> getOtaTaskRecordStatusCountMap(
  44 + @RequestParam(value = "firmwareId", required = false) Long firmwareId,
  45 + @RequestParam(value = "taskId", required = false) Long taskId) {
  46 + return success(otaTaskRecordService.getOtaTaskRecordStatusCountMap(firmwareId, taskId));
45 } 47 }
46 48
47 @GetMapping("/page") 49 @GetMapping("/page")
48 - @Operation(summary = "获得升级记录分页")  
49 - @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") 50 + @Operation(summary = "获得 OTA 升级记录分页")
  51 + @PreAuthorize("@ss.hasPermission('iot:ota-task-record:query')")
50 public CommonResult<PageResult<IotOtaTaskRecordRespVO>> getOtaTaskRecordPage( 52 public CommonResult<PageResult<IotOtaTaskRecordRespVO>> getOtaTaskRecordPage(
51 @Valid IotOtaTaskRecordPageReqVO pageReqVO) { 53 @Valid IotOtaTaskRecordPageReqVO pageReqVO) {
52 PageResult<IotOtaTaskRecordDO> pageResult = otaTaskRecordService.getOtaTaskRecordPage(pageReqVO); 54 PageResult<IotOtaTaskRecordDO> pageResult = otaTaskRecordService.getOtaTaskRecordPage(pageReqVO);
@@ -54,8 +56,8 @@ public class IotOtaTaskRecordController { @@ -54,8 +56,8 @@ public class IotOtaTaskRecordController {
54 } 56 }
55 57
56 @GetMapping("/get") 58 @GetMapping("/get")
57 - @Operation(summary = "获得升级记录")  
58 - @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") 59 + @Operation(summary = "获得 OTA 升级记录")
  60 + @PreAuthorize("@ss.hasPermission('iot:ota-task-record:query')")
59 @Parameter(name = "id", description = "升级记录编号", required = true, example = "1024") 61 @Parameter(name = "id", description = "升级记录编号", required = true, example = "1024")
60 public CommonResult<IotOtaTaskRecordRespVO> getOtaTaskRecord(@RequestParam("id") Long id) { 62 public CommonResult<IotOtaTaskRecordRespVO> getOtaTaskRecord(@RequestParam("id") Long id) {
61 IotOtaTaskRecordDO upgradeRecord = otaTaskRecordService.getOtaTaskRecord(id); 63 IotOtaTaskRecordDO upgradeRecord = otaTaskRecordService.getOtaTaskRecord(id);
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/IotOtaTaskCreateReqVO.java
@@ -32,4 +32,6 @@ public class IotOtaTaskCreateReqVO { @@ -32,4 +32,6 @@ public class IotOtaTaskCreateReqVO {
32 @Schema(description = "选中的设备编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3") 32 @Schema(description = "选中的设备编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3")
33 private List<Long> deviceIds; 33 private List<Long> deviceIds;
34 34
  35 + // TODO @li:如果 deviceScope 等于 2 时,deviceIds 校验非空;
  36 +
35 } 37 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordPageReqVO.java
@@ -2,19 +2,16 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record; @@ -2,19 +2,16 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageParam; 3 import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 import io.swagger.v3.oas.annotations.media.Schema; 4 import io.swagger.v3.oas.annotations.media.Schema;
5 -import jakarta.validation.constraints.NotNull;  
6 import lombok.Data; 5 import lombok.Data;
7 6
8 @Schema(description = "管理后台 - IoT OTA 升级记录分页 Request VO") 7 @Schema(description = "管理后台 - IoT OTA 升级记录分页 Request VO")
9 @Data 8 @Data
10 public class IotOtaTaskRecordPageReqVO extends PageParam { 9 public class IotOtaTaskRecordPageReqVO extends PageParam {
11 10
12 - // TODO @芋艿:分页条件字段梳理;  
13 - @Schema(description = "升级任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")  
14 - @NotNull(message = "升级任务编号不能为空") 11 + @Schema(description = "升级任务编号", example = "1024")
15 private Long taskId; 12 private Long taskId;
16 13
17 - @Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "摄像头A1-1") 14 + @Schema(description = "设备标识", example = "摄像头A1-1")
18 private String deviceName; 15 private String deviceName;
19 16
20 } 17 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordRespVO.java
@@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record; @@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record;
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 4 import lombok.Data;
5 5
6 -import java.time.LocalDateTime;  
7 -  
8 @Schema(description = "管理后台 - IoT OTA 升级记录 Response VO") 6 @Schema(description = "管理后台 - IoT OTA 升级记录 Response VO")
9 @Data 7 @Data
10 public class IotOtaTaskRecordRespVO { 8 public class IotOtaTaskRecordRespVO {
@@ -23,12 +21,6 @@ public class IotOtaTaskRecordRespVO { @@ -23,12 +21,6 @@ public class IotOtaTaskRecordRespVO {
23 @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") 21 @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
24 private Long taskId; 22 private Long taskId;
25 23
26 - @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "iot")  
27 - private String productKey;  
28 -  
29 - @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "iot")  
30 - private String deviceName;  
31 -  
32 @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") 24 @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
33 private String deviceId; 25 private String deviceId;
34 26
@@ -47,10 +39,4 @@ public class IotOtaTaskRecordRespVO { @@ -47,10 +39,4 @@ public class IotOtaTaskRecordRespVO {
47 @Schema(description = "升级进度描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") 39 @Schema(description = "升级进度描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
48 private String description; 40 private String description;
49 41
50 - @Schema(description = "升级开始时间", requiredMode = Schema.RequiredMode.REQUIRED)  
51 - private LocalDateTime startTime;  
52 -  
53 - @Schema(description = "升级结束时间", requiredMode = Schema.RequiredMode.REQUIRED)  
54 - private LocalDateTime endTime;  
55 -  
56 } 42 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java
@@ -117,7 +117,7 @@ public class IotDeviceDO extends TenantBaseDO { @@ -117,7 +117,7 @@ public class IotDeviceDO extends TenantBaseDO {
117 * 117 *
118 * 关联 {@link IotOtaFirmwareDO#getId()} 118 * 关联 {@link IotOtaFirmwareDO#getId()}
119 */ 119 */
120 - private String firmwareId; 120 + private Long firmwareId;
121 121
122 /** 122 /**
123 * 设备密钥,用于设备认证 123 * 设备密钥,用于设备认证
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaTaskDO.java
@@ -61,7 +61,7 @@ public class IotOtaTaskDO extends BaseDO { @@ -61,7 +61,7 @@ public class IotOtaTaskDO extends BaseDO {
61 /** 61 /**
62 * 设备总数数量 62 * 设备总数数量
63 */ 63 */
64 - private Long deviceTotalCount; 64 + private Integer deviceTotalCount;
65 /** 65 /**
66 * 设备成功数量 66 * 设备成功数量
67 */ 67 */
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaTaskRecordDO.java
@@ -7,9 +7,10 @@ import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskRecordStatusEnum; @@ -7,9 +7,10 @@ import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskRecordStatusEnum;
7 import com.baomidou.mybatisplus.annotation.KeySequence; 7 import com.baomidou.mybatisplus.annotation.KeySequence;
8 import com.baomidou.mybatisplus.annotation.TableId; 8 import com.baomidou.mybatisplus.annotation.TableId;
9 import com.baomidou.mybatisplus.annotation.TableName; 9 import com.baomidou.mybatisplus.annotation.TableName;
10 -import lombok.*;  
11 -  
12 -import java.time.LocalDateTime; 10 +import lombok.AllArgsConstructor;
  11 +import lombok.Builder;
  12 +import lombok.Data;
  13 +import lombok.NoArgsConstructor;
13 14
14 /** 15 /**
15 * IoT OTA 升级任务记录 DO 16 * IoT OTA 升级任务记录 DO
@@ -70,13 +71,5 @@ public class IotOtaTaskRecordDO extends BaseDO { @@ -70,13 +71,5 @@ public class IotOtaTaskRecordDO extends BaseDO {
70 * 如果想看历史记录,可以查看 {@link IotDeviceMessageDO} 设备日志 71 * 如果想看历史记录,可以查看 {@link IotDeviceMessageDO} 设备日志
71 */ 72 */
72 private String description; 73 private String description;
73 - /**  
74 - * 升级开始时间  
75 - */  
76 - private LocalDateTime startTime;  
77 - /**  
78 - * 升级结束时间  
79 - */  
80 - private LocalDateTime endTime;  
81 74
82 } 75 }
83 \ No newline at end of file 76 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java
@@ -7,20 +7,11 @@ import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwa @@ -7,20 +7,11 @@ import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwa
7 import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; 7 import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO;
8 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
9 9
10 -import java.util.List;  
11 -  
12 @Mapper 10 @Mapper
13 public interface IotOtaFirmwareMapper extends BaseMapperX<IotOtaFirmwareDO> { 11 public interface IotOtaFirmwareMapper extends BaseMapperX<IotOtaFirmwareDO> {
14 12
15 - /**  
16 - * 根据产品ID和固件版本号查询固件信息列表。  
17 - *  
18 - * @param productId 产品ID,用于筛选固件信息。  
19 - * @param version 固件版本号,用于筛选固件信息。  
20 - * @return 返回符合条件的固件信息列表。  
21 - */  
22 - default List<IotOtaFirmwareDO> selectByProductIdAndVersion(Long productId, String version) {  
23 - return selectList(IotOtaFirmwareDO::getProductId, productId, 13 + default IotOtaFirmwareDO selectByProductIdAndVersion(Long productId, String version) {
  14 + return selectOne(IotOtaFirmwareDO::getProductId, productId,
24 IotOtaFirmwareDO::getVersion, version); 15 IotOtaFirmwareDO::getVersion, version);
25 } 16 }
26 17
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaTaskMapper.java
@@ -7,20 +7,12 @@ import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskPageRe @@ -7,20 +7,12 @@ import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskPageRe
7 import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO; 7 import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO;
8 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
9 9
10 -import java.util.List;  
11 -  
12 -/**  
13 - * OTA 升级任务 Mapper  
14 - *  
15 - * @author Shelly  
16 - */  
17 @Mapper 10 @Mapper
18 public interface IotOtaTaskMapper extends BaseMapperX<IotOtaTaskDO> { 11 public interface IotOtaTaskMapper extends BaseMapperX<IotOtaTaskDO> {
19 12
20 - default List<IotOtaTaskDO> selectByFirmwareIdAndName(Long firmwareId, String name) {  
21 - return selectList(new LambdaQueryWrapperX<IotOtaTaskDO>()  
22 - .eqIfPresent(IotOtaTaskDO::getFirmwareId, firmwareId)  
23 - .eqIfPresent(IotOtaTaskDO::getName, name)); 13 + default IotOtaTaskDO selectByFirmwareIdAndName(Long firmwareId, String name) {
  14 + return selectOne(IotOtaTaskDO::getFirmwareId, firmwareId,
  15 + IotOtaTaskDO::getName, name);
24 } 16 }
25 17
26 default PageResult<IotOtaTaskDO> selectUpgradeTaskPage(IotOtaTaskPageReqVO pageReqVO) { 18 default PageResult<IotOtaTaskDO> selectUpgradeTaskPage(IotOtaTaskPageReqVO pageReqVO) {
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaTaskRecordMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.dal.mysql.ota;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordPageReqVO;
  7 +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO;
  8 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +
  11 +import java.util.List;
  12 +import java.util.Set;
  13 +
  14 +@Mapper
  15 +public interface IotOtaTaskRecordMapper extends BaseMapperX<IotOtaTaskRecordDO> {
  16 +
  17 + default List<IotOtaTaskRecordDO> selectListByFirmwareIdAndTaskId(Long firmwareId, Long taskId) {
  18 + return selectList(new LambdaQueryWrapperX<IotOtaTaskRecordDO>()
  19 + .eqIfPresent(IotOtaTaskRecordDO::getFirmwareId, firmwareId)
  20 + .eqIfPresent(IotOtaTaskRecordDO::getTaskId, taskId)
  21 + .select(IotOtaTaskRecordDO::getDeviceId, IotOtaTaskRecordDO::getStatus));
  22 + }
  23 +
  24 + default PageResult<IotOtaTaskRecordDO> selectPage(IotOtaTaskRecordPageReqVO pageReqVO) {
  25 + return selectPage(pageReqVO, new LambdaQueryWrapperX<IotOtaTaskRecordDO>()
  26 + .eqIfPresent(IotOtaTaskRecordDO::getTaskId, pageReqVO.getTaskId()));
  27 + }
  28 +
  29 + default void updateByTaskIdAndStatus(Long taskId, Integer fromStatus, IotOtaTaskRecordDO updateRecord) {
  30 + update(updateRecord, new LambdaUpdateWrapper<IotOtaTaskRecordDO>()
  31 + .eq(IotOtaTaskRecordDO::getTaskId, taskId)
  32 + .eq(IotOtaTaskRecordDO::getStatus, fromStatus));
  33 + }
  34 +
  35 + default List<IotOtaTaskRecordDO> selectListByDeviceIdAndStatus(Set<Long> deviceIds, Set<Integer> statuses) {
  36 + return selectList(new LambdaQueryWrapperX<IotOtaTaskRecordDO>()
  37 + .inIfPresent(IotOtaTaskRecordDO::getDeviceId, deviceIds)
  38 + .inIfPresent(IotOtaTaskRecordDO::getStatus, statuses));
  39 + }
  40 +
  41 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java deleted
1 -package cn.iocoder.yudao.module.iot.dal.mysql.ota;  
2 -  
3 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
4 -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;  
5 -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;  
6 -import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordPageReqVO;  
7 -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO;  
8 -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;  
9 -import org.apache.ibatis.annotations.Mapper;  
10 -import org.apache.ibatis.annotations.Param;  
11 -import org.apache.ibatis.annotations.Select;  
12 -  
13 -import java.util.List;  
14 -import java.util.Map;  
15 -  
16 -@Mapper  
17 -public interface IotOtaUpgradeRecordMapper extends BaseMapperX<IotOtaTaskRecordDO> {  
18 -  
19 - // TODO @li:selectByFirmwareIdAndTaskIdAndDeviceId;让方法自解释  
20 - /**  
21 - * 根据条件查询单个OTA升级记录  
22 - *  
23 - * @param firmwareId 固件ID,可选参数,用于筛选固件ID匹配的记录  
24 - * @param taskId 任务ID,可选参数,用于筛选任务ID匹配的记录  
25 - * @param deviceId 设备ID,可选参数,用于筛选设备ID匹配的记录  
26 - * @return 返回符合条件的单个OTA升级记录,如果不存在则返回null  
27 - */  
28 - default IotOtaTaskRecordDO selectByConditions(Long firmwareId, Long taskId, String deviceId) {  
29 - // 使用LambdaQueryWrapperX构建查询条件,根据传入的参数动态添加查询条件  
30 - return selectOne(new LambdaQueryWrapperX<IotOtaTaskRecordDO>()  
31 - .eqIfPresent(IotOtaTaskRecordDO::getFirmwareId, firmwareId)  
32 - .eqIfPresent(IotOtaTaskRecordDO::getTaskId, taskId)  
33 - .eqIfPresent(IotOtaTaskRecordDO::getDeviceId, deviceId));  
34 - }  
35 -  
36 - // TODO @li:这个是不是 groupby status 就 ok 拉?  
37 - /**  
38 - * 根据任务ID和设备名称查询OTA升级记录的状态统计信息。  
39 - * 该函数通过SQL查询统计不同状态(0到5)的记录数量,并返回一个包含统计结果的Map列表。  
40 - *  
41 - * @param taskId 任务ID,用于筛选特定任务的OTA升级记录。  
42 - * @param deviceName 设备名称,支持模糊查询,用于筛选特定设备的OTA升级记录。  
43 - * @return 返回一个Map列表,每个Map包含不同状态(0到5)的记录数量。  
44 - */  
45 - @Select("select count(case when status = 0 then 1 else 0) as `0` " +  
46 - "count(case when status = 1 then 1 else 0) as `1` " +  
47 - "count(case when status = 2 then 1 else 0) as `2` " +  
48 - "count(case when status = 3 then 1 else 0) as `3` " +  
49 - "count(case when status = 4 then 1 else 0) as `4` " +  
50 - "count(case when status = 5 then 1 else 0) as `5` " +  
51 - "from iot_ota_upgrade_record " +  
52 - "where task_id = #{taskId} " +  
53 - "and device_name like concat('%', #{deviceName}, '%') " +  
54 - "and status = #{status}")  
55 - List<Map<String, Object>> selectOtaUpgradeRecordCount(@Param("taskId") Long taskId,  
56 - @Param("deviceName") String deviceName);  
57 -  
58 - /**  
59 - * 根据固件ID查询OTA升级记录的状态统计信息。  
60 - * 该函数通过SQL查询统计不同状态(0到5)的记录数量,并返回一个包含统计结果的Map列表。  
61 - *  
62 - * @param firmwareId 固件ID,用于筛选特定固件的OTA升级记录。  
63 - * @return 返回一个Map列表,每个Map包含不同状态(0到5)的记录数量。  
64 - */  
65 - @Select("select count(case when status = 0 then 1 else 0) as `0` " +  
66 - "count(case when status = 1 then 1 else 0) as `1` " +  
67 - "count(case when status = 2 then 1 else 0) as `2` " +  
68 - "count(case when status = 3 then 1 else 0) as `3` " +  
69 - "count(case when status = 4 then 1 else 0) as `4` " +  
70 - "count(case when status = 5 then 1 else 0) as `5` " +  
71 - "from iot_ota_upgrade_record " +  
72 - "where firmware_id = #{firmwareId}")  
73 - List<Map<String, Object>> selectOtaUpgradeRecordStatistics(Long firmwareId);  
74 -  
75 - // TODO @li:这里的注释,可以去掉哈  
76 - /**  
77 - * 根据分页查询条件获取 OTA升级记录的分页结果  
78 - *  
79 - * @param pageReqVO 分页查询请求参数,包含设备名称、任务ID等查询条件  
80 - * @return 返回分页查询结果,包含符合条件的 OTA升级记录列表  
81 - */  
82 - // TODO @li:selectPage 就 ok 拉。  
83 - default PageResult<IotOtaTaskRecordDO> selectUpgradeRecordPage(IotOtaTaskRecordPageReqVO pageReqVO) {  
84 - // TODO @li:这里的注释,可以去掉哈;然后下面的“如果”。。。也没必要注释  
85 - // 使用LambdaQueryWrapperX构建查询条件,并根据请求参数动态添加查询条件  
86 - return selectPage(pageReqVO, new LambdaQueryWrapperX<IotOtaTaskRecordDO>()  
87 -// .likeIfPresent(IotOtaTaskRecordDO::getDeviceName, pageReqVO.getDeviceName()) // 如果设备名称存在,则添加模糊查询条件  
88 - .eqIfPresent(IotOtaTaskRecordDO::getTaskId, pageReqVO.getTaskId())); // 如果任务ID存在,则添加等值查询条件  
89 - }  
90 -  
91 - // TODO @li:这里的注释,可以去掉哈  
92 - /**  
93 - * 根据任务ID和状态更新升级记录的状态  
94 - * <p>  
95 - * 该函数用于将符合指定任务ID和状态的升级记录的状态更新为新的状态。  
96 - *  
97 - * @param setStatus 要设置的新状态值,类型为Integer  
98 - * @param taskId 要更新的升级记录对应的任务ID,类型为Long  
99 - * @param whereStatus 用于筛选升级记录的当前状态值,类型为Integer  
100 - */  
101 - // TODO @li:改成 updateByTaskIdAndStatus(taskId, status, IotOtaUpgradeRecordDO) 更通用一些。  
102 - default void updateUpgradeRecordStatusByTaskIdAndStatus(Integer setStatus, Long taskId, Integer whereStatus) {  
103 - // 使用LambdaUpdateWrapper构建更新条件,将指定状态的记录更新为指定状态  
104 - update(new LambdaUpdateWrapper<IotOtaTaskRecordDO>()  
105 - .set(IotOtaTaskRecordDO::getStatus, setStatus)  
106 - .eq(IotOtaTaskRecordDO::getTaskId, taskId)  
107 - .eq(IotOtaTaskRecordDO::getStatus, whereStatus)  
108 - );  
109 - }  
110 -  
111 -}  
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java
@@ -16,4 +16,7 @@ public class DictTypeConstants { @@ -16,4 +16,7 @@ public class DictTypeConstants {
16 16
17 public static final String ALERT_LEVEL = "iot_alert_level"; 17 public static final String ALERT_LEVEL = "iot_alert_level";
18 18
  19 + public static final String OTA_TASK_DEVICE_SCOPE = "iot_ota_task_device_scope";
  20 + public static final String OTA_TASK_STATUS = "iot_ota_task_status";
  21 +
19 } 22 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
@@ -41,20 +41,25 @@ public interface ErrorCodeConstants { @@ -41,20 +41,25 @@ public interface ErrorCodeConstants {
41 ErrorCode DEVICE_GROUP_NOT_EXISTS = new ErrorCode(1_050_005_000, "设备分组不存在"); 41 ErrorCode DEVICE_GROUP_NOT_EXISTS = new ErrorCode(1_050_005_000, "设备分组不存在");
42 ErrorCode DEVICE_GROUP_DELETE_FAIL_DEVICE_EXISTS = new ErrorCode(1_050_005_001, "设备分组下存在设备,不允许删除"); 42 ErrorCode DEVICE_GROUP_DELETE_FAIL_DEVICE_EXISTS = new ErrorCode(1_050_005_001, "设备分组下存在设备,不允许删除");
43 43
44 - // ========== 固件相关 1-050-008-000 ========== 44 + // ========== OTA 固件相关 1-050-008-000 ==========
45 45
46 ErrorCode OTA_FIRMWARE_NOT_EXISTS = new ErrorCode(1_050_008_000, "固件信息不存在"); 46 ErrorCode OTA_FIRMWARE_NOT_EXISTS = new ErrorCode(1_050_008_000, "固件信息不存在");
47 ErrorCode OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE = new ErrorCode(1_050_008_001, "产品版本号重复"); 47 ErrorCode OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE = new ErrorCode(1_050_008_001, "产品版本号重复");
48 48
49 - ErrorCode OTA_UPGRADE_TASK_NOT_EXISTS = new ErrorCode(1_050_008_100, "升级任务不存在");  
50 - ErrorCode OTA_UPGRADE_TASK_NAME_DUPLICATE = new ErrorCode(1_050_008_101, "升级任务名称重复");  
51 - ErrorCode OTA_UPGRADE_TASK_DEVICE_IDS_EMPTY = new ErrorCode(1_050_008_102, "设备编号列表不能为空");  
52 - ErrorCode OTA_UPGRADE_TASK_DEVICE_LIST_EMPTY = new ErrorCode(1_050_008_103, "设备列表不能为空");  
53 - ErrorCode OTA_UPGRADE_TASK_CANNOT_CANCEL = new ErrorCode(1_050_008_104, "升级任务不能取消"); 49 + // ========== OTA 升级任务相关 1-050-008-100 ==========
54 50
55 - ErrorCode OTA_UPGRADE_RECORD_NOT_EXISTS = new ErrorCode(1_050_008_200, "升级记录不存在");  
56 - ErrorCode OTA_UPGRADE_RECORD_DUPLICATE = new ErrorCode(1_050_008_201, "升级记录重复");  
57 - ErrorCode OTA_UPGRADE_RECORD_CANNOT_RETRY = new ErrorCode(1_050_008_202, "升级记录不能重试"); 51 + ErrorCode OTA_TASK_NOT_EXISTS = new ErrorCode(1_050_008_100, "升级任务不存在");
  52 + ErrorCode OTA_TASK_CREATE_FAIL_NAME_DUPLICATE = new ErrorCode(1_050_008_101, "创建 OTA 任务失败,原因:任务名称重复");
  53 + ErrorCode OTA_TASK_CREATE_FAIL_DEVICE_FIRMWARE_EXISTS = new ErrorCode(1_050_008_102,
  54 + "创建 OTA 任务失败,原因:设备({})已经是该固件版本");
  55 + ErrorCode OTA_TASK_CREATE_FAIL_DEVICE_OTA_IN_PROCESS = new ErrorCode(1_050_008_102,
  56 + "创建 OTA 任务失败,原因:设备({})已经在升级中...");
  57 + ErrorCode OTA_TASK_CREATE_FAIL_DEVICE_EMPTY = new ErrorCode(1_050_008_103, "创建 OTA 任务失败,原因:没有可升级的设备");
  58 + ErrorCode OTA_TASK_CANCEL_FAIL_STATUS_END = new ErrorCode(1_050_008_104, "取消 OTA 任务失败,原因:任务状态不是进行中");
  59 +
  60 + // ========== OTA 升级任务相关 1-050-008-100 ==========
  61 +
  62 + ErrorCode OTA_TASK_RECORD_NOT_EXISTS = new ErrorCode(1_050_008_200, "升级记录不存在");
58 63
59 // ========== IoT 数据流转规则 1-050-010-000 ========== 64 // ========== IoT 数据流转规则 1-050-010-000 ==========
60 ErrorCode DATA_RULE_NOT_EXISTS = new ErrorCode(1_050_010_000, "数据流转规则不存在"); 65 ErrorCode DATA_RULE_NOT_EXISTS = new ErrorCode(1_050_010_000, "数据流转规则不存在");
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaTaskRecordStatusEnum.java
@@ -2,10 +2,13 @@ package cn.iocoder.yudao.module.iot.enums.ota; @@ -2,10 +2,13 @@ package cn.iocoder.yudao.module.iot.enums.ota;
2 2
3 3
4 import cn.iocoder.yudao.framework.common.core.ArrayValuable; 4 import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  5 +import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
5 import lombok.Getter; 6 import lombok.Getter;
6 import lombok.RequiredArgsConstructor; 7 import lombok.RequiredArgsConstructor;
7 8
8 import java.util.Arrays; 9 import java.util.Arrays;
  10 +import java.util.List;
  11 +import java.util.Set;
9 12
10 /** 13 /**
11 * IoT OTA 升级任务记录的状态枚举 14 * IoT OTA 升级任务记录的状态枚举
@@ -26,6 +29,17 @@ public enum IotOtaTaskRecordStatusEnum implements ArrayValuable&lt;Integer&gt; { @@ -26,6 +29,17 @@ public enum IotOtaTaskRecordStatusEnum implements ArrayValuable&lt;Integer&gt; {
26 public static final Integer[] ARRAYS = Arrays.stream(values()) 29 public static final Integer[] ARRAYS = Arrays.stream(values())
27 .map(IotOtaTaskRecordStatusEnum::getStatus).toArray(Integer[]::new); 30 .map(IotOtaTaskRecordStatusEnum::getStatus).toArray(Integer[]::new);
28 31
  32 + public static final Set<Integer> IN_PROCESS_STATUSES = SetUtils.asSet(
  33 + PENDING.getStatus(),
  34 + PUSHED.getStatus(),
  35 + UPGRADING.getStatus(),
  36 + SUCCESS.getStatus());
  37 +
  38 + public static final List<Integer> PRIORITY_STATUSES = Arrays.asList(
  39 + SUCCESS.getStatus(),
  40 + PENDING.getStatus(), PUSHED.getStatus(), UPGRADING.getStatus(),
  41 + FAILURE.getStatus(), CANCELED.getStatus());
  42 +
29 /** 43 /**
30 * 状态 44 * 状态
31 */ 45 */
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java
@@ -12,7 +12,6 @@ import java.time.LocalDateTime; @@ -12,7 +12,6 @@ import java.time.LocalDateTime;
12 import java.util.Collection; 12 import java.util.Collection;
13 import java.util.List; 13 import java.util.List;
14 import java.util.Map; 14 import java.util.Map;
15 -import java.util.Set;  
16 15
17 /** 16 /**
18 * IoT 设备 Service 接口 17 * IoT 设备 Service 接口
@@ -155,22 +154,14 @@ public interface IotDeviceService { @@ -155,22 +154,14 @@ public interface IotDeviceService {
155 List<IotDeviceDO> getDeviceListByState(Integer state); 154 List<IotDeviceDO> getDeviceListByState(Integer state);
156 155
157 /** 156 /**
158 - * 根据产品ID获取设备列表 157 + * 根据产品编号,获取设备列表
159 * 158 *
160 - * @param productId 产品ID,用于查询特定产品的设备列表  
161 - * @return 返回与指定产品ID关联的设备列表,列表中的每个元素为IotDeviceDO对象 159 + * @param productId 产品编号
  160 + * @return 设备列表
162 */ 161 */
163 List<IotDeviceDO> getDeviceListByProductId(Long productId); 162 List<IotDeviceDO> getDeviceListByProductId(Long productId);
164 163
165 /** 164 /**
166 - * 根据设备ID列表获取设备信息列表  
167 - *  
168 - * @param deviceIdList 设备ID列表,包含需要查询的设备ID  
169 - * @return 返回与设备ID列表对应的设备信息列表,列表中的每个元素为IotDeviceDO对象  
170 - */  
171 - List<IotDeviceDO> getDeviceListByIdList(List<Long> deviceIdList);  
172 -  
173 - /**  
174 * 基于产品编号,获得设备数量 165 * 基于产品编号,获得设备数量
175 * 166 *
176 * @param productId 产品编号 167 * @param productId 产品编号
@@ -248,6 +239,6 @@ public interface IotDeviceService { @@ -248,6 +239,6 @@ public interface IotDeviceService {
248 * 239 *
249 * @param ids 设备编号数组 240 * @param ids 设备编号数组
250 */ 241 */
251 - void validateDevicesExist(Set<Long> ids); 242 + List<IotDeviceDO> validateDeviceListExists(Collection<Long> ids);
252 243
253 } 244 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java
@@ -279,11 +279,6 @@ public class IotDeviceServiceImpl implements IotDeviceService { @@ -279,11 +279,6 @@ public class IotDeviceServiceImpl implements IotDeviceService {
279 } 279 }
280 280
281 @Override 281 @Override
282 - public List<IotDeviceDO> getDeviceListByIdList(List<Long> deviceIdList) {  
283 - return deviceMapper.selectByIds(deviceIdList);  
284 - }  
285 -  
286 - @Override  
287 public void updateDeviceState(IotDeviceDO device, Integer state) { 282 public void updateDeviceState(IotDeviceDO device, Integer state) {
288 // 1. 更新状态和时间 283 // 1. 更新状态和时间
289 IotDeviceDO updateObj = new IotDeviceDO().setId(device.getId()).setState(state); 284 IotDeviceDO updateObj = new IotDeviceDO().setId(device.getId()).setState(state);
@@ -474,14 +469,15 @@ public class IotDeviceServiceImpl implements IotDeviceService { @@ -474,14 +469,15 @@ public class IotDeviceServiceImpl implements IotDeviceService {
474 } 469 }
475 470
476 @Override 471 @Override
477 - public void validateDevicesExist(Set<Long> ids) { 472 + public List<IotDeviceDO> validateDeviceListExists(Collection<Long> ids) {
478 if (CollUtil.isEmpty(ids)) { 473 if (CollUtil.isEmpty(ids)) {
479 - return; 474 + return Collections.emptyList();
480 } 475 }
481 - List<IotDeviceDO> deviceIds = deviceMapper.selectByIds(ids);  
482 - if (deviceIds.size() != ids.size()) { 476 + List<IotDeviceDO> devices = deviceMapper.selectByIds(ids);
  477 + if (devices.size() != ids.size()) {
483 throw exception(DEVICE_NOT_EXISTS); 478 throw exception(DEVICE_NOT_EXISTS);
484 } 479 }
  480 + return devices;
485 } 481 }
486 482
487 private IotDeviceServiceImpl getSelf() { 483 private IotDeviceServiceImpl getSelf() {
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java
@@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; @@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO;
8 import jakarta.validation.Valid; 8 import jakarta.validation.Valid;
9 9
10 /** 10 /**
11 - * OTA 固件管理 Service 11 + * OTA 固件管理 Service 接口
12 * 12 *
13 * @author Shelly Chan 13 * @author Shelly Chan
14 */ 14 */
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java
@@ -23,9 +23,14 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU @@ -23,9 +23,14 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
23 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.OTA_FIRMWARE_NOT_EXISTS; 23 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.OTA_FIRMWARE_NOT_EXISTS;
24 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE; 24 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE;
25 25
26 -@Slf4j 26 +/**
  27 + * OTA 固件管理 Service 实现类
  28 + *
  29 + * @author Shelly Chan
  30 + */
27 @Service 31 @Service
28 @Validated 32 @Validated
  33 +@Slf4j
29 public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService { 34 public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService {
30 35
31 @Resource 36 @Resource
@@ -37,7 +42,9 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService { @@ -37,7 +42,9 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService {
37 @Override 42 @Override
38 public Long createOtaFirmware(IotOtaFirmwareCreateReqVO saveReqVO) { 43 public Long createOtaFirmware(IotOtaFirmwareCreateReqVO saveReqVO) {
39 // 1.1 校验固件产品 + 版本号不能重复 44 // 1.1 校验固件产品 + 版本号不能重复
40 - validateProductAndVersionDuplicate(saveReqVO.getProductId(), saveReqVO.getVersion()); 45 + if (otaFirmwareMapper.selectByProductIdAndVersion(saveReqVO.getProductId(), saveReqVO.getVersion()) != null) {
  46 + throw exception(OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE);
  47 + }
41 // 1.2 校验产品存在 48 // 1.2 校验产品存在
42 productService.validateProductExists(saveReqVO.getProductId()); 49 productService.validateProductExists(saveReqVO.getProductId());
43 50
@@ -84,24 +91,11 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService { @@ -84,24 +91,11 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService {
84 } 91 }
85 92
86 /** 93 /**
87 - * 验证产品和版本号是否重复  
88 - */  
89 - private void validateProductAndVersionDuplicate(Long productId, String version) {  
90 - // 只查询1条记录检查是否存在  
91 - IotOtaFirmwareDO firmware = otaFirmwareMapper.selectOne(IotOtaFirmwareDO::getProductId, productId,  
92 - IotOtaFirmwareDO::getVersion, version);  
93 - if (firmware != null) {  
94 - throw exception(OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE);  
95 - }  
96 - }  
97 -  
98 - /**  
99 * 计算文件签名 94 * 计算文件签名
100 - * 95 + *
101 * @param firmware 固件对象 96 * @param firmware 固件对象
102 - * @throws Exception 下载或计算签名失败时抛出异常  
103 */ 97 */
104 - private void calculateFileDigest(IotOtaFirmwareDO firmware) throws Exception { 98 + private void calculateFileDigest(IotOtaFirmwareDO firmware) {
105 String fileUrl = firmware.getFileUrl(); 99 String fileUrl = firmware.getFileUrl();
106 // 下载文件并计算签名 100 // 下载文件并计算签名
107 byte[] fileBytes = HttpUtil.downloadBytes(fileUrl); 101 byte[] fileBytes = HttpUtil.downloadBytes(fileUrl);
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordService.java
@@ -2,67 +2,67 @@ package cn.iocoder.yudao.module.iot.service.ota; @@ -2,67 +2,67 @@ package cn.iocoder.yudao.module.iot.service.ota;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordPageReqVO; 4 import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordPageReqVO;
  5 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
5 import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO; 6 import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO;
6 import jakarta.validation.Valid; 7 import jakarta.validation.Valid;
7 8
8 import java.util.List; 9 import java.util.List;
9 import java.util.Map; 10 import java.util.Map;
  11 +import java.util.Set;
10 12
11 -// TODO @li:注释写的有点冗余,可以看看别的模块哈。= = AI 生成的注释,有的时候太啰嗦了,需要处理下的哈  
12 /** 13 /**
13 - * IotOtaUpgradeRecordService 接口定义了与物联网设备OTA升级记录相关的操作。  
14 - * 该接口提供了创建、更新、查询、统计和重试升级记录的功能。 14 + * IoT OTA 升级记录 Service 接口
15 */ 15 */
16 public interface IotOtaTaskRecordService { 16 public interface IotOtaTaskRecordService {
17 17
18 /** 18 /**
19 * 批量创建 OTA 升级记录 19 * 批量创建 OTA 升级记录
20 - * 该函数用于为指定的设备列表、固件ID和升级任务ID创建OTA升级记录。  
21 * 20 *
22 - * @param deviceIds 设备ID列表,表示需要升级的设备集合。  
23 - * @param firmwareId 固件ID,表示要升级到的固件版本。  
24 - * @param upgradeTaskId 升级任务ID,表示此次升级任务的唯一标识。 21 + * @param devices 设备列表
  22 + * @param firmwareId 固件编号
  23 + * @param taskId 任务编号
25 */ 24 */
26 - void createOtaTaskRecordBatch(List<Long> deviceIds, Long firmwareId, Long upgradeTaskId); 25 + void createOtaTaskRecordList(List<IotDeviceDO> devices, Long firmwareId, Long taskId);
27 26
28 /** 27 /**
29 - * 获取 OTA 升级记录的数量统计 28 + * 获取 OTA 升级记录的状态统计
30 * 29 *
31 - * @return 返回一个 Map,其中键为状态码,值为对应状态的升级记录数量 30 + * @param firmwareId 固件编号
  31 + * @param taskId 任务编号
  32 + * @return 状态统计 Map,key 为状态码,value 为对应状态的升级记录数量
32 */ 33 */
33 - Map<Integer, Long> getOtaTaskRecordCount(@Valid IotOtaTaskRecordPageReqVO pageReqVO); 34 + Map<Integer, Long> getOtaTaskRecordStatusCountMap(Long firmwareId, Long taskId);
34 35
35 /** 36 /**
36 - * 获取 OTA 升级记录的统计信息 37 + * 获取 OTA 升级记录
37 * 38 *
38 - * @return 返回一个 Map,其中键为状态码,值为对应状态的升级记录统计信息 39 + * @param id 编号
  40 + * @return OTA 升级记录
39 */ 41 */
40 - Map<Integer, Long> getOtaTaskRecordStatistics(Long firmwareId); 42 + IotOtaTaskRecordDO getOtaTaskRecord(Long id);
41 43
42 /** 44 /**
43 - * 获取指定 ID 的 OTA 升级记录的详细信息 45 + * 获取 OTA 升级记录分页
44 * 46 *
45 - * @param id 需要查询的升级记录的 ID  
46 - * @return 返回包含升级记录详细信息的响应对象 47 + * @param pageReqVO 分页查询
  48 + * @return OTA 升级记录分页
47 */ 49 */
48 - IotOtaTaskRecordDO getOtaTaskRecord(Long id); 50 + PageResult<IotOtaTaskRecordDO> getOtaTaskRecordPage(@Valid IotOtaTaskRecordPageReqVO pageReqVO);
49 51
50 /** 52 /**
51 - * 分页查询 OTA 升级记录 53 + * 根据 OTA 任务编号,取消未结束的升级记录
52 * 54 *
53 - * @param pageReqVO 包含分页查询条件的请求对象,必须经过验证。  
54 - * @return 返回包含分页查询结果的响应对象。 55 + * @param taskId 升级任务编号
55 */ 56 */
56 - PageResult<IotOtaTaskRecordDO> getOtaTaskRecordPage(@Valid IotOtaTaskRecordPageReqVO pageReqVO); 57 + void cancelTaskRecordListByTaskId(Long taskId);
57 58
58 /** 59 /**
59 - * 根据任务 ID 取消升级记录  
60 - * <p>  
61 - * 该函数用于根据给定的任务ID,取消与该任务相关的升级记录。通常用于在任务执行失败或用户手动取消时,  
62 - * 清理或标记相关的升级记录为取消状态。 60 + * 根据设备编号和记录状态,获取 OTA 升级记录列表
63 * 61 *
64 - * @param taskId 要取消升级记录的任务ID。该ID唯一标识一个任务,通常由任务管理系统生成。 62 + * @param deviceIds 设备编号集合
  63 + * @param statuses 记录状态集合
  64 + * @return OTA 升级记录列表
65 */ 65 */
66 - void cancelUpgradeRecordByTaskId(Long taskId); 66 + List<IotOtaTaskRecordDO> getOtaTaskRecordListByDeviceIdAndStatus(Set<Long> deviceIds, Set<Integer> statuses);
67 67
68 } 68 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordServiceImpl.java
@@ -2,177 +2,100 @@ package cn.iocoder.yudao.module.iot.service.ota; @@ -2,177 +2,100 @@ package cn.iocoder.yudao.module.iot.service.ota;
2 2
3 import cn.hutool.core.convert.Convert; 3 import cn.hutool.core.convert.Convert;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;  
6 import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordPageReqVO; 5 import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordPageReqVO;
7 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; 6 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
8 -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO;  
9 import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO; 7 import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO;
10 -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO;  
11 -import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaUpgradeRecordMapper; 8 +import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaTaskRecordMapper;
12 import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskRecordStatusEnum; 9 import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskRecordStatusEnum;
13 -import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;  
14 import jakarta.annotation.Resource; 10 import jakarta.annotation.Resource;
15 import lombok.extern.slf4j.Slf4j; 11 import lombok.extern.slf4j.Slf4j;
16 import org.springframework.stereotype.Service; 12 import org.springframework.stereotype.Service;
17 -import org.springframework.transaction.annotation.Transactional;  
18 import org.springframework.validation.annotation.Validated; 13 import org.springframework.validation.annotation.Validated;
19 14
  15 +import java.util.Arrays;
20 import java.util.List; 16 import java.util.List;
21 import java.util.Map; 17 import java.util.Map;
22 -import java.util.Objects;  
23 -import java.util.stream.Collectors; 18 +import java.util.Set;
24 19
25 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 20 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
26 -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; 21 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  22 +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.OTA_TASK_RECORD_NOT_EXISTS;
27 23
28 -// TODO @li:@Service、@Validated、@Slf4j,先用关键注解;2)类注释,简单写  
29 -@Slf4j 24 +/**
  25 + * OTA 升级任务记录 Service 实现类
  26 + */
30 @Service 27 @Service
31 @Validated 28 @Validated
  29 +@Slf4j
32 public class IotOtaTaskRecordServiceImpl implements IotOtaTaskRecordService { 30 public class IotOtaTaskRecordServiceImpl implements IotOtaTaskRecordService {
33 31
34 @Resource 32 @Resource
35 - private IotOtaUpgradeRecordMapper iotOtaUpgradeRecordMapper;  
36 -  
37 - @Resource  
38 - private IotDeviceService deviceService;  
39 - @Resource  
40 - private IotOtaFirmwareService firmwareService;  
41 - @Resource  
42 - private IotOtaTaskService upgradeTaskService; 33 + private IotOtaTaskRecordMapper otaTaskRecordMapper;
43 34
44 @Override 35 @Override
45 - public void createOtaTaskRecordBatch(List<Long> deviceIds, Long firmwareId, Long upgradeTaskId) {  
46 - // 1. 校验升级记录信息是否存在,并且已经取消的任务可以重新开始  
47 - deviceIds.forEach(deviceId -> validateUpgradeRecordDuplicate(firmwareId, upgradeTaskId, String.valueOf(deviceId)));  
48 -  
49 - // 2. 初始化OTA升级记录列表信息  
50 - IotOtaTaskDO upgradeTask = upgradeTaskService.getOtaTask(upgradeTaskId);  
51 - IotOtaFirmwareDO firmware = firmwareService.getOtaFirmware(firmwareId);  
52 - List<IotDeviceDO> deviceList = deviceService.getDeviceListByIdList(deviceIds);  
53 - List<IotOtaTaskRecordDO> upgradeRecordList = deviceList.stream().map(device -> {  
54 - IotOtaTaskRecordDO upgradeRecord = new IotOtaTaskRecordDO();  
55 - upgradeRecord.setFirmwareId(firmware.getId());  
56 - upgradeRecord.setTaskId(upgradeTask.getId());  
57 - upgradeRecord.setDeviceId(device.getId());  
58 - upgradeRecord.setFromFirmwareId(Convert.toLong(device.getFirmwareId()));  
59 - upgradeRecord.setStatus(IotOtaTaskRecordStatusEnum.PENDING.getStatus());  
60 - upgradeRecord.setProgress(0);  
61 - return upgradeRecord;  
62 - }).toList();  
63 - // 3. 保存数据  
64 - iotOtaUpgradeRecordMapper.insertBatch(upgradeRecordList);  
65 - // TODO @芋艿:在这里需要处理推送升级任务的逻辑 36 + public void createOtaTaskRecordList(List<IotDeviceDO> devices, Long firmwareId, Long taskId) {
  37 + List<IotOtaTaskRecordDO> records = convertList(devices, device ->
  38 + IotOtaTaskRecordDO.builder().firmwareId(firmwareId).taskId(taskId)
  39 + .deviceId(device.getId()).fromFirmwareId(Convert.toLong(device.getFirmwareId()))
  40 + .status(IotOtaTaskRecordStatusEnum.PENDING.getStatus()).progress(0).build());
  41 + otaTaskRecordMapper.insertBatch(records);
66 } 42 }
67 43
68 - // TODO @li:1)方法注释,简单写;2)父类写了注释,子类就不用写了。。。  
69 - /**  
70 - * 获取OTA升级记录的数量统计。  
71 - * 该方法根据传入的查询条件,统计不同状态的OTA升级记录数量,并返回一个包含各状态数量的映射。  
72 - *  
73 - * @param pageReqVO 包含查询条件的请求对象,主要包括任务ID和设备名称等信息。  
74 - * @return 返回一个Map,其中键为状态常量,值为对应状态的记录数量。  
75 - */  
76 @Override 44 @Override
77 - @Transactional  
78 - public Map<Integer, Long> getOtaTaskRecordCount(IotOtaTaskRecordPageReqVO pageReqVO) {  
79 - // 分别查询不同状态的OTA升级记录数量  
80 - List<Map<String, Object>> upgradeRecordCountList = iotOtaUpgradeRecordMapper.selectOtaUpgradeRecordCount(  
81 - pageReqVO.getTaskId(), pageReqVO.getDeviceName());  
82 - Map<String, Object> upgradeRecordCountMap = ObjectUtils.defaultIfNull(upgradeRecordCountList.get(0));  
83 - Objects.requireNonNull(upgradeRecordCountMap);  
84 - return upgradeRecordCountMap.entrySet().stream().collect(Collectors.toMap(  
85 - entry -> Convert.toInt(entry.getKey()),  
86 - entry -> Convert.toLong(entry.getValue()))); 45 + public Map<Integer, Long> getOtaTaskRecordStatusCountMap(Long firmwareId, Long taskId) {
  46 + // 按照 status 枚举,初始化 countMap 为 0
  47 + Map<Integer, Long> countMap = convertMap(Arrays.asList(IotOtaTaskRecordStatusEnum.values()),
  48 + IotOtaTaskRecordStatusEnum::getStatus, iotOtaTaskRecordStatusEnum -> 0L);
  49 +
  50 + // 查询记录,只返回 id、status 字段
  51 + List<IotOtaTaskRecordDO> records = otaTaskRecordMapper.selectListByFirmwareIdAndTaskId(firmwareId, taskId);
  52 + Map<Long, List<Integer>> deviceStatusesMap = convertMultiMap(records,
  53 + IotOtaTaskRecordDO::getDeviceId, IotOtaTaskRecordDO::getStatus);
  54 + // 找到第一个匹配的优先级状态,避免重复计算
  55 + deviceStatusesMap.forEach((deviceId, statuses) -> {
  56 + for (Integer priorityStatus : IotOtaTaskRecordStatusEnum.PRIORITY_STATUSES) {
  57 + if (statuses.contains(priorityStatus)) {
  58 + countMap.put(priorityStatus, countMap.get(priorityStatus) + 1);
  59 + return;
  60 + }
  61 + }
  62 + });
  63 + return countMap;
87 } 64 }
88 65
89 @Override 66 @Override
90 - @Transactional  
91 - public Map<Integer, Long> getOtaTaskRecordStatistics(Long firmwareId) {  
92 - // 查询并统计不同状态的OTA升级记录数量  
93 - List<Map<String, Object>> upgradeRecordStatisticsList = iotOtaUpgradeRecordMapper.selectOtaUpgradeRecordStatistics(firmwareId);  
94 - Map<String, Object> upgradeRecordStatisticsMap = ObjectUtils.defaultIfNull(upgradeRecordStatisticsList.get(0));  
95 - Objects.requireNonNull(upgradeRecordStatisticsMap);  
96 - return upgradeRecordStatisticsMap.entrySet().stream().collect(Collectors.toMap(  
97 - entry -> Convert.toInt(entry.getKey()),  
98 - entry -> Convert.toLong(entry.getValue()))); 67 + public IotOtaTaskRecordDO getOtaTaskRecord(Long id) {
  68 + return otaTaskRecordMapper.selectById(id);
99 } 69 }
100 70
101 @Override 71 @Override
102 - public IotOtaTaskRecordDO getOtaTaskRecord(Long id) {  
103 - return iotOtaUpgradeRecordMapper.selectById(id); 72 + public PageResult<IotOtaTaskRecordDO> getOtaTaskRecordPage(IotOtaTaskRecordPageReqVO pageReqVO) {
  73 + return otaTaskRecordMapper.selectPage(pageReqVO);
104 } 74 }
105 75
106 @Override 76 @Override
107 - public PageResult<IotOtaTaskRecordDO> getOtaTaskRecordPage(IotOtaTaskRecordPageReqVO pageReqVO) {  
108 - return iotOtaUpgradeRecordMapper.selectUpgradeRecordPage(pageReqVO); 77 + public void cancelTaskRecordListByTaskId(Long taskId) {
  78 + // 设置取消记录的描述
  79 + IotOtaTaskRecordDO updateRecord = IotOtaTaskRecordDO.builder()
  80 + .status(IotOtaTaskRecordStatusEnum.CANCELED.getStatus())
  81 + .description("管理员取消升级任务")
  82 + .build();
  83 +
  84 + otaTaskRecordMapper.updateByTaskIdAndStatus(
  85 + taskId, IotOtaTaskRecordStatusEnum.PENDING.getStatus(), updateRecord);
109 } 86 }
110 87
111 @Override 88 @Override
112 - public void cancelUpgradeRecordByTaskId(Long taskId) {  
113 - // 暂定只有待推送的升级记录可以取消 TODO @芋艿:可以看看阿里云,哪些可以取消  
114 - iotOtaUpgradeRecordMapper.updateUpgradeRecordStatusByTaskIdAndStatus(  
115 - IotOtaTaskRecordStatusEnum.CANCELED.getStatus(), taskId,  
116 - IotOtaTaskRecordStatusEnum.PENDING.getStatus()); 89 + public List<IotOtaTaskRecordDO> getOtaTaskRecordListByDeviceIdAndStatus(Set<Long> deviceIds, Set<Integer> statuses) {
  90 + return otaTaskRecordMapper.selectListByDeviceIdAndStatus(deviceIds, statuses);
117 } 91 }
118 92
119 - /**  
120 - * 验证指定的升级记录是否存在。  
121 - * <p>  
122 - * 该函数通过给定的ID查询升级记录,如果查询结果为空,则抛出异常,表示升级记录不存在。  
123 - *  
124 - * @param id 升级记录的唯一标识符,类型为Long。  
125 - * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,则抛出异常,异常类型为OTA_UPGRADE_RECORD_NOT_EXISTS。  
126 - */  
127 private IotOtaTaskRecordDO validateUpgradeRecordExists(Long id) { 93 private IotOtaTaskRecordDO validateUpgradeRecordExists(Long id) {
128 - // 根据ID查询升级记录  
129 - IotOtaTaskRecordDO upgradeRecord = iotOtaUpgradeRecordMapper.selectById(id);  
130 - // 如果查询结果为空,抛出异常 94 + IotOtaTaskRecordDO upgradeRecord = otaTaskRecordMapper.selectById(id);
131 if (upgradeRecord == null) { 95 if (upgradeRecord == null) {
132 - throw exception(OTA_UPGRADE_RECORD_NOT_EXISTS); 96 + throw exception(OTA_TASK_RECORD_NOT_EXISTS);
133 } 97 }
134 return upgradeRecord; 98 return upgradeRecord;
135 } 99 }
136 100
137 - // TODO @li:注释有点冗余  
138 - /**  
139 - * 校验固件升级记录是否重复。  
140 - * <p>  
141 - * 该函数用于检查给定的固件ID、任务ID和设备ID是否已经存在未取消的升级记录。  
142 - * 如果存在未取消的记录,则抛出异常,提示升级记录重复。  
143 - *  
144 - * @param firmwareId 固件ID,用于标识特定的固件版本  
145 - * @param taskId 任务ID,用于标识特定的升级任务  
146 - * @param deviceId 设备ID,用于标识特定的设备  
147 - */  
148 - private void validateUpgradeRecordDuplicate(Long firmwareId, Long taskId, String deviceId) {  
149 - IotOtaTaskRecordDO upgradeRecord = iotOtaUpgradeRecordMapper.selectByConditions(firmwareId, taskId, deviceId);  
150 - if (upgradeRecord == null) {  
151 - return;  
152 - }  
153 - if (!Objects.equals(upgradeRecord.getStatus(), IotOtaTaskRecordStatusEnum.CANCELED.getStatus())) {  
154 - throw exception(OTA_UPGRADE_RECORD_DUPLICATE);  
155 - }  
156 - }  
157 -  
158 - // TODO @li:注释有点冗余  
159 - /**  
160 - * 验证升级记录是否可以重试。  
161 - * <p>  
162 - * 该方法用于检查给定的升级记录是否处于允许重试的状态。如果升级记录的状态为  
163 - * PENDING、PUSHED 或 UPGRADING,则抛出异常,表示不允许重试。  
164 - *  
165 - * @param upgradeRecord 需要验证的升级记录对象,类型为 IotOtaUpgradeRecordDO  
166 - * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,则抛出 OTA_UPGRADE_RECORD_CANNOT_RETRY 异常  
167 - */  
168 - // TODO @li:这种一次性的方法(不复用的),其实一步一定要抽成小方法;  
169 - private void validateUpgradeRecordCanRetry(IotOtaTaskRecordDO upgradeRecord) {  
170 - if (ObjectUtils.equalsAny(upgradeRecord.getStatus(),  
171 - IotOtaTaskRecordStatusEnum.PENDING.getStatus(),  
172 - IotOtaTaskRecordStatusEnum.PUSHED.getStatus(),  
173 - IotOtaTaskRecordStatusEnum.UPGRADING.getStatus())) {  
174 - throw exception(OTA_UPGRADE_RECORD_CANNOT_RETRY);  
175 - }  
176 - }  
177 -  
178 } 101 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskService.java
@@ -14,7 +14,7 @@ import jakarta.validation.Valid; @@ -14,7 +14,7 @@ import jakarta.validation.Valid;
14 public interface IotOtaTaskService { 14 public interface IotOtaTaskService {
15 15
16 /** 16 /**
17 - * 创建 OTA升 级任务 17 + * 创建 OTA 升级任务
18 * 18 *
19 * @param createReqVO 创建请求对象 19 * @param createReqVO 创建请求对象
20 * @return 升级任务编号 20 * @return 升级任务编号
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskServiceImpl.java
1 package cn.iocoder.yudao.module.iot.service.ota; 1 package cn.iocoder.yudao.module.iot.service.ota;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 -import cn.hutool.core.convert.Convert; 4 +import cn.hutool.core.util.ObjUtil;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
7 import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskCreateReqVO; 7 import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskCreateReqVO;
@@ -9,8 +9,10 @@ import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskPageRe @@ -9,8 +9,10 @@ import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskPageRe
9 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; 9 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
10 import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; 10 import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO;
11 import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO; 11 import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO;
  12 +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO;
12 import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaTaskMapper; 13 import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaTaskMapper;
13 import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskDeviceScopeEnum; 14 import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskDeviceScopeEnum;
  15 +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskRecordStatusEnum;
14 import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskStatusEnum; 16 import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskStatusEnum;
15 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; 17 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
16 import jakarta.annotation.Resource; 18 import jakarta.annotation.Resource;
@@ -24,6 +26,7 @@ import java.util.List; @@ -24,6 +26,7 @@ import java.util.List;
24 import java.util.Objects; 26 import java.util.Objects;
25 27
26 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 28 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  29 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
27 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; 30 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
28 31
29 /** 32 /**
@@ -45,26 +48,29 @@ public class IotOtaTaskServiceImpl implements IotOtaTaskService { @@ -45,26 +48,29 @@ public class IotOtaTaskServiceImpl implements IotOtaTaskService {
45 private IotOtaFirmwareService otaFirmwareService; 48 private IotOtaFirmwareService otaFirmwareService;
46 @Resource 49 @Resource
47 @Lazy // 延迟,避免循环依赖报错 50 @Lazy // 延迟,避免循环依赖报错
48 - private IotOtaTaskRecordService otaUpgradeRecordService; 51 + private IotOtaTaskRecordService otaTaskRecordService;
49 52
50 @Override 53 @Override
51 @Transactional(rollbackFor = Exception.class) 54 @Transactional(rollbackFor = Exception.class)
52 public Long createOtaTask(IotOtaTaskCreateReqVO createReqVO) { 55 public Long createOtaTask(IotOtaTaskCreateReqVO createReqVO) {
53 - // 1.1 校验同一固件的升级任务名称不重复  
54 - validateFirmwareTaskDuplicate(createReqVO.getFirmwareId(), createReqVO.getName());  
55 - // 1.2 校验固件信息是否存在 56 + // 1.1 校验固件信息是否存在
56 IotOtaFirmwareDO firmware = otaFirmwareService.validateFirmwareExists(createReqVO.getFirmwareId()); 57 IotOtaFirmwareDO firmware = otaFirmwareService.validateFirmwareExists(createReqVO.getFirmwareId());
57 - // 1.3 补全设备范围信息,并且校验是否又设备可以升级,如果没有设备可以升级,则报错  
58 - validateScopeAndDevice(createReqVO.getDeviceScope(), createReqVO.getDeviceIds(), firmware.getProductId());  
59 -  
60 - // 2. 保存 OTA 升级任务信息到数据库  
61 - IotOtaTaskDO upgradeTask = initOtaUpgradeTask(createReqVO, firmware.getProductId());  
62 - otaTaskMapper.insert(upgradeTask);  
63 -  
64 - // 3. 生成设备升级记录信息并存储,等待定时任务轮询  
65 - // TODO @芋艿:在处理;  
66 -// otaUpgradeRecordService.createOtaUpgradeRecordBatch(upgradeTask.getDeviceIds(), firmware.getId(), upgradeTask.getId());  
67 - return upgradeTask.getId(); 58 + // 1.2 校验同一固件的升级任务名称不重复
  59 + if (otaTaskMapper.selectByFirmwareIdAndName(firmware.getId(), createReqVO.getName()) != null) {
  60 + throw exception(OTA_TASK_CREATE_FAIL_NAME_DUPLICATE);
  61 + }
  62 + // 1.3 校验设备范围信息
  63 + List<IotDeviceDO> devices = validateOtaTaskDeviceScope(createReqVO, firmware.getProductId());
  64 +
  65 + // 2. 保存升级任务,直接转换
  66 + IotOtaTaskDO task = BeanUtils.toBean(createReqVO, IotOtaTaskDO.class)
  67 + .setStatus(IotOtaTaskStatusEnum.IN_PROGRESS.getStatus())
  68 + .setDeviceTotalCount(devices.size()).setDeviceSuccessCount(0);
  69 + otaTaskMapper.insert(task);
  70 +
  71 + // 3. 生成设备升级记录
  72 + otaTaskRecordService.createOtaTaskRecordList(devices, firmware.getId(), task.getId());
  73 + return task.getId();
68 } 74 }
69 75
70 @Override 76 @Override
@@ -73,18 +79,17 @@ public class IotOtaTaskServiceImpl implements IotOtaTaskService { @@ -73,18 +79,17 @@ public class IotOtaTaskServiceImpl implements IotOtaTaskService {
73 // 1.1 校验升级任务是否存在 79 // 1.1 校验升级任务是否存在
74 IotOtaTaskDO upgradeTask = validateUpgradeTaskExists(id); 80 IotOtaTaskDO upgradeTask = validateUpgradeTaskExists(id);
75 // 1.2 校验升级任务是否可以取消 81 // 1.2 校验升级任务是否可以取消
76 - // TODO @li:ObjUtil notequals  
77 - if (!Objects.equals(upgradeTask.getStatus(), IotOtaTaskStatusEnum.IN_PROGRESS.getStatus())) {  
78 - throw exception(OTA_UPGRADE_TASK_CANNOT_CANCEL); 82 + if (ObjUtil.notEqual(upgradeTask.getStatus(), IotOtaTaskStatusEnum.IN_PROGRESS.getStatus())) {
  83 + throw exception(OTA_TASK_CANCEL_FAIL_STATUS_END);
79 } 84 }
80 85
81 - // 2. 更新 OTA 升级任务状态为已取消 86 + // 2. 更新升级任务状态为已取消
82 otaTaskMapper.updateById(IotOtaTaskDO.builder() 87 otaTaskMapper.updateById(IotOtaTaskDO.builder()
83 .id(id).status(IotOtaTaskStatusEnum.CANCELED.getStatus()) 88 .id(id).status(IotOtaTaskStatusEnum.CANCELED.getStatus())
84 .build()); 89 .build());
85 90
86 - // 3. 更新 OTA 升级记录状态为已取消  
87 - otaUpgradeRecordService.cancelUpgradeRecordByTaskId(id); 91 + // 3. 更新升级记录状态为已取消
  92 + otaTaskRecordService.cancelTaskRecordListByTaskId(id);
88 } 93 }
89 94
90 @Override 95 @Override
@@ -97,50 +102,55 @@ public class IotOtaTaskServiceImpl implements IotOtaTaskService { @@ -97,50 +102,55 @@ public class IotOtaTaskServiceImpl implements IotOtaTaskService {
97 return otaTaskMapper.selectUpgradeTaskPage(pageReqVO); 102 return otaTaskMapper.selectUpgradeTaskPage(pageReqVO);
98 } 103 }
99 104
100 - /**  
101 - * 校验固件升级任务是否重复  
102 - */  
103 - private void validateFirmwareTaskDuplicate(Long firmwareId, String taskName) {  
104 - List<IotOtaTaskDO> upgradeTaskList = otaTaskMapper.selectByFirmwareIdAndName(firmwareId, taskName);  
105 - if (CollUtil.isNotEmpty(upgradeTaskList)) {  
106 - throw exception(OTA_UPGRADE_TASK_NAME_DUPLICATE);  
107 - }  
108 - }  
109 -  
110 - private void validateScopeAndDevice(Integer scope, List<Long> deviceIds, Long productId) {  
111 - if (Objects.equals(scope, IotOtaTaskDeviceScopeEnum.SELECT.getScope())) {  
112 - if (CollUtil.isEmpty(deviceIds)) {  
113 - throw exception(OTA_UPGRADE_TASK_DEVICE_IDS_EMPTY); 105 + private List<IotDeviceDO> validateOtaTaskDeviceScope(IotOtaTaskCreateReqVO createReqVO, Long productId) {
  106 + // 情况一:选择设备
  107 + if (Objects.equals(createReqVO.getDeviceScope(), IotOtaTaskDeviceScopeEnum.SELECT.getScope())) {
  108 + // 1.1 校验设备存在
  109 + List<IotDeviceDO> devices = deviceService.validateDeviceListExists(createReqVO.getDeviceIds());
  110 + for (IotDeviceDO device : devices) {
  111 + if (ObjUtil.notEqual(device.getProductId(), productId)) {
  112 + throw exception(DEVICE_NOT_EXISTS);
  113 + }
114 } 114 }
115 - return; 115 + // 1.2 校验设备是否已经是该固件版本
  116 + devices.forEach(device -> {
  117 + if (Objects.equals(device.getFirmwareId(), createReqVO.getFirmwareId())) {
  118 + throw exception(OTA_TASK_CREATE_FAIL_DEVICE_FIRMWARE_EXISTS, device.getDeviceName());
  119 + }
  120 + });
  121 + // 1.3 校验设备是否已经在升级中
  122 + List<IotOtaTaskRecordDO> records = otaTaskRecordService.getOtaTaskRecordListByDeviceIdAndStatus(
  123 + convertSet(devices, IotDeviceDO::getId), IotOtaTaskRecordStatusEnum.IN_PROCESS_STATUSES);
  124 + devices.forEach(device -> {
  125 + if (CollUtil.contains(records, item -> item.getDeviceId().equals(device.getId()))) {
  126 + throw exception(OTA_TASK_CREATE_FAIL_DEVICE_OTA_IN_PROCESS, device.getDeviceName());
  127 + }
  128 + });
  129 + return devices;
116 } 130 }
117 -  
118 - if (Objects.equals(scope, IotOtaTaskDeviceScopeEnum.ALL.getScope())) {  
119 - List<IotDeviceDO> deviceList = deviceService.getDeviceListByProductId(productId);  
120 - if (CollUtil.isEmpty(deviceList)) {  
121 - throw exception(OTA_UPGRADE_TASK_DEVICE_LIST_EMPTY); 131 + // 情况二:全部设备
  132 + if (Objects.equals(createReqVO.getDeviceScope(), IotOtaTaskDeviceScopeEnum.ALL.getScope())) {
  133 + List<IotDeviceDO> devices = deviceService.getDeviceListByProductId(productId);
  134 + // 2.1.1 移除已经是该固件版本的设备
  135 + devices.removeIf(device -> Objects.equals(device.getFirmwareId(), createReqVO.getFirmwareId()));
  136 + // 2.1.2 移除已经在升级中的设备
  137 + List<IotOtaTaskRecordDO> records = otaTaskRecordService.getOtaTaskRecordListByDeviceIdAndStatus(
  138 + convertSet(devices, IotDeviceDO::getId), IotOtaTaskRecordStatusEnum.IN_PROCESS_STATUSES);
  139 + devices.removeIf(device -> CollUtil.contains(records,
  140 + item -> item.getDeviceId().equals(device.getId())));
  141 + // 2.2 校验是否有可升级的设备
  142 + if (CollUtil.isEmpty(devices)) {
  143 + throw exception(OTA_TASK_CREATE_FAIL_DEVICE_EMPTY);
122 } 144 }
  145 + return devices;
123 } 146 }
  147 + throw new IllegalArgumentException("不支持的设备范围:" + createReqVO.getDeviceScope());
124 } 148 }
125 149
126 private IotOtaTaskDO validateUpgradeTaskExists(Long id) { 150 private IotOtaTaskDO validateUpgradeTaskExists(Long id) {
127 IotOtaTaskDO upgradeTask = otaTaskMapper.selectById(id); 151 IotOtaTaskDO upgradeTask = otaTaskMapper.selectById(id);
128 if (Objects.isNull(upgradeTask)) { 152 if (Objects.isNull(upgradeTask)) {
129 - throw exception(OTA_UPGRADE_TASK_NOT_EXISTS);  
130 - }  
131 - return upgradeTask;  
132 - }  
133 -  
134 - private IotOtaTaskDO initOtaUpgradeTask(IotOtaTaskCreateReqVO createReqVO, Long productId) {  
135 - IotOtaTaskDO upgradeTask = BeanUtils.toBean(createReqVO, IotOtaTaskDO.class);  
136 - upgradeTask.setDeviceTotalCount(Convert.toLong(CollUtil.size(createReqVO.getDeviceIds())))  
137 - .setStatus(IotOtaTaskStatusEnum.IN_PROGRESS.getStatus());  
138 -  
139 - if (Objects.equals(createReqVO.getDeviceScope(), IotOtaTaskDeviceScopeEnum.ALL.getScope())) {  
140 - List<IotDeviceDO> deviceList = deviceService.getDeviceListByProductId(productId);  
141 - upgradeTask.setDeviceTotalCount((long) deviceList.size());  
142 -// upgradeTask.setDeviceIds(  
143 -// deviceList.stream().map(IotDeviceDO::getId).collect(Collectors.toList())); 153 + throw exception(OTA_TASK_NOT_EXISTS);
144 } 154 }
145 return upgradeTask; 155 return upgradeTask;
146 } 156 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java
@@ -121,7 +121,7 @@ public class IotDataRuleServiceImpl implements IotDataRuleService { @@ -121,7 +121,7 @@ public class IotDataRuleServiceImpl implements IotDataRuleService {
121 convertSet(sourceConfigs, IotDataRuleDO.SourceConfig::getProductId)); 121 convertSet(sourceConfigs, IotDataRuleDO.SourceConfig::getProductId));
122 122
123 // 2. 校验设备 123 // 2. 校验设备
124 - deviceService.validateDevicesExist(convertSet(sourceConfigs, IotDataRuleDO.SourceConfig::getDeviceId, 124 + deviceService.validateDeviceListExists(convertSet(sourceConfigs, IotDataRuleDO.SourceConfig::getDeviceId,
125 config -> ObjUtil.notEqual(config.getDeviceId(), IotDeviceDO.DEVICE_ID_ALL))); 125 config -> ObjUtil.notEqual(config.getDeviceId(), IotDeviceDO.DEVICE_ID_ALL)));
126 126
127 // 3. 校验物模型存在 127 // 3. 校验物模型存在