Commit 97260b8efeedc2a8e51c534f3517463e92403e1a

Authored by YunaiV
1 parent 53c7ce22

feat:【IoT 物联网】新增告警恢复场景规则执行类 IotAlertRecoverSceneRuleAction

yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertRecordController.java
@@ -18,6 +18,7 @@ import org.springframework.validation.annotation.Validated; @@ -18,6 +18,7 @@ import org.springframework.validation.annotation.Validated;
18 import org.springframework.web.bind.annotation.*; 18 import org.springframework.web.bind.annotation.*;
19 19
20 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 20 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  21 +import static java.util.Collections.singleton;
21 22
22 @Tag(name = "管理后台 - IoT 告警记录") 23 @Tag(name = "管理后台 - IoT 告警记录")
23 @RestController 24 @RestController
@@ -49,7 +50,7 @@ public class IotAlertRecordController { @@ -49,7 +50,7 @@ public class IotAlertRecordController {
49 @Operation(summary = "处理告警记录") 50 @Operation(summary = "处理告警记录")
50 @PreAuthorize("@ss.hasPermission('iot:alert-record:process')") 51 @PreAuthorize("@ss.hasPermission('iot:alert-record:process')")
51 public CommonResult<Boolean> processAlertRecord(@Valid @RequestBody IotAlertRecordProcessReqVO processReqVO) { 52 public CommonResult<Boolean> processAlertRecord(@Valid @RequestBody IotAlertRecordProcessReqVO processReqVO) {
52 - alertRecordService.processAlertRecord(processReqVO); 53 + alertRecordService.processAlertRecordList(singleton(processReqVO.getId()), processReqVO.getProcessRemark());
53 return success(true); 54 return success(true);
54 } 55 }
55 56
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertRecordDO.java
@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; 4 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
5 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; 5 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
6 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; 6 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
  7 +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
7 import com.baomidou.mybatisplus.annotation.KeySequence; 8 import com.baomidou.mybatisplus.annotation.KeySequence;
8 import com.baomidou.mybatisplus.annotation.TableField; 9 import com.baomidou.mybatisplus.annotation.TableField;
9 import com.baomidou.mybatisplus.annotation.TableId; 10 import com.baomidou.mybatisplus.annotation.TableId;
@@ -51,6 +52,12 @@ public class IotAlertRecordDO extends BaseDO { @@ -51,6 +52,12 @@ public class IotAlertRecordDO extends BaseDO {
51 * 字典 {@link cn.iocoder.yudao.module.iot.enums.DictTypeConstants#ALERT_LEVEL} 52 * 字典 {@link cn.iocoder.yudao.module.iot.enums.DictTypeConstants#ALERT_LEVEL}
52 */ 53 */
53 private Integer configLevel; 54 private Integer configLevel;
  55 + /**
  56 + * 场景规则编号
  57 + *
  58 + * 关联 {@link IotRuleSceneDO#getId()}
  59 + */
  60 + private Long sceneRuleId;
54 61
55 /** 62 /**
56 * 产品编号 63 * 产品编号
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertRecordMapper.java
@@ -5,8 +5,12 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; @@ -5,8 +5,12 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordPageReqVO; 6 import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordPageReqVO;
7 import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO; 7 import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO;
  8 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
8 import org.apache.ibatis.annotations.Mapper; 9 import org.apache.ibatis.annotations.Mapper;
9 10
  11 +import java.util.Collection;
  12 +import java.util.List;
  13 +
10 /** 14 /**
11 * IoT 告警记录 Mapper 15 * IoT 告警记录 Mapper
12 * 16 *
@@ -26,4 +30,17 @@ public interface IotAlertRecordMapper extends BaseMapperX&lt;IotAlertRecordDO&gt; { @@ -26,4 +30,17 @@ public interface IotAlertRecordMapper extends BaseMapperX&lt;IotAlertRecordDO&gt; {
26 .orderByDesc(IotAlertRecordDO::getId)); 30 .orderByDesc(IotAlertRecordDO::getId));
27 } 31 }
28 32
  33 + default List<IotAlertRecordDO> selectListBySceneRuleId(Long sceneRuleId, Long deviceId, Boolean processStatus) {
  34 + return selectList(new LambdaQueryWrapperX<IotAlertRecordDO>()
  35 + .eq(IotAlertRecordDO::getSceneRuleId, sceneRuleId)
  36 + .eqIfPresent(IotAlertRecordDO::getDeviceId, deviceId)
  37 + .eqIfPresent(IotAlertRecordDO::getProcessStatus, processStatus)
  38 + .orderByDesc(IotAlertRecordDO::getId));
  39 + }
  40 +
  41 + default int updateList(Collection<Long> ids, IotAlertRecordDO updateObj) {
  42 + return update(updateObj, new LambdaUpdateWrapper<IotAlertRecordDO>()
  43 + .in(IotAlertRecordDO::getId, ids));
  44 + }
  45 +
29 } 46 }
30 \ No newline at end of file 47 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordService.java
@@ -2,10 +2,13 @@ package cn.iocoder.yudao.module.iot.service.alert; @@ -2,10 +2,13 @@ package cn.iocoder.yudao.module.iot.service.alert;
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.alert.vo.recrod.IotAlertRecordPageReqVO; 4 import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordPageReqVO;
5 -import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordProcessReqVO;  
6 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; 5 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
7 import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; 6 import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO;
8 import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO; 7 import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO;
  8 +import jakarta.validation.constraints.NotNull;
  9 +
  10 +import java.util.Collection;
  11 +import java.util.List;
9 12
10 /** 13 /**
11 * IoT 告警记录 Service 接口 14 * IoT 告警记录 Service 接口
@@ -31,19 +34,32 @@ public interface IotAlertRecordService { @@ -31,19 +34,32 @@ public interface IotAlertRecordService {
31 PageResult<IotAlertRecordDO> getAlertRecordPage(IotAlertRecordPageReqVO pageReqVO); 34 PageResult<IotAlertRecordDO> getAlertRecordPage(IotAlertRecordPageReqVO pageReqVO);
32 35
33 /** 36 /**
  37 + * 获得指定场景规则的告警记录列表
  38 + *
  39 + * @param sceneRuleId 场景规则编号
  40 + * @param deviceId 设备编号
  41 + * @param processStatus 处理状态,允许空
  42 + * @return 告警记录列表
  43 + */
  44 + List<IotAlertRecordDO> getAlertRecordListBySceneRuleId(@NotNull(message = "场景规则编号不能为空") Long sceneRuleId,
  45 + Long deviceId, Boolean processStatus);
  46 +
  47 + /**
34 * 处理告警记录 48 * 处理告警记录
35 * 49 *
36 - * @param processReqVO 处理请求 50 + * @param ids 告警记录编号
  51 + * @param remark 处理结果(备注)
37 */ 52 */
38 - void processAlertRecord(IotAlertRecordProcessReqVO processReqVO); 53 + void processAlertRecordList(Collection<Long> ids, String remark);
39 54
40 /** 55 /**
41 - * 创建告警记录 56 + * 创建告警记录(包含场景规则编号)
42 * 57 *
43 * @param config 告警配置 58 * @param config 告警配置
  59 + * @param sceneRuleId 场景规则编号
44 * @param deviceMessage 设备消息,可为空 60 * @param deviceMessage 设备消息,可为空
45 * @return 告警记录编号 61 * @return 告警记录编号
46 */ 62 */
47 - Long createAlertRecord(IotAlertConfigDO config, IotDeviceMessage deviceMessage); 63 + Long createAlertRecord(IotAlertConfigDO config, Long sceneRuleId, IotDeviceMessage deviceMessage);
48 64
49 } 65 }
50 \ No newline at end of file 66 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordServiceImpl.java
1 package cn.iocoder.yudao.module.iot.service.alert; 1 package cn.iocoder.yudao.module.iot.service.alert;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordPageReqVO; 5 import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordPageReqVO;
5 -import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordProcessReqVO;  
6 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; 6 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
7 import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; 7 import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO;
8 import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO; 8 import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO;
@@ -13,8 +13,8 @@ import jakarta.annotation.Resource; @@ -13,8 +13,8 @@ import jakarta.annotation.Resource;
13 import org.springframework.stereotype.Service; 13 import org.springframework.stereotype.Service;
14 import org.springframework.validation.annotation.Validated; 14 import org.springframework.validation.annotation.Validated;
15 15
16 -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;  
17 -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.ALERT_RECORD_NOT_EXISTS; 16 +import java.util.Collection;
  17 +import java.util.List;
18 18
19 /** 19 /**
20 * IoT 告警记录 Service 实现类 20 * IoT 告警记录 Service 实现类
@@ -42,35 +42,35 @@ public class IotAlertRecordServiceImpl implements IotAlertRecordService { @@ -42,35 +42,35 @@ public class IotAlertRecordServiceImpl implements IotAlertRecordService {
42 } 42 }
43 43
44 @Override 44 @Override
45 - public void processAlertRecord(IotAlertRecordProcessReqVO processReqVO) {  
46 - // 校验告警记录是否存在  
47 - IotAlertRecordDO alertRecord = alertRecordMapper.selectById(processReqVO.getId());  
48 - if (alertRecord == null) {  
49 - throw exception(ALERT_RECORD_NOT_EXISTS);  
50 - } 45 + public List<IotAlertRecordDO> getAlertRecordListBySceneRuleId(Long sceneRuleId, Long deviceId, Boolean processStatus) {
  46 + return alertRecordMapper.selectListBySceneRuleId(sceneRuleId, deviceId, processStatus);
  47 + }
51 48
52 - // 更新处理状态和备注  
53 - alertRecordMapper.updateById(IotAlertRecordDO.builder()  
54 - .id(processReqVO.getId())  
55 - .processStatus(true)  
56 - .processRemark(processReqVO.getProcessRemark())  
57 - .build()); 49 + @Override
  50 + public void processAlertRecordList(Collection<Long> ids, String processRemark) {
  51 + if (CollUtil.isEmpty(ids)) {
  52 + return;
  53 + }
  54 + // 批量更新告警记录的处理状态
  55 + alertRecordMapper.updateList(ids, IotAlertRecordDO.builder()
  56 + .processStatus(true).processRemark(processRemark).build());
58 } 57 }
59 58
60 @Override 59 @Override
61 - public Long createAlertRecord(IotAlertConfigDO config, IotDeviceMessage message) { 60 + public Long createAlertRecord(IotAlertConfigDO config, Long sceneRuleId, IotDeviceMessage message) {
62 // 构建告警记录 61 // 构建告警记录
63 IotAlertRecordDO.IotAlertRecordDOBuilder builder = IotAlertRecordDO.builder() 62 IotAlertRecordDO.IotAlertRecordDOBuilder builder = IotAlertRecordDO.builder()
64 .configId(config.getId()).configName(config.getName()).configLevel(config.getLevel()) 63 .configId(config.getId()).configName(config.getName()).configLevel(config.getLevel())
65 - .processStatus(false); 64 + .sceneRuleId(sceneRuleId).processStatus(false);
66 if (message != null) { 65 if (message != null) {
67 builder.deviceMessage(message); 66 builder.deviceMessage(message);
68 // 填充设备信息 67 // 填充设备信息
69 IotDeviceDO device = deviceService.getDeviceFromCache(message.getDeviceId()); 68 IotDeviceDO device = deviceService.getDeviceFromCache(message.getDeviceId());
70 - if (device!= null) { 69 + if (device != null) {
71 builder.productId(device.getProductId()).deviceId(device.getId()); 70 builder.productId(device.getProductId()).deviceId(device.getId());
72 } 71 }
73 } 72 }
  73 +
74 // 插入记录 74 // 插入记录
75 IotAlertRecordDO record = builder.build(); 75 IotAlertRecordDO record = builder.build();
76 alertRecordMapper.insert(record); 76 alertRecordMapper.insert(record);
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java
@@ -8,6 +8,9 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; @@ -8,6 +8,9 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
8 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; 8 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum;
9 import cn.iocoder.yudao.module.iot.service.alert.IotAlertConfigService; 9 import cn.iocoder.yudao.module.iot.service.alert.IotAlertConfigService;
10 import cn.iocoder.yudao.module.iot.service.alert.IotAlertRecordService; 10 import cn.iocoder.yudao.module.iot.service.alert.IotAlertRecordService;
  11 +import cn.iocoder.yudao.module.system.api.mail.MailSendApi;
  12 +import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
  13 +import cn.iocoder.yudao.module.system.api.sms.SmsSendApi;
11 import jakarta.annotation.Resource; 14 import jakarta.annotation.Resource;
12 import org.springframework.stereotype.Component; 15 import org.springframework.stereotype.Component;
13 16
@@ -25,10 +28,16 @@ public class IotAlertTriggerSceneRuleAction implements IotSceneRuleAction { @@ -25,10 +28,16 @@ public class IotAlertTriggerSceneRuleAction implements IotSceneRuleAction {
25 28
26 @Resource 29 @Resource
27 private IotAlertConfigService alertConfigService; 30 private IotAlertConfigService alertConfigService;
28 -  
29 @Resource 31 @Resource
30 private IotAlertRecordService alertRecordService; 32 private IotAlertRecordService alertRecordService;
31 33
  34 + @Resource
  35 + private SmsSendApi smsSendApi;
  36 + @Resource
  37 + private MailSendApi mailSendApi;
  38 + @Resource
  39 + private NotifyMessageSendApi notifyMessageSendApi;
  40 +
32 @Override 41 @Override
33 public void execute(@Nullable IotDeviceMessage message, 42 public void execute(@Nullable IotDeviceMessage message,
34 IotRuleSceneDO rule, IotRuleSceneDO.ActionConfig actionConfig) throws Exception { 43 IotRuleSceneDO rule, IotRuleSceneDO.ActionConfig actionConfig) throws Exception {
@@ -37,8 +46,19 @@ public class IotAlertTriggerSceneRuleAction implements IotSceneRuleAction { @@ -37,8 +46,19 @@ public class IotAlertTriggerSceneRuleAction implements IotSceneRuleAction {
37 if (CollUtil.isEmpty(alertConfigs)) { 46 if (CollUtil.isEmpty(alertConfigs)) {
38 return; 47 return;
39 } 48 }
40 - alertConfigs.forEach(alertConfig ->  
41 - alertRecordService.createAlertRecord(alertConfig, message)); 49 + alertConfigs.forEach(alertConfig -> {
  50 + // 记录告警记录,传递场景规则ID
  51 + alertRecordService.createAlertRecord(alertConfig, rule.getId(), message);
  52 + // 发送告警消息
  53 + sendAlertMessage(alertConfig, message);
  54 + });
  55 + }
  56 +
  57 + private void sendAlertMessage(IotAlertConfigDO config, IotDeviceMessage deviceMessage) {
  58 + // TODO @芋艿:等场景联动开发完,再实现
  59 + // TODO @芋艿:短信
  60 + // TODO @芋艿:邮箱
  61 + // TODO @芋艿:站内信
42 } 62 }
43 63
44 @Override 64 @Override