From 97260b8efeedc2a8e51c534f3517463e92403e1a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 28 Jun 2025 19:37:28 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9=E8=81=94?= =?UTF-8?q?=E7=BD=91=E3=80=91=E6=96=B0=E5=A2=9E=E5=91=8A=E8=AD=A6=E6=81=A2?= =?UTF-8?q?=E5=A4=8D=E5=9C=BA=E6=99=AF=E8=A7=84=E5=88=99=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E7=B1=BB=20IotAlertRecoverSceneRuleAction?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/alert/IotAlertRecordController.java | 3 +- .../dataobject/alert/IotAlertRecordDO.java | 7 ++++ .../dal/mysql/alert/IotAlertRecordMapper.java | 17 +++++++++ .../service/alert/IotAlertRecordService.java | 28 +++++++++++--- .../alert/IotAlertRecordServiceImpl.java | 38 +++++++++---------- .../IotAlertTriggerSceneRuleAction.java | 26 +++++++++++-- 6 files changed, 90 insertions(+), 29 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertRecordController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertRecordController.java index d75f42e3f4..91f15b989c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertRecordController.java +++ b/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; import org.springframework.web.bind.annotation.*; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static java.util.Collections.singleton; @Tag(name = "管理后台 - IoT 告警记录") @RestController @@ -49,7 +50,7 @@ public class IotAlertRecordController { @Operation(summary = "处理告警记录") @PreAuthorize("@ss.hasPermission('iot:alert-record:process')") public CommonResult processAlertRecord(@Valid @RequestBody IotAlertRecordProcessReqVO processReqVO) { - alertRecordService.processAlertRecord(processReqVO); + alertRecordService.processAlertRecordList(singleton(processReqVO.getId()), processReqVO.getProcessRemark()); return success(true); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertRecordDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertRecordDO.java index c057f85ccf..588b27068e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertRecordDO.java +++ b/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; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; @@ -51,6 +52,12 @@ public class IotAlertRecordDO extends BaseDO { * 字典 {@link cn.iocoder.yudao.module.iot.enums.DictTypeConstants#ALERT_LEVEL} */ private Integer configLevel; + /** + * 场景规则编号 + * + * 关联 {@link IotRuleSceneDO#getId()} + */ + private Long sceneRuleId; /** * 产品编号 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertRecordMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertRecordMapper.java index 3d29c5ff81..f23fe60f74 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertRecordMapper.java +++ b/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; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; +import java.util.Collection; +import java.util.List; + /** * IoT 告警记录 Mapper * @@ -26,4 +30,17 @@ public interface IotAlertRecordMapper extends BaseMapperX { .orderByDesc(IotAlertRecordDO::getId)); } + default List selectListBySceneRuleId(Long sceneRuleId, Long deviceId, Boolean processStatus) { + return selectList(new LambdaQueryWrapperX() + .eq(IotAlertRecordDO::getSceneRuleId, sceneRuleId) + .eqIfPresent(IotAlertRecordDO::getDeviceId, deviceId) + .eqIfPresent(IotAlertRecordDO::getProcessStatus, processStatus) + .orderByDesc(IotAlertRecordDO::getId)); + } + + default int updateList(Collection ids, IotAlertRecordDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .in(IotAlertRecordDO::getId, ids)); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordService.java index 57ad9a3762..68a2da97c9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordService.java +++ b/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; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordProcessReqVO; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO; +import jakarta.validation.constraints.NotNull; + +import java.util.Collection; +import java.util.List; /** * IoT 告警记录 Service 接口 @@ -31,19 +34,32 @@ public interface IotAlertRecordService { PageResult getAlertRecordPage(IotAlertRecordPageReqVO pageReqVO); /** - * 处理告警记录 + * 获得指定场景规则的告警记录列表 * - * @param processReqVO 处理请求 + * @param sceneRuleId 场景规则编号 + * @param deviceId 设备编号 + * @param processStatus 处理状态,允许空 + * @return 告警记录列表 */ - void processAlertRecord(IotAlertRecordProcessReqVO processReqVO); + List getAlertRecordListBySceneRuleId(@NotNull(message = "场景规则编号不能为空") Long sceneRuleId, + Long deviceId, Boolean processStatus); /** - * 创建告警记录 + * 处理告警记录 + * + * @param ids 告警记录编号 + * @param remark 处理结果(备注) + */ + void processAlertRecordList(Collection ids, String remark); + + /** + * 创建告警记录(包含场景规则编号) * * @param config 告警配置 + * @param sceneRuleId 场景规则编号 * @param deviceMessage 设备消息,可为空 * @return 告警记录编号 */ - Long createAlertRecord(IotAlertConfigDO config, IotDeviceMessage deviceMessage); + Long createAlertRecord(IotAlertConfigDO config, Long sceneRuleId, IotDeviceMessage deviceMessage); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordServiceImpl.java index 72b13d2546..34a673a4b5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordServiceImpl.java @@ -1,8 +1,8 @@ package cn.iocoder.yudao.module.iot.service.alert; +import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordProcessReqVO; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO; @@ -13,8 +13,8 @@ import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.ALERT_RECORD_NOT_EXISTS; +import java.util.Collection; +import java.util.List; /** * IoT 告警记录 Service 实现类 @@ -42,35 +42,35 @@ public class IotAlertRecordServiceImpl implements IotAlertRecordService { } @Override - public void processAlertRecord(IotAlertRecordProcessReqVO processReqVO) { - // 校验告警记录是否存在 - IotAlertRecordDO alertRecord = alertRecordMapper.selectById(processReqVO.getId()); - if (alertRecord == null) { - throw exception(ALERT_RECORD_NOT_EXISTS); - } - - // 更新处理状态和备注 - alertRecordMapper.updateById(IotAlertRecordDO.builder() - .id(processReqVO.getId()) - .processStatus(true) - .processRemark(processReqVO.getProcessRemark()) - .build()); + public List getAlertRecordListBySceneRuleId(Long sceneRuleId, Long deviceId, Boolean processStatus) { + return alertRecordMapper.selectListBySceneRuleId(sceneRuleId, deviceId, processStatus); } @Override - public Long createAlertRecord(IotAlertConfigDO config, IotDeviceMessage message) { + public void processAlertRecordList(Collection ids, String processRemark) { + if (CollUtil.isEmpty(ids)) { + return; + } + // 批量更新告警记录的处理状态 + alertRecordMapper.updateList(ids, IotAlertRecordDO.builder() + .processStatus(true).processRemark(processRemark).build()); + } + + @Override + public Long createAlertRecord(IotAlertConfigDO config, Long sceneRuleId, IotDeviceMessage message) { // 构建告警记录 IotAlertRecordDO.IotAlertRecordDOBuilder builder = IotAlertRecordDO.builder() .configId(config.getId()).configName(config.getName()).configLevel(config.getLevel()) - .processStatus(false); + .sceneRuleId(sceneRuleId).processStatus(false); if (message != null) { builder.deviceMessage(message); // 填充设备信息 IotDeviceDO device = deviceService.getDeviceFromCache(message.getDeviceId()); - if (device!= null) { + if (device != null) { builder.productId(device.getProductId()).deviceId(device.getId()); } } + // 插入记录 IotAlertRecordDO record = builder.build(); alertRecordMapper.insert(record); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java index 8ac33fcefc..df34eea16f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java +++ b/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; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; import cn.iocoder.yudao.module.iot.service.alert.IotAlertConfigService; import cn.iocoder.yudao.module.iot.service.alert.IotAlertRecordService; +import cn.iocoder.yudao.module.system.api.mail.MailSendApi; +import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; +import cn.iocoder.yudao.module.system.api.sms.SmsSendApi; import jakarta.annotation.Resource; import org.springframework.stereotype.Component; @@ -25,10 +28,16 @@ public class IotAlertTriggerSceneRuleAction implements IotSceneRuleAction { @Resource private IotAlertConfigService alertConfigService; - @Resource private IotAlertRecordService alertRecordService; + @Resource + private SmsSendApi smsSendApi; + @Resource + private MailSendApi mailSendApi; + @Resource + private NotifyMessageSendApi notifyMessageSendApi; + @Override public void execute(@Nullable IotDeviceMessage message, IotRuleSceneDO rule, IotRuleSceneDO.ActionConfig actionConfig) throws Exception { @@ -37,8 +46,19 @@ public class IotAlertTriggerSceneRuleAction implements IotSceneRuleAction { if (CollUtil.isEmpty(alertConfigs)) { return; } - alertConfigs.forEach(alertConfig -> - alertRecordService.createAlertRecord(alertConfig, message)); + alertConfigs.forEach(alertConfig -> { + // 记录告警记录,传递场景规则ID + alertRecordService.createAlertRecord(alertConfig, rule.getId(), message); + // 发送告警消息 + sendAlertMessage(alertConfig, message); + }); + } + + private void sendAlertMessage(IotAlertConfigDO config, IotDeviceMessage deviceMessage) { + // TODO @芋艿:等场景联动开发完,再实现 + // TODO @芋艿:短信 + // TODO @芋艿:邮箱 + // TODO @芋艿:站内信 } @Override