|
|
@@ -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;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|