fix: 汇总表整数不再显示 .00(公式整数格同跳过)+ 导出列宽按内容自适应 + 09-04 测试报告与母版数据体检清单
1个文件已修改
2个文件已添加
117 ■■■■■ 已修改文件
docs/功能测试报告/功能测试报告_汇总表整数不显示0.00与列宽自适应_2026-09-04.md 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/生成汇总大表/汇总表母版数据体检与待决策清单_2026-09-04.md 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/¹¦ÄܲâÊÔ±¨¸æ/¹¦ÄܲâÊÔ±¨¸æ_»ã×ܱíÕûÊý²»ÏÔʾ0.00ÓëÁпí×ÔÊÊÓ¦_2026-09-04.md
New file
@@ -0,0 +1,26 @@
# åŠŸèƒ½æµ‹è¯•æŠ¥å‘Šï¼šæ±‡æ€»è¡¨æ•´æ•°ä¸æ˜¾ç¤º .00 ä¸Žåˆ—宽自适应(2026-09-04)
## åŠŸèƒ½è¯´æ˜Ž
针对《生成_道路运输量汇总表》两个体验问题修改(仅动 ReportExportService.java):
1. æ•°å­—显示:保留“显示两位小数、存储全精度”的总原则,但整数值不再显示 `.00`(原实现对“公式结果为整数”的格也会套 0.00,本次补齐跳过逻辑)。
2. åˆ—宽:汇总表整本导出后按单元格内容自动加宽(只加宽不缩窄;跳过合并单元格标题;中文按 2 å€å®½ä¼°ç®—;单格超宽文本封顶 34,列宽上限 46,防止长说明把列撑爆)。
## æµ‹è¯•环境
- åŽç«¯ 8090(重新编译并重启,新代码生效);MySQL 127.0.0.1:3308。
- æ¯ç‰ˆï¼šdocs/生成汇总大表/2026å¹´7月道路运输量汇总表.xlsx;基线文件:docs/生成汇总大表/生成_道路运输量汇总表.xlsx(旧代码导出)。
## ç”¨ä¾‹ä¸Žç»“æžœ
| # | ç”¨ä¾‹ | è¾“å…¥/预期 | å®žé™… | ç»“论 |
|---|---|---|---|---|
| 1 | æ±‡æ€»è¡¨æ•´æ•°æ ¼ä¸å¸¦ .00(正向) | 2026-07 æ•´æœ¬å¯¼å‡ºï¼Œæ•´æ•°æ ¼ä¸å†è¢«å¥— 0.00 æ ·å¼ | æ•´æ•°ä¸” 0.00 æ ·å¼çš„æ ¼ç”±æ—§æ–‡ä»¶ 972 å¤„降至 34 å¤„(剩余 34 å¤„为母版本身预设 0.00 æ ·å¼ï¼Œéžæœ¬æ¬¡å¯¼å‡ºæ–°å¢žï¼‰ï¼›0.00 æ ·å¼æ€»æ•° 10588→9650 | PASS |
| 2 | æ±‡æ€»è¡¨å°æ•°æ ¼ä»ä¸¤ä½æ˜¾ç¤ºã€ä¿ç•™å…¨ç²¾åº¦ï¼ˆæ­£å‘) | éžæ•´æ•°æ ¼æ˜¾ç¤º 0.00、数值精度不变 | æŠ½æŸ¥ä¸­å£å¾„分析 B4=11204.5406 ç­‰ä»æŒ‰ 0.00 æ˜¾ç¤ºä¸”存储全精度;非整数纯数值格无遗漏(nonint-plain=0) | PASS |
| 3 | åˆ—宽按内容加宽(正向) | å„页签列宽只增不减 | ä¸­å£å¾„分析 B/D/H、城市汇总、货运量排名、城市分市州、班线包车等抽查列宽均加宽(如货运量排名 Q åŽŸæœªè®¾å®½åº¦â†’21、B→21);max å®½ 36 ä»¥å†… | PASS |
| 4 | ç‹¬ç«‹æŠ¥è¡¨å›žå½’(wycSplit 2026-07) | æ•´æ•°ä¸å¸¦ .00、非整数全部 0.00 | æ•´æ•°ä¸” .00 æ ¼=0;188 ä¸ªéžæ•´æ•°æ ¼å…¨éƒ¨ 0.00 æ˜¾ç¤º | PASS |
| 5 | ç¼–译与启动回归 | mvn compile EXIT=0、后端重启就绪 | ç¼–译 EXIT=0;8090 å¯åЍ OK | PASS |
## å‘现的问题与处置
1. æ¯ç‰ˆè‡ªèº«ä»æœ‰ 34 ä¸ªâ€œæ•´æ•°æ ¼é¢„设 0.00 æ ·å¼â€ï¼ˆå±žç‰ˆå¼è®¾è®¡è€Œéžå¯¼å‡ºäº§ç”Ÿï¼‰ï¼Œå¦‚需彻底去掉需改母版样式,本次不动。
2. æ±‡æ€»è¡¨æ¯ç‰ˆå­˜åœ¨æ•°æ®é—®é¢˜ï¼ˆ7月当月块错用累计值,涉及 5 ä¸ªé¡µç­¾ï¼‰ï¼Œå±žæ•°æ®å±‚问题、非本次格式修改范围,另见《汇总表母版数据体检与待决策清单_2026-09-04.md》。
## ç»“论
两项修改通过测试:整数不再显示 .00;汇总表导出后列宽按内容自适应加宽;非整数格仍显示两位小数并保留全精度。
docs/Éú³É»ã×Ü´ó±í/»ã×ܱíĸ°æÊý¾ÝÌå¼ìÓë´ý¾ö²ßÇåµ¥_2026-09-04.md
New file
@@ -0,0 +1,26 @@
# æ±‡æ€»è¡¨æ¯ç‰ˆæ•°æ®ä½“检与待决策清单(2026-09-04)
> ç»“论先行:当前“生成_道路运输量汇总表 = æ•´æœ¬å¤åˆ¶æ¯ç‰ˆâ€ã€‚本次体检发现的问题绝大多数**存在于母版文件本身(数据层)**,不是导出程序把它算错。母版文件:docs/生成汇总大表/2026å¹´7月道路运输量汇总表.xlsx。
## ä¸€ã€å·²ç¡®è®¤é—®é¢˜ï¼ˆå½“月块错用累计值)
母版中以下 5 ä¸ªæˆå“é¡µçš„“7月当月”数据块,被复制成了“1-7月累计”数据块(数值、同比全部相同):
| é¡µç­¾ | ç´¯è®¡å— | å½“月块(错误) | ç¤ºä¾‹ | 7月当月应约为 |
|---|---|---|---|---|
| ä¸­å£å¾„分析 | r3-r7 | r12-r16 | æ€»å®¢è¿é‡ 27524.49 | â‰ˆ4028(班线 1631.20+公交城乡 1466.66+出租城乡 509.00+网约车城乡 421.46,均取 2026-07 åº“内/拆分值) |
| åŸŽå¸‚汇总 | r3-r9 | r14-r20 | æ€»å®¢è¿é‡ 237412.33 | â‰ˆ35465(公交 12974.73+巡游出租 5860.24+网约车 4852.30+轨道 11731.83+轮渡 46.05) |
| åŸŽå¸‚分市州 | r5 èµ· | r50 èµ· | å…¨çœæ€»å®¢è¿é‡ 237412.33 | åŒåŸŽå¸‚汇总单月口径 |
| è´§è¿é‡æŽ’名 | r4-r21 | r25-… | å…¨çœè§„上 27734.461 | 7月单月(远小于 1-7 ç´¯è®¡ï¼‰ |
| è´§è¿å‘¨è½¬é‡æŽ’名 | r5 èµ· | r27 èµ· | å…¨çœè§„上周转量 4357157.34 | 7月单月 |
连带影响:当月块的“同比”“排名”“占比”也随错误值一并错(如中口径分析 C12/G12 åŒ C3/G3,用的都是累计同比)。
## äºŒã€å…¶ä»–需要你拍板/留意的问题
1. æ•°æ®æºç¼ºå£ï¼ˆå½±å“â€œç¨‹åºè‡ªåŠ¨ç”Ÿæˆ 1-7 ç´¯è®¡â€ï¼‰ï¼šåº“内 h2031 ä¼ä¸šæœˆæŠ¥åªæœ‰ 2026-03、2026-07;城市公交/巡游出租只有 2026-06、2026-07;个体客运只有 2026-07。当前唯一完整的 1-7 å„月口径依据是母版台账页本身。
2. ç½‘约车月度拆分输入《网约车订单及全省总量.xlsx》目前只有 2026-07 ä¸€è¡Œï¼Œ1-6 æœˆç½‘约车各月无法由程序自动计算。
3. æ¯ç‰ˆå…¶å®ƒé—留:右侧大量 2024/更早参考列与 `#REF!` æ–­é“¾ï¼ˆå·²çŸ¥å¤„理项);页签间公式引用与“空母版填值”方案仍按 P2 è½åœ°æ–¹æ¡ˆæŽ¨è¿›ï¼ˆè¡Œåˆ—边界、月份扩展、2024 åˆ—处理、轨道轮渡入库、输出目录五项待拍板)。
## ä¸‰ã€ä¿®å¤æ–¹å‘建议(请选择/确认)
- æ–¹æ¡ˆ A(短平快,仅本月正确):按上表把母版 5 ä¸ªé¡µç­¾çš„“7月当月块”用 7 æœˆå½“月库值/拆分结果改正确,本次生成即正确;以后每月母版仍需人工保证当月块正确。
- æ–¹æ¡ˆ B(根治,推荐后续 P2 å®žçŽ°ï¼‰ï¼šå¯¼å‡ºæ—¶ä¸å†ä¿¡ä»»æ¯ç‰ˆå½“æœˆå—ï¼Œæ”¹ä¸ºâ€œå°è´¦é¡µï¼ˆä¿ç•™ 1-7 å„月)+当月库值+网约车拆分输入”自动重算成品页当月块;累计块与台账页一致性也可加入生成后自动校验。
- å…ˆåš A é¡¶ä½æœ¬æœˆæµ‹è¯•,再排期做 B。
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java
@@ -3208,6 +3208,8 @@
        try (InputStream in = new FileInputStream(template);
             XSSFWorkbook wb = new XSSFWorkbook(in)) {
            dynamicSummaryYear(wb, year);
            applyTwoDecimalFormat(wb);
            autoFitContentColumns(wb); // æ±‡æ€»è¡¨å¯¼å‡ºåŽæŒ‰å†…容加宽列宽(只加宽不缩窄)
            return toBytes(wb);
        }
    }
@@ -4574,7 +4576,13 @@
                        CellType ct = cell.getCellType();
                        if (ct != CellType.NUMERIC && ct != CellType.FORMULA) continue;
                        if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) continue;
                        if (ct == CellType.NUMERIC && Math.rint(cell.getNumericCellValue()) == cell.getNumericCellValue()) continue;
                        boolean integral = false;
                        if (ct == CellType.NUMERIC) {
                            integral = Math.rint(cell.getNumericCellValue()) == cell.getNumericCellValue();
                        } else if (cell.getCachedFormulaResultType() == CellType.NUMERIC) {
                            integral = Math.rint(cell.getNumericCellValue()) == cell.getNumericCellValue();
                        }
                        if (integral) continue; // æ•´æ•°ä¸æ˜¾ç¤º .00(含公式结果为整数的格)
                        org.apache.poi.ss.usermodel.CellStyle cs = cell.getCellStyle();
                        if (cs == null) continue;
                        String f = cs.getDataFormatString();
@@ -4595,6 +4603,61 @@
        }
    }
    /** æ±‡æ€»è¡¨å¯¼å‡ºåŽæŒ‰å†…容自动加宽列宽(只加宽不缩窄;跳过合并单元格标题,防长标题把单列撑爆) */
    private void autoFitContentColumns(org.apache.poi.ss.usermodel.Workbook wb) {
        if (wb == null) return;
        org.apache.poi.ss.usermodel.DataFormatter dfmt = new org.apache.poi.ss.usermodel.DataFormatter();
        for (int s = 0; s < wb.getNumberOfSheets(); s++) {
            org.apache.poi.ss.usermodel.Sheet sh = wb.getSheetAt(s);
            if (sh == null) continue;
            java.util.Set<String> merged = new java.util.HashSet<>();
            for (org.apache.poi.ss.util.CellRangeAddress ra : sh.getMergedRegions()) {
                for (int r = ra.getFirstRow(); r <= ra.getLastRow(); r++) {
                    for (int c = ra.getFirstColumn(); c <= ra.getLastColumn(); c++) {
                        merged.add(r + ":" + c);
                    }
                }
            }
            int maxCol = -1;
            for (org.apache.poi.ss.usermodel.Row row : sh) {
                if (row == null) continue;
                maxCol = Math.max(maxCol, (int) row.getLastCellNum() - 1);
            }
            if (maxCol < 0) continue;
            int[] need = new int[maxCol + 1];
            for (org.apache.poi.ss.usermodel.Row row : sh) {
                if (row == null) continue;
                for (org.apache.poi.ss.usermodel.Cell cell : row) {
                    int c = cell.getColumnIndex();
                    if (c > maxCol || merged.contains(row.getRowNum() + ":" + c)) continue;
                    String txt;
                    try {
                        txt = dfmt.formatCellValue(cell);
                    } catch (Exception ignore) {
                        continue;
                    }
                    if (txt == null || txt.isEmpty()) continue;
                    int units = 0;
                    for (int i = 0; i < txt.length(); i++) {
                        units += isWideChar(txt.charAt(i)) ? 2 : 1;
                    }
                    if (units > need[c]) need[c] = Math.min(units, 34); // é•¿æ–‡æœ¬ä¸æŠŠå•列撑爆
                }
            }
            for (int c = 0; c <= maxCol; c++) {
                if (need[c] <= 0) continue;
                int target = Math.min(need[c] + 2, 46) * 256;
                if (target > sh.getColumnWidth(c)) sh.setColumnWidth(c, target);
            }
        }
    }
    /** CJK / å…¨è§’字符按两倍宽度计(近似 Excel æ˜¾ç¤ºåˆ—宽) */
    private boolean isWideChar(char ch) {
        return (ch >= 0x2E80 && ch <= 0x9FFF) || (ch >= 0xF900 && ch <= 0xFAFF)
            || (ch >= 0xFF00 && ch <= 0xFFEF);
    }
    private byte[] toBytes(XSSFWorkbook wb) throws Exception {
        applyTwoDecimalFormat(wb);
        try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {