feat:【IoT 物联网】新增告警记录管理功能,包括告警记录接口和前端展示页面
This commit is contained in:
@@ -1,16 +1,19 @@
|
||||
package cn.iocoder.yudao.framework.mybatis.config;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.handler.DefaultDBFieldHandler;
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import com.baomidou.mybatisplus.extension.incrementer.*;
|
||||
import com.baomidou.mybatisplus.extension.parser.JsqlParserGlobal;
|
||||
import com.baomidou.mybatisplus.extension.parser.cache.JdkSerialCaffeineJsqlParseCache;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
@@ -18,6 +21,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@@ -73,4 +77,11 @@ public class YudaoMybatisAutoConfiguration {
|
||||
throw new IllegalArgumentException(StrUtil.format("DbType{} 找不到合适的 IKeyGenerator 实现类", dbType));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JacksonTypeHandler jacksonTypeHandler(List<ObjectMapper> objectMappers) {
|
||||
// 特殊:设置 JacksonTypeHandler 的 ObjectMapper!
|
||||
JacksonTypeHandler.setObjectMapper(CollUtil.getFirst(objectMappers));
|
||||
return new JacksonTypeHandler(Object.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.alert;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
@@ -15,15 +16,18 @@ import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
|
||||
|
||||
@Tag(name = "管理后台 - IoT 告警配置")
|
||||
@@ -34,7 +38,7 @@ public class IotAlertConfigController {
|
||||
|
||||
@Resource
|
||||
private IotAlertConfigService alertConfigService;
|
||||
|
||||
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
|
||||
@@ -76,12 +80,26 @@ public class IotAlertConfigController {
|
||||
@PreAuthorize("@ss.hasPermission('iot:alert-config:query')")
|
||||
public CommonResult<PageResult<IotAlertConfigRespVO>> getAlertConfigPage(@Valid IotAlertConfigPageReqVO pageReqVO) {
|
||||
PageResult<IotAlertConfigDO> pageResult = alertConfigService.getAlertConfigPage(pageReqVO);
|
||||
|
||||
// 转换返回
|
||||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
|
||||
convertSetByFlatMap(pageResult.getList(), config -> config.getReceiveUserIds().stream()));
|
||||
return success(BeanUtils.toBean(pageResult, IotAlertConfigRespVO.class, vo ->
|
||||
vo.setReceiveUserNames(vo.getReceiveUserIds().stream().map(userMap::get)
|
||||
.filter(Objects::nonNull).map(AdminUserRespDTO::getNickname).collect(Collectors.toList()))));
|
||||
return success(BeanUtils.toBean(pageResult, IotAlertConfigRespVO.class, vo -> {
|
||||
vo.setReceiveUserNames(vo.getReceiveUserIds().stream()
|
||||
.map(userMap::get)
|
||||
.filter(Objects::nonNull)
|
||||
.map(AdminUserRespDTO::getNickname)
|
||||
.collect(Collectors.toList()));
|
||||
}));
|
||||
}
|
||||
|
||||
@GetMapping("/simple-list")
|
||||
@Operation(summary = "获得告警配置简单列表", description = "只包含被开启的告警配置,主要用于前端的下拉选项")
|
||||
@PreAuthorize("@ss.hasPermission('iot:alert-config:query')")
|
||||
public CommonResult<List<IotAlertConfigRespVO>> getAlertConfigSimpleList() {
|
||||
List<IotAlertConfigDO> list = alertConfigService.getAlertConfigListByStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
return success(convertList(list, config -> // 只返回 id、name 字段
|
||||
new IotAlertConfigRespVO().setId(config.getId()).setName(config.getName())));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.alert;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
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.controller.admin.alert.vo.recrod.IotAlertRecordRespVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO;
|
||||
import cn.iocoder.yudao.module.iot.service.alert.IotAlertRecordService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - IoT 告警记录")
|
||||
@RestController
|
||||
@RequestMapping("/iot/alert-record")
|
||||
@Validated
|
||||
public class IotAlertRecordController {
|
||||
|
||||
@Resource
|
||||
private IotAlertRecordService alertRecordService;
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得告警记录")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('iot:alert-record:query')")
|
||||
public CommonResult<IotAlertRecordRespVO> getAlertRecord(@RequestParam("id") Long id) {
|
||||
IotAlertRecordDO alertRecord = alertRecordService.getAlertRecord(id);
|
||||
return success(BeanUtils.toBean(alertRecord, IotAlertRecordRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得告警记录分页")
|
||||
@PreAuthorize("@ss.hasPermission('iot:alert-record:query')")
|
||||
public CommonResult<PageResult<IotAlertRecordRespVO>> getAlertRecordPage(@Valid IotAlertRecordPageReqVO pageReqVO) {
|
||||
PageResult<IotAlertRecordDO> pageResult = alertRecordService.getAlertRecordPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, IotAlertRecordRespVO.class));
|
||||
}
|
||||
|
||||
@PutMapping("/process")
|
||||
@Operation(summary = "处理告警记录")
|
||||
@PreAuthorize("@ss.hasPermission('iot:alert-record:process')")
|
||||
public CommonResult<Boolean> processAlertRecord(@Valid @RequestBody IotAlertRecordProcessReqVO processReqVO) {
|
||||
alertRecordService.processAlertRecord(processReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 告警记录分页 Request VO")
|
||||
@Data
|
||||
public class IotAlertRecordPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "告警配置编号", example = "29320")
|
||||
private Long configId;
|
||||
|
||||
@Schema(description = "告警级别", example = "1")
|
||||
private Integer level;
|
||||
|
||||
@Schema(description = "产品编号", example = "2050")
|
||||
private Long productId;
|
||||
|
||||
@Schema(description = "设备编号", example = "21727")
|
||||
private String deviceId;
|
||||
|
||||
@Schema(description = "是否处理", example = "true")
|
||||
private Boolean processStatus;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 告警记录处理 Request VO")
|
||||
@Data
|
||||
public class IotAlertRecordProcessReqVO {
|
||||
|
||||
@Schema(description = "记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "记录编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "处理结果(备注)", requiredMode = Schema.RequiredMode.REQUIRED, example = "已处理告警,问题已解决")
|
||||
private String processRemark;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 告警记录 Response VO")
|
||||
@Data
|
||||
public class IotAlertRecordRespVO {
|
||||
|
||||
@Schema(description = "记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "19904")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "告警配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "29320")
|
||||
private Long configId;
|
||||
|
||||
@Schema(description = "告警名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
|
||||
private String configName;
|
||||
|
||||
@Schema(description = "告警级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer configLevel;
|
||||
|
||||
@Schema(description = "产品编号", example = "2050")
|
||||
private Long productId;
|
||||
|
||||
@Schema(description = "设备编号", example = "21727")
|
||||
private Long deviceId;
|
||||
|
||||
@Schema(description = "触发的设备消息")
|
||||
private IotDeviceMessage deviceMessage;
|
||||
|
||||
@Schema(description = "是否处理", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Boolean processStatus;
|
||||
|
||||
@Schema(description = "处理结果(备注)", example = "你说的对")
|
||||
private String processRemark;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -19,7 +19,7 @@ import lombok.NoArgsConstructor;
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@TableName("iot_alert_record")
|
||||
@TableName(value = "iot_alert_record", autoResultMap = true)
|
||||
@KeySequence("iot_alert_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@Builder
|
||||
@@ -44,6 +44,13 @@ public class IotAlertRecordDO extends BaseDO {
|
||||
* 冗余 {@link IotAlertConfigDO#getName()}
|
||||
*/
|
||||
private String configName;
|
||||
/**
|
||||
* 告警级别
|
||||
*
|
||||
* 冗余 {@link IotAlertConfigDO#getLevel()}
|
||||
* 字典 {@link cn.iocoder.yudao.module.iot.enums.DictTypeConstants#ALERT_LEVEL}
|
||||
*/
|
||||
private Integer configLevel;
|
||||
|
||||
/**
|
||||
* 产品编号
|
||||
@@ -56,7 +63,7 @@ public class IotAlertRecordDO extends BaseDO {
|
||||
*
|
||||
* 关联 {@link IotDeviceDO#getId()}
|
||||
*/
|
||||
private String deviceId;
|
||||
private Long deviceId;
|
||||
/**
|
||||
* 触发的设备消息
|
||||
*/
|
||||
|
||||
@@ -198,14 +198,6 @@ public class IotRuleSceneDO extends TenantBaseDO {
|
||||
*/
|
||||
private ActionDeviceControl deviceControl;
|
||||
|
||||
/**
|
||||
* 数据桥接编号
|
||||
*
|
||||
* 必填:当 {@link #type} 为 {@link IotRuleSceneActionTypeEnum#DATA_BRIDGE} 时
|
||||
* 关联:{@link IotDataSinkDO#getId()}
|
||||
*/
|
||||
private Long dataBridgeId;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,10 +3,13 @@ package cn.iocoder.yudao.module.iot.dal.mysql.alert;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConfigPageReqVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* IoT 告警配置 Mapper
|
||||
*
|
||||
@@ -23,4 +26,14 @@ public interface IotAlertConfigMapper extends BaseMapperX<IotAlertConfigDO> {
|
||||
.orderByDesc(IotAlertConfigDO::getId));
|
||||
}
|
||||
|
||||
default List<IotAlertConfigDO> selectListByStatus(Integer status) {
|
||||
return selectList(IotAlertConfigDO::getStatus, status);
|
||||
}
|
||||
|
||||
default List<IotAlertConfigDO> selectListBySceneRuleIdAndStatus(Long sceneRuleId, Integer status) {
|
||||
return selectList(new LambdaQueryWrapperX<IotAlertConfigDO>()
|
||||
.eq(IotAlertConfigDO::getStatus, status)
|
||||
.apply(MyBatisUtils.findInSet("scene_rule_id", sceneRuleId)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package cn.iocoder.yudao.module.iot.dal.mysql.alert;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
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 org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* IoT 告警记录 Mapper
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Mapper
|
||||
public interface IotAlertRecordMapper extends BaseMapperX<IotAlertRecordDO> {
|
||||
|
||||
default PageResult<IotAlertRecordDO> selectPage(IotAlertRecordPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<IotAlertRecordDO>()
|
||||
.eqIfPresent(IotAlertRecordDO::getConfigId, reqVO.getConfigId())
|
||||
.eqIfPresent(IotAlertRecordDO::getConfigLevel, reqVO.getLevel())
|
||||
.eqIfPresent(IotAlertRecordDO::getProductId, reqVO.getProductId())
|
||||
.eqIfPresent(IotAlertRecordDO::getDeviceId, reqVO.getDeviceId())
|
||||
.eqIfPresent(IotAlertRecordDO::getProcessStatus, reqVO.getProcessStatus())
|
||||
.betweenIfPresent(IotAlertRecordDO::getCreateTime, reqVO.getCreateTime())
|
||||
.orderByDesc(IotAlertRecordDO::getId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -67,4 +67,7 @@ public interface ErrorCodeConstants {
|
||||
// ========== IoT 告警配置 1-050-013-000 ==========
|
||||
ErrorCode ALERT_CONFIG_NOT_EXISTS = new ErrorCode(1_050_013_000, "IoT 告警配置不存在");
|
||||
|
||||
// ========== IoT 告警记录 1-050-014-000 ==========
|
||||
ErrorCode ALERT_RECORD_NOT_EXISTS = new ErrorCode(1_050_014_000, "IoT 告警记录不存在");
|
||||
|
||||
}
|
||||
@@ -10,8 +10,6 @@ import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
// TODO @puhui999:后面重构哈
|
||||
|
||||
/**
|
||||
* 针对 {@link IotDeviceMessage} 的消费者,处理数据流转
|
||||
*
|
||||
|
||||
@@ -6,6 +6,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConf
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* IoT 告警配置 Service 接口
|
||||
*
|
||||
@@ -51,4 +53,20 @@ public interface IotAlertConfigService {
|
||||
*/
|
||||
PageResult<IotAlertConfigDO> getAlertConfigPage(IotAlertConfigPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 获得告警配置列表
|
||||
*
|
||||
* @param status 状态
|
||||
* @return 告警配置列表
|
||||
*/
|
||||
List<IotAlertConfigDO> getAlertConfigListByStatus(Integer status);
|
||||
|
||||
/**
|
||||
* 获得告警配置列表
|
||||
*
|
||||
* @param sceneRuleId 场景流动规则编号
|
||||
* @return 告警配置列表
|
||||
*/
|
||||
List<IotAlertConfigDO> getAlertConfigListBySceneRuleIdAndStatus(Long sceneRuleId, Integer status);
|
||||
|
||||
}
|
||||
@@ -9,9 +9,12 @@ import cn.iocoder.yudao.module.iot.dal.mysql.alert.IotAlertConfigMapper;
|
||||
import cn.iocoder.yudao.module.iot.service.rule.scene.IotRuleSceneService;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.ALERT_CONFIG_NOT_EXISTS;
|
||||
|
||||
@@ -28,6 +31,7 @@ public class IotAlertConfigServiceImpl implements IotAlertConfigService {
|
||||
private IotAlertConfigMapper alertConfigMapper;
|
||||
|
||||
@Resource
|
||||
@Lazy // 延迟,避免循环依赖报错
|
||||
private IotRuleSceneService ruleSceneService;
|
||||
|
||||
@Resource
|
||||
@@ -39,6 +43,7 @@ public class IotAlertConfigServiceImpl implements IotAlertConfigService {
|
||||
ruleSceneService.validateRuleSceneList(createReqVO.getSceneRuleIds());
|
||||
adminUserApi.validateUserList(createReqVO.getReceiveUserIds());
|
||||
|
||||
// 插入
|
||||
IotAlertConfigDO alertConfig = BeanUtils.toBean(createReqVO, IotAlertConfigDO.class);
|
||||
alertConfigMapper.insert(alertConfig);
|
||||
return alertConfig.getId();
|
||||
@@ -81,4 +86,14 @@ public class IotAlertConfigServiceImpl implements IotAlertConfigService {
|
||||
return alertConfigMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IotAlertConfigDO> getAlertConfigListByStatus(Integer status) {
|
||||
return alertConfigMapper.selectListByStatus(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IotAlertConfigDO> getAlertConfigListBySceneRuleIdAndStatus(Long sceneRuleId, Integer status) {
|
||||
return alertConfigMapper.selectListBySceneRuleIdAndStatus(sceneRuleId, status);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* IoT 告警记录 Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface IotAlertRecordService {
|
||||
|
||||
/**
|
||||
* 获得告警记录
|
||||
*
|
||||
* @param id 编号
|
||||
* @return 告警记录
|
||||
*/
|
||||
IotAlertRecordDO getAlertRecord(Long id);
|
||||
|
||||
/**
|
||||
* 获得告警记录分页
|
||||
*
|
||||
* @param pageReqVO 分页查询
|
||||
* @return 告警记录分页
|
||||
*/
|
||||
PageResult<IotAlertRecordDO> getAlertRecordPage(IotAlertRecordPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 处理告警记录
|
||||
*
|
||||
* @param processReqVO 处理请求
|
||||
*/
|
||||
void processAlertRecord(IotAlertRecordProcessReqVO processReqVO);
|
||||
|
||||
/**
|
||||
* 创建告警记录
|
||||
*
|
||||
* @param config 告警配置
|
||||
* @param deviceMessage 设备消息,可为空
|
||||
* @return 告警记录编号
|
||||
*/
|
||||
Long createAlertRecord(IotAlertConfigDO config, IotDeviceMessage deviceMessage);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
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 cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.mysql.alert.IotAlertRecordMapper;
|
||||
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
|
||||
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;
|
||||
|
||||
/**
|
||||
* IoT 告警记录 Service 实现类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class IotAlertRecordServiceImpl implements IotAlertRecordService {
|
||||
|
||||
@Resource
|
||||
private IotAlertRecordMapper alertRecordMapper;
|
||||
|
||||
@Resource
|
||||
private IotDeviceService deviceService;
|
||||
|
||||
@Override
|
||||
public IotAlertRecordDO getAlertRecord(Long id) {
|
||||
return alertRecordMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<IotAlertRecordDO> getAlertRecordPage(IotAlertRecordPageReqVO pageReqVO) {
|
||||
return alertRecordMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long createAlertRecord(IotAlertConfigDO config, IotDeviceMessage message) {
|
||||
// 构建告警记录
|
||||
IotAlertRecordDO.IotAlertRecordDOBuilder builder = IotAlertRecordDO.builder()
|
||||
.configId(config.getId()).configName(config.getName()).configLevel(config.getLevel())
|
||||
.processStatus(false);
|
||||
if (message != null) {
|
||||
builder.deviceMessage(message);
|
||||
// 填充设备信息
|
||||
IotDeviceDO device = deviceService.getDeviceFromCache(message.getDeviceId());
|
||||
if (device!= null) {
|
||||
builder.productId(device.getProductId()).deviceId(device.getId());
|
||||
}
|
||||
}
|
||||
// 插入记录
|
||||
IotAlertRecordDO record = builder.build();
|
||||
alertRecordMapper.insert(record);
|
||||
return record.getId();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* IoT 规则场景 Service 接口
|
||||
* IoT 规则场景规则 Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@@ -57,10 +57,10 @@ public interface IotRuleSceneService {
|
||||
PageResult<IotRuleSceneDO> getRuleScenePage(IotRuleScenePageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 校验规则场景编号们是否存在。如下情况,视为无效:
|
||||
* 1. 规则场景编号不存在
|
||||
* 校验规则场景联动规则编号们是否存在。如下情况,视为无效:
|
||||
* 1. 规则场景联动规则编号不存在
|
||||
*
|
||||
* @param ids 规则场景编号数组
|
||||
* @param ids 场景联动规则编号数组
|
||||
*/
|
||||
void validateRuleSceneList(Collection<Long> ids);
|
||||
|
||||
@@ -91,7 +91,7 @@ public interface IotRuleSceneService {
|
||||
/**
|
||||
* 基于 {@link IotRuleSceneTriggerTypeEnum#TIMER} 场景,执行规则场景
|
||||
*
|
||||
* @param id 场景编号
|
||||
* @param id 场景联动规则编号
|
||||
*/
|
||||
void executeRuleSceneByTimer(Long id);
|
||||
|
||||
|
||||
@@ -443,7 +443,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
|
||||
// 3.2 执行动作
|
||||
actions.forEach(action -> {
|
||||
try {
|
||||
action.execute(message, actionConfig);
|
||||
action.execute(message, ruleScene, actionConfig);
|
||||
log.info("[executeRuleSceneAction][消息({}) 规则场景编号({}) 的执行动作({}) 成功]",
|
||||
message, ruleScene.getId(), actionConfig);
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.service.rule.scene.action;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
|
||||
import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* IoT 告警触发的 {@link IotSceneRuleAction} 实现类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Component
|
||||
public class IotAlertTriggerRuleSceneAction implements IotSceneRuleAction {
|
||||
|
||||
@Override
|
||||
public void execute(@Nullable IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) {
|
||||
// TODO @AI:
|
||||
}
|
||||
|
||||
@Override
|
||||
public IotRuleSceneActionTypeEnum getType() {
|
||||
return IotRuleSceneActionTypeEnum.ALERT_TRIGGER;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package cn.iocoder.yudao.module.iot.service.rule.scene.action;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
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.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 jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
// TODO @puhui999、@芋艿:未测试;需要场景联动开发完
|
||||
/**
|
||||
* IoT 告警触发的 {@link IotSceneRuleAction} 实现类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Component
|
||||
public class IotAlertTriggerSceneRuleAction implements IotSceneRuleAction {
|
||||
|
||||
@Resource
|
||||
private IotAlertConfigService alertConfigService;
|
||||
|
||||
@Resource
|
||||
private IotAlertRecordService alertRecordService;
|
||||
|
||||
@Override
|
||||
public void execute(@Nullable IotDeviceMessage message,
|
||||
IotRuleSceneDO rule, IotRuleSceneDO.ActionConfig actionConfig) throws Exception {
|
||||
List<IotAlertConfigDO> alertConfigs = alertConfigService.getAlertConfigListBySceneRuleIdAndStatus(
|
||||
rule.getId(), CommonStatusEnum.ENABLE.getStatus());
|
||||
if (CollUtil.isEmpty(alertConfigs)) {
|
||||
return;
|
||||
}
|
||||
alertConfigs.forEach(alertConfig ->
|
||||
alertRecordService.createAlertRecord(alertConfig, message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IotRuleSceneActionTypeEnum getType() {
|
||||
return IotRuleSceneActionTypeEnum.ALERT_TRIGGER;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,23 +26,24 @@ public class IotDeviceControlRuleSceneAction implements IotSceneRuleAction {
|
||||
private IotDeviceMessageService deviceMessageService;
|
||||
|
||||
@Override
|
||||
public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) {
|
||||
IotRuleSceneDO.ActionDeviceControl control = config.getDeviceControl();
|
||||
public void execute(IotDeviceMessage message,
|
||||
IotRuleSceneDO rule, IotRuleSceneDO.ActionConfig actionConfig) {
|
||||
IotRuleSceneDO.ActionDeviceControl control = actionConfig.getDeviceControl();
|
||||
Assert.notNull(control, "设备控制配置不能为空");
|
||||
// 遍历每个设备,下发消息
|
||||
control.getDeviceNames().forEach(deviceName -> {
|
||||
IotDeviceDO device = deviceService.getDeviceFromCache(control.getProductKey(), deviceName);
|
||||
if (device == null) {
|
||||
log.error("[execute][message({}) config({}) 对应的设备不存在]", message, config);
|
||||
log.error("[execute][message({}) actionConfig({}) 对应的设备不存在]", message, actionConfig);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// TODO @芋艿:@puhui999:这块可能要改,从 type => method
|
||||
IotDeviceMessage downstreamMessage = deviceMessageService.sendDeviceMessage(IotDeviceMessage.requestOf(
|
||||
control.getType() + control.getIdentifier(), control.getData()).setDeviceId(device.getId()));
|
||||
log.info("[execute][message({}) config({}) 下发消息({})成功]", message, config, downstreamMessage);
|
||||
log.info("[execute][message({}) actionConfig({}) 下发消息({})成功]", message, actionConfig, downstreamMessage);
|
||||
} catch (Exception e) {
|
||||
log.error("[execute][message({}) config({}) 下发消息失败]", message, config, e);
|
||||
log.error("[execute][message({}) actionConfig({}) 下发消息失败]", message, actionConfig, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -19,9 +19,12 @@ public interface IotSceneRuleAction {
|
||||
* @param message 消息,允许空
|
||||
* 1. 空的情况:定时触发
|
||||
* 2. 非空的情况:设备触发
|
||||
* @param config 配置
|
||||
* @param rule 规则
|
||||
* @param actionConfig 执行配置(实际对应规则里的哪条执行配置)
|
||||
*/
|
||||
void execute(@Nullable IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) throws Exception;
|
||||
void execute(@Nullable IotDeviceMessage message,
|
||||
IotRuleSceneDO rule,
|
||||
IotRuleSceneDO.ActionConfig actionConfig) throws Exception;
|
||||
|
||||
/**
|
||||
* 获得类型
|
||||
|
||||
Reference in New Issue
Block a user