traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java
@@ -2223,15 +2223,10 @@
                    if (blockOffset % 5 == 0) {
                        if (isYoy) {
                            fillMidYoyCell(c, mid, currentYear, monthOfCol(col), area, -1, volume);
                        } else if (monthOfCol(col) > 6) {
                            // 扩列出来的 7~12 月总行值列:模板里本无此列,克隆后既没有公式也没有缓存值,
                            // 直接写库内四维合计(维度0)。1~6 月保留模板缓存值,避免丢掉模板里的定稿数。
                            double total = midClassVal(mid, currentYear, monthOfCol(col), area, 0, volume);
                            c.setBlank();
                            if (total != 0.0) c.setCellValue(round(total, 4));
                        } else if (c.getCellType() == CellType.FORMULA) {
                            keepCached(c); // 1~6 月总行值列 = 模板缓存值,保留
                        }
                        // 总行值列:一律保留模板公式(1~6 月原公式 + 扩列克隆出来的公式),
                        // 由生成收尾的 recalcWorkbookFormulas 求值写回缓存。早期版本这里 keepCached
                        // 会把刚克隆出来的公式清成空格,导致 7 月及以后总行永远空白。
                        continue;
                    }
                    int k = blockOffset % 5; // 1=班线 2=公交 3=出租城乡 4=网约车城乡
@@ -2249,7 +2244,27 @@
            int[] recalc = recalcWorkbookFormulas(wb);
            log.info("中口径明细公式重算完成:成功 {} 格,失败 {} 格", recalc[0], recalc[1]);
            clearFormulaErrorsAll(wb); // 去年同期明细页残留 #REF! 同比公式 → 清空
            blankFutureMonthColumns(sheet, fillMonths); // 报表期之后的月份列不保留克隆公式/0 值
            return toBytes(wb);
        }
    }
    /**
     * 清空「报表期之后」的月份列(扩列克隆出来的 7~12 月里、尚未到期的月份)。
     * 不清的话,克隆出来的总行公式会算出 0,报表上会出现"9~12 月全是 0"的假数据;
     * 累计列(AA)的公式/缓存值已在重算阶段算好,清空格子不影响它(空 = 0)。
     */
    private void blankFutureMonthColumns(Sheet sheet, int filledMonths) {
        for (int m = filledMonths + 1; m <= 12; m++) {
            int col = 2 * m;            // 0 基:1 月=2(C)、7 月=14(O)、12 月=24(Y)
            for (int r = 4; r <= sheet.getLastRowNum(); r++) { // 0 基第 4 行 = 第 5 行(首个数据行),表头不动
                Row row = sheet.getRow(r);
                if (row == null) continue;
                Cell val = row.getCell(col);
                if (val != null) val.setBlank();
                Cell yoy = row.getCell(col + 1);
                if (yoy != null) yoy.setBlank();
            }
        }
    }
@@ -2274,12 +2289,19 @@
        return (col - 1) / 2;
    }
    /** 填中口径数据单元格:班线/公交/出租城乡/网约车城乡 四维统一取库内值(无值清空) */
    /**
     * 填中口径数据单元格:班线/公交/出租城乡/网约车城乡 四维统一取库内值。
     * 库内该月该维无源(取值为 0)时**保留母版/模板原值**——绝不写空、也不写 0。
     * 依据:模板的城市级城乡行是「台账页 总量 − 城市内」的引用、并已业务定稿;
     * 用库内缺失值覆盖会把定稿数清掉(如 2026-01~06 网约车订单缺失时,
     * 全省网约车城乡 333.39 与各市州值会被清空)。
     */
    private void fillMidCell(Cell c, Map<Integer, Map<String, double[][]>> mid, int year, int month, String area, int k, boolean volume) {
        double v = midClassVal(mid, year, month, area, k, volume);
        if (v == 0.0) return; // 库内无源:保留母版/定稿原值,缺数据不覆盖
        // POI setCellValue(double) 对公式单元格只更新缓存不移除公式,必须先 setBlank 再写值
        c.setBlank();
        if (v != 0.0) c.setCellValue(round(v, 4));
        c.setCellValue(round(v, 4));
    }
    /** 显式写入 0(POI setCellValue(0.0) 会转 blank,需操作底层 XML) */
@@ -3445,6 +3467,14 @@
            log.warn("汇总工作簿公式重算:创建求值器失败,跳过({})", e.getMessage());
            return new int[]{0, 0};
        }
        try {
            // 跨簿公式([1]出租!C13 之类)在外部工作簿缺失时默认抛异常,会让引用它的
            // 总行/累计/派生公式连锁失败(表现为「公式还在但没有缓存值」)。
            // 置 true 后改用公式格自身的缓存值(即定稿值)参与计算。
            ev.setIgnoreMissingWorkbooks(true);
        } catch (Exception ignore) {
            // 个别实现不支持该开关,忽略即可
        }
        int ok = 0, fail = 0;
        java.util.List<String> samples = new java.util.ArrayList<>();
        for (int i = 0; i < wb.getNumberOfSheets(); i++) {