From 8ad75d5872872b79abada58589adad0df4614db6 Mon Sep 17 00:00:00 2001
From: xyc <jc_xiong@hotmail.com>
Date: 星期三, 07 十月 2026 11:59:44 +0800
Subject: [PATCH] fix(holiday): 走势图按年度配置截取假期天数

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

diff --git a/traffic-audit-server/src/main/java/com/trafficaudit/holiday/service/HolidayTrendService.java b/traffic-audit-server/src/main/java/com/trafficaudit/holiday/service/HolidayTrendService.java
index 39b61d4..f02238e 100644
--- a/traffic-audit-server/src/main/java/com/trafficaudit/holiday/service/HolidayTrendService.java
+++ b/traffic-audit-server/src/main/java/com/trafficaudit/holiday/service/HolidayTrendService.java
@@ -47,10 +47,16 @@
         if (holidayLabel == null) {
             throw new IllegalArgumentException("涓嶆敮鎸佺殑鑺傚亣鏃ョ被鍨�");
         }
+        List<HolidayCalendar> holidayDays = configService.findHolidayDays(year, holidayType);
+        if (holidayDays.isEmpty()) {
+            throw new IllegalArgumentException("鎵�閫夊勾浠藉拰鑺傚亣鏃ュ皻鏈厤缃棩鏈燂紝璇峰厛鍦ㄧ郴缁熼厤缃腑缁存姢鑺傚亣鏃�");
+        }
+        List<String> dayLabels = dayLabels(holidayDays);
+        int dayCount = holidayDays.size();
         List<Integer> years = Arrays.asList(year, year - 1, year - 2);
         Map<Integer, YearData> yearData = new LinkedHashMap<>();
         for (Integer item : years) {
-            yearData.put(item, buildYearData(item, holidayType));
+            yearData.put(item, buildYearData(item, holidayType, dayCount));
         }
         YearData selected = yearData.get(year);
         if (selected == null || !selected.hasAnyData()) {
@@ -63,13 +69,13 @@
         blocks.add(new HolidayTrendWordService.ChartBlock(
                 prefix + "鍏ㄧ渷璺ㄥ尯鍩熶汉鍛樻祦鍔ㄩ噺鎯呭喌",
                 chartService.lineChart("涓囦汉娆�",
-                        series(years, yearData, item -> item.totalDaily), false, 1100, 715),
-                new HolidayTrendWordService.ImageSize(5268595L, 3424555L)));
+                        series(years, yearData, item -> item.totalDaily), false, dayLabels, 2, 1100, 715),
+                lineImageSize(5268595L, 3424555L)));
         blocks.add(new HolidayTrendWordService.ChartBlock(
                 "鈥�" + holidayLabel + "鈥濆亣鏈熺疮璁¤法鍖哄煙浜哄憳娴佸姩閲忚蛋鍔�",
                 chartService.lineChart("涓囦汉娆�",
-                        series(years, yearData, item -> item.totalCumulative), false, 1100, 590),
-                new HolidayTrendWordService.ImageSize(5268595L, 2821305L)));
+                        series(years, yearData, item -> item.totalCumulative), false, dayLabels, 2, 1100, 590),
+                lineImageSize(5268595L, 2821305L)));
         blocks.add(new HolidayTrendWordService.ChartBlock(
                 "鈥�" + holidayLabel + "鈥濆亣鏈熷悇浜ら�氳繍杈撴柟寮忓杩愰噺鍗犳瘮鎯呭喌",
                 chartService.pieChart("浜烘", selected.modalShare(), 1000, 607), true,
@@ -79,45 +85,45 @@
         blocks.add(new HolidayTrendWordService.ChartBlock(
                 "鈥�" + holidayLabel + "鈥濆亣鏈熻嚜椹惧嚭琛岄噺鎯呭喌",
                 chartService.lineChart("涓囦汉娆�",
-                        series(years, yearData, item -> item.selfDrivingPersonFlow), false, 1100, 522),
-                new HolidayTrendWordService.ImageSize(5232400L, 2484120L)));
+                        series(years, yearData, item -> item.selfDrivingPersonFlow), false, dayLabels, 2, 1100, 522),
+                lineImageSize(5232400L, 2484120L)));
         blocks.add(new HolidayTrendWordService.ChartBlock(
                 "鈥�" + holidayLabel + "鈥濆亣鏈熼搧璺杩愰噺鎯呭喌",
                 chartService.lineChart("涓囦汉娆�",
-                        series(years, yearData, item -> item.rail), false, 1100, 445),
-                new HolidayTrendWordService.ImageSize(5264785L, 2129155L)));
+                        series(years, yearData, item -> item.rail), false, dayLabels, 2, 1100, 445),
+                lineImageSize(5264785L, 2129155L)));
         blocks.add(new HolidayTrendWordService.ChartBlock(
                 "鈥�" + holidayLabel + "鈥濆亣鏈熸按璺杩愰噺鎯呭喌",
                 chartService.lineChart("涓囦汉娆�",
-                        series(years, yearData, item -> item.water), false, 1100, 433),
-                new HolidayTrendWordService.ImageSize(5274310L, 2075815L)));
+                        series(years, yearData, item -> item.water), false, dayLabels, 2, 1100, 433),
+                lineImageSize(5274310L, 2075815L)));
         blocks.add(new HolidayTrendWordService.ChartBlock(
                 "鈥�" + holidayLabel + "鈥濆亣鏈熸皯鑸杩愰噺鎯呭喌",
                 chartService.lineChart("涓囦汉娆�",
-                        series(years, yearData, item -> item.civilAviation), false, 1100, 521),
-                new HolidayTrendWordService.ImageSize(5271135L, 2496185L)));
+                        series(years, yearData, item -> item.civilAviation), false, dayLabels, 2, 1100, 521),
+                lineImageSize(5271135L, 2496185L)));
         blocks.add(new HolidayTrendWordService.ChartBlock(
                 "鈥�" + holidayLabel + "鈥濆亣鏈熼亾璺杩愰噺鎯呭喌",
                 chartService.lineChart("涓囦汉娆�",
-                        series(years, yearData, item -> item.road), false, 1100, 590),
-                new HolidayTrendWordService.ImageSize(5268595L, 2821305L)));
+                        series(years, yearData, item -> item.road), false, dayLabels, 2, 1100, 590),
+                lineImageSize(5268595L, 2821305L)));
 
         blocks.add(new HolidayTrendWordService.SectionBlock("涓夈�佽溅娴侀噺璧板娍"));
         blocks.add(new HolidayTrendWordService.ChartBlock(
                 "鈥�" + holidayLabel + "鈥濆亣鏈熼珮閫熷叕璺溅娴侀噺鎯呭喌",
                 chartService.lineChart("涓囪締娆�",
-                        series(years, yearData, item -> item.expressway), false, 1100, 590),
-                new HolidayTrendWordService.ImageSize(5268595L, 2821305L)));
+                        series(years, yearData, item -> item.expressway), false, dayLabels, 2, 1100, 590),
+                lineImageSize(5268595L, 2821305L)));
         blocks.add(new HolidayTrendWordService.ChartBlock(
                 "鈥�" + holidayLabel + "鈥濆亣鏈熸櫘閫氬浗鐪侀亾杞︽祦閲忔儏鍐�",
                 chartService.lineChart("涓囪締娆�",
-                        series(years, yearData, item -> item.nationalProvincial), false, 1100, 590),
-                new HolidayTrendWordService.ImageSize(5268595L, 2821305L)));
+                        series(years, yearData, item -> item.nationalProvincial), false, dayLabels, 2, 1100, 590),
+                lineImageSize(5268595L, 2821305L)));
         blocks.add(new HolidayTrendWordService.ChartBlock(
                 "鈥�" + holidayLabel + "鈥濆亣鏈熷叏鐪佽溅娴佹�婚噺鎯呭喌",
                 chartService.lineChart("涓囪締娆�",
-                        series(years, yearData, item -> item.totalVehicleFlow), false, 1100, 590),
-                new HolidayTrendWordService.ImageSize(5268595L, 2821305L)));
+                        series(years, yearData, item -> item.totalVehicleFlow), false, dayLabels, 2, 1100, 590),
+                lineImageSize(5268595L, 2821305L)));
         blocks.add(new HolidayTrendWordService.ChartBlock(
                 "鈥�" + holidayLabel + "鈥濆亣鏈熷叕璺嚭琛岀粨鏋�",
                 chartService.stackedBarChart("涓囦汉娆�",
@@ -129,22 +135,22 @@
         blocks.add(new HolidayTrendWordService.ChartBlock(
                 "鈥�" + holidayLabel + "鈥濆亣鏈熸瘡鏃ュ娴佹瀯鎴愬彉鍖�",
                 chartService.stackedBarChart("鍗犳瘮",
-                        HolidayTrendChartService.DAY_LABELS,
-                        dailyShareSeries(selected), true, 1000, 607), true,
+                        dayLabels,
+                        dailyShareSeries(selected, dayCount), true, 1000, 607), true,
                 new HolidayTrendWordService.ImageSize(5106670L, 3097530L)));
 
         blocks.add(new HolidayTrendWordService.SectionBlock("闄勫綍浜� 鏅�氬浗鐪侀亾瑙傛祴绔欒矾缃戣繍琛�"));
-        ObservationData observation = observationData(year, holidayType);
+        ObservationData observation = observationData(holidayDays);
         blocks.add(new HolidayTrendWordService.ChartBlock(
                 prefix + "鏅�氬浗鐪侀亾瑙傛祴绔欏钩鍧囨満鍔ㄨ溅閫熷害",
                 chartService.lineChart("鍏噷/灏忔椂",
-                        Collections.singletonList(series("骞冲潎閫熷害", observation.speed)), false, 1100, 590),
-                new HolidayTrendWordService.ImageSize(5268595L, 2821305L)));
+                        Collections.singletonList(series("骞冲潎閫熷害", observation.speed)), false, dayLabels, 2, 1100, 590),
+                lineImageSize(5268595L, 2821305L)));
         blocks.add(new HolidayTrendWordService.ChartBlock(
                 prefix + "鏅�氬浗鐪侀亾瑙傛祴绔欏钩鍧囨嫢鎸ゅ害",
                 chartService.lineChart("鎷ユ尋搴�",
-                        Collections.singletonList(series("骞冲潎鎷ユ尋搴�", observation.congestion)), false, 3, 1100, 590),
-                new HolidayTrendWordService.ImageSize(5268595L, 2821305L)));
+                        Collections.singletonList(series("骞冲潎鎷ユ尋搴�", observation.congestion)), false, dayLabels, 2, 1100, 590),
+                lineImageSize(5268595L, 2821305L)));
 
         File template = resolveTemplateFile();
         if (!template.exists() || !template.isFile()) {
@@ -157,9 +163,9 @@
         }
     }
 
-    private YearData buildYearData(int year, String holidayType) {
+    private YearData buildYearData(int year, String holidayType, int dayCount) {
         List<DailyMetrics> metrics = new ArrayList<>();
-        for (int day = 1; day <= HolidayTrendChartService.DAY_LABELS.size(); day++) {
+        for (int day = 1; day <= dayCount; day++) {
             metrics.add(statService.dailyMetrics(year, holidayType, day));
         }
         YearData data = new YearData();
@@ -210,19 +216,19 @@
         return result;
     }
 
-    private List<HolidayTrendChartService.ChartSeries> dailyShareSeries(YearData data) {
+    private List<HolidayTrendChartService.ChartSeries> dailyShareSeries(YearData data, int dayCount) {
         List<HolidayTrendChartService.ChartSeries> result = new ArrayList<>();
-        result.add(series("鑷┚", share(data.selfDrivingPersonFlow, data)));
-        result.add(series("閬撹矾", share(data.road, data)));
-        result.add(series("閾佽矾", share(data.rail, data)));
-        result.add(series("姘戣埅", share(data.civilAviation, data)));
-        result.add(series("姘磋矾", share(data.water, data)));
+        result.add(series("鑷┚", share(data.selfDrivingPersonFlow, data, dayCount)));
+        result.add(series("閬撹矾", share(data.road, data, dayCount)));
+        result.add(series("閾佽矾", share(data.rail, data, dayCount)));
+        result.add(series("姘戣埅", share(data.civilAviation, data, dayCount)));
+        result.add(series("姘磋矾", share(data.water, data, dayCount)));
         return result;
     }
 
-    private List<BigDecimal> share(List<BigDecimal> values, YearData data) {
+    private List<BigDecimal> share(List<BigDecimal> values, YearData data, int dayCount) {
         List<BigDecimal> result = new ArrayList<>();
-        for (int i = 0; i < HolidayTrendChartService.DAY_LABELS.size(); i++) {
+        for (int i = 0; i < dayCount; i++) {
             BigDecimal total = dayTotal(data, i);
             BigDecimal value = valueAt(values, i);
             result.add(total == null || total.signum() == 0
@@ -260,13 +266,12 @@
                 series("閬撹矾瀹㈣繍閲�", road));
     }
 
-    private ObservationData observationData(int year, String holidayType) {
-        List<HolidayCalendar> days = configService.findHolidayDays(year, holidayType);
+    private ObservationData observationData(List<HolidayCalendar> days) {
         if (days.isEmpty()) {
-            return new ObservationData(nulls(), nulls());
+            return new ObservationData(nulls(0), nulls(0));
         }
         LocalDate start = days.get(0).getHolidayDate();
-        LocalDate end = start.plusDays(HolidayTrendChartService.DAY_LABELS.size() - 1L);
+        LocalDate end = days.get(days.size() - 1).getHolidayDate();
         List<ObservationDailyOperation> rows = observationStationFlowMapper.selectDailyOperations(start, end);
         Map<LocalDate, ObservationDailyOperation> byDate = new LinkedHashMap<>();
         for (ObservationDailyOperation row : rows) {
@@ -274,8 +279,8 @@
         }
         List<BigDecimal> speed = new ArrayList<>();
         List<BigDecimal> congestion = new ArrayList<>();
-        for (int i = 0; i < HolidayTrendChartService.DAY_LABELS.size(); i++) {
-            ObservationDailyOperation row = byDate.get(start.plusDays(i));
+        for (HolidayCalendar day : days) {
+            ObservationDailyOperation row = byDate.get(day.getHolidayDate());
             speed.add(row == null ? null : row.getAverageSpeed());
             congestion.add(row == null ? null : row.getAverageCongestion());
         }
@@ -319,7 +324,8 @@
 
     private List<BigDecimal> percentageChanges(List<BigDecimal> current, List<BigDecimal> previous) {
         List<BigDecimal> result = new ArrayList<>();
-        for (int i = 0; i < HolidayTrendChartService.DAY_LABELS.size(); i++) {
+        int size = Math.max(current == null ? 0 : current.size(), previous == null ? 0 : previous.size());
+        for (int i = 0; i < size; i++) {
             BigDecimal currentValue = valueAt(current, i);
             BigDecimal previousValue = valueAt(previous, i);
             BigDecimal ratio = HolidayNumberUtils.divide(currentValue, previousValue);
@@ -342,11 +348,31 @@
     }
 
     private List<BigDecimal> nulls() {
+        return nulls(HolidayTrendChartService.DAY_LABELS.size());
+    }
+
+    private List<BigDecimal> nulls(int size) {
         List<BigDecimal> result = new ArrayList<>();
-        for (int i = 0; i < HolidayTrendChartService.DAY_LABELS.size(); i++) result.add(null);
+        for (int i = 0; i < size; i++) result.add(null);
         return result;
     }
 
+    static List<String> dayLabels(List<HolidayCalendar> days) {
+        List<String> labels = new ArrayList<>();
+        if (days == null) return labels;
+        for (HolidayCalendar day : days) {
+            if (day == null || day.getHolidayDate() == null) continue;
+            labels.add(day.getHolidayDate().getMonthValue() + "鏈�"
+                    + day.getHolidayDate().getDayOfMonth() + "鏃�");
+        }
+        return labels;
+    }
+
+    private HolidayTrendWordService.ImageSize lineImageSize(long width, long height) {
+        return new HolidayTrendWordService.ImageSize(
+                width, HolidayTrendChartService.scaleLineChartHeight(height));
+    }
+
     private File resolveTemplateFile() {
         List<File> candidates = new ArrayList<>();
         File configured = new File(trendTemplatePath);

--
Gitblit v1.9.1