Просмотр исходного кода

feat(alarm): 实现报警系统自动预警和设备状态同步功能

- 集成MyBatis-Plus自动生成ID策略,为AlarmAssignDetail和AlarmAssignList添加@TableId注解
- 引入EarlyWarningAutoService实现自动预警功能,支持接近阈值时的预警处理
- 在环境服务中重构checkAndSaveAlarm方法,区分报警和预警逻辑并返回触发状态
- 为井盖服务扩展AlarmUtil工具类,新增saveAlarmWithLevel和updateDeviceAlarmStatus方法
- 重构井盖数据服务中的告警检查逻辑,支持倾斜角度动态阈值和多类型状态告警
- 在消防压力和可燃气体服务中实现设备报警状态同步到equipment_status表
- 添加设备状态API URL配置项,统一管理设备报警状态更新接口地址
- 优化报警数据保存逻辑,集成自动预警关闭和生成机制,提升系统响应效率
林仔 1 месяц назад
Родитель
Сommit
30a8d95477

+ 54 - 72
environment-service/src/main/java/com/zksy/environment/config/RSServerService.java

@@ -9,7 +9,12 @@ import com.zksy.environment.utils.AlarmUtil;
 import com.zksy.utils.DevicePhoneFetchUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
 import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
 import rk.netDevice.sdk.p2.*;
 
 import javax.annotation.PostConstruct;
@@ -17,7 +22,9 @@ import javax.annotation.PreDestroy;
 import java.math.BigDecimal;
 import java.text.SimpleDateFormat;
 import java.time.LocalDateTime;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
@@ -48,6 +55,11 @@ public class RSServerService {
     private DevicePhoneFetchUtil devicePhoneFetchUtil;
     @Autowired
     private AlarmUtil alarmUtil;
+    @Autowired
+    private RestTemplate restTemplate;
+
+    @Value("${device.status.api.url:http://zk-api-service/equipmentStatus/updateAlarmStatus}")
+    private String deviceStatusApiUrl;
 
     @PostConstruct
     public void init() {
@@ -117,6 +129,8 @@ public class RSServerService {
 
                 @Override
                 public void receiveRealtimeData(RealTimeData data) {
+                    String deviceId = String.valueOf(data.getDeviceId());
+                    boolean hasAlarm = false;
                     for (NodeData nd : data.getNodeList()) {
                         try {
                             // 获取当前节点ID
@@ -179,8 +193,7 @@ public class RSServerService {
                             // 数据库插入
                             realTimeDataMapper.insert(realTimeData);
 
-                            // ====================== 报警处理 ======================
-                            String deviceId = String.valueOf(data.getDeviceId());
+                            // ====================== 报警/预警处理 ======================
 
                             // 悬浮物判断
                             if (!"".equals(realTimeData.getFloatValue()) && nd.getNodeId() == 1) {
@@ -190,20 +203,9 @@ public class RSServerService {
                                 Double temMaxValue = temThreshold != null ? temThreshold.getMaxValue() : null;
                                 String temWarningType = temThreshold != null ? temThreshold.getWarningType() : "悬浮物预警";
                                 String temRemark = temThreshold != null ? temThreshold.getRemark() : "环境悬浮物报警";
-
-                                boolean temShouldAlarm = false;
-                                BigDecimal temValue = BigDecimal.valueOf(nd.getTem());
-                                if (temMinValue != null && nd.getTem() <= temMinValue) {
-                                    temShouldAlarm = true;
-                                }
-                                if (temMaxValue != null && nd.getTem() >= temMaxValue) {
-                                    temShouldAlarm = true;
-                                }
-                                if (temShouldAlarm) {
-                                    alarmUtil.saveAlarm(deviceId, temWarningType, temWarningCode,
-                                            temMinValue != null ? BigDecimal.valueOf(temMinValue) : null,
-                                            temMaxValue != null ? BigDecimal.valueOf(temMaxValue) : null,
-                                            temValue, temRemark);
+                                if (alarmUtil.checkAndSaveAlarm(deviceId, temWarningType, temWarningCode,
+                                        temMinValue, temMaxValue, BigDecimal.valueOf(nd.getTem()), temRemark)) {
+                                    hasAlarm = true;
                                 }
                             }
 
@@ -215,20 +217,9 @@ public class RSServerService {
                                 Double humMaxValue = humThreshold != null ? humThreshold.getMaxValue() : 40.0;
                                 String humWarningType = humThreshold != null ? humThreshold.getWarningType() : "COD预警";
                                 String humRemark = humThreshold != null ? humThreshold.getRemark() : "环境COD报警";
-
-                                boolean humShouldAlarm = false;
-                                BigDecimal humValue = BigDecimal.valueOf(finalValue);
-                                if (humMinValue != null && finalValue <= humMinValue) {
-                                    humShouldAlarm = true;
-                                }
-                                if (humMaxValue != null && finalValue >= humMaxValue) {
-                                    humShouldAlarm = true;
-                                }
-                                if (humShouldAlarm) {
-                                    alarmUtil.saveAlarm(deviceId, humWarningType, humWarningCode,
-                                            humMinValue != null ? BigDecimal.valueOf(humMinValue) : null,
-                                            humMaxValue != null ? BigDecimal.valueOf(humMaxValue) : null,
-                                            humValue, humRemark);
+                                if (alarmUtil.checkAndSaveAlarm(deviceId, humWarningType, humWarningCode,
+                                        humMinValue, humMaxValue, BigDecimal.valueOf(finalValue), humRemark)) {
+                                    hasAlarm = true;
                                 }
                             }
                             if (nodeId == 3 && !Float.isNaN(nd.getHum())) {
@@ -238,20 +229,9 @@ public class RSServerService {
                                 Double humMaxValue = humThreshold != null ? humThreshold.getMaxValue() : null;
                                 String humWarningType = humThreshold != null ? humThreshold.getWarningType() : "氨氮预警";
                                 String humRemark = humThreshold != null ? humThreshold.getRemark() : "环境氨氮报警";
-
-                                boolean humShouldAlarm = false;
-                                BigDecimal humValue = BigDecimal.valueOf(finalValue);
-                                if (humMinValue != null && finalValue <= humMinValue) {
-                                    humShouldAlarm = true;
-                                }
-                                if (humMaxValue != null && finalValue >= humMaxValue) {
-                                    humShouldAlarm = true;
-                                }
-                                if (humShouldAlarm) {
-                                    alarmUtil.saveAlarm(deviceId, humWarningType, humWarningCode,
-                                            humMinValue != null ? BigDecimal.valueOf(humMinValue) : null,
-                                            humMaxValue != null ? BigDecimal.valueOf(humMaxValue) : null,
-                                            humValue, humRemark);
+                                if (alarmUtil.checkAndSaveAlarm(deviceId, humWarningType, humWarningCode,
+                                        humMinValue, humMaxValue, BigDecimal.valueOf(finalValue), humRemark)) {
+                                    hasAlarm = true;
                                 }
                             }
                             if (nodeId == 4 && !Float.isNaN(nd.getHum())) {
@@ -261,20 +241,9 @@ public class RSServerService {
                                 Double humMaxValue = humThreshold != null ? humThreshold.getMaxValue() : null;
                                 String humWarningType = humThreshold != null ? humThreshold.getWarningType() : "电导率预警";
                                 String humRemark = humThreshold != null ? humThreshold.getRemark() : "环境电导率报警";
-
-                                boolean humShouldAlarm = false;
-                                BigDecimal humValue = BigDecimal.valueOf(finalValue);
-                                if (humMinValue != null && finalValue <= humMinValue) {
-                                    humShouldAlarm = true;
-                                }
-                                if (humMaxValue != null && finalValue >= humMaxValue) {
-                                    humShouldAlarm = true;
-                                }
-                                if (humShouldAlarm) {
-                                    alarmUtil.saveAlarm(deviceId, humWarningType, humWarningCode,
-                                            humMinValue != null ? BigDecimal.valueOf(humMinValue) : null,
-                                            humMaxValue != null ? BigDecimal.valueOf(humMaxValue) : null,
-                                            humValue, humRemark);
+                                if (alarmUtil.checkAndSaveAlarm(deviceId, humWarningType, humWarningCode,
+                                        humMinValue, humMaxValue, BigDecimal.valueOf(finalValue), humRemark)) {
+                                    hasAlarm = true;
                                 }
                             }
                             if (nodeId == 5 && !Float.isNaN(nd.getHum())) {
@@ -284,20 +253,9 @@ public class RSServerService {
                                 Double humMaxValue = humThreshold != null ? humThreshold.getMaxValue() : null;
                                 String humWarningType = humThreshold != null ? humThreshold.getWarningType() : "PH预警";
                                 String humRemark = humThreshold != null ? humThreshold.getRemark() : "环境PH报警";
-
-                                boolean humShouldAlarm = false;
-                                BigDecimal humValue = BigDecimal.valueOf(finalValue);
-                                if (humMinValue != null && finalValue <= humMinValue) {
-                                    humShouldAlarm = true;
-                                }
-                                if (humMaxValue != null && finalValue >= humMaxValue) {
-                                    humShouldAlarm = true;
-                                }
-                                if (humShouldAlarm) {
-                                    alarmUtil.saveAlarm(deviceId, humWarningType, humWarningCode,
-                                            humMinValue != null ? BigDecimal.valueOf(humMinValue) : null,
-                                            humMaxValue != null ? BigDecimal.valueOf(humMaxValue) : null,
-                                            humValue, humRemark);
+                                if (alarmUtil.checkAndSaveAlarm(deviceId, humWarningType, humWarningCode,
+                                        humMinValue, humMaxValue, BigDecimal.valueOf(finalValue), humRemark)) {
+                                    hasAlarm = true;
                                 }
                             }
 
@@ -309,6 +267,8 @@ public class RSServerService {
                             log.error("实时数据入库失败:设备ID={}, 节点ID={}", data.getDeviceId(), nd.getNodeId(), e);
                         }
                     }
+                    // 同步设备报警状态到 equipment_status 表
+                    updateDeviceAlarmStatus(deviceId, hasAlarm ? 1 : 0);
                 }
 
                 @Override
@@ -424,4 +384,26 @@ public class RSServerService {
             return null;
         }
     }
+
+    /**
+     * 更新设备报警状态
+     * @param deviceCode 设备编码
+     * @param alarmStatus 报警状态:0-正常,1-报警
+     */
+    private void updateDeviceAlarmStatus(String deviceCode, int alarmStatus) {
+        try {
+            Map<String, Object> params = new HashMap<>();
+            params.put("deviceCode", deviceCode);
+            params.put("alarmStatus", alarmStatus);
+
+            HttpHeaders headers = new HttpHeaders();
+            headers.setContentType(MediaType.APPLICATION_JSON);
+            HttpEntity<Map<String, Object>> request = new HttpEntity<>(params, headers);
+
+            restTemplate.postForObject(deviceStatusApiUrl, request, Map.class);
+            log.info("设备报警状态更新成功: deviceCode={}, alarmStatus={}", deviceCode, alarmStatus);
+        } catch (Exception e) {
+            log.error("更新设备报警状态失败: deviceCode={}, alarmStatus={}", deviceCode, alarmStatus, e);
+        }
+    }
 }

+ 20 - 7
environment-service/src/main/java/com/zksy/environment/utils/AlarmUtil.java

@@ -3,6 +3,7 @@ package com.zksy.environment.utils;
 import com.alibaba.fastjson.JSONObject;
 import com.zksy.api.domain.AlarmData;
 import com.zksy.api.service.AlarmDataService;
+import com.zksy.api.service.EarlyWarningAutoService;
 import com.zksy.api.utils.AlarmLevelUtil;
 import com.zksy.api.utils.SmsUtil;
 import com.zksy.utils.DevicePhoneFetchUtil;
@@ -24,17 +25,26 @@ public class AlarmUtil {
     @Autowired
     private AlarmDataService alarmDataService;
     @Autowired
+    private EarlyWarningAutoService earlyWarningAutoService;
+    @Autowired
     private SmsUtil smsUtil;
     @Autowired
     private DevicePhoneFetchUtil devicePhoneFetchUtil;
 
-    public void checkAndSaveAlarm(String deviceCode,
+    /**
+     * 越限 → 报警;接近阈值未越限 → 自动预警
+     * @return 是否触发报警
+     */
+    public boolean checkAndSaveAlarm(String deviceCode,
                                     String warningType, String warningCode, Double minValue, Double maxValue,
                                     BigDecimal actualValue, String remark) {
-        if (actualValue == null) {
-            return;
+        if (actualValue == null || (minValue == null && maxValue == null)) {
+            return false;
         }
 
+        BigDecimal minBd = minValue != null ? BigDecimal.valueOf(minValue) : null;
+        BigDecimal maxBd = maxValue != null ? BigDecimal.valueOf(maxValue) : null;
+
         boolean shouldAlarm = false;
         if (minValue != null && actualValue.doubleValue() <= minValue) {
             shouldAlarm = true;
@@ -44,10 +54,13 @@ public class AlarmUtil {
         }
 
         if (shouldAlarm) {
-            saveAlarm(deviceCode, warningType, warningCode,
-                    minValue != null ? BigDecimal.valueOf(minValue) : null,
-                    maxValue != null ? BigDecimal.valueOf(maxValue) : null,
-                    actualValue, remark);
+            saveAlarm(deviceCode, warningType, warningCode, minBd, maxBd, actualValue, remark);
+            earlyWarningAutoService.closeAutoWarning(deviceCode, warningCode, "已达报警阈值,转报警处理");
+            return true;
+        } else {
+            earlyWarningAutoService.checkAndGenerate(deviceCode, warningType, warningCode,
+                    minBd, maxBd, actualValue, remark);
+            return false;
         }
     }
 

+ 128 - 74
firefighting-pressure-service/src/main/java/com/zksy/pressure/utils/MessageHandler.java

@@ -4,6 +4,7 @@ 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.WarningThreshold;
+import com.zksy.api.service.EarlyWarningAutoService;
 import com.zksy.api.service.WarningThresholdService;
 import com.zksy.api.domain.AlarmData;
 import com.zksy.api.service.AlarmDataService;
@@ -23,10 +24,16 @@ import lombok.extern.slf4j.Slf4j;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
 import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
 
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -41,9 +48,16 @@ public class MessageHandler extends ChannelInboundHandlerAdapter {
 	@Autowired
 	private AlarmDataService alarmDataService;
 	@Autowired
+	private EarlyWarningAutoService earlyWarningAutoService;
+	@Autowired
 	private SmsUtil smsUtil;
 	@Autowired
-	private DevicePhoneFetchUtil devicePhoneFetchUtil;
+    private DevicePhoneFetchUtil devicePhoneFetchUtil;
+    @Autowired
+    private RestTemplate restTemplate;
+
+    @Value("${device.status.api.url:http://zk-api-service/equipmentStatus/updateAlarmStatus}")
+    private String deviceStatusApiUrl;
 	@Autowired
 	public MessageHandler(FirefightingPressureService firefightingPressureService) {
 		this.firefightingPressureService = firefightingPressureService;
@@ -101,8 +115,8 @@ public class MessageHandler extends ChannelInboundHandlerAdapter {
 				logger.info("生成的回复报文: {}", responseMsg);
 				byte[] messageBytes = hexStringToByteArray(responseMsg);
 				ctx.channel().writeAndFlush(Unpooled.copiedBuffer(messageBytes));
-				//短信预警
-				//checkIfSmsAlertNeeded(resultData);
+				// 阈值监测:报警 + 接近阈值自动预警
+				checkIfSmsAlertNeeded(resultData);
 			}
 		} catch (InvalidMessageException e) {
 			logger.error("数据入库失败: {}", e.getMessage());
@@ -220,79 +234,97 @@ public class MessageHandler extends ChannelInboundHandlerAdapter {
 		}
 	}
 	//检查是否会触发短信预警
-	public void checkIfSmsAlertNeeded(FirefightingPressure resultData){
-		try {
-			//用遥测站地址作为设备的设备编号
-			String deviceId = resultData.getTelemeteringStation();
-
-			//1、获取到压力阈值
-			String warningCode = "WARN-PRESSURE";
-			WarningThreshold threshold = null;
+		public void checkIfSmsAlertNeeded(FirefightingPressure resultData){
 			try {
-				//1.2根据设备编码获取压力阈值
-				threshold = warningThresholdService.getWarningThresholdByDeviceAndCode(deviceId, warningCode);
-			} catch (Exception e) {
-				log.error("查询预警阈值失败");
-			}
+				//用遥测站地址作为设备的设备编号
+				String deviceId = resultData.getTelemeteringStation();
+				boolean hasAlarm = false;
 
-			String warningType = threshold != null ? threshold.getWarningType() : "压力预警";
-			String remark = threshold != null ? threshold.getRemark() : null;
-			Double minValue = threshold != null ? threshold.getMinValue() : null;
-			Double maxValue = threshold != null ? threshold.getMaxValue() : null;
+				//1、获取到压力阈值
+				String warningCode = "WARN-PRESSURE";
+				WarningThreshold threshold = null;
+				try {
+					//1.2根据设备编码获取压力阈值
+					threshold = warningThresholdService.getWarningThresholdByDeviceAndCode(deviceId, warningCode);
+				} catch (Exception e) {
+					log.error("查询预警阈值失败");
+				}
 
-			//1.2获取到实际压力值
-			Double pressureValue = resultData.getPressureValue();
-			boolean isOverThreshold = false;
-			if (minValue != null && pressureValue != null && pressureValue <= minValue) {
-				isOverThreshold = true;
-			}
-			if (maxValue != null && pressureValue != null && pressureValue >= maxValue) {
-				isOverThreshold = true;
-			}
-			//1.3超出了阈值则发送短信,先保存告警数据再发送短信
-			if(isOverThreshold){
-				int alarmLevel = saveAlarmData(deviceId, warningType, warningCode,
-						minValue != null ? BigDecimal.valueOf(minValue) : null,
-						maxValue != null ? BigDecimal.valueOf(maxValue) : null,
-						pressureValue != null ? BigDecimal.valueOf(pressureValue) : null,
-						remark != null ? remark : "压力报警");
-				if (alarmLevel == 1) {
-					sendMessage(deviceId,warningType,resultData.getLongitude(),resultData.getLatitude());
+				String warningType = threshold != null ? threshold.getWarningType() : "压力预警";
+				String remark = threshold != null ? threshold.getRemark() : null;
+				Double minValue = threshold != null ? threshold.getMinValue() : null;
+				Double maxValue = threshold != null ? threshold.getMaxValue() : null;
+
+				//1.2获取到实际压力值
+				Double pressureValue = resultData.getPressureValue();
+				if (pressureValue != null && (minValue != null || maxValue != null)) {
+					BigDecimal minBd = minValue != null ? BigDecimal.valueOf(minValue) : null;
+					BigDecimal maxBd = maxValue != null ? BigDecimal.valueOf(maxValue) : null;
+					BigDecimal actualBd = BigDecimal.valueOf(pressureValue);
+
+					boolean isOverThreshold = false;
+					if (minValue != null && pressureValue <= minValue) {
+						isOverThreshold = true;
+					}
+					if (maxValue != null && pressureValue >= maxValue) {
+						isOverThreshold = true;
+					}
+					if (isOverThreshold) {
+						int alarmLevel = saveAlarmData(deviceId, warningType, warningCode,
+								minBd, maxBd, actualBd, remark != null ? remark : "压力报警");
+						earlyWarningAutoService.closeAutoWarning(deviceId, warningCode, "已达报警阈值,转报警处理");
+						hasAlarm = true;
+						if (alarmLevel == 1) {
+							sendMessage(deviceId, warningType, resultData.getLongitude(), resultData.getLatitude());
+						}
+					} else {
+						earlyWarningAutoService.checkAndGenerate(deviceId, warningType, warningCode,
+								minBd, maxBd, actualBd, remark);
+					}
 				}
+				if(resultData.getD14()==1){
+					saveAlarmDataLevelOne(deviceId, "压力变幅报警", "WARN-PRESSURE-VARY", null, "压力变幅报警");
+					sendMessage(deviceId,"压力变幅报警",resultData.getLongitude(),resultData.getLatitude());
+					hasAlarm = true;
+				}
+				if(resultData.getD13()==1){
+					saveAlarmDataLevelOne(deviceId, "压力下下限报警", "WARN-PRESSURE-LOW-LOW", null, "压力下下限报警");
+					sendMessage(deviceId,"压力下下限报警",resultData.getLongitude(),resultData.getLatitude());
+					hasAlarm = true;
+				}
+				if(resultData.getD12()==1){
+					saveAlarmDataLevelOne(deviceId, "压力上上限报警", "WARN-PRESSURE-HIGH-HIGH", null, "压力上上限报警");
+					sendMessage(deviceId,"压力上上限报警",resultData.getLongitude(),resultData.getLatitude());
+					hasAlarm = true;
+				}
+				if(resultData.getD11()==1){
+					saveAlarmDataLevelOne(deviceId, "压力下线报警", "WARN-PRESSURE-LOW", null, "压力下线报警");
+					sendMessage(deviceId,"压力下线报警",resultData.getLongitude(),resultData.getLatitude());
+					hasAlarm = true;
+				}
+				if(resultData.getD10()==1){
+					saveAlarmDataLevelOne(deviceId, "压力上限报警", "WARN-PRESSURE-HIGH", null, "压力上限报警");
+					sendMessage(deviceId,"压力上限报警",resultData.getLongitude(),resultData.getLatitude());
+					hasAlarm = true;
+				}
+				if(resultData.getD9()==1){
+					saveAlarmDataLevelOne(deviceId, "传感器状态", "WARN-SENSOR-STATUS", null, "传感器状态");
+					sendMessage(deviceId,"传感器状态",resultData.getLongitude(),resultData.getLatitude());
+					hasAlarm = true;
+				}
+				if(resultData.getD1()==1){
+					saveAlarmDataLevelOne(deviceId, "倾斜报警1", "WARN-TILT-1", null, "倾斜报警1");
+					sendMessage(deviceId,"倾斜报警1",resultData.getLongitude(),resultData.getLatitude());
+					hasAlarm = true;
+				}
+
+				// 同步设备报警状态到 equipment_status 表
+				updateDeviceAlarmStatus(deviceId, hasAlarm ? 1 : 0);
+			} catch (Exception e) {
+				log.error("设备报警处理失败", e);
 			}
-			if(resultData.getD14()==1){
-				saveAlarmDataLevelOne(deviceId, "压力变幅报警", "WARN-PRESSURE-VARY", null, "压力变幅报警");
-				sendMessage(deviceId,"压力变幅报警",resultData.getLongitude(),resultData.getLatitude());
-			}
-			if(resultData.getD13()==1){
-				saveAlarmDataLevelOne(deviceId, "压力下下限报警", "WARN-PRESSURE-LOW-LOW", null, "压力下下限报警");
-				sendMessage(deviceId,"压力下下限报警",resultData.getLongitude(),resultData.getLatitude());
-			}
-			if(resultData.getD12()==1){
-				saveAlarmDataLevelOne(deviceId, "压力上上限报警", "WARN-PRESSURE-HIGH-HIGH", null, "压力上上限报警");
-				sendMessage(deviceId,"压力上上限报警",resultData.getLongitude(),resultData.getLatitude());
-			}
-			if(resultData.getD11()==1){
-				saveAlarmDataLevelOne(deviceId, "压力下线报警", "WARN-PRESSURE-LOW", null, "压力下线报警");
-				sendMessage(deviceId,"压力下线报警",resultData.getLongitude(),resultData.getLatitude());
-			}
-			if(resultData.getD10()==1){
-				saveAlarmDataLevelOne(deviceId, "压力上限报警", "WARN-PRESSURE-HIGH", null, "压力上限报警");
-				sendMessage(deviceId,"压力上限报警",resultData.getLongitude(),resultData.getLatitude());
-			}
-			if(resultData.getD9()==1){
-				saveAlarmDataLevelOne(deviceId, "传感器状态", "WARN-SENSOR-STATUS", null, "传感器状态");
-				sendMessage(deviceId,"传感器状态",resultData.getLongitude(),resultData.getLatitude());
-			}
-			if(resultData.getD1()==1){
-				saveAlarmDataLevelOne(deviceId, "倾斜报警1", "WARN-TILT-1", null, "倾斜报警1");
-				sendMessage(deviceId,"倾斜报警1",resultData.getLongitude(),resultData.getLatitude());
-			}
-		} catch (Exception e) {
-			log.error("设备报警处理失败", e);
-		}
 
-	}
+		}
 
 	private int saveAlarmData(String deviceCode, String warningType, String warningCode,
 							  BigDecimal minValue, BigDecimal maxValue,
@@ -357,7 +389,29 @@ public class MessageHandler extends ChannelInboundHandlerAdapter {
 		// 经纬度处理(为执行信息处理)
 		params.put("location", String.format("经纬度:%.6f,%.8f", lng, lat));
 		List<String> phoneListByDeviceId = devicePhoneFetchUtil.getPhoneListByDeviceId(deviceNo);
-		Map<String, Boolean> sendResults = smsUtil.sendBatchSms(phoneListByDeviceId, params.toJSONString());
-		log.info("发送信息完成");
-	}
-}
+			Map<String, Boolean> sendResults = smsUtil.sendBatchSms(phoneListByDeviceId, params.toJSONString());
+			log.info("发送信息完成");
+		}
+
+		/**
+		 * 更新设备报警状态
+		 * @param deviceCode 设备编码
+		 * @param alarmStatus 报警状态:0-正常,1-报警
+		 */
+		private void updateDeviceAlarmStatus(String deviceCode, int alarmStatus) {
+			try {
+				Map<String, Object> params = new HashMap<>();
+				params.put("deviceCode", deviceCode);
+				params.put("alarmStatus", alarmStatus);
+
+				HttpHeaders headers = new HttpHeaders();
+				headers.setContentType(MediaType.APPLICATION_JSON);
+				HttpEntity<Map<String, Object>> request = new HttpEntity<>(params, headers);
+
+				restTemplate.postForObject(deviceStatusApiUrl, request, Map.class);
+				log.info("设备报警状态更新成功: deviceCode={}, alarmStatus={}", deviceCode, alarmStatus);
+			} catch (Exception e) {
+				log.error("更新设备报警状态失败: deviceCode={}, alarmStatus={}", deviceCode, alarmStatus, e);
+			}
+		}
+	}

+ 116 - 36
flammable-gas-service/src/main/java/com/zksy/gas/utils/MessageHandler.java

@@ -1,7 +1,9 @@
 package com.zksy.gas.utils;
 
+import cn.hutool.core.lang.UUID;
 import com.alibaba.fastjson.JSONObject;
 import com.zksy.api.domain.WarningThreshold;
+import com.zksy.api.service.EarlyWarningAutoService;
 import com.zksy.api.service.WarningThresholdService;
 import com.zksy.api.domain.AlarmData;
 import com.zksy.api.service.AlarmDataService;
@@ -22,10 +24,16 @@ import lombok.extern.slf4j.Slf4j;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
 import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
 
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -40,11 +48,18 @@ public class MessageHandler extends ChannelInboundHandlerAdapter {
 	@Autowired
 	private AlarmDataService alarmDataService;
 	@Autowired
-	private SmsUtil smsUtil;
+	private EarlyWarningAutoService earlyWarningAutoService;
 	@Autowired
-	private DevicePhoneFetchUtil devicePhoneFetchUtil;
+	private SmsUtil smsUtil;
 	@Autowired
-	private AlarmUtil alarmUtil;
+    private DevicePhoneFetchUtil devicePhoneFetchUtil;
+    @Autowired
+    private AlarmUtil alarmUtil;
+    @Autowired
+    private RestTemplate restTemplate;
+
+    @Value("${device.status.api.url:http://zk-api-service/equipmentStatus/updateAlarmStatus}")
+    private String deviceStatusApiUrl;
 
 	@Autowired
 	public MessageHandler(GasMonitorDataService firefightingPressureService) {
@@ -177,8 +192,9 @@ public class MessageHandler extends ChannelInboundHandlerAdapter {
 		}
 	}
 	public void checkIfSmsAlertNeeded(GasMonitorData resultData){
-		//用MAC地址作为设备的设备编号
-		String deviceId = resultData.getMacAddress();
+        //用MAC地址作为设备的设备编号
+        String deviceId = resultData.getMacAddress();
+        boolean hasAlarm = false;
 
 		//获取温度阈值
 		String temWarningCode = "WARN-GAS-TEMPERATURE";
@@ -213,13 +229,21 @@ public class MessageHandler extends ChannelInboundHandlerAdapter {
 		if (temMaxValue != null && temperature >= temMaxValue) {
 			temperatureIsOverThreshold = true;
 		}
-		if(temperatureIsOverThreshold){
-			int alarmLevel = saveAlarmData(deviceId, temWarningType, temWarningCode,
-					temMinValue != null ? BigDecimal.valueOf(temMinValue) : null,
-					temMaxValue != null ? BigDecimal.valueOf(temMaxValue) : null,
-					BigDecimal.valueOf(temperature), temRemark != null ? temRemark : "可燃气体温度报警");
-			if (alarmLevel == 1) {
-				sendMessage(deviceId, temWarningType, resultData.getLongitude(), resultData.getLatitude());
+		BigDecimal temMinBd = temMinValue != null ? BigDecimal.valueOf(temMinValue) : null;
+		BigDecimal temMaxBd = temMaxValue != null ? BigDecimal.valueOf(temMaxValue) : null;
+		BigDecimal temActualBd = BigDecimal.valueOf(temperature);
+		if (temMinValue != null || temMaxValue != null) {
+			if (temperatureIsOverThreshold) {
+					int alarmLevel = saveAlarmData(deviceId, temWarningType, temWarningCode,
+							temMinBd, temMaxBd, temActualBd, temRemark != null ? temRemark : "可燃气体温度报警");
+					earlyWarningAutoService.closeAutoWarning(deviceId, temWarningCode, "已达报警阈值,转报警处理");
+					hasAlarm = true;
+					if (alarmLevel == 1) {
+					sendMessage(deviceId, temWarningType, resultData.getLongitude(), resultData.getLatitude());
+				}
+			} else {
+				earlyWarningAutoService.checkAndGenerate(deviceId, temWarningType, temWarningCode,
+						temMinBd, temMaxBd, temActualBd, temRemark);
 			}
 		}
 
@@ -232,13 +256,21 @@ public class MessageHandler extends ChannelInboundHandlerAdapter {
 		if (humMaxValue != null && humidity >= humMaxValue) {
 			humidityIsOverThreshold = true;
 		}
-		if(humidityIsOverThreshold){
-			int alarmLevel = saveAlarmData(deviceId, humWarningType, humWarningCode,
-					humMinValue != null ? BigDecimal.valueOf(humMinValue) : null,
-					humMaxValue != null ? BigDecimal.valueOf(humMaxValue) : null,
-					BigDecimal.valueOf(humidity), humRemark != null ? humRemark : "可燃气体湿度报警");
-			if (alarmLevel == 1) {
-				sendMessage(deviceId, humWarningType, resultData.getLongitude(), resultData.getLatitude());
+		BigDecimal humMinBd = humMinValue != null ? BigDecimal.valueOf(humMinValue) : null;
+		BigDecimal humMaxBd = humMaxValue != null ? BigDecimal.valueOf(humMaxValue) : null;
+		BigDecimal humActualBd = BigDecimal.valueOf(humidity);
+		if (humMinValue != null || humMaxValue != null) {
+			if (humidityIsOverThreshold) {
+					int alarmLevel = saveAlarmData(deviceId, humWarningType, humWarningCode,
+							humMinBd, humMaxBd, humActualBd, humRemark != null ? humRemark : "可燃气体湿度报警");
+					earlyWarningAutoService.closeAutoWarning(deviceId, humWarningCode, "已达报警阈值,转报警处理");
+					hasAlarm = true;
+					if (alarmLevel == 1) {
+					sendMessage(deviceId, humWarningType, resultData.getLongitude(), resultData.getLatitude());
+				}
+			} else {
+				earlyWarningAutoService.checkAndGenerate(deviceId, humWarningType, humWarningCode,
+						humMinBd, humMaxBd, humActualBd, humRemark);
 			}
 		}
 
@@ -252,85 +284,111 @@ public class MessageHandler extends ChannelInboundHandlerAdapter {
 		if (gasMaxValue != null && actualGasConcentration >= gasMaxValue) {
 			concentrationIsOverThreshold = true;
 		}
-		if(concentrationIsOverThreshold){
-			int alarmLevel = saveAlarmData(deviceId, gasWarningType, gasWarningCode,
-					gasMinValue != null ? BigDecimal.valueOf(gasMinValue) : null,
-					gasMaxValue != null ? BigDecimal.valueOf(gasMaxValue) : null,
-					gasConcentration, gasRemark != null ? gasRemark : "可燃气体浓度报警");
-			if (alarmLevel == 1) {
-				sendMessage(deviceId, gasWarningType, resultData.getLongitude(), resultData.getLatitude());
+		BigDecimal gasMinBd = gasMinValue != null ? BigDecimal.valueOf(gasMinValue) : null;
+		BigDecimal gasMaxBd = gasMaxValue != null ? BigDecimal.valueOf(gasMaxValue) : null;
+		if ((gasMinValue != null || gasMaxValue != null) && gasConcentration != null) {
+			if (concentrationIsOverThreshold) {
+					int alarmLevel = saveAlarmData(deviceId, gasWarningType, gasWarningCode,
+							gasMinBd, gasMaxBd, gasConcentration, gasRemark != null ? gasRemark : "可燃气体浓度报警");
+					earlyWarningAutoService.closeAutoWarning(deviceId, gasWarningCode, "已达报警阈值,转报警处理");
+					hasAlarm = true;
+					if (alarmLevel == 1) {
+					sendMessage(deviceId, gasWarningType, resultData.getLongitude(), resultData.getLatitude());
+				}
+			} else {
+				earlyWarningAutoService.checkAndGenerate(deviceId, gasWarningType, gasWarningCode,
+						gasMinBd, gasMaxBd, gasConcentration, gasRemark);
 			}
 		}
 
 		//获取到的数据逐一进行判断
 		Map<String, Boolean> alarmBits = resultData.parseAlarmBits();
 		if(alarmBits.get("unknownAlarm")){
-			saveAlarmDataLevelOne(deviceId, "未知报警", "WARN-UNKNOWN", null, "可燃气体未知报警");
-			sendMessage(deviceId,"未知报警",resultData.getLongitude(),resultData.getLatitude());
-		}
-		if(alarmBits.get("highAlarm")){
-			saveAlarmDataLevelOne(deviceId, "高报警", "WARN-HIGH", null, "可燃气体高报警");
-			sendMessage(deviceId,"高报警",resultData.getLongitude(),resultData.getLatitude());
-		}
+				saveAlarmDataLevelOne(deviceId, "未知报警", "WARN-UNKNOWN", null, "可燃气体未知报警");
+				sendMessage(deviceId,"未知报警",resultData.getLongitude(),resultData.getLatitude());
+				hasAlarm = true;
+			}
+			if(alarmBits.get("highAlarm")){
+				saveAlarmDataLevelOne(deviceId, "高报警", "WARN-HIGH", null, "可燃气体高报警");
+				sendMessage(deviceId,"高报警",resultData.getLongitude(),resultData.getLatitude());
+				hasAlarm = true;
+			}
 		if(alarmBits.get("overRange")){
 			saveAlarmDataLevelOne(deviceId, "超量程", "WARN-OVER-RANGE", null, "可燃气体超量程报警");
 			sendMessage(deviceId,"超量程",resultData.getLongitude(),resultData.getLatitude());
+			hasAlarm = true;
 		}
 		if(alarmBits.get("calibrationCycle")){
 			saveAlarmDataLevelOne(deviceId, "标定周期", "WARN-CALIBRATION-CYCLE", null, "可燃气体标定周期报警");
 			sendMessage(deviceId,"标定周期",resultData.getLongitude(),resultData.getLatitude());
+			hasAlarm = true;
 		}
 		if(alarmBits.get("overLife")){
 			saveAlarmDataLevelOne(deviceId, "超寿命", "WARN-OVER-LIFE", null, "可燃气体超寿命报警");
 			sendMessage(deviceId,"超寿命",resultData.getLongitude(),resultData.getLatitude());
+			hasAlarm = true;
 		}
 		if(alarmBits.get("fallAlarm")){
 			saveAlarmDataLevelOne(deviceId, "跌倒报警", "WARN-FALL", null, "可燃气体跌倒报警");
 			sendMessage(deviceId,"跌倒报警",resultData.getLongitude(),resultData.getLatitude());
+			hasAlarm = true;
 		}
 		if(alarmBits.get("undervoltage")){
 			saveAlarmDataLevelOne(deviceId, "欠压报警", "WARN-UNDERVOLTAGE", null, "可燃气体欠压报警");
 			sendMessage(deviceId,"欠压报警",resultData.getLongitude(),resultData.getLatitude());
+			hasAlarm = true;
 		}
 		if(alarmBits.get("rangeAlarm")){
 			saveAlarmDataLevelOne(deviceId, "区间报警", "WARN-RANGE", null, "可燃气体区间报警");
 			sendMessage(deviceId,"区间报警",resultData.getLongitude(),resultData.getLatitude());
+			hasAlarm = true;
 		}
 		if(alarmBits.get("keyAlarm")){
 			saveAlarmDataLevelOne(deviceId, "按键报警", "WARN-KEY", null, "可燃气体按键报警");
 			sendMessage(deviceId,"按键报警",resultData.getLongitude(),resultData.getLatitude());
+			hasAlarm = true;
 		}
 		if(alarmBits.get("vibrationAlarm")){
 			saveAlarmDataLevelOne(deviceId, "震动报警", "WARN-VIBRATION", null, "可燃气体震动报警");
 			sendMessage(deviceId,"震动报警",resultData.getLongitude(),resultData.getLatitude());
+			hasAlarm = true;
 		}
 		if(alarmBits.get("waterLevelAlarm")){
 			saveAlarmDataLevelOne(deviceId, "水位报警", "WARN-WATER-LEVEL", null, "可燃气体水位报警");
 			sendMessage(deviceId,"水位报警",resultData.getLongitude(),resultData.getLatitude());
+			hasAlarm = true;
 		}
 		if(alarmBits.get("powerOffAlarm")){
 			saveAlarmDataLevelOne(deviceId, "断电报警", "WARN-POWER-OFF", null, "可燃气体断电报警");
 			sendMessage(deviceId,"断电报警",resultData.getLongitude(),resultData.getLatitude());
+			hasAlarm = true;
 		}
 		if(alarmBits.get("sensorFault")){
 			saveAlarmDataLevelOne(deviceId, "传感器故障", "WARN-SENSOR-FAULT", null, "可燃气体传感器故障");
 			sendMessage(deviceId,"传感器故障",resultData.getLongitude(),resultData.getLatitude());
+			hasAlarm = true;
 		}
 		if(alarmBits.get("overHumidity")){
 			saveAlarmDataLevelOne(deviceId, "超湿报警", "WARN-OVER-HUMIDITY", null, "可燃气体超湿报警");
 			sendMessage(deviceId,"超湿报警",resultData.getLongitude(),resultData.getLatitude());
+			hasAlarm = true;
 		}
 		if(alarmBits.get("overTemperature")){
 			saveAlarmDataLevelOne(deviceId, "超温报警", "WARN-OVER-TEMPERATURE", null, "可燃气体超温报警");
 			sendMessage(deviceId,"超温报警",resultData.getLongitude(),resultData.getLatitude());
+			hasAlarm = true;
 		}
 		if(alarmBits.get("systemFault")){
 			saveAlarmDataLevelOne(deviceId, "系统故障", "WARN-SYSTEM-FAULT", null, "可燃气体系统故障");
 			sendMessage(deviceId,"系统故障",resultData.getLongitude(),resultData.getLatitude());
+			hasAlarm = true;
+			}
+
+			// 同步设备报警状态到 equipment_status 表
+			updateDeviceAlarmStatus(deviceId, hasAlarm ? 1 : 0);
 		}
-	}
 
-	private WarningThreshold checkThreshold(String deviceCode, String warningCode) {
+		private WarningThreshold checkThreshold(String deviceCode, String warningCode) {
 		try {
 			return warningThresholdService.getWarningThresholdByDeviceAndCode(deviceCode, warningCode);
 		} catch (Exception e) {
@@ -404,5 +462,27 @@ public class MessageHandler extends ChannelInboundHandlerAdapter {
 		List<String> phoneListByDeviceId = devicePhoneFetchUtil.getPhoneListByDeviceId(deviceNo);
 		Map<String, Boolean> sendResults = smsUtil.sendBatchSms(phoneListByDeviceId, params.toJSONString());
 		log.info("发送信息完成");
-	}
+    }
+
+    /**
+     * 更新设备报警状态
+     * @param deviceCode 设备编码
+     * @param alarmStatus 报警状态:0-正常,1-报警
+     */
+    private void updateDeviceAlarmStatus(String deviceCode, int alarmStatus) {
+        try {
+            Map<String, Object> params = new HashMap<>();
+            params.put("deviceCode", deviceCode);
+            params.put("alarmStatus", alarmStatus);
+
+            HttpHeaders headers = new HttpHeaders();
+            headers.setContentType(MediaType.APPLICATION_JSON);
+            HttpEntity<Map<String, Object>> request = new HttpEntity<>(params, headers);
+
+            restTemplate.postForObject(deviceStatusApiUrl, request, Map.class);
+            log.info("设备报警状态更新成功: deviceCode={}, alarmStatus={}", deviceCode, alarmStatus);
+        } catch (Exception e) {
+            log.error("更新设备报警状态失败: deviceCode={}, alarmStatus={}", deviceCode, alarmStatus, e);
+        }
+    }
 }

+ 80 - 101
manhole-service/src/main/java/com/zksy/manhole/service/impl/ManholeDataServiceImpl.java

@@ -1,64 +1,43 @@
 package com.zksy.manhole.service.impl;
 
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.zksy.api.domain.WarningThreshold;
-import com.zksy.api.service.WarningThresholdService;
+import com.zksy.api.utils.AlarmLevelUtil;
 import com.zksy.manhole.domain.ManholeData;
 import com.zksy.manhole.mapper.ManholeDataMapper;
 import com.zksy.manhole.service.ManholeDataService;
 import com.zksy.manhole.utils.AlarmUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Service;
-import org.springframework.web.client.RestTemplate;
 
 import java.math.BigDecimal;
-import java.util.List;
-import java.util.stream.Collectors;
 
 /**
- * @author Administrator
- * @version 1.0
- * @project dh-server-micro
- * @description
- * @date 2025/2/20 10:55:03
+ * 井盖数据Service业务层处理
+ * 
+ * @author zksy
  */
 @Slf4j
 @Service
 public class ManholeDataServiceImpl extends ServiceImpl<ManholeDataMapper, ManholeData> implements ManholeDataService {
+
     @Autowired
     private ManholeDataMapper manholeDataMapper;
     @Autowired
     private AlarmUtil alarmUtil;
-    @Autowired
-    private WarningThresholdService warningThresholdService;
-    //@Autowired
-    //private BaseDevicesService baseDevicesService;
-    @Autowired
-    private RestTemplate restTemplate;
 
-    @Value("${websocket.url:http://127.0.0.1:8103}")
-    private String BASE_URL;
+    /** 倾斜角度告警编码 */
+    private static final String WARN_CODE_TILT = "WARN-TILT";
+    /** 设备报警编码 */
+    private static final String WARN_CODE_DEVICE = "WARN-DEVICE-ALARM";
+    /** 水浸告警编码 */
+    private static final String WARN_CODE_WATER_INFILTRATION = "WARN-WATER-INFILTRATION";
+    /** 水位告警编码 */
+    private static final String WARN_CODE_WATER_LEVEL = "WARN-WATER-LEVEL";
+
     @Override
     public Integer saveManholeData(ManholeData result) {
         Integer resultData = manholeDataMapper.insert(result);
-        // 更新设备状态为在线
-        //baseDevicesService.getByDeviceNumberStatus(result.getImeiCardNumber(),0,1);
-
-        /*if(resultData > 0 && Integer.parseInt(result.getTiltAngle()) > 60) {
-            String url = BASE_URL + "/push/pushAll?msg=" + result.getTiltAngle();
-            try {
-                // 调用目标接口并获取响应实体
-                ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
-                System.out.println("webSocket响应:" + response.getBody());
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        }*/
 
         if (resultData > 0) {
             checkAndSaveAlarm(result);
@@ -67,87 +46,87 @@ public class ManholeDataServiceImpl extends ServiceImpl<ManholeDataMapper, Manho
         return resultData;
     }
 
+    /**
+     * 检查并保存告警数据
+     * - 倾斜角度:阈值来自采集数据字段 angleAlarmThreshold,根据偏差率计算告警等级
+     * - 设备报警/水浸/水位:状态型告警,告警即为1级
+     */
     private void checkAndSaveAlarm(ManholeData result) {
         String deviceCode = result.getImeiCardNumber();
+        boolean hasAlarm = false;
 
-        // 温度判断
-        if (result.getTemperatureValue() != null && !result.getTemperatureValue().isEmpty()) {
-            try {
-                String temWarningCode = "WARN-TEMPERATURE";
-                WarningThreshold temThreshold = checkThreshold(deviceCode, temWarningCode);
-                Double temMinValue = temThreshold != null ? temThreshold.getMinValue() : null;
-                Double temMaxValue = temThreshold != null ? temThreshold.getMaxValue() : 50.0;
-                String temWarningType = temThreshold != null ? temThreshold.getWarningType() : "温度预警";
-                String temRemark = temThreshold != null ? temThreshold.getRemark() : "井盖温度报警";
-
-                BigDecimal temValue = new BigDecimal(result.getTemperatureValue());
-                boolean temShouldAlarm = false;
-                if (temMinValue != null && temValue.doubleValue() <= temMinValue) {
-                    temShouldAlarm = true;
-                }
-                if (temMaxValue != null && temValue.doubleValue() >= temMaxValue) {
-                    temShouldAlarm = true;
-                }
-                if (temShouldAlarm) {
-                    alarmUtil.saveAlarm(deviceCode, temWarningType, temWarningCode,
-                            temMinValue != null ? BigDecimal.valueOf(temMinValue) : null,
-                            temMaxValue != null ? BigDecimal.valueOf(temMaxValue) : null,
-                            temValue, temRemark);
-                }
-            } catch (Exception e) {
-                log.error("处理温度报警失败", e);
-            }
-        }
-
-        // 倾斜判断
-        if (result.getTiltAngle() != null && !result.getTiltAngle().isEmpty() 
-                && result.getAngleAlarmThreshold() != null && !result.getAngleAlarmThreshold().isEmpty()) {
-            try {
-                String tiltWarningCode = "WARN-TILT";
-                WarningThreshold tiltThreshold = checkThreshold(deviceCode, tiltWarningCode);
-                Double tiltMinValue = tiltThreshold != null ? tiltThreshold.getMinValue() : null;
-                Double tiltMaxValue = tiltThreshold != null ? tiltThreshold.getMaxValue() : Double.parseDouble(result.getAngleAlarmThreshold());
-                String tiltWarningType = tiltThreshold != null ? tiltThreshold.getWarningType() : "倾斜预警";
-                String tiltRemark = tiltThreshold != null ? tiltThreshold.getRemark() : "井盖倾斜报警";
-
-                double tiltAngle = Double.parseDouble(result.getTiltAngle());
-                boolean tiltShouldAlarm = false;
-                if (tiltMinValue != null && tiltAngle <= tiltMinValue) {
-                    tiltShouldAlarm = true;
-                }
-                if (tiltMaxValue != null && tiltAngle >= tiltMaxValue) {
-                    tiltShouldAlarm = true;
-                }
-                if (tiltShouldAlarm) {
-                    alarmUtil.saveAlarm(deviceCode, tiltWarningType, tiltWarningCode,
-                            tiltMinValue != null ? BigDecimal.valueOf(tiltMinValue) : null,
-                            tiltMaxValue != null ? BigDecimal.valueOf(tiltMaxValue) : null,
-                            BigDecimal.valueOf(tiltAngle), tiltRemark);
-                }
-            } catch (Exception e) {
-                log.error("处理倾斜报警失败", e);
-            }
+        // 1. 倾斜角度告警:阈值从采集数据字段 angleAlarmThreshold 获取
+        if (checkTiltAlarm(result, deviceCode)) {
+            hasAlarm = true;
         }
 
+        // 2. 设备报警状态:告警即为1级
         if ("1".equals(result.getAlarmStatus())) {
-            alarmUtil.saveAlarm(deviceCode, "设备报警", "WARN-DEVICE-ALARM", null, null, null, "井盖设备状态报警");
+            alarmUtil.saveAlarmWithLevel(deviceCode, "设备报警", WARN_CODE_DEVICE,
+                    null, 1, "井盖设备状态报警");
+            hasAlarm = true;
         }
 
+        // 3. 水浸报警状态:告警即为1级
         if ("1".equals(result.getWaterInfiltrationAlarmStatus())) {
-            alarmUtil.saveAlarm(deviceCode, "水浸预警", "WARN-WATER-INFILTRATION", null, null, null, "井盖水浸报警");
+            alarmUtil.saveAlarmWithLevel(deviceCode, "水浸预警", WARN_CODE_WATER_INFILTRATION,
+                    null, 1, "井盖水浸报警");
+            hasAlarm = true;
         }
 
+        // 4. 水位报警状态:告警即为1级
         if ("1".equals(result.getWaterLevelAlarmStatus())) {
-            alarmUtil.saveAlarm(deviceCode, "水位预警", "WARN-WATER-LEVEL", null, null, null, "井盖水位报警");
+            alarmUtil.saveAlarmWithLevel(deviceCode, "水位预警", WARN_CODE_WATER_LEVEL,
+                    null, 1, "井盖水位报警");
+            hasAlarm = true;
         }
+
+        // 5. 同步设备报警状态到 equipment_status 表
+        alarmUtil.updateDeviceAlarmStatus(deviceCode, hasAlarm ? 1 : 0);
     }
 
-    private WarningThreshold checkThreshold(String deviceCode, String warningCode) {
+    /**
+     * 倾斜角度告警检查
+     * 阈值直接从采集数据字段 angleAlarmThreshold 获取,不再查询阈值表
+     * 根据实际值和阈值的偏差率计算告警等级
+     * @return 是否触发告警
+     */
+    private boolean checkTiltAlarm(ManholeData result, String deviceCode) {
+        String tiltAngleStr = result.getTiltAngle();
+        String angleThresholdStr = result.getAngleAlarmThreshold();
+
+        if (tiltAngleStr == null || tiltAngleStr.isEmpty()
+                || angleThresholdStr == null || angleThresholdStr.isEmpty()) {
+            return false;
+        }
+
         try {
-            return warningThresholdService.getWarningThresholdByDeviceAndCode(deviceCode, warningCode);
-        } catch (Exception e) {
-            log.error("查询预警阈值失败:deviceCode={}, warningCode={}", deviceCode, warningCode, e);
-            return null;
+            BigDecimal tiltAngle = new BigDecimal(tiltAngleStr);
+            BigDecimal angleThreshold = new BigDecimal(angleThresholdStr);
+
+            // 倾斜角度超过阈值才告警
+            if (tiltAngle.compareTo(angleThreshold) < 0) {
+                return false;
+            }
+
+            // 使用 AlarmLevelUtil 计算告警等级
+            // minValue=0(正常角度为0),maxValue=angleThreshold(阈值作为上限)
+            BigDecimal minValue = BigDecimal.ZERO;
+            int alarmLevel = AlarmLevelUtil.calculateLevel(tiltAngle, minValue, angleThreshold);
+            BigDecimal deviationRatio = AlarmLevelUtil.calculateDeviationRatio(tiltAngle, minValue, angleThreshold);
+
+            String remark = String.format("井盖倾斜报警,当前角度:%s°,阈值:%s°",
+                    tiltAngle, angleThreshold);
+
+            alarmUtil.saveAlarm(deviceCode, "倾斜预警", WARN_CODE_TILT,
+                    minValue, angleThreshold, tiltAngle, remark);
+
+            log.info("倾斜告警入库: deviceCode={}, tiltAngle={}°, threshold={}°, level={}级, deviationRatio={}%",
+                    deviceCode, tiltAngle, angleThreshold, alarmLevel, deviationRatio);
+            return true;
+        } catch (NumberFormatException e) {
+            log.error("倾斜角度或阈值解析失败: tiltAngle={}, threshold={}", tiltAngleStr, angleThresholdStr, e);
+            return false;
         }
     }
-}
+}

+ 67 - 0
manhole-service/src/main/java/com/zksy/manhole/utils/AlarmUtil.java

@@ -36,6 +36,9 @@ public class AlarmUtil {
     @Value("${alarm.api.url:http://zk-api-service/alarmData/save}")
     private String alarmApiUrl;
 
+    @Value("${device.status.api.url:http://zk-api-service/equipmentStatus/updateAlarmStatus}")
+    private String deviceStatusApiUrl;
+
     public void checkAndSaveAlarm(String deviceCode,
                                     String warningType, String warningCode, Double minValue, Double maxValue,
                                     BigDecimal actualValue, String remark) {
@@ -99,6 +102,48 @@ public class AlarmUtil {
         return alarmLevel;
     }
 
+    /**
+     * 保存告警数据(指定告警等级,适用于状态型告警)
+     * @param deviceCode 设备编码
+     * @param warningType 告警类型
+     * @param warningCode 告警编码
+     * @param actualValue 实际值(可为null)
+     * @param alarmLevel 告警等级(1-4)
+     * @param remark 备注
+     * @return 告警等级
+     */
+    public int saveAlarmWithLevel(String deviceCode,
+                                   String warningType, String warningCode,
+                                   BigDecimal actualValue, int alarmLevel, String remark) {
+        try {
+            Map<String, Object> alarmData = new HashMap<>();
+            alarmData.put("deviceCode", deviceCode);
+            alarmData.put("warningType", warningType);
+            alarmData.put("warningCode", warningCode);
+            alarmData.put("actualValue", actualValue);
+            alarmData.put("alarmLevel", alarmLevel);
+            alarmData.put("deviationRatio", BigDecimal.ZERO);
+            alarmData.put("alarmStatus", 0);
+            alarmData.put("alarmTime", LocalDateTime.now().toString());
+            alarmData.put("remark", remark);
+
+            HttpHeaders headers = new HttpHeaders();
+            headers.setContentType(MediaType.APPLICATION_JSON);
+            HttpEntity<Map<String, Object>> request = new HttpEntity<>(alarmData, headers);
+
+            restTemplate.postForObject(alarmApiUrl, request, AjaxResult.class);
+
+            if (alarmLevel == 1) {
+                log.warn("【1级紧急告警】deviceCode={}, warningCode={}", deviceCode, warningCode);
+                sendAlarmSms(deviceCode, warningType, actualValue, null, null);
+            }
+            log.info("告警数据入库成功: deviceCode={}, warningCode={}, level={}级", deviceCode, warningCode, alarmLevel);
+        } catch (Exception e) {
+            log.error("保存告警数据异常: {}", e.getMessage());
+        }
+        return alarmLevel;
+    }
+
     private void sendAlarmSms(String deviceCode, String warningType, BigDecimal actualValue,
                               BigDecimal minValue, BigDecimal maxValue) {
         try {
@@ -119,4 +164,26 @@ public class AlarmUtil {
             log.error("发送报警短信异常: {}", e.getMessage());
         }
     }
+
+    /**
+     * 更新设备报警状态
+     * @param deviceCode 设备编码
+     * @param alarmStatus 报警状态:0-正常,1-报警
+     */
+    public void updateDeviceAlarmStatus(String deviceCode, int alarmStatus) {
+        try {
+            Map<String, Object> params = new HashMap<>();
+            params.put("deviceCode", deviceCode);
+            params.put("alarmStatus", alarmStatus);
+
+            HttpHeaders headers = new HttpHeaders();
+            headers.setContentType(MediaType.APPLICATION_JSON);
+            HttpEntity<Map<String, Object>> request = new HttpEntity<>(params, headers);
+
+            restTemplate.postForObject(deviceStatusApiUrl, request, Map.class);
+            log.info("设备报警状态更新成功: deviceCode={}, alarmStatus={}", deviceCode, alarmStatus);
+        } catch (Exception e) {
+            log.error("更新设备报警状态失败: deviceCode={}, alarmStatus={}", deviceCode, alarmStatus, e);
+        }
+    }
 }

+ 3 - 0
pipe-network-service/zksy-system/src/main/java/com/zksy/base/domain/AlarmAssignDetail.java

@@ -4,6 +4,8 @@ import com.zksy.common.annotation.Excel;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
 
 import java.io.Serializable;
 
@@ -20,6 +22,7 @@ public class AlarmAssignDetail implements Serializable
     private static final long serialVersionUID = 1L;
 
     /** 报警清单明细ID */
+    @TableId(type = IdType.ASSIGN_ID)
     @ApiModelProperty(value = "报警清单明细ID", required = true)
     private Long alarmAssignDetailId;
 

+ 3 - 0
pipe-network-service/zksy-system/src/main/java/com/zksy/base/domain/AlarmAssignList.java

@@ -5,6 +5,8 @@ import com.zksy.common.annotation.Excel;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
 
 import java.io.Serializable;
 import java.util.Date;
@@ -22,6 +24,7 @@ public class AlarmAssignList implements Serializable
     private static final long serialVersionUID = 1L;
 
     /** 报警清单ID */
+    @TableId(type = IdType.ASSIGN_ID)
     @Excel(name = "报警清单ID")
     @ApiModelProperty(value = "报警清单ID", required = true)
     private Long alarmAssignId;

+ 2 - 0
pipe-network-service/zksy-system/src/main/java/com/zksy/base/service/impl/AlarmAssignDetailServiceImpl.java

@@ -3,6 +3,7 @@ package com.zksy.base.service.impl;
 import java.util.List;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
 import com.zksy.base.mapper.AlarmAssignDetailMapper;
 import com.zksy.base.domain.AlarmAssignDetail;
 import com.zksy.base.service.IAlarmAssignDetailService;
@@ -52,6 +53,7 @@ public class AlarmAssignDetailServiceImpl implements IAlarmAssignDetailService
     @Override
     public int insertAlarmAssignDetail(AlarmAssignDetail alarmAssignDetail)
     {
+        alarmAssignDetail.setAlarmAssignDetailId(IdWorker.getId());
         return alarmAssignDetailMapper.insertAlarmAssignDetail(alarmAssignDetail);
     }
 

+ 2 - 0
pipe-network-service/zksy-system/src/main/java/com/zksy/base/service/impl/AlarmAssignListServiceImpl.java

@@ -2,6 +2,7 @@ package com.zksy.base.service.impl;
 
 import cn.hutool.core.collection.CollUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.zksy.base.domain.AlarmAssignDetail;
@@ -72,6 +73,7 @@ public class AlarmAssignListServiceImpl extends ServiceImpl<AlarmAssignListMappe
     @Override
     public int insertAlarmAssignList(AlarmAssignList alarmAssignList)
     {
+        alarmAssignList.setAlarmAssignId(IdWorker.getId());
         return this.baseMapper.insertAlarmAssignList(alarmAssignList);
     }
 

+ 140 - 80
radar-service/src/main/java/com/zksy/radar/utils/MessageHandler.java

@@ -3,6 +3,7 @@ package com.zksy.radar.utils;
 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.SmsUtil;
@@ -20,10 +21,16 @@ import lombok.extern.slf4j.Slf4j;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
 import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
 
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -35,18 +42,27 @@ public class MessageHandler extends ChannelInboundHandlerAdapter {
 	private final RadarDataService service;
 	private final WarningThresholdService warningThresholdService;
 	private final AlarmDataService alarmDataService;
+	private final EarlyWarningAutoService earlyWarningAutoService;
 	private final SmsUtil smsUtil;
 	private final DevicePhoneFetchUtil devicePhoneFetchUtil;
-
-	@Autowired
-	public MessageHandler(RadarDataService RadarDataService, WarningThresholdService warningThresholdService,
-	                       AlarmDataService alarmDataService, SmsUtil smsUtil, DevicePhoneFetchUtil devicePhoneFetchUtil) {
-		this.service = RadarDataService;
-		this.warningThresholdService = warningThresholdService;
-		this.alarmDataService = alarmDataService;
-		this.smsUtil = smsUtil;
-		this.devicePhoneFetchUtil = devicePhoneFetchUtil;
-	}
+    private final RestTemplate restTemplate;
+
+    @Value("${device.status.api.url:http://zk-api-service/equipmentStatus/updateAlarmStatus}")
+    private String deviceStatusApiUrl;
+
+    @Autowired
+    public MessageHandler(RadarDataService RadarDataService, WarningThresholdService warningThresholdService,
+                           AlarmDataService alarmDataService, EarlyWarningAutoService earlyWarningAutoService,
+                           SmsUtil smsUtil, DevicePhoneFetchUtil devicePhoneFetchUtil,
+                           RestTemplate restTemplate) {
+        this.service = RadarDataService;
+        this.warningThresholdService = warningThresholdService;
+        this.alarmDataService = alarmDataService;
+        this.earlyWarningAutoService = earlyWarningAutoService;
+        this.smsUtil = smsUtil;
+        this.devicePhoneFetchUtil = devicePhoneFetchUtil;
+        this.restTemplate = restTemplate;
+    }
 
 	@Override
 	public void channelActive(ChannelHandlerContext ctx) throws Exception {
@@ -190,89 +206,111 @@ public class MessageHandler extends ChannelInboundHandlerAdapter {
 	}
 
 	/**
-	 * 处理雷达设备告警
-	 */
-	private void handleRadarAlarm(RadarData resultData) {
-		try {
-			// 设备编码从设备数据获取
-			String deviceCode = resultData.getDeviceCode();
-			if (deviceCode == null) {
-				deviceCode = resultData.getSystemIdentifier();
-			}
+		 * 处理雷达设备告警
+		 */
+		private void handleRadarAlarm(RadarData resultData) {
+			try {
+				// 设备编码从设备数据获取
+				String deviceCode = resultData.getDeviceCode();
+				if (deviceCode == null) {
+					deviceCode = resultData.getSystemIdentifier();
+				}
 
-			// 1. 处理瞬时流量告警
-			if (resultData.getMeter1InstantFlow() != null) {
-				handleAlarm(deviceCode, "WARN_INSTANT_FLOW", "瞬时流量", 
-					resultData.getMeter1InstantFlow());
-			}
+				boolean hasAlarm = false;
 
-			// 2. 处理流速告警
-			if (resultData.getFlowSpeed() != null) {
-				handleAlarm(deviceCode, "WARN_FLOW_SPEED", "流速", 
-					resultData.getFlowSpeed());
-			}
+				// 1. 处理瞬时流量告警
+				if (resultData.getMeter1InstantFlow() != null) {
+					if (handleAlarm(deviceCode, "WARN_INSTANT_FLOW", "瞬时流量", 
+						resultData.getMeter1InstantFlow())) {
+						hasAlarm = true;
+					}
+				}
 
-		} catch (Exception e) {
-			logger.error("雷达告警处理异常", e);
+				// 2. 处理流速告警
+				if (resultData.getFlowSpeed() != null) {
+					if (handleAlarm(deviceCode, "WARN_FLOW_SPEED", "流速", 
+						resultData.getFlowSpeed())) {
+						hasAlarm = true;
+					}
+				}
+
+				// 同步设备报警状态到 equipment_status 表
+				updateDeviceAlarmStatus(deviceCode, hasAlarm ? 1 : 0);
+
+			} catch (Exception e) {
+				logger.error("雷达告警处理异常", e);
+			}
 		}
-	}
 
 	/**
-	 * 处理单个告警
-	 */
-	private void handleAlarm(String deviceCode, String warningCode, String warningType, String valueStr) {
-		try {
-			// 解析实际值
-			Double actualValue = null;
+		 * 处理单个告警
+		 * @return 是否触发告警
+		 */
+		private boolean handleAlarm(String deviceCode, String warningCode, String warningType, String valueStr) {
 			try {
-				actualValue = Double.parseDouble(valueStr);
-			} catch (NumberFormatException e) {
-				logger.warn("无法解析告警值: {}", valueStr);
-				return;
-			}
+				// 解析实际值
+				Double actualValue = null;
+				try {
+					actualValue = Double.parseDouble(valueStr);
+				} catch (NumberFormatException e) {
+					logger.warn("无法解析告警值: {}", valueStr);
+					return false;
+				}
 
-			// 查询预警阈值表
-			WarningThreshold threshold = null;
-			try {
-				threshold = warningThresholdService.getWarningThresholdByDeviceAndCode(deviceCode, warningCode);
-			} catch (Exception e) {
-				logger.error("查询预警阈值失败: deviceCode={}, warningCode={}", deviceCode, warningCode, e);
-			}
+				// 查询预警阈值表
+				WarningThreshold threshold = null;
+				try {
+					threshold = warningThresholdService.getWarningThresholdByDeviceAndCode(deviceCode, warningCode);
+				} catch (Exception e) {
+					logger.error("查询预警阈值失败: deviceCode={}, warningCode={}", deviceCode, warningCode, e);
+				}
 
-			// 使用阈值表中的预警类型(如果有的话)
-			if (threshold != null && threshold.getWarningType() != null) {
-				warningType = threshold.getWarningType();
-			}
+				// 使用阈值表中的预警类型(如果有的话)
+				if (threshold != null && threshold.getWarningType() != null) {
+					warningType = threshold.getWarningType();
+				}
 
-			// 获取最小值和最大值
-			Double minValue = threshold != null ? threshold.getMinValue() : null;
-			Double maxValue = threshold != null ? threshold.getMaxValue() : null;
-			String remark = threshold != null ? threshold.getRemark() : null;
+				// 获取最小值和最大值
+				Double minValue = threshold != null ? threshold.getMinValue() : null;
+				Double maxValue = threshold != null ? threshold.getMaxValue() : null;
+				String remark = threshold != null ? threshold.getRemark() : null;
 
-			// 判断是否触发报警
-			boolean isOverThreshold = false;
-			if (minValue != null && actualValue <= minValue) {
-				isOverThreshold = true;
-			}
-			if (maxValue != null && actualValue >= maxValue) {
-				isOverThreshold = true;
-			}
+				// 未配置阈值则跳过
+				if (minValue == null && maxValue == null) {
+					return false;
+				}
 
-			if (isOverThreshold) {
-				logger.warn("设备{}触发{}告警(当前值:{},最小值:{},最大值:{})",
-					deviceCode, warningType, actualValue, minValue, maxValue);
+				BigDecimal minBd = minValue != null ? BigDecimal.valueOf(minValue) : null;
+				BigDecimal maxBd = maxValue != null ? BigDecimal.valueOf(maxValue) : null;
+				BigDecimal actualBd = BigDecimal.valueOf(actualValue);
 
-				// 保存到 alarm_data 表
-				saveAlarmData(deviceCode, warningType, warningCode,
-					minValue != null ? BigDecimal.valueOf(minValue) : null,
-					maxValue != null ? BigDecimal.valueOf(maxValue) : null,
-					BigDecimal.valueOf(actualValue), remark);
-			}
+				// 判断是否触发报警
+				boolean isOverThreshold = false;
+				if (minValue != null && actualValue <= minValue) {
+					isOverThreshold = true;
+				}
+				if (maxValue != null && actualValue >= maxValue) {
+					isOverThreshold = true;
+				}
 
-		} catch (Exception e) {
-			logger.error("处理告警异常", e);
+				if (isOverThreshold) {
+					logger.warn("设备{}触发{}告警(当前值:{},最小值:{},最大值:{})",
+						deviceCode, warningType, actualValue, minValue, maxValue);
+
+					saveAlarmData(deviceCode, warningType, warningCode, minBd, maxBd, actualBd, remark);
+					earlyWarningAutoService.closeAutoWarning(deviceCode, warningCode, "已达报警阈值,转报警处理");
+					return true;
+				} else {
+					earlyWarningAutoService.checkAndGenerate(deviceCode, warningType, warningCode,
+							minBd, maxBd, actualBd, remark);
+					return false;
+				}
+
+			} catch (Exception e) {
+				logger.error("处理告警/预警异常", e);
+				return false;
+			}
 		}
-	}
 
 	/**
 	 * 保存告警数据到 alarm_data 表
@@ -328,6 +366,28 @@ public class MessageHandler extends ChannelInboundHandlerAdapter {
 			logger.info("1级告警短信发送完成,成功{}条,失败{}条", successCount, phoneList.size() - successCount);
 		} catch (Exception e) {
 			logger.error("发送报警短信异常: {}", e.getMessage());
+			}
 		}
-	}
-}
+
+		/**
+		 * 更新设备报警状态
+		 * @param deviceCode 设备编码
+		 * @param alarmStatus 报警状态:0-正常,1-报警
+		 */
+		private void updateDeviceAlarmStatus(String deviceCode, int alarmStatus) {
+			try {
+				Map<String, Object> params = new HashMap<>();
+				params.put("deviceCode", deviceCode);
+				params.put("alarmStatus", alarmStatus);
+
+				HttpHeaders headers = new HttpHeaders();
+				headers.setContentType(MediaType.APPLICATION_JSON);
+				HttpEntity<Map<String, Object>> request = new HttpEntity<>(params, headers);
+
+				restTemplate.postForObject(deviceStatusApiUrl, request, Map.class);
+				logger.info("设备报警状态更新成功: deviceCode={}, alarmStatus={}", deviceCode, alarmStatus);
+			} catch (Exception e) {
+				logger.error("更新设备报警状态失败: deviceCode={}, alarmStatus={}", deviceCode, alarmStatus, e);
+			}
+		}
+	}

+ 132 - 73
water-level-service/src/main/java/com/zksy/water/utils/MessageHandler.java

@@ -3,6 +3,7 @@ package com.zksy.water.utils;
 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.SmsUtil;
@@ -20,10 +21,16 @@ import lombok.extern.slf4j.Slf4j;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
 import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
 
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -35,18 +42,27 @@ public class MessageHandler extends ChannelInboundHandlerAdapter {
 	private final WaterMonitorDataService service;
 	private final WarningThresholdService warningThresholdService;
 	private final AlarmDataService alarmDataService;
+	private final EarlyWarningAutoService earlyWarningAutoService;
 	private final SmsUtil smsUtil;
 	private final DevicePhoneFetchUtil devicePhoneFetchUtil;
+    private final RestTemplate restTemplate;
+
+    @Value("${device.status.api.url:http://zk-api-service/equipmentStatus/updateAlarmStatus}")
+    private String deviceStatusApiUrl;
 
 	@Autowired
-	public MessageHandler(WaterMonitorDataService waterMonitorDataService, WarningThresholdService warningThresholdService,
-	                       AlarmDataService alarmDataService, SmsUtil smsUtil, DevicePhoneFetchUtil devicePhoneFetchUtil) {
-		this.service = waterMonitorDataService;
-		this.warningThresholdService = warningThresholdService;
-		this.alarmDataService = alarmDataService;
-		this.smsUtil = smsUtil;
-		this.devicePhoneFetchUtil = devicePhoneFetchUtil;
-	}
+    public MessageHandler(WaterMonitorDataService waterMonitorDataService, WarningThresholdService warningThresholdService,
+                           AlarmDataService alarmDataService, EarlyWarningAutoService earlyWarningAutoService,
+                           SmsUtil smsUtil, DevicePhoneFetchUtil devicePhoneFetchUtil,
+                           RestTemplate restTemplate) {
+        this.service = waterMonitorDataService;
+        this.warningThresholdService = warningThresholdService;
+        this.alarmDataService = alarmDataService;
+        this.earlyWarningAutoService = earlyWarningAutoService;
+        this.smsUtil = smsUtil;
+        this.devicePhoneFetchUtil = devicePhoneFetchUtil;
+        this.restTemplate = restTemplate;
+    }
 
 	@Override
 	public void channelActive(ChannelHandlerContext ctx) throws Exception {
@@ -190,83 +206,104 @@ public class MessageHandler extends ChannelInboundHandlerAdapter {
 	}
 
 	/**
-	 * 处理水位告警
-	 */
-	private void handleWaterLevelAlarm(WaterMonitorData resultData) {
-		try {
-			// 设备编码从设备数据获取
-			String deviceCode = resultData.getDeviceCode();
-			if (deviceCode == null) {
-				deviceCode = resultData.getSystemIdentifier();
-			}
+		 * 处理水位告警
+		 */
+		private void handleWaterLevelAlarm(WaterMonitorData resultData) {
+			try {
+				// 设备编码从设备数据获取
+				String deviceCode = resultData.getDeviceCode();
+				if (deviceCode == null) {
+					deviceCode = resultData.getSystemIdentifier();
+				}
 
-			// 处理水位告警
-			if (resultData.getWaterLevel() != null) {
-				handleAlarm(deviceCode, "WARN_WATER_LEVEL", "水位", 
-					resultData.getWaterLevel());
-			}
+				boolean hasAlarm = false;
 
-		} catch (Exception e) {
-			logger.error("水位告警处理异常", e);
+				// 处理水位告警
+				if (resultData.getWaterLevel() != null) {
+					if (handleAlarm(deviceCode, "WARN_WATER_LEVEL", "水位", 
+						resultData.getWaterLevel())) {
+						hasAlarm = true;
+					}
+				}
+
+				// 同步设备报警状态到 equipment_status 表
+				updateDeviceAlarmStatus(deviceCode, hasAlarm ? 1 : 0);
+
+			} catch (Exception e) {
+				logger.error("水位告警处理异常", e);
+			}
 		}
-	}
 
 	/**
-	 * 处理单个告警
-	 */
-	private void handleAlarm(String deviceCode, String warningCode, String warningType, String valueStr) {
-		try {
-			// 解析实际值
-			Double actualValue = null;
+		 * 处理单个告警
+		 * @return 是否触发告警
+		 */
+		private boolean handleAlarm(String deviceCode, String warningCode, String warningType, String valueStr) {
 			try {
-				actualValue = Double.parseDouble(valueStr);
-			} catch (NumberFormatException e) {
-				logger.warn("无法解析告警值: {}", valueStr);
-				return;
-			}
+				// 解析实际值
+				Double actualValue = null;
+				try {
+					actualValue = Double.parseDouble(valueStr);
+				} catch (NumberFormatException e) {
+					logger.warn("无法解析告警值: {}", valueStr);
+					return false;
+				}
 
-			// 查询预警阈值表
-			WarningThreshold threshold = null;
-			try {
-				threshold = warningThresholdService.getWarningThresholdByDeviceAndCode(deviceCode, warningCode);
-			} catch (Exception e) {
-				logger.error("查询预警阈值失败: deviceCode={}, warningCode={}", deviceCode, warningCode, e);
-			}
+				// 查询预警阈值表
+				WarningThreshold threshold = null;
+				try {
+					threshold = warningThresholdService.getWarningThresholdByDeviceAndCode(deviceCode, warningCode);
+				} catch (Exception e) {
+					logger.error("查询预警阈值失败: deviceCode={}, warningCode={}", deviceCode, warningCode, e);
+				}
 
-			// 使用阈值表中的预警类型(如果有的话)
-			if (threshold != null && threshold.getWarningType() != null) {
-				warningType = threshold.getWarningType();
-			}
+				// 使用阈值表中的预警类型(如果有的话)
+				if (threshold != null && threshold.getWarningType() != null) {
+					warningType = threshold.getWarningType();
+				}
 
-			// 获取最小值和最大值
-			Double minValue = threshold != null ? threshold.getMinValue() : null;
-			Double maxValue = threshold != null ? threshold.getMaxValue() : null;
-			String remark = threshold != null ? threshold.getRemark() : null;
+				// 获取最小值和最大值
+				Double minValue = threshold != null ? threshold.getMinValue() : null;
+				Double maxValue = threshold != null ? threshold.getMaxValue() : null;
+				String remark = threshold != null ? threshold.getRemark() : null;
 
-			// 判断是否触发报警
-			boolean isOverThreshold = false;
-			if (minValue != null && actualValue <= minValue) {
-				isOverThreshold = true;
-			}
-			if (maxValue != null && actualValue >= maxValue) {
-				isOverThreshold = true;
-			}
+				// 未配置阈值则跳过
+				if (minValue == null && maxValue == null) {
+					return false;
+				}
 
-			if (isOverThreshold) {
-				logger.warn("设备{}触发{}告警(当前值:{},最小值:{},最大值:{})",
-					deviceCode, warningType, actualValue, minValue, maxValue);
+				BigDecimal minBd = minValue != null ? BigDecimal.valueOf(minValue) : null;
+				BigDecimal maxBd = maxValue != null ? BigDecimal.valueOf(maxValue) : null;
+				BigDecimal actualBd = BigDecimal.valueOf(actualValue);
 
-				// 保存到 alarm_data 表
-				saveAlarmData(deviceCode, warningType, warningCode,
-					minValue != null ? BigDecimal.valueOf(minValue) : null,
-					maxValue != null ? BigDecimal.valueOf(maxValue) : null,
-					BigDecimal.valueOf(actualValue), remark);
-			}
+				// 判断是否触发报警
+				boolean isOverThreshold = false;
+				if (minValue != null && actualValue <= minValue) {
+					isOverThreshold = true;
+				}
+				if (maxValue != null && actualValue >= maxValue) {
+					isOverThreshold = true;
+				}
 
-		} catch (Exception e) {
-			logger.error("处理告警异常", e);
+				if (isOverThreshold) {
+					logger.warn("设备{}触发{}告警(当前值:{},最小值:{},最大值:{})",
+						deviceCode, warningType, actualValue, minValue, maxValue);
+
+					saveAlarmData(deviceCode, warningType, warningCode, minBd, maxBd, actualBd, remark);
+					earlyWarningAutoService.closeAutoWarning(deviceCode, warningCode, "已达报警阈值,转报警处理");
+					return true;
+				} else {
+					// 接近阈值但未越限 → 自动生成预警
+					earlyWarningAutoService.checkAndGenerate(deviceCode, warningType, warningCode,
+							minBd, maxBd, actualBd, remark);
+					return false;
+				}
+
+			} catch (Exception e) {
+				logger.error("处理告警/预警异常", e);
+				return false;
+			}
 		}
-	}
 
 	/**
 	 * 保存告警数据到 alarm_data 表
@@ -322,6 +359,28 @@ public class MessageHandler extends ChannelInboundHandlerAdapter {
 			logger.info("1级告警短信发送完成,成功{}条,失败{}条", successCount, phoneList.size() - successCount);
 		} catch (Exception e) {
 			logger.error("发送报警短信异常: {}", e.getMessage());
+			}
 		}
-	}
-}
+
+		/**
+		 * 更新设备报警状态
+		 * @param deviceCode 设备编码
+		 * @param alarmStatus 报警状态:0-正常,1-报警
+		 */
+		private void updateDeviceAlarmStatus(String deviceCode, int alarmStatus) {
+			try {
+				Map<String, Object> params = new HashMap<>();
+				params.put("deviceCode", deviceCode);
+				params.put("alarmStatus", alarmStatus);
+
+				HttpHeaders headers = new HttpHeaders();
+				headers.setContentType(MediaType.APPLICATION_JSON);
+				HttpEntity<Map<String, Object>> request = new HttpEntity<>(params, headers);
+
+				restTemplate.postForObject(deviceStatusApiUrl, request, Map.class);
+				logger.info("设备报警状态更新成功: deviceCode={}, alarmStatus={}", deviceCode, alarmStatus);
+			} catch (Exception e) {
+				logger.error("更新设备报警状态失败: deviceCode={}, alarmStatus={}", deviceCode, alarmStatus, e);
+			}
+		}
+	}