From e92968f85531df814268b6afbe62f6e062f5a07f Mon Sep 17 00:00:00 2001
From: xyc <jc_xiong@hotmail.com>
Date: 星期二, 06 十月 2026 02:02:48 +0800
Subject: [PATCH] feat(holiday): 新增往年国省道调整并按前一日环比基期重算汇总

---
 traffic-audit-server/src/main/java/com/trafficaudit/holiday/service/HolidayStatService.java |  156 ++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 110 insertions(+), 46 deletions(-)

diff --git a/traffic-audit-server/src/main/java/com/trafficaudit/holiday/service/HolidayStatService.java b/traffic-audit-server/src/main/java/com/trafficaudit/holiday/service/HolidayStatService.java
index 3015c71..2309466 100644
--- a/traffic-audit-server/src/main/java/com/trafficaudit/holiday/service/HolidayStatService.java
+++ b/traffic-audit-server/src/main/java/com/trafficaudit/holiday/service/HolidayStatService.java
@@ -8,7 +8,9 @@
 import com.trafficaudit.holiday.entity.HolidayCalendar;
 import com.trafficaudit.holiday.entity.HolidayPassengerFlow;
 import com.trafficaudit.holiday.entity.HolidayVehicleFlow;
+import com.trafficaudit.holiday.entity.HolidayVehicleAdjustment;
 import com.trafficaudit.holiday.mapper.HolidayPassengerFlowMapper;
+import com.trafficaudit.holiday.mapper.HolidayVehicleAdjustmentMapper;
 import com.trafficaudit.holiday.mapper.HolidayVehicleFlowMapper;
 import lombok.Data;
 import org.springframework.stereotype.Service;
@@ -36,6 +38,8 @@
     private HolidayPassengerFlowMapper passengerFlowMapper;
     @Resource
     private HolidayVehicleFlowMapper vehicleFlowMapper;
+    @Resource
+    private HolidayVehicleAdjustmentMapper vehicleAdjustmentMapper;
     @Resource
     private ImportBatchMapper importBatchMapper;
 
@@ -93,37 +97,33 @@
         Map<LocalDate, Map<String, BigDecimal>> vehicleByDate = loadVehicleByDate(year);
         Map<LocalDate, BigDecimal> comparisonBaseByDate = loadComparisonBaseByDate(year);
         BigDecimal coefficient = configService.coefficientOf(year, HolidayConstants.CATEGORY_HOLIDAY);
-        List<Map<String, Object>> rows = new ArrayList<>();
-        BigDecimal previousNationalProvincial = null;
+        Map<Integer, HolidayCalendar> calendarByDay = new LinkedHashMap<>();
         for (HolidayCalendar day : calendar) {
-            Map<String, BigDecimal> passenger = passengerByDate.getOrDefault(day.getHolidayDate(), Collections.emptyMap());
-            Map<String, BigDecimal> vehicle = vehicleByDate.getOrDefault(day.getHolidayDate(), Collections.emptyMap());
-            BigDecimal expressway = vehicle.get(HolidayConstants.ROAD_EXPRESSWAY);
-            BigDecimal nationalProvincial = vehicle.get(HolidayConstants.ROAD_NATIONAL_PROVINCIAL);
-            BigDecimal comparisonBase = comparisonBaseByDate.get(day.getHolidayDate());
-            BigDecimal nationalProvincialRingRatio = nationalProvincialRingRatio(
-                    year, nationalProvincial, previousNationalProvincial, comparisonBase);
-            BigDecimal nonBusinessPersonFlow = null;
-            if (coefficient != null && (expressway != null || nationalProvincial != null)) {
-                nonBusinessPersonFlow = HolidayNumberUtils.multiply(
-                        HolidayNumberUtils.sumNullable(expressway, nationalProvincial), coefficient);
-            }
+            if (day.getDayIndex() != null) calendarByDay.put(day.getDayIndex(), day);
+        }
+        List<Map<String, Object>> rows = new ArrayList<>();
+        for (HolidayCalendar day : calendar) {
+            DailyMetrics current = buildDailyMetrics(year, holidayType, day.getDayIndex(), day.getHolidayDate(),
+                    passengerByDate, vehicleByDate, comparisonBaseByDate, coefficient);
+            DailyMetrics ringRatioBase = ringRatioBaseFromMaps(year, holidayType, day.getDayIndex(), calendarByDay,
+                    passengerByDate, vehicleByDate, comparisonBaseByDate, coefficient);
+            BigDecimal nationalProvincialRingRatio = ratio(current.getNationalProvincial(),
+                    ringRatioBase == null ? null : ringRatioBase.getNationalProvincial());
             Map<String, Object> row = new LinkedHashMap<>();
             row.put("dayIndex", day.getDayIndex());
             row.put("date", day.getHolidayDate());
-            row.put("rail", passenger.get(HolidayConstants.MODE_RAIL));
-            row.put("civilAviation", passenger.get(HolidayConstants.MODE_CIVIL_AVIATION));
-            row.put("road", passenger.get(HolidayConstants.MODE_ROAD));
-            row.put("water", passenger.get(HolidayConstants.MODE_WATER));
-            row.put("expressway", expressway);
-            row.put("nationalProvincial", nationalProvincial);
-            row.put("comparisonBase", comparisonBase);
+            row.put("rail", current.getRail());
+            row.put("civilAviation", current.getCivilAviation());
+            row.put("road", current.getRoad());
+            row.put("water", current.getWater());
+            row.put("expressway", current.getExpressway());
+            row.put("nationalProvincial", current.getNationalProvincial());
+            row.put("comparisonBase", current.getComparisonBase());
             row.put("nationalProvincialRingRatio", nationalProvincialRingRatio);
-            row.put("coefficient", coefficient);
-            row.put("nonBusinessPersonFlow", nonBusinessPersonFlow);
-            row.put("totalPersonFlow", totalPersonFlow(passenger, nonBusinessPersonFlow));
+            row.put("coefficient", current.getCoefficient());
+            row.put("nonBusinessPersonFlow", current.getNonBusinessPersonFlow());
+            row.put("totalPersonFlow", current.getTotalPersonFlow());
             rows.add(row);
-            previousNationalProvincial = nationalProvincial;
         }
         return rows;
     }
@@ -150,17 +150,37 @@
         Map<LocalDate, Map<String, BigDecimal>> passengerByDate = loadPassengerByDate(year);
         Map<LocalDate, Map<String, BigDecimal>> vehicleByDate = loadVehicleByDate(year);
         Map<LocalDate, BigDecimal> comparisonBaseByDate = loadComparisonBaseByDate(year);
+        BigDecimal coefficient = configService.coefficientOf(year, HolidayConstants.CATEGORY_HOLIDAY);
+        return buildDailyMetrics(year, holidayType, dayIndex, date, passengerByDate, vehicleByDate,
+                comparisonBaseByDate, coefficient);
+    }
+
+    public DailyMetrics ringRatioBaseMetrics(int year, String holidayType, int dayIndex) {
+        if (dayIndex <= 1) return null;
+        List<HolidayCalendar> calendar = configService.findHolidayDays(year, holidayType);
+        Map<Integer, HolidayCalendar> calendarByDay = new LinkedHashMap<>();
+        for (HolidayCalendar day : calendar) {
+            if (day.getDayIndex() != null) calendarByDay.put(day.getDayIndex(), day);
+        }
+        Map<LocalDate, Map<String, BigDecimal>> passengerByDate = loadPassengerByDate(year);
+        Map<LocalDate, Map<String, BigDecimal>> vehicleByDate = loadVehicleByDate(year);
+        Map<LocalDate, BigDecimal> comparisonBaseByDate = loadComparisonBaseByDate(year);
+        BigDecimal coefficient = configService.coefficientOf(year, HolidayConstants.CATEGORY_HOLIDAY);
+        return ringRatioBaseFromMaps(year, holidayType, dayIndex, calendarByDay, passengerByDate,
+                vehicleByDate, comparisonBaseByDate, coefficient);
+    }
+
+    private DailyMetrics buildDailyMetrics(int year, String holidayType, int dayIndex, LocalDate date,
+                                           Map<LocalDate, Map<String, BigDecimal>> passengerByDate,
+                                           Map<LocalDate, Map<String, BigDecimal>> vehicleByDate,
+                                           Map<LocalDate, BigDecimal> comparisonBaseByDate,
+                                           BigDecimal coefficient) {
         Map<String, BigDecimal> passenger = passengerByDate.getOrDefault(date, Collections.emptyMap());
         Map<String, BigDecimal> vehicle = vehicleByDate.getOrDefault(date, Collections.emptyMap());
-        BigDecimal coefficient = configService.coefficientOf(year, HolidayConstants.CATEGORY_HOLIDAY);
         BigDecimal expressway = vehicle.get(HolidayConstants.ROAD_EXPRESSWAY);
         BigDecimal nationalProvincial = vehicle.get(HolidayConstants.ROAD_NATIONAL_PROVINCIAL);
         BigDecimal comparisonBase = comparisonBaseByDate.get(date);
-        BigDecimal nonBusiness = null;
-        if (coefficient != null && (expressway != null || nationalProvincial != null)) {
-            nonBusiness = HolidayNumberUtils.multiply(
-                    HolidayNumberUtils.sumNullable(expressway, nationalProvincial), coefficient);
-        }
+        BigDecimal nonBusiness = nonBusinessPersonFlow(expressway, nationalProvincial, coefficient);
 
         DailyMetrics metrics = new DailyMetrics();
         metrics.setYear(year);
@@ -176,9 +196,43 @@
         metrics.setComparisonBase(comparisonBase);
         metrics.setCoefficient(coefficient);
         metrics.setNonBusinessPersonFlow(nonBusiness);
-        metrics.setRoadPersonFlow(sumNullable(metrics.getRoad(), nonBusiness));
-        metrics.setTotalPersonFlow(totalPersonFlow(passenger, nonBusiness));
+        recalculateDerived(metrics);
         return metrics;
+    }
+
+    private DailyMetrics ringRatioBaseFromMaps(int year, String holidayType, int dayIndex,
+                                               Map<Integer, HolidayCalendar> calendarByDay,
+                                               Map<LocalDate, Map<String, BigDecimal>> passengerByDate,
+                                               Map<LocalDate, Map<String, BigDecimal>> vehicleByDate,
+                                               Map<LocalDate, BigDecimal> comparisonBaseByDate,
+                                               BigDecimal coefficient) {
+        if (dayIndex <= 1) return null;
+        HolidayCalendar previous = calendarByDay.get(dayIndex - 1);
+        if (previous == null || previous.getHolidayDate() == null) return null;
+        DailyMetrics base = buildDailyMetrics(year, holidayType, previous.getDayIndex(), previous.getHolidayDate(),
+                passengerByDate, vehicleByDate, comparisonBaseByDate, coefficient);
+        BigDecimal comparisonBase = comparisonBaseByDate.get(previous.getHolidayDate());
+        if (comparisonBase != null) {
+            base.setNationalProvincial(comparisonBase);
+            recalculateDerived(base);
+        }
+        return base;
+    }
+
+    private void recalculateDerived(DailyMetrics metrics) {
+        BigDecimal nonBusiness = nonBusinessPersonFlow(metrics.getExpressway(), metrics.getNationalProvincial(),
+                metrics.getCoefficient());
+        metrics.setNonBusinessPersonFlow(nonBusiness);
+        metrics.setRoadPersonFlow(sumNullable(metrics.getRoad(), nonBusiness));
+        metrics.setTotalPersonFlow(totalPersonFlow(nonBusiness, metrics.getRoad(), metrics.getRail(),
+                metrics.getCivilAviation(), metrics.getWater()));
+    }
+
+    private BigDecimal nonBusinessPersonFlow(BigDecimal expressway, BigDecimal nationalProvincial,
+                                            BigDecimal coefficient) {
+        if (coefficient == null || (expressway == null && nationalProvincial == null)) return null;
+        return HolidayNumberUtils.multiply(
+                HolidayNumberUtils.sumNullable(expressway, nationalProvincial), coefficient);
     }
 
     public DailyMetrics cumulativeMetrics(int year, String holidayType, int dayIndex) {
@@ -228,6 +282,23 @@
             result.computeIfAbsent(row.getFlowDate(), key -> new LinkedHashMap<>())
                     .put(row.getRoadCategory(), row.getVehicleCount());
         }
+        Map<LocalDate, BigDecimal> adjustments = loadNationalProvincialAdjustmentsByDate(year);
+        for (Map.Entry<LocalDate, BigDecimal> entry : adjustments.entrySet()) {
+            result.computeIfAbsent(entry.getKey(), key -> new LinkedHashMap<>())
+                    .put(HolidayConstants.ROAD_NATIONAL_PROVINCIAL, entry.getValue());
+        }
+        return result;
+    }
+
+    private Map<LocalDate, BigDecimal> loadNationalProvincialAdjustmentsByDate(int year) {
+        Map<LocalDate, BigDecimal> result = new LinkedHashMap<>();
+        List<HolidayVehicleAdjustment> rows = vehicleAdjustmentMapper.selectList(
+                new LambdaQueryWrapper<HolidayVehicleAdjustment>().eq(HolidayVehicleAdjustment::getYear, year));
+        for (HolidayVehicleAdjustment row : rows) {
+            if (row.getFlowDate() != null && row.getAdjustedValue() != null) {
+                result.put(row.getFlowDate(), row.getAdjustedValue());
+            }
+        }
         return result;
     }
 
@@ -243,23 +314,16 @@
         return result;
     }
 
-    private BigDecimal totalPersonFlow(Map<String, BigDecimal> passenger, BigDecimal nonBusinessPersonFlow) {
+    private BigDecimal totalPersonFlow(BigDecimal nonBusinessPersonFlow, BigDecimal road, BigDecimal rail,
+                                       BigDecimal civilAviation, BigDecimal water) {
         BigDecimal total = nonBusinessPersonFlow;
-        total = sumNullable(total, passenger.get(HolidayConstants.MODE_ROAD));
-        total = sumNullable(total, passenger.get(HolidayConstants.MODE_RAIL));
-        total = sumNullable(total, passenger.get(HolidayConstants.MODE_CIVIL_AVIATION));
-        total = sumNullable(total, passenger.get(HolidayConstants.MODE_WATER));
+        total = sumNullable(total, road);
+        total = sumNullable(total, rail);
+        total = sumNullable(total, civilAviation);
+        total = sumNullable(total, water);
         return total;
     }
 
-    private BigDecimal nationalProvincialRingRatio(int year, BigDecimal current,
-                                                   BigDecimal previous, BigDecimal comparisonBase) {
-        if (current == null) return null;
-        if (HolidayConstants.supportsComparisonBase(year) && comparisonBase != null) {
-            return ratio(current, comparisonBase);
-        }
-        return previous == null ? null : ratio(current, previous);
-    }
 
     private BigDecimal ratio(BigDecimal current, BigDecimal base) {
         BigDecimal quotient = HolidayNumberUtils.divide(current, base);

--
Gitblit v1.9.1