فهرست منبع

refactor(pressure): 消防压力预警改为基于阈值配置判定

- 移除设备上报的 D10~D14 报警标志判定逻辑,改用 WARNING-FIRE-PRESSURE 阈值配置统一评估
- 引入 WarningThresholdService 获取设备阈值,按 min/max 判定是否越限报警
- 集成 EarlyWarningAutoService 实现越限关闭预警、未越限自动生成接近阈值预警
- 删除旧的 handleReportedAlarm 和 saveAlarmDataLevelOne 方法,统一走阈值评估流程
- 新增 buildAlarmContent 方法构建告警内容,与其他采集服务保持一致
- 修复 saveAlarmData 中 createTime 重复设置问题,补充 updateTime 字段
- 短信发送增加经纬度为空的容错处理
林仔 6 روز پیش
والد
کامیت
201c9c1c91
1فایلهای تغییر یافته به همراه98 افزوده شده و 47 حذف شده
  1. 98 47
      firefighting-pressure-service/src/main/java/com/zksy/pressure/utils/MessageHandler.java

+ 98 - 47
firefighting-pressure-service/src/main/java/com/zksy/pressure/utils/MessageHandler.java

@@ -6,8 +6,12 @@ import cn.hutool.core.lang.UUID;
 import com.alibaba.fastjson.JSONObject;
 import com.aliyun.apache.hc.client5.http.utils.Hex;
 import com.zksy.api.domain.AlarmData;
+import com.zksy.api.domain.WarningThreshold;
 import com.zksy.api.service.AlarmDataService;
+import com.zksy.api.service.EarlyWarningAutoService;
+import com.zksy.api.service.WarningThresholdService;
 import com.zksy.api.utils.AlarmLevelUtil;
+import com.zksy.api.utils.EarlyWarningLevelUtil;
 import com.zksy.api.utils.SmsUtil;
 import com.zksy.common.exception.InvalidMessageException;
 import com.zksy.pressure.domain.FirefightingPressure;
@@ -43,10 +47,19 @@ import java.util.Map;
 @Component
 public class MessageHandler extends ChannelInboundHandlerAdapter {
 	private static Logger logger = LoggerFactory.getLogger(MessageHandler.class);
+
+	/** 压力值预警编码,阈值取自 app_user.warning_threshold(device_code + warning_code) */
+	private static final String PRESSURE_WARNING_CODE = "WARN-FIRE-PRESSURE";
+	private static final String PRESSURE_WARNING_TYPE = "消防压力监测";
+
 	private final FirefightingPressureService firefightingPressureService;
 	@Autowired
 	private AlarmDataService alarmDataService;
 	@Autowired
+	private WarningThresholdService warningThresholdService;
+	@Autowired
+	private EarlyWarningAutoService earlyWarningAutoService;
+	@Autowired
 	private SmsUtil smsUtil;
 	@Autowired
     private DeviceContactService devicePhoneFetchUtil;
@@ -239,36 +252,73 @@ public class MessageHandler extends ChannelInboundHandlerAdapter {
 			logger.error("发送数据失败: {}", e.getMessage());
 		}
 	}
-	//检查是否会触发短信预警
-    public void checkIfSmsAlertNeeded(FirefightingPressure data) {
-        String deviceCode = data.getTelemeteringStation();
-        Integer status = alarmStatus(
-                handleReportedAlarm(data, data.getD14(), "压力变幅报警", "WARN-PRESSURE-VARY"),
-                handleReportedAlarm(data, data.getD13(), "压力下下限报警", "WARN-PRESSURE-LOW-LOW"),
-                handleReportedAlarm(data, data.getD12(), "压力上上限报警", "WARN-PRESSURE-HIGH-HIGH"),
-                handleReportedAlarm(data, data.getD11(), "压力下线报警", "WARN-PRESSURE-LOW"),
-                handleReportedAlarm(data, data.getD10(), "压力上限报警", "WARN-PRESSURE-HIGH"));
-        if (status != null) {
-            updateDeviceAlarmStatus(deviceCode, status);
-        }
-    }
+	/**
+	 * 压力值阈值评估:不再使用设备上报的 D14~D10 五种压力报警标志,
+	 * 统一按 pressure_value 与 WARN-FIRE-PRESSURE 配置阈值判定。
+	 */
+	public void checkIfSmsAlertNeeded(FirefightingPressure data) {
+		if (data == null) {
+			log.warn("消防压力数据为空,跳过阈值预警评估");
+			return;
+		}
+		String deviceCode = data.getTelemeteringStation() == null ? null : data.getTelemeteringStation().trim();
+		if (deviceCode == null || deviceCode.isEmpty()) {
+			log.warn("消防压力数据缺少遥测站地址,跳过阈值预警评估");
+			return;
+		}
+		// 评估失败(阈值未配置、压力值缺失)时返回 null,保留设备上一报警状态
+		Boolean status = evaluate(deviceCode, PRESSURE_WARNING_CODE + ":压力阈值评估",
+				() -> evaluatePressure(deviceCode, data));
+		if (status != null) {
+			updateDeviceAlarmStatus(deviceCode, status ? 1 : 0);
+		}
+	}
 
-    private Boolean handleReportedAlarm(FirefightingPressure data, Integer flag, String type, String code) {
-        if (flag == null || (flag != 0 && flag != 1)) {
-            return null;
-        }
-        if (flag == 1) {
-            String deviceCode = data.getTelemeteringStation();
-            BigDecimal actualValue = data.getPressureValue() == null
-                    ? null : BigDecimal.valueOf(data.getPressureValue());
-            run(deviceCode, code + ":主动报警入库", () -> saveAlarmDataLevelOne(deviceCode, type, code, actualValue, type));
-            run(deviceCode, code + ":短信通知", () -> sendMessage(deviceCode, type, data.getLongitude(), data.getLatitude()));
-        } else {
-            run(data.getTelemeteringStation(), code + ":告警恢复",
-                    () -> alarmDataService.recoverAlarm(data.getTelemeteringStation(), code));
-        }
-        return flag == 1;
-    }
+	/**
+	 * 按阈值判定本次压力值:越限写报警并关闭预警;未越限则处理告警恢复并生成接近阈值预警。
+	 *
+	 * @return true 报警,false 正常/预警区
+	 */
+	private boolean evaluatePressure(String deviceCode, FirefightingPressure data) {
+		if (warningThresholdService == null || alarmDataService == null || earlyWarningAutoService == null) {
+			throw new IllegalStateException("阈值预警依赖未注入");
+		}
+		if (data.getPressureValue() == null) {
+			throw new IllegalArgumentException("采集报文缺少压力值,无法判定报警状态");
+		}
+		BigDecimal actual = BigDecimal.valueOf(data.getPressureValue());
+		WarningThreshold threshold = warningThresholdService
+				.getWarningThresholdByDeviceAndCode(deviceCode, PRESSURE_WARNING_CODE);
+		if (threshold == null || (threshold.getMinValue() == null && threshold.getMaxValue() == null)) {
+			throw new IllegalStateException("消防压力阈值未配置,无法判定报警状态: deviceCode=" + deviceCode);
+		}
+
+		BigDecimal min = threshold.getMinValue() == null ? null : BigDecimal.valueOf(threshold.getMinValue());
+		BigDecimal max = threshold.getMaxValue() == null ? null : BigDecimal.valueOf(threshold.getMaxValue());
+		// 单侧阈值时补齐等级/预警区计算基线:压力不会为负,仅上限以 0 作下限;仅下限以两倍下限作上限,
+		// 保证只配一侧时等级计算仍有可比区间(与可燃气体仅按上限判定的处理保持一致)。
+		BigDecimal levelMin = min != null ? min : BigDecimal.ZERO;
+		BigDecimal levelMax = max != null ? max : min.multiply(BigDecimal.valueOf(2));
+
+		if (EarlyWarningLevelUtil.isOverThreshold(actual, min, max)) {
+			int level = saveAlarmData(deviceCode, PRESSURE_WARNING_TYPE, PRESSURE_WARNING_CODE,
+					levelMin, levelMax, actual, "消防压力值越限报警");
+			run(deviceCode, PRESSURE_WARNING_CODE + ":关闭预警",
+					() -> earlyWarningAutoService.closeAutoWarning(deviceCode, PRESSURE_WARNING_CODE, "已达报警阈值,转报警处理"));
+			if (level == 1) {
+				run(deviceCode, PRESSURE_WARNING_CODE + ":一级告警短信",
+						() -> sendMessage(deviceCode, PRESSURE_WARNING_TYPE, data.getLongitude(), data.getLatitude()));
+			}
+			return true;
+		}
+
+		run(deviceCode, PRESSURE_WARNING_CODE + ":告警恢复",
+				() -> alarmDataService.recoverThresholdAlarm(deviceCode, PRESSURE_WARNING_CODE, levelMin, levelMax, actual));
+		run(deviceCode, PRESSURE_WARNING_CODE + ":生成预警",
+				() -> earlyWarningAutoService.checkAndGenerate(deviceCode, PRESSURE_WARNING_TYPE, PRESSURE_WARNING_CODE,
+						levelMin, levelMax, actual, null));
+		return false;
+	}
 
 	private int saveAlarmData(String deviceCode, String warningType, String warningCode,
 							  BigDecimal minValue, BigDecimal maxValue,
@@ -287,10 +337,11 @@ public class MessageHandler extends ChannelInboundHandlerAdapter {
 			BigDecimal deviationRatio = AlarmLevelUtil.calculateDeviationRatio(actualValue, minValue, maxValue);
 			alarmData.setAlarmLevel(alarmLevel);
 			alarmData.setDeviationRatio(deviationRatio);
+			alarmData.setAlarmContent(buildAlarmContent(warningType, actualValue, minValue, maxValue, remark));
 
 			alarmData.setAlarmStatus(0);
 			alarmData.setCreateTime(LocalDateTime.now());
-			alarmData.setCreateTime(LocalDateTime.now());
+			alarmData.setUpdateTime(LocalDateTime.now());
 			boolean saved = run(deviceCode, warningCode + ":报警入库", () -> requireSaved(alarmDataService.saveAlarmData(alarmData)));
 
 			if (alarmLevel == 1) {
@@ -304,24 +355,22 @@ public class MessageHandler extends ChannelInboundHandlerAdapter {
 		return alarmLevel;
 	}
 
-	private void saveAlarmDataLevelOne(String deviceCode, String warningType, String warningCode,
-									   BigDecimal actualValue, String remark) {
-		try {
-			AlarmData alarmData = new AlarmData();
-			alarmData.setDeviceCode(deviceCode);
-			
-			alarmData.setWarningCode(warningCode);
-			alarmData.setActualValue(actualValue);
-			alarmData.setAlarmLevel(1);
-			alarmData.setAlarmStatus(0);
-			alarmData.setCreateTime(LocalDateTime.now());
-			alarmData.setCreateTime(LocalDateTime.now());
-			boolean saved = run(deviceCode, warningCode + ":报警入库", () -> requireSaved(alarmDataService.saveAlarmData(alarmData)));
-			if (saved) { log.info("设备主动告警入库(1级): deviceCode={}, warningCode={}", deviceCode, warningCode); }
-		} catch (Exception e) {
-			log.error("保存告警数据失败", e);
+	/** 告警内容与其他采集服务保持一致:指标名称 + 越限方向,便于前端直接展示。 */
+	private String buildAlarmContent(String warningType, BigDecimal actualValue,
+									 BigDecimal minValue, BigDecimal maxValue, String remark) {
+		String content = warningType == null || warningType.trim().isEmpty() ? remark : warningType.trim();
+		if (actualValue == null) {
+			return content;
+		}
+		if (minValue != null && actualValue.compareTo(minValue) <= 0) {
+			return content + "达到或低于下限";
 		}
+		if (maxValue != null && actualValue.compareTo(maxValue) >= 0) {
+			return content + "达到或超过上限";
+		}
+		return content;
 	}
+
 	//构造发送短信参数&&发送短信
 	public void sendMessage(String deviceNo,String alarmType,BigDecimal lng,BigDecimal lat){
 		// 构造短信参数
@@ -329,7 +378,9 @@ public class MessageHandler extends ChannelInboundHandlerAdapter {
 		params.put("deviceNo", deviceNo);
 		params.put("alarmType", alarmType);
 		// 经纬度处理(为执行信息处理)
-		params.put("location", String.format("经纬度:%.6f,%.8f", lng, lat));
+		params.put("location", (lng != null && lat != null)
+				? String.format("经纬度:%.6f,%.8f", lng, lat)
+				: "位置未知");
 		List<String> phoneListByDeviceId = devicePhoneFetchUtil.getPhoneListByDeviceCode(deviceNo);
 			Map<String, Boolean> sendResults = smsUtil.sendBatchSms(phoneListByDeviceId, params.toJSONString());
 			log.info("发送信息完成");