From 922823a3f1faaf0293256e3ffb1285eaeb8a3b23 Mon Sep 17 00:00:00 2001
From: xyc <jc_xiong@hotmail.com>
Date: 星期日, 04 十月 2026 07:03:42 +0800
Subject: [PATCH] fix(holiday): 快报百分比按Excel显示精度取值

---
 traffic-audit-server/src/main/java/com/trafficaudit/holiday/service/HolidayBulletinService.java |  134 ++++++++++++++++++++++++++++----------------
 1 files changed, 86 insertions(+), 48 deletions(-)

diff --git a/traffic-audit-server/src/main/java/com/trafficaudit/holiday/service/HolidayBulletinService.java b/traffic-audit-server/src/main/java/com/trafficaudit/holiday/service/HolidayBulletinService.java
index f99c55d..312d18f 100644
--- a/traffic-audit-server/src/main/java/com/trafficaudit/holiday/service/HolidayBulletinService.java
+++ b/traffic-audit-server/src/main/java/com/trafficaudit/holiday/service/HolidayBulletinService.java
@@ -42,6 +42,8 @@
 
     private static final String WORD_NS = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
     private static final BigDecimal EPSILON = new BigDecimal("0.0000001");
+    private static final int EXCEL_ONE_DECIMAL_PERCENT = 1;
+    private static final int EXCEL_TWO_DECIMAL_PERCENT = 2;
 
     @Value("${holiday.bulletin-template:docs/涓撻」缁熻/閲嶈鑺傚亣鏃�/婀栧寳鐪佸浗搴嗗亣鏈熺患鍚堣繍杈撳娴佸揩鎶ユā鏉�.docx}")
     private String bulletinTemplatePath;
@@ -79,12 +81,12 @@
 
         String currentTotal = formatNumber(current.getTotalPersonFlow());
         String ringRatioClause = previousDay == null ? "" : "锛岀幆姣�" + ratioPhrase(
-                current.getTotalPersonFlow(), previousDay.getTotalPersonFlow());
+                current.getTotalPersonFlow(), previousDay.getTotalPersonFlow(), EXCEL_TWO_DECIMAL_PERCENT);
         String paragraph1 = String.format("%d鏈�%d鏃ワ紙鍋囨湡绗�%d澶╋級锛屽叏鐪佸叏绀句細璺ㄥ尯鍩熶汉鍛樻祦鍔ㄩ噺%s涓囦汉娆�%s锛屾瘮2025骞村悓鏈�%s锛屾瘮2024骞村悓鏈�%s銆�",
                 date.getMonthValue(), date.getDayOfMonth(), current.getDayIndex(), currentTotal,
                 ringRatioClause,
-                ratioPhrase(current.getTotalPersonFlow(), previousYear == null ? null : previousYear.getTotalPersonFlow()),
-                ratioPhrase(current.getTotalPersonFlow(), twoYearsAgo == null ? null : twoYearsAgo.getTotalPersonFlow()));
+                ratioPhrase(current.getTotalPersonFlow(), previousYear == null ? null : previousYear.getTotalPersonFlow(), EXCEL_ONE_DECIMAL_PERCENT),
+                ratioPhrase(current.getTotalPersonFlow(), twoYearsAgo == null ? null : twoYearsAgo.getTotalPersonFlow(), EXCEL_ONE_DECIMAL_PERCENT));
         String paragraph2 = cumulativeParagraph(currentCumulative, previousYearCumulative, twoYearsAgoCumulative);
 
         File template = resolveTemplateFile();
@@ -131,34 +133,46 @@
                 current, twoYearsAgo, DailyMetrics::getCivilAviation);
         writeTableRow(table, 2, new String[]{
                 number(current.getNonBusinessPersonFlow()),
-                ratio(current.getNonBusinessPersonFlow(), previousDay == null ? null : previousDay.getNonBusinessPersonFlow()),
-                ratio(current.getNonBusinessPersonFlow(), previousYear == null ? null : previousYear.getNonBusinessPersonFlow()),
-                ratio(current.getNonBusinessPersonFlow(), twoYearsAgo == null ? null : twoYearsAgo.getNonBusinessPersonFlow()),
+                ratio(current.getNonBusinessPersonFlow(), previousDay == null ? null : previousDay.getNonBusinessPersonFlow(),
+                        EXCEL_TWO_DECIMAL_PERCENT),
+                ratio(current.getNonBusinessPersonFlow(), previousYear == null ? null : previousYear.getNonBusinessPersonFlow(),
+                        EXCEL_ONE_DECIMAL_PERCENT),
+                ratio(current.getNonBusinessPersonFlow(), twoYearsAgo == null ? null : twoYearsAgo.getNonBusinessPersonFlow(),
+                        EXCEL_ONE_DECIMAL_PERCENT),
                 number(currentCumulative.getNonBusinessPersonFlow()),
                 ratio(currentCumulative.getNonBusinessPersonFlow(),
-                        previousYearCumulative == null ? null : previousYearCumulative.getNonBusinessPersonFlow()),
+                        previousYearCumulative == null ? null : previousYearCumulative.getNonBusinessPersonFlow(),
+                        EXCEL_TWO_DECIMAL_PERCENT),
                 ratio(currentCumulative.getNonBusinessPersonFlow(),
-                        twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getNonBusinessPersonFlow())
+                        twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getNonBusinessPersonFlow(),
+                        EXCEL_TWO_DECIMAL_PERCENT)
         });
         writeTableRow(table, 3, new String[]{
                 number(current.getRoad()),
-                ratio(current.getRoad(), previousDay == null ? null : previousDay.getRoad()),
-                ratio(current.getRoad(), previousYear == null ? null : previousYear.getRoad()),
-                ratio(current.getRoad(), twoYearsAgo == null ? null : twoYearsAgo.getRoad()),
+                ratio(current.getRoad(), previousDay == null ? null : previousDay.getRoad(), EXCEL_ONE_DECIMAL_PERCENT),
+                ratio(current.getRoad(), previousYear == null ? null : previousYear.getRoad(), EXCEL_ONE_DECIMAL_PERCENT),
+                ratio(current.getRoad(), twoYearsAgo == null ? null : twoYearsAgo.getRoad(), EXCEL_ONE_DECIMAL_PERCENT),
                 number(currentCumulative.getRoad()),
-                ratio(currentCumulative.getRoad(), previousYearCumulative == null ? null : previousYearCumulative.getRoad()),
-                ratio(currentCumulative.getRoad(), twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getRoad())
+                ratio(currentCumulative.getRoad(), previousYearCumulative == null ? null : previousYearCumulative.getRoad(),
+                        EXCEL_ONE_DECIMAL_PERCENT),
+                ratio(currentCumulative.getRoad(), twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getRoad(),
+                        EXCEL_ONE_DECIMAL_PERCENT)
         });
         writeTableRow(table, 4, new String[]{
                 number(current.getRoadPersonFlow()),
-                ratio(current.getRoadPersonFlow(), previousDay == null ? null : previousDay.getRoadPersonFlow()),
-                ratio(current.getRoadPersonFlow(), previousYear == null ? null : previousYear.getRoadPersonFlow()),
-                ratio(current.getRoadPersonFlow(), twoYearsAgo == null ? null : twoYearsAgo.getRoadPersonFlow()),
+                ratio(current.getRoadPersonFlow(), previousDay == null ? null : previousDay.getRoadPersonFlow(),
+                        EXCEL_TWO_DECIMAL_PERCENT),
+                ratio(current.getRoadPersonFlow(), previousYear == null ? null : previousYear.getRoadPersonFlow(),
+                        EXCEL_ONE_DECIMAL_PERCENT),
+                ratio(current.getRoadPersonFlow(), twoYearsAgo == null ? null : twoYearsAgo.getRoadPersonFlow(),
+                        EXCEL_ONE_DECIMAL_PERCENT),
                 number(currentCumulative.getRoadPersonFlow()),
                 ratio(currentCumulative.getRoadPersonFlow(),
-                        previousYearCumulative == null ? null : previousYearCumulative.getRoadPersonFlow()),
+                        previousYearCumulative == null ? null : previousYearCumulative.getRoadPersonFlow(),
+                        EXCEL_TWO_DECIMAL_PERCENT),
                 ratio(currentCumulative.getRoadPersonFlow(),
-                        twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getRoadPersonFlow())
+                        twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getRoadPersonFlow(),
+                        EXCEL_TWO_DECIMAL_PERCENT)
         });
         writeTableRow(table, 5, transportRow(current.getRail(),
                 firstDayRailBase == null ? null : firstDayRailBase.getRail(),
@@ -166,41 +180,54 @@
                 twoYearsAgo == null ? null : twoYearsAgo.getRail(),
                 currentCumulative.getRail(),
                 previousYearCumulative == null ? null : previousYearCumulative.getRail(),
-                twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getRail()));
+                twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getRail(),
+                EXCEL_ONE_DECIMAL_PERCENT));
         writeTableRow(table, 6, transportRow(current.getCivilAviation(),
                 firstDayCivilAviationBase == null ? null : firstDayCivilAviationBase.getCivilAviation(),
                 previousYear == null ? null : previousYear.getCivilAviation(),
                 twoYearsAgo == null ? null : twoYearsAgo.getCivilAviation(),
                 currentCumulative.getCivilAviation(),
                 previousYearCivilCumulative == null ? null : previousYearCivilCumulative.getCivilAviation(),
-                twoYearsAgoCivilCumulative == null ? null : twoYearsAgoCivilCumulative.getCivilAviation()));
+                twoYearsAgoCivilCumulative == null ? null : twoYearsAgoCivilCumulative.getCivilAviation(),
+                EXCEL_ONE_DECIMAL_PERCENT));
         writeTableRow(table, 7, transportRow(current.getWater(),
                 previousDay == null ? null : previousDay.getWater(),
                 previousYear == null ? null : previousYear.getWater(),
                 twoYearsAgo == null ? null : twoYearsAgo.getWater(),
                 currentCumulative.getWater(),
                 previousYearCumulative == null ? null : previousYearCumulative.getWater(),
-                twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getWater()));
-        writeTableRow(table, 8, transportRow(current.getTotalPersonFlow(),
-                previousDay == null ? null : previousDay.getTotalPersonFlow(),
-                previousYear == null ? null : previousYear.getTotalPersonFlow(),
-                twoYearsAgo == null ? null : twoYearsAgo.getTotalPersonFlow(),
-                currentCumulative.getTotalPersonFlow(),
-                previousYearCumulative == null ? null : previousYearCumulative.getTotalPersonFlow(),
-                twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getTotalPersonFlow()));
+                twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getWater(),
+                EXCEL_TWO_DECIMAL_PERCENT));
+        writeTableRow(table, 8, new String[]{
+                number(current.getTotalPersonFlow()),
+                ratio(current.getTotalPersonFlow(), previousDay == null ? null : previousDay.getTotalPersonFlow(),
+                        EXCEL_TWO_DECIMAL_PERCENT),
+                ratio(current.getTotalPersonFlow(), previousYear == null ? null : previousYear.getTotalPersonFlow(),
+                        EXCEL_ONE_DECIMAL_PERCENT),
+                ratio(current.getTotalPersonFlow(), twoYearsAgo == null ? null : twoYearsAgo.getTotalPersonFlow(),
+                        EXCEL_ONE_DECIMAL_PERCENT),
+                number(currentCumulative.getTotalPersonFlow()),
+                ratio(currentCumulative.getTotalPersonFlow(),
+                        previousYearCumulative == null ? null : previousYearCumulative.getTotalPersonFlow(),
+                        EXCEL_TWO_DECIMAL_PERCENT),
+                ratio(currentCumulative.getTotalPersonFlow(),
+                        twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getTotalPersonFlow(),
+                        EXCEL_TWO_DECIMAL_PERCENT)
+        });
     }
 
     private String[] transportRow(BigDecimal current, BigDecimal previousDay, BigDecimal previousYear,
                                   BigDecimal twoYearsAgo, BigDecimal currentCumulative,
-                                  BigDecimal previousYearCumulative, BigDecimal twoYearsAgoCumulative) {
+                                  BigDecimal previousYearCumulative, BigDecimal twoYearsAgoCumulative,
+                                  int ringRatioExcelScale) {
         return new String[]{
                 number(current),
-                ratio(current, previousDay),
-                ratio(current, previousYear),
-                ratio(current, twoYearsAgo),
+                ratio(current, previousDay, ringRatioExcelScale),
+                ratio(current, previousYear, EXCEL_ONE_DECIMAL_PERCENT),
+                ratio(current, twoYearsAgo, EXCEL_ONE_DECIMAL_PERCENT),
                 number(currentCumulative),
-                ratio(currentCumulative, previousYearCumulative),
-                ratio(currentCumulative, twoYearsAgoCumulative)
+                ratio(currentCumulative, previousYearCumulative, EXCEL_ONE_DECIMAL_PERCENT),
+                ratio(currentCumulative, twoYearsAgoCumulative, EXCEL_ONE_DECIMAL_PERCENT)
         };
     }
 
@@ -322,11 +349,10 @@
         return builder.toString();
     }
 
-    private String ratioPhrase(BigDecimal current, BigDecimal base) {
-        if (current == null || base == null || base.abs().compareTo(EPSILON) < 0) return "鏃犲彲姣旀暟鎹�";
-        BigDecimal ratio = HolidayNumberUtils.divide(current, base);
-        BigDecimal percent = HolidayNumberUtils.multiply(ratio.subtract(BigDecimal.ONE), BigDecimal.valueOf(100));
-        if (percent == null || percent.abs().compareTo(EPSILON) < 0) return "鎸佸钩";
+    private String ratioPhrase(BigDecimal current, BigDecimal base, int excelPercentScale) {
+        BigDecimal percent = bulletinPercent(current, base, excelPercentScale);
+        if (percent == null) return "鏃犲彲姣旀暟鎹�";
+        if (percent.signum() == 0) return "鎸佸钩";
         return (percent.signum() > 0 ? "澧為暱" : "涓嬮檷") + HolidayNumberUtils.format1(percent.abs()) + "%";
     }
 
@@ -351,18 +377,30 @@
         BigDecimal total = currentCumulative == null ? null : currentCumulative.getTotalPersonFlow();
         return String.format("鍋囨湡浠ユ潵锛屽叏鐪佸叏绀句細璺ㄥ尯鍩熶汉鍛樻祦鍔ㄩ噺绱%s涓囦汉娆★紝姣�2025骞村悓鏈�%s锛屾瘮2024骞村悓鏈�%s銆�",
                 formatNumber(total),
-                ratioPhrase(total, previousYearCumulative == null ? null : previousYearCumulative.getTotalPersonFlow()),
-                ratioPhrase(total, twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getTotalPersonFlow()));
+                ratioPhrase(total, previousYearCumulative == null ? null : previousYearCumulative.getTotalPersonFlow(),
+                        EXCEL_TWO_DECIMAL_PERCENT),
+                ratioPhrase(total, twoYearsAgoCumulative == null ? null : twoYearsAgoCumulative.getTotalPersonFlow(),
+                        EXCEL_TWO_DECIMAL_PERCENT));
     }
 
-    private String ratio(BigDecimal current, BigDecimal base) {
-        if (current == null || base == null || base.abs().compareTo(EPSILON) < 0) return "鈥�";
-        BigDecimal ratio = HolidayNumberUtils.divide(current, base);
-        if (ratio == null) return "鈥�";
-        BigDecimal percent = HolidayNumberUtils.multiply(ratio.subtract(BigDecimal.ONE), BigDecimal.valueOf(100));
+    private String ratio(BigDecimal current, BigDecimal base, int excelPercentScale) {
+        BigDecimal percent = bulletinPercent(current, base, excelPercentScale);
         if (percent == null) return "鈥�";
-        BigDecimal rounded = percent.setScale(1, RoundingMode.HALF_UP);
-        return rounded.signum() == 0 ? "0%" : rounded.toPlainString() + "%";
+        return percent.signum() == 0 ? "0%" : percent.toPlainString() + "%";
+    }
+
+    /**
+     * Mirrors the source Excel percentage cell format, then applies the bulletin's one-decimal rule.
+     * Excel stores full precision but displays 0.0% or 0.00%; reviewers compare against that display.
+     */
+    private BigDecimal bulletinPercent(BigDecimal current, BigDecimal base, int excelPercentScale) {
+        if (current == null || base == null || base.abs().compareTo(EPSILON) < 0) return null;
+        BigDecimal ratio = HolidayNumberUtils.divide(current, base);
+        if (ratio == null) return null;
+        BigDecimal percent = HolidayNumberUtils.multiply(ratio.subtract(BigDecimal.ONE), BigDecimal.valueOf(100));
+        if (percent == null) return null;
+        BigDecimal displayed = percent.setScale(excelPercentScale, RoundingMode.HALF_UP);
+        return displayed.setScale(1, RoundingMode.HALF_UP);
     }
 
     private String number(BigDecimal value) {

--
Gitblit v1.9.1