feat:【IoT 物联网】增加 OTA 相关的任务、记录取消
This commit is contained in:
@@ -22,6 +22,7 @@ import org.dromara.hutool.core.collection.CollUtil;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@@ -90,4 +91,13 @@ public class IotOtaTaskRecordController {
|
||||
return success(BeanUtils.toBean(upgradeRecord, IotOtaTaskRecordRespVO.class));
|
||||
}
|
||||
|
||||
@PutMapping("/cancel")
|
||||
@Operation(summary = "取消 OTA 升级记录")
|
||||
@PreAuthorize("@ss.hasPermission('iot:ota-task-record:cancel')")
|
||||
@Parameter(name = "id", description = "升级记录编号", required = true, example = "1024")
|
||||
public CommonResult<Boolean> cancelOtaTaskRecord(@RequestParam("id") Long id) {
|
||||
otaTaskRecordService.cancelOtaTaskRecord(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,13 @@ import lombok.NoArgsConstructor;
|
||||
@AllArgsConstructor
|
||||
public class IotOtaTaskRecordDO extends BaseDO {
|
||||
|
||||
public static final String DESCRIPTION_CANCEL_BY_TASK = "管理员手动取消升级任务(批量)";
|
||||
|
||||
public static final String DESCRIPTION_CANCEL_BY_RECORD = "管理员手动取消升级记录(单个)";
|
||||
|
||||
/**
|
||||
* 升级记录编号
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskPageReqVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
@@ -15,10 +16,17 @@ public interface IotOtaTaskMapper extends BaseMapperX<IotOtaTaskDO> {
|
||||
IotOtaTaskDO::getName, name);
|
||||
}
|
||||
|
||||
default PageResult<IotOtaTaskDO> selectUpgradeTaskPage(IotOtaTaskPageReqVO pageReqVO) {
|
||||
default PageResult<IotOtaTaskDO> selectPage(IotOtaTaskPageReqVO pageReqVO) {
|
||||
return selectPage(pageReqVO, new LambdaQueryWrapperX<IotOtaTaskDO>()
|
||||
.eqIfPresent(IotOtaTaskDO::getFirmwareId, pageReqVO.getFirmwareId())
|
||||
.likeIfPresent(IotOtaTaskDO::getName, pageReqVO.getName()));
|
||||
.likeIfPresent(IotOtaTaskDO::getName, pageReqVO.getName())
|
||||
.orderByDesc(IotOtaTaskDO::getId));
|
||||
}
|
||||
|
||||
default int updateByIdAndStatus(Long id, Integer whereStatus, IotOtaTaskDO updateObj) {
|
||||
return update(updateObj, new LambdaUpdateWrapper<IotOtaTaskDO>()
|
||||
.eq(IotOtaTaskDO::getId, id)
|
||||
.eq(IotOtaTaskDO::getStatus, whereStatus));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -27,10 +28,30 @@ public interface IotOtaTaskRecordMapper extends BaseMapperX<IotOtaTaskRecordDO>
|
||||
.eqIfPresent(IotOtaTaskRecordDO::getStatus, pageReqVO.getStatus()));
|
||||
}
|
||||
|
||||
default void updateByTaskIdAndStatus(Long taskId, Integer fromStatus, IotOtaTaskRecordDO updateRecord) {
|
||||
update(updateRecord, new LambdaUpdateWrapper<IotOtaTaskRecordDO>()
|
||||
default List<IotOtaTaskRecordDO> selectListByTaskIdAndStatus(Long taskId, Collection<Integer> statuses) {
|
||||
return selectList(new LambdaQueryWrapperX<IotOtaTaskRecordDO>()
|
||||
.eq(IotOtaTaskRecordDO::getTaskId, taskId)
|
||||
.in(IotOtaTaskRecordDO::getStatus, statuses));
|
||||
}
|
||||
|
||||
default Long selectCountByTaskIdAndStatus(Long taskId, Collection<Integer> statuses) {
|
||||
return selectCount(new LambdaQueryWrapperX<IotOtaTaskRecordDO>()
|
||||
.eq(IotOtaTaskRecordDO::getTaskId, taskId)
|
||||
.eq(IotOtaTaskRecordDO::getStatus, fromStatus));
|
||||
.in(IotOtaTaskRecordDO::getStatus, statuses));
|
||||
}
|
||||
|
||||
default int updateByIdAndStatus(Long id, Collection<Integer> whereStatuses,
|
||||
IotOtaTaskRecordDO updateObj) {
|
||||
return update(updateObj, new LambdaUpdateWrapper<IotOtaTaskRecordDO>()
|
||||
.eq(IotOtaTaskRecordDO::getId, id)
|
||||
.in(IotOtaTaskRecordDO::getStatus, whereStatuses));
|
||||
}
|
||||
|
||||
default void updateListByIdAndStatus(Collection<Long> ids, Collection<Integer> whereStatuses,
|
||||
IotOtaTaskRecordDO updateObj) {
|
||||
update(updateObj, new LambdaUpdateWrapper<IotOtaTaskRecordDO>()
|
||||
.in(IotOtaTaskRecordDO::getId, ids)
|
||||
.in(IotOtaTaskRecordDO::getStatus, whereStatuses));
|
||||
}
|
||||
|
||||
default List<IotOtaTaskRecordDO> selectListByDeviceIdAndStatus(Set<Long> deviceIds, Set<Integer> statuses) {
|
||||
|
||||
@@ -57,9 +57,10 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode OTA_TASK_CREATE_FAIL_DEVICE_EMPTY = new ErrorCode(1_050_008_103, "创建 OTA 任务失败,原因:没有可升级的设备");
|
||||
ErrorCode OTA_TASK_CANCEL_FAIL_STATUS_END = new ErrorCode(1_050_008_104, "取消 OTA 任务失败,原因:任务状态不是进行中");
|
||||
|
||||
// ========== OTA 升级任务相关 1-050-008-100 ==========
|
||||
// ========== OTA 升级任务记录相关 1-050-008-200 ==========
|
||||
|
||||
ErrorCode OTA_TASK_RECORD_NOT_EXISTS = new ErrorCode(1_050_008_200, "升级记录不存在");
|
||||
ErrorCode OTA_TASK_RECORD_CANCEL_FAIL_STATUS_ERROR = new ErrorCode(1_050_008_201, "取消 OTA 升级记录失败,原因:记录状态不是进行中");
|
||||
|
||||
// ========== IoT 数据流转规则 1-050-010-000 ==========
|
||||
ErrorCode DATA_RULE_NOT_EXISTS = new ErrorCode(1_050_010_000, "数据流转规则不存在");
|
||||
|
||||
@@ -32,8 +32,7 @@ public enum IotOtaTaskRecordStatusEnum implements ArrayValuable<Integer> {
|
||||
public static final Set<Integer> IN_PROCESS_STATUSES = SetUtils.asSet(
|
||||
PENDING.getStatus(),
|
||||
PUSHED.getStatus(),
|
||||
UPGRADING.getStatus(),
|
||||
SUCCESS.getStatus());
|
||||
UPGRADING.getStatus());
|
||||
|
||||
public static final List<Integer> PRIORITY_STATUSES = Arrays.asList(
|
||||
SUCCESS.getStatus(),
|
||||
|
||||
@@ -16,7 +16,7 @@ import java.util.Arrays;
|
||||
public enum IotOtaTaskStatusEnum implements ArrayValuable<Integer> {
|
||||
|
||||
IN_PROGRESS(10), // 进行中(升级中)
|
||||
COMPLETED(20), // 已完成(包括全部成功、部分成功)
|
||||
END(20), // 已结束(包括全部成功、部分成功)
|
||||
CANCELED(30),; // 已取消(一般是主动取消任务)
|
||||
|
||||
public static final Integer[] ARRAYS = Arrays.stream(values())
|
||||
|
||||
@@ -65,4 +65,11 @@ public interface IotOtaTaskRecordService {
|
||||
*/
|
||||
List<IotOtaTaskRecordDO> getOtaTaskRecordListByDeviceIdAndStatus(Set<Long> deviceIds, Set<Integer> statuses);
|
||||
|
||||
/**
|
||||
* 取消 OTA 升级记录
|
||||
*
|
||||
* @param id 记录编号
|
||||
*/
|
||||
void cancelOtaTaskRecord(Long id);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.iocoder.yudao.module.iot.service.ota;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordPageReqVO;
|
||||
@@ -12,14 +13,12 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.OTA_TASK_RECORD_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.OTA_TASK_RECORD_CANCEL_FAIL_STATUS_ERROR;
|
||||
|
||||
/**
|
||||
* OTA 升级任务记录 Service 实现类
|
||||
@@ -32,6 +31,9 @@ public class IotOtaTaskRecordServiceImpl implements IotOtaTaskRecordService {
|
||||
@Resource
|
||||
private IotOtaTaskRecordMapper otaTaskRecordMapper;
|
||||
|
||||
@Resource
|
||||
private IotOtaTaskService otaTaskService;
|
||||
|
||||
@Override
|
||||
public void createOtaTaskRecordList(List<IotDeviceDO> devices, Long firmwareId, Long taskId) {
|
||||
List<IotOtaTaskRecordDO> records = convertList(devices, device ->
|
||||
@@ -75,14 +77,16 @@ public class IotOtaTaskRecordServiceImpl implements IotOtaTaskRecordService {
|
||||
|
||||
@Override
|
||||
public void cancelTaskRecordListByTaskId(Long taskId) {
|
||||
// 设置取消记录的描述
|
||||
IotOtaTaskRecordDO updateRecord = IotOtaTaskRecordDO.builder()
|
||||
.status(IotOtaTaskRecordStatusEnum.CANCELED.getStatus())
|
||||
.description("管理员取消升级任务")
|
||||
.build();
|
||||
|
||||
otaTaskRecordMapper.updateByTaskIdAndStatus(
|
||||
taskId, IotOtaTaskRecordStatusEnum.PENDING.getStatus(), updateRecord);
|
||||
List<IotOtaTaskRecordDO> records = otaTaskRecordMapper.selectListByTaskIdAndStatus(
|
||||
taskId, IotOtaTaskRecordStatusEnum.IN_PROCESS_STATUSES);
|
||||
if (CollUtil.isEmpty(records)) {
|
||||
return;
|
||||
}
|
||||
// 批量更新
|
||||
Collection<Long> ids = convertSet(records, IotOtaTaskRecordDO::getId);
|
||||
otaTaskRecordMapper.updateListByIdAndStatus(ids, IotOtaTaskRecordStatusEnum.IN_PROCESS_STATUSES,
|
||||
IotOtaTaskRecordDO.builder().status(IotOtaTaskRecordStatusEnum.CANCELED.getStatus())
|
||||
.description(IotOtaTaskRecordDO.DESCRIPTION_CANCEL_BY_RECORD).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -90,6 +94,23 @@ public class IotOtaTaskRecordServiceImpl implements IotOtaTaskRecordService {
|
||||
return otaTaskRecordMapper.selectListByDeviceIdAndStatus(deviceIds, statuses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelOtaTaskRecord(Long id) {
|
||||
// 1. 校验记录是否存在
|
||||
IotOtaTaskRecordDO record = validateUpgradeRecordExists(id);
|
||||
|
||||
// 2. 更新记录状态为取消
|
||||
int updateCount = otaTaskRecordMapper.updateByIdAndStatus(record.getId(), IotOtaTaskRecordStatusEnum.IN_PROCESS_STATUSES,
|
||||
IotOtaTaskRecordDO.builder().id(id).status(IotOtaTaskRecordStatusEnum.CANCELED.getStatus())
|
||||
.description(IotOtaTaskRecordDO.DESCRIPTION_CANCEL_BY_RECORD).build());
|
||||
if (updateCount == 0) {
|
||||
throw exception(OTA_TASK_RECORD_CANCEL_FAIL_STATUS_ERROR);
|
||||
}
|
||||
|
||||
// 3. 检查并更新任务状态
|
||||
checkAndUpdateOtaTaskStatus(record.getTaskId());
|
||||
}
|
||||
|
||||
private IotOtaTaskRecordDO validateUpgradeRecordExists(Long id) {
|
||||
IotOtaTaskRecordDO upgradeRecord = otaTaskRecordMapper.selectById(id);
|
||||
if (upgradeRecord == null) {
|
||||
@@ -98,4 +119,20 @@ public class IotOtaTaskRecordServiceImpl implements IotOtaTaskRecordService {
|
||||
return upgradeRecord;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查并更新任务状态
|
||||
* 如果任务下没有进行中的记录,则将任务状态更新为已结束
|
||||
*/
|
||||
private void checkAndUpdateOtaTaskStatus(Long taskId) {
|
||||
// 如果还有进行中的记录,直接返回
|
||||
Long inProcessCount = otaTaskRecordMapper.selectCountByTaskIdAndStatus(
|
||||
taskId, IotOtaTaskRecordStatusEnum.IN_PROCESS_STATUSES);
|
||||
if (inProcessCount > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 没有进行中的记录,将任务状态更新为已结束
|
||||
otaTaskService.updateOtaTaskStatusEnd(taskId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -44,4 +44,11 @@ public interface IotOtaTaskService {
|
||||
*/
|
||||
PageResult<IotOtaTaskDO> getOtaTaskPage(@Valid IotOtaTaskPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 更新 OTA 任务状态为已结束
|
||||
*
|
||||
* @param id 任务编号
|
||||
*/
|
||||
void updateOtaTaskStatusEnd(Long id);
|
||||
|
||||
}
|
||||
|
||||
@@ -99,7 +99,16 @@ public class IotOtaTaskServiceImpl implements IotOtaTaskService {
|
||||
|
||||
@Override
|
||||
public PageResult<IotOtaTaskDO> getOtaTaskPage(IotOtaTaskPageReqVO pageReqVO) {
|
||||
return otaTaskMapper.selectUpgradeTaskPage(pageReqVO);
|
||||
return otaTaskMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateOtaTaskStatusEnd(Long taskId) {
|
||||
int updateCount = otaTaskMapper.updateByIdAndStatus(taskId, IotOtaTaskStatusEnum.IN_PROGRESS.getStatus(),
|
||||
new IotOtaTaskDO().setStatus(IotOtaTaskStatusEnum.END.getStatus()));
|
||||
if (updateCount == 0) {
|
||||
log.warn("[updateOtaTaskStatusEnd][任务({})不存在或状态不是进行中,无法更新]", taskId);
|
||||
}
|
||||
}
|
||||
|
||||
private List<IotDeviceDO> validateOtaTaskDeviceScope(IotOtaTaskCreateReqVO createReqVO, Long productId) {
|
||||
|
||||
Reference in New Issue
Block a user