diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/warn/vo/AlarmTrendRespVO.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/warn/vo/AlarmTrendRespVO.java new file mode 100644 index 0000000..3cc67d4 --- /dev/null +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/warn/vo/AlarmTrendRespVO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.alert.controller.admin.warn.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +public class AlarmTrendRespVO { + @Schema(description = "实时历史值列表", example = "id") + private List> realTimeList; + + @Schema(description = "上限值列表", example = "id") + private List> upList; + + @Schema(description = "下限值列表", example = "id") + private List> lowList; + + @Schema(description = "告警值列表", example = "id") + private List> errorList; + + @Schema(description = "所有值列表", example = "id") + List>> valueList; + + @Schema(description = "标签列表", example = "id") + List tagList; + + @Schema(description = "光字牌名称", example = "id") + private String gzpName; + + + + + + + +} diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/warn/warnController.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/warn/warnController.java index ccdf136..d68eea4 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/warn/warnController.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/controller/admin/warn/warnController.java @@ -3,9 +3,11 @@ package cn.iocoder.yudao.module.alert.controller.admin.warn; 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.alert.controller.admin.exa.vo.EXAHistoryReqVO; import cn.iocoder.yudao.module.alert.controller.admin.instant.vo.InstantPageReqVO; import cn.iocoder.yudao.module.alert.controller.admin.instant.vo.InstantRespVO; import cn.iocoder.yudao.module.alert.controller.admin.instant.vo.InstantSaveReqVO; +import cn.iocoder.yudao.module.alert.controller.admin.warn.vo.AlarmTrendRespVO; import cn.iocoder.yudao.module.alert.controller.admin.warn.vo.WarnPageReqVO; import cn.iocoder.yudao.module.alert.controller.admin.warn.vo.WarnRespVO; import cn.iocoder.yudao.module.alert.controller.admin.warn.vo.WarnSaveReqVO; @@ -79,4 +81,11 @@ public class warnController { } + @GetMapping("/alarm/trend") + @Operation(summary = "获取该条告警的趋势", description = "获取该条告警的趋势") + public CommonResult getAlarmTrend(@RequestParam("id") Long id, @Valid EXAHistoryReqVO exaHistoryReqVO) { +// versionReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + AlarmTrendRespVO alarmTrendRespVO = warnService.getAlarmTrend(id, exaHistoryReqVO); + return success(alarmTrendRespVO); + } } diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dal/mysql/warn/WarnMapper.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dal/mysql/warn/WarnMapper.java index a8dadc6..fa570ce 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dal/mysql/warn/WarnMapper.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/dal/mysql/warn/WarnMapper.java @@ -41,4 +41,8 @@ public interface WarnMapper extends BaseMapperX { .apply("TIMESTAMPDIFF(SECOND, create_time, NOW()) > time_duration_threshold") .orderByAsc(WarnDO::getWarnId)); } + + default WarnDO selectByWarnId(Long warnId) { + return selectOne(WarnDO::getWarnId, warnId); + } } diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/warn/WarnService.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/warn/WarnService.java index cb053a0..a1a9ce0 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/warn/WarnService.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/warn/WarnService.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.alert.service.warn; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.alert.controller.admin.exa.vo.EXAHistoryReqVO; import cn.iocoder.yudao.module.alert.controller.admin.instant.vo.InstantSaveReqVO; +import cn.iocoder.yudao.module.alert.controller.admin.warn.vo.AlarmTrendRespVO; import cn.iocoder.yudao.module.alert.controller.admin.warn.vo.WarnPageReqVO; import cn.iocoder.yudao.module.alert.controller.admin.warn.vo.WarnRespVO; import cn.iocoder.yudao.module.alert.controller.admin.warn.vo.WarnSaveReqVO; @@ -60,4 +62,14 @@ public interface WarnService { * @return 报警等级列表-不分页 */ List getAlarmLevelList(); + + + /** + * 获得报警趋势 + * + * @param id 预警编号 + * @return 报警趋势 + */ + AlarmTrendRespVO getAlarmTrend(Long id, EXAHistoryReqVO exaHistoryReqVO); + } diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/warn/WarnServiceImpl.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/warn/WarnServiceImpl.java index fb59248..a9e34bf 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/warn/WarnServiceImpl.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/service/warn/WarnServiceImpl.java @@ -3,9 +3,12 @@ package cn.iocoder.yudao.module.alert.service.warn; import cn.hutool.core.collection.CollectionUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.alert.controller.admin.exa.vo.EXAHistoryReqVO; import cn.iocoder.yudao.module.alert.controller.admin.instant.vo.InstantSaveReqVO; import cn.iocoder.yudao.module.alert.controller.admin.model.vo.ModelVersionPageReqVO; +import cn.iocoder.yudao.module.alert.controller.admin.warn.vo.AlarmTrendRespVO; import cn.iocoder.yudao.module.alert.controller.admin.warn.vo.WarnPageReqVO; import cn.iocoder.yudao.module.alert.controller.admin.warn.vo.WarnRespVO; import cn.iocoder.yudao.module.alert.controller.admin.warn.vo.WarnSaveReqVO; @@ -32,11 +35,15 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.CacheEvict; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.RequestParam; import java.io.IOException; import java.net.URISyntaxException; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -244,4 +251,96 @@ public class WarnServiceImpl implements WarnService { return alarmLevelMapper.selectList(); } + @Override + public AlarmTrendRespVO getAlarmTrend(Long id,EXAHistoryReqVO exaHistoryReqVO) { + try { + // 1. 查询预警配置信息 + WarnDO warnDO = warnMapper.selectByWarnId(id); + if (warnDO == null) { + throw exception(WARN_NOT_EXISTS,"未找到预警配置信息,warnId: " + id); + } + + // 2. 提取必要参数 + String point = warnDO.getPointId(); + String outpoint = warnDO.getOutputPoint(); + String uplimit = warnDO.getUplimit(); + String lowlimit = warnDO.getLowlimit(); + + EXAUtils exaUtils = new EXAUtils(); + exaHistoryReqVO.setItemName(point); + // 3. 获取历史数据 + exaHistoryReqVO.setItemName("SYG1_10BBA20ECMS501"); + exaHistoryReqVO.setStartTime("2023-10-28 17:00:00"); + exaHistoryReqVO.setEndTime("2023-10-28 23:00:00"); + exaHistoryReqVO.setInterval(60L); + List> inputData = exaUtils.getHistory(EXA_IP, exaHistoryReqVO); + List> outputData = exaUtils.getHistory(EXA_IP, exaHistoryReqVO); + // 4. 数据校验 + if (inputData.isEmpty() || outputData.isEmpty()) { + throw exception(EXA_HISTORY_IS_EMPTY,"历史数据为空,point: " + point + ", outputPoint: " + outpoint); + } + + //直接深拷贝outputData + //上限值列表 + List> upList = new ArrayList<>(outputData.size()); + for (List inner : outputData) { + upList.add(new ArrayList<>(inner)); + } + //下限值列表 + List> lowList = new ArrayList<>(outputData.size()); + for (List inner : outputData) { + lowList.add(new ArrayList<>(inner)); + } + //告警值列表 + List> errorList = new ArrayList<>(outputData.size()); + for (List inner : outputData) { + errorList.add(new ArrayList<>(inner)); + } + + // 7. 数据处理:计算上下限、误差标记 + for (int i = 0; i < outputData.size(); i++) { + List inputRow = inputData.get(i); + List outputRow = outputData.get(i); + Double inputValue = inputRow.size() > 1 ? inputRow.get(1) : null; + Double outputValue = outputRow.size() > 1 ? outputRow.get(1) : null; + // 计算上下限 + double h = (outputValue != null ? outputValue : 0) + Double.parseDouble(uplimit); + double l = (outputValue != null ? outputValue : 0) + Double.parseDouble(lowlimit); + + // ⚠️ 分别拷贝 + List upRow = new ArrayList<>(outputRow); + upRow.set(1, h); + upList.set(i, upRow); + + List lowRow = new ArrayList<>(outputRow); + lowRow.set(1, l); + lowList.set(i, lowRow); + + List errorRow = new ArrayList<>(outputRow); + + // 误差标记(1表示异常,null表示正常) + if (inputValue != null && (inputValue < l || inputValue > h)) { + errorRow.set(1, 1.0); + } else { + errorRow.set(1, null); + } + errorList.set(i, errorRow); + } + + // 8. 组装结果对象 + AlarmTrendRespVO result = new AlarmTrendRespVO(); + result.setRealTimeList(inputData); + result.setUpList(upList); + result.setLowList(lowList); + result.setErrorList(errorList); + result.setGzpName(warnDO.getGzpName() + " " + warnDO.getUnit()); + result.setValueList(Arrays.asList(inputData, upList, lowList, errorList)); + result.setTagList(Arrays.asList("实时值", "上限值", "下限值", "告警值")); + return result; + + } catch (Exception e) { + log.error("getAlarmTrend error", e); + throw exception(ALARM_TREND_FAILED, "获取告警趋势失败: " + e.getMessage()); + } + } } diff --git a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/utils/EXAUtils.java b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/utils/EXAUtils.java index ee71aa7..17e9b80 100644 --- a/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/utils/EXAUtils.java +++ b/yudao-module-alert/yudao-module-alert-biz/src/main/java/cn/iocoder/yudao/module/alert/utils/EXAUtils.java @@ -185,6 +185,7 @@ public class EXAUtils { * @param exaHistoryReqVo 传入对象,点号、开始时间、结束时间 * itemName 单点号 * @return exa列表 + * [[1698369232000,0.0],[1698369332000,0.0],[1698369432000,0.0],[1698369532000,0.0],[1698369632000,0.0],[1698369732000,0.0],[1698369832000,0.0],[1698369932000,0.0],[1698370032000,0.0],[1698370132000,0.0],[1698370232000,0.0],[1698370332000,0.0],[1698370432000,0.0],[1698370532000,0.0],[1698370632000,0.0],[1698370732000,0.0],[1698370832000,0.0],[1698370932000,0.0]] */ public List> getHistory(String exaIp, EXAHistoryReqVO req) { List> result = Collections.emptyList(); diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java index d2fc284..da6f3c0 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java @@ -177,7 +177,12 @@ public interface ErrorCodeConstants { ErrorCode CALCULATE_ERROR = new ErrorCode(3_001_002, "模型实例计算失败,失败原因:({})"); // ========== 预警模块 4-001========== - ErrorCode WARN_NOT_EXISTS = new ErrorCode(4_001_000, "预警不存在"); + ErrorCode WARN_NOT_EXISTS = new ErrorCode(4_001_000, "预警信息不存在"); + + ErrorCode ALARM_TREND_FAILED=new ErrorCode(4_001_001, "预警趋势获取失败"); + + + ErrorCode Company_NOT_EXISTS = new ErrorCode(1_002_30_000,"集团不存在"); ErrorCode Company_NAME_DUPLICATE = new ErrorCode(1_002_31_000,"集团名称已存在"); @@ -195,5 +200,6 @@ public interface ErrorCodeConstants { ErrorCode EXA_POINT_IMPORT_LIST_IS_EMPTY = new ErrorCode(6_001_000, "导入EXA测点数据不能为空!"); ErrorCode EXA_POINT_IMPORT_FAILED = new ErrorCode(6_001_001, "导入EXA测点数据失败!失败测点:({})"); ErrorCode EXA_REAL_FAILED = new ErrorCode(6_001_002, "读取EXA测点实时数据失败!失败测点:({})"); + ErrorCode EXA_HISTORY_IS_EMPTY = new ErrorCode(6_001_003, "EXA测点历史数据获取失败!"); }