fix(汇总大表): 扩列器整本重算写缓存(修公式无缓存导致的取数差异)待验收
2个文件已修改
21 ■■■■■ 已修改文件
HANDOFF.md 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/layout/SummaryLayoutExpander.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HANDOFF.md
@@ -64,6 +64,13 @@
- **一处需用户拍板的数值变化**:本次生成件 `中口径排名` 有 **46 格**(同比/排名,如 `D3` 0.0581→**0.0402**、`E4` 第10→第**9**)与上一版不同;**新值与《中口径分析》页逐位一致**(`B3=35028.0636`、`C3=0.04015856`)——即排名页与明细/分析页口径统一(原旧值是该页在母版里的旧缓存)。**保留新值 / 回退旧值待用户确认**。
- **归档说明**:`归档/` 内 5 件历史母版/版式件仍可随时取回(未删除);母版目录以后只放"当期一本"。
- **状态**:**【待验收】**。
### 10-12(9):扩列器加「整本重算写缓存」+ 明确保留中口径排名新值【待验收】
- **问题定位(用户问"为什么产生这 46 格差异")**:母版里**大量公式只有公式、没有缓存值**(POI 写公式不带缓存)。实证:母版经 Excel 保存前后 **约 2.47 万格**由"空"变"有值"(如 ` 货运!U5: 空→130311.8927`)。`中口径排名` 的同比/排名由程序**读母版缓存**计算(方案 A)→ 缓存空时算旧值 `0.0581`,缓存补齐后算 `0.0402`(**与《中口径分析》逐位一致**)。**新值才是数据完整时的正确结果**。
- **改动**:`SummaryLayoutExpander` 新增 `recalcAndCache(wb)`(`clearAllCachedResultValues()` + `evaluateAll()` 写回缓存,失败仅 WARN),在 `expand()` 与 `fixTitles()` 中调用。
- **验证**:扩列 2026-08 → 公式格 **39,961** 个,**空缓存仅 4 格**(全在 ` 货运`,POI 无法求解的外部引用,Excel 打开会算);修复前同类母版约 2.47 万格无缓存。
- **用户决定**:`中口径排名` 那 46 格**保留新值**(与中口径分析一致,口径统一)。
- **报告(本地、不入库)**:`docs/功能测试报告/功能测试报告_扩列整本重算写缓存_2026-10-12.md`。状态:**【待验收】**。
## 最新(2026-10-12,zyj 线)
### 10-12:扩列器补「标题按母版期次重写」+ 修正 8 月母版标题【待验收】
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/layout/SummaryLayoutExpander.java
@@ -3,6 +3,7 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
@@ -80,6 +81,7 @@
                if (sh == null || expanded.contains(sh.getSheetName())) continue;
                shiftQualifiedRefs(sh, insertColOf);
            }
            recalcAndCache(wb);
            int titleFixed = applyTitles(wb, year, targetMonth);
            if (titleFixed > 0) {
                log.info("扩列:标题按 {}年{}月 重写 {} 格", year, targetMonth, titleFixed);
@@ -96,6 +98,7 @@
    /** 只把 7 个标题页的标题按给定期次重写(用于修正母版里滞后的标题)。 */
    public byte[] fixTitles(byte[] source, int year, int month) {
        try (XSSFWorkbook wb = new XSSFWorkbook(new ByteArrayInputStream(source))) {
            recalcAndCache(wb);
            int n = applyTitles(wb, year, month);
            wb.setForceFormulaRecalculation(true);
            ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -107,6 +110,17 @@
        }
    }
    /** 整本重算并把结果写入缓存值:否则母版里只有公式没有值,后续读取会把空值当 0(2026-10-12 修) */
    private void recalcAndCache(XSSFWorkbook wb) {
        try {
            FormulaEvaluator ev = wb.getCreationHelper().createFormulaEvaluator();
            ev.clearAllCachedResultValues();
            ev.evaluateAll();
        } catch (Exception e) {
            log.warn("扩列:整本重算未完成(公式仍在,Excel 打开会再算):{}", e.getMessage());
        }
    }
    /** 把 7 个页签的标题文字按「累计=1-M月、当月=M月」重写;命中标记才改,避免误伤备注。 */
    private int applyTitles(XSSFWorkbook wb, int year, int month) {
        int changed = 0;