瀏覽代碼

首页预警天数调整

xy 5 天之前
父節點
當前提交
0945b95a8c

+ 139 - 32
tz-module-pressure2/tz-module-pressure2-biz/src/main/java/cn/start/tz/module/pressure2/service/riskalert/RiskAlertServiceImpl.java

@@ -2,18 +2,21 @@ package cn.start.tz.module.pressure2.service.riskalert;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.start.tz.framework.common.pojo.CommonResult;
 import cn.start.tz.module.pressure2.controller.admin.riskalert.vo.*;
 import cn.start.tz.module.pressure2.dal.dataobject.useralertconfig.UserAlertConfigDO;
 import cn.start.tz.module.pressure2.dal.mysql.riskalert.RiskAlertMapper;
 import cn.start.tz.module.pressure2.dal.mysql.useralertconfig.UserAlertConfigMapper;
+import cn.start.tz.module.system.api.calendar.CalendarApi;
 import cn.start.tz.module.system.api.dept.DeptApi;
 import cn.start.tz.module.system.api.dept.dto.DeptRespDTO;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import jakarta.annotation.Resource;
+import lombok.AllArgsConstructor;
+import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
-import java.time.DayOfWeek;
 import java.time.LocalDate;
 import java.util.*;
 import java.util.stream.Collectors;
@@ -30,7 +33,7 @@ public class RiskAlertServiceImpl implements RiskAlertService {
     private static final Map<Integer, String> BOILER_CHECK_TYPE_MAP = Map.of(
             100, "内部检验", 200, "外部检验", 300, "耐压检验"
     );
-    // 管道检验性质:100定检验 200年度检查
+    // 管道检验性质:100定检验 200年度检查
     private static final Map<Integer, String> PIPE_CHECK_TYPE_MAP = Map.of(
             100, "定期检验", 200, "年度检查"
     );
@@ -44,6 +47,9 @@ public class RiskAlertServiceImpl implements RiskAlertService {
     @Resource
     private DeptApi deptApi;
 
+    @Resource
+    private CalendarApi calendarApi;
+
     // ============ 锅炉预警 ============
 
     @Override
@@ -132,25 +138,29 @@ public class RiskAlertServiceImpl implements RiskAlertService {
 
     /**
      * 按检验性质分组统计,只保留剩余工作日 <= alertDays 的记录
+     * <p>
+     * 计算逻辑:约检日期(checkDate) + N个工作日 = 应完成日期,再计算剩余工作日
+     * 定期检验(100/300) = 30个工作日,管道年检(200)=30个工作日,锅炉外检(200)=10个工作日
      */
-    private List<TaskOrderReportAlertCountRespVO> aggregateByCheckType(List<Map<String, Object>> rows, int alertDays, String equipType) {
+    private List<TaskOrderReportAlertCountRespVO> aggregateByCheckType(
+            List<Map<String, Object>> rows, int alertDays, String equipType) {
         Map<Integer, String> checkTypeNameMap = "boiler".equals(equipType) ? BOILER_CHECK_TYPE_MAP : PIPE_CHECK_TYPE_MAP;
-        // 收集唯一 checkDate → 批量计算剩余工作日
+
+        // 1. 收集唯一的 checkDate,批量计算应完成日期
         Set<LocalDate> dateSet = new HashSet<>();
         for (Map<String, Object> row : rows) {
             Object checkDateObj = row.get("check_date");
-            if (checkDateObj instanceof java.sql.Date) {
-                dateSet.add(((java.sql.Date) checkDateObj).toLocalDate());
-            } else if (checkDateObj instanceof LocalDate) {
-                dateSet.add((LocalDate) checkDateObj);
+            if (checkDateObj != null) {
+                dateSet.add(toLocalDate(checkDateObj));
             }
         }
-        Map<LocalDate, Integer> remainingMap = new HashMap<>();
-        for (LocalDate date : dateSet) {
-            remainingMap.put(date, calcRemainingWorkDays(date));
-        }
+        dateSet.remove(null);
+
+        // 2. 批量计算:checkDate + N工作日 → 应完成日期,再计算剩余工作日
+        // Map<checkDate, Map<checkType, remainingDays>>
+        Map<LocalDate, Map<Integer, Integer>> remainingMap = calculateRemainingDaysBatch(dateSet, equipType);
 
-        // 分类统计
+        // 3. 分类统计
         Map<Integer, Set<String>> checkTypeMap = new LinkedHashMap<>();
         for (Map<String, Object> row : rows) {
             Integer checkType = toInt(row.get("check_type"));
@@ -161,7 +171,10 @@ public class RiskAlertServiceImpl implements RiskAlertService {
             LocalDate checkDate = toLocalDate(checkDateObj);
             if (checkDate == null) continue;
 
-            Integer remain = remainingMap.get(checkDate);
+            Map<Integer, Integer> typeMap = remainingMap.get(checkDate);
+            if (typeMap == null) continue;
+
+            Integer remain = typeMap.get(checkType);
             if (remain != null && remain <= alertDays) {
                 checkTypeMap.computeIfAbsent(checkType, k -> new LinkedHashSet<>()).add(equipCode);
             }
@@ -180,6 +193,110 @@ public class RiskAlertServiceImpl implements RiskAlertService {
         return result;
     }
 
+    /**
+     * 批量计算剩余工作日(含节假日,按检验性质区分工作日天数)
+     * <p>
+     * 计算逻辑:
+     * 1. 约检日期(checkDate) + N个工作日 = 应完成日期(dueDate)
+     *    定期检验(100/300): 30个工作日
+     *    管道年检(200)=30个工作日,锅炉外检(200)=10个工作日
+     * 2. 剩余工作日 = 从今天到应完成日期之间的工作日数(可为负表示超期)
+     *
+     * @param checkDateSet 约检日期集合
+     * @return Map<checkDate, Map<checkType, remainingDays>>
+     */
+    private Map<LocalDate, Map<Integer, Integer>> calculateRemainingDaysBatch(Set<LocalDate> checkDateSet, String equipType) {
+        Map<LocalDate, Map<Integer, Integer>> resultMap = new HashMap<>();
+        if (CollUtil.isEmpty(checkDateSet)) return resultMap;
+
+        LocalDate today = LocalDate.now();
+        List<LocalDate> dateList = new ArrayList<>(checkDateSet);
+        boolean isBoiler = "boiler".equals(equipType);
+
+        // 缓存:key = "checkDate_workDays"
+        Map<String, LocalDate> dueDateCache = new HashMap<>();
+
+        // 先批量计算所有应完成日期(去重,减少API调用)
+        for (LocalDate checkDate : dateList) {
+            // 30个工作日:100/300(全部),管道200(年检)
+            String key30 = checkDate + "_30";
+            if (!dueDateCache.containsKey(key30)) {
+                try {
+                    CommonResult<LocalDate> result = calendarApi.getCalendarDateByParam(
+                            checkDate.plusDays(1), 30);
+                    if (result.isSuccess() && result.getData() != null) {
+                        dueDateCache.put(key30, result.getData());
+                    }
+                } catch (Exception e) {
+                    log.error("[calculateRemainingDaysBatch] 计算30天应完成日期失败, checkDate={}", checkDate, e);
+                }
+            }
+
+            // 10个工作日:仅锅炉外检(200)
+            if (isBoiler) {
+                String key10 = checkDate + "_10";
+                if (!dueDateCache.containsKey(key10)) {
+                    try {
+                        CommonResult<LocalDate> result = calendarApi.getCalendarDateByParam(
+                                checkDate.plusDays(1), 10);
+                        if (result.isSuccess() && result.getData() != null) {
+                            dueDateCache.put(key10, result.getData());
+                        }
+                    } catch (Exception e) {
+                        log.error("[calculateRemainingDaysBatch] 计算10天应完成日期失败, checkDate={}", checkDate, e);
+                    }
+                }
+            }
+        }
+
+        // 根据应完成日期计算剩余工作日
+        for (LocalDate checkDate : dateList) {
+            Map<Integer, Integer> typeRemaining = new HashMap<>();
+
+            // 30天类型:100、300、管道200
+            String key30 = checkDate + "_30";
+            LocalDate due30 = dueDateCache.get(key30);
+            if (due30 != null) {
+                int remaining = calcRemaining(today, due30, 30);
+                typeRemaining.put(100, remaining);
+                typeRemaining.put(300, remaining);
+                if (!isBoiler) {
+                    // 管道年检(200)也是30天
+                    typeRemaining.put(200, remaining);
+                }
+            }
+
+            // 10天类型:仅锅炉外检(200)
+            if (isBoiler) {
+                String key10 = checkDate + "_10";
+                LocalDate due10 = dueDateCache.get(key10);
+                if (due10 != null) {
+                    typeRemaining.put(200, calcRemaining(today, due10, 10));
+                }
+            }
+
+            resultMap.put(checkDate, typeRemaining);
+        }
+
+        return resultMap;
+    }
+
+    /**
+     * 计算从 today 到 dueDate 之间的剩余工作日
+     */
+    private int calcRemaining(LocalDate today, LocalDate dueDate, int fallbackDays) {
+        if (today.isEqual(dueDate)) return 0;
+        try {
+            CommonResult<Integer> result = calendarApi.calculateWorkdayInfo(dueDate, today.plusDays(1));
+            if (result.isSuccess() && result.getData() != null) {
+                return result.getData();
+            }
+        } catch (Exception e) {
+            log.error("[calcRemaining] 计算剩余工作日失败, dueDate={}", dueDate, e);
+        }
+        return fallbackDays;
+    }
+
     private int getUserAlertDays(String userId) {
         UserAlertConfigDO config = userAlertConfigMapper.selectOne(
                 Wrappers.<UserAlertConfigDO>lambdaQuery().eq(UserAlertConfigDO::getUserId, userId));
@@ -197,23 +314,6 @@ public class RiskAlertServiceImpl implements RiskAlertService {
         }
     }
 
-    /**
-     * 计算剩余工作日(不含周末)
-     */
-    private static int calcRemainingWorkDays(LocalDate checkDate) {
-        LocalDate today = LocalDate.now();
-        if (!checkDate.isAfter(today)) return 0;
-        int workDays = 0;
-        LocalDate d = today;
-        while (d.isBefore(checkDate)) {
-            d = d.plusDays(1);
-            if (d.getDayOfWeek() != DayOfWeek.SATURDAY && d.getDayOfWeek() != DayOfWeek.SUNDAY) {
-                workDays++;
-            }
-        }
-        return workDays;
-    }
-
     private static Integer toInt(Object obj) {
         if (obj == null) return null;
         if (obj instanceof Number) return ((Number) obj).intValue();
@@ -227,4 +327,11 @@ public class RiskAlertServiceImpl implements RiskAlertService {
         return null;
     }
 
-}
+    @Data
+    @AllArgsConstructor
+    private static class CalculateCacheKey {
+        private LocalDate checkDate;
+        private int workDaysToAdd;
+    }
+
+}