fix(汇总大表): 扩列公式克隆修正(值列相对右移、同比列重写)并落盘 9 月母版 待验收
1个文件已添加
2个文件已修改
50 ■■■■■ 已修改文件
HANDOFF.md 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/生成汇总大表/2026年9月道路运输量汇总表.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/layout/SummaryLayoutExpander.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HANDOFF.md
@@ -17,6 +17,18 @@
- **口径结论(写进设计)**:**新母版一律从"当期产物"派生**(产物带当期数据与公式),不再从旧母版派生——否则每月都会丢"当期列",累计逐月漏数。
- **遗留**:① å¾…用户确认是否把 v3 è½ç›˜ä¸ºæ­£å¼ 9 æœˆæ¯ç‰ˆï¼ˆä¼šå…ˆå¤‡ä»½æ‰‹å·¥ç‰ˆï¼‰ï¼›â‘¡ æ‰©åˆ—产物中被重写的公式暂无缓存值(只写公式 + `fullCalcOnLoad`,Excel/WPS æ‰“开自动算)——建议补"整本重算写缓存";③ `中口径明细` è¡¨å¤´è¡Œè¯†åˆ«è¿”回 `[2,4]`,需核查。
- **报告(本地、不入库)**:`docs/功能测试报告/功能测试报告_扩列以当期产物为底_2026-10-12.md`。状态:**【待验收】**。
### 10-12(4):扩列公式克隆两处修正 + 9 æœˆæ¯ç‰ˆè½ç›˜ + ç«¯åˆ°ç«¯éªŒè¯é€šè¿‡ã€å¾…验收】
- **修前问题(同一批次的三个)**:① å…‹éš†"当月值列"时公式未相对右移(新列写成 `=Q7+Q9`,应 `=S7+S9`)→ å…¨çœè¡Œå–到上月数;② å…‹éš†"当月同比列"时分子指向旧月份(`=Q5/AN5-1`,应 `=S5/AN5-1`)→ ç®—的是"上月值÷去年同月";③ POI `setCellFormula` **不接受前导 `=`** â†’ æŽ¥å£ 500(`FormulaParseException`,§6.3 åŽ†å²å‘ï¼‰ã€‚
- **修法**:新增 `shiftRefsAll`(克隆时对"本页/已扩列页"引用**无条件 +2**,相对复制)与 `cloneYoyCell`(不克隆,直接写 `本月值/表中定位的去年同月-1`,即 C3 å£å¾„);公式串去掉前导 `=`。
- **9 æœˆæ¯ç‰ˆè½ç›˜ï¼ˆç”¨æˆ·å·²ç¡®è®¤ï¼‰**:手工版备份为 `_bak_2026å¹´9月母版_手工版_20261012.xlsx`;新母版 = "8 æœˆäº§ç‰© â†’ æ‰©åˆ—",1,083,567 B;输出目录命名理顺(最新件 `_扩列_2026å¹´9月_待确认.xlsx`,旧版加 `_bak_` å‰ç¼€ï¼‰ã€‚
- **端到端验证(用新母版生成 2026-09)**:
  - è´§è¿ 8 æœˆåˆ—有值:全口径 **16888.7615**、规上 **3665.3638**、规下 **13223.3977**;
  - 9 æœˆåˆ—:全口径 3575.1211(②表未导,只有①规上)、规上 3575.1211;
  - **累计:全口径 133887.0138(=1-8月 130311.89 + 9月 3575.12)、规上 34974.9459(=27734.46+3665.36+3575.12)、规下 98912.0679** âœ“ ä¸Žæ‰‹ç®—一致;
  - å…¬äº¤ï¼š8 æœˆ 12315.37、累计 110776.34 âœ“。
- **遗留**:① æ‰©åˆ—产物被重写的公式无缓存值(建议补"整本重算写缓存");② `中口径明细` è¡¨å¤´è¡Œè¯†åˆ«è¿”回 `[2,4]` å¾…核查;③ â‘¡è¡¨ï¼ˆå…¨å£å¾„)9 æœˆæœªå¯¼å…¥å‰ï¼Œ"全口径"行显示等于规上(公式 =规上+规下、规下为空),体检已提示,导数据后自动正常。
- **报告(本地、不入库)**:`docs/功能测试报告/功能测试报告_扩列公式克隆修正与9月验证_2026-10-12.md`。状态:**【待验收】**。
## æœ€æ–°ï¼ˆ2026-10-12,zyj çº¿ï¼‰
### 10-12:扩列器补「标题按母版期次重写」+ ä¿®æ­£ 8 æœˆæ¯ç‰ˆæ ‡é¢˜ã€å¾…验收】
docs/Éú³É»ã×Ü´ó±í/2026Äê9ÔµÀ·ÔËÊäÁ¿»ã×ܱí.xlsx
Binary files differ
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/layout/SummaryLayoutExpander.java
@@ -208,8 +208,8 @@
            if (headerRows.contains(r)) continue;
            Row row = sh.getRow(r);
            if (row == null) continue;
            cloneDataCell(row, srcVal, insertCol, shiftable, insertCol);
            cloneDataCell(row, srcYoy, insertCol + 1, shiftable, insertCol);
            cloneDataCell(row, srcVal, insertCol, shiftable);
            cloneYoyCell(row, srcYoy, insertCol + 1, insertCol, lastYearSameMonth + 2);
        }
        // 5) ç´¯è®¡åˆ—补当月项;累计同比分母补去年同月列
        int cumCol = insertCol + 2, cumYoyCol = insertCol + 3;
@@ -348,17 +348,47 @@
        }
    }
    private void cloneDataCell(Row row, int srcCol, int dstCol, Set<String> shiftable, int insertCol) {
    private void cloneDataCell(Row row, int srcCol, int dstCol, Set<String> shiftable) {
        Cell s = row.getCell(srcCol);
        if (s == null) return;
        Cell d = getOrCreate(row, dstCol);
        d.setBlank();
        d.setCellStyle(s.getCellStyle());
        if (s.getCellType() == CellType.FORMULA) {
            d.setCellFormula(shiftRefs(s.getCellFormula(), insertCol, shiftable));
            d.setCellFormula(shiftRefsAll(s.getCellFormula(), shiftable));
        }
    }
    /** å½“月同比列:不克隆上月公式,直接按「本月值 / åŽ»å¹´åŒæœˆ âˆ’ 1」重写(去年同月列已按表头定位) */
    private void cloneYoyCell(Row row, int srcCol, int dstCol, int valCol0, int denCol0) {
        Cell s = row.getCell(srcCol);
        if (s == null) return;
        Cell d = getOrCreate(row, dstCol);
        d.setBlank();
        d.setCellStyle(s.getCellStyle());
        if (s.getCellType() == CellType.FORMULA) {
            int excelRow = row.getRowNum() + 1;
            d.setCellFormula(colLetter(valCol0) + excelRow + "/" + colLetter(denCol0) + excelRow + "-1");
        }
    }
    /** ç›¸å¯¹å¤åˆ¶ç”¨çš„平移:把本页/已扩列页的引用整体 +2(不做列号阈值判断) */
    private String shiftRefsAll(String formula, Set<String> shiftable) {
        Matcher m = REF.matcher(formula);
        StringBuffer sb = new StringBuffer();
        while (m.find()) {
            String sheet = m.group(2) != null ? m.group(2) : m.group(3);
            if ((sheet != null && !shiftable.contains(sheet)) || isFunctionName(formula, m)) {
                m.appendReplacement(sb, Matcher.quoteReplacement(m.group(0)));
                continue;
            }
            int colIdx = colIndex(m.group(5));
            m.appendReplacement(sb, Matcher.quoteReplacement(rebuild(m, sheet, colIdx + 2)));
        }
        m.appendTail(sb);
        return sb.toString();
    }
    private void shiftAllRefs(Sheet sh, int insertCol, Set<String> shiftable) {
        for (int r = 0; r <= sh.getLastRowNum(); r++) {
            Row row = sh.getRow(r);