From 259db33b22095891f436b9ed5a81a21496b11c4c Mon Sep 17 00:00:00 2001
From: zhizhijie <zhizhijie@users.noreply.gitee.com>
Date: 星期一, 12 十月 2026 23:41:55 +0800
Subject: [PATCH] feat(汇总大表): 缺数清单加导出前弹窗并在生成件附《数据缺失清单》页(待验收)

---
 HANDOFF.md                                                                                        |   16 ++++
 traffic-audit-web/src/views/ReportExport.vue                                                      |   56 +++++++++++++
 traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java |  105 ++++++++++++++++++++++++++
 traffic-audit-server/src/main/java/com/trafficaudit/reportexport/calc/FreightReadinessCheck.java  |   14 ++-
 4 files changed, 186 insertions(+), 5 deletions(-)

diff --git a/HANDOFF.md b/HANDOFF.md
index 987bbda..0de4f3c 100644
--- a/HANDOFF.md
+++ b/HANDOFF.md
@@ -4,6 +4,22 @@
 > **姣忓ぉ缁撴潫鏃�**锛氭妸褰撳ぉ杩涘睍銆佽俯杩囩殑鍧戙�佹柊闇�姹傘�佹湭瀹屾垚浜嬮」鏇存柊鍒版湰鏂囦欢锛岀劧鍚庡彲浠ユ斁蹇冨紑鏂板璇濄��
 > **鍗忎綔绾﹀畾锛�2026-08-31锛�**锛氳銆屾彁浜ゃ��= 鏈湴 commit + 鎺ㄩ�佸埌杩滅 git锛坥rigin main锛孏itblit锛夛紝涓嶅啀鍙仛鏈湴 commit銆�
 
+### 10-12锛�14锛夛細姹囨�诲ぇ琛ㄣ�岀己鏁版竻鍗曞脊绐� + 鐢熸垚浠躲�婃暟鎹己澶辨竻鍗曘�嬮〉銆�+ 浣撴鍋囬槼鎬т慨澶� + 鍏氦 9鏈堢己琛屾牳鏌ャ�愬緟楠屾敹銆�
+
+- **鍔ㄥ洜**锛氱敤鎴疯姹傛妸缂烘暟鎽嗗埌鍙伴潰涓婏紙P0-3 鍓╀綑锛夛紝骞跺湪鐢熸垚浠堕噷缁欎竴椤点�婃暟鎹己澶辨竻鍗曘�嬨��
+- **鏀瑰姩锛�3 澶勶級**锛�
+  1. 鍚庣 `ReportExportService.appendMissingDataSheet(...)`锛氱敓鎴愭敹灏惧湪浜х墿鏈熬杩藉姞銆婃暟鎹己澶辨竻鍗曘�嬮〉锛堢 20 椤碉級锛屽垎銆屼竴銆佺己鏁版竻鍗� / 浜屻�佹暟鎹綋妫� / 涓夈�佸叾瀹冩彁绀恒�嶏紝鍐欐姤琛ㄦ湡+鐢熸垚鏃堕棿+鏉℃暟锛涘彧璇绘彁绀洪〉銆佷笉鍙備笌璁$畻锛涙瘝鐗堣嫢鐢变骇鐗╂淳鐢熷凡甯﹀悓鍚嶉〉浼氬厛绉婚櫎鍐嶅缓銆�
+  2. 鍓嶇 `ReportExport.vue`锛氱偣銆屽鍑�/鐢熸垚銆嶅厛璋� `GET /api/report/summaryWorkbook/missing` + `freightCheck`锛屽懡涓垯寮圭獥锛堝垎涓ゆ銆佸彲婊氬姩锛夈�屼粛瑕佺敓鎴� / 鍙栨秷銆嶏紱涓ら」鐨嗙┖銆佹帴鍙e紓甯告垨骞存姤妯″紡 鈫� 鐩存帴鐢熸垚銆�
+  3. `FreightReadinessCheck` 淇亣闃虫�э細鈶″叏鍙e緞鏁存湡鏈鏃朵笉鍐嶆寜 `0鈭掕涓奰 鎶ャ�岃涓嬩负璐熴�嶏紙涓婇潰宸叉姤銆岀己鈶″叏鍙e緞銆嶏級鈫� 2026-09 鍛戒腑 68鈫�34锛�2026-08 浠� 0銆�
+- **瀹炴祴锛坉ev 8090/8080锛屼粎鐢熸垚/鍙锛�**锛歮issing(2026-09)=4 鏉★紙璐ц繍鈶♀憿銆佺綉绾﹁溅璁㈠崟銆佺綉绾﹁溅 pin锛夛紱freightCheck(2026-09)=34銆�2026-08=0锛涘紓姝ョ敓鎴� 2026-09锛坮efresh=true锛夆啋 1,303,490 B / 20 椤� / 娓呭崟 39 鏉★紙4+34+1锛夛紝钀界洏缂撳瓨鍚屾鍒锋柊涓� `_cache/summaryWorkbook_2026-09_month__vc0e2afa47b51bc04.xlsx`锛涘墠绔� `Compiled successfully`銆乥undle `/js/6.js` 宸插惈鏂颁唬鐮侊紱骞存姤妯″紡涓ゆ帴鍙h繑鍥炵┖銆�
+- **鎶ュ憡锛堟湰鍦般�佷笉鍏ュ簱锛�**锛歚docs/鍔熻兘娴嬭瘯鎶ュ憡/鍔熻兘娴嬭瘯鎶ュ憡_姹囨�诲ぇ琛ㄧ己鏁版竻鍗曞脊绐椾笌鐢熸垚浠堕〉_2026-10-12.md`銆傜姸鎬侊細**銆愬緟楠屾敹銆�**銆�
+- **銆愬緟楠屾敹 / 寰呭畾澶� / 寰呭鐞嗐�戜笁椤�**锛�
+  1. 銆愬緟楠屾敹銆戝鍑哄墠寮圭獥 + 鐢熸垚浠躲�婃暟鎹己澶辨竻鍗曘�嬮〉锛堜骇鐗� `docs/鐢熸垚姹囨�诲ぇ琛�/杈撳嚭/鐢熸垚_閬撹矾杩愯緭閲忔眹鎬昏〃_2026-09.xlsx` 鏈〉锛夛紱
+  2. 銆愬緟鐢ㄦ埛瀹氬ず銆戞帓鍚嶉〉缂烘暟鏈熺暀绌猴細鏁板�煎垪鐣欑┖绗﹀悎棰勬湡锛屼絾銆婅揣杩愬懆杞噺鎺掑悕銆媊R` 鍒椾粛鏄剧ず **10.00**锛堟瘝鐗� `=10-Q` 鍦� `Q` 娓呯┖鍚庣畻鍑猴紱婧愪晶绌鸿〃鏃犳鍏紡锛夛紝鏄惁涓�骞舵竻绌烘湰娆�**鏈敼**锛�
+  3. 銆愬緟澶勭悊銆戝叕浜� 2026-09 灏� 1 琛屽睘**婧愭枃浠剁己琛�**鈥斺�擿闅忓窞甯偮�42138100005路骞挎按甯傚畨椤哄叕浜ゆ湁闄愬叕鍙竊 鍦� 6/7 鏈堟簮琛ㄧ 119 琛屽瓨鍦ㄣ��9 鏈堟簮琛ㄦ病鏈夛紙`import_batch#551` 璁板綍 141/141/0锛岄潪瀵煎叆璺宠繃锛夆啋 闇�鍚戞暟鎹潵婧愯ˉ浠舵垨纭浼佷笟鍋滄姤锛�**鏈鍏ヤ换浣曟暟鎹�**銆�
+- **椤哄甫澶嶆牳**锛�09 鏈堟瘝鐗� 9 鏈堝垪鏁板�兼棤璇紙`鐝嚎鍖呰溅!S9=20647.5363`銆乣鍏氦!S8=61618.09`銆乣鍑虹!S6=32787.72`銆乣涓彛寰勬槑缁�!S5=3517.9161`锛涘叏绨� `46266` 鍙墿 3 涓悎娉曡〃澶磋锛夈��
+- **鐜鎻愮ず**锛氭湰鏈烘畫鐣� 1 涓棤绐楀彛 `EXCEL.EXE`锛圥ID 23540锛宍taskkill` 鎷掔粷璁块棶锛夛紱宸茬‘璁�**姣嶇増鏈閿�**锛堣鍐欐祴璇曢�氳繃锛夛紝涓嬫鐢� Excel COM 鍓嶅厛澶嶆煡璇ヨ繘绋嬨��
+
 ### 10-12锛�13锛夛細涓嬬彮鍏虫満浜ゆ帴 鈥� 姹囨�诲ぇ琛ㄧ己鏁�/姣嶇増鑴忔牸淇宸叉彁浜ゆ帹閫侊紝涓嬩竴姝ュ緟鍔炰笌鏂颁細璇濊捣姝�
 
 **鎺ユ墜鍏ュ彛锛堟柊浼氳瘽鍏堣杩欎笁澶勶級**锛氣憼 鏍圭洰褰� `AGENTS.md`锛涒憽 鏈枃浠堕《閮紙鏈妭 + 10-12锛�11锛夛紙12锛夛級锛涒憿 涓婁竴浼氳瘽鏍囬銆�10.8鏃ユ瘮瀵规眹鎬诲ぇ琛ㄥ拰涓撻」缁熻鐨勭敓鎴愰�昏緫銆嶏紙鍥犱笂涓嬫枃瓒呴檺鎶ラ敊涓柇锛屽叾宸ヤ綔宸茬敱鏈妭杩欐潯绾垮仛瀹屽苟琛ユ彁浜わ級銆�
diff --git a/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/calc/FreightReadinessCheck.java b/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/calc/FreightReadinessCheck.java
index 20f01f5..11d4e2c 100644
--- a/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/calc/FreightReadinessCheck.java
+++ b/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/calc/FreightReadinessCheck.java
@@ -128,10 +128,16 @@
                 issues.add(String.format("璐ц繍浣撴锛�%s %s 缂衡憽鍏ㄥ彛寰勫懆杞噺锛堣涓� %.4f 鍦ㄣ�佸叏鍙e緞缂猴級鈫� 瑙勪笅鏃犳硶璁$畻",
                         period, city, abT));
             }
-            double belowF = (totalF == null ? 0 : totalF) - (abF == null ? 0 : abF);
-            double belowT = (totalT == null ? 0 : totalT) - (abT == null ? 0 : abT);
-            if (belowF < -TOL) issues.add(String.format("璐ц繍浣撴锛�%s %s 瑙勪笅璐ц繍閲忎负璐燂紙鍏ㄥ彛寰� %.4f 鈭� 瑙勪笂 %.4f = %.4f锛�", period, city, totalF, abF, belowF));
-            if (belowT < -TOL) issues.add(String.format("璐ц繍浣撴锛�%s %s 瑙勪笅鍛ㄨ浆閲忎负璐燂紙鍏ㄥ彛寰� %.4f 鈭� 瑙勪笂 %.4f = %.4f锛�", period, city, totalT, abT, belowT));
+            // 2026-10-12锛氣憽鍏ㄥ彛寰勭己锛堟湭瀵硷級鏃朵笉鍐嶆姤銆岃涓嬩负璐熴�嶁�斺�斾笂闈㈠凡鍗曠嫭鎶ャ�岀己鈶″叏鍙e緞銆嶏紝
+            // 鑻ヨ繖閲屼粛鎸� 0 鈭� 瑙勪笂 绠楋紝浼氬姣忎釜甯傚窞澶氬埛涓�鏉″亣闃虫�э紙鍊间笉鏄礋銆佹槸缂猴級锛屾妸鐪熼棶棰樻饭娌°��
+            if (totalF != null) {
+                double belowF = totalF - (abF == null ? 0 : abF);
+                if (belowF < -TOL) issues.add(String.format("璐ц繍浣撴锛�%s %s 瑙勪笅璐ц繍閲忎负璐燂紙鍏ㄥ彛寰� %.4f 鈭� 瑙勪笂 %.4f = %.4f锛�", period, city, totalF, abF, belowF));
+            }
+            if (totalT != null) {
+                double belowT = totalT - (abT == null ? 0 : abT);
+                if (belowT < -TOL) issues.add(String.format("璐ц繍浣撴锛�%s %s 瑙勪笅鍛ㄨ浆閲忎负璐燂紙鍏ㄥ彛寰� %.4f 鈭� 瑙勪笂 %.4f = %.4f锛�", period, city, totalT, abT, belowT));
+            }
             if (totalF != null && abF == null) issues.add(String.format("璐ц繍浣撴锛�%s %s 鏈夊叏鍙e緞浣嗘棤瑙勪笂璁板綍 鈫� 瑙勪笅绛変簬鍏ㄥ彛寰勶紙%.4f锛夛紝鐤戔憼婕忔姤", period, city, totalF));
             if (totalF != null && abF != null && totalF < abF) issues.add(String.format("璐ц繍浣撴锛�%s %s 鍏ㄥ彛寰� %.4f 灏忎簬瑙勪笂 %.4f", period, city, totalF, abF));
 
diff --git a/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java b/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java
index 59ceab0..358a446 100644
--- a/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java
+++ b/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java
@@ -42,8 +42,12 @@
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
 import org.apache.poi.ss.usermodel.FormulaEvaluator;
 import org.apache.poi.xssf.usermodel.XSSFSheet;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
@@ -3781,6 +3785,7 @@
             log.info("姹囨�诲伐浣滅翱鍏紡閲嶇畻瀹屾垚锛氭垚鍔� {} 鏍硷紝澶辫触 {} 鏍硷紙澶辫触鏍间繚鐣欐瘝鐗堟棫缂撳瓨鍊硷紝鎵撳紑鏃舵寜 fullCalcOnLoad 閲嶇畻锛�", recalc[0], recalc[1]);
             if (!wb.getCTWorkbook().isSetCalcPr()) wb.getCTWorkbook().addNewCalcPr();
             wb.getCTWorkbook().getCalcPr().setFullCalcOnLoad(true); // 杩樺師/鏀瑰啓鍏紡鍚庢墦寮�鍗抽噸绠�
+            appendMissingDataSheet(wb, effPeriod, dbProblems); // 2026-10-12锛氱己鏁�/浣撴缁撴灉鍐欒繘鐢熸垚浠讹紙鐢ㄦ埛瑕佹眰锛�
             reportProgress(progress, 95, "鍐欏嚭鏂囦欢");
             return toBytes(wb);
         } finally {
@@ -3788,6 +3793,106 @@
         }
     }
 
+    /**
+     * 鐢熸垚浠躲�婃暟鎹己澶辨竻鍗曘�嬮〉锛�2026-10-12锛岀敤鎴疯姹傦級銆�
+     *
+     * <p>鎶婃湰娆″鍑虹殑銆岀己鏁版竻鍗曘�嶄笌銆岃揣杩愬熀鏁颁綋妫�銆嶇粨鏋滄樉寮忓啓杩涗骇鐗╋細鐢ㄦ埛鎷垮埌鏂囦欢鍗冲彲鐪嬪埌鏈姤琛ㄦ湡
+     * 鏈夊摢浜涙暟娌″埌銆佸摢浜涙暟涓嶅悎鐞嗭紝涓嶅繀缈诲鍑烘棩蹇椼�傚彧璇绘彁绀洪〉锛屼笉鍙備笌鏈〃璁$畻銆�
+     */
+    private void appendMissingDataSheet(XSSFWorkbook wb, String period, List<String> problems) {
+        String sheetName = "鏁版嵁缂哄け娓呭崟";
+        int old = wb.getSheetIndex(sheetName);
+        if (old >= 0) wb.removeSheetAt(old); // 姣嶇増鐢便�屽綋鏈熶骇鐗┿�嶆淳鐢熸椂鍙兘宸插甫鏈〉锛屽厛绉婚櫎閬垮厤閲嶅悕
+        XSSFSheet sh = wb.createSheet(sheetName);
+
+        CellStyle titleStyle = wb.createCellStyle();
+        Font titleFont = wb.createFont();
+        titleFont.setBold(true);
+        titleFont.setFontHeightInPoints((short) 14);
+        titleStyle.setFont(titleFont);
+
+        CellStyle metaStyle = wb.createCellStyle();
+        Font metaFont = wb.createFont();
+        metaFont.setFontHeightInPoints((short) 10);
+        metaFont.setColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        metaStyle.setFont(metaFont);
+
+        CellStyle sectionStyle = wb.createCellStyle();
+        Font sectionFont = wb.createFont();
+        sectionFont.setBold(true);
+        sectionStyle.setFont(sectionFont);
+
+        CellStyle bodyStyle = wb.createCellStyle();
+        bodyStyle.setWrapText(true);
+        bodyStyle.setVerticalAlignment(VerticalAlignment.TOP);
+
+        List<String> missing = new ArrayList<>();
+        List<String> check = new ArrayList<>();
+        List<String> other = new ArrayList<>();
+        if (problems != null) {
+            for (String p : problems) {
+                if (p == null || p.trim().isEmpty()) continue;
+                if (p.startsWith("缂烘暟")) missing.add(p);
+                else if (p.startsWith("璐ц繍浣撴")) check.add(p);
+                else other.add(p);
+            }
+        }
+
+        int r = 0;
+        Row tRow = sh.createRow(r++);
+        Cell tCell = tRow.createCell(0);
+        tCell.setCellValue("鏁版嵁缂哄け娓呭崟");
+        tCell.setCellStyle(titleStyle);
+
+        Row mRow = sh.createRow(r++);
+        Cell mCell = mRow.createCell(0);
+        mCell.setCellValue("鎶ヨ〃鏈� " + period + "銆�鐢熸垚鏃堕棿 "
+            + new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm").format(new java.util.Date())
+            + "銆�鍏� " + (missing.size() + check.size() + other.size()) + " 鏉�");
+        mCell.setCellStyle(metaStyle);
+
+        Row nRow = sh.createRow(r++);
+        Cell nCell = nRow.createCell(0);
+        nCell.setCellValue("鏈〉鐢辩▼搴忚嚜鍔ㄧ敓鎴愶紙鍙鎻愮ず锛夛細涓�銆佺己鏁版竻鍗曪紳璇ユ湁鐨勬暟娌℃湁锛涗簩銆佹暟鎹綋妫�锛濇暟鍊间笉鍚堢悊锛堝瑙勪笅涓鸿礋锛夈�備笉鍙備笌鏈〃璁$畻銆�");
+        nCell.setCellStyle(metaStyle);
+
+        r++;
+        r = writeProblemSection(sh, r, "涓�銆佺己鏁版竻鍗曪紙璇ユ湁鐨勬暟娌℃湁锛�", missing, sectionStyle, bodyStyle);
+        r = writeProblemSection(sh, r, "浜屻�佹暟鎹綋妫�锛堟暟鍊间笉鍚堢悊锛�", check, sectionStyle, bodyStyle);
+        if (!other.isEmpty()) {
+            r = writeProblemSection(sh, r, "涓夈�佸叾瀹冩彁绀�", other, sectionStyle, bodyStyle);
+        }
+
+        sh.setColumnWidth(0, 6 * 256);
+        sh.setColumnWidth(1, 120 * 256);
+        sh.createFreezePane(0, 3);
+    }
+
+    /** 鍐欎竴涓竻鍗曞垎鍖猴紙鏍囬 + 閫愭潯锛夛紝杩斿洖涓嬩竴涓彲鍐欒鍙� */
+    private int writeProblemSection(XSSFSheet sh, int rowIdx, String title, List<String> lines,
+                                    CellStyle sectionStyle, CellStyle bodyStyle) {
+        Row hr = sh.createRow(rowIdx++);
+        Cell hc = hr.createCell(0);
+        hc.setCellValue(title);
+        hc.setCellStyle(sectionStyle);
+        sh.addMergedRegion(new CellRangeAddress(rowIdx - 1, rowIdx - 1, 0, 1));
+        if (lines.isEmpty()) {
+            Row er = sh.createRow(rowIdx++);
+            er.createCell(0).setCellValue("鈥�");
+            er.createCell(1).setCellValue("鏃�");
+            return rowIdx;
+        }
+        int i = 1;
+        for (String line : lines) {
+            Row row = sh.createRow(rowIdx++);
+            row.createCell(0).setCellValue(i++);
+            Cell c = row.createCell(1);
+            c.setCellValue(line);
+            c.setCellStyle(bodyStyle);
+        }
+        return rowIdx;
+    }
+
     /** 瀵煎嚭杩涘害鍥炶皟锛堝紓姝ュ鍑轰换鍔$敤锛夛細鍥炶皟鑷韩寮傚父涓嶅奖鍝嶅鍑� */
     private static void reportProgress(java.util.function.BiConsumer<Integer, String> progress, int percent, String step) {
         if (progress == null) return;
diff --git a/traffic-audit-web/src/views/ReportExport.vue b/traffic-audit-web/src/views/ReportExport.vue
index bb53610..d689d3c 100644
--- a/traffic-audit-web/src/views/ReportExport.vue
+++ b/traffic-audit-web/src/views/ReportExport.vue
@@ -190,6 +190,25 @@
             <el-button size="small" v-else type="primary" @click="closeTask">鍏抽棴</el-button>
           </span>
         </el-dialog>
+        <!-- 姹囨�诲ぇ琛ㄥ鍑哄墠缂烘暟娓呭崟寮圭獥锛�2026-10-12 鐢ㄦ埛瑕佹眰锛氱己鏁版憜鍒板彴闈笂锛� -->
+        <el-dialog title="鐢熸垚鍓嶆彁绀� - 鏁版嵁缂哄け娓呭崟" :visible.sync="missDialogVisible" width="720px" top="6vh">
+          <div class="miss-body">
+            <p class="miss-lead">鎶ヨ〃鏈� <b>{{ missDialogPeriod }}</b>锛氫互涓嬫暟鎹湰娆$敓鎴愪細缂哄け/寮傚父锛岀敓鎴愪欢鏈熬涔熶細闄勩�婃暟鎹己澶辨竻鍗曘�嬮〉銆�</p>
+            <template v-if="missDialogMissing.length">
+              <div class="miss-sec">涓�銆佺己鏁版竻鍗曪紙璇ユ湁鐨勬暟娌℃湁锛夈��鍏� {{ missDialogMissing.length }} 鏉�</div>
+              <ul class="miss-list"><li v-for="(t, i) in missDialogMissing" :key="'m' + i">{{ t }}</li></ul>
+            </template>
+            <template v-if="missDialogCheck.length">
+              <div class="miss-sec">浜屻�佹暟鎹綋妫�锛堟暟鍊间笉鍚堢悊锛夈��鍏� {{ missDialogCheck.length }} 鏉�</div>
+              <ul class="miss-list"><li v-for="(t, i) in missDialogCheck" :key="'c' + i">{{ t }}</li></ul>
+            </template>
+            <p class="miss-tip">缂烘暟澶氫负婧愭暟鎹皻鏈鍏ワ紝瀵煎叆鍚庨噸鏂扮敓鎴愬嵆鍙紱浣撴椤硅鏍稿婧愭枃浠躲��</p>
+          </div>
+          <span slot="footer">
+            <el-button size="small" @click="missDialogVisible = false">鍙栨秷</el-button>
+            <el-button size="small" type="primary" @click="confirmMissDialog">浠嶈鐢熸垚</el-button>
+          </span>
+        </el-dialog>
       </el-main>
     </el-container>
   </el-container>
@@ -228,6 +247,12 @@
       taskFileName: '',
       taskFileSize: 0,
       taskKey: 'summaryWorkbook',
+      // 瀵煎嚭鍓嶇己鏁版竻鍗曞脊绐楋紙2026-10-12锛夛細缂烘暟/浣撴鎽嗗埌鍙伴潰涓婏紝纭鍚庡啀鐢熸垚
+      missDialogVisible: false,
+      missDialogPeriod: '',
+      missDialogMissing: [],
+      missDialogCheck: [],
+      missDialogRefresh: false,
       modules: [
         {
           key: 'summary', title: '姹囨�诲ぇ琛�', items: [
@@ -626,6 +651,28 @@
         })
         .catch(err => this.failWith(err))
     },
+    // 瀵煎嚭鍓嶇己鏁版鏌ワ細璋冨彧璇绘帴鍙f妸缂烘暟/浣撴缁撴灉鎽嗗埌鐢ㄦ埛闈㈠墠锛岀‘璁ゅ悗鍐嶈蛋寮傛鐢熸垚浠诲姟
+    generateSummaryWorkbook(refresh) {
+      if (!this.period) { this.$message.warning('璇峰厛閫夋嫨鍛ㄦ湡鍜屾湀浠�'); return }
+      const params = { period: this.period }
+      Promise.all([
+        api.get('/report/summaryWorkbook/missing', { params, timeout: 60000 }).catch(() => null),
+        api.get('/report/summaryWorkbook/freightCheck', { params, timeout: 60000 }).catch(() => null)
+      ]).then(res => {
+        const miss = (res[0] && res[0].code === 200 && res[0].data) || []
+        const chk = (res[1] && res[1].code === 200 && res[1].data) || []
+        if (!miss.length && !chk.length) { this.startSummaryTask(refresh); return }
+        this.missDialogPeriod = this.period
+        this.missDialogMissing = miss
+        this.missDialogCheck = chk
+        this.missDialogRefresh = refresh
+        this.missDialogVisible = true
+      })
+    },
+    confirmMissDialog() {
+      this.missDialogVisible = false
+      this.startSummaryTask(this.missDialogRefresh)
+    },
     restartTask() { this.startSummaryTask(true) },
     closeTask() { this.taskVisible = false; this.stopTaskPolling(); this.loading = '' },
     // 鐢熸垚涓敹璧峰脊绐楋細浠诲姟缁х画鍦ㄥ悗鍙版墽琛岋紝瀹屾垚鍚庝粛浼氳嚜鍔ㄤ笅杞斤紙涓庡師鏉ュ悓姝ュ鍑虹殑銆岀偣瀹屽嵆涓嬭浇銆嶄竴鑷达級
@@ -643,7 +690,7 @@
       const doExport = () => {
         if (items.length === 1) {
           // 姹囨�诲ぇ琛ㄧ敓鎴愪竴娆$害 10~20 绉掞紝璧板紓姝ヤ换鍔★紙杩涘害寮圭獥锛夛紝閬垮厤鐐瑰嚮鍚庨暱鏃堕棿鏃犲搷搴�
-          if (items[0].key === 'summaryWorkbook') { this.startSummaryTask(false); return }
+          if (items[0].key === 'summaryWorkbook') { this.generateSummaryWorkbook(false); return }
           api.get('/report/export/' + items[0].key, { params, responseType: 'blob', timeout: 120000 })
             .then(res => { this.downloadBlob(res, this.fileNameOf(items[0])); this.$message.success('鎶ヨ〃瀵煎嚭鎴愬姛'); this.loading = '' })
             .catch(err => this.failWith(err))
@@ -794,6 +841,13 @@
 .task-meta { margin: 2px 0; font-size: 12px; color:#909399; line-height: 1.6; }
 .task-error { margin: 8px 0 0; font-size: 13px; color:#F56C6C; word-break: break-all; }
 .task-done { margin: 8px 0 0; font-size: 13px; color:#67C23A; line-height: 1.6; }
+/* 瀵煎嚭鍓嶇己鏁版竻鍗曞脊绐� */
+.miss-body { max-height: 62vh; overflow-y: auto; }
+.miss-lead { font-size: 13px; color: #303133; margin: 0 0 10px; line-height: 1.7; }
+.miss-sec { font-size: 13px; font-weight: 600; color: #F56C6C; margin: 10px 0 4px; }
+.miss-list { margin: 0; padding-left: 20px; font-size: 13px; color: #303133; line-height: 1.7; }
+.miss-list li { margin: 2px 0; }
+.miss-tip { font-size: 12px; color: #909399; margin: 10px 0 0; }
 </style>
 
 <style>

--
Gitblit v1.9.1