|
|
@@ -0,0 +1,223 @@
|
|
|
+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<String> 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);
|
|
|
+ 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<EarlyWarning>()
|
|
|
+ .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 newLevel = String.valueOf(result.getLevel());
|
|
|
+ boolean levelChanged = !newLevel.equals(existing.getWarningLevel());
|
|
|
+ existing.setWarningLevel(newLevel);
|
|
|
+ existing.setWarningContent(content);
|
|
|
+ if (warningType != null && !warningType.isEmpty()) {
|
|
|
+ existing.setWarningType(warningType);
|
|
|
+ existing.setWarningName(buildWarningName(warningType, result.getLevel()));
|
|
|
+ }
|
|
|
+ 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.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.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<EquipmentBase>()
|
|
|
+ .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;
|
|
|
+ }
|
|
|
+}
|