From ea7cc07ceb578d50d9ff83eb6d7e173f5b1cce1d Mon Sep 17 00:00:00 2001
From: zhizhijie <zhizhijie@users.noreply.gitee.com>
Date: 星期日, 13 九月 2026 13:17:49 +0800
Subject: [PATCH] feat: 汇总大表四页(城市汇总/城市分市州/中口径分析/道路运输周转量)随报表期数据驱动刷新至 1-8月

---
 docs/工作日结/工作日结_2026-09-13.md                                                                      |   60 +++++
 traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java |  496 +++++++++++++++++++++++++++++++++++++++++
 docs/功能测试报告/功能测试报告_汇总大表四页数据驱动_2026-09-13.md                                                       |  135 +++++++++++
 3 files changed, 689 insertions(+), 2 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_\346\261\207\346\200\273\345\244\247\350\241\250\345\233\233\351\241\265\346\225\260\346\215\256\351\251\261\345\212\250_2026-09-13.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\233\233\351\241\265\346\225\260\346\215\256\351\251\261\345\212\250_2026-09-13.md"
new file mode 100644
index 0000000..4b7b719
--- /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\233\233\351\241\265\346\225\260\346\215\256\351\251\261\345\212\250_2026-09-13.md"
@@ -0,0 +1,135 @@
+# 鍔熻兘娴嬭瘯鎶ュ憡_姹囨�诲ぇ琛ㄥ洓椤垫暟鎹┍鍔╛2026-09-13
+
+## 涓�銆佸姛鑳借鏄�
+
+### 1. 鑳屾櫙
+
+鐢ㄦ埛鍙嶉锛氬鍑� 2026 骞� 8 鏈堛�婇亾璺繍杈撻噺姹囨�昏〃銆嬪悗锛屼互涓� 4 寮�**璺ㄩ〉鍚堟垚椤�**浠嶆槸涓婁竴鎶ヨ〃鏈熺殑闈欐�佸�硷紙鏍囬鍐欍��2026骞�1-7鏈� / 2026骞�7鏈堛�嶏紝鏁板�间篃鏄� 7 鏈堢殑锛屼笉闅忔姤琛ㄦ湡鍙樺寲锛夛細
+
+| 椤靛悕 | 姣嶇増鍘熺姸鎬� |
+| --- | --- |
+| `鍩庡競姹囨�籤 | 鏁撮〉闈欐�侊紙1-7 鏈堢疮璁� + 7 鏈堝綋鏈堬級 |
+| `鍩庡競鍒嗗競宸瀈 | 4 鍧楁暣椤甸潤鎬� |
+| `涓彛寰勫垎鏋恅 | 2 鍧楁暣椤甸潤鎬� |
+| `閬撹矾杩愯緭鍛ㄨ浆閲廯 | 2 鍧楁暣椤甸潤鎬� |
+
+鐢ㄦ埛閫夊畾**鏂规 A**锛氭部鐢ㄨ揣杩愭帓鍚嶉〉鐨勫仛娉曗�斺�旂敤姣嶇増鍙拌处椤佃嚜甯︾殑 2025 骞村悓鏈熷垪缂撳瓨鍊煎綋鍚屾瘮鍩烘暟锛屾妸銆屽綋骞寸疮璁″�笺�嶅埛鎴� 1-8 鏈堬紙鍚屾瘮鍒楁部鐢ㄦ瘝鐗堝彛寰勶級锛�4 椤典竴娆℃�у仛鍑烘潵銆�
+
+### 2. 鍙e緞锛堝厛楠岃瘉銆佸悗缂栫爜锛�
+
+缂栫爜鍓嶅厛鐢ㄦ瘝鐗堝彴璐﹂〉閫愭牸鑱氬悎鍙嶆帹鍥涢〉鍙e緞锛屼笌鍥涢〉鎴愬搧閫愭牸姣斿 **0 宸紓**鍚庣‘璁わ細
+
+| 鎸囨爣 | 鍙e緞 |
+| --- | --- |
+| 鍩庡競瀹㈣繍閲� | 鍏氦鍩庡競鍐呭杩愰噺 + 宸℃父鍑虹鍩庡競鍐呭杩愰噺 + 缃戠害杞﹀煄甯傚唴瀹㈣繍閲� + 杞ㄩ亾瀹㈣繍閲� + 杞浮瀹㈣繍閲� |
+| 鍩庡競瀹㈣繍鍛ㄨ浆閲� | 鍚屼笂锛屾崲鎴愬悇鑷梾瀹㈠懆杞噺 |
+| 涓彛寰勫杩愰噺/鍛ㄨ浆閲� | 鍏矾鐝嚎鍖呰溅 + 鍩庨檯鍩庝埂鍏氦 + 鍩庨檯鍩庝埂宸℃父鍑虹 + 鍩庨檯鍩庝埂缃戠害杞︼紝鍏朵腑銆屽煄闄呭煄涔� X = X 鎬婚噺 鈭� X 鍩庡競鍐呫�嶏紙浠呭叕浜�/鍑虹/缃戠害杞︼紱鐝嚎鍖呰溅鏃犲煄甯傚唴姒傚康锛岀洿鎺ョ敤鎬婚噺锛� |
+| 閬撹矾璐ц繍鍛ㄨ浆閲� | 璐ц繍椤靛競宸炪�岃涓婅揣鐗╁懆杞噺 + 瑙勪笅璐х墿鍛ㄨ浆閲忋�嶏紙**涓嶇敤**姣嶇増銆岃涓�+瑙勪笅銆嶅叕寮忚锛� |
+| 閬撹矾杩愯緭鍛ㄨ浆閲忛〉銆岄亾璺杩愬懆杞噺銆� | 鐝嚎鍖呰溅鍛ㄨ浆閲� + 鍩庨檯鍩庝埂鍏氦/鍑虹/缃戠害杞﹀懆杞噺 |
+| 鍚屾瘮 | 褰撴湡 梅 姣嶇増鍙拌处椤� 2025 骞村悓鏈熷垪 鈭� 1 |
+
+**鍏充簬 2025 鍚屾湡鍩烘暟**锛氬簱涓彧鏈� 2026 骞村煄甯傚杩�/缃戠害杞︽暟鎹紝娌℃湁 2025 骞存暟鎹紝鏁� 2025 鍚屾湡涓�寰嬪彇**姣嶇増鍙拌处椤佃嚜甯︾殑 2025 骞撮�愭湀鍒楃紦瀛樺��**锛圴=1鏈堛�乆=2鏈� 鈥� AJ=8鏈堬級銆傝繖涔熸鏄柟妗� A 鐨勫彇宸х偣锛氭瘝鐗堝彴璐﹂〉鏈韩甯﹀叏 2025 閫愭湀鍒楋紝鏃犻渶绛� 2025 鏁版嵁鍏ュ簱銆�
+
+### 3. 瀹炵幇
+
+鏀瑰姩鏂囦欢锛歚traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java`锛�+494 鈭�2锛夈��
+
+- 鏂板鍏ュ彛 `refreshSummaryCumulativeSheets(XSSFWorkbook wb, int year, int month)`锛涙帴鍦ㄥ鍑洪摼璺殑 `refreshSummaryRankSheets(...)` 涔嬪悗銆乣applySummaryReferenceLayout(wb)` 涔嬪墠璋冪敤銆�
+- 鍙拌处鍙栨暟 `smReadLedgerMetrics`锛�**鎸夎鏍囩璇嗗埆銆佷笉鍐欐琛屽彿**
+  - `鍏氦`/`鍑虹`/`缃戠害杞锛氭瘡甯傚窞銆屽杩愰噺 / 鏃呭鍛ㄨ浆閲� / 鍏朵腑鍩庡競鍐呭杩愰噺 / 鍏朵腑鍩庡競鍐呮梾瀹㈠懆杞噺銆�4 琛岋紱
+  - `杞ㄩ亾銆佽疆娓锛氳建閬擄紙鍏ㄧ渷/姝︽眽/榛勭煶锛変笌杞浮锛堝叏鐪�/姝︽眽锛夊垎鍧楋紱
+  - `鐝嚎鍖呰溅`锛氬叏鐪佷笌 17 甯傚窞瀹㈣繍閲�/鍛ㄨ浆閲忥紙銆屽叾涓釜浣撱�嶈涓嶉噸澶嶈鍏ワ級锛�
+  - ` 璐ц繍`锛堥〉鍚嶅甫鍓嶅绌烘牸锛夛細甯傚窞銆岃涓婅揣鐗╁懆杞噺 + 瑙勪笅璐х墿鍛ㄨ浆閲忋�嶃��
+- 鏈堜唤鍒楋細2026 骞撮�愭湀鍒� C=1鏈� 鈥� Q=8鏈堬紙`SM_CUR_COL0=2`锛夛紝2025 骞村悓鏈熷垪 V=1鏈� 鈥� AJ=8鏈堬紙`SM_LAST_COL0=21`锛夛紝姣忔湀闂撮殧 2 鍒楋紙鍊煎垪 + 鍚屾瘮鍒楋級銆�
+- 19 缁存寚鏍囦綅锛坄SM_DIM=19`锛夛細鍏氦/鍑虹/缃戠害杞� 鍚� 4 缁达紙鎬婚噺銆佸懆杞噺銆佸煄甯傚唴鎬婚噺銆佸煄甯傚唴鍛ㄨ浆閲忥級+ 杞ㄩ亾 2 缁� + 杞浮 2 缁� + 鐝嚎鍖呰溅 2 缁� + 璐ц繍鍛ㄨ浆閲� 1 缁淬��
+- 鍐欏�艰鍒� `smSetVal`锛�**鐩爣鏍煎師鏈槸鍏紡 鈫� 淇濈暀姣嶇増鍏紡涓嶈鐩�**锛堟墦寮�鍗抽噸绠楋級锛涚洰鏍囨牸涓虹┖涓旀柊鍊间负 0 鈫� 涓嶆柊澧烇紱鍏朵綑鍏� `setBlank()` 鍐嶅啓锛岄伩鍏� inlineStr 娈嬬暀銆�
+- 鍥涢〉瀹為檯鍐欏叆 **1056 鏍�**銆�
+
+## 浜屻�佹祴璇曠幆澧�
+
+- 鍚庣 `http://localhost:8090`锛坄start-dev.ps1` 鍚姩锛孭ID 27840锛夛紝鍓嶇 `http://localhost:8080`锛圥ID 23416锛夊潎灏辩华銆�
+- 姣嶇増锛歚docs/鐢熸垚姹囨�诲ぇ琛�/2026骞�8鏈堥亾璺繍杈撻噺姹囨�昏〃.xlsx`锛涚増寮忓弬鐓э細`docs/鐢熸垚姹囨�诲ぇ琛�/鐢熸垚_閬撹矾杩愯緭閲忔眹鎬昏〃.xlsx`銆�
+- 瀵煎嚭鎺ュ彛锛歚GET /api/report/export/summaryWorkbook?period=YYYY-MM`锛圔earer token锛夈��
+- 娴嬭瘯鏃堕棿锛�2026-09-13銆�
+- 娴嬭瘯浜х墿锛歚_t3_2026-08.xlsx`锛�950,783 瀛楄妭 / HTTP 200 / 36.8 绉掞級銆乣_t3_2026-07.xlsx`锛�942,691 瀛楄妭 / HTTP 200 / 25.7 绉掞級锛涘綊妗d欢 `docs/鐢熸垚姹囨�诲ぇ琛�/杈撳嚭/鐢熸垚_閬撹矾杩愯緭閲忔眹鎬昏〃_2026-08_鍥涢〉鏁版嵁椹卞姩_2026-09-13.xlsx`锛�950,783 瀛楄妭锛夈��
+- 鐙珛澶嶆牳鑴氭湰锛歚_v5_four.py`锛堣緭鍑� `_v5_four.txt`锛夈�乣_verify_four.py`锛堣緭鍑� `_verify_four.txt`锛夈��
+
+## 涓夈�佺敤渚嬭〃
+
+### 3.1 姝e悜鐢ㄤ緥
+
+| 缂栧彿 | 杈撳叆 | 棰勬湡 | 瀹為檯 | 缁撹 |
+| --- | --- | --- | --- | --- |
+| TC-1 | 瀵煎嚭 `period=2026-08` | HTTP 200锛屾甯镐骇鍑� | 950,783 瀛楄妭锛�36.8 绉� | 閫氳繃 |
+| TC-2 | 涓� 09-13 13:06 褰掓。浠舵瘮瀵� | 鍚屽弬鏁板鍑虹粨鏋滅‘瀹� | 涓ゆ浜х墿鍚屼负 950,783 瀛楄妭 | 閫氳繃 |
+| TC-3 | 鍚庣鍥炲~鏃ュ織 | 鏈夊洓椤靛埛鏂扮粺璁°�佹棤缂烘暟鎻愮ず銆佹棤寮傚父 | 銆屽埛鏂板洓椤碉紙鍩庡競姹囨��/鍩庡競鍒嗗競宸�/涓彛寰勫垎鏋�/閬撹矾杩愯緭鍛ㄨ浆閲忥級鏁板�兼牸鏁�=1056銆嶃�屽埛鏂版帓鍚嶉〉鏁板�兼牸鏁�=711銆嶃�岀己鏁版彁绀�=[]銆嶏紱鏈�杩� 4MB 鏃ュ織鏃� `ERROR`/`Exception`/`WARN` | 閫氳繃 |
+| TC-4 | `鍩庡競姹囨�籤 鏍囬 | 闅忔姤琛ㄦ湡鏀逛负 1-8 鏈� / 8 鏈� | `A1=2026骞�1-8鏈堝叏鐪佺疮璁″畬鎴愬煄甯傚杩愰噺鎯呭喌`銆乣A12=2026骞�8鏈堝叏鐪佸畬鎴愬煄甯傚杩愰噺鎯呭喌` | 閫氳繃 |
+| TC-5 | `鍩庡競姹囨�籤 绱鍧楋紙B3:E9锛� | 瀹㈣繍閲�/鍚屾瘮/鍛ㄨ浆閲�/鍚屾瘮 鍚� 7 琛� | 28 鏍煎叏閮ㄤ竴鑷达紙濡� B3=269628.07銆丆3=0.00117銆丏3=1681467.65銆丒3=0.00835锛� | 閫氳繃 |
+| TC-6 | `鍩庡競姹囨�籤 褰撴湀鍧楋紙B14:E20锛� | 鍚屼笂锛屽綋鏈堝彛寰� | 28 鏍煎叏閮ㄤ竴鑷达紙濡� B14=32215.74銆丆14=0.0444锛� | 閫氳繃 |
+| TC-7 | `鍩庡競鍒嗗競宸瀈 鏍囬 脳4 | 4 鍧楁爣棰橀殢鎶ヨ〃鏈� | `A1=鈥�1-8鏈堢疮璁℃儏鍐礰銆乣A23=鈥�1-8鏈堢疮璁℃儏鍐礰銆乣A46=鈥�8鏈堟儏鍐礰銆乣A68=鈥�8鏈堟儏鍐礰 | 閫氳繃 |
+| TC-8 | `鍩庡競鍒嗗競宸瀈 4 鍧� 脳 17 甯傚窞 脳 6 鍊煎垪 | 6 缁勫�� = 鎬婚噺/鍏氦/鍑虹/缃戠害杞�/杞ㄩ亾/杞浮 | 408 鏍煎叏閮ㄤ竴鑷� | 閫氳繃 |
+| TC-9 | `涓彛寰勫垎鏋恅 鏍囬 + 鏁板�� | 2 鍧楁爣棰� + 姣忓潡 鎬�/鐝嚎/鍩庝埂鍏氦/鍩庝埂鍑虹/鍩庝埂缃戠害杞� | `A1=1-8鏈堜腑鍙e緞瀹㈣繍閲忓強鍛ㄨ浆閲廯銆乣A10=8鏈堜腑鍙e緞瀹㈣繍閲忓強鍛ㄨ浆閲廯锛汢3=31528.0607銆丗3=1227147.4890 绛� 10 鏍煎叏閮ㄤ竴鑷� | 閫氳繃 |
+| TC-10 | `閬撹矾杩愯緭鍛ㄨ浆閲廯 鏍囬 + 鏁板�� | 2 鍧楁爣棰� + 17 甯傚窞 G/L/Q/W/X/Y | `A1=2026骞�1-8鏈堝叏鐪佺疮璁″畬鎴愪氦閫氬懆杞噺鎯呭喌`銆乣A23=2026骞�8鏈堝叏鐪佸畬鎴愪氦閫氬懆杞噺鎯呭喌`锛�102 鏍煎叏閮ㄤ竴鑷达紙濡� G4=17492129.04788293銆丩4=269628.07銆丵4=1227147.48902锛沇/X/Y 鍚屾湡鍒楀彇 2025 骞村悓鏈熺疮璁★紝濡� W4=17492068.4575銆乆4=269312.48銆乊4=1256684.2157锛� | 閫氳繃 |
+
+### 3.2 璐熷悜鐢ㄤ緥
+
+| 缂栧彿 | 杈撳叆 | 棰勬湡 | 瀹為檯 | 缁撹 |
+| --- | --- | --- | --- | --- |
+| TC-N1 | 鐩爣鏍兼槸姣嶇増鍏紡锛坄鍩庡競鍒嗗競宸瀈 鍏ㄧ渷琛� `B5=G5+L5+Q5+V5+X5`銆乣閬撹矾杩愯緭鍛ㄨ浆閲廯 `J4=G4/W4-1`锛� | 涓嶈鍐欏�艰鐩栵紝淇濈暀姣嶇増鍏紡 | 涓よ�呬粛涓哄叕寮忥紱鍥涢〉鍐欏叆鏍兼暟 1056 < 鍥涢〉鐞嗚鏍兼暟锛岃鏄庡叕寮忔牸琚烦杩� | 閫氳繃 |
+| TC-N2 | 鐩爣鏍间负绌轰笖鏂板�间负 0 | 涓嶆柊澧� 0锛岄伩鍏嶆妸鎴愬搧椤靛啓鎴愭弧椤� 0 | `SM_璐ц繍` 鏃犳暟鎹殑甯傚窞杞ㄩ亾/杞浮鍊兼湭浜х敓鏂板 0 鏍� | 閫氳繃 |
+| TC-N3 | 2025 鍚屾湡鏃犲簱鏁版嵁 | 鍙栨瘝鐗堝彴璐﹂〉 2025 鍒楃紦瀛橈紝涓嶅嚭鐜� NaN/Inf | 鍚屾瘮鍏ㄩ儴涓烘湁闄愭暟锛堝 `鍩庡競姹囨�� C7=0.4870`銆乣C14=0.0444`锛� | 閫氳繃 |
+| TC-N4 | 鍙拌处椤佃涓嶅埌甯傚窞鏁版嵁锛堟瀬绔儏鍐碉級 | 璁� `WARN` 骞�**淇濇寔姣嶇増鍘熷��**銆佷笉鍐欏潖椤� | 浠g爜璺緞 `curCum.isEmpty()` 鈫� `log.warn("鈥﹀彴璐﹂〉鏈鍒板競宸炴暟鎹紝璺宠繃锛堜繚鎸佹瘝鐗堝師鍊硷級")`锛涙湰杞彴璐﹂〉鏁版嵁榻愬叏锛屾湭瀹為檯瑙﹀彂锛�**浠g爜瀹℃煡鐢ㄤ緥**锛� | 閫氳繃锛堝鏌ワ級 |
+| TC-N5 | 姣嶇増鏍囬涓� inlineStr | 鏍囬蹇呴』鐪熸钀界洏鏇存柊锛屼笉鑳藉彧鏀� `<v>` | `smSetTitle` 鍏� `setBlank()` 鍐嶅啓锛屾爣棰樻牎楠屽叏閮ㄨ鍙栧埌鏂版枃妗� | 閫氳繃 |
+
+### 3.3 鍥炲綊鐢ㄤ緥
+
+| 缂栧彿 | 杈撳叆 | 棰勬湡 | 瀹為檯 | 缁撹 |
+| --- | --- | --- | --- | --- |
+| TC-R1 | 瀵煎嚭 `period=2026-07` | 涓嶅穿锛屼笖鍥涢〉搴斿洖閫�鎴愩��1-7 鏈堛�嶅彛寰� | HTTP 200 / 942,691 瀛楄妭 / 25.7 绉掞紱鏍囬 `鍩庡競姹囨�� A1=2026骞�1-7鏈堚�銆乣鍩庡競瀹㈣繍瀹㈣繍閲忓垎甯傚窞1-7鏈堢疮璁℃儏鍐礰銆乣1-7鏈堜腑鍙e緞瀹㈣繍閲忓強鍛ㄨ浆閲廯銆乣2026骞�1-7鏈堝叏鐪佺疮璁″畬鎴愪氦閫氬懆杞噺鎯呭喌` | 閫氳繃 |
+| TC-R2 | 2026-07 瀵煎嚭鍊� vs 姣嶇増 1-7 鏈堥潤鎬佹潈濞佸�� | **搴斿畬鍏ㄤ竴鑷�**锛堣瘉鏄庡彛寰勪笌姣嶇増涓�鑷达紝鍙槸闅忔湀浠藉欢闀匡級 | 鍩庡競姹囨�� B3=237412.33000000002锛堟瘝鐗� 237412.33锛夈�佷腑鍙e緞 B3=27524.4906銆侀亾璺繍杈撳懆杞噺 G4=15222118.44638293銆佸煄甯傚垎甯傚窞 B6=135474.77989442425 鈥斺�� 涓庢瘝鐗堥�愰」涓�鑷� | 閫氳繃 |
+| TC-R3 | 鍚庣鏈嶅姟鍙敤鎬� | 鍓嶇棣栭〉鍙闂� | `http://localhost:8080/` HTTP 200锛屾爣棰樸�屼氦閫氱粺璁℃姤琛ㄥ鏍哥郴缁熴�� | 閫氳繃 |
+
+### 3.4 閫愭牸鐙珛澶嶆牳锛堝叧閿瘉鎹級
+
+**鏂规硶**锛氫粠鐢熸垚浠�**鑷韩鐨勫彴璐﹂〉**閲嶆柊鑱氬悎锛堜笉璇诲簱銆佷笉鍙傝�冧换浣曞叾瀹冩枃浠讹級锛屽啀涓庡洓椤甸�愭牸姣斿銆�
+
+| 澶嶆牳鑼冨洿 | 鏍兼暟 |
+| --- | --- |
+| 鏍囬锛堝煄甯傛眹鎬� 2 + 鍩庡競鍒嗗競宸� 4 + 涓彛寰� 2 + 閬撹矾杩愯緭鍛ㄨ浆閲� 2锛� | 10 |
+| 鍩庡競姹囨�� 绱鍧楋紙7 琛� 脳 瀹㈣繍閲�/鍚屾瘮/鍛ㄨ浆閲�/鍚屾瘮锛� | 28 |
+| 鍩庡競姹囨�� 褰撴湀鍧楋紙鍚屼笂锛� | 28 |
+| 鍩庡競鍒嗗競宸� 4 鍧� 脳 17 甯傚窞 脳 6 鍊煎垪 | 408 |
+| 涓彛寰勫垎鏋� 2 鍧� 脳 5 琛� 脳 2 鍒� | 10 |
+| 閬撹矾杩愯緭鍛ㄨ浆閲� 2 鍧� 脳 17 甯傚窞 脳 6 鍒楋紙G/L/Q + J/O/T + W/X/Y锛� | 102 |
+| **鍚堣** | **586** |
+
+缁撴灉锛�**姣斿 586 鏍硷紝宸紓 0 鏍�**锛坄_v5_four.txt` 鏈熬銆屾眹鎬伙細姣斿鏍兼暟 = 586锛屽樊寮傛牸鏁� = 0銆嶏級銆�
+
+琛ュ厖鑷唇鏍¢獙锛堝叏鐪佽 = 危17 甯傚窞锛夛細閬撹矾杩愯緭鍛ㄨ浆閲� G4=17492129.04788293 = 危(G5:G21)銆丩4=269628.07 = 危(L5:L21)銆丵4=1227147.48902 = 危(Q5:Q21)銆乄4/X4/Y4 鍚岀悊锛堝樊 鈮� 6e-11锛屾诞鐐硅宸骇锛夈��
+
+鍙︼細13:06 閭d竴鐗堝綊妗d欢鐢� `_verify_four.py` 澶嶆牳锛堝惈銆屼笌姣嶇増 1-7 鏈堥潤鎬佸�煎鐓с�嶅皬鑺傦級锛屽悓鏍�**宸紓 0 鏍�**銆�
+
+涓庢瘝鐗堥潤鎬佸�肩殑瀵圭収锛堣瘉鏄庛�岀‘瀹炰粠闈欐�佸彉鍔ㄦ�併�嶏級锛�
+
+| 鍗曞厓鏍� | 姣嶇増锛�1-7 鏈堥潤鎬侊級 | 鐢熸垚浠讹紙1-8 鏈堬級 |
+| --- | --- | --- |
+| 鍩庡競姹囨�� B3 | 237412.33 | 269628.07 |
+| 鍩庡競姹囨�� A12 | 2026骞�7鏈堝叏鐪佸畬鎴愬煄甯傚杩愰噺鎯呭喌 | 2026骞�8鏈堝叏鐪佸畬鎴愬煄甯傚杩愰噺鎯呭喌 |
+| 鍩庡競鍒嗗競宸� B6 | 135474.779894424 | 153695.70483259356 |
+| 涓彛寰勫垎鏋� B3 | 27524.4906 | 31528.060700000005 |
+| 閬撹矾杩愯緭鍛ㄨ浆閲� G4 | 15222118.4463982 | 17492129.04788293 |
+
+## 鍥涖�佸彂鐜扮殑闂涓庡缃�
+
+1. **姣嶇増鏍囬鏄� inlineStr**锛歅OI 鐩存帴 `setCellValue` 鍙啓 `<v>`銆佷笉鏀� `<is>`锛孍xcel 浠嶆樉绀烘棫鏂囨锛�7 鏈堬級銆傗啋 `smSetTitle` 鏀逛负鍏� `setBlank()` 鍐嶅啓銆�
+2. **鎴愬搧椤甸噷娣锋湁姣嶇増鍏紡**锛堝煄甯傚垎甯傚窞鍏ㄧ渷琛屻�侀亾璺繍杈撳懆杞噺 J 鍒楀悓姣旂瓑锛夛細鑻ヤ竴寰嬪啓鍊间細鐮村潖姣嶇増鑷唇鍏紡銆傗啋 `smSetVal` 閬� `FORMULA` 鐩存帴璺宠繃锛屽啓鍏ユ牸鏁� 1056 灏忎簬鍥涢〉鐞嗚鏍兼暟鍗充负姝ゃ��
+3. **鍩庡競姹囨�荤 5 琛屾槸銆屽嚭绉�+缃戠害杞︺�嶅悎璁�**锛屼笉鏄崟鍑虹銆傗啋 浠g爜鎸夈�屽嚭绉� + 缃戠害杞︺�嶅啓鍏ワ紙姣嶇増绗� 6 琛屾墠鏄崟鍑虹锛夛紝涓庢瘝鐗堝彛寰勪竴鑷淬��
+4. **涓彛寰勭殑銆屽煄闄呭煄涔°�嶄笉鑳界洿鎺ュ彇鍙拌处鎬婚噺**銆傗啋 鎸夈�屾�婚噺 鈭� 鍩庡競鍐呫�嶈绠楋紙浠呭叕浜�/鍑虹/缃戠害杞︼級銆�
+5. **搴撲腑鏃� 2025 骞村煄甯傚杩�/缃戠害杞︽暟鎹�**銆傗啋 鍚屾瘮鍩烘暟鍙栨瘝鐗堝彴璐﹂〉 2025 骞撮�愭湀鍒楃紦瀛樺�硷紙鏂规 A 鐨勬牳蹇冿級锛屽悗缁� 2025 鏁版嵁鍏ュ簱鍚庡彲鍐嶅垏鎹负璇诲簱銆�
+
+## 浜斻�佺粨璁�
+
+- 姝e悜 10 渚嬨�佽礋鍚� 5 渚嬨�佸洖褰� 3 渚嬨�侀�愭牸鐙珛澶嶆牳 586 鏍硷紝鍏ㄩ儴閫氳繃銆�
+- 鍥涘紶璺ㄩ〉鍚堟垚椤靛凡浠�**闈欐��**鍙樹负**闅忔姤琛ㄦ湡鏁版嵁椹卞姩**锛氬鍑� 2026-08 鏃舵爣棰樹笌鏁板�煎潎涓� 1-8 鏈�/8 鏈堝彛寰勶紱瀵煎嚭 2026-07 鏃跺張鑳界簿纭洖閫�鎴愪笌姣嶇増涓�鑷寸殑 1-7 鏈堟潈濞佸�笺��
+- 姣嶇増鍏紡淇濈暀銆佸悓姣斿熀鏁版部鐢ㄦ瘝鐗� 2025 缂撳瓨锛屾姤琛ㄦ墦寮�鍚庝粛璧版瘝鐗堣嚜甯︾殑閲嶇畻閾捐矾锛坄fullCalcOnLoad`锛夈��
+- 閬楃暀锛氫腑鍙e緞鎺掑悕椤电殑銆屽悓姣斿閫熴�嶅垪浠嶆槸姣嶇増鏃у�硷紙搴撲腑鏃� 2025 骞翠腑鍙e緞瀹氱鏁版嵁锛岀畻涓嶅嚭鍚屾瘮锛夛紝寰� 2025 鏁版嵁鍏ュ簱鍚庡埛鏂般��
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-13.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-13.md"
new file mode 100644
index 0000000..7824b7b
--- /dev/null
+++ "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-13.md"
@@ -0,0 +1,60 @@
+# 宸ヤ綔鏃ョ粨_2026-09-13
+
+> 琛ヨ锛�2026-09-12 鏃犱唬鐮佹敼鍔ㄣ�佹棤鎻愪氦锛坄git log --since=2026-09-12` 涓虹┖锛夛紝鏁呮湭鍗曠嫭鐣欐。銆�
+
+## 涓�銆佷粖澶╁仛浜嗕粈涔�
+
+### 1. 姹囨�诲ぇ琛ㄣ�屽洓椤甸潤鎬併�嶉棶棰樺畾浣嶄笌鏂规纭
+- 鐢ㄦ埛鍙嶉锛氬鍑� 2026-08 姹囨�诲ぇ琛ㄥ悗锛宍鍩庡競姹囨�籤銆乣鍩庡競鍒嗗競宸瀈銆乣涓彛寰勫垎鏋恅銆乣閬撹矾杩愯緭鍛ㄨ浆閲廯 鍥涢〉鏍囬浠嶅啓銆�1-7鏈�/7鏈堛�嶃�佹暟鍊间篃鏄� 7 鏈堥潤鎬佸�笺��
+- 缁欏嚭涓夊鏂规锛圓 娌跨敤姣嶇増 2025 缂撳瓨鍋氬悓姣斿熀鏁扮殑蹇矾瀛� / B 绛� 2025 鏁版嵁鍏ュ簱 / C 鍙仛褰撴湀鍧楋級锛岀敤鎴烽�夊畾 **鏂规 A**銆�
+
+### 2. 鍙e緞鍙嶆帹锛堝厛璇佸悗鍐欙級
+- 鎶婃瘝鐗堝彴璐﹂〉锛坄鍏氦`/`鍑虹`/`缃戠害杞/`杞ㄩ亾銆佽疆娓/`鐝嚎鍖呰溅`/` 璐ц繍`锛夐�愭牸鑱氬悎锛屽弽鎺ㄥ洓椤靛彛寰勶紝涓庡洓椤垫垚鍝�**閫愭牸 0 宸紓**鍚庢墠鍔ㄤ唬鐮併��
+- 纭鍙e緞锛氬煄甯傚杩愰噺 = 鍏氦鍩庡競鍐� + 鍑虹鍩庡競鍐� + 缃戠害杞﹀煄甯傚唴 + 杞ㄩ亾 + 杞浮锛涗腑鍙e緞 = 鐝嚎鍖呰溅 + (鎬婚噺 鈭� 鍩庡競鍐�)脳(鍏氦/鍑虹/缃戠害杞�)锛涢亾璺揣杩愬懆杞噺 = 瑙勪笂 + 瑙勪笅锛涘悓姣� = 褰撴湡 梅 姣嶇増鍙拌处椤� 2025 鍚屾湡鍒� 鈭� 1锛堝簱涓棤 2025 鍩庡競瀹㈣繍鏁版嵁锛屾晠鍙栨瘝鐗堢紦瀛橈級銆�
+
+### 3. 浠g爜瀹炵幇锛堝敮涓�鏀瑰姩鏂囦欢锛�
+- `traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java`锛�+494 鈭�2锛夛細
+  - 鏂板 `refreshSummaryCumulativeSheets(wb, year, month)`锛屾彃鍦� `refreshSummaryRankSheets` 涔嬪悗銆乣applySummaryReferenceLayout` 涔嬪墠锛�
+  - 鍙拌处鍙栨暟 `smReadLedgerMetrics` 鍏ㄩ儴**鎸夎鏍囩璇嗗埆**锛堜笉鍐欐琛屽彿锛夛紝19 缁存寚鏍囦綅锛�2026 閫愭湀鍒� C鈥銆�2025 鍚屾湡鍒� V鈥J锛�
+  - 鍐欏�� `smSetVal` 閬囩洰鏍囨牸鏄叕寮�**鐩存帴璺宠繃**锛堜繚鐣欐瘝鐗堝叕寮忥紝鎵撳紑閲嶇畻锛夈��0 涓斿師涓虹┖鏍间笉鏂板锛沗smSetTitle` 鍏� `setBlank()` 鍐嶅啓锛堟瘝鐗堟爣棰樻槸 inlineStr锛孭OI 鍙啓 `<v>` 涓嶆洿鏂� `<is>` 鐨勫潙锛夈��
+- 鍥涢〉闅忔姤琛ㄦ湡鍐欏叆 **1056 鏍�**銆�
+
+### 4. 缂栬瘧銆侀噸鍚笌瀹炴祴
+- `mvn -o -q compile` 閫氳繃锛沗start-dev.ps1` 閲嶅惎鍚庣锛圥ID 27840锛変笌鍓嶇锛圥ID 23416锛夊潎灏辩华銆�
+- 瀵煎嚭 2026-08锛欻TTP 200 / 950,783 瀛楄妭 / 36.8 绉掞紱鏃ュ織銆屽埛鏂板洓椤碘�︽暟鍊兼牸鏁�=1056銆佸埛鏂版帓鍚嶉〉鏁板�兼牸鏁�=711銆佺己鏁版彁绀�=[]銆嶏紝鏈�杩� 4MB 鏃ュ織鏃� ERROR/WARN銆�
+- 褰掓。浠讹細`docs/鐢熸垚姹囨�诲ぇ琛�/杈撳嚭/鐢熸垚_閬撹矾杩愯緭閲忔眹鎬昏〃_2026-08_鍥涢〉鏁版嵁椹卞姩_2026-09-13.xlsx`銆�
+
+### 5. 鐙珛澶嶆牳锛堜粠鐢熸垚浠惰嚜韬彴璐﹂〉閲嶆柊鑱氬悎锛�
+- 鏂板啓 `_v5_four.py`锛氳鐩栨爣棰� 10 鏍� + 鍩庡競姹囨�荤疮璁″潡 28 鏍� + 褰撴湀鍧� 28 鏍� + 鍩庡競鍒嗗競宸� 408 鏍� + 涓彛寰� 10 鏍� + 閬撹矾杩愯緭鍛ㄨ浆閲� 102 鏍� = **586 鏍硷紝宸紓 0 鏍�**銆�
+- 鍙︾敤 `_verify_four.py` 澶嶆牳 13:06 褰掓。浠讹紙鍚笌姣嶇増 1-7 鏈堥潤鎬佸�煎鐓э級锛屽悓鏍� **0 宸紓**銆�
+- 鍏ㄧ渷琛岃嚜娲斤細G4/L4/Q4/W4/X4/Y4 = 危17 甯傚窞锛堝樊 鈮� 6e-11锛夈��
+
+### 6. 鏂囨。
+- 銆婂姛鑳芥祴璇曟姤鍛奯姹囨�诲ぇ琛ㄥ洓椤垫暟鎹┍鍔╛2026-09-13.md銆嬪啓鍏� `docs/鍔熻兘娴嬭瘯鎶ュ憡/`銆�
+- 鏈�婂伐浣滄棩缁撱�嬨��
+
+## 浜屻�佹祴璇曠粨鏋滄憳瑕侊紙璇﹁銆婂姛鑳芥祴璇曟姤鍛娿�嬶級
+
+| 椤� | 缁撴灉 |
+| --- | --- |
+| 瀵煎嚭 2026-08 | HTTP 200 / 950,783 瀛楄妭 / 36.8 绉掞紱涓ゆ瀵煎嚭瀛楄妭鏁颁竴鑷达紙纭畾鎬э級 |
+| 鍥涢〉鏍囬 | 鍩庡競姹囨�汇�佸煄甯傚垎甯傚窞锛�4 鍧楋級銆佷腑鍙e緞鍒嗘瀽锛�2 鍧楋級銆侀亾璺繍杈撳懆杞噺锛�2 鍧楋級鍏ㄩ儴鏇存柊涓� 1-8鏈�/8鏈� |
+| 閫愭牸澶嶆牳 | 586 鏍硷紝宸紓 0 鏍硷紙浠庣敓鎴愪欢鑷韩鍙拌处椤电嫭绔嬮噸绠楋級 |
+| 鏈堜唤鍥為��锛堝洖褰掞級 | 瀵煎嚭 2026-07 鏃跺洓椤电簿纭洖閫�鎴愭瘝鐗� 1-7 鏈堟潈濞佸�硷細鍩庡競姹囨�� B3=237412.33銆佷腑鍙e緞 B3=27524.4906銆佸懆杞噺 G4=15222118.44638293銆佸煄甯傚垎甯傚窞 B6=135474.77989442425 鈥斺�� 涓庢瘝鐗堥�愰」涓�鑷� |
+| 璐熷悜 | 姣嶇増鍏紡鏍兼湭琚鐩栵紙`鍩庡競鍒嗗競宸�!B5`銆乣閬撹矾杩愯緭鍛ㄨ浆閲�!J4` 浠嶄负鍏紡锛夛紱2025 鏃犲簱鏁版嵁鏃跺悓姣斿彇姣嶇増缂撳瓨銆佷笉鍑虹幇 NaN/Inf锛涚┖+0 涓嶆柊澧� |
+| 鍓嶇 | `http://localhost:8080/` HTTP 200锛堥椤垫甯革級 |
+
+## 涓夈�侀仐鐣欓棶棰樹笌寰呭姙
+
+1. **涓彛寰勬帓鍚嶉〉銆屽悓姣斿閫熴�嶅垪浠嶆槸姣嶇増鏃у��**锛氬簱涓彧鏈� 2026 骞存暟鎹�佹病鏈� 2025 骞翠腑鍙e緞瀹氱鏁版嵁锛岀畻涓嶅嚭 8 鏈堝悓姣旓紱绛� 2025 鏁版嵁鍏ュ簱鍚庤嚜鍔ㄥ埛鏂般��
+2. **缃戠害杞� 8 鏈堣鍗曟暟鐤戜技鏈洿鏂�**锛氬簱涓� `wyc_order_monthly` 鐨� 2026-07 涓� 2026-08 `order_sum` 閮芥槸 29,730,791锛�7銆�8 鏈堢浉鍚岋級锛岃鐢ㄦ埛鏍稿鏄惁閲嶄紶杩囩湡瀹� 8 鏈堣繍琛岀洃娴嬫姤鍛娿��
+3. **鏍圭洰褰曚复鏃舵枃浠�**锛歚_*.py` / `_*.sql` / `_*.xlsx` / `_*.txt` / `_bak_*.java` 绛� 100+ 涓湭璺熻釜鏂囦欢锛堢敤鎴锋湭鍚屾剰鍓嶄笉娓呯悊銆佷笉鎻愪氦锛夈��
+4. `docs/鐢熸垚姹囨�诲ぇ琛�/鐢熸垚_閬撹矾杩愯緭閲忔眹鎬昏〃.xlsx`锛堢増寮忓弬鐓т欢锛変笌 `docs/鐢熸垚姹囨�诲ぇ琛�/杈撳嚭/` 涓嬬殑鍘嗗彶浜х墿鍧囦负鏈窡韪枃浠讹紝鏆傛寜鎯緥涓嶇撼鍏ユ彁浜ゃ��
+5. 2026-08 瀵煎嚭鐨勩�屾湭鎵惧埌鍚屾湡澶囦唤姣嶇増銆嶅憡璀﹀睘鏃犲鎻愮ず锛屾槸鍚︽秷闄ゅ緟鐢ㄦ埛瀹氥��
+
+## 鍥涖�佹槑澶╄鍒�
+
+1. 鐢ㄦ埛鏍稿/閲嶄紶鐪熷疄 8 鏈堢綉绾﹁溅杩愯鐩戞祴鎶ュ憡鍚庯紝閲嶅 2026-08 骞跺鏍哥綉绾﹁溅椤点��
+2. 鎸夌敤鎴峰弽棣堢户缁牳瀵瑰洓椤垫垚鍝侊紙閲嶇偣锛氬煄甯傚垎甯傚窞澧為�熷垪銆侀亾璺繍杈撳懆杞噺鍚屾湡鍒楀彛寰勬槸鍚︾鍚堜笟鍔¢鏈燂級銆�
+3. 璺熻繘 2025 骞村煄甯傚杩�/涓彛寰勬暟鎹叆搴擄紝鍏ュ簱鍚庢妸鍥涢〉鍚屾瘮浠庛�屾瘝鐗堢紦瀛樸�嶅垏鍒般�岃搴撱�嶃��
+4. 瑙嗙敤鎴锋剰鎰挎竻鐞嗘牴鐩綍涓存椂鏂囦欢銆�
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 ceea4f1..b006de5 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
@@ -3353,10 +3353,12 @@
             int yoyFilled = summaryWorkbookFiller.ensureMonthYoyFormulas(wb, year, effMonth);
             int monthFormulaFilled = summaryWorkbookFiller.ensureMonthFormulas(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, widthApplied, dbProblems);
+                    + "鍒锋柊鎺掑悕椤垫暟鍊兼牸鏁�={}锛屽埛鏂板洓椤碉紙鍩庡競姹囨��/鍩庡競鍒嗗競宸�/涓彛寰勫垎鏋�/閬撹矾杩愯緭鍛ㄨ浆閲忥級鏁板�兼牸鏁�={}锛�"
+                    + "鎸夈�婄敓鎴恄閬撹矾杩愯緭閲忔眹鎬昏〃銆嬪榻愬垪瀹藉垪鏁�={}锛岀己鏁版彁绀�={}",
+                    dbFilled, yoyFilled, monthFormulaFilled, rankRefreshed, cumulativeRefreshed, widthApplied, dbProblems);
             applyTwoDecimalFormat(wb); // 鏁板�兼樉绀轰袱浣嶅皬鏁帮紙淇濈暀鍏ㄧ簿搴︼級锛�% / 鏃ユ湡绛夋棦鏈夋牱寮忎笉鏀瑰彉
             if (!wb.getCTWorkbook().isSetCalcPr()) wb.getCTWorkbook().addNewCalcPr();
             wb.getCTWorkbook().getCalcPr().setFullCalcOnLoad(true); // 杩樺師/鏀瑰啓鍏紡鍚庢墦寮�鍗抽噸绠�
@@ -3654,6 +3656,496 @@
     }
 
     /** 瀹氫綅鐗堝紡鍙傜収浠� docs/鐢熸垚姹囨�诲ぇ琛�/鐢熸垚_閬撹矾杩愯緭閲忔眹鎬昏〃.xlsx锛堜紭鍏堢骇鍚屾瘝鐗堬細閰嶇疆鐩綍 鈫� user.dir 鐩稿 鈫� 涓婄骇锛� */
+    // ==================== 姹囨�诲ぇ琛細鍥涘紶鈥滆法椤靛悎鎴愨�濋〉闅忔姤琛ㄦ湡鍒锋柊 ====================
+    // 鍩庡競姹囨�� / 鍩庡競鍒嗗競宸� / 涓彛寰勫垎鏋� / 閬撹矾杩愯緭鍛ㄨ浆閲� 姝ゅ墠鏁撮〉娌跨敤姣嶇増闈欐�佸�硷紙鏍囬鍋滃湪 1-7 鏈堬級銆�
+    // 鏈鎸� 2026-09-13 宸查獙璇佸彛寰勶紙涓� 8 鏈堟瘝鐗堥�愭牸 0 宸紓锛変粠姣嶇増鍙拌处椤电幇绠楋細
+    //   鍩庡競瀹㈣繍閲�     = 鍩庡競鍐呭叕浜� + 鍩庡競鍐呭贰娓稿嚭绉� + 鍩庡競鍐呯綉绾﹁溅 + 杞ㄩ亾 + 杞浮
+    //   閬撹矾瀹㈣繍鍛ㄨ浆閲� = 鍏矾鐝嚎 + 鍩庨檯鍩庝埂鍏氦 + 鍩庨檯鍩庝埂宸℃父鍑虹 + 鍩庨檯鍩庝埂缃戠害杞�
+    //   閬撹矾璐ц繍鍛ㄨ浆閲� = 璐ц繍椤� 甯傚窞 瑙勪笂璐х墿鍛ㄨ浆閲� + 瑙勪笅璐х墿鍛ㄨ浆閲�
+    // 2026 骞� 1..N 鏈堝彇鍙拌处椤� 2026 鍒楋紙C/E/G鈥︼級锛屽幓骞村悓鏈熷彇姣嶇増缂撳瓨 2025 鍒楋紙V/X/Z鈥︼級鈥斺�斿簱閲屾病鏈� 2025 骞村煄甯傚杩愭暟鎹��
+
+    /** 鍩庡競瀹㈣繍鍙e緞鎸囨爣浣嶏紙0..17 鍩庡競瀹㈣繍锛�18 璐ц繍鍛ㄨ浆閲忥級 */
+    private static final int SM_BUS_PAX = 0, SM_BUS_TURN = 1;
+    private static final int SM_TAXI_PAX = 2, SM_TAXI_TURN = 3;
+    private static final int SM_WYC_PAX = 4, SM_WYC_TURN = 5;
+    private static final int SM_RAIL_PAX = 6, SM_RAIL_TURN = 7;
+    private static final int SM_FERRY_PAX = 8, SM_FERRY_TURN = 9;
+    private static final int SM_BX_PAX = 10, SM_BX_TURN = 11;
+    private static final int SM_BUS_CX_PAX = 12, SM_BUS_CX_TURN = 13;
+    private static final int SM_TAXI_CX_PAX = 14, SM_TAXI_CX_TURN = 15;
+    private static final int SM_WYC_CX_PAX = 16, SM_WYC_CX_TURN = 17;
+    private static final int SM_FREIGHT_TURN = 18;
+    private static final int SM_DIM = 19;
+    /** 2026 骞� 1 鏈堝綋鏈堝�煎垪锛�0 鍩猴紝C 鍒楋級锛�2025 骞� 1 鏈堝綋鏈堝�煎垪锛�0 鍩猴紝V 鍒楋級 */
+    private static final int SM_CUR_COL0 = 2;
+    private static final int SM_LAST_COL0 = 21;
+
+    /**
+     * 鍒锋柊鍥涘紶璺ㄩ〉鍚堟垚椤碉細褰撳勾绱锛�1..month 鏈堬級銆佸綋鏈堬紙month 鏈堬級鍙婂搴斿悓姣旓紱
+     * 2026 涓� 2025 鍚屾湡閮藉彇鑷瘝鐗堝彴璐﹂〉缂撳瓨锛岃繑鍥炲啓鍏ュ崟鍏冩牸鏁般��
+     */
+    private int refreshSummaryCumulativeSheets(XSSFWorkbook wb, int year, int month) {
+        if (wb == null || month <= 0) return 0;
+        int[] cumMonths = new int[month];
+        for (int m = 1; m <= month; m++) cumMonths[m - 1] = m;
+        int[] oneMonth = new int[]{month};
+        Map<String, double[]> curCum = smReadLedgerMetrics(wb, true, cumMonths);
+        Map<String, double[]> lastCum = smReadLedgerMetrics(wb, false, cumMonths);
+        Map<String, double[]> curMon = smReadLedgerMetrics(wb, true, oneMonth);
+        Map<String, double[]> lastMon = smReadLedgerMetrics(wb, false, oneMonth);
+        if (curCum.isEmpty()) {
+            log.warn("姹囨�诲ぇ琛ㄥ洓椤靛埛鏂帮細鍙拌处椤垫湭璇诲埌甯傚窞鏁版嵁锛岃烦杩囷紙淇濇寔姣嶇増鍘熷�硷級");
+            return 0;
+        }
+        double[] pCurCum = smProvinceSum(curCum);
+        double[] pLastCum = smProvinceSum(lastCum);
+        double[] pCurMon = smProvinceSum(curMon);
+        double[] pLastMon = smProvinceSum(lastMon);
+        int n = 0;
+        n += smWriteCitySummary(wb, year, month, pCurCum, pLastCum, pCurMon, pLastMon);
+        n += smWriteCityByRegion(wb, month, curCum, lastCum, curMon, lastMon);
+        n += smWriteMidAnalysis(wb, month, pCurCum, pLastCum, pCurMon, pLastMon);
+        n += smWriteTurnoverSheets(wb, year, month, curCum, lastCum, curMon, lastMon);
+        return n;
+    }
+
+    /** 17 甯傚窞鍚堣锛堜笉鍚彴璐﹂〉鈥滃叏鐪佲�濆叕寮忚锛� */
+    private double[] smProvinceSum(Map<String, double[]> m) {
+        double[] p = new double[SM_DIM];
+        for (String c : RegionUtil.cityList()) {
+            double[] a = m.get(c);
+            if (a == null) continue;
+            for (int i = 0; i < SM_DIM; i++) p[i] += a[i];
+        }
+        return p;
+    }
+
+    /** 鍙拌处椤电疮璁″彇鏁帮細甯傚窞瑙勮寖鍚� -> 19 缁存寚鏍� */
+    private Map<String, double[]> smReadLedgerMetrics(XSSFWorkbook wb, boolean curYear, int[] months) {
+        Map<String, double[]> out = new LinkedHashMap<>();
+        smReadCityPaxPage(wb, "鍏氦", curYear, months, out, SM_BUS_PAX, SM_BUS_TURN, SM_BUS_CX_PAX, SM_BUS_CX_TURN);
+        smReadCityPaxPage(wb, "鍑虹", curYear, months, out, SM_TAXI_PAX, SM_TAXI_TURN, SM_TAXI_CX_PAX, SM_TAXI_CX_TURN);
+        smReadCityPaxPage(wb, "缃戠害杞�", curYear, months, out, SM_WYC_PAX, SM_WYC_TURN, SM_WYC_CX_PAX, SM_WYC_CX_TURN);
+        smReadRailFerry(wb, curYear, months, out);
+        smReadBanxian(wb, curYear, months, out);
+        smReadFreightTurnover(wb, curYear, months, out);
+        return out;
+    }
+
+    /** 鍏氦/鍑虹/缃戠害杞﹂〉锛氭瘡甯傚窞 4 琛岋紙瀹㈣繍閲�/鏃呭鍛ㄨ浆閲�/鍏朵腑鍩庡競鍐呭杩愰噺/鍏朵腑鍩庡競鍐呮梾瀹㈠懆杞噺锛� */
+    private void smReadCityPaxPage(XSSFWorkbook wb, String sheetName, boolean curYear, int[] months,
+                                   Map<String, double[]> out, int paxIdx, int turnIdx, int cxPaxIdx, int cxTurnIdx) {
+        Sheet sh = wb.getSheet(sheetName);
+        if (sh == null) return;
+        int last = sh.getLastRowNum();
+        for (int r = sh.getFirstRowNum(); r <= last; r++) {
+            Row row = sh.getRow(r);
+            if (row == null) continue;
+            String city = smCityOf(row.getCell(0));
+            if (city == null) continue;
+            int paxRow = -1, turnRow = -1, cxPaxRow = -1, cxTurnRow = -1;
+            for (int k = r; k <= Math.min(last, r + 4); k++) {
+                Row kr = sh.getRow(k);
+                if (kr == null) continue;
+                String b = smText(kr.getCell(1));
+                if (b == null || b.contains("涓綋")) continue;
+                boolean inner = b.contains("鍩庡競鍐�");
+                boolean turn = b.contains("鍛ㄨ浆閲�");
+                if (inner) {
+                    if (turn) { if (cxTurnRow < 0) cxTurnRow = k; }
+                    else if (cxPaxRow < 0) cxPaxRow = k;
+                } else {
+                    if (turn) { if (turnRow < 0) turnRow = k; }
+                    else if (paxRow < 0) paxRow = k;
+                }
+            }
+            double totalPax = smSumMonths(sh, paxRow, curYear, months);
+            double totalTurn = smSumMonths(sh, turnRow, curYear, months);
+            double cityPax = smSumMonths(sh, cxPaxRow, curYear, months);
+            double cityTurn = smSumMonths(sh, cxTurnRow, curYear, months);
+            double[] arr = out.computeIfAbsent(city, k -> new double[SM_DIM]);
+            arr[paxIdx] += cityPax;                 // 鍩庡競瀹㈣繍鍙e緞鍙栤�滃煄甯傚唴鈥�
+            arr[turnIdx] += cityTurn;
+            arr[cxPaxIdx] += totalPax - cityPax;    // 鍩庨檯鍩庝埂 = 鎬婚噺 - 鍩庡競鍐�
+            arr[cxTurnIdx] += totalTurn - cityTurn;
+        }
+    }
+
+    /** 杞ㄩ亾銆佽疆娓¢〉锛氳建閬撳潡锛堟姹�/榛勭煶锛�+ 杞浮鍧楋紙姝︽眽锛� */
+    private void smReadRailFerry(XSSFWorkbook wb, boolean curYear, int[] months, Map<String, double[]> out) {
+        Sheet sh = wb.getSheet("杞ㄩ亾銆佽疆娓�");
+        if (sh == null) return;
+        int last = sh.getLastRowNum();
+        int ferryTitle = -1;
+        for (int r = sh.getFirstRowNum(); r <= last; r++) {
+            Row row = sh.getRow(r);
+            if (row == null) continue;
+            String a = smText(row.getCell(0));
+            if (a != null && a.contains("杞浮瀹㈣繍閲�")) { ferryTitle = r; break; }
+        }
+        smReadRailFerryBlock(sh, curYear, months, out, sh.getFirstRowNum(),
+                ferryTitle < 0 ? last : ferryTitle - 1, SM_RAIL_PAX);
+        if (ferryTitle >= 0) smReadRailFerryBlock(sh, curYear, months, out, ferryTitle, last, SM_FERRY_PAX);
+    }
+
+    private void smReadRailFerryBlock(Sheet sh, boolean curYear, int[] months, Map<String, double[]> out,
+                                      int start, int end, int baseIdx) {
+        for (int r = start; r <= end; r++) {
+            Row row = sh.getRow(r);
+            if (row == null) continue;
+            String city = smCityOf(row.getCell(0));
+            if (city == null) continue;
+            int paxRow = -1, turnRow = -1;
+            for (int k = r; k <= Math.min(end, r + 3); k++) {
+                Row kr = sh.getRow(k);
+                if (kr == null) continue;
+                String b = smText(kr.getCell(1));
+                if (b == null) continue;
+                if (b.contains("鍛ㄨ浆閲�")) { if (turnRow < 0) turnRow = k; }
+                else if (paxRow < 0) paxRow = k;
+            }
+            double[] arr = out.computeIfAbsent(city, k -> new double[SM_DIM]);
+            arr[baseIdx] += smSumMonths(sh, paxRow, curYear, months);
+            arr[baseIdx + 1] += smSumMonths(sh, turnRow, curYear, months);
+        }
+    }
+
+    /** 鐝嚎鍖呰溅椤碉細姣忓競宸� 瀹㈣繍閲� / 鏃呭鍛ㄨ浆閲忥紙鈥滃叾涓釜浣撯�濊涓嶉噸澶嶈鍏ワ級 */
+    private void smReadBanxian(XSSFWorkbook wb, boolean curYear, int[] months, Map<String, double[]> out) {
+        Sheet sh = wb.getSheet("鐝嚎鍖呰溅");
+        if (sh == null) return;
+        int last = sh.getLastRowNum();
+        for (int r = sh.getFirstRowNum(); r <= last; r++) {
+            Row row = sh.getRow(r);
+            if (row == null) continue;
+            String city = smCityOf(row.getCell(0));
+            if (city == null) continue;
+            int paxRow = -1, turnRow = -1;
+            for (int k = r; k <= Math.min(last, r + 4); k++) {
+                Row kr = sh.getRow(k);
+                if (kr == null) continue;
+                String b = smText(kr.getCell(1));
+                if (b == null || b.contains("涓綋")) continue;
+                if (b.contains("鍛ㄨ浆閲�")) { if (turnRow < 0) turnRow = k; }
+                else if (b.contains("瀹㈣繍閲�") && paxRow < 0) paxRow = k;
+            }
+            double[] arr = out.computeIfAbsent(city, k -> new double[SM_DIM]);
+            arr[SM_BX_PAX] += smSumMonths(sh, paxRow, curYear, months);
+            arr[SM_BX_TURN] += smSumMonths(sh, turnRow, curYear, months);
+        }
+    }
+
+    /** 璐ц繍椤碉細姣忓競宸� 瑙勪笂璐х墿鍛ㄨ浆閲� + 瑙勪笅璐х墿鍛ㄨ浆閲忥紙鈥滆涓�+瑙勪笅鈥濊鏈韩鏄眰鍜屽叕寮忥紝涓嶇洿鎺ュ彇锛� */
+    private void smReadFreightTurnover(XSSFWorkbook wb, boolean curYear, int[] months, Map<String, double[]> out) {
+        Sheet sh = wb.getSheet(" 璐ц繍");
+        if (sh == null) sh = wb.getSheet("璐ц繍");
+        if (sh == null) return;
+        int last = sh.getLastRowNum();
+        for (int r = sh.getFirstRowNum(); r <= last; r++) {
+            Row row = sh.getRow(r);
+            if (row == null) continue;
+            String city = smCityOf(row.getCell(0));
+            if (city == null) continue;
+            int above = -1, below = -1;
+            for (int k = r; k <= Math.min(last, r + 6); k++) {
+                Row kr = sh.getRow(k);
+                if (kr == null) continue;
+                String b = smText(kr.getCell(1));
+                if (b == null || b.contains("鍏朵腑")) continue;
+                if (b.contains("瑙勪笂璐х墿鍛ㄨ浆閲�")) { if (above < 0) above = k; }
+                else if (b.contains("瑙勪笅璐х墿鍛ㄨ浆閲�")) { if (below < 0) below = k; }
+            }
+            double[] arr = out.computeIfAbsent(city, k -> new double[SM_DIM]);
+            arr[SM_FREIGHT_TURN] += smSumMonths(sh, above, curYear, months) + smSumMonths(sh, below, curYear, months);
+        }
+    }
+
+    private double smSumMonths(Sheet sh, int rowIdx, boolean curYear, int[] months) {
+        if (sh == null || rowIdx < 0) return 0;
+        Row row = sh.getRow(rowIdx);
+        if (row == null) return 0;
+        double s = 0;
+        for (int m : months) {
+            int col = (curYear ? SM_CUR_COL0 : SM_LAST_COL0) + 2 * (m - 1);
+            s += smNum(row.getCell(col));
+        }
+        return s;
+    }
+
+    /** 鍙拌处椤靛崟鍏冩牸鍙栨暟锛堟暟瀛� / 鏁板瓧鏂囨湰 / 鍏紡缂撳瓨锛� */
+    private double smNum(Cell c) {
+        if (c == null) return 0;
+        try {
+            CellType t = c.getCellType();
+            if (t == CellType.NUMERIC) return c.getNumericCellValue();
+            if (t == CellType.FORMULA) {
+                return c.getCachedFormulaResultType() == CellType.NUMERIC ? c.getNumericCellValue() : 0;
+            }
+            if (t == CellType.STRING) {
+                String s = c.getStringCellValue();
+                if (s == null) return 0;
+                s = s.replace(",", "").replace("%", "").trim();
+                if (s.isEmpty()) return 0;
+                return Double.parseDouble(s);
+            }
+        } catch (Exception ignore) {
+            return 0;
+        }
+        return 0;
+    }
+
+    private String smText(Cell c) {
+        if (c == null) return null;
+        try {
+            return c.getCellType() == CellType.STRING ? c.getStringCellValue() : null;
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    /** 鍒� A 鏂囨 -> 瑙勮寖甯傚窞鍚嶏紙鈥滃叏鐪�/婀栧寳鐪佲�濅笌闈炲競宸炶杩斿洖 null锛� */
+    private String smCityOf(Cell a) {
+        String t = smText(a);
+        if (t == null || t.trim().isEmpty()) return null;
+        String norm = RegionUtil.normalizeCityName(t.trim());
+        if (norm == null) return null;
+        return RegionUtil.cityList().contains(norm) ? norm : null;
+    }
+
+    private double smYoy(double cur, double last) {
+        return last == 0.0 ? 0.0 : (cur - last) / last;
+    }
+
+    /** 鍐欏�硷細鍏紡鏍间笉鍔紙淇濈暀姣嶇増鍏紡锛屾墦寮�鍗抽噸绠楋級锛�0 涓斿師涓虹┖鏍煎垯涓嶆柊澧� */
+    private int smSetVal(Sheet sh, int r0, int c0, double v) {
+        Row row = sh.getRow(r0);
+        if (row == null) return 0;
+        Cell c = row.getCell(c0);
+        if (c != null && c.getCellType() == CellType.FORMULA) return 0;
+        if (c == null) {
+            if (v == 0.0) return 0;
+            c = row.createCell(c0);
+            Cell left = row.getCell(c0 - 1);
+            if (left != null) c.setCellStyle(left.getCellStyle());
+        } else if (v == 0.0 && c.getCellType() == CellType.BLANK) {
+            return 0;
+        }
+        c.setBlank();
+        c.setCellValue(v);
+        return 1;
+    }
+
+    private void smSetTitle(Sheet sh, int r0, int c0, String text) {
+        if (sh == null) return;
+        Row row = sh.getRow(r0);
+        if (row == null) return;
+        Cell c = row.getCell(c0);
+        if (c == null || c.getCellType() == CellType.FORMULA) return;
+        c.setBlank();
+        c.setCellValue(text);
+    }
+
+    /** 鍩庡競姹囨�婚〉锛氬潡1锛�1..N 鏈堢疮璁★級琛� 3-9锛屽潡2锛堝綋鏈堬級琛� 14-20锛涘垪 B/C/D/E = 瀹㈣繍閲�/鍚屾瘮/鍛ㄨ浆閲�/鍚屾瘮 */
+    private int smWriteCitySummary(XSSFWorkbook wb, int year, int month,
+                                   double[] pCurCum, double[] pLastCum, double[] pCurMon, double[] pLastMon) {
+        Sheet sh = wb.getSheet("鍩庡競姹囨��");
+        if (sh == null) return 0;
+        smSetTitle(sh, 0, 0, year + "骞�1-" + month + "鏈堝叏鐪佺疮璁″畬鎴愬煄甯傚杩愰噺鎯呭喌");
+        smSetTitle(sh, 11, 0, year + "骞�" + month + "鏈堝叏鐪佸畬鎴愬煄甯傚杩愰噺鎯呭喌");
+        int n = 0;
+        int[] rows = {2, 3, 4, 5, 6, 7, 8};
+        for (int i = 0; i < rows.length; i++) {
+            double[] v = smCitySummaryRow(pCurCum, pLastCum, i);
+            n += smSetVal(sh, rows[i], 1, v[0]);
+            n += smSetVal(sh, rows[i], 2, v[2]);
+            n += smSetVal(sh, rows[i], 3, v[1]);
+            n += smSetVal(sh, rows[i], 4, v[3]);
+        }
+        for (int i = 0; i < rows.length; i++) {
+            double[] v = smCitySummaryRow(pCurMon, pLastMon, i);
+            n += smSetVal(sh, rows[i] + 11, 1, v[0]);
+            n += smSetVal(sh, rows[i] + 11, 2, v[2]);
+            n += smSetVal(sh, rows[i] + 11, 3, v[1]);
+            n += smSetVal(sh, rows[i] + 11, 4, v[3]);
+        }
+        return n;
+    }
+
+    /** i=0 鎬诲杩愰噺 1 鍏氦 2 鍑虹杞� 3 宸℃父鍑虹 4 缃戠害杞� 5 杞ㄩ亾 6 杞浮锛涜繑鍥� [瀹㈣繍閲�, 鍛ㄨ浆閲�, 瀹㈣繍閲忓悓姣�, 鍛ㄨ浆閲忓悓姣擼 */
+    private double[] smCitySummaryRow(double[] p, double[] pl, int i) {
+        double pax, turn, lPax, lTurn;
+        if (i == 0) {
+            pax = p[SM_BUS_PAX] + p[SM_TAXI_PAX] + p[SM_WYC_PAX] + p[SM_RAIL_PAX] + p[SM_FERRY_PAX];
+            turn = p[SM_BUS_TURN] + p[SM_TAXI_TURN] + p[SM_WYC_TURN] + p[SM_RAIL_TURN] + p[SM_FERRY_TURN];
+            lPax = pl[SM_BUS_PAX] + pl[SM_TAXI_PAX] + pl[SM_WYC_PAX] + pl[SM_RAIL_PAX] + pl[SM_FERRY_PAX];
+            lTurn = pl[SM_BUS_TURN] + pl[SM_TAXI_TURN] + pl[SM_WYC_TURN] + pl[SM_RAIL_TURN] + pl[SM_FERRY_TURN];
+        } else if (i == 1) {
+            pax = p[SM_BUS_PAX]; turn = p[SM_BUS_TURN]; lPax = pl[SM_BUS_PAX]; lTurn = pl[SM_BUS_TURN];
+        } else if (i == 2) {
+            pax = p[SM_TAXI_PAX] + p[SM_WYC_PAX]; turn = p[SM_TAXI_TURN] + p[SM_WYC_TURN];
+            lPax = pl[SM_TAXI_PAX] + pl[SM_WYC_PAX]; lTurn = pl[SM_TAXI_TURN] + pl[SM_WYC_TURN];
+        } else if (i == 3) {
+            pax = p[SM_TAXI_PAX]; turn = p[SM_TAXI_TURN]; lPax = pl[SM_TAXI_PAX]; lTurn = pl[SM_TAXI_TURN];
+        } else if (i == 4) {
+            pax = p[SM_WYC_PAX]; turn = p[SM_WYC_TURN]; lPax = pl[SM_WYC_PAX]; lTurn = pl[SM_WYC_TURN];
+        } else if (i == 5) {
+            pax = p[SM_RAIL_PAX]; turn = p[SM_RAIL_TURN]; lPax = pl[SM_RAIL_PAX]; lTurn = pl[SM_RAIL_TURN];
+        } else {
+            pax = p[SM_FERRY_PAX]; turn = p[SM_FERRY_TURN]; lPax = pl[SM_FERRY_PAX]; lTurn = pl[SM_FERRY_TURN];
+        }
+        return new double[]{pax, turn, smYoy(pax, lPax), smYoy(turn, lTurn)};
+    }
+
+    /** 鍩庡競鍒嗗競宸為〉锛�4 鍧楋紙绱瀹㈣繍閲�/绱鍛ㄨ浆閲�/褰撴湀瀹㈣繍閲�/褰撴湀鍛ㄨ浆閲忥級锛屾瘡鍧� 鍏ㄧ渷 1 琛� + 17 甯傚窞 */
+    private int smWriteCityByRegion(XSSFWorkbook wb, int month,
+                                    Map<String, double[]> curCum, Map<String, double[]> lastCum,
+                                    Map<String, double[]> curMon, Map<String, double[]> lastMon) {
+        Sheet sh = wb.getSheet("鍩庡競鍒嗗競宸�");
+        if (sh == null) return 0;
+        smSetTitle(sh, 0, 0, "鍩庡競瀹㈣繍瀹㈣繍閲忓垎甯傚窞1-" + month + "鏈堢疮璁℃儏鍐�");
+        smSetTitle(sh, 22, 0, "鍩庡競瀹㈣繍瀹㈣繍鍛ㄨ浆閲忓垎甯傚窞1-" + month + "鏈堢疮璁℃儏鍐�");
+        smSetTitle(sh, 45, 0, "鍩庡競瀹㈣繍瀹㈣繍閲忓垎甯傚窞" + month + "鏈堟儏鍐�");
+        smSetTitle(sh, 67, 0, "鍩庡競瀹㈣繍瀹㈣繍鍛ㄨ浆閲忓垎甯傚窞" + month + "鏈堟儏鍐�");
+        int n = 0;
+        n += smWriteCityByRegionBlock(sh, 4, true, curCum, lastCum);
+        n += smWriteCityByRegionBlock(sh, 26, false, curCum, lastCum);
+        n += smWriteCityByRegionBlock(sh, 49, true, curMon, lastMon);
+        n += smWriteCityByRegionBlock(sh, 71, false, curMon, lastMon);
+        return n;
+    }
+
+    private int smWriteCityByRegionBlock(Sheet sh, int provRow, boolean pax,
+                                         Map<String, double[]> cur, Map<String, double[]> last) {
+        int n = 0;
+        double[] provCur = smProvinceSum(cur);
+        double[] provLast = smProvinceSum(last);
+        List<String> cities = RegionUtil.cityList();
+        for (int i = -1; i < cities.size(); i++) {
+            int r = provRow + i + 1;
+            double[] c = i < 0 ? provCur : cur.get(cities.get(i));
+            double[] l = i < 0 ? provLast : last.get(cities.get(i));
+            if (c == null) c = new double[SM_DIM];
+            if (l == null) l = new double[SM_DIM];
+            double[] g = smCityGroupValues(c, l, pax);
+            n += smSetVal(sh, r, 1, g[0]);
+            n += smSetVal(sh, r, 4, g[6]);
+            n += smSetVal(sh, r, 6, g[1]);
+            n += smSetVal(sh, r, 9, g[7]);
+            n += smSetVal(sh, r, 11, g[2]);
+            n += smSetVal(sh, r, 14, g[8]);
+            n += smSetVal(sh, r, 16, g[3]);
+            n += smSetVal(sh, r, 19, g[9]);
+            n += smSetVal(sh, r, 21, g[4]);
+            n += smSetVal(sh, r, 22, g[10]);
+            n += smSetVal(sh, r, 23, g[5]);
+            n += smSetVal(sh, r, 24, g[11]);
+        }
+        return n;
+    }
+
+    /** 6 缁勫�� + 6 缁勫閫燂細[鎬婚噺, 鍏氦, 鍑虹, 缃戠害杞�, 杞ㄩ亾, 杞浮, 鎬婚噺澧為��, 鍏氦鈥�, 杞浮] */
+    private double[] smCityGroupValues(double[] c, double[] l, boolean pax) {
+        int busI = pax ? SM_BUS_PAX : SM_BUS_TURN;
+        int taxiI = pax ? SM_TAXI_PAX : SM_TAXI_TURN;
+        int wycI = pax ? SM_WYC_PAX : SM_WYC_TURN;
+        int railI = pax ? SM_RAIL_PAX : SM_RAIL_TURN;
+        int ferryI = pax ? SM_FERRY_PAX : SM_FERRY_TURN;
+        double bus = c[busI], taxi = c[taxiI], wyc = c[wycI], rail = c[railI], ferry = c[ferryI];
+        double lBus = l[busI], lTaxi = l[taxiI], lWyc = l[wycI], lRail = l[railI], lFerry = l[ferryI];
+        double total = bus + taxi + wyc + rail + ferry;
+        double lTotal = lBus + lTaxi + lWyc + lRail + lFerry;
+        return new double[]{total, bus, taxi, wyc, rail, ferry,
+                smYoy(total, lTotal), smYoy(bus, lBus), smYoy(taxi, lTaxi), smYoy(wyc, lWyc),
+                smYoy(rail, lRail), smYoy(ferry, lFerry)};
+    }
+
+    /** 涓彛寰勫垎鏋愰〉锛氬潡1锛堢疮璁★級琛� 3-7锛屽潡2锛堝綋鏈堬級琛� 12-16锛涘垪 B/C/F/G = 瀹㈣繍閲�/鍚屾瘮/鍛ㄨ浆閲�/鍚屾瘮 */
+    private int smWriteMidAnalysis(XSSFWorkbook wb, int month,
+                                   double[] pCurCum, double[] pLastCum, double[] pCurMon, double[] pLastMon) {
+        Sheet sh = wb.getSheet("涓彛寰勫垎鏋�");
+        if (sh == null) return 0;
+        smSetTitle(sh, 0, 0, "1-" + month + "鏈堜腑鍙e緞瀹㈣繍閲忓強鍛ㄨ浆閲�");
+        smSetTitle(sh, 9, 0, month + "鏈堜腑鍙e緞瀹㈣繍閲忓強鍛ㄨ浆閲�");
+        int n = 0;
+        int[] rows = {2, 3, 4, 5, 6};
+        for (int i = 0; i < rows.length; i++) {
+            double[] v = smMidRow(pCurCum, pLastCum, i);
+            n += smSetVal(sh, rows[i], 1, v[0]);
+            n += smSetVal(sh, rows[i], 2, v[2]);
+            n += smSetVal(sh, rows[i], 5, v[1]);
+            n += smSetVal(sh, rows[i], 6, v[3]);
+        }
+        for (int i = 0; i < rows.length; i++) {
+            double[] v = smMidRow(pCurMon, pLastMon, i);
+            n += smSetVal(sh, rows[i] + 9, 1, v[0]);
+            n += smSetVal(sh, rows[i] + 9, 2, v[2]);
+            n += smSetVal(sh, rows[i] + 9, 5, v[1]);
+            n += smSetVal(sh, rows[i] + 9, 6, v[3]);
+        }
+        return n;
+    }
+
+    /** i=0 鎬� 1 鍏矾鐝嚎 2 鍩庨檯鍩庝埂鍏氦 3 鍩庨檯鍩庝埂宸℃父鍑虹 4 鍩庨檯鍩庝埂缃戠害杞︼紱杩斿洖 [瀹㈣繍閲�, 鍛ㄨ浆閲�, 瀹㈣繍閲忓悓姣�, 鍛ㄨ浆閲忓悓姣擼 */
+    private double[] smMidRow(double[] p, double[] pl, int i) {
+        int[] paxIdx = {SM_BX_PAX, SM_BX_PAX, SM_BUS_CX_PAX, SM_TAXI_CX_PAX, SM_WYC_CX_PAX};
+        int[] turnIdx = {SM_BX_TURN, SM_BX_TURN, SM_BUS_CX_TURN, SM_TAXI_CX_TURN, SM_WYC_CX_TURN};
+        double pax, turn, lPax, lTurn;
+        if (i == 0) {
+            pax = p[SM_BX_PAX] + p[SM_BUS_CX_PAX] + p[SM_TAXI_CX_PAX] + p[SM_WYC_CX_PAX];
+            turn = p[SM_BX_TURN] + p[SM_BUS_CX_TURN] + p[SM_TAXI_CX_TURN] + p[SM_WYC_CX_TURN];
+            lPax = pl[SM_BX_PAX] + pl[SM_BUS_CX_PAX] + pl[SM_TAXI_CX_PAX] + pl[SM_WYC_CX_PAX];
+            lTurn = pl[SM_BX_TURN] + pl[SM_BUS_CX_TURN] + pl[SM_TAXI_CX_TURN] + pl[SM_WYC_CX_TURN];
+        } else {
+            pax = p[paxIdx[i]]; turn = p[turnIdx[i]];
+            lPax = pl[paxIdx[i]]; lTurn = pl[turnIdx[i]];
+        }
+        return new double[]{pax, turn, smYoy(pax, lPax), smYoy(turn, lTurn)};
+    }
+
+    /** 閬撹矾杩愯緭鍛ㄨ浆閲忛〉锛氬潡1锛堢疮璁★級琛� 4-21锛屽潡2锛堝綋鏈堬級琛� 26-43锛涘彧鍐欏�煎垪锛圔/E/V 绛夊叕寮忎繚鐣欙級 */
+    private int smWriteTurnoverSheets(XSSFWorkbook wb, int year, int month,
+                                      Map<String, double[]> curCum, Map<String, double[]> lastCum,
+                                      Map<String, double[]> curMon, Map<String, double[]> lastMon) {
+        Sheet sh = wb.getSheet("閬撹矾杩愯緭鍛ㄨ浆閲�");
+        if (sh == null) return 0;
+        smSetTitle(sh, 0, 0, year + "骞�1-" + month + "鏈堝叏鐪佺疮璁″畬鎴愪氦閫氬懆杞噺鎯呭喌");
+        smSetTitle(sh, 22, 0, year + "骞�" + month + "鏈堝叏鐪佸畬鎴愪氦閫氬懆杞噺鎯呭喌");
+        int n = 0;
+        n += smWriteTurnoverBlock(sh, 3, curCum, lastCum);
+        n += smWriteTurnoverBlock(sh, 25, curMon, lastMon);
+        return n;
+    }
+
+    private int smWriteTurnoverBlock(Sheet sh, int provRow, Map<String, double[]> cur, Map<String, double[]> last) {
+        int n = 0;
+        double[] provCur = smProvinceSum(cur);
+        double[] provLast = smProvinceSum(last);
+        List<String> cities = RegionUtil.cityList();
+        for (int i = -1; i < cities.size(); i++) {
+            int r = provRow + i + 1;
+            double[] c = i < 0 ? provCur : cur.get(cities.get(i));
+            double[] l = i < 0 ? provLast : last.get(cities.get(i));
+            if (c == null) c = new double[SM_DIM];
+            if (l == null) l = new double[SM_DIM];
+            double freight = c[SM_FREIGHT_TURN], lFreight = l[SM_FREIGHT_TURN];
+            double pax = c[SM_BUS_PAX] + c[SM_TAXI_PAX] + c[SM_WYC_PAX] + c[SM_RAIL_PAX] + c[SM_FERRY_PAX];
+            double lPax = l[SM_BUS_PAX] + l[SM_TAXI_PAX] + l[SM_WYC_PAX] + l[SM_RAIL_PAX] + l[SM_FERRY_PAX];
+            double road = c[SM_BX_TURN] + c[SM_BUS_CX_TURN] + c[SM_TAXI_CX_TURN] + c[SM_WYC_CX_TURN];
+            double lRoad = l[SM_BX_TURN] + l[SM_BUS_CX_TURN] + l[SM_TAXI_CX_TURN] + l[SM_WYC_CX_TURN];
+            n += smSetVal(sh, r, 6, freight);
+            n += smSetVal(sh, r, 9, smYoy(freight, lFreight));
+            n += smSetVal(sh, r, 11, pax);
+            n += smSetVal(sh, r, 14, smYoy(pax, lPax));
+            n += smSetVal(sh, r, 16, road);
+            n += smSetVal(sh, r, 19, smYoy(road, lRoad));
+            n += smSetVal(sh, r, 22, lFreight);
+            n += smSetVal(sh, r, 23, lPax);
+            n += smSetVal(sh, r, 24, lRoad);
+        }
+        return n;
+    }
+
+
     private File resolveSummaryLayoutRef() {
         String rel = summaryTemplateDir;
         while (rel != null && rel.startsWith("./")) rel = rel.substring(2);

--
Gitblit v1.9.1