traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java
@@ -35,6 +35,7 @@
import com.trafficaudit.reportexport.calc.PaxCalc;
import com.trafficaudit.reportexport.calc.SummaryWorkbookFiller;
import com.trafficaudit.reportexport.calc.FreightReadinessCheck;
import com.trafficaudit.reportexport.calc.SummaryMissingDataCheck;
import com.trafficaudit.reportexport.layout.SummaryLayoutExpander;
import com.trafficaudit.reportexport.calc.WycSplitCalc;
import lombok.extern.slf4j.Slf4j;
@@ -107,6 +108,8 @@
    private SummaryLayoutExpander summaryLayoutExpander;
    @Resource
    private FreightReadinessCheck freightReadinessCheck;
    @Resource
    private SummaryMissingDataCheck missingDataCheck;
    @Resource
    private WycSplitCalc wycSplitCalc;
    @Resource
@@ -3641,14 +3644,54 @@
        if (month >= 12) {
            throw new RuntimeException("扩列:12 月之后需新开一本,跨年规则另行处理");
        }
        File mother = resolveSummaryMother(period, "month");
        if (mother == null) {
            throw new RuntimeException("未找到汇总表母版(docs/生成汇总大表):" + year + "年" + month + "月道路运输量汇总表.xlsx");
        // 2026-10-12:扩列以「当期产物」为底(产物含当期列的值与公式;母版的当期列是空的,
        // 直接拿母版扩列会把当期数据丢成空洞,导致累计漏月)。产物取自导出落盘缓存;缺产物时回退母版并告警。
        File source = resolveLatestProduct(period);
        boolean fromProduct = source != null;
        if (source == null) {
            source = resolveSummaryMother(period, "month");
            if (source != null) {
                log.warn("汇总大表扩列:未找到 {} 的产物缓存,回退用母版扩列——历史列里缺少当期数据,累计可能漏月", period);
        }
        try (InputStream in = new FileInputStream(mother)) {
        }
        if (source == null) {
            throw new RuntimeException("未找到汇总表母版或产物(docs/生成汇总大表):" + year + "年" + month + "月道路运输量汇总表.xlsx");
        }
        try (InputStream in = new FileInputStream(source)) {
            byte[] out = summaryLayoutExpander.expand(org.apache.poi.util.IOUtils.toByteArray(in), year, month + 1);
            log.info("汇总大表扩列完成:{}年{}月母版 -> {}年{}月版式(只做版式、数据留空)", year, month, year, month + 1);
            log.info("汇总大表扩列完成:{}{} -> {}年{}月版式(只做版式、当期列留空)",
                    fromProduct ? "产物" : "母版", source.getName(), year, month + 1);
            return out;
        }
    }
    /** 取该期「最新产物」:导出落盘缓存 _cache/summaryWorkbook_<period>_month_v*.xlsx(按修改时间取最新) */
    private File resolveLatestProduct(String period) {
        try {
            String rel = summaryTemplateDir;
            while (rel != null && rel.startsWith("./")) rel = rel.substring(2);
            String[] roots = {
                summaryTemplateDir,
                System.getProperty("user.dir") + "/" + rel,
                System.getProperty("user.dir") + "/../" + rel
            };
            String prefix = "summaryWorkbook_" + period + "_month_";
            for (String root : roots) {
                if (root == null || root.trim().isEmpty()) continue;
                File dir = new File(root, "_cache");
                if (!dir.isDirectory()) continue;
                File[] files = dir.listFiles((d, name) -> name.startsWith(prefix) && name.endsWith(".xlsx"));
                if (files == null || files.length == 0) continue;
                File latest = files[0];
                for (File f : files) {
                    if (f.lastModified() > latest.lastModified()) latest = f;
                }
                return latest;
            }
            return null;
        } catch (Exception e) {
            log.warn("汇总大表扩列:查找产物缓存失败(忽略):{}", e.getMessage());
            return null;
        }
    }
@@ -3711,6 +3754,7 @@
            List<String> dbProblems = new ArrayList<>();
            String effPeriod = String.format("%04d-%02d", year, effMonth);
            dbProblems.addAll(freightReadinessCheck.check(effPeriod));   // B4:货运口径导出前体检(6 条规则)
            dbProblems.addAll(missingDataCheck.check(effPeriod));        // 缺数清单(该有的数没有)
            reportProgress(progress, 22, "回填当月数据");
            int dbFilled = summaryWorkbookFiller.fillMonthlyLedger(wb, effPeriod, year, effMonth, dbProblems);
            int yoyFilled = summaryWorkbookFiller.ensureMonthYoyFormulas(wb, year, effMonth);