fix(汇总大表): 扩列表头行改按基准月份列判定并清理9月母版被写入日期的13格(待验收)
3个文件已修改
49 ■■■■■ 已修改文件
HANDOFF.md 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/生成汇总大表/2026年9月道路运输量汇总表.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/layout/SummaryLayoutExpander.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HANDOFF.md
@@ -4,6 +4,14 @@
> **每天结束时**:把当天进展、踩过的坑、新需求、未完成事项更新到本文件,然后可以放心开新对话。
> **协作约定(2026-08-31)**:说「提交」= æœ¬åœ° commit + æŽ¨é€åˆ°è¿œç«¯ git(origin main,Gitblit),不再只做本地 commit。
### 10-12(11):扩列表头行二次修正 + 9 æœˆæ¯ç‰ˆè¢«æ‰©åˆ—写成日期的 13 æ ¼æ¸…理【待验收】
- **现象(用户报告)**:生成表里"很多数据是 8 æœˆçš„"。排查发现 **9 æœˆæ¯ç‰ˆé‡Œæœ‰ 13 ä¸ªæ•°æ®æ ¼è¢«å†™æˆäº† 9 æœˆæœˆä»½æ—¥æœŸåºåˆ— `46266`(= 2026-09-01)**:` è´§è¿!S11/T11`、`班线包车!S9/T9`、`公交!S8/T8`、`出租!S6/T6`、`中口径明细!S5/T5`;下游缓存被带偏(`班线包车!S5`、`中口径明细!S99/S100/S104/S105` ç­‰ä¹Ÿæ˜¯ 46266)。
- **根因**:扩列器 `headerRowsOf` é¦–版只要求"整行 â‰¥2 ä¸ªæœˆä»½æ ¼",而出租第 6 è¡Œã€ç­çº¿åŒ…车第 3 è¡Œè¿™ç±»**数据行**里恰好有 2 ä¸ªåƒæ—¥æœŸåºåˆ—的数值 â†’ è¢«è¯¯åˆ¤æˆè¡¨å¤´è¡Œ â†’ æ‰©åˆ—时把"月份日期"写进了数据行(`cloneHeaderCell` å¯¹æ•°å€¼æ ¼å†™ `targetMonth` çš„æ—¥æœŸï¼‰ã€‚
- **修法**:改为**先取"月份表头格最多的那一行"作基准,把它的月份列当标准列**;只有这些列上大半是月份格的行才算表头行。轨道、轮渡一页两个块的 `[1,10]` ä¿æŒ âœ“ï¼›` è´§è¿/公交/网约车/中口径明细` ä»ä¸ºå•行表头 âœ“。
- **母版修复(用 Excel COM,未整本重写)**:13 æ ¼æŒ‰æ‰©åˆ—规则精修(该留空的清空、公式按规则补回 `=S12+S13` / `=S11/AN11-1` / `=S10+S14+…`)+ `CalculateFull` æ•´æœ¬é‡ç®—刷新缓存;修复前备份 `_bak_2026å¹´9月母版_清理脏格前_20261012.xlsx`。修复后全簿只剩 3 ä¸ª `46266` çš„**合法表头月份格**(城市客运 S2、公交 S3、出租 S3)。
- **验证**:重跑 2026-08→9 æœˆæ‰©åˆ—(日志表头行 ` è´§è¿[2] ç­çº¿åŒ…车[1] åŸŽå¸‚客运[1] å…¬äº¤[2] å‡ºç§Ÿ[2] ç½‘约车[2] è½¨é“、轮渡[1,10] ä¸­å£å¾„明细[2]`),新推件在这 13 æ ¼ä¸Šå…¨éƒ¨æ­£ç¡®ï¼›é‡è·‘ 2026-09 ç”Ÿæˆï¼Œäº§ç‰© `docs\生成汇总大表\输出\生成_道路运输量汇总表_2026-09.xlsx` ä¸­ 13 æ ¼æ¢å¤ä¸ºçœŸå®ž 9 æœˆå€¼ï¼ˆ`班线包车!S9=20647.5363`、`公交!S8=61618.09`、`出租!S6=32787.72`),**无 46266 æ®‹ç•™**。
- **报告(本地、不入库)**:`docs/功能测试报告/功能测试报告_扩列表头行基准列修正与母版脏格清理_2026-10-12.md`。状态:**【待验收】**。
### 10-12(3):修「9 æœˆäº§ç‰©ä¸¢ 8 æœˆåˆ— / ç´¯è®¡æ¼æœˆã€â€”—扩列改为**以当期产物为底**【待验收】
- **现象(用户报告)**:生成的 9 æœˆæ±‡æ€»å¤§è¡¨é‡Œ **8 æœˆåˆ—全空**,累计漏掉 8 æœˆï¼ˆè§„上货运量累计显示 31309.58,正确应为 1-7月 27734.46 + 8月 3665.36 + 9月 3575.12 = **34974.95**)。
docs/Éú³É»ã×Ü´ó±í/2026Äê9ÔµÀ·ÔËÊäÁ¿»ã×ܱí.xlsx
Binary files differ
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/layout/SummaryLayoutExpander.java
@@ -264,23 +264,48 @@
        return insertCol;
    }
    /** è¡¨å¤´è¡Œï¼ˆ0 åŸºï¼‰ï¼šå«ã€Œå¹´+月」表头单元格的行;轨道、轮渡有两个块 â†’ ä¸¤è¡Œã€‚ */
    /**
     * è¡¨å¤´è¡Œï¼ˆ0 åŸºï¼‰ï¼šè½¨é“、轮渡这类一页两个块的有两行。
     *
     * <p>2026-10-12 äºŒæ¬¡ä¿®æ­£ï¼šå…ˆå–「月份表头格最多的那一行」作基准,把它的月份列当作标准列,
     * åªæœ‰è¿™äº›åˆ—上大半是月份格的行才算表头行。前版只要求「整行 â‰¥2 ä¸ªæœˆä»½æ ¼ã€ï¼Œ
     * ä¼šæŠŠæ•°æ®è¡Œé‡Œæ°å¥½è½æˆæ—¥æœŸåºåˆ—的数值当成表头 â†’ æ‰©åˆ—时把月份日期写进数据行
     * ï¼ˆ2026-09 æ¯ç‰ˆ ` è´§è¿!S11`、`出租!S6` ç­‰ 13 æ ¼è¢«å†™æˆ 46266)。
     */
    private List<Integer> headerRowsOf(Sheet sh) {
        List<Integer> rows = new ArrayList<>();
        int lastRow = Math.min(sh.getLastRowNum(), sh.getFirstRowNum() + HEADER_SCAN_ROWS);
        for (int r = sh.getFirstRowNum(); r <= lastRow; r++) {
        int first = sh.getFirstRowNum();
        int lastRow = Math.min(sh.getLastRowNum(), first + HEADER_SCAN_ROWS);
        List<Integer> base = new ArrayList<>();
        for (int r = first; r <= lastRow; r++) {
            Row row = sh.getRow(r);
            if (row == null) continue;
            for (int c = row.getFirstCellNum(); c >= 0 && c < row.getLastCellNum(); c++) {
                if (yearMonthOf(row.getCell(c)) != null) {
                    rows.add(r);
                    break;
            List<Integer> cols = monthColsOf(row);
            if (cols.size() > base.size()) base = cols;
                }
        List<Integer> rows = new ArrayList<>();
        if (base.size() < 2) return rows;
        int need = Math.max(2, (base.size() + 1) / 2);
        for (int r = first; r <= lastRow; r++) {
            Row row = sh.getRow(r);
            if (row == null) continue;
            int hit = 0;
            for (int c : base) {
                if (yearMonthOf(row.getCell(c)) != null) hit++;
            }
            if (hit >= need) rows.add(r);
        }
        return rows;
    }
    /** è¡Œå†…所有「年+月」表头格的列号(0 åŸºï¼‰ */
    private List<Integer> monthColsOf(Row row) {
        List<Integer> cols = new ArrayList<>();
        for (int c = row.getFirstCellNum(); c >= 0 && c < row.getLastCellNum(); c++) {
            if (yearMonthOf(row.getCell(c)) != null) cols.add(c);
        }
        return cols;
    }
    private Map<Integer, Integer> monthCols(Sheet sh, int year) {
        Map<Integer, Integer> cols = new LinkedHashMap<>();
        int lastRow = Math.min(sh.getLastRowNum(), sh.getFirstRowNum() + HEADER_SCAN_ROWS);