EarlyWarningAutoServiceImpl.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. package com.zksy.api.service.impl;
  2. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  3. import com.zksy.api.domain.EarlyWarning;
  4. import com.zksy.api.domain.EquipmentBase;
  5. import com.zksy.api.mapper.EarlyWarningApiMapper;
  6. import com.zksy.api.mapper.EquipmentBaseApiMapper;
  7. import com.zksy.api.service.EarlyWarningAutoService;
  8. import com.zksy.api.utils.EarlyWarningLevelUtil;
  9. import com.zksy.api.utils.EarlyWarningLevelUtil.EarlyWarningLevelResult;
  10. import lombok.extern.slf4j.Slf4j;
  11. import org.springframework.beans.factory.annotation.Autowired;
  12. import org.springframework.stereotype.Service;
  13. import java.math.BigDecimal;
  14. import java.time.LocalDateTime;
  15. import java.time.format.DateTimeFormatter;
  16. import java.util.Arrays;
  17. import java.util.List;
  18. import java.util.Random;
  19. /**
  20. * 采集数据接近阈值时自动写入 early_warning
  21. */
  22. @Slf4j
  23. @Service
  24. public class EarlyWarningAutoServiceImpl implements EarlyWarningAutoService {
  25. private static final String AUTO_PREFIX = "AUTO|";
  26. private static final String SYSTEM_USER = "系统自动";
  27. private static final List<String> OPEN_STATUS = Arrays.asList(
  28. "DRAFT", "PENDING", "PROCESSING", "RELEASED"
  29. );
  30. @Autowired
  31. private EarlyWarningApiMapper earlyWarningApiMapper;
  32. @Autowired
  33. private EquipmentBaseApiMapper equipmentBaseApiMapper;
  34. @Override
  35. public Integer checkAndGenerate(String deviceCode, String warningType, String warningCode,
  36. BigDecimal minValue, BigDecimal maxValue, BigDecimal actualValue,
  37. String extraRemark) {
  38. if (deviceCode == null || deviceCode.isEmpty() || warningCode == null || warningCode.isEmpty()) {
  39. return null;
  40. }
  41. if (actualValue == null || (minValue == null && maxValue == null)) {
  42. return null;
  43. }
  44. try {
  45. // 已越限或回到安全区:关闭自动预警
  46. if (EarlyWarningLevelUtil.isOverThreshold(actualValue, minValue, maxValue)) {
  47. closeAutoWarning(deviceCode, warningCode, "已达报警阈值,转报警处理");
  48. return null;
  49. }
  50. EarlyWarningLevelResult result = EarlyWarningLevelUtil.calculate(actualValue, minValue, maxValue);
  51. if (result == null) {
  52. closeAutoWarning(deviceCode, warningCode, "监测值已回落至安全区间");
  53. return null;
  54. }
  55. EarlyWarning existing = findOpenAutoWarning(deviceCode, warningCode);
  56. String content = buildContent(deviceCode, warningType, warningCode,
  57. minValue, maxValue, actualValue, result, extraRemark);
  58. if (existing != null) {
  59. updateExisting(existing, result, content, warningType, deviceCode, actualValue, minValue, maxValue);
  60. return result.getLevel();
  61. }
  62. createNew(deviceCode, warningType, warningCode, result, content, minValue, maxValue, actualValue);
  63. return result.getLevel();
  64. } catch (Exception e) {
  65. log.error("自动生成预警失败: deviceCode={}, warningCode={}", deviceCode, warningCode, e);
  66. return null;
  67. }
  68. }
  69. @Override
  70. public void closeAutoWarning(String deviceCode, String warningCode, String reason) {
  71. try {
  72. EarlyWarning existing = findOpenAutoWarning(deviceCode, warningCode);
  73. if (existing == null) {
  74. return;
  75. }
  76. existing.setStatus("CLOSED");
  77. existing.setUpdateBy(SYSTEM_USER);
  78. existing.setUpdateTime(LocalDateTime.now());
  79. if (reason != null && !reason.isEmpty()) {
  80. String content = existing.getWarningContent() == null ? "" : existing.getWarningContent();
  81. existing.setWarningContent(content + "【系统自动解除】" + reason);
  82. }
  83. earlyWarningApiMapper.updateById(existing);
  84. log.info("自动关闭预警: warningNo={}, deviceCode={}, warningCode={}, reason={}",
  85. existing.getWarningNo(), deviceCode, warningCode, reason);
  86. } catch (Exception e) {
  87. log.error("关闭自动预警失败: deviceCode={}, warningCode={}", deviceCode, warningCode, e);
  88. }
  89. }
  90. private EarlyWarning findOpenAutoWarning(String deviceCode, String warningCode) {
  91. String marker = buildRemarkMarker(deviceCode, warningCode);
  92. return earlyWarningApiMapper.selectOne(new LambdaQueryWrapper<EarlyWarning>()
  93. .eq(EarlyWarning::getRemark, marker)
  94. .in(EarlyWarning::getStatus, OPEN_STATUS)
  95. .orderByDesc(EarlyWarning::getCreateTime)
  96. .last("LIMIT 1"));
  97. }
  98. private void updateExisting(EarlyWarning existing, EarlyWarningLevelResult result,
  99. String content, String warningType, String deviceCode,
  100. BigDecimal actualValue, BigDecimal minValue, BigDecimal maxValue) {
  101. String newLevel = String.valueOf(result.getLevel());
  102. boolean levelChanged = !newLevel.equals(existing.getWarningLevel());
  103. existing.setWarningLevel(newLevel);
  104. existing.setWarningContent(content);
  105. existing.setDeviceCode(deviceCode);
  106. if (warningType != null && !warningType.isEmpty()) {
  107. existing.setWarningType(warningType);
  108. existing.setWarningName(buildWarningName(warningType, result.getLevel()));
  109. }
  110. EquipmentBase equipment = findEquipment(deviceCode);
  111. if (equipment != null && equipment.getEquipmentName() != null) {
  112. existing.setDeviceName(equipment.getEquipmentName());
  113. }
  114. existing.setUpdateBy(SYSTEM_USER);
  115. existing.setUpdateTime(LocalDateTime.now());
  116. earlyWarningApiMapper.updateById(existing);
  117. if (levelChanged) {
  118. log.info("自动更新预警级别: warningNo={}, level={}级, approachRatio={}%",
  119. existing.getWarningNo(), result.getLevel(), result.getApproachRatio());
  120. }
  121. }
  122. private void createNew(String deviceCode, String warningType, String warningCode,
  123. EarlyWarningLevelResult result, String content,
  124. BigDecimal minValue, BigDecimal maxValue, BigDecimal actualValue) {
  125. EquipmentBase equipment = findEquipment(deviceCode);
  126. LocalDateTime now = LocalDateTime.now();
  127. EarlyWarning warning = new EarlyWarning();
  128. warning.setWarningNo(generateWarningNo());
  129. warning.setWarningName(buildWarningName(
  130. warningType != null ? warningType : warningCode, result.getLevel()));
  131. warning.setWarningType(warningType != null && !warningType.isEmpty() ? warningType : warningCode);
  132. warning.setWarningLevel(String.valueOf(result.getLevel()));
  133. warning.setWarningSpecial(warningCode);
  134. warning.setDeviceCode(deviceCode);
  135. warning.setStatus("RELEASED");
  136. warning.setPublisher(SYSTEM_USER);
  137. warning.setPublishTime(now);
  138. warning.setCreateBy(SYSTEM_USER);
  139. warning.setCreateTime(now);
  140. warning.setUpdateTime(now);
  141. warning.setWarningContent(content);
  142. warning.setRemark(buildRemarkMarker(deviceCode, warningCode));
  143. if (equipment != null) {
  144. warning.setDeviceName(equipment.getEquipmentName());
  145. warning.setLocation(equipment.getEquipmentLocation());
  146. warning.setLongitude(equipment.getLongitude());
  147. warning.setLatitude(equipment.getLatitude());
  148. warning.setOwnershipUnit(equipment.getOwnershipUnit());
  149. warning.setHandler(equipment.getMaintainer());
  150. if (equipment.getEquipmentName() != null) {
  151. warning.setWarningName(equipment.getEquipmentName() + "-"
  152. + buildWarningName(warningType != null ? warningType : warningCode, result.getLevel()));
  153. }
  154. } else {
  155. warning.setLocation("设备编码:" + deviceCode);
  156. }
  157. earlyWarningApiMapper.insert(warning);
  158. log.info("自动生成预警成功: warningNo={}, deviceCode={}, warningCode={}, level={}级, actual={}, min={}, max={}",
  159. warning.getWarningNo(), deviceCode, warningCode, result.getLevel(),
  160. actualValue, minValue, maxValue);
  161. }
  162. private EquipmentBase findEquipment(String deviceCode) {
  163. try {
  164. return equipmentBaseApiMapper.selectOne(new LambdaQueryWrapper<EquipmentBase>()
  165. .eq(EquipmentBase::getEquipmentCode, deviceCode)
  166. .last("LIMIT 1"));
  167. } catch (Exception e) {
  168. log.warn("查询设备信息失败: deviceCode={}", deviceCode);
  169. return null;
  170. }
  171. }
  172. private static String buildRemarkMarker(String deviceCode, String warningCode) {
  173. return AUTO_PREFIX + deviceCode + "|" + warningCode;
  174. }
  175. private static String buildWarningName(String warningType, int level) {
  176. return warningType + "-接近阈值预警(" + EarlyWarningLevelUtil.getLevelName(level) + ")";
  177. }
  178. private static String buildContent(String deviceCode, String warningType, String warningCode,
  179. BigDecimal minValue, BigDecimal maxValue, BigDecimal actualValue,
  180. EarlyWarningLevelResult result, String extraRemark) {
  181. StringBuilder sb = new StringBuilder();
  182. sb.append("【系统自动预警】设备[").append(deviceCode).append("]");
  183. if (warningType != null) {
  184. sb.append(" ").append(warningType);
  185. }
  186. sb.append("(").append(warningCode).append(")");
  187. sb.append(" 当前值=").append(actualValue);
  188. sb.append(",阈值范围=[")
  189. .append(minValue != null ? minValue : "-")
  190. .append(", ")
  191. .append(maxValue != null ? maxValue : "-")
  192. .append("]");
  193. sb.append(",逼近侧=").append("UPPER".equals(result.getSide()) ? "上限" : "下限");
  194. sb.append(",逼近率=").append(result.getApproachRatio()).append("%");
  195. sb.append(",级别=").append(EarlyWarningLevelUtil.getLevelName(result.getLevel()));
  196. sb.append("。数据已接近阈值但尚未越限,请关注。");
  197. if (extraRemark != null && !extraRemark.isEmpty()) {
  198. sb.append(" 备注:").append(extraRemark);
  199. }
  200. return sb.toString();
  201. }
  202. private static String generateWarningNo() {
  203. String ts = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
  204. String random = String.format("%04d", new Random().nextInt(10000));
  205. return "YJ" + ts + random;
  206. }
  207. }