From 2b39c4eb64b194e23f338873e4467eda2b18ccc3 Mon Sep 17 00:00:00 2001
From: zhizhijie <zhizhijie@users.noreply.gitee.com>
Date: 星期二, 22 九月 2026 11:28:56 +0800
Subject: [PATCH] feat(报表生成): 汇总大表导出结果落盘缓存,无新导入即秒回复用
---
traffic-audit-web/src/views/ReportExport.vue | 5
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportTaskService.java | 135 +++++++++++++++++++++++++++++++--
.gitignore | 3
docs/功能测试报告/功能测试报告_汇总大表导出结果落盘缓存复用_2026-09-22.md | 56 ++++++++++++++
docs/交接文档_2026-09-21.md | 2
docs/工作日结/工作日结_2026-09-22.md | 11 ++
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/controller/ReportExportController.java | 2
7 files changed, 199 insertions(+), 15 deletions(-)
diff --git a/.gitignore b/.gitignore
index 597389e..46be7cc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -97,5 +97,8 @@
_*.zip
_bak_*
+# 姹囨�诲ぇ琛ㄥ鍑虹粨鏋滆惤鐩樼紦瀛橈紙澶嶇敤涓婁竴娆$敓鎴愮粨鏋滅敤锛屼笉鍏ュ簱锛�
+docs/鐢熸垚姹囨�诲ぇ琛�/_cache/
+
# Codex 搴旂敤鍦ㄦ湰浠撳簱鏍圭洰褰曚骇鐢熺殑浜х墿鐩綍锛堜繚鐣欏湪鏈湴锛屼笉鍏ュ簱锛�
outputs/
diff --git "a/docs/\344\272\244\346\216\245\346\226\207\346\241\243_2026-09-21.md" "b/docs/\344\272\244\346\216\245\346\226\207\346\241\243_2026-09-21.md"
index f04d309..4dedf8b 100644
--- "a/docs/\344\272\244\346\216\245\346\226\207\346\241\243_2026-09-21.md"
+++ "b/docs/\344\272\244\346\216\245\346\226\207\346\241\243_2026-09-21.md"
@@ -217,7 +217,7 @@
| P2-3 | `applySummaryReferenceLayout()` 鎸�**鍒楀簭鍙�**濂楀垪瀹�/闅愯棌 | 鍙傜収浠朵竴鍔犲噺鍒楀氨鏁翠綋閿欎綅锛屽簲鏀逛负鎸夎〃澶存枃瀛楀尮閰� | 鉂� |
| P2-4 | 缂烘瘝鐗堟彁绀猴紙T08锛夋湭瀹炴祴 | 鏈夋祴璇曞壇鏈椂琛ユ祴 | 鉂� |
| P2-5 | 閮ㄧ讲鍖呭唴鏄�**甯� AJ 鍒楃殑鏃ф瘝鐗�** | `deploy/traffic-audit-deploy-20260913/backend/docs/鐢熸垚姹囨�诲ぇ琛�/`銆乣_deploytest/`锛涚敤鎴� 09-20 鏄庣‘銆岄儴缃插寘鍏堜笉绠°�嶏紝鍙戝寘鍓嶅繀椤诲悓姝� | 鈴� |
-| P2-6 | 瀵煎嚭缂撳瓨鏄�**鍐呭瓨鎬�** | 杩涚▼閲嶅惎鍗冲け鏁堬紱濡傞渶璺ㄩ噸鍚�/澶氫汉鍏辩敤鐨勩�屽鍑鸿褰曘�嶉〉闇�鍙﹀仛 | 鉂� |
+| P2-6 | ~~瀵煎嚭缂撳瓨鏄唴瀛樻�亊~ | **宸茶В鍐筹紙2026-09-22锛�**锛氱粨鏋滆惤鐩樺埌 `docs/鐢熸垚姹囨�诲ぇ琛�/_cache/`锛堟枃浠跺悕甯︽暟鎹増鏈� `MAX(import_batch.id)`锛夛紝鍐呭瓨 鈫� 钀界洏 鈫� 鐪熺畻閫愮骇鍛戒腑锛岄噸鍚悗绔悗浠嶅彲绉掑洖澶嶇敤锛涙湁鏂板鍏ュ嵆澶辨晥锛�7 澶╀笂闄愬苟鑷姩娓呯悊銆傞仐鐣欙細鏁版嵁鐗堟湰鏄叏灞�鐨勶紙涓庢眹鎬绘棤鍏崇殑瀵煎叆涔熶細璁╃紦瀛樺け鏁堬級锛屽闇�鎸夊鍏ョ被鍨嬬粏鍒嗗緟鎺掓湡 | 鉁咃紙鍙紭鍖栭」瑙佸彸锛墊
| P2-7 | 甯傚窞鍗曡〃銆屽甯傚窞鍧椼�嶅厹搴曟彁绀� | 鏄惁鍦ㄨ瘑鍒埌涓�浠芥枃浠跺惈澶氫釜甯傚窞鍧楁椂寮圭獥鎻愮ず/璺宠繃锛屽緟纭锛堜笌 P0-1 鍚屼竴鏍瑰洜锛� | 鈴� |
| P2-8 | 浠撳簱鏍圭洰褰� `_*.*` 涓存椂鏂囦欢澧炲 | `_chk_*`锛堟湰娆℃眹鎬诲ぇ琛ㄦ帓鏌ヤ骇鐢燂紝瑙佹眹鎬诲ぇ琛ㄤ氦鎺ョ 10 鑺傦級銆乣_hyb_*`銆乣_loo_*` 绛夛紝**缁忕敤鎴峰悓鎰忓悗鍐嶆竻** | 鈴� |
| P2-9 | `2026骞�8鏈堥亾璺繍杈撻噺姹囨�昏〃_鐗堝紡鍘熷瀷.xlsx` 鍘荤暀 | 杩愯鏃舵湭琚紩鐢� | 鈴� |
diff --git "a/docs/\345\212\237\350\203\275\346\265\213\350\257\225\346\212\245\345\221\212/\345\212\237\350\203\275\346\265\213\350\257\225\346\212\245\345\221\212_\346\261\207\346\200\273\345\244\247\350\241\250\345\257\274\345\207\272\347\273\223\346\236\234\350\220\275\347\233\230\347\274\223\345\255\230\345\244\215\347\224\250_2026-09-22.md" "b/docs/\345\212\237\350\203\275\346\265\213\350\257\225\346\212\245\345\221\212/\345\212\237\350\203\275\346\265\213\350\257\225\346\212\245\345\221\212_\346\261\207\346\200\273\345\244\247\350\241\250\345\257\274\345\207\272\347\273\223\346\236\234\350\220\275\347\233\230\347\274\223\345\255\230\345\244\215\347\224\250_2026-09-22.md"
new file mode 100644
index 0000000..5188e41
--- /dev/null
+++ "b/docs/\345\212\237\350\203\275\346\265\213\350\257\225\346\212\245\345\221\212/\345\212\237\350\203\275\346\265\213\350\257\225\346\212\245\345\221\212_\346\261\207\346\200\273\345\244\247\350\241\250\345\257\274\345\207\272\347\273\223\346\236\234\350\220\275\347\233\230\347\274\223\345\255\230\345\244\215\347\224\250_2026-09-22.md"
@@ -0,0 +1,56 @@
+# 鍔熻兘娴嬭瘯鎶ュ憡_姹囨�诲ぇ琛ㄥ鍑虹粨鏋滆惤鐩樼紦瀛樺鐢╛2026-09-22
+
+## 涓�銆佸姛鑳借鏄�
+
+鐢ㄦ埛璇夋眰锛氥�屾垜宸茬粡涓嬭浇杩囦簡涓轰粈涔堣繕瑕侀噸鏂扮敓鎴愬憿锛熷彲浠ュ紕涓�涓蹇嗗姛鑳藉悧鈥斺�旀垜涓嬭浇杩囨煇涓暟鎹紝绗簩娆′笅杞芥湡闂存病鏈夋柊瀵煎叆鏁版嵁锛屽氨鐩存帴娌跨敤涓婃绠楀ソ鐨勭粨鏋溿�備笉鐒舵瘡娆′笅杞介兘瑕佺瓑寰堜箙銆傘��
+
+**鏀归�犲墠**锛氬凡鏈夈��10 鍒嗛挓鍐� + 鏈熼棿鏃犳柊瀵煎叆銆嶇殑鍐呭瓨缂撳瓨锛屼絾鈶犵獥鍙e彧鏈� 10 鍒嗛挓锛涒憽瀛樺湪鍐呭瓨閲岋紝杩涚▼涓�閲嶅惎灏辨病浜� 鈫� 姝e父鍦烘櫙涓嬬浜屾涓嬭浇浠嶈閲嶇畻 13~17 绉掋��
+
+**鏀归�犲悗**锛�
+1. 缁撴灉**钀界洏**淇濆瓨鍒� `docs/鐢熸垚姹囨�诲ぇ琛�/_cache/`锛堝凡鍔犲叆 `.gitignore`锛夛紝鏂囦欢鍚� `<key>_v<鏁版嵁鐗堟湰>.xlsx`锛�
+2. 鎻愪氦瀵煎嚭鏃讹紙鏈偣銆岄噸鏂扮敓鎴愩�嶏級锛�**鍐呭瓨缂撳瓨 鈫� 钀界洏缂撳瓨 鈫� 鐪熺畻**锛涜惤鐩樺懡涓姹傘�屽悓涓�鎶ヨ〃鏈� + 鍚屼竴鏁版嵁鐗堟湰銆嶏紱
+3. **鏁版嵁鐗堟湰 = `MAX(import_batch.id)`**锛氬彧瑕佹湡闂存湁浠讳綍涓�娆℃暟鎹鍏ワ紝鐗堟湰灏卞彉锛屾棫缂撳瓨鑷姩澶辨晥锛�
+4. 澶嶇敤涓婇檺 **7 澶�**锛堥槻闄堝勾缁撴灉琚綋鏂拌〃鍙戝嚭锛夛紝瓒呮湡鏂囦欢鍦ㄤ笅娆℃彁浜ゆ椂鑷姩娓呯悊锛涘悓涓� key 鍙繚鐣欐渶鏂扮増鏈枃浠讹紱
+5. 鍓嶇鍛戒腑缂撳瓨鏃舵樉绀恒�屾湰娆$洿鎺ユ部鐢� <鐢熸垚鏃堕棿> 鐢熸垚鐨勭粨鏋滐紙鏈熼棿娌℃湁鏂扮殑鏁版嵁瀵煎叆锛夈�傚闇�鎸夋渶鏂版暟鎹噸绠楋紝璇风偣銆岄噸鏂扮敓鎴愩�嶃�傘�嶏紝骞舵妸涓�琛屽厓淇℃伅鏀规垚銆屾姤琛ㄦ湡 2026-08銆�涓婃鐢熸垚浜� 鈥︺�嶏紙涓嶅啀鏄剧ず銆屼笂娆$敓鎴愮敤鏃� 0.0 绉掋�嶏級锛�
+6. 淇帀钀界洏鍛戒腑鏃� `elapsedMs` 涓鸿礋鏁扮殑闂锛堜互鐢熸垚鏃堕棿浣滀负浠诲姟璧风偣锛夈��
+
+鏀瑰姩鏂囦欢锛歚ReportExportTaskService.java`锛堟牳蹇冿級銆乣ReportExportController.java`锛堟敞閲婏級銆乣ReportExport.vue`锛堟枃妗堬級銆乣.gitignore`銆�
+
+## 浜屻�佹祴璇曠幆澧�
+
+- 鍚庣 Spring Boot 8090锛堥噸鍚姞杞芥柊浠g爜锛夛紱鍓嶇 `npm run serve` 8080锛坄Compiled successfully`锛�
+- 鏁版嵁搴� MySQL 3308 / `traffic_audit`锛涙姤琛ㄦ湡 2026-08锛堟湀鎶ワ級
+- 缂撳瓨鐩綍锛歚docs/鐢熸垚姹囨�诲ぇ琛�/_cache/`锛涘懡涓垽鎹� `MAX(import_batch.id)`锛堟祴璇曟椂涓� **541**锛�
+
+## 涓夈�佺敤渚嬭〃
+
+| # | 鐢ㄤ緥 | 鎿嶄綔 | 棰勬湡 | 瀹為檯 | 缁撹 |
+| --- | --- | --- | --- | --- | --- |
+| T01 | 棣栨鎻愪氦锛堟棤缂撳瓨锛屾鍚戯級 | `GET /api/report/exportTask/summaryWorkbook?period=2026-08` | 鐪熺畻锛屽畬鎴愬悗鍐欒惤鐩樼紦瀛� | `RUNNING` 鈫� `DONE`锛�12.4 s锛夛紱鐢熸垚 `summaryWorkbook_2026-08_month__v541.xlsx`锛�1,204,461 B锛� | 閫氳繃 |
+| T02 | 鍐嶆鎻愪氦锛堝唴瀛樺懡涓級 | 鍚屼笂鎶� | 绔嬪嵆 DONE銆乫romCache=true | 鎻愪氦鑰楁椂 **164 ms**锛宍fromCache=true`锛涗笅杞� 1,204,461 B 涓庣紦瀛樻枃浠朵竴鑷� | 閫氳繃 |
+| T03 | **閲嶅惎鍚庣鍚庡啀鎻愪氦锛堣惤鐩樺懡涓紝鏍稿績锛�** | 鍋�/璧峰墠鍚庣鍚庢彁浜� | 浠嶇珛鍗� DONE锛堜笉鍐嶉噸绠楋級 | 鎻愪氦 **1,194 ms**锛宍fromCache=true`锛屾棩蹇椼�屽懡涓惤鐩樼紦瀛樷�︺�嶏紝涓嬭浇瀛楄妭涓�鑷� | 閫氳繃 |
+| T04 | 鏈夋柊瀵煎叆锛堣礋鍚戯級 | 涓存椂鎻掑叆涓�鏉� `import_batch`锛坕d 鍙� 542锛夊悗鎻愪氦 | 缂撳瓨澶辨晥銆侀噸鏂扮敓鎴� | `fromCache=false`銆乣status=RUNNING` | 閫氳繃 |
+| T05 | 鍚� key 鍙暀鏈�鏂扮増鏈� | 閲嶇畻瀹屾垚鍚庣湅缂撳瓨鐩綍 | 鏃х増鏈枃浠惰鍒犻櫎 | 鐩綍鍙墿 `鈥v542.xlsx`锛坴541 宸插垹锛� | 閫氳繃 |
+| T06 | 鐗堟湰鍥炶惤鍚� | 鍒犳帀涓存椂瀵煎叆琛岋紙鐗堟湰鍥炲埌 541锛夊悗鍐嶆彁浜� | 涓嶅懡涓� v542锛岄噸绠楀苟鍐欏洖 v541 | `fromCache=false` 鈫� 閲嶇畻瀹屾垚锛涚洰褰曞彧鍓� `鈥v541.xlsx` | 閫氳繃 |
+| T07 | 鏃堕暱鏄剧ず锛堝洖褰掍慨澶嶏級 | 钀界洏鍛戒腑鏃剁湅 `elapsedMs` / 鍓嶇鍏冧俊鎭� | 涓嶄负璐熸暟 | 淇鍓� `elapsedMs=-72937`锛涗慨澶嶅悗 `elapsedMs=0`锛屽墠绔樉绀恒�屾姤琛ㄦ湡 2026-08銆�涓婃鐢熸垚浜� 2026-09-22 11:27:32銆� | 閫氳繃 |
+| T08 | 娴忚鍣ㄧ鍒扮锛堟鍚戯級 | admin/123456 鈫� 鎶ヨ〃鐢熸垚 鈫� 姹囨�诲ぇ琛� 鈫� 2026-08 鈫� 瀵煎嚭 | 绉掑嚭骞惰嚜鍔ㄤ笅杞斤紝鏂囨姝g‘ | 鐐瑰嚮鍚�**绔嬪嵆**銆屾眹鎬诲ぇ琛ㄥ凡鐢熸垚銆�100%锛涙樉绀恒�屾湰娆$洿鎺ユ部鐢� 2026-09-22 11:27:32 鐢熸垚鐨勭粨鏋滐紙鏈熼棿娌℃湁鏂扮殑鏁版嵁瀵煎叆锛夈�嶃�併�屽凡鑷姩涓嬭浇锛氱敓鎴恄閬撹矾杩愯緭閲忔眹鎬昏〃_2026-08.xlsx 锛�1.15 MB锛夆�︺�嶏紱鎸夐挳浠呫�岄噸鏂扮敓鎴� / 鍏抽棴銆嶏紱鎺у埗鍙� 0 鎶ラ敊 | 閫氳繃 |
+| T09 | 缂撳瓨涓嶄覆鏈燂紙闈欐�侊級 | 鈥斺�� | 涓嶅悓鎶ヨ〃鏈�/妯″紡浜掍笉鍛戒腑 | key锛坱ype\|period\|mode\|toMonth锛夊悓鏃惰繘鍏ュ唴瀛橀敭涓庤惤鐩樻枃浠跺悕鍓嶇紑 | 閫氳繃锛堥潤鎬侊級 |
+| T10 | 鑷姩娓呯悊 | 鈥斺�� | 瓒呮湡鏂囦欢琚垹闄� | 姣忔鎻愪氦璋冪敤 `cleanupExpired()`锛氬唴瀛樻潯鐩笌纾佺洏鏂囦欢瓒呰繃 7 澶╁嵆娓� | 閫氳繃锛堥潤鎬侊級 |
+
+## 鍥涖�佸彂鐜扮殑闂涓庡缃�
+
+| # | 闂 | 澶勭疆 |
+| --- | --- | --- |
+| P1 | 钀界洏鍛戒腑鏃跺墠绔�岀敤鏃躲�嶄负璐熸暟锛坄elapsedMs=-72937`锛屽洜涓轰换鍔¤捣鐐规槸鐜板湪銆佺粨鏉熸椂闂存槸鍘嗗彶鐢熸垚鏃堕棿锛� | 宸蹭慨锛氳惤鐩樺懡涓椂鎶婁换鍔¤捣鐐硅涓虹敓鎴愭椂闂达紱鍓嶇缂撳瓨鍛戒腑涓嶅啀鏄剧ず鐢ㄦ椂锛屾敼鏄剧ず銆屼笂娆$敓鎴愪簬 鈥︺�� |
+| P2 | 娴嬭瘯鐢ㄧ殑涓存椂 `import_batch` 琛� | 宸插垹闄わ紙`MAX(id)` 鍥炲埌 541銆佹壒娆� 419 鏉★級锛屼粎鐢ㄤ簬楠岃瘉銆屽鍏ュ嵆澶辨晥銆� |
+| P3 | 鏁版嵁鐗堟湰鏄�**鍏ㄥ眬**鐨勶細浠讳綍涓�娆″鍏ワ紙鍚笌姹囨�诲ぇ琛ㄦ棤鍏崇殑鎶曡祫/鑳借�楀鍏ワ級閮戒細璁╂眹鎬荤紦瀛樺け鏁� | 灞炰繚瀹堣璁★紙瀹佸彲閲嶇畻涓嶅彲鍑洪敊锛夈�傝嫢甯屾湜銆屽彧鏈夌浉鍏虫暟鎹鍏ユ墠澶辨晥銆嶏紝闇�瑕佹寜 `import_type` 缁嗗垎渚濊禆锛屽緟鐢ㄦ埛纭鍚庢帓鏈� |
+| P4 | 钀界洏鐩綍 | 鏂板 `docs/鐢熸垚姹囨�诲ぇ琛�/_cache/` 骞跺姞鍏� `.gitignore`锛堢粨鏋滄枃浠朵笉鍏ュ簱锛� |
+
+## 浜斻�佺粨璁�
+
+- 銆屼笅杞借繃涓�娆°�佹湡闂存病鏈夋柊瀵煎叆 鈫� 绗簩娆$洿鎺ユ部鐢ㄣ�嶅凡瀹炵幇锛屼笖**璺ㄥ悗绔噸鍚湁鏁�**锛堣繖鏄湰娆$殑鍏抽敭澧為噺锛夛紱
+- 澶嶇敤姝g‘鎬х敱銆屾暟鎹増鏈紙`MAX(import_batch.id)`锛�+ 7 澶╀笂闄愩�嶅弻閲嶆妸鍏筹細鏈夋柊瀵煎叆蹇呭畾閲嶇畻锛屾祴璇曞凡瑕嗙洊锛�
+- 鐢ㄦ埛浣撻獙锛氬懡涓紦瀛樻椂鐐瑰鍑�**绉掑洖**锛堟绉掔骇锛夛紝涓嶅啀姣忔绛� 13~17 绉掞紱銆岄噸鏂扮敓鎴愩�嶄繚鐣欎负寮哄埗閲嶇畻鍏ュ彛锛�
+- 娴忚鍣ㄧ鍒扮瀹炴祴閫氳繃锛屾棤鎺у埗鍙版姤閿欍��
+
+娴嬭瘯浜猴細Codex锛圓I锛夈��娴嬭瘯鏃ユ湡锛�2026-09-22
diff --git "a/docs/\345\267\245\344\275\234\346\227\245\347\273\223/\345\267\245\344\275\234\346\227\245\347\273\223_2026-09-22.md" "b/docs/\345\267\245\344\275\234\346\227\245\347\273\223/\345\267\245\344\275\234\346\227\245\347\273\223_2026-09-22.md"
index 744a27e..d92387e 100644
--- "a/docs/\345\267\245\344\275\234\346\227\245\347\273\223/\345\267\245\344\275\234\346\227\245\347\273\223_2026-09-22.md"
+++ "b/docs/\345\267\245\344\275\234\346\227\245\347\273\223/\345\267\245\344\275\234\346\227\245\347\273\223_2026-09-22.md"
@@ -69,6 +69,16 @@
- 淇涓や釜鍙e緞鍧戯細璐ц繍閲忓懆杞噺琛ㄧ殑"琛屽唴绱 + 婀栧寳鐪佸悎璁¤"閲嶅璁$畻锛�1,149,579 鈫� 130,311.89 涓囧惃锛夈�佺粨鏉熸湀鏃犳暟鎹嚜鍔ㄥ洖閫�锛�
- 涓庢墜宸ユ牳绠椾竴鑷达細鍏氦 1-8 鏈� 110776.34 涓囦汉娆°�佽揣杩愪紒涓� 313,998,248 鍚ㄣ�佽揣杩愰噺鍛ㄨ浆閲� 130,311.89 涓囧惃銆�
+### 5. 姹囨�诲ぇ琛ㄥ鍑虹粨鏋滆惤鐩樼紦瀛橈紙鐢ㄦ埛锛�"涓嬭浇杩囧氨涓嶈鍐嶇瓑寰堜箙锛岃兘涓嶈兘璁颁綇涓婃缁撴灉"锛�
+
+- **鑳屾櫙**锛氬師鏉ュ彧鏈夈��10 鍒嗛挓鍐� + 鏈熼棿鏃犳柊瀵煎叆銆嶇殑**鍐呭瓨**缂撳瓨锛岀獥鍙g煭銆侀噸鍚嵆澶辨晥 鈫� 绗簩娆′笅杞借繕瑕佺瓑 13~17 绉掋��
+- **鏀瑰姩**锛坄ReportExportTaskService.java` 涓轰富锛夛細
+ 1. 缁撴灉**钀界洏**鍒� `docs/鐢熸垚姹囨�诲ぇ琛�/_cache/`锛屾枃浠跺悕 `<key>_v<鏁版嵁鐗堟湰>.xlsx`锛堟暟鎹増鏈�=`MAX(import_batch.id)`锛夛紝宸插姞 `.gitignore`锛�
+ 2. 鎻愪氦椤哄簭锛氬唴瀛樼紦瀛� 鈫� 钀界洏缂撳瓨锛堝悓鎶ヨ〃鏈� + 鍚屾暟鎹増鏈� + 7 澶╁唴锛夆啋 鐪熺畻锛涚敓鎴愭垚鍔熷悗鍐欑洏骞跺垹闄ゅ悓 key 鏃х増鏈紱
+ 3. 鍓嶇鏂囨锛氬懡涓紦瀛樻樉绀恒�屾湰娆$洿鎺ユ部鐢� <鏃堕棿> 鐢熸垚鐨勭粨鏋滐紙鏈熼棿娌℃湁鏂扮殑鏁版嵁瀵煎叆锛夈�嶏紝鍏冧俊鎭敼涓恒�屼笂娆$敓鎴愪簬 鈥︺�嶃��
+- **椤哄甫淇� bug**锛氳惤鐩樺懡涓椂 `elapsedMs` 涓鸿礋鏁帮紙浠诲姟璧风偣鐢ㄧ幇鍦ㄣ�佺粨鏉熸椂闂存槸鍘嗗彶鐢熸垚鏃堕棿锛夆啋 宸叉敼涓轰互鐢熸垚鏃堕棿浣滆捣鐐广��
+- **瀹炴祴**锛氶娆� 12.4 s 鍐欑紦瀛橈紱鍐嶆鎻愪氦 **164 ms** 鍛戒腑鍐呭瓨锛�**閲嶅惎鍚庣鍚庢彁浜� 1.19 s 鍛戒腑钀界洏**锛涗复鏃舵彃涓�鏉″鍏ヨ褰曞悗 `fromCache=false` 閲嶆柊鐢熸垚锛堥獙璇併�屾湁鏂板鍏ュ嵆澶辨晥銆嶏級锛涙祻瑙堝櫒鐐瑰鍑虹鍑恒�佹枃妗堜笌鎸夐挳姝g‘銆佹帶鍒跺彴 0 鎶ラ敊銆�
+
## 浜屻�佹祴璇曠粨鏋滄憳瑕�
- 鎶ュ憡锛歚docs/鍔熻兘娴嬭瘯鎶ュ憡/鍔熻兘娴嬭瘯鎶ュ憡_鏁版嵁鏌ョ湅琛ラ綈缃戠害杞︿笌涓綋瀹㈣繍绫诲瀷_2026-09-22.md`
@@ -77,6 +87,7 @@
- 鎶ュ憡锛歚docs/鍔熻兘娴嬭瘯鎶ュ憡/鍔熻兘娴嬭瘯鎶ュ憡_鏁版嵁鏌ョ湅鍙e緞绛涢�変笌琛ㄥご鍗曚綅_2026-09-22.md`锛堟帴鍙� 7 鏉� + 鐪熸満 2 鏉″叏閫氳繃锛�
- 鎶ュ憡锛歚docs/鍔熻兘娴嬭瘯鎶ュ憡/鍔熻兘娴嬭瘯鎶ュ憡_鏁版嵁鏌ョ湅鎸夊競宸炴眹鎬讳笌瀵煎嚭_2026-09-22.md`锛堟帴鍙� 10 鏉� + 鐪熸満 4 鏉″叏閫氳繃锛�
- 鎶ュ憡锛歚docs/鍔熻兘娴嬭瘯鎶ュ憡/鍔熻兘娴嬭瘯鎶ュ憡_姹囨�诲ぇ琛ㄨ繘搴﹀脊绐椾紭鍖朹2026-09-22.md`锛�6 鏉$敤渚嬮�氳繃锛氱敓鎴愪腑鐘舵�� / 瀹屾垚鎻愮ず / 鍐嶆涓嬭浇璧扮紦瀛� / 鍏抽棴 / 鏃犳帶鍒跺彴鎶ラ敊 / 鍏跺畠瀵煎嚭鏈彈褰卞搷锛�
+- 鎶ュ憡锛歚docs/鍔熻兘娴嬭瘯鎶ュ憡/鍔熻兘娴嬭瘯鎶ュ憡_姹囨�诲ぇ琛ㄥ鍑虹粨鏋滆惤鐩樼紦瀛樺鐢╛2026-09-22.md`锛�10 鏉$敤渚嬮�氳繃锛氶娆$敓鎴愬啓缂撳瓨 / 鍐呭瓨鍛戒腑 164ms / **閲嶅惎鍚庤惤鐩樺懡涓� 1.19s** / 鏈夋柊瀵煎叆鍗冲け鏁� / 鍚� key 鍙暀鏈�鏂扮増鏈� / 鏃堕暱鏄剧ず淇 / 娴忚鍣ㄧ鍒扮锛�
- 鐜锛氬悗绔� `mvn spring-boot:run`锛�8090锛宍Started TrafficAuditApplication`锛夛紱鍓嶇 `npm run serve`锛�8080锛宍Compiled successfully in 4769ms`锛夛紱MySQL `localhost:3308/traffic_audit`锛涚櫥褰� admin/123456 鍙� JWT銆�
- 缁撴灉锛�3 涓柊绫诲瀷姝e悜锛堝惈鏈熼棿/鍏抽敭瀛楃瓫閫夛級銆佽礋鍚戯紙鏈煡绫诲瀷銆佹棤鏁版嵁鏈熴�佹棤 token锛夊叏閮ㄩ�氳繃锛涘叆搴撴娊鏌ユ潯鏁颁笌搴撳唴涓�鑷达紙20 / 20 / 139锛夛紱鍘熸湁 15 绫诲洖褰掓甯搞��
diff --git a/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/controller/ReportExportController.java b/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/controller/ReportExportController.java
index f4e8e8a..d344393 100644
--- a/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/controller/ReportExportController.java
+++ b/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/controller/ReportExportController.java
@@ -99,7 +99,7 @@
/**
* 姹囨�诲ぇ琛ㄥ紓姝ュ鍑猴細绔嬪嵆杩斿洖浠诲姟鍙凤紝鍓嶇杞杩涘害銆佸畬鎴愬悗鍐嶄笅杞芥枃浠躲��
- * 鐢熸垚涓�娆$害 10~20 绉掞紝璧板紓姝ュ彲閬垮厤鐐瑰嚮鍚庨暱鏃堕棿鏃犲搷搴旓紱鍚屾姤琛ㄦ湡 10 鍒嗛挓鍐呯殑缁撴灉鐩存帴澶嶇敤锛堟湡闂存湁瀵煎叆鍒欒嚜鍔ㄥけ鏁堬級锛�
+ * 鐢熸垚涓�娆$害 10~20 绉掞紝璧板紓姝ュ彲閬垮厤鐐瑰嚮鍚庨暱鏃堕棿鏃犲搷搴旓紱鍚屾姤琛ㄦ湡缁撴灉鐩存帴澶嶇敤锛堣惤鐩樹繚瀛樸�佽繘绋嬮噸鍚悗浠嶆湁鏁堬紱鏈熼棿鏈夊鍏ュ垯鑷姩澶辨晥锛夛紝
* refresh=true 鍙己鍒堕噸鏂扮敓鎴愩��
*/
@GetMapping("/exportTask/summaryWorkbook")
diff --git a/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportTaskService.java b/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportTaskService.java
index ac01627..6c430eb 100644
--- a/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportTaskService.java
+++ b/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportTaskService.java
@@ -8,6 +8,7 @@
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
+import java.io.File;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
@@ -26,10 +27,11 @@
* 鐩殑锛�2026-09-20 鐢ㄦ埛涓婃姤銆岀偣涓嬭浇瑕佺瓑涓�浼氾紝鏁版嵁澶氫簡浼氫笉浼氬崱姝汇�嶏級锛�
* 1) 鐐瑰嚮鍚庣珛鍒绘湁鍙嶉锛屼笉鍐嶉暱鏃堕棿鏃犲搷搴旓紱
* 2) 鐢熸垚杩囩▼涓嶅崰鐢� HTTP 璇锋眰绾跨▼锛岄伩鍏嶅浜哄悓鏃剁偣鎶婂鍣ㄦ嫋姝伙紙宸ヤ綔绾跨▼鍥哄畾 1 涓紝澶氫綑璇锋眰鏄剧ず銆屾帓闃熶腑銆嶏級锛�
- * 3) 鍚屼竴鎶ヨ〃鏈� 10 鍒嗛挓鍐呯殑缁撴灉鍙鐢紝閬垮厤姣忔閲嶇畻鏁存湰绾� 4 涓囨牸鍏紡銆�
+ * 3) 鍚屼竴鎶ヨ〃鏈熺殑缁撴灉鍙鐢紙**钀界洏淇濆瓨锛岃繘绋嬮噸鍚悗渚濈劧鏈夋晥**锛夛紝閬垮厤姣忔閲嶇畻鏁存湰绾� 4 涓囨牸鍏紡銆�
*
- * 缂撳瓨姝g‘鎬у畧鍗細鍙湁褰撱�岃窛涓婃鐢熸垚涓嶈秴杩� TTL銆嶄笖銆屾湡闂存病鏈変换浣曟柊鐨勬暟鎹鍏ワ紙import_batch 鏈�澶� id 鏈彉锛夈��
- * 鏃舵墠澶嶇敤锛涘鍏ュ嵆澶辨晥锛岄伩鍏嶆妸杩囨湡鎶ヨ〃缁欑敤鎴枫�傚墠绔粛鎻愪緵銆岄噸鏂扮敓鎴愩�嶅己鍒跺埛鏂般��
+ * 缂撳瓨姝g‘鎬у畧鍗細鍙湁褰撱�屾湡闂存病鏈変换浣曟柊鐨勬暟鎹鍏ワ紙import_batch 鏈�澶� id 鏈彉锛夈�嶄笖銆岀粨鏋滀笉瓒呰繃 7 澶┿�嶆椂鎵嶅鐢紱
+ * 瀵煎叆鍗冲け鏁堬紝閬垮厤鎶婅繃鏈熸姤琛ㄧ粰鐢ㄦ埛銆傚墠绔粛鎻愪緵銆岄噸鏂扮敓鎴愩�嶅己鍒堕噸绠楋紙璺宠繃缂撳瓨锛夈��
+ * 钀界洏浣嶇疆锛歿summary.template-dir}/_cache/<key>_v<鏁版嵁鐗堟湰>.xlsx
*/
@Slf4j
@Service
@@ -40,13 +42,41 @@
/** 鐢熸垚缁撴灉淇濈暀鏃堕暱锛氭湡闂村彲鍙嶅涓嬭浇锛岃繃鍚庤嚜鍔ㄦ竻鐞� */
private static final long RESULT_TTL_MS = 30 * 60 * 1000L;
- /** 鍚屼竴鎶ヨ〃鏈熺粨鏋滃鐢ㄦ椂闀匡紙涓旀湡闂存棤鏂板鍏ユ椂鎵嶅鐢級 */
- private static final long CACHE_TTL_MS = 10 * 60 * 1000L;
+ /** 鍚屼竴鎶ヨ〃鏈熺粨鏋滃鐢ㄤ笂闄愶細鍙鏈熼棿娌℃湁鏂板鍏ュ氨涓�鐩存部鐢紱瓒呰繃璇ュぉ鏁颁笉鍐嶅鐢紙闃叉闄堝勾缁撴灉琚綋鏂拌〃鍙戝嚭锛� */
+ private static final long CACHE_MAX_AGE_MS = 7L * 24 * 60 * 60 * 1000;
+ /** 钀界洏缂撳瓨瀛愮洰褰曪紙鐩稿 summary.template-dir锛� */
+ private static final String CACHE_SUBDIR = "_cache";
@Resource
private ReportExportService reportService;
@Resource
private ImportBatchMapper importBatchMapper;
+
+ /** 姹囨�诲伐浣滅翱鐩綍锛堜笌 ReportExportService 鍚岄厤缃級锛岃惤鐩樼紦瀛樻斁鍦ㄥ叾 _cache 瀛愮洰褰� */
+ @org.springframework.beans.factory.annotation.Value("${summary.template-dir:docs/鐢熸垚姹囨�诲ぇ琛▆")
+ private String summaryTemplateDir;
+
+ /** 钀界洏缂撳瓨鐩綍锛涘畾浣嶇瓥鐣ヤ笌妯℃澘涓�鑷达紙閰嶇疆鐩綍 / user.dir 鐩稿 / 涓婄骇鐩綍锛� */
+ private File cacheDir() {
+ String rel = summaryTemplateDir;
+ while (rel.startsWith("./")) rel = rel.substring(2);
+ String[] roots = {rel, System.getProperty("user.dir") + "/" + rel, System.getProperty("user.dir") + "/../" + rel};
+ for (String root : roots) {
+ if (root == null || root.trim().isEmpty()) continue;
+ File base = new File(root);
+ if (base.isDirectory()) {
+ File dir = new File(base, CACHE_SUBDIR);
+ if (!dir.isDirectory() && !dir.mkdirs()) continue;
+ return dir;
+ }
+ }
+ return null;
+ }
+
+ /** 缂撳瓨鏂囦欢鍚嶅墠缂�锛堜笉鍚暟鎹増鏈笌鎵╁睍鍚嶏級锛歬ey 閲岀殑闈炴硶瀛楃缁熶竴鏇挎崲 */
+ private String cacheFilePrefix(String type, String period, String mode, Integer toMonth) {
+ return (cacheKey(type, period, mode, toMonth)).replaceAll("[^0-9A-Za-z_-]", "_");
+ }
private final Map<String, Task> tasks = new ConcurrentHashMap<>();
/** 鍚屾姤琛ㄦ湡鏈�杩戜竴娆℃垚鍔熺粨鏋滐細key -> task */
@@ -64,7 +94,7 @@
private final String period;
private final String mode;
private final Integer toMonth;
- private final long createdAt = System.currentTimeMillis();
+ private volatile long createdAt = System.currentTimeMillis();
/** 鐢熸垚鏃剁殑鏁版嵁鐗堟湰锛坕mport_batch 鏈�澶� id锛夛紝鐢ㄤ簬鍒ゆ柇缂撳瓨鏄惁杩囨湡 */
private final long importVersion;
private volatile String status = "PENDING"; // PENDING/RUNNING/DONE/FAILED
@@ -72,6 +102,8 @@
private volatile String step = "鎺掗槦涓�";
private volatile String error;
private volatile byte[] data;
+ /** 钀界洏缂撳瓨鏂囦欢锛氬唴瀛樻暟鎹娓呯悊鍚庝粛鍙粠杩欓噷鍙栵紙璺ㄨ繘绋嬮噸鍚鐢級 */
+ private volatile File cacheFile;
private volatile String fileName;
private volatile boolean fromCache;
private volatile long finishedAt;
@@ -93,11 +125,24 @@
public String getStatus() { return status; }
- public boolean isDone() { return "DONE".equals(status) && data != null; }
+ public boolean isDone() {
+ return "DONE".equals(status) && (data != null || (cacheFile != null && cacheFile.isFile()));
+ }
public boolean isFromCache() { return fromCache; }
- public byte[] getData() { return data; }
+ public byte[] getData() {
+ if (data != null) return data;
+ File f = cacheFile;
+ if (f != null && f.isFile()) {
+ try {
+ return java.nio.file.Files.readAllBytes(f.toPath());
+ } catch (Exception e) {
+ log.warn("璇诲彇瀵煎嚭缂撳瓨鏂囦欢澶辫触锛歿} {}", f.getAbsolutePath(), e.getMessage());
+ }
+ }
+ return null;
+ }
public String getFileName() { return fileName; }
@@ -135,8 +180,16 @@
Task hit = cache.get(key);
if (cacheUsable(hit)) {
hit.fromCache = true;
- log.info("鎶ヨ〃瀵煎嚭浠诲姟鍛戒腑缂撳瓨锛歿} {}锛堢敓鎴愪簬 {}锛�", type, period, new Date(hit.finishedAt));
+ log.info("鎶ヨ〃瀵煎嚭浠诲姟鍛戒腑鍐呭瓨缂撳瓨锛歿} {}锛堢敓鎴愪簬 {}锛�", type, period, new Date(hit.finishedAt));
return hit;
+ }
+ Task disk = loadFromDisk(key, type, period, mode, toMonth);
+ if (disk != null) {
+ tasks.put(disk.id, disk);
+ cache.put(key, disk);
+ log.info("鎶ヨ〃瀵煎嚭浠诲姟鍛戒腑钀界洏缂撳瓨锛歿} {}锛堢敓鎴愪簬 {}锛屾枃浠� {}锛�", type, period,
+ new Date(disk.finishedAt), disk.cacheFile.getName());
+ return disk;
}
}
Task running = findRunning(key);
@@ -168,6 +221,7 @@
t.status = "DONE";
t.finishedAt = System.currentTimeMillis();
cache.put(cacheKey(t.type, t.period, t.mode, t.toMonth), t);
+ writeToDisk(t, data);
log.info("鎶ヨ〃瀵煎嚭浠诲姟瀹屾垚锛歿} {} 鐢ㄦ椂 {} ms锛寋} 瀛楄妭", t.type, t.period, t.finishedAt - start, data.length);
} catch (Throwable e) {
t.status = "FAILED";
@@ -188,7 +242,7 @@
private boolean cacheUsable(Task t) {
if (t == null || !"DONE".equals(t.status) || t.data == null) return false;
- if (System.currentTimeMillis() - t.finishedAt > CACHE_TTL_MS) return false;
+ if (System.currentTimeMillis() - t.finishedAt > CACHE_MAX_AGE_MS) return false;
long now = importVersion();
if (now < 0 || t.importVersion < 0) return false; // 鍙栦笉鍒版暟鎹増鏈椂涓嶅啋椋庨櫓澶嶇敤
return now == t.importVersion;
@@ -218,7 +272,66 @@
}
for (Iterator<Map.Entry<String, Task>> it = cache.entrySet().iterator(); it.hasNext(); ) {
Task t = it.next().getValue();
- if (t.finishedAt <= 0 || now - t.finishedAt > CACHE_TTL_MS) it.remove();
+ if (t.finishedAt <= 0 || now - t.finishedAt > CACHE_MAX_AGE_MS) it.remove();
+ }
+ File dir = cacheDir();
+ if (dir == null) return;
+ File[] fs = dir.listFiles((d, n) -> n.endsWith(".xlsx"));
+ if (fs == null) return;
+ for (File f : fs) {
+ if (now - f.lastModified() > CACHE_MAX_AGE_MS && !f.delete()) {
+ log.warn("娓呯悊杩囨湡瀵煎嚭缂撳瓨澶辫触锛歿}", f.getAbsolutePath());
+ }
+ }
+ }
+
+ /** 鐢熸垚鎴愬姛鍚庢妸缁撴灉钀界洏锛屼緵杩涚▼閲嶅惎鍚庡鐢紱鍐欑洏澶辫触鍙憡璀︼紝涓嶅奖鍝嶆湰娆″鍑� */
+ private void writeToDisk(Task t, byte[] data) {
+ try {
+ File dir = cacheDir();
+ if (dir == null) return;
+ long version = t.importVersion;
+ if (version < 0) return;
+ String prefix = cacheFilePrefix(t.type, t.period, t.mode, t.toMonth);
+ File target = new File(dir, prefix + "_v" + version + ".xlsx");
+ java.nio.file.Files.write(target.toPath(), data);
+ File[] siblings = dir.listFiles((d, n) -> n.startsWith(prefix + "_v") && n.endsWith(".xlsx"));
+ if (siblings != null) {
+ for (File f : siblings) {
+ if (!f.getName().equals(target.getName()) && !f.delete()) {
+ log.warn("娓呯悊鏃х増鏈鍑虹紦瀛樺け璐ワ細{}", f.getAbsolutePath());
+ }
+ }
+ }
+ } catch (Exception e) {
+ log.warn("瀵煎嚭缁撴灉钀界洏澶辫触锛堜笉褰卞搷鏈瀵煎嚭锛屼粎鏃犳硶璺ㄩ噸鍚鐢級锛歿}", e.getMessage());
+ }
+ }
+
+ /** 浠庤惤鐩樼紦瀛橀噷鎵俱�屽悓涓�鎶ヨ〃鏈� + 鍚屼竴鏁版嵁鐗堟湰 + 鏈秴鏈熴�嶇殑缁撴灉锛涙病鏈夎繑鍥� null */
+ private Task loadFromDisk(String key, String type, String period, String mode, Integer toMonth) {
+ try {
+ File dir = cacheDir();
+ if (dir == null) return null;
+ long version = importVersion();
+ if (version < 0) return null; // 鍙栦笉鍒版暟鎹増鏈椂涓嶅啋椋庨櫓澶嶇敤
+ File f = new File(dir, cacheFilePrefix(type, period, mode, toMonth) + "_v" + version + ".xlsx");
+ if (!f.isFile()) return null;
+ long finished = f.lastModified();
+ if (finished <= 0 || System.currentTimeMillis() - finished > CACHE_MAX_AGE_MS) return null;
+ Task t = new Task(type, period, mode, toMonth, version);
+ t.cacheFile = f;
+ t.createdAt = finished; // 澶嶇敤鍘嗗彶缁撴灉锛氫互鐢熸垚鏃堕棿浣滀负璧风偣锛岄伩鍏� elapsedMs 鍑虹幇璐熸暟
+ t.fileName = "鐢熸垚_閬撹矾杩愯緭閲忔眹鎬昏〃_" + period + ".xlsx";
+ t.status = "DONE";
+ t.percent = 100;
+ t.step = "瀹屾垚";
+ t.finishedAt = finished;
+ t.fromCache = true;
+ return t;
+ } catch (Exception e) {
+ log.warn("璇诲彇钀界洏瀵煎嚭缂撳瓨澶辫触锛歿}", e.getMessage());
+ return null;
}
}
diff --git a/traffic-audit-web/src/views/ReportExport.vue b/traffic-audit-web/src/views/ReportExport.vue
index e649937..20c86d5 100644
--- a/traffic-audit-web/src/views/ReportExport.vue
+++ b/traffic-audit-web/src/views/ReportExport.vue
@@ -168,8 +168,9 @@
<el-progress :percentage="taskInfo.percent || 0" :status="taskInfo.status === 'FAILED' ? 'exception' : (taskDone ? 'success' : null)"
:stroke-width="14"></el-progress>
<p class="task-step">{{ taskInfo.step || '鎺掗槦涓�' }}</p>
- <p class="task-meta" v-if="taskInfo.period">鎶ヨ〃鏈� {{ taskInfo.period }}銆�{{ taskInfo.fromCache ? '涓婃鐢熸垚鐢ㄦ椂' : '宸茬敤' }} {{ (taskInfo.elapsedMs / 1000).toFixed(1) }} 绉�</p>
- <p class="task-meta" v-if="taskInfo.fromCache">鏈鐩存帴浣跨敤 {{ taskCacheTime }} 鐢熸垚鐨勭粨鏋滐紙10 鍒嗛挓鍐呬笖鏈熼棿娌℃湁鏂板鍏ユ暟鎹級銆傚闇�鎸夋渶鏂版暟鎹噸绠楋紝璇风偣銆岄噸鏂扮敓鎴愩�嶃��</p>
+ <p class="task-meta" v-if="taskInfo.period && !taskInfo.fromCache">鎶ヨ〃鏈� {{ taskInfo.period }}銆�宸茬敤 {{ ((taskInfo.elapsedMs || 0) / 1000).toFixed(1) }} 绉�</p>
+ <p class="task-meta" v-else-if="taskInfo.period">鎶ヨ〃鏈� {{ taskInfo.period }}銆�涓婃鐢熸垚浜� {{ taskCacheTime }}</p>
+ <p class="task-meta" v-if="taskInfo.fromCache">鏈鐩存帴娌跨敤 {{ taskCacheTime }} 鐢熸垚鐨勭粨鏋滐紙鏈熼棿娌℃湁鏂扮殑鏁版嵁瀵煎叆锛夈�傚闇�鎸夋渶鏂版暟鎹噸绠楋紝璇风偣銆岄噸鏂扮敓鎴愩�嶃��</p>
<p class="task-done" v-if="taskDownloaded">
宸茶嚜鍔ㄤ笅杞斤細<b>{{ taskFileName }}</b><span v-if="taskFileSize">锛坽{ taskFileSizeText }}锛�</span>锛屾枃浠跺湪娴忚鍣ㄩ粯璁や笅杞界洰褰曘��
</p>
--
Gitblit v1.9.1