package com.zksy.api.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.zksy.api.domain.EarlyWarning; import com.zksy.api.domain.EquipmentBase; import com.zksy.api.mapper.EarlyWarningApiMapper; import com.zksy.api.mapper.EquipmentBaseApiMapper; import com.zksy.api.service.EarlyWarningAutoService; import com.zksy.api.utils.EarlyWarningLevelUtil; import com.zksy.api.utils.EarlyWarningLevelUtil.EarlyWarningLevelResult; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.List; import java.util.Random; /** * 采集数据接近阈值时自动写入 early_warning */ @Slf4j @Service public class EarlyWarningAutoServiceImpl implements EarlyWarningAutoService { private static final String AUTO_PREFIX = "AUTO|"; private static final String SYSTEM_USER = "系统自动"; private static final List OPEN_STATUS = Arrays.asList( "DRAFT", "PENDING", "PROCESSING", "RELEASED" ); @Autowired private EarlyWarningApiMapper earlyWarningApiMapper; @Autowired private EquipmentBaseApiMapper equipmentBaseApiMapper; @Override public Integer checkAndGenerate(String deviceCode, String warningType, String warningCode, BigDecimal minValue, BigDecimal maxValue, BigDecimal actualValue, String extraRemark) { if (deviceCode == null || deviceCode.isEmpty() || warningCode == null || warningCode.isEmpty()) { return null; } if (actualValue == null || (minValue == null && maxValue == null)) { return null; } try { // 已越限或回到安全区:关闭自动预警 if (EarlyWarningLevelUtil.isOverThreshold(actualValue, minValue, maxValue)) { closeAutoWarning(deviceCode, warningCode, "已达报警阈值,转报警处理"); return null; } EarlyWarningLevelResult result = EarlyWarningLevelUtil.calculate(actualValue, minValue, maxValue); if (result == null) { closeAutoWarning(deviceCode, warningCode, "监测值已回落至安全区间"); return null; } EarlyWarning existing = findOpenAutoWarning(deviceCode, warningCode); String content = buildContent(deviceCode, warningType, warningCode, minValue, maxValue, actualValue, result, extraRemark); if (existing != null) { updateExisting(existing, result, content, warningType, deviceCode, actualValue, minValue, maxValue); return result.getLevel(); } createNew(deviceCode, warningType, warningCode, result, content, minValue, maxValue, actualValue); return result.getLevel(); } catch (Exception e) { log.error("自动生成预警失败: deviceCode={}, warningCode={}", deviceCode, warningCode, e); return null; } } @Override public void closeAutoWarning(String deviceCode, String warningCode, String reason) { try { EarlyWarning existing = findOpenAutoWarning(deviceCode, warningCode); if (existing == null) { return; } existing.setStatus("CLOSED"); existing.setUpdateBy(SYSTEM_USER); existing.setUpdateTime(LocalDateTime.now()); if (reason != null && !reason.isEmpty()) { String content = existing.getWarningContent() == null ? "" : existing.getWarningContent(); existing.setWarningContent(content + "【系统自动解除】" + reason); } earlyWarningApiMapper.updateById(existing); log.info("自动关闭预警: warningNo={}, deviceCode={}, warningCode={}, reason={}", existing.getWarningNo(), deviceCode, warningCode, reason); } catch (Exception e) { log.error("关闭自动预警失败: deviceCode={}, warningCode={}", deviceCode, warningCode, e); } } private EarlyWarning findOpenAutoWarning(String deviceCode, String warningCode) { String marker = buildRemarkMarker(deviceCode, warningCode); return earlyWarningApiMapper.selectOne(new LambdaQueryWrapper() .eq(EarlyWarning::getRemark, marker) .in(EarlyWarning::getStatus, OPEN_STATUS) .orderByDesc(EarlyWarning::getCreateTime) .last("LIMIT 1")); } private void updateExisting(EarlyWarning existing, EarlyWarningLevelResult result, String content, String warningType, String deviceCode, BigDecimal actualValue, BigDecimal minValue, BigDecimal maxValue) { String newLevel = String.valueOf(result.getLevel()); boolean levelChanged = !newLevel.equals(existing.getWarningLevel()); existing.setWarningLevel(newLevel); existing.setWarningContent(content); existing.setDeviceCode(deviceCode); if (warningType != null && !warningType.isEmpty()) { existing.setWarningType(warningType); existing.setWarningName(buildWarningName(warningType, result.getLevel())); } EquipmentBase equipment = findEquipment(deviceCode); if (equipment != null && equipment.getEquipmentName() != null) { existing.setDeviceName(equipment.getEquipmentName()); } existing.setUpdateBy(SYSTEM_USER); existing.setUpdateTime(LocalDateTime.now()); earlyWarningApiMapper.updateById(existing); if (levelChanged) { log.info("自动更新预警级别: warningNo={}, level={}级, approachRatio={}%", existing.getWarningNo(), result.getLevel(), result.getApproachRatio()); } } private void createNew(String deviceCode, String warningType, String warningCode, EarlyWarningLevelResult result, String content, BigDecimal minValue, BigDecimal maxValue, BigDecimal actualValue) { EquipmentBase equipment = findEquipment(deviceCode); LocalDateTime now = LocalDateTime.now(); EarlyWarning warning = new EarlyWarning(); warning.setWarningNo(generateWarningNo()); warning.setWarningName(buildWarningName( warningType != null ? warningType : warningCode, result.getLevel())); warning.setWarningType(warningType != null && !warningType.isEmpty() ? warningType : warningCode); warning.setWarningLevel(String.valueOf(result.getLevel())); warning.setWarningSpecial(warningCode); warning.setDeviceCode(deviceCode); warning.setStatus("RELEASED"); warning.setPublisher(SYSTEM_USER); warning.setPublishTime(now); warning.setCreateBy(SYSTEM_USER); warning.setCreateTime(now); warning.setUpdateTime(now); warning.setWarningContent(content); warning.setRemark(buildRemarkMarker(deviceCode, warningCode)); if (equipment != null) { warning.setDeviceName(equipment.getEquipmentName()); warning.setLocation(equipment.getEquipmentLocation()); warning.setLongitude(equipment.getLongitude()); warning.setLatitude(equipment.getLatitude()); warning.setOwnershipUnit(equipment.getOwnershipUnit()); warning.setHandler(equipment.getMaintainer()); if (equipment.getEquipmentName() != null) { warning.setWarningName(equipment.getEquipmentName() + "-" + buildWarningName(warningType != null ? warningType : warningCode, result.getLevel())); } } else { warning.setLocation("设备编码:" + deviceCode); } earlyWarningApiMapper.insert(warning); log.info("自动生成预警成功: warningNo={}, deviceCode={}, warningCode={}, level={}级, actual={}, min={}, max={}", warning.getWarningNo(), deviceCode, warningCode, result.getLevel(), actualValue, minValue, maxValue); } private EquipmentBase findEquipment(String deviceCode) { try { return equipmentBaseApiMapper.selectOne(new LambdaQueryWrapper() .eq(EquipmentBase::getEquipmentCode, deviceCode) .last("LIMIT 1")); } catch (Exception e) { log.warn("查询设备信息失败: deviceCode={}", deviceCode); return null; } } private static String buildRemarkMarker(String deviceCode, String warningCode) { return AUTO_PREFIX + deviceCode + "|" + warningCode; } private static String buildWarningName(String warningType, int level) { return warningType + "-接近阈值预警(" + EarlyWarningLevelUtil.getLevelName(level) + ")"; } private static String buildContent(String deviceCode, String warningType, String warningCode, BigDecimal minValue, BigDecimal maxValue, BigDecimal actualValue, EarlyWarningLevelResult result, String extraRemark) { StringBuilder sb = new StringBuilder(); sb.append("【系统自动预警】设备[").append(deviceCode).append("]"); if (warningType != null) { sb.append(" ").append(warningType); } sb.append("(").append(warningCode).append(")"); sb.append(" 当前值=").append(actualValue); sb.append(",阈值范围=[") .append(minValue != null ? minValue : "-") .append(", ") .append(maxValue != null ? maxValue : "-") .append("]"); sb.append(",逼近侧=").append("UPPER".equals(result.getSide()) ? "上限" : "下限"); sb.append(",逼近率=").append(result.getApproachRatio()).append("%"); sb.append(",级别=").append(EarlyWarningLevelUtil.getLevelName(result.getLevel())); sb.append("。数据已接近阈值但尚未越限,请关注。"); if (extraRemark != null && !extraRemark.isEmpty()) { sb.append(" 备注:").append(extraRemark); } return sb.toString(); } private static String generateWarningNo() { String ts = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); String random = String.format("%04d", new Random().nextInt(10000)); return "YJ" + ts + random; } }