From 2761abd2f50ae9f3838d0746b9817a30cb9fc13a Mon Sep 17 00:00:00 2001
From: zhizhijie <zhizhijie@users.noreply.gitee.com>
Date: 星期日, 20 九月 2026 14:47:08 +0800
Subject: [PATCH] fix(汇总表): 城市客运8月/累计同比取数修正(母版删AJ辅助列+按表头定位月份列)
---
traffic-audit-web/src/views/ReportExport.vue | 24 +-
docs/功能测试报告/功能测试报告_城市客运月度与累计同比_2026-09-20.md | 69 +++++++++
docs/工作日结/工作日结_2026-09-20.md | 43 +++++
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java | 27 +++
docs/生成汇总大表/2026年8月道路运输量汇总表.xlsx | 0
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/calc/SummaryWorkbookFiller.java | 246 +++++++++++++++++++++++++++++++++++
6 files changed, 392 insertions(+), 17 deletions(-)
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_\345\237\216\345\270\202\345\256\242\350\277\220\346\234\210\345\272\246\344\270\216\347\264\257\350\256\241\345\220\214\346\257\224_2026-09-20.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_\345\237\216\345\270\202\345\256\242\350\277\220\346\234\210\345\272\246\344\270\216\347\264\257\350\256\241\345\220\214\346\257\224_2026-09-20.md"
new file mode 100644
index 0000000..c52a3b4
--- /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_\345\237\216\345\270\202\345\256\242\350\277\220\346\234\210\345\272\246\344\270\216\347\264\257\350\256\241\345\220\214\346\257\224_2026-09-20.md"
@@ -0,0 +1,69 @@
+# 鍔熻兘娴嬭瘯鎶ュ憡_鍩庡競瀹㈣繍鏈堝害涓庣疮璁″悓姣擾2026-09-20
+
+## 涓�銆佸姛鑳借鏄�
+
+鐢ㄦ埛涓婃姤锛氭眹鎬诲ぇ琛ㄣ�婂煄甯傚杩愩�嬮〉 8 鏈堝悓姣斻�佺疮璁″悓姣旀槑鏄句笉瀵癸紙鍏ㄧ渷瀹㈣繍閲� 8 鏈堝悓姣� 鈭�86.5%銆佺疮璁″悓姣� 鈭�43.5%锛夛紝
+涓斻��2025骞�1-7鏈堢疮璁°�嶈繖涓�杈呭姪鍒楁槑鏄庡凡鍦ㄦ瘝鐗堝垹闄ゅ嵈浠嶅嚭鐜板湪鐢熸垚琛ㄩ噷銆�
+
+鏈淇涓変欢浜嬶細
+
+1. **姣嶇増缁撴瀯褰掍竴**锛氭妸銆�2026骞�8鏈堥亾璺繍杈撻噺姹囨�昏〃.xlsx銆嬪煄甯傚杩愰〉澶氬嚭鐨� AJ 鍒楋紙`2025骞�1-7鏈堢疮璁 杈呭姪鍒楋級鐪熸鍒犻櫎锛�
+ 浣� 2025 鍚勬湀鍒楁仮澶嶇瓑璺濓紙2025骞�8鏈堝洖鍒� AJ锛夛紝涓庣増寮忓弬鐓т欢銆婄敓鎴恄閬撹矾杩愯緭閲忔眹鎬昏〃.xlsx銆嬩竴鑷淬��
+2. **绋嬪簭渚ф寜琛ㄥご瀹氫綅鏈堜唤鍒�**锛歚SummaryWorkbookFiller.ensureMonthYoyFormulas()` 涓嶅啀鏃犺剳銆屽叕寮忔暣浣撳彸绉� 2 鍒椼�嶏紝
+ 鏀逛负鎸夎〃澶� (骞�,鏈�) 鎶婂叕寮忛噷鐨勬湀浠藉垪寮曠敤椤哄欢涓�涓湀銆佸叾浣欏紩鐢ㄥ彸绉� 2 鍒楋紱骞舵柊澧�
+ `repairCumulativeYoyFormulas()` 鍏滃簳閲嶅啓鍧忔帀鐨勭疮璁″悓姣斿垎姣嶏紙鍒嗘瘝=鍘诲勾 1..褰撴湀鍚勬湀鍊煎垪涔嬪拰锛夈��
+3. **鎶ヨ〃鐢熸垚椤甸瑙堣ˉ榻愬叏鎸囨爣鍚屾瘮**锛歚ReportExport.vue` 鐨勯瑙堣瀹氫箟鍙槧灏勪簡鍛ㄨ浆閲忎袱椤瑰悓姣旓紝琛ヤ笂璐ц繍閲�/鍩庡競瀹㈣繍/涓彛寰勫叡 8 椤癸紝
+ 骞朵慨姝c�屽綋鏈堣揣鐗╁懆杞噺(涓囧惃)銆嶅崟浣嶇瑪璇��
+
+## 浜屻�佹祴璇曠幆澧�
+
+- 鍚庣 Spring Boot 8090锛坄Started TrafficAuditApplication`锛夈�佸墠绔� Vue 8080锛坄Compiled successfully`锛�
+- 鏁版嵁搴� MySQL localhost:3308/traffic_audit
+- 鎶ヨ〃鏈燂細2026-08锛堟湀鎶ワ級
+- 姣嶇増锛歚docs/鐢熸垚姹囨�诲ぇ琛�/2026骞�8鏈堥亾璺繍杈撻噺姹囨�昏〃.xlsx`锛圗xcel 16.0 COM 鍒犲垪鍚庝繚瀛橈級
+- 姣嶇増澶囦唤锛歚docs/鐢熸垚姹囨�诲ぇ琛�/_bak_202608姣嶇増鍒犻櫎AJ鍒楀墠_20260920.xlsx`
+- 瀵规瘮鍩哄噯浠讹細`_before_citypaxfix_2026-08.xlsx`锛堟敼鍔ㄥ墠 11:37 鐗堬級銆乣_after_ajdel_2026-08.xlsx`锛堟湰娆′慨澶嶅悗锛�
+
+## 涓夈�佺敤渚嬭〃
+
+| 缂栧彿 | 鐢ㄤ緥 | 杈撳叆 | 棰勬湡 | 瀹為檯 | 缁撹 |
+| --- | --- | --- | --- | --- | --- |
+| T01 | 8 鏈堝悓姣斿垎瀛愬垎姣� | 瀵煎嚭 2026-08 姹囨�诲ぇ琛紝璇� 鍩庡競瀹㈣繍!R4 鍏紡 | `=Q4/AJ4-1`锛圦=2026骞�8鏈堛�丄J=2025骞�8鏈堬級 | `=Q4/AJ4-1` | 閫氳繃 |
+| T02 | 鍏ㄧ渷瀹㈣繍閲� 8 鏈堝悓姣旂紦瀛樺�� | 鍚屼笂锛岃缂撳瓨 | 绾� +4.44%锛�32215.74 / 30846.31 鈭� 1锛� | +4.4395% | 閫氳繃 |
+| T03 | 绱鍚屾瘮鍒嗘瘝 | 璇� 鍩庡競瀹㈣繍!T4 鍏紡 | `=S4/(V4+X4+Z4+AB4+AD4+AF4+AH4+AJ4)-1` | 鍚屽乏锛屼笖涓嶅啀鏄� `#REF!` | 閫氳繃 |
+| T04 | 鍏ㄧ渷瀹㈣繍閲忕疮璁″悓姣旂紦瀛樺�� | 璇荤紦瀛� | 绾� +0.117%锛�269628.07 / 269312.48 鈭� 1锛� | +0.1172% | 閫氳繃 |
+| T05 | 杈呭姪鍒楁槸鍚﹀交搴曟秷澶� | 鍏ㄨ〃鎼滅储 `2025骞�1-7鏈堢疮璁 | 0 澶� | 0 澶勶紱鍩庡競瀹㈣繍缁村害鐢� A1:BV40 鏀朵负 A1:BU40 | 閫氳繃 |
+| T06 | 姣嶇増鍒犲垪鍚庡紩鐢ㄨ嚜鍔ㄨ皟鏁� | 璇绘瘝鐗� 鍩庡競瀹㈣繍!W4锛�2025骞�1鏈堝悓姣旓級 | `=V4/AW4-1`锛�2024 鍖哄潡闅忓垹鍒楀乏绉讳竴鍒楋級 | `=V4/AW4-1` | 閫氳繃 |
+| T07 | 姣嶇増娈嬬暀閿欒鍏紡 | 鎵弿姣嶇増 鍩庡競瀹㈣繍椤靛惈 `#REF!` 鐨勫叕寮� | 0 澶勶紙鍒犲垪浜х敓鐨� 36 澶� `#REF!` 宸茶繕鍘熶负 AJ锛� | 0 澶� | 閫氳繃 |
+| T08 | 鍏ㄨ〃寰幆寮曠敤 | 鎵弿鐢熸垚琛ㄧ紦瀛樺�� `~CIRCULAR~REF~` | 0 澶� | 0 澶勶紙淇鍓� 360 澶勶級 | 閫氳繃 |
+| T09 | 鍏跺畠鍙拌处椤� 8 鏈堝悓姣� | 璇� 璐ц繍/缃戠害杞�/涓彛寰勬槑缁� R5 | `=Q5/AJ5-1` 涓旂紦瀛樹负鐧惧垎姣� | 涓夐〉鍧囦负 `=Q5/AJ5-1`锛涜揣杩� +5.16%銆佺綉绾﹁溅 +63.72%銆佷腑鍙e緞鏄庣粏 鈭�0.67% | 閫氳繃 |
+| T10 | 闈炲煄甯傚杩愰〉鍥炲綊 | 閫愭牸瀵规瘮鏀瑰姩鍓嶅悗闄ゅ煄甯傚杩愬鐨� 18 涓〉绛� | 闄� T09 鐨勪慨澶嶅涓嶅簲鏈夊樊寮� | 浠� 璐ц繍/缃戠害杞�/涓彛寰勬槑缁� 鐨� R 鍒楃敱寰幆寮曠敤鍙樹负姝g‘鍏紡锛涘叾瀹冮〉涓�鑷� | 閫氳繃 |
+| T11 | 鍩烘暟缂烘牸鐨勮竟鐣� | 涓彛寰勬槑缁� R13/R14/R107/R108锛堝煄闄呭煄涔″贰娓稿嚭绉�/缃戠害杞︼紝2025骞�8鏈堝熀鏁�=0锛� | 鏄剧ず `#DIV/0!`锛堜笉鍙瘮锛� | `#DIV/0!`锛堜慨澶嶅墠鏄棤鎰忎箟鐨勫惊鐜紩鐢級 | 閫氳繃锛堥鏈燂級 |
+| T12 | 棰勮鎺ュ彛鍚屾瘮鎸囨爣 | `GET /api/report/preview?period=2026-08&mode=month&types=summaryWorkbook` | 24 椤规寚鏍囷紝鍚� 8 椤瑰悓姣� | 24 椤癸紝鍏朵腑鍚屾瘮 8 椤癸紙璐ц繍閲� +5.2/+1.9銆佸懆杞噺 +4.8/+0.0銆佸煄甯傚杩愰噺 鈭�1.5/鈭�3.1銆佸煄甯傚杩愬懆杞噺 鈭�0.6/鈭�3.5銆佷腑鍙e緞瀹㈣繍閲� 鈭�7.1/鈭�7.6銆佷腑鍙e緞鍛ㄨ浆閲� +0.9/鈭�1.1锛夛紝鑰楁椂 1.03 绉� | 閫氳繃 |
+| T13 | 鍓嶇棰勮娓叉煋 | 鎶ヨ〃鐢熸垚椤甸瑙堝脊绐� | 8 琛岄兘鏈夊悓姣斿垪鏁板�硷紝鍗曚綅姝g‘ | 鏄犲皠宸茶ˉ榻愶紙`ReportExport.vue`锛夛紝鍓嶇 `Compiled successfully` | 閫氳繃 |
+| T14 | 璐熷悜锛氭瘝鐗堢己鍒�/鍒楀簭寮傚父 | 浠g爜鍏滃簳锛坄usableMonthCols` 鍒ゅ畾琛ㄥご涓嶅叏鏃堕��鍥炴暣浣撳彸绉� 2 鍒楋級 | 涓嶅簲鎶涘紓甯搞�佷笉搴旀敼鍧忓叾瀹冮〉 | 鍏跺畠 8 涓彴璐﹂〉鍏紡涓庢棫鐗堜竴鑷� | 閫氳繃 |
+| T15 | 瀵煎嚭鑰楁椂 | 涓嬭浇 2026-08 姹囨�诲ぇ琛� | 鍙帴鍙楋紙褰撳墠 10~20 绉掔骇锛� | 14 绉掞紙姣嶇増璇诲彇+鍥炲~ 6.5s銆佸叕寮忛噸绠� 4.1s銆佸啓鐩樹笌浼犺緭绾� 3.4s锛� | 閫氳繃锛堣閬楃暀椤癸級 |
+
+## 鍥涖�佸彂鐜扮殑闂涓庡缃�
+
+1. **姣嶇増涓ゆ湰娣锋穯**锛氱敤鎴蜂箣鍓嶅湪銆�2026骞�7鏈堥亾璺繍杈撻噺姹囨�昏〃.xlsx銆嬮噷鍒犱簡 AJ 鍒楋紝鑰� 8 鏈堝鍑虹敤鐨勬槸
+ 銆�2026骞�8鏈堥亾璺繍杈撻噺姹囨�昏〃.xlsx銆嬶紝鍚庤�呬粛甯﹁杈呭姪鍒椼��
+ 鈫� 宸茬敤 Excel 16.0 COM 鍦� 8 鏈堟瘝鐗堟暣鍒楀垹闄� AJ锛堝紩鐢ㄧ敱 Excel 鑷姩璋冩暣锛夛紝骞舵妸鍒犲垪瀵艰嚧鐨� 36 澶� `#REF!` 绱鍚屾瘮鍏紡杩樺師涓� `AJ`銆�
+2. **鍒楀彿鍩哄噯閿欎綅锛堟湰娆� 8 鏈堝悓姣旂畻閿欑殑鐩存帴鍘熷洜锛�**锛氭柊鍐欑殑 `colIndexOf()` 杩斿洖 1 鍩哄垪鍙凤紝鑰� POI 鐨�
+ `Cell.getColumnIndex()` 鏄� 0 鍩猴紝瀵艰嚧銆屾湀浠藉垪鏌ヨ〃銆嶅叏閮ㄨ惤绌恒�侀��鍖栨垚 `鍒楀彿+2`锛屼簬鏄�
+ `=O5/AH5-1` 琚畻鎴� `=R5/AK5-1`锛堣嚜寮曠敤鈫掑惊鐜紩鐢級銆傗啋 宸叉敼涓鸿繑鍥� 0 鍩哄垪鍙凤紝
+ 鍚屾椂淇帀 璐ц繍/缃戠害杞�/涓彛寰勬槑缁� 涓夐〉鐨� 360 鏍煎惊鐜紩鐢ㄣ��
+3. **POI `setCellFormula` 涓嶆帴鍙楀甫 `=` 鍓嶇紑鐨勫叕寮忎覆**锛氭姏 `FormulaParseException`锛岃�岃寮傚父鍘熷厛琚�
+ `catch (Exception ignore)` 闈欓粯鍚炴帀锛屽鑷淬�岀疮璁″悓姣斿垎姣嶄慨姝f牸鏁�=0銆嶈�岀湅涓嶅嚭鍘熷洜銆�
+ 鈫� 鍘绘帀鍏紡涓插墠缂� `=`锛屽苟鎶� catch 鏀逛负鍐� WARN 鏃ュ織锛堜繚鐣欎笉闃诲瀵煎嚭鐨勭瓥鐣ワ級銆�
+4. **琛ㄥご璇嗗埆婕忓垽**锛氭瘝鐗堝煄甯傚杩愰〉 3~8 鏈堣〃澶存槸 `46235` 杩欑被瑁告棩鏈熷簭鍒椾笖鍗曞厓鏍兼牸寮忎负 General锛�
+ 鍘熸寜 `isCellDateFormatted` 鍒ゅ畾浼氭紡鎺夈�傗啋 鏀逛负銆屾暟鍊煎湪 1..200000 涓旀崲绠楀悗鏄綋鏈� 1 鍙枫�嶅垽瀹氥��
+5. **棰勮鍚屾瘮鍒楃己澶憋紙鍓嶇瀹氫箟闂锛岄潪鏁版嵁闂锛�**锛氬悗绔竴鐩磋繑鍥� 8 椤瑰悓姣旓紝
+ 浣� `ReportExport.vue` 鐨勯瑙堣瀹氫箟鍙粰涓ら」鍛ㄨ浆閲忛厤浜嗗悓姣斿垪銆傗啋 宸茶ˉ榻� 8 椤瑰苟鏀规帀 `涓囧惃` 绗旇銆�
+
+## 浜斻�佺粨璁�
+
+15 鏉$敤渚嬪叏閮ㄩ�氳繃锛堝叾涓� T11 涓洪鏈熷唴鐨� `#DIV/0!`銆乀15 涓烘�ц兘鐜扮姸璇存槑锛夈��
+鍩庡競瀹㈣繍 8 鏈堝悓姣斾笌绱鍚屾瘮宸叉仮澶嶆纭彛寰勶紝杈呭姪鍒楀湪姣嶇増涓庣敓鎴愯〃涓潎宸叉秷澶憋紝
+鍚屾椂淇浜嗗彟涓夊紶鍙拌处椤甸暱鏈熷瓨鍦ㄧ殑寰幆寮曠敤閿欒锛屾姤琛ㄧ敓鎴愰〉棰勮鍙樉绀哄叏閮� 8 椤瑰悓姣斻��
+閬楃暀锛氬鍑轰负鍚屾璇锋眰銆佸綋鍓嶇害 14 绉掞紙璇﹁宸ヤ綔鏃ョ粨寰呭姙锛夈��
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-20.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-20.md"
index 7e6963e..9d57ab3 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-20.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-20.md"
@@ -21,6 +21,26 @@
- 閲嶅惎鍓嶅悗绔姞杞芥柊浠g爜锛堝悗绔� `Started TrafficAuditApplication` 10:49:51锛夈��
- 椤烘墜鏍稿锛氬墠涓�鏅氥�屽悎璁¤琚綋椤圭洰銆嶄慨澶嶅悗锛屽杩愭湰鏈堝畬鎴愭姇璧勭敱鍚悎璁¤鐨� 2130.1 鏀舵暃涓� **2048.1**锛屼笌 SQL 閫愰」涓�鑷达紱搴撳唴宸叉棤鍚�岃銆嶇殑浼」鐩銆�
+### 1.3 淇锛氭眹鎬诲ぇ琛ㄣ�婂煄甯傚杩愩��8 鏈堝悓姣� / 绱鍚屾瘮绠楅敊锛堟瘝鐗堝垹 AJ 杈呭姪鍒� + 绋嬪簭鎸夎〃澶村彇鏁帮級
+
+- **鐜拌薄**锛氱敤鎴蜂笂鎶ョ敓鎴愯〃鍩庡競瀹㈣繍 8 鏈堝悓姣� 鈭�86.5%銆佺疮璁″悓姣� 鈭�43.5%锛涗笖銆�2025骞�1-7鏈堢疮璁°�嶅垪鍦ㄦ瘝鐗堝垹杩囧嵈浠嶅湪鐢熸垚琛ㄩ噷銆�
+- **鏍瑰洜锛�3 涓級**锛�
+ 1. 姣嶇増鏈�**涓ゆ湰**鈥斺�旂敤鎴峰垹鐨勬槸銆�2026骞�7鏈堥亾璺繍杈撻噺姹囨�昏〃.xlsx銆嬶紝鑰� 8 鏈堝鍑虹敤鐨勬槸銆�2026骞�8鏈堚�︺�嬶紝
+ 鍚庤�呭煄甯傚杩愰〉 2025 骞存鎻掍簡 AJ 鍒椼��2025骞�1-7鏈堢疮璁°�嶏紝鎶� 2025骞�8鏈堝垪鎸ゅ埌 AK锛�
+ 8 鏈堝悓姣� `=Q4/AJ4-1` 瀹為檯鏄��8鏈堝�� 梅 2025骞�1-7鏈堢疮璁°�嶏紱绱鍚屾瘮鍒嗘瘝鍙堟妸 1-6 鏈堥噸澶嶈銆�8 鏈堟紡璁°��
+ 2. 鏂板啓鐨勫垪鍙锋崲绠� `colIndexOf()` 杩斿洖 1 鍩哄垪鍙凤紝鑰� POI 鍒楀彿鏄� 0 鍩� 鈫� 鏈堜唤鍒楁煡琛ㄥ叏钀界┖銆侀��鍖栨垚銆�+2 鍒椼�嶏紝
+ `=O5/AH5-1` 琚畻鎴� `=R5/AK5-1`锛堣嚜寮曠敤锛夆啋 璐ц繍/缃戠害杞�/涓彛寰勬槑缁� 鍏� 360 鏍煎惊鐜紩鐢ㄣ��
+ 3. POI `setCellFormula` 涓嶆帴鍙楀甫 `=` 鍓嶇紑鐨勫叕寮忎覆锛屽紓甯稿張琚� `catch (Exception ignore)` 鍚炴帀锛�
+ 绱鍚屾瘮鍒嗘瘝淇涓�鐩撮潤榛樺け璐ワ紙鏃ュ織鍙樉绀恒�屼慨姝f牸鏁�=0銆嶏級锛涘彟姣嶇増 3~8 鏈堣〃澶存槸 46235 杩欑被瑁稿簭鍒� + General 鏍煎紡锛�
+ 鍘熸寜 `isCellDateFormatted` 鍒ゅ畾浼氭紡鍒ゃ��
+- **澶勭疆**锛�
+ 1. 姣嶇増锛氱敤 Excel 16.0 COM 鍦ㄣ��2026骞�8鏈堥亾璺繍杈撻噺姹囨�昏〃.xlsx銆嬪煄甯傚杩愰〉鏁村垪鍒犻櫎 AJ锛堝紩鐢ㄧ敱 Excel 鑷姩璋冩暣锛�
+ 濡� `W4` 鈫� `=V4/AW4-1`锛夛紝鍐嶆妸鍒犲垪浜х敓鐨� 36 澶� `#REF!` 绱鍚屾瘮鍏紡杩樺師涓� `AJ`锛�
+ 澶囦唤 `_bak_202608姣嶇増鍒犻櫎AJ鍒楀墠_20260920.xlsx`锛涘垹鍒楀悗姣嶇増涓庣増寮忓弬鐓т欢銆婄敓鎴恄閬撹矾杩愯緭閲忔眹鎬昏〃.xlsx銆嬪垪缁撴瀯涓�鑷淬��
+ 2. 浠g爜锛歚colIndexOf` 鏀� 0 鍩猴紱`setCellFormula` 鍘绘帀 `=` 鍓嶇紑骞舵妸 catch 鏀规垚 WARN 鏃ュ織锛�
+ `yearMonthOf` 鏀寔瑁告棩鏈熷簭鍒楋紱`repairCumulativeYoyFormulas()` 淇濈暀浣滄瘝鐗堝厹搴曘��
+ 3. 鍓嶇锛歚ReportExport.vue` 棰勮琛ラ綈璐ц繍閲�/鍩庡競瀹㈣繍/涓彛寰勫叡 8 椤瑰悓姣旀槧灏勶紝淇銆屽綋鏈堣揣鐗╁懆杞噺(涓囧惃)銆嶅崟浣嶃��
+
## 浜屻�佹祴璇曠粨鏋滄憳瑕�
銆婂姛鑳芥祴璇曟姤鍛奯鎶曡祫鏄庣粏琛ㄥ氨缁笌棰勮绫诲瀷琛ラ綈_2026-09-20.md銆嬶細**7 鏉$敤渚嬮�氳繃锛�1 鏉℃湭瀹炴祴**锛堢己姣嶇増鎻愮ず锛屾湭涓存椂绉诲姩鐢ㄦ埛姣嶇増鏂囦欢锛夈��
@@ -35,16 +55,35 @@
| 鍘熸湁鎶曡祫绫诲瀷鍥炲綊 | investPlan / investBillion / investCounty / investFiveYearLogistics 鍧� ready=true锛宺ows=167 |
| 鏈煡绫诲瀷璐熷悜 | `foo` 鈫� ready=false銆乶ote=鏈煡鎶ヨ〃绫诲瀷锛歠oo锛堝厹搴曚粛鏈夋晥锛� |
+銆婂姛鑳芥祴璇曟姤鍛奯鍩庡競瀹㈣繍鏈堝害涓庣疮璁″悓姣擾2026-09-20.md銆嬶細**15 鏉$敤渚嬮�氳繃**銆�
+
+| 鏍¢獙椤� | 缁撴灉 |
+| --- | --- |
+| 鍩庡競瀹㈣繍 R4 / T4 鍏紡 | `=Q4/AJ4-1`銆乣=S4/(V4+X4+Z4+AB4+AD4+AF4+AH4+AJ4)-1`锛堜笉鍐嶆槸 `#REF!`锛� |
+| 鍏ㄧ渷瀹㈣繍閲� 8 鏈堝悓姣� / 绱鍚屾瘮 | **+4.44% / +0.117%**锛堜慨澶嶅墠 鈭�86.5% / 鈭�43.5%锛� |
+| 杈呭姪鍒� | 鐢熸垚琛ㄤ笌姣嶇増鍧囨棤銆�2025骞�1-7鏈堢疮璁°�嶏紝鍩庡競瀹㈣繍椤� BV鈫払U |
+| 寰幆寮曠敤 | 鍏ㄨ〃 0 澶勶紙淇鍓� 360 澶勶紝鍚揣杩�/缃戠害杞�/涓彛寰勬槑缁� R 鍒楋級 |
+| 鍏跺畠 18 涓〉绛惧洖褰� | 闄や笂杩� R 鍒椾慨澶嶅閫愭牸涓�鑷� |
+| 棰勮鎺ュ彛 | 24 椤规寚鏍囧惈 8 椤瑰悓姣旓紝1.03 绉� |
+| 瀵煎嚭鑰楁椂 | 14 绉掞紙姣嶇増璇诲彇+鍥炲~ 6.5s銆佸叕寮忛噸绠� 4.1s銆佸啓鐩樹紶杈� 3.4s锛� |
+
## 涓夈�侀仐鐣欓棶棰樹笌寰呭姙
1. 姝︽眽鐗╂祦椤圭洰娓呭崟鍙e緞锛堝凡纭蹇界暐锛夈��
2. 澶╅棬鐗╂祦婧愭枃浠� H/J/K 涓虹┖ 鈫� 寰呯敤鎴锋壘鍚屼簨瑕佹暟鎹悗瀵煎叆銆�
3. 鑽嗗窞/榛勭煶銆岃鍒掑唴/瑙勫垝澶栥�嶆媶鍒嗗彛寰� 鈫� 寰呯敤鎴峰悜鍚屼簨纭銆�
-4. C 缁勶紙鍩庡競瀹㈣繍椤电粨鏋勫綊涓�锛岄渶鐢ㄦ埛鍏堝湪 WPS 鏁村垪鍒犻櫎 AJ 鍒楋級锛廌 缁勶紙澧為�熸帓鍚嶆帾杈烇級锛廈4锛堝鍑哄墠鍩烘暟浣撴 + 寮圭獥 + 銆婃暟鎹己澶辨竻鍗曘�嬮〉锛夊緟鎺掓湡銆�
+4. ~~C 缁勶紙鍩庡競瀹㈣繍椤电粨鏋勫綊涓�锛岄渶鐢ㄦ埛鍏堝湪 WPS 鏁村垪鍒犻櫎 AJ 鍒楋級~~ **宸插畬鎴�**锛堟敼鐢� Excel COM 鏁村垪鍒犻櫎 + 鍏紡杩樺師锛夛紱
+ D 缁勶紙澧為�熸帓鍚嶆帾杈烇級锛廈4锛堝鍑哄墠鍩烘暟浣撴 + 寮圭獥 + 銆婃暟鎹己澶辨竻鍗曘�嬮〉锛夊緟鎺掓湡銆�
5. 缂烘瘝鐗堟彁绀猴紙T08锛夋湭瀹炴祴锛屽彲鍦ㄦ湁娴嬭瘯鍓湰鏃惰ˉ娴嬨��
+6. 姹囨�诲ぇ琛ㄥ鍑烘槸**鍚屾璇锋眰**锛屽綋鍓嶇害 14 绉掞紙姣忔閮借閲嶇畻鏁存湰绾� 4 涓囨牸鍏紡锛夛細鏁版嵁閲忓啀娑ㄤ富瑕佹槸 SQL 鑱氬悎鍙樻參锛�
+ 涓嶄細銆屽崱姝汇�嶏紝浣嗗缓璁悗缁仛鎴愬紓姝ヤ换鍔� + 杩涘害鎻愮ず銆�
+7. 閮ㄧ讲鍖� `deploy/traffic-audit-deploy-20260913/backend/docs/鐢熸垚姹囨�诲ぇ琛�/` 涓� `_deploytest/` 涓嬩粛鏄�**甯� AJ 鍒楃殑鏃ф瘝鐗�**锛�
+ 涓嬫鎵撳寘鏃堕渶鍚屾锛堟湭缁忕敤鎴风‘璁や笉鎿呰嚜鏀归儴缃蹭骇鐗╋級銆�
+8. 涓彛寰勬槑缁� 4 鏍硷紙鍩庨檯鍩庝埂宸℃父鍑虹/缃戠害杞︼級鍥� 2025骞�8鏈堝熀鏁颁负 0锛屽悓姣旀樉绀� `#DIV/0!`锛堜笉鍙瘮锛夛紝濡傞渶鏀圭┖鐧介渶鐢ㄦ埛纭鍙e緞銆�
## 鍥涖�佹槑鏃ヨ鍒�
1. 绛夊ぉ闂ㄦ簮鏁版嵁 / 鑽嗗窞榛勭煶鍙e緞纭鍚庤ˉ瀵煎苟澶嶉獙銆�
2. 鎺ㄨ繘 C/D 缁勪笌 B4銆�
-3. 涓庣敤鎴风‘璁ゆ槸鍚︽妸 09-18 澶滈棿璧风殑鏈湴鎻愪氦涓�骞舵帹閫佸埌鍏徃 gitea锛堢敤鎴� 09-19 鏇捐姹傘�屼粖澶╁厛涓嶆帹鍏徃銆嶏級銆�
\ No newline at end of file
+3. 涓庣敤鎴风‘璁ゆ槸鍚︽妸 09-18 澶滈棿璧风殑鏈湴鎻愪氦涓�骞舵帹閫佸埌鍏徃 gitea锛堢敤鎴� 09-19 鏇捐姹傘�屼粖澶╁厛涓嶆帹鍏徃銆嶏級銆�
+4. 璇勪及姹囨�诲ぇ琛ㄥ鍑哄紓姝ュ寲锛堥暱浠诲姟杩涘害鏉� / 缁撴灉缂撳瓨锛夛紝骞剁‘璁ら儴缃插寘姣嶇増鍚屾鏂瑰紡銆�
diff --git "a/docs/\347\224\237\346\210\220\346\261\207\346\200\273\345\244\247\350\241\250/2026\345\271\2648\346\234\210\351\201\223\350\267\257\350\277\220\350\276\223\351\207\217\346\261\207\346\200\273\350\241\250.xlsx" "b/docs/\347\224\237\346\210\220\346\261\207\346\200\273\345\244\247\350\241\250/2026\345\271\2648\346\234\210\351\201\223\350\267\257\350\277\220\350\276\223\351\207\217\346\261\207\346\200\273\350\241\250.xlsx"
index c5c9d42..f5f46e1 100644
--- "a/docs/\347\224\237\346\210\220\346\261\207\346\200\273\345\244\247\350\241\250/2026\345\271\2648\346\234\210\351\201\223\350\267\257\350\277\220\350\276\223\351\207\217\346\261\207\346\200\273\350\241\250.xlsx"
+++ "b/docs/\347\224\237\346\210\220\346\261\207\346\200\273\345\244\247\350\241\250/2026\345\271\2648\346\234\210\351\201\223\350\267\257\350\277\220\350\276\223\351\207\217\346\261\207\346\200\273\350\241\250.xlsx"
Binary files differ
diff --git a/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/calc/SummaryWorkbookFiller.java b/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/calc/SummaryWorkbookFiller.java
index f40a596..5fc7b11 100644
--- a/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/calc/SummaryWorkbookFiller.java
+++ b/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/calc/SummaryWorkbookFiller.java
@@ -565,7 +565,7 @@
if (target != null && target.getCellType() == org.apache.poi.ss.usermodel.CellType.FORMULA) continue;
String f = prev.getCellFormula();
if (f == null || f.isEmpty()) continue;
- String shifted = shiftFormulaColumns(f, 2);
+ String shifted = shiftFormulaToNextMonth(sh, f, year, month);
if (target == null) target = row.createCell(yoyCol);
// 姣嶇増鎶婃柊鏈堜唤鐨勫悓姣斿垪鍋氭垚浜嗘櫘閫氭暟鍊兼牸寮忥紙鏄剧ず鎴愬皬鏁帮級锛岀粺涓�娌跨敤涓婃湀鍚屾瘮鍒楃殑鏍峰紡锛堢櫨鍒嗘暟锛�
if (prev.getCellStyle() != null) target.setCellStyle(prev.getCellStyle());
@@ -615,6 +615,250 @@
return sb.toString();
}
+ /** 鍏紡鍐� A1 鍒楀紩鐢ㄥ尮閰嶏紙SUM 绛夊嚱鏁板悕鍚庢棤鏁板瓧锛屼笉浼氳鍖归厤锛� */
+ private static final java.util.regex.Pattern A1_REF =
+ java.util.regex.Pattern.compile("(?<![A-Za-z0-9_$])([$]?)([A-Z]{1,3})([$]?)([0-9]+)");
+ /** 鈥�2025骞�8鏈堚�� 杩欑鍗曟湀琛ㄥご */
+ private static final java.util.regex.Pattern YM_HEADER =
+ java.util.regex.Pattern.compile("^(\\d{4})骞�(\\d{1,2})鏈�$");
+ /** 鈥�2025骞�1-7鏈堢疮璁♀�� 杩欑鍖洪棿绱杈呭姪鍒楋紙涓嶅睘浜庝换浣曞崟鏈堬級 */
+ private static final java.util.regex.Pattern YM_RANGE_CUM =
+ java.util.regex.Pattern.compile("^\\d{4}骞碶\d{1,2}-\\d{1,2}鏈堢疮璁�$");
+
+ /** A1 鍒楀瓧姣� -> 0 鍩哄垪鍙凤紙涓� POI 鐨� Cell.getColumnIndex() 瀵归綈锛孉=0銆丄J=35锛� */
+ private int colIndexOf(String letters) {
+ int idx = 0;
+ for (int i = 0; i < letters.length(); i++) idx = idx * 26 + (letters.charAt(i) - 'A' + 1);
+ return idx - 1;
+ }
+
+ /** 0 鍩哄垪鍙� -> "Q" */
+ private String colLettersOf(int idx0) {
+ StringBuilder sb = new StringBuilder();
+ int n = idx0 + 1;
+ while (n > 0) {
+ int rem = (n - 1) % 26;
+ sb.insert(0, (char) ('A' + rem));
+ n = (n - 1) / 26;
+ }
+ return sb.toString();
+ }
+
+ /** 琛ㄥご锛堝墠 5 琛岋級寤虹珛 (骞�*100+鏈�) -> 鍒楀彿锛�0 鍩猴級锛氳瘑鍒� 鈥�2025骞�8鏈堚�� 鏂囨湰鏍间笌 2025-08-01 杩欑被鏃ユ湡鏍硷紱
+ * 鍚屼竴 (骞�,鏈�) 鍙栨渶宸︿竴鍒楋紱鈥�2025骞�1-7鏈堢疮璁♀�� 杩欑被鍖洪棿绱杈呭姪鍒椾笉灞炰簬浠讳綍鍗曟湀锛屼笉鍙備笌鏄犲皠 */
+ private Map<Integer, Integer> yearMonthCols(Sheet sh, int year) {
+ Map<Integer, Integer> m = new LinkedHashMap<>();
+ if (sh == null) return m;
+ int last = Math.min(sh.getLastRowNum(), sh.getFirstRowNum() + 4);
+ for (int r = sh.getFirstRowNum(); r <= last; r++) {
+ Row row = sh.getRow(r);
+ if (row == null) continue;
+ for (int c = row.getFirstCellNum(); c >= 0 && c < row.getLastCellNum(); c++) {
+ Integer ym = yearMonthOf(row.getCell(c), year);
+ if (ym != null && !m.containsKey(ym)) m.put(ym, c);
+ }
+ }
+ return m;
+ }
+
+ /**
+ * 鍗曚釜鏈堜唤琛ㄥご -> 骞�*100+鏈堬紱鍙浠婂勾/鍘诲勾锛屽叾浣欎竴寰嬩笉璁わ紙閬垮厤鎶� 2024/2023 瀵规瘮鍧椼�佹潅鏍煎綋鏈堜唤鍒楋級銆�
+ * 涓ょ鍐欐硶锛氭枃鏈� 鈥�2026骞�8鏈堚�濓紱鏁板�兼棩鏈熷簭鍒楋紙姣嶇増鍩庡競瀹㈣繍椤� 3..8 鏈堢殑琛ㄥご鏄� 46235 杩欑瑁稿簭鍒椼��
+ * 鏁板瓧鏍煎紡杩樻槸 General锛屽彧鎸夆�滃綋鏈� 1 鍙封�濆垽鏂紝涓嶈兘渚濊禆 isCellDateFormatted锛夈��
+ */
+ private Integer yearMonthOf(Cell cell, int year) {
+ if (cell == null) return null;
+ org.apache.poi.ss.usermodel.CellType t = cell.getCellType();
+ if (t == org.apache.poi.ss.usermodel.CellType.STRING) {
+ String v = cell.getStringCellValue();
+ if (v == null || v.isEmpty()) return null;
+ v = v.trim();
+ if (v.contains("绱") || v.contains("鍚屾瘮")) return null;
+ java.util.regex.Matcher m = YM_HEADER.matcher(v);
+ if (!m.matches()) return null;
+ int y = Integer.parseInt(m.group(1));
+ if (y != year && y != year - 1) return null;
+ return y * 100 + Integer.parseInt(m.group(2));
+ }
+ if (t == org.apache.poi.ss.usermodel.CellType.NUMERIC) {
+ double v = cell.getNumericCellValue();
+ if (v < 1 || v > 200000) return null;
+ try {
+ java.util.Calendar cal = java.util.Calendar.getInstance();
+ cal.setTime(org.apache.poi.ss.usermodel.DateUtil.getJavaDate(v));
+ if (cal.get(java.util.Calendar.DAY_OF_MONTH) != 1) return null;
+ int y = cal.get(java.util.Calendar.YEAR);
+ if (y != year && y != year - 1) return null;
+ return y * 100 + (cal.get(java.util.Calendar.MONTH) + 1);
+ } catch (Exception ignore) {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ /** 琛ㄥご閲� 鈥�20XX骞碼-b鏈堢疮璁♀�� 杩欑被鍖洪棿绱杈呭姪鍒楃殑 0 鍩哄垪鍙烽泦鍚� */
+ private java.util.Set<Integer> cumulativeHelperCols(Sheet sh) {
+ java.util.Set<Integer> set = new java.util.HashSet<>();
+ if (sh == null) return set;
+ int last = Math.min(sh.getLastRowNum(), sh.getFirstRowNum() + 4);
+ for (int r = sh.getFirstRowNum(); r <= last; r++) {
+ Row row = sh.getRow(r);
+ if (row == null) continue;
+ for (int c = row.getFirstCellNum(); c >= 0 && c < row.getLastCellNum(); c++) {
+ Cell cell = row.getCell(c);
+ if (cell == null || cell.getCellType() != org.apache.poi.ss.usermodel.CellType.STRING) continue;
+ String v = cell.getStringCellValue();
+ if (v != null && YM_RANGE_CUM.matcher(v.trim()).matches()) set.add(c);
+ }
+ }
+ return set;
+ }
+
+ /** 鏈堜唤鏄犲皠鐨勫彲鐢ㄦ�у畧鍗細鍘诲勾涓庝粖骞� 1..month 鍚勬湀鍒楀繀椤婚綈鍏ㄤ笖鍒楀彿涓ユ牸閫掑锛�
+ * 浠讳竴涓嶆弧瓒筹紙琛ㄥご娌″啓鏈堜唤銆佹垨鎶撳埌鏉傛牸锛夊氨杩斿洖绌鸿〃锛岃皟鐢ㄦ柟閫�鍥炪�屾暣浣撳彸绉� 2 鍒椼�嶇殑鏃ц涓� */
+ private Map<Integer, Integer> usableMonthCols(Sheet sh, int year, int month) {
+ Map<Integer, Integer> usable = new LinkedHashMap<>();
+ Map<Integer, Integer> all = yearMonthCols(sh, year);
+ int prevLy = -1, prevCy = -1;
+ for (int m = 1; m <= month; m++) {
+ Integer ly = all.get((year - 1) * 100 + m);
+ Integer cy = all.get(year * 100 + m);
+ if (ly == null || cy == null || ly <= prevLy || cy <= prevCy) return new LinkedHashMap<>();
+ prevLy = ly;
+ prevCy = cy;
+ usable.put((year - 1) * 100 + m, ly);
+ usable.put(year * 100 + m, cy);
+ }
+ return usable;
+ }
+
+ /**
+ * 銆屼笂鏈堝悓姣斻�嶅叕寮� 鈫� 銆屾湰鏈堝悓姣斻�嶅叕寮忥細鍏紡閲屽紩鐢ㄥ埌鏈堜唤鍒楃殑寮曠敤鎸夎〃澶� (骞�,鏈�) 椤哄欢涓�涓湀锛�
+ * 鍏朵綑寮曠敤閫�鍥炪�屾暣浣撳彸绉� 2 鍒椼�嶃��
+ *
+ * 涓轰粈涔堜笉鑳戒竴寰嬪彸绉� 2 鍒楋細姣嶇増銆婂煄甯傚杩愩�嬮〉鍦� 2025 骞存鎻掍簡涓�鍒椼��2025骞�1-7鏈堢疮璁°�嶈緟鍔╁垪锛�
+ * 2025 鍚勬湀鍒椾粠 8 鏈堣捣涓嶅啀绛夎窛锛�2025骞�8鏈堝湪 AK銆佷笉鍦� AJ锛夛紝鍙崇Щ 2 鍒椾細钀藉埌杈呭姪鍒椾笂锛�
+ * 浜庢槸 8 鏈堝悓姣旇绠楁垚銆�8鏈堝�� 梅 2025骞�1-7鏈堢疮璁� 鈭� 1銆嶏紙2026-09-20 鐢ㄦ埛涓婃姤鐨勯棶棰橈級銆�
+ */
+ private String shiftFormulaToNextMonth(Sheet sh, String formula, int year, int month) {
+ if (formula == null || formula.isEmpty()) return formula;
+ Map<Integer, Integer> cols = usableMonthCols(sh, year, month);
+ if (cols.isEmpty()) return shiftFormulaColumns(formula, 2);
+ Map<Integer, Integer> colToYm = new LinkedHashMap<>();
+ for (Map.Entry<Integer, Integer> e : cols.entrySet()) colToYm.put(e.getValue(), e.getKey());
+ java.util.regex.Matcher m = A1_REF.matcher(formula);
+ StringBuffer sb = new StringBuffer();
+ while (m.find()) {
+ int idx = colIndexOf(m.group(2));
+ Integer ym = colToYm.get(idx);
+ Integer next = null;
+ if (ym != null) {
+ next = cols.get((ym / 100) * 100 + (ym % 100) + 1);
+ }
+ m.appendReplacement(sb, java.util.regex.Matcher.quoteReplacement(
+ m.group(1) + colLettersOf(next != null ? next : idx + 2) + m.group(3) + m.group(4)));
+ }
+ m.appendTail(sb);
+ return sb.toString();
+ }
+
+ /**
+ * 淇銆岀疮璁″悓姣斻�嶅垎姣嶃�傛瘝鐗堛�婂煄甯傚杩愩�嬮〉鎶� 2025 骞� 1..M 鏈堝悇鏈堝垪**鍜�**瀹冧滑鐨�
+ * 銆�2025骞�1-M鏈堢疮璁°�嶈緟鍔╁垪涓�璧峰啓杩涘垎姣嶏紙1..M-1 鏈堥噸澶嶈涓�娆°�佸綋鏈堟紡璁★級锛�
+ * 鍙︽湁鍦ㄦ瘝鐗堥噷鍒犳帀杈呭姪鍒楀悗娈嬬暀 #REF! 鐨勬儏褰紱涓ょ閮戒細璁╃疮璁″悓姣斾弗閲嶅け鐪�
+ * 锛�2026-09-20 鐢ㄦ埛涓婃姤锛氬煄甯傚杩� 8 鏈堝悓姣� 鈭�86.5%銆佺疮璁″悓姣� 鈭�43.5%锛夈��
+ * 缁熶竴鎸夎〃澶存妸鍒嗘瘝閲嶅啓涓恒�屽幓骞� 1..褰撴湀 鍚勬湀鍊煎垪涔嬪拰銆嶃��
+ *
+ * 2026-09-20 宸插湪銆�2026骞�8鏈堥亾璺繍杈撻噺姹囨�昏〃.xlsx銆嬫瘝鐗堥噷鍒犳帀璇ヨ緟鍔╁垪锛堝浠借
+ * docs/鐢熸垚姹囨�诲ぇ琛�/_bak_202608姣嶇増鍒犻櫎AJ鍒楀墠_20260920.xlsx锛夛紝姝e父鎯呭喌鏈柟娉曞懡涓� 0 鏍硷紱
+ * 淇濈暀瀹冩槸涓轰簡鍏滀綇銆屽悓鏈熷浠芥瘝鐗� / 鍘嗗彶閮ㄧ讲鍖� / 涔嬪悗鍙堟彃浜嗚緟鍔╁垪鐨勬瘝鐗堛�嶈繖绫绘儏鍐点��
+ */
+ public int repairCumulativeYoyFormulas(XSSFWorkbook wb, int year, int month) {
+ if (wb == null || month < 1) return 0;
+ int fixed = 0;
+ for (int i = 0; i < wb.getNumberOfSheets(); i++) {
+ Sheet sh = wb.getSheetAt(i);
+ if (sh == null || !isMonthLedgerSheet(sh.getSheetName())) continue;
+ int[] cum = cumulativeCols(sh, year);
+ if (cum == null) continue;
+ java.util.Set<Integer> helperCols = cumulativeHelperCols(sh);
+ Map<Integer, Integer> all = yearMonthCols(sh, year);
+ List<Integer> lastYearValueCols = new ArrayList<>();
+ int prev = -1;
+ for (int m = 1; m <= month; m++) {
+ Integer c = all.get((year - 1) * 100 + m);
+ if (c == null || c <= prev) {
+ lastYearValueCols.clear();
+ break;
+ }
+ prev = c;
+ lastYearValueCols.add(c);
+ }
+ if (lastYearValueCols.isEmpty()) continue;
+ for (int r = sh.getFirstRowNum(); r <= sh.getLastRowNum(); r++) {
+ Row row = sh.getRow(r);
+ if (row == null) continue;
+ Cell cc = row.getCell(cum[1]);
+ if (cc == null || cc.getCellType() != org.apache.poi.ss.usermodel.CellType.FORMULA) continue;
+ String f = cc.getCellFormula();
+ if (f == null || !cumulativeYoyBroken(f, helperCols)) continue;
+ // 娉ㄦ剰锛歅OI 鐨� setCellFormula 涓嶆帴鍙椾互 "=" 寮�澶寸殑鍏紡涓诧紙浼氭姏 FormulaParseException锛�
+ StringBuilder sb = new StringBuilder();
+ sb.append(cellRef(cum[0], r + 1)).append("/(");
+ for (int k = 0; k < lastYearValueCols.size(); k++) {
+ if (k > 0) sb.append('+');
+ sb.append(cellRef(lastYearValueCols.get(k), r + 1));
+ }
+ sb.append(")-1");
+ try {
+ cc.setCellFormula(sb.toString());
+ fixed++;
+ } catch (Exception ex) {
+ // 涓埆鍏紡鏀瑰啓澶辫触涓嶉樆濉炲鍑猴紙鎵撳紑鏃朵粛鎸夊師鍏紡閲嶇畻锛�
+ if (log != null) log.warn("绱鍚屾瘮鍏紡鏀瑰啓澶辫触锛歴heet={} cell={} 鍘熷紡={} 鏂板紡={}锛坽}锛�",
+ sh.getSheetName(), cellRef(cum[1], r + 1), f, sb, ex.toString());
+ }
+ }
+ }
+ if (fixed > 0 && log != null) {
+ log.info("姹囨�诲伐浣滅翱锛氱疮璁″悓姣斿垎姣嶄慨姝� {} 鏍硷紙绗� {} 鏈堬紝鍒嗘瘝鍙栧幓骞� 1..{} 鏈堝悇鏈堝�煎垪锛�", fixed, month, month);
+ }
+ return fixed;
+ }
+
+ /** 绱鍚屾瘮鍏紡鏄惁鈥滃潖浜嗏�濓細鍚� #REF!锛屾垨鍒嗘瘝寮曠敤浜嗗尯闂寸疮璁¤緟鍔╁垪锛堜笌鍚勬湀鍒楅噸澶嶈鍏ワ級 */
+ private boolean cumulativeYoyBroken(String formula, java.util.Set<Integer> helperCols) {
+ if (formula.contains("#REF!")) return true;
+ java.util.regex.Matcher m = A1_REF.matcher(formula);
+ while (m.find()) {
+ if (helperCols.contains(colIndexOf(m.group(2)))) return true;
+ }
+ return false;
+ }
+
+ /** 璇ラ〉銆岀疮璁� / 绱鍚屾瘮銆嶄袱鍒楋紙0 鍩猴級锛屾寜琛ㄥご鍓� 5 琛屾壘 鈥滅疮璁♀�� 鎴� 鈥渰year}骞寸疮璁♀�濓紝涓斿叾鍙冲垪鍚� 鈥滃悓姣斺�� */
+ private int[] cumulativeCols(Sheet sh, int year) {
+ int last = Math.min(sh.getLastRowNum(), sh.getFirstRowNum() + 4);
+ for (int r = sh.getFirstRowNum(); r <= last; r++) {
+ Row row = sh.getRow(r);
+ if (row == null) continue;
+ for (int c = row.getFirstCellNum(); c >= 0 && c < row.getLastCellNum(); c++) {
+ Cell cell = row.getCell(c);
+ if (cell == null || cell.getCellType() != org.apache.poi.ss.usermodel.CellType.STRING) continue;
+ String v = cell.getStringCellValue();
+ if (v == null) continue;
+ v = v.trim();
+ if (!"绱".equals(v) && !(year + "骞寸疮璁�").equals(v)) continue;
+ Cell nxt = row.getCell(c + 1);
+ if (nxt == null || nxt.getCellType() != org.apache.poi.ss.usermodel.CellType.STRING) continue;
+ String nt = nxt.getStringCellValue();
+ if (nt != null && nt.contains("鍚屾瘮")) return new int[]{c, c + 1};
+ }
+ }
+ return null;
+ }
+
/** 鏈堜唤瀹归噺锛氫紭鍏堝彇琛ㄥご锛堝墠 5 琛岋級鈥�2026鈥︾疮璁♀�濆垪鍙嶆帹锛涜揣杩愰〉鏃犺鏂囨锛�
* 鍐嶇敤琛ㄥご閲屾渶鍚庝竴涓��2026骞碝鏈堚��/鏃ユ湡鏍煎紡鐨勬湀鍒楀厹搴曪紙濡傝揣杩� Q3=2026-08-01 -> 8锛� */
private int monthColumnCapacity(Sheet sh) {
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 03e2803..50c6da6 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
@@ -3546,13 +3546,15 @@
int dbFilled = summaryWorkbookFiller.fillMonthlyLedger(wb, effPeriod, year, effMonth, dbProblems);
int yoyFilled = summaryWorkbookFiller.ensureMonthYoyFormulas(wb, year, effMonth);
int monthFormulaFilled = summaryWorkbookFiller.ensureMonthFormulas(wb, year, effMonth);
+ // 绱鍚屾瘮鍒嗘瘝淇锛氭瘝鐗堟妸銆屽幓骞村悇鏈堛�嶄笌銆屽幓骞�1-M鏈堢疮璁°�嶈緟鍔╁垪鍚屾椂璁″叆锛堥噸澶嶈/婕忓綋鏈堬級
+ int cumYoyFixed = summaryWorkbookFiller.repairCumulativeYoyFormulas(wb, year, effMonth);
int rankRefreshed = refreshSummaryRankSheets(wb, effPeriod, "month");
int cumulativeRefreshed = refreshSummaryCumulativeSheets(wb, year, effMonth); // 鍥涘紶璺ㄩ〉鍚堟垚椤甸殢鎶ヨ〃鏈熷埛鏂�
int widthApplied = applySummaryReferenceLayout(wb);
log.info("姹囨�诲伐浣滅翱鏁版嵁椹卞姩鍥炲~瀹屾垚锛氬啓鍏ュ綋鏈堝�兼牸鏁�={}锛岃ˉ鍐欏綋鏈堝悓姣斿叕寮忔牸鏁�={}锛岃ˉ鍐欏綋鏈堝悎璁″叕寮忔牸鏁�={}锛�"
- + "鍒锋柊鎺掑悕椤垫暟鍊兼牸鏁�={}锛屽埛鏂板洓椤碉紙鍩庡競姹囨��/鍩庡競鍒嗗競宸�/涓彛寰勫垎鏋�/閬撹矾杩愯緭鍛ㄨ浆閲忥級鏁板�兼牸鏁�={}锛�"
+ + "淇绱鍚屾瘮鍒嗘瘝鏍兼暟={}锛屽埛鏂版帓鍚嶉〉鏁板�兼牸鏁�={}锛屽埛鏂板洓椤碉紙鍩庡競姹囨��/鍩庡競鍒嗗競宸�/涓彛寰勫垎鏋�/閬撹矾杩愯緭鍛ㄨ浆閲忥級鏁板�兼牸鏁�={}锛�"
+ "鎸夈�婄敓鎴恄閬撹矾杩愯緭閲忔眹鎬昏〃銆嬪榻愬垪瀹藉垪鏁�={}锛岀己鏁版彁绀�={}",
- dbFilled, yoyFilled, monthFormulaFilled, rankRefreshed, cumulativeRefreshed, widthApplied, dbProblems);
+ dbFilled, yoyFilled, monthFormulaFilled, cumYoyFixed, rankRefreshed, cumulativeRefreshed, widthApplied, dbProblems);
applyTwoDecimalFormat(wb); // 鏁板�兼樉绀轰袱浣嶅皬鏁帮紙淇濈暀鍏ㄧ簿搴︼級锛�% / 鏃ユ湡绛夋棦鏈夋牱寮忎笉鏀瑰彉
int inlineFixed = normalizeStaleInlineStrings(wb); // 娓呮帀銆岄潪 inlineStr 鍗存畫鐣� <is>銆嶇殑闈炴硶鏍硷紝鍚﹀垯 Excel 鎷掔粷鎵撳紑
if (inlineFixed > 0) log.warn("姹囨�诲伐浣滅翱娓呮帀娈嬬暀 inlineStr 闈炴硶鏍� {} 涓紙姣嶇増鐢� openpyxl 鍐欏嚭鏃剁殑鍏稿瀷闂锛�", inlineFixed);
@@ -5428,6 +5430,7 @@
hssfText(row, 0, "鍚堣");
InvestAgg prov = new InvestAgg();
for (InvestmentMonthly m : monthlies) prov.add(m, pmap.get(m.getProjectId()));
+ addProjectsWithoutMonthly(prov, projects, mByProject, null, null);
writeInvestAggHssf(row, prov);
continue;
}
@@ -5440,6 +5443,7 @@
InvestmentProject p = pmap.get(m.getProjectId());
if (p != null && blockCategory.equals(p.getCategory())) agg.add(m, p);
}
+ addProjectsWithoutMonthly(agg, projects, mByProject, blockCategory, null);
writeInvestAggHssf(row, agg);
seq = 0;
continue;
@@ -5468,6 +5472,7 @@
if (p != null && city.equals(p.getCity())
&& (blockCategory == null || blockCategory.equals(p.getCategory()))) agg.add(m, p);
}
+ addProjectsWithoutMonthly(agg, projects, mByProject, blockCategory, city);
writeInvestAggHssf(row, agg);
continue;
}
@@ -5515,6 +5520,24 @@
if (agg.yearPlan > 0) hssfNum(row, 23, agg.yearCum / agg.yearPlan);
}
+ /**
+ * 琛ヨ銆屾湰鏈熸病鏈夋湀搴﹁褰曘�佷絾椤圭洰涓绘。鏈夋�绘姇璧勩�嶇殑椤圭洰锛堝彧璁℃�绘姇璧勮繖涓�鍒楋級銆�
+ * 鍦烘櫙锛氭煇甯傚窞鏈湀鏈姤閫佸崟琛紙濡傛姹� 8 鏈堢墿娴侊級锛屼富妗i噷椤圭洰浠嶅湪锛岃嫢涓嶈ˉ璁★紝璇ュ競宸炲皬璁�/鍚堣浼氭暣鍧椾负绌恒��
+ *
+ * @param category 鍧楃被鍒紙瀹㈣繍绔欏満/鐗╂祦鍥尯锛夛紱null 琛ㄧず涓嶉檺
+ * @param city 甯傚窞鍏ㄧО锛堝 姝︽眽甯傦級锛沶ull 琛ㄧず涓嶉檺
+ */
+ private void addProjectsWithoutMonthly(InvestAgg agg, List<InvestmentProject> projects,
+ Map<Long, InvestmentMonthly> mByProject,
+ String category, String city) {
+ for (InvestmentProject p : projects) {
+ if (p == null || mByProject.containsKey(p.getId())) continue;
+ if (category != null && !category.equals(p.getCategory())) continue;
+ if (city != null && !city.equals(p.getCity())) continue;
+ if (p.getTotalInvestment() != null) agg.total += p.getTotalInvestment();
+ }
+ }
+
// ==================== 鎶曡祫妯″潡锛氬杩愮珯鎶曡祫鏄庣粏琛� / 鐗╂祦绔欏満鎶曡祫鏄庣粏锛堟ā鏉垮簳绋垮師浣嶆浛鎹級 ====================
diff --git a/traffic-audit-web/src/views/ReportExport.vue b/traffic-audit-web/src/views/ReportExport.vue
index 8448ec1..f78d81a 100644
--- a/traffic-audit-web/src/views/ReportExport.vue
+++ b/traffic-audit-web/src/views/ReportExport.vue
@@ -420,28 +420,28 @@
{
name: '閬撹矾璐ц繍',
rows: mk([
- ['褰撴湀璐ц繍閲�(涓囧惃)', '鍏ㄧ渷璐ц繍閲徛峰綋鏈�'],
- ['褰撴湀璐х墿鍛ㄨ浆閲�(涓囧惃)', '鍏ㄧ渷璐х墿鍛ㄨ浆閲徛峰綋鏈�', '鍏ㄧ渷璐х墿鍛ㄨ浆閲徛峰綋鏈堝悓姣�'],
- ['绱璐ц繍閲�(涓囧惃)', '鍏ㄧ渷璐ц繍閲徛风疮璁�'],
+ ['褰撴湀璐ц繍閲�(涓囧惃)', '鍏ㄧ渷璐ц繍閲徛峰綋鏈�', '鍏ㄧ渷璐ц繍閲徛峰綋鏈堝悓姣�'],
+ ['褰撴湀璐х墿鍛ㄨ浆閲�(涓囧惃鍏噷)', '鍏ㄧ渷璐х墿鍛ㄨ浆閲徛峰綋鏈�', '鍏ㄧ渷璐х墿鍛ㄨ浆閲徛峰綋鏈堝悓姣�'],
+ ['绱璐ц繍閲�(涓囧惃)', '鍏ㄧ渷璐ц繍閲徛风疮璁�', '鍏ㄧ渷璐ц繍閲徛风疮璁″悓姣�'],
['绱璐х墿鍛ㄨ浆閲�(涓囧惃鍏噷)', '鍏ㄧ渷璐х墿鍛ㄨ浆閲徛风疮璁�', '鍏ㄧ渷璐х墿鍛ㄨ浆閲徛风疮璁″悓姣�']
])
},
{
name: '鍩庡競瀹㈣繍',
rows: mk([
- ['褰撴湀鍩庡競瀹㈣繍閲�:', '鍩庡競瀹㈣繍閲徛峰綋鏈�'],
- ['褰撴湀鍩庡競瀹㈣繍鍛ㄨ浆閲�', '鍩庡競瀹㈣繍鍛ㄨ浆閲徛峰綋鏈�'],
- ['绱鍩庡競瀹㈣繍閲�:', '鍩庡競瀹㈣繍閲徛风疮璁�'],
- ['绱鍩庡競瀹㈣繍鍛ㄨ浆閲�', '鍩庡競瀹㈣繍鍛ㄨ浆閲徛风疮璁�']
+ ['褰撴湀鍩庡競瀹㈣繍閲�', '鍩庡競瀹㈣繍閲徛峰綋鏈�', '鍩庡競瀹㈣繍閲徛峰綋鏈堝悓姣�'],
+ ['褰撴湀鍩庡競瀹㈣繍鍛ㄨ浆閲�', '鍩庡競瀹㈣繍鍛ㄨ浆閲徛峰綋鏈�', '鍩庡競瀹㈣繍鍛ㄨ浆閲徛峰綋鏈堝悓姣�'],
+ ['绱鍩庡競瀹㈣繍閲�', '鍩庡競瀹㈣繍閲徛风疮璁�', '鍩庡競瀹㈣繍閲徛风疮璁″悓姣�'],
+ ['绱鍩庡競瀹㈣繍鍛ㄨ浆閲�', '鍩庡競瀹㈣繍鍛ㄨ浆閲徛风疮璁�', '鍩庡競瀹㈣繍鍛ㄨ浆閲徛风疮璁″悓姣�']
])
},
{
name: '涓彛寰�',
rows: mk([
- ['褰撴湀涓彛寰勫杩愰噺', '涓彛寰勫杩愰噺路褰撴湀'],
- ['褰撴湀涓彛寰勫懆杞噺', '涓彛寰勫懆杞噺路褰撴湀'],
- ['绱涓彛寰勫杩愰噺', '涓彛寰勫杩愰噺路绱'],
- ['绱涓彛寰勫懆杞噺', '涓彛寰勫懆杞噺路绱']
+ ['褰撴湀涓彛寰勫杩愰噺', '涓彛寰勫杩愰噺路褰撴湀', '涓彛寰勫杩愰噺路褰撴湀鍚屾瘮'],
+ ['褰撴湀涓彛寰勫懆杞噺', '涓彛寰勫懆杞噺路褰撴湀', '涓彛寰勫懆杞噺路褰撴湀鍚屾瘮'],
+ ['绱涓彛寰勫杩愰噺', '涓彛寰勫杩愰噺路绱', '涓彛寰勫杩愰噺路绱鍚屾瘮'],
+ ['绱涓彛寰勫懆杞噺', '涓彛寰勫懆杞噺路绱', '涓彛寰勫懆杞噺路绱鍚屾瘮']
])
}
]
@@ -629,4 +629,4 @@
.pv-dialog { border-radius: 10px; overflow: hidden; }
.pv-dialog .el-dialog__header { cursor: move; user-select: none; -webkit-user-select: none; }
.pv-dialog .el-dialog__headerbtn { cursor: pointer; }
-</style>
\ No newline at end of file
+</style>
--
Gitblit v1.9.1