|
|
@@ -0,0 +1,144 @@
|
|
|
+package com.zksy.api.utils;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 告警等级计算工具类
|
|
|
+ * 采用"偏离正常范围的偏差率"来定级
|
|
|
+ * 1级最高,4级最低
|
|
|
+ */
|
|
|
+public class AlarmLevelUtil {
|
|
|
+
|
|
|
+ private static final BigDecimal HUNDRED = new BigDecimal("100");
|
|
|
+ private static final BigDecimal TEN = new BigDecimal("10");
|
|
|
+ private static final BigDecimal THIRTY = new BigDecimal("30");
|
|
|
+ private static final BigDecimal SIXTY = new BigDecimal("60");
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算告警等级
|
|
|
+ *
|
|
|
+ * @param actual 实际值
|
|
|
+ * @param min 最小值
|
|
|
+ * @param max 最大值
|
|
|
+ * @return 告警等级 1-4,1级最高,4级最低;若参数无效返回4级
|
|
|
+ */
|
|
|
+ public static int calculateLevel(BigDecimal actual, BigDecimal min, BigDecimal max) {
|
|
|
+ BigDecimal deviationRatio = calculateDeviationRatio(actual, min, max);
|
|
|
+ return mapToLevel(deviationRatio);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算偏差率(百分比,范围0-100)
|
|
|
+ *
|
|
|
+ * @param actual 实际值
|
|
|
+ * @param min 最小值
|
|
|
+ * @param max 最大值
|
|
|
+ * @return 偏差率百分比,例如返回 25 表示 25%
|
|
|
+ */
|
|
|
+ public static BigDecimal calculateDeviationRatio(BigDecimal actual, BigDecimal min, BigDecimal max) {
|
|
|
+ // 参数校验
|
|
|
+ if (actual == null || min == null || max == null) {
|
|
|
+ return BigDecimal.ZERO;
|
|
|
+ }
|
|
|
+
|
|
|
+ BigDecimal deviation;
|
|
|
+ BigDecimal denominator;
|
|
|
+
|
|
|
+ // 计算偏差
|
|
|
+ if (actual.compareTo(min) < 0) {
|
|
|
+ // 低于下限:偏差 = min - actual
|
|
|
+ deviation = min.subtract(actual);
|
|
|
+ } else if (actual.compareTo(max) > 0) {
|
|
|
+ // 高于上限:偏差 = actual - max
|
|
|
+ deviation = actual.subtract(max);
|
|
|
+ } else {
|
|
|
+ // 在正常范围内,无偏差
|
|
|
+ return BigDecimal.ZERO;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算分母
|
|
|
+ BigDecimal range = max.subtract(min);
|
|
|
+ if (range.compareTo(BigDecimal.ZERO) != 0) {
|
|
|
+ denominator = range;
|
|
|
+ } else {
|
|
|
+ // 特殊兜底:max - min 为 0 或无效
|
|
|
+ BigDecimal maxAbs = max.abs();
|
|
|
+ BigDecimal minAbs = min.abs();
|
|
|
+ if (maxAbs.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ denominator = maxAbs;
|
|
|
+ } else if (minAbs.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ denominator = minAbs;
|
|
|
+ } else {
|
|
|
+ // 都为 0,偏差率视为 100%
|
|
|
+ return HUNDRED;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算偏差率 = (偏差 / 分母) * 100
|
|
|
+ if (denominator.compareTo(BigDecimal.ZERO) == 0) {
|
|
|
+ return HUNDRED;
|
|
|
+ }
|
|
|
+
|
|
|
+ BigDecimal ratio = deviation.divide(denominator, 4, RoundingMode.HALF_UP)
|
|
|
+ .multiply(HUNDRED);
|
|
|
+
|
|
|
+ // 限制在 0-100 范围内
|
|
|
+ if (ratio.compareTo(BigDecimal.ZERO) < 0) {
|
|
|
+ return BigDecimal.ZERO;
|
|
|
+ }
|
|
|
+ if (ratio.compareTo(HUNDRED) > 0) {
|
|
|
+ return HUNDRED;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ratio;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将偏差率映射到告警等级
|
|
|
+ *
|
|
|
+ * @param deviationRatio 偏差率(百分比)
|
|
|
+ * @return 告警等级 1-4
|
|
|
+ */
|
|
|
+ private static int mapToLevel(BigDecimal deviationRatio) {
|
|
|
+ if (deviationRatio == null) {
|
|
|
+ return 4;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 偏差率 < 10% → 4级
|
|
|
+ if (deviationRatio.compareTo(TEN) < 0) {
|
|
|
+ return 4;
|
|
|
+ }
|
|
|
+ // 偏差率 >= 10% 且 < 30% → 3级
|
|
|
+ if (deviationRatio.compareTo(THIRTY) < 0) {
|
|
|
+ return 3;
|
|
|
+ }
|
|
|
+ // 偏差率 >= 30% 且 < 60% → 2级
|
|
|
+ if (deviationRatio.compareTo(SIXTY) < 0) {
|
|
|
+ return 2;
|
|
|
+ }
|
|
|
+ // 偏差率 >= 60% → 1级
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取等级名称
|
|
|
+ *
|
|
|
+ * @param level 告警等级
|
|
|
+ * @return 等级名称
|
|
|
+ */
|
|
|
+ public static String getLevelName(int level) {
|
|
|
+ switch (level) {
|
|
|
+ case 1:
|
|
|
+ return "1级(紧急)";
|
|
|
+ case 2:
|
|
|
+ return "2级(高危)";
|
|
|
+ case 3:
|
|
|
+ return "3级(警告)";
|
|
|
+ case 4:
|
|
|
+ return "4级(提醒)";
|
|
|
+ default:
|
|
|
+ return "未知等级";
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|