|
|
@@ -1,12 +1,9 @@
|
|
|
/*
|
|
|
* 文 件 名: InspectionAlarmAdapter
|
|
|
* 版 权: 华设设计集团股份有限公司
|
|
|
- * 描 述: <描述>
|
|
|
+ * 描 述: 巡检与告警集成适配器 - 完整实现版
|
|
|
* 修 改 人: lvwenbin
|
|
|
* 修改时间: 2026/2/3
|
|
|
- * 跟踪单号: <跟踪单号>
|
|
|
- * 修改单号: <修改单号>
|
|
|
- * 修改内容: <修改内容>
|
|
|
*/
|
|
|
package com.ruoyi.ems.service.alarm;
|
|
|
|
|
|
@@ -21,6 +18,7 @@ import com.ruoyi.ems.domain.InspectionRule;
|
|
|
import com.ruoyi.ems.service.IEmsObjAttrValueService;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.commons.collections4.CollectionUtils;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Component;
|
|
|
|
|
|
@@ -34,11 +32,15 @@ import java.util.stream.Collectors;
|
|
|
* 巡检与告警集成适配器
|
|
|
*
|
|
|
* 【功能说明】
|
|
|
- * 将自动巡检的检查结果转换为告警
|
|
|
- * 实现巡检和告警的联动
|
|
|
+ * 1. 将自动巡检的异常结果转换为告警
|
|
|
+ * 2. 复用告警规则引擎进行检查
|
|
|
+ * 3. 实现巡检和告警的联动
|
|
|
*
|
|
|
- * 【使用方式】
|
|
|
- * 在InspectionPlanServiceImpl中调用此适配器
|
|
|
+ * 【调用时机】
|
|
|
+ * 在 InspectionPlanServiceImpl.executeAutoInspection() 执行完成后调用
|
|
|
+ *
|
|
|
+ * 【告警来源】
|
|
|
+ * - Alarm.SOURCE_INSPECTION (2): 自动巡检产生的告警
|
|
|
*/
|
|
|
@Slf4j
|
|
|
@Component
|
|
|
@@ -53,6 +55,9 @@ public class InspectionAlarmAdapter {
|
|
|
/**
|
|
|
* 处理巡检结果,生成告警
|
|
|
*
|
|
|
+ * 【核心入口方法】
|
|
|
+ * 在巡检执行完成后调用,将异常设备生成告警
|
|
|
+ *
|
|
|
* @param report 巡检报告
|
|
|
* @param details 巡检明细列表
|
|
|
* @return 生成的告警列表
|
|
|
@@ -61,95 +66,147 @@ public class InspectionAlarmAdapter {
|
|
|
List<Alarm> alarms = new ArrayList<>();
|
|
|
|
|
|
if (report == null || CollectionUtils.isEmpty(details)) {
|
|
|
+ log.debug("巡检报告或明细为空,跳过告警生成");
|
|
|
return alarms;
|
|
|
}
|
|
|
|
|
|
log.info("开始处理巡检结果生成告警: reportCode={}, detailCount={}",
|
|
|
report.getReportCode(), details.size());
|
|
|
|
|
|
+ int processedCount = 0;
|
|
|
+ int alarmCount = 0;
|
|
|
+
|
|
|
for (InspectionReportDetail detail : details) {
|
|
|
// 只处理异常的设备
|
|
|
if (detail.getResultStatus() == null || detail.getResultStatus() == 0) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
+ processedCount++;
|
|
|
+
|
|
|
try {
|
|
|
List<Alarm> deviceAlarms = processDeviceDetail(detail, report.getReportCode());
|
|
|
- alarms.addAll(deviceAlarms);
|
|
|
+ if (CollectionUtils.isNotEmpty(deviceAlarms)) {
|
|
|
+ alarms.addAll(deviceAlarms);
|
|
|
+ alarmCount += deviceAlarms.size();
|
|
|
+ }
|
|
|
} catch (Exception e) {
|
|
|
log.error("处理设备巡检结果异常: deviceCode={}, error={}",
|
|
|
- detail.getDeviceCode(), e.getMessage());
|
|
|
+ detail.getDeviceCode(), e.getMessage(), e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- log.info("巡检结果告警生成完成: reportCode={}, alarmCount={}",
|
|
|
- report.getReportCode(), alarms.size());
|
|
|
+ log.info("巡检结果告警生成完成: reportCode={}, 处理异常设备数={}, 生成告警数={}",
|
|
|
+ report.getReportCode(), processedCount, alarmCount);
|
|
|
|
|
|
return alarms;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 处理单个设备的巡检明细
|
|
|
+ * 处理单个设备的巡检明细,生成告警
|
|
|
*/
|
|
|
private List<Alarm> processDeviceDetail(InspectionReportDetail detail, String reportCode) {
|
|
|
List<Alarm> alarms = new ArrayList<>();
|
|
|
|
|
|
- // 构建设备信息
|
|
|
+ // 构建设备信息对象
|
|
|
+ EmsDevice device = buildDeviceFromDetail(detail);
|
|
|
+
|
|
|
+ // 获取设备属性值(从检查项结果或数据库)
|
|
|
+ Map<String, String> attrValues = getDeviceAttrValues(detail);
|
|
|
+
|
|
|
+ if (attrValues.isEmpty()) {
|
|
|
+ log.warn("设备属性值为空,无法生成告警: deviceCode={}", detail.getDeviceCode());
|
|
|
+ return alarms;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 调用告警处理服务进行规则检查和告警生成
|
|
|
+ try {
|
|
|
+ List<Alarm> generatedAlarms = alarmProcessService.processInspection(
|
|
|
+ device, attrValues, reportCode);
|
|
|
+
|
|
|
+ if (CollectionUtils.isNotEmpty(generatedAlarms)) {
|
|
|
+ alarms.addAll(generatedAlarms);
|
|
|
+ log.debug("设备[{}]生成告警数量: {}", detail.getDeviceCode(), generatedAlarms.size());
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("调用告警处理服务异常: deviceCode={}, error={}",
|
|
|
+ detail.getDeviceCode(), e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ return alarms;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从巡检明细构建设备对象
|
|
|
+ */
|
|
|
+ private EmsDevice buildDeviceFromDetail(InspectionReportDetail detail) {
|
|
|
EmsDevice device = new EmsDevice();
|
|
|
device.setDeviceCode(detail.getDeviceCode());
|
|
|
device.setDeviceName(detail.getDeviceName());
|
|
|
device.setDeviceModel(detail.getDeviceModel());
|
|
|
device.setDeviceModelName(detail.getDeviceModelName());
|
|
|
device.setLocation(detail.getLocation());
|
|
|
- // 从areaPath解析areaCode
|
|
|
- if (detail.getAreaPath() != null && detail.getAreaPath().contains(",")) {
|
|
|
+ device.setAreaPath(detail.getAreaPath());
|
|
|
+
|
|
|
+ // 从areaPath解析areaCode(取最后一个)
|
|
|
+ if (StringUtils.isNotBlank(detail.getAreaPath())) {
|
|
|
String[] paths = detail.getAreaPath().split(",");
|
|
|
if (paths.length > 0) {
|
|
|
- device.setAreaCode(paths[paths.length - 1]);
|
|
|
+ device.setAreaCode(paths[paths.length - 1].trim());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 获取设备属性值
|
|
|
- Map<String, String> attrValues = getDeviceAttrValues(detail);
|
|
|
-
|
|
|
- // 调用告警处理服务
|
|
|
- List<Alarm> generatedAlarms = alarmProcessService.processInspection(device, attrValues, reportCode);
|
|
|
- alarms.addAll(generatedAlarms);
|
|
|
+ // 从检查项中提取设备状态
|
|
|
+ List<CheckItemResult> checkItems = detail.getCheckItemList();
|
|
|
+ if (CollectionUtils.isNotEmpty(checkItems)) {
|
|
|
+ for (CheckItemResult item : checkItems) {
|
|
|
+ if ("deviceStatus".equals(item.getAttrKey()) && item.getActualValue() != null) {
|
|
|
+ try {
|
|
|
+ device.setDeviceStatus(Integer.parseInt(item.getActualValue()));
|
|
|
+ } catch (NumberFormatException ignored) {
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- return alarms;
|
|
|
+ return device;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 从巡检明细中提取属性值
|
|
|
+ * 优先从检查项结果获取,否则从数据库获取
|
|
|
*/
|
|
|
private Map<String, String> getDeviceAttrValues(InspectionReportDetail detail) {
|
|
|
Map<String, String> attrValues = new HashMap<>();
|
|
|
|
|
|
- // 从checkItems中提取
|
|
|
+ // 1. 优先从checkItems中提取(已有的检查结果)
|
|
|
List<CheckItemResult> checkItems = detail.getCheckItemList();
|
|
|
if (CollectionUtils.isNotEmpty(checkItems)) {
|
|
|
for (CheckItemResult item : checkItems) {
|
|
|
- if (item.getAttrKey() != null && item.getActualValue() != null) {
|
|
|
+ if (StringUtils.isNotBlank(item.getAttrKey())
|
|
|
+ && StringUtils.isNotBlank(item.getActualValue())) {
|
|
|
attrValues.put(item.getAttrKey(), item.getActualValue());
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 如果checkItems为空,从数据库获取
|
|
|
- if (attrValues.isEmpty() && detail.getDeviceModel() != null) {
|
|
|
+ // 2. 如果checkItems数据不完整,从数据库补充
|
|
|
+ if (attrValues.size() < 3 && StringUtils.isNotBlank(detail.getDeviceModel())) {
|
|
|
try {
|
|
|
List<EmsObjAttrValue> dbValues = attrValueService.selectByObjCode(
|
|
|
detail.getDeviceModel(), detail.getDeviceCode());
|
|
|
if (CollectionUtils.isNotEmpty(dbValues)) {
|
|
|
- attrValues = dbValues.stream()
|
|
|
- .filter(v -> v.getAttrKey() != null && v.getAttrValue() != null)
|
|
|
- .collect(Collectors.toMap(
|
|
|
- EmsObjAttrValue::getAttrKey,
|
|
|
- EmsObjAttrValue::getAttrValue,
|
|
|
- (v1, v2) -> v2));
|
|
|
+ for (EmsObjAttrValue v : dbValues) {
|
|
|
+ if (v.getAttrKey() != null && v.getAttrValue() != null) {
|
|
|
+ // 不覆盖已有值
|
|
|
+ attrValues.putIfAbsent(v.getAttrKey(), v.getAttrValue());
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
- log.warn("获取设备属性值失败: deviceCode={}", detail.getDeviceCode());
|
|
|
+ log.warn("获取设备属性值失败: deviceCode={}, error={}",
|
|
|
+ detail.getDeviceCode(), e.getMessage());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -160,8 +217,8 @@ public class InspectionAlarmAdapter {
|
|
|
* 将巡检规则转换为告警规则格式
|
|
|
*
|
|
|
* 【说明】
|
|
|
- * 此方法用于复用巡检规则配置
|
|
|
- * 当巡检规则和告警规则需要统一时使用
|
|
|
+ * 用于需要复用巡检规则配置的场景
|
|
|
+ * 当巡检规则和告警规则需要统一管理时使用
|
|
|
*
|
|
|
* @param inspectionRule 巡检规则
|
|
|
* @return 告警规则
|
|
|
@@ -189,20 +246,137 @@ public class InspectionAlarmAdapter {
|
|
|
// 根据检查类型设置操作符
|
|
|
if (inspectionRule.getCheckType() != null) {
|
|
|
switch (inspectionRule.getCheckType()) {
|
|
|
- case 1: // 范围
|
|
|
+ case 1: // 范围检查
|
|
|
alarmRule.setOperator(AlarmRule.OP_RANGE);
|
|
|
break;
|
|
|
- case 2: // 等值
|
|
|
+ case 2: // 等值检查
|
|
|
alarmRule.setOperator(AlarmRule.OP_EQ);
|
|
|
break;
|
|
|
case 4: // 在线状态
|
|
|
alarmRule.setOperator(AlarmRule.OP_EQ);
|
|
|
+ alarmRule.setThresholdValue("0"); // 离线值
|
|
|
break;
|
|
|
default:
|
|
|
+ alarmRule.setOperator(AlarmRule.OP_NE);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return alarmRule;
|
|
|
}
|
|
|
-}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 批量转换巡检规则为告警规则
|
|
|
+ *
|
|
|
+ * @param inspectionRules 巡检规则列表
|
|
|
+ * @return 告警规则列表
|
|
|
+ */
|
|
|
+ public List<AlarmRule> convertToAlarmRules(List<InspectionRule> inspectionRules) {
|
|
|
+ if (CollectionUtils.isEmpty(inspectionRules)) {
|
|
|
+ return new ArrayList<>();
|
|
|
+ }
|
|
|
+
|
|
|
+ return inspectionRules.stream()
|
|
|
+ .filter(r -> r != null && r.getEnabled() != null && r.getEnabled() == 1)
|
|
|
+ .map(this::convertToAlarmRule)
|
|
|
+ .filter(r -> r != null)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据检查项结果直接生成告警(不依赖告警规则)
|
|
|
+ *
|
|
|
+ * 【用途】
|
|
|
+ * 当巡检检查项结果已经明确标记异常时,直接生成告警
|
|
|
+ * 无需再次进行规则匹配
|
|
|
+ *
|
|
|
+ * @param detail 巡检明细
|
|
|
+ * @param reportCode 报告代码
|
|
|
+ * @return 告警列表
|
|
|
+ */
|
|
|
+ public List<Alarm> createAlarmsFromCheckItems(InspectionReportDetail detail, String reportCode) {
|
|
|
+ List<Alarm> alarms = new ArrayList<>();
|
|
|
+
|
|
|
+ List<CheckItemResult> checkItems = detail.getCheckItemList();
|
|
|
+ if (CollectionUtils.isEmpty(checkItems)) {
|
|
|
+ return alarms;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (CheckItemResult item : checkItems) {
|
|
|
+ // 只处理异常项
|
|
|
+ if (item.getStatus() == null || item.getStatus() == 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ Alarm alarm = createAlarmFromCheckItem(detail, item, reportCode);
|
|
|
+ if (alarm != null) {
|
|
|
+ alarms.add(alarm);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("从检查项创建告警失败: deviceCode={}, ruleCode={}, error={}",
|
|
|
+ detail.getDeviceCode(), item.getRuleCode(), e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return alarms;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从单个检查项创建告警
|
|
|
+ */
|
|
|
+ private Alarm createAlarmFromCheckItem(InspectionReportDetail detail,
|
|
|
+ CheckItemResult item,
|
|
|
+ String reportCode) {
|
|
|
+ Alarm alarm = new Alarm();
|
|
|
+
|
|
|
+ // 设置告警ID(由AlarmProcessService处理)
|
|
|
+ alarm.setAlarmId(null);
|
|
|
+
|
|
|
+ // 设置区域(从areaPath解析)
|
|
|
+ if (StringUtils.isNotBlank(detail.getAreaPath())) {
|
|
|
+ String[] paths = detail.getAreaPath().split(",");
|
|
|
+ if (paths.length > 0) {
|
|
|
+ alarm.setAreaCode(paths[paths.length - 1].trim());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置目标信息
|
|
|
+ alarm.setTargetType(2); // 设备
|
|
|
+ alarm.setTargetCode(detail.getDeviceCode());
|
|
|
+ alarm.setTargetName(detail.getDeviceName());
|
|
|
+ alarm.setDeviceModel(detail.getDeviceModel());
|
|
|
+ alarm.setDeviceModelName(detail.getDeviceModelName());
|
|
|
+ alarm.setLocation(detail.getLocation());
|
|
|
+
|
|
|
+ // 设置规则和属性信息
|
|
|
+ alarm.setRuleCode(item.getRuleCode());
|
|
|
+ alarm.setRuleName(item.getRuleName());
|
|
|
+ alarm.setAttrKey(item.getAttrKey());
|
|
|
+ alarm.setAttrName(item.getAttrName());
|
|
|
+ alarm.setAttrValue(item.getActualValue());
|
|
|
+ alarm.setThresholdValue(item.getExpectRange());
|
|
|
+
|
|
|
+ // 设置告警级别(默认一般)
|
|
|
+ alarm.setAlarmLevel(Alarm.LEVEL_NORMAL);
|
|
|
+
|
|
|
+ // 设置告警代码(从规则代码派生)
|
|
|
+ alarm.setAlarmCode("INSP_" + (StringUtils.isNotBlank(item.getRuleCode())
|
|
|
+ ? item.getRuleCode() : "UNKNOWN"));
|
|
|
+
|
|
|
+ // 设置告警消息
|
|
|
+ String msg = StringUtils.isNotBlank(item.getMessage())
|
|
|
+ ? item.getMessage()
|
|
|
+ : String.format("设备[%s]%s异常,当前值:%s",
|
|
|
+ detail.getDeviceName(),
|
|
|
+ item.getAttrName() != null ? item.getAttrName() : item.getAttrKey(),
|
|
|
+ item.getActualValue());
|
|
|
+ alarm.setAlarmMsg(msg);
|
|
|
+
|
|
|
+ // 设置来源信息
|
|
|
+ alarm.setAlarmSource(Alarm.SOURCE_INSPECTION);
|
|
|
+ alarm.setSourceRef(reportCode);
|
|
|
+
|
|
|
+ return alarm;
|
|
|
+ }
|
|
|
+}
|