From a76a8cce476ceccbc061a3f51681b6090a7d3741 Mon Sep 17 00:00:00 2001
From: zhizhijie <zhizhijie@users.noreply.gitee.com>
Date: 星期五, 11 九月 2026 17:32:41 +0800
Subject: [PATCH] feat: 汇总大表排名页随报表期刷新 + 同比列统一百分数显示
---
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java | 216 +++++++++++++++++++++++++++++++++++
docs/功能测试报告/功能测试报告_汇总表排名页刷新与同比百分数_2026-09-11.md | 80 +++++++++++++
docs/工作日结/工作日结_2026-09-11.md | 13 ++
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/calc/SummaryWorkbookFiller.java | 7
4 files changed, 310 insertions(+), 6 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\350\241\250\346\216\222\345\220\215\351\241\265\345\210\267\346\226\260\344\270\216\345\220\214\346\257\224\347\231\276\345\210\206\346\225\260_2026-09-11.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\350\241\250\346\216\222\345\220\215\351\241\265\345\210\267\346\226\260\344\270\216\345\220\214\346\257\224\347\231\276\345\210\206\346\225\260_2026-09-11.md"
new file mode 100644
index 0000000..a3fbccd
--- /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\350\241\250\346\216\222\345\220\215\351\241\265\345\210\267\346\226\260\344\270\216\345\220\214\346\257\224\347\231\276\345\210\206\346\225\260_2026-09-11.md"
@@ -0,0 +1,80 @@
+# 鍔熻兘娴嬭瘯鎶ュ憡_姹囨�昏〃鎺掑悕椤靛埛鏂颁笌鍚屾瘮鐧惧垎鏁癬2026-09-11
+
+## 涓�銆佸姛鑳借鏄�
+
+鐢ㄦ埛鍙嶉銆婇亾璺繍杈撻噺姹囨�昏〃銆嬩袱涓棶棰橈細**1. 鎵�鏈夋帓鍚嶈〃閲岄潰鐨勬暟鎹病鏈夋洿鏂帮紱2. 鍚屾瘮搴旇鏄櫨鍒嗘暟鑰屼笉鏄皬鏁�**銆傛湰杞畾浣嶅苟淇锛�
+
+### 1. 鎺掑悕椤垫暟鎹埛鏂帮紙闂 1锛�
+
+- 鐜拌薄锛氭眹鎬诲ぇ琛ㄦ瘝鐗� `2026骞�8鏈堥亾璺繍杈撻噺姹囨�昏〃.xlsx` 閲岀殑 `璐ц繍閲忔帓鍚峘 / `璐ц繍鍛ㄨ浆閲忔帓鍚峘 / `涓彛寰勬帓鍚峘 涓夐〉鏄�**涓婁竴鎶ヨ〃鏈熺殑闈欐�佸��**锛堟爣棰樺啓銆�2026骞�1-7鏈� / 2026骞�7鏈堛�嶏紝鏁板�间篃鏄� 7 鏈堬級锛屽鍑� 8 鏈堟椂鏁撮〉涓嶉殢鏁版嵁鍙樺寲銆�
+- 澶勭疆锛氬鍑洪摼璺柊澧� `refreshSummaryRankSheets`锛岀敤绋嬪簭鑷繁鐨勭嫭绔嬫帓鍚嶈〃锛坄鐢熸垚_璐ц繍閲忔帓鍚�.xlsx` / `鐢熸垚_鍛ㄨ浆閲忔帓鍚�.xlsx` / `鐢熸垚_涓彛寰勬帓鍚�.xlsx`锛屼笌鐢ㄦ埛鏃ュ父鏍稿鍙e緞涓�鑷达級鍒锋柊杩欎笁椤碉細
+ - 鏁板�兼牸鎼暟鍊硷紱婧愪晶鏄叕寮忕殑锛圧ANK/鍗犳瘮绛夛級鎸夌洰鏍囧潡鍋忕Щ鏁翠綋骞崇Щ鍚庡啓鎴愬叕寮忥紙鎵撳紑鏃舵寜姹囨�昏〃鑷韩鏁版嵁閲嶇畻锛夛紱鐩爣鏍兼湰韬凡鏄叕寮忕殑锛堟瘝鐗� SUM/RANK/鍗犳瘮锛変繚鐣欎笉鍔紱
+ - 鍧楁爣棰橀殢鎶ヨ〃鏈熷悓姝ワ紙`2026骞�1-7鏈堚� 鈫� `2026骞�1-8鏈堚�銆乣2026骞�7鏈堚� 鈫� `2026骞�8鏈堚�锛夈��
+
+### 2. 鍚屾瘮鍒楁樉绀烘垚灏忔暟锛堥棶棰� 2锛�
+
+- 鐜拌薄锛氭瘝鐗堟妸鏂版湀浠斤紙8 鏈堬級鐨勫悓姣斿垪鍋氭垚浜嗐�屾櫘閫氭暟鍊� `0.00`銆嶆牸寮忥紝鑰� 7 鏈堝強浠ュ墠鐨勫悓姣斿垪鏄� `0.00%`锛涘洖濉叕寮忓悗 8 鏈堝悓姣旀樉绀烘垚 `-0.0294` 杩欐牱鐨勫皬鏁般��
+- 澶勭疆锛歚SummaryWorkbookFiller.ensureMonthYoyFormulas` 鍘熸潵鍙湪鐩爣鏍间负绌烘椂濂楃敤涓婃湀鍚屾瘮鍒楁牱寮忥紝鏀逛负**鏃犳潯浠舵部鐢ㄤ笂鏈堝悓姣斿垪鏍峰紡**锛坄0.00%`锛夈��
+
+### 鏀瑰姩鏂囦欢
+
+- `traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java`锛氭柊澧� `refreshSummaryRankSheets` / `copyRankValues` / `rankCell` / `shiftFormula`锛屽湪 `ensureMonthFormulas` 涔嬪悗銆乣applySummaryReferenceLayout` 涔嬪墠璋冪敤銆�
+- `traffic-audit-server/src/main/java/com/trafficaudit/reportexport/calc/SummaryWorkbookFiller.java`锛歚ensureMonthYoyFormulas` 鏍峰紡娌跨敤銆�
+
+## 浜屻�佹祴璇曠幆澧�
+
+- 鍚庣 `http://localhost:8090`锛坄start-dev.ps1` 鍚姩锛夛紝瀵煎嚭鎺ュ彛 `GET /api/report/export/summaryWorkbook?period=YYYY-MM`銆�
+- 姣嶇増锛歚docs/鐢熸垚姹囨�诲ぇ琛�/2026骞�8鏈堥亾璺繍杈撻噺姹囨�昏〃.xlsx`锛涚増寮忓弬鐓э細`docs/鐢熸垚姹囨�诲ぇ琛�/鐢熸垚_閬撹矾杩愯緭閲忔眹鎬昏〃.xlsx`銆�
+- 鐙珛鎺掑悕琛ㄥ簳绋匡細`docs/璐ц繍/鐢熸垚_璐ц繍閲忔帓鍚�.xlsx`銆乣docs/璐ц繍/鐢熸垚_鍛ㄨ浆閲忔帓鍚�.xlsx`銆乣docs/鍏矾鏃呭/鐢熸垚_涓彛寰勬帓鍚�.xlsx`銆�
+- 娴嬭瘯鏃堕棿锛�2026-09-11锛涙祴璇曚骇鐗╋細`_gen2_2026-08.xlsx`銆乣_gen2_2026-07.xlsx`銆乣_v2_freight_rank.xlsx`銆乣_v2_turnover_rank.xlsx`銆乣_v2_mid_rank.xlsx`銆�
+
+## 涓夈�佺敤渚嬭〃
+
+### 3.1 姝e悜鐢ㄤ緥
+
+| 缂栧彿 | 杈撳叆 | 棰勬湡 | 瀹為檯 | 缁撹 |
+| --- | --- | --- | --- | --- |
+| TC-1 | 瀵煎嚭 `period=2026-08` | HTTP 200锛屾甯镐骇鍑烘枃浠� | 949,956 瀛楄妭锛�23.8 绉掕繑鍥� | 閫氳繃 |
+| TC-2 | 鍚庣鍥炲~鏃ュ織 | 鏈夋帓鍚嶉〉鍒锋柊缁熻銆佹棤缂烘暟鎻愮ず | 鍐欏叆褰撴湀鍊兼牸鏁�=1659锛岃ˉ鍐欏綋鏈堝悓姣斿叕寮忔牸鏁�=600锛岃ˉ鍐欏綋鏈堝悎璁″叕寮忔牸鏁�=43锛�**鍒锋柊鎺掑悕椤垫暟鍊兼牸鏁�=711**锛屽榻愬垪瀹藉垪鏁�=422锛岀己鏁版彁绀�=[] | 閫氳繃 |
+| TC-3 | 璐ц繍閲忔帓鍚嶅潡鏍囬 | 闅忔姤琛ㄦ湡鏀逛负 1-8 鏈�/8 鏈� | `A1=2026骞�1-8鏈堝叏鐪佸垎甯傚窞绱瀹屾垚鍏矾璐ц繍閲忔儏鍐礰锛沗A22=2026骞�8鏈堝叏鐪佸垎甯傚窞瀹屾垚鍏矾璐ц繍閲忔儏鍐礰 | 閫氳繃 |
+| TC-4 | 璐ц繍鍛ㄨ浆閲忔帓鍚嶅潡鏍囬 | 鍚屼笂 | `A2=鈥�2026骞�1-8鏈堚�锛沗A24=鈥�2026骞�8鏈堚� | 閫氳繃 |
+| TC-5 | 涓彛寰勬帓鍚嶅潡鏍囬 | 鍚屼笂 | `J1=2026骞�1-8鏈堝叏鐪佸垎甯傚窞绱瀹屾垚閬撹矾瀹㈣繍鐢熶骇鎯呭喌`锛沗J22=2026骞�8鏈堚� | 閫氳繃 |
+| TC-6 | 鏍囬钀界洏鏂瑰紡锛堝師濮� XML 鏍¢獙锛� | `<is><t>` 涓庢樉绀轰竴鑷达紙涓嶈兘鍐嶅嚭鐜� `<v>` 鏂板�� + `<is>` 鏃у�硷級 | `xl/worksheets/sheet2.xml`锛歚<c r="A1" s="776" t="s"><v>0</v></c>`锛屽叡浜覆 0 = `2026骞�1-8鏈堚�锛堟棫鏂囦欢鏄� inlineStr锛宍<v>`=8鏈堛�乣<is><t>`=7鏈堬級 | 閫氳繃 |
+| TC-7 | 璐ц繍閲忔帓鍚嶉�愭牸鍏ュ簱鎶芥煡锛堜笌鐙珛鎺掑悕琛ㄦ瘮瀵癸級 | 鍏ㄥ潡涓�鑷� | 绱鍧� + 褰撴湀鍧楀叡 **454 鏍奸�愪釜姣斿锛�0 澶勪笉涓�鑷�** | 閫氳繃 |
+| TC-8 | 璐ц繍鍛ㄨ浆閲忔帓鍚嶅綋鏈堝潡鎶芥煡 | 涓庣嫭绔嬭〃涓�鑷� | 姝︽眽 B28=192320.5226锛堟簮 B27锛夈�丟28=504369.61288609065锛堟簮 G27锛夈�丒28=0.3334642531154999锛堟簮 E27锛夈�丣28=-0.021161120884320206锛堟簮 J27锛� | 閫氳繃 |
+| TC-9 | 璐ц繍鍛ㄨ浆閲忔帓鍚嶆瘝鐗堝叕寮忎繚鐣� | 涓嶅啓姝诲�硷紝淇濈暀 SUM/RANK/鍗犳瘮 | 鍏ㄧ渷 B27=`=SUM(B28:B44)`锛涙姹� C28=`=RANK(B28,B$28:B$44)`銆丏28=`=B28/B$27` | 閫氳繃 |
+| TC-10 | 涓彛寰勬帓鍚嶆暟鍊兼娊鏌� | 涓庣嫭绔嬭〃涓�鑷� | K4=2759.8855锛堟簮 B4锛夈�丱4=152330.9312锛堟簮 F4锛夈�並25=349.536锛堟簮 L4锛夈�丱25=18917.1637锛堟簮 P4锛� | 閫氳繃 |
+| TC-11 | 涓彛寰勬帓鍚嶃�屽閫熸帓鍚嶃�嶅垪 | 涓嶅啀鏄潤鎬佹��硷紝涓斾笌椤靛唴鍚屾瘮鑷唇 | 鐢遍潤鎬佸�硷紙澶氳鍚屼负 1.0锛夋敼涓� `=RANK(M4,M$4:M$20)`銆乣=RANK(M25,M$25:M$41)` 绛夎嚜娲藉叕寮忥紱缂撳瓨鍊间笌姣嶇増鍘熷�间竴鑷达紙L25=5銆丯25=10銆丳25=2銆丷25=5锛� | 閫氳繃 |
+| TC-12 | 8 鏈堝悓姣斿垪鏍煎紡锛堥棶棰� 2锛� | 鐧惧垎鏁� `0.00%` | 璐ц繍 R5=`=Q5/AJ5-1` / `0.00%`锛涚彮绾垮寘杞︺�佸煄甯傚杩愩�佸叕浜ゃ�佸嚭绉熴�佺綉绾﹁溅銆佽建閬撹疆娓°�佷腑鍙e緞鏄庣粏 8 鏈堝悓姣斿垪锛圧 鍒楋級**鍏ㄩ儴 `0.00%`** | 閫氳繃 |
+| TC-13 | 鎺掑悕椤靛悓姣斿垪鏍煎紡 | 鐧惧垎鏁� `0.00%` | 璐ц繍閲忔帓鍚� E4=-0.0763 / `0.00%`銆丏5=0.3207鈥� / `0.00%`锛涜揣杩愬懆杞噺鎺掑悕銆佷腑鍙e緞鎺掑悕鍚屾瘮鍒楀悓涓� `0.00%` | 閫氳繃 |
+| TC-14 | 鎵撳紑鍗抽噸绠� | 浠嶅甫鍏ㄩ噺閲嶇畻鏍囪 | `<calcPr 鈥� fullCalcOnLoad="true"/>` 淇濈暀 | 閫氳繃 |
+
+### 3.2 璐熷悜鐢ㄤ緥
+
+| 缂栧彿 | 杈撳叆 | 棰勬湡 | 瀹為檯 | 缁撹 |
+| --- | --- | --- | --- | --- |
+| TC-N1 | 鍏ㄨ〃鎵弿銆岃〃澶村惈鍚屾瘮 + 鏁板��/鍏紡 + 鏍煎紡闈炵櫨鍒嗘暟銆嶇殑鏍� | 涓嶅簲鏈夋柊寮曞叆鐨勫皬鏁板悓姣� | 8 鏈堜欢鍛戒腑 3 鏍硷紝鍏ㄩ儴鍦ㄩ殣钘忛〉锛坄2025骞村煄甯傚杩愰噺!E13`銆乣涓彛寰勮绠楄繃绋�!G85/G86`锛夛紝姣嶇増鍚屼綅缃悓鏍峰姝� | 閫氳繃锛堥潪鏈疆寮曞叆锛� |
+| TC-N2 | 鐙珛鎺掑悕琛ㄦ簮渚у悓姣斾负绌烘椂锛堝簱涓棤 2025 骞翠腑鍙e緞鏁版嵁锛� | 涓嶅簲鎶� POI 瀵圭┖鍊肩殑姹傚�肩粨鏋滐紙鍏ㄤ负 1锛夋惉杩涙眹鎬昏〃 | 鏀逛负鍐欏叕寮忓悗锛岃鍒椾负 `=RANK(鈥�)` 鍏紡锛屾寜椤靛唴鍚屾瘮鍙栧�硷紝涓嶅啀鏄� 17 琛屽叏 1 | 閫氳繃 |
+| TC-N3 | 璋冭瘯鏃ュ織娓呯悊 | 瀵煎嚭鏃ュ織涓嶅簲娈嬬暀 `RANKDBG` | `backend.log` 涓� `RANKDBG` 璁℃暟 = 0 | 閫氳繃 |
+
+### 3.3 鍘嗗彶鏈堝洖褰掞紙2026-07锛�
+
+| 缂栧彿 | 杈撳叆 | 棰勬湡 | 瀹為檯 | 缁撹 |
+| --- | --- | --- | --- | --- |
+| TC-R1 | 瀵煎嚭 `period=2026-07` | 姝e父浜у嚭銆佸綋鏈堝悓姣斾粛鎸囧悜 2025 骞� 7 鏈� | 941,903 瀛楄妭锛涜揣杩� P5=`=O5/AF5-1` / `0.00%` | 閫氳繃 |
+| TC-R2 | 涓庢敼鍔ㄥ墠 7 鏈堜骇鐗╋紙`_gen_2026-07.xlsx`锛夐�愭牸 diff | 宸紓浠呴檺琚埛鏂扮殑鎺掑悕椤� | 浠� `璐ц繍閲忔帓鍚峘 51 鏍笺�乣涓彛寰勬帓鍚峘 133 鏍兼湁宸紓锛堟帓鍚嶉〉鐢遍潤鎬佸�兼敼涓烘寜鏁版嵁鍒锋柊锛屽睘棰勬湡锛夛紱鍏朵綑 16 椤� 0 宸紓 | 閫氳繃 |
+| TC-R3 | 7 鏈堟帓鍚嶉〉鏍囬 | 浠嶄负 1-7 鏈�/7 鏈堬紙鎸夋姤琛ㄦ湡锛� | `A1=2026骞�1-7鏈堚�銆乣A22=2026骞�7鏈堚�锛涗腑鍙e緞 `J22=2026骞�7鏈堚� | 閫氳繃 |
+| TC-R4 | 7 鏈堝悓姣旀牸寮� | 鏃犳柊澧炲皬鏁板悓姣� | 鍏ㄨ〃鍛戒腑 3 鏍硷紝鍧囦负闅愯棌椤垫瘝鐗堝師鏈夋牸 | 閫氳繃 |
+
+## 鍥涖�佸彂鐜扮殑闂涓庡缃�
+
+1. **鎺掑悕椤垫爣棰樻敼浜嗕絾 Excel 浠嶆樉绀烘棫鏈堜唤**锛氭瘝鐗堟爣棰樺崟鍏冩牸鏄� `inlineStr`锛孭OI 鍦� `t="inlineStr"` 鍗曞厓鏍间笂 `setCellValue(String)` 鍙啓 `<v>`銆佷笉鍔� `<is><t>`锛岃�� Excel/WPS 浼樺厛璇� `<is><t>`銆傚缃細鍐欏�煎墠鍏� `setBlank()` 娓呮帀鍘熷崟鍏冩牸鍐嶅啓锛堣惤鐩樹负鍏变韩涓诧紝`<is>` 涓嶅啀娈嬬暀鏃ф枃妗堬級銆�
+2. **POI 姹傚�煎彛寰勫亸宸�**锛氭簮鐙珛鎺掑悕琛ㄩ噷鎵嬪伐鐣欑┖鐨勫悓姣斾細璁� `RANK` 鍑芥暟姹傚�间竴寰嬭繑鍥� 1锛岀洿鎺ユ惉鍊间細鎶� 17 琛屻�屽閫熸帓鍚嶃�嶅啓鎴愬叏 1銆傚缃細婧愪晶鍏紡涓嶅啀鎼眰鍊肩粨鏋滐紝鑰屾槸鎸夌洰鏍囧潡鍋忕Щ骞崇Щ鎴愬叕寮忓啓鍏ワ紝鍐嶇敤姹囨�昏〃鑷韩鏁版嵁姹傚�肩紦瀛樸��
+3. **涓彛寰勬帓鍚嶅悓姣斿垪浠嶄负姣嶇増鏃у��**锛氬簱涓彧鏈� 2026-01~08 鐨勫杩愭暟鎹紙`h2031_enterprise_monthly` / `city_bus_monthly`锛夛紝娌℃湁 2025 瀹氱鏁版嵁锛岀嫭绔嬫帓鍚嶈〃绠椾笉鍑轰腑鍙e緞鍚屾瘮 鈫� 璇ュ垪鎸夎璁′繚鐣欐瘝鐗堝�硷紱绛� 2025 鏁版嵁鍏ュ簱鍚庨殢瀵煎嚭鑷姩鍒锋柊銆�
+4. **闈欐�侀〉寰呭姙**锛歚鍩庡競姹囨�籤銆乣鍩庡競鍒嗗競宸瀈銆乣涓彛寰勫垎鏋恅銆乣閬撹矾杩愯緭鍛ㄨ浆閲廯 鍥涢〉鍦ㄦ瘝鐗堥噷鏄暣椤甸潤鎬侊紙鏈疆瀵煎嚭涓庢瘝鐗堥�愭牸 0 宸紓锛夛紝椤垫爣棰樹粛鍐欍��1-7 鏈� / 7 鏈堛�嶃�傚洜鏁撮〉鏁版嵁鏈暟鎹┍鍔紝鏈疆**鏈�**鍙敼鏍囬锛堥伩鍏嶆爣棰� 8 鏈堛�佹暟鎹� 7 鏈堬級锛岀暀寰呭悗缁仛鎴愭暟鎹┍鍔ㄦ椂涓�骞跺鐞嗐��
+
+## 浜斻�佺粨璁�
+
+- 鐢ㄦ埛鍙嶉鐨勪袱涓棶棰樺潎宸蹭慨澶嶅苟楠岃瘉锛氫笁寮犳帓鍚嶉〉鐨勬爣棰樹笌鏁板�奸殢鎶ヨ〃鏈熷埛鏂帮紙璐ц繍閲忔帓鍚� 454 鏍奸�愭牸姣斿 0 宸紓锛夛紝8 鏈堝悓姣斿垪缁熶竴涓虹櫨鍒嗘暟鏄剧ず銆�
+- 2026-08 / 2026-07 鍙屾湡瀵煎嚭閫氳繃锛�7 鏈堝巻鍙叉湀鍥炲綊宸紓浠呴檺琚埛鏂扮殑鎺掑悕椤碉紝鏃犲壇浣滅敤銆�
+- 閬楃暀锛氫腑鍙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-11.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-11.md"
index 71fb4ee..4f60a44 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-11.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-11.md"
@@ -16,12 +16,22 @@
- 鐝嚎鍖呰溅銆佽建閬撹疆娓°�屽叏鐪併�嶈琛ラ綈鍚堣鍏紡锛堟瘝鐗堝師鍙 1 鏈堝啓姝诲叕寮忥級銆�
- 鐗堝紡鎸夌敤鎴锋寚瀹氬弬鐓т欢 `docs/鐢熸垚姹囨�诲ぇ琛�/鐢熸垚_閬撹矾杩愯緭閲忔眹鎬昏〃.xlsx` 閫愬垪瀵归綈鍒楀/闅愯棌锛�**8 鏈堟墿鍒� Q/R 鐨勫搴︿篃鍙栬嚜鍙傜収浠�**銆�
+### 3. 姹囨�昏〃鎺掑悕椤靛埛鏂� + 鍚屾瘮鐧惧垎鏁帮紙鐢ㄦ埛鏂板弽棣� 2 椤癸級
+- 鐢ㄦ埛鍙嶉銆岃揣杩愮殑姹囨�昏〃閲� 1.鎵�鏈夋帓鍚嶈〃鏁版嵁娌℃湁鏇存柊锛�2.鍚屾瘮搴旇鏄櫨鍒嗘暟鑰屼笉鏄皬鏁般�嶃��
+- 鎺掑悕椤碉細姣嶇増閲� `璐ц繍閲忔帓鍚峘/`璐ц繍鍛ㄨ浆閲忔帓鍚峘/`涓彛寰勬帓鍚峘 涓夐〉鏄笂涓�鏈熺殑闈欐�佸�笺�傚鍑烘椂鏀圭敤绋嬪簭鑷繁鐨勭嫭绔嬫帓鍚嶈〃锛堢敓鎴恄璐ц繍閲忔帓鍚�/鍛ㄨ浆閲忔帓鍚�/涓彛寰勬帓鍚嶏級鍒锋柊杩欎笁椤碉細鏁板�兼惉鍊笺�佹簮渚у叕寮忔寜鍋忕Щ骞崇Щ鍚庡啓鍏紡锛堟墦寮�閲嶇畻锛夈�佹瘝鐗堣嚜甯﹀叕寮忎繚鐣欍�佸潡鏍囬闅忔姤琛ㄦ湡鍚屾锛�1-7鏈堚啋1-8鏈堬級銆�
+- 鍚屾瘮鏍煎紡锛歚ensureMonthYoyFormulas` 鏀逛负鏃犳潯浠舵部鐢ㄤ笂鏈堝悓姣斿垪鏍峰紡锛堟瘝鐗堟妸鏂版湀浠藉悓姣斿垪鍋氭垚鏅�氭暟鍊� `0.00`锛屾樉绀烘垚灏忔暟锛夈��
+- 淇帀涓や釜鍧戯細鈶� 姣嶇増鏍囬鏄� inlineStr锛孭OI `setCellValue` 鍙啓 `<v>` 涓嶆洿鏂� `<is>`锛孍xcel 缁х画鏄剧ず 7 鏈� 鈫� 鍏� `setBlank()` 鍐嶅啓锛涒憽 鐩存帴鎼� POI 瀵规簮琛� RANK 鐨勬眰鍊肩粨鏋滀細鎶娿�屽閫熸帓鍚嶃�嶅啓鎴� 17 琛屽叏 1 鈫� 鏀逛负骞崇Щ鍐欏叕寮忋��
+
### 3. 鏂囨。褰掓。
- 鏄ㄥぉ宸插畬鎴愩�婃箹鍖楃渷閬撹矾璐х墿杩愯緭閲忓垎甯傚窞缁熻鏂规硶(2023)缂栧埗璇存槑銆嬪涔犵瑪璁板綊妗o紙`docs/璐ц繍/瀛︿範绗旇_鍒嗗競宸為亾璺揣鐗╄繍杈撻噺缁熻鏂规硶_2026-09-10.md`锛夛紝浠婂ぉ鏈啀鏀瑰姩銆�
## 浜屻�佹祴璇曠粨鏋滄憳瑕侊紙璇﹁銆婂姛鑳芥祴璇曟姤鍛娿�嬶級
- `docs/鍔熻兘娴嬭瘯鎶ュ憡/鍔熻兘娴嬭瘯鎶ュ憡_缃戠害杞﹁鍗曟姤鍛婂鍏2026-09-11.md`锛歍C-1~TC-7 鍏ㄩ儴閫氳繃锛�7 鏈堟姤鍛婅В鏋� 17 甯傚窞銆佸悎璁� 29,730,791锛屼笌搴撲腑閫愰」涓�鑷达紱涓ょ被璐熷悜鐢ㄤ緥鎻愮ず鏄庣‘銆�
- `docs/鍔熻兘娴嬭瘯鎶ュ憡/鍔熻兘娴嬭瘯鎶ュ憡_姹囨�诲ぇ琛�8鏈堟暟鎹洖濉笌鐗堝紡瀵归綈_2026-09-11.md`锛歍C-1~TC-16 鍏ㄩ儴閫氳繃銆�
+- `docs/鍔熻兘娴嬭瘯鎶ュ憡/鍔熻兘娴嬭瘯鎶ュ憡_姹囨�昏〃鎺掑悕椤靛埛鏂颁笌鍚屾瘮鐧惧垎鏁癬2026-09-11.md`锛氭鍚� 14 渚� / 璐熷悜 3 渚� / 鍥炲綊 4 渚嬪叏閮ㄩ�氳繃銆�
+ - 2026-08 瀵煎嚭鎴愬姛锛�23.8s / 949,956 瀛楄妭锛夛紱鏃ュ織銆屽埛鏂版帓鍚嶉〉鏁板�兼牸鏁�=711锛岀己鏁版彁绀�=[]銆嶃��
+ - 涓夊紶鎺掑悕椤垫爣棰樺凡鍒� 1-8 鏈�/8 鏈堬紱璐ц繍閲忔帓鍚嶄笌鐙珛鎺掑悕琛ㄩ�愭牸姣斿 454 鏍� 0 宸紓锛�8 鏈堝悓姣斿垪鍏ㄩ儴 `0.00%`銆�
+ - 7 鏈堝巻鍙叉湀鍥炲綊锛氫粎琚埛鏂扮殑鎺掑悕椤垫湁棰勬湡宸紓锛堣揣杩愰噺鎺掑悕 51 鏍笺�佷腑鍙e緞鎺掑悕 133 鏍硷級锛屽叾浣� 16 椤� 0 宸紓銆�
- 2026-08 瀵煎嚭鎴愬姛锛�4.6s / 948,735 瀛楄妭锛夛紱鍐欏叆褰撴湀鍊� 1659 鏍笺�佸綋鏈堝悓姣斿叕寮� 600 鏍笺�佸綋鏈堝悎璁″叕寮� 43 鏍笺�佺己鏁版彁绀轰负绌恒��
- 璐ц繍 危17 甯傚窞 = 鍏ㄧ渷锛�16888.7615锛夛紱缃戠害杞�/鍏氦/鍑虹/鐝嚎鍖呰溅/杞ㄩ亾杞浮鍏ㄧ渷琛屼笌甯傚窞琛屽潎姝g‘銆�
- 鍒楀涓庡弬鐓т欢**鐪熷疄宸紓 0 鍒�**銆�
@@ -32,9 +42,12 @@
2. 2026-08 瀵煎嚭浼氭墦鍗般�屾湭鎵惧埌鍚屾湡澶囦唤姣嶇増锛坃澶囦唤_2026骞�8鏈堚�︼級銆嶅憡璀︼紝灞炴棤瀹虫彁绀猴紙8 鏈堟瘝鐗堟湰韬畬鏁达級锛屽悗缁彲鑰冭檻鎸夐渶姹傚喅瀹氭槸鍚︽秷闄ゃ��
3. 鏍圭洰褰曞爢绉緝澶氬巻鍙蹭复鏃舵枃浠讹紙`_t_*.py`銆乣_*.sql`銆乣_gen_*.xlsx`銆乣_bak_*.java`銆乣_token.txt` 绛夛級锛屽緟鐢ㄦ埛鍚屾剰鍚庨泦涓竻鐞嗐��
4. 鐗堝紡鍙傜収浠� `docs/鐢熸垚姹囨�诲ぇ琛�/鐢熸垚_閬撹矾杩愯緭閲忔眹鎬昏〃.xlsx` 鐩墠涓烘湭鍏ュ簱鏂囦欢锛屾槸鍚︾撼鍏ョ増鏈鐞嗗緟纭銆�
+5. 涓彛寰勬帓鍚嶇殑銆屽悓姣斿閫熴�嶅垪浠嶆槸姣嶇増鏃у�硷細搴撲腑鍙湁 2026 骞存暟鎹紝娌℃湁 2025 骞翠腑鍙e緞瀹氱鏁版嵁锛岀畻涓嶅嚭 8 鏈堝悓姣旓紱绛� 2025 鏁版嵁鍏ュ簱鍚庤嚜鍔ㄥ埛鏂般��
+6. `鍩庡競姹囨�籤/`鍩庡競鍒嗗競宸瀈/`涓彛寰勫垎鏋恅/`閬撹矾杩愯緭鍛ㄨ浆閲廯 鍥涢〉鍦ㄦ瘝鐗堥噷鏄暣椤甸潤鎬侊紙鏈疆瀵煎嚭涓庢瘝鐗� 0 宸紓锛夛紝鏍囬浠嶅啓 7 鏈堬紝闇�鍚庣画鍋氭垚鏁版嵁椹卞姩鍚庝竴骞舵洿鏂般��
## 鍥涖�佹槑澶╄鍒�
1. 鐢ㄦ埛閲嶄紶鐪熷疄 8 鏈堢綉绾﹁溅鎶ュ憡鍚庯紝閲嶆柊瀵煎嚭 2026-08 骞堕�愰」澶嶆牳缃戠害杞﹂〉銆�
2. 缁х画鎸夌敤鎴峰弽棣堟牳瀵� 8 鏈堟眹鎬诲ぇ琛ㄦ垚鍝侊紙閲嶇偣锛氫腑鍙e緞鍚勯〉銆佽揣杩愭帓鍚嶉〉锛夈��
3. 娓呯悊涓存椂鏂囦欢锛堥渶鐢ㄦ埛纭锛夈��
+4. 瑙嗙敤鎴峰弽棣堝喅瀹氭槸鍚︽妸鍥涘紶闈欐�佹垚鍝侀〉锛堝煄甯傛眹鎬�/鍩庡競鍒嗗競宸�/涓彛寰勫垎鏋�/閬撹矾杩愯緭鍛ㄨ浆閲忥級鍋氭垚鏁版嵁椹卞姩銆�
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 1abdfca..5cf99d7 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
@@ -530,10 +530,9 @@
String f = prev.getCellFormula();
if (f == null || f.isEmpty()) continue;
String shifted = shiftFormulaColumns(f, 2);
- if (target == null) {
- target = row.createCell(yoyCol);
- if (prev.getCellStyle() != null) target.setCellStyle(prev.getCellStyle());
- }
+ if (target == null) target = row.createCell(yoyCol);
+ // 姣嶇増鎶婃柊鏈堜唤鐨勫悓姣斿垪鍋氭垚浜嗘櫘閫氭暟鍊兼牸寮忥紙鏄剧ず鎴愬皬鏁帮級锛岀粺涓�娌跨敤涓婃湀鍚屾瘮鍒楃殑鏍峰紡锛堢櫨鍒嗘暟锛�
+ if (prev.getCellStyle() != null) target.setCellStyle(prev.getCellStyle());
try {
target.setCellFormula(shifted);
written++;
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 c8ae866..ceea4f1 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
@@ -53,6 +53,7 @@
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -3351,10 +3352,11 @@
int dbFilled = summaryWorkbookFiller.fillMonthlyLedger(wb, effPeriod, year, effMonth, dbProblems);
int yoyFilled = summaryWorkbookFiller.ensureMonthYoyFormulas(wb, year, effMonth);
int monthFormulaFilled = summaryWorkbookFiller.ensureMonthFormulas(wb, year, effMonth);
+ int rankRefreshed = refreshSummaryRankSheets(wb, effPeriod, "month");
int widthApplied = applySummaryReferenceLayout(wb);
log.info("姹囨�诲伐浣滅翱鏁版嵁椹卞姩鍥炲~瀹屾垚锛氬啓鍏ュ綋鏈堝�兼牸鏁�={}锛岃ˉ鍐欏綋鏈堝悓姣斿叕寮忔牸鏁�={}锛岃ˉ鍐欏綋鏈堝悎璁″叕寮忔牸鏁�={}锛�"
- + "鎸夈�婄敓鎴恄閬撹矾杩愯緭閲忔眹鎬昏〃銆嬪榻愬垪瀹藉垪鏁�={}锛岀己鏁版彁绀�={}",
- dbFilled, yoyFilled, monthFormulaFilled, widthApplied, dbProblems);
+ + "鍒锋柊鎺掑悕椤垫暟鍊兼牸鏁�={}锛屾寜銆婄敓鎴恄閬撹矾杩愯緭閲忔眹鎬昏〃銆嬪榻愬垪瀹藉垪鏁�={}锛岀己鏁版彁绀�={}",
+ dbFilled, yoyFilled, monthFormulaFilled, rankRefreshed, widthApplied, dbProblems);
applyTwoDecimalFormat(wb); // 鏁板�兼樉绀轰袱浣嶅皬鏁帮紙淇濈暀鍏ㄧ簿搴︼級锛�% / 鏃ユ湡绛夋棦鏈夋牱寮忎笉鏀瑰彉
if (!wb.getCTWorkbook().isSetCalcPr()) wb.getCTWorkbook().addNewCalcPr();
wb.getCTWorkbook().getCalcPr().setFullCalcOnLoad(true); // 杩樺師/鏀瑰啓鍏紡鍚庢墦寮�鍗抽噸绠�
@@ -3441,6 +3443,216 @@
return max;
}
+ // ==================== 姹囨�诲伐浣滅翱鍐呯殑鎺掑悕椤靛埛鏂� ====================
+
+ /**
+ * 姹囨�诲伐浣滅翱閲岀殑銆岃揣杩愰噺鎺掑悕 / 璐ц繍鍛ㄨ浆閲忔帓鍚� / 涓彛寰勬帓鍚嶃�嶅湪姣嶇増閲屾槸涓婁竴鎶ヨ〃鏈熺殑闈欐�佸�硷紝
+ * 瀵煎嚭鏃剁敤鐙珛鎺掑悕琛紙銆婄敓鎴恄璐ц繍閲忔帓鍚嶃�嬨�婄敓鎴恄鍛ㄨ浆閲忔帓鍚嶃�嬨�婄敓鎴恄涓彛寰勬帓鍚嶃�嬶紝涓庣敤鎴锋棩甯告牳瀵圭殑鍙e緞涓�鑷达級
+ * 鐨勭粨鏋滃埛鏂版暟鍊硷紝閬垮厤姹囨�昏〃閲岀殑鎺掑悕椤靛仠鐣欏湪鏃ф湀浠姐��
+ * 鏁板�兼牸鎼�笺�佸叕寮忔牸鎸夊亸绉诲钩绉诲叕寮忓悗鍐欏叆锛涚洰鏍囨牸鏈韩宸叉槸鍏紡鐨勶紙SUM/RANK/鍗犳瘮/琛ユ暟锛変繚鐣欎笉鍔紝鎵撳紑鏃舵寜鏂版暟鎹噸绠椼��
+ */
+ private int refreshSummaryRankSheets(XSSFWorkbook wb, String period, String mode) throws Exception {
+ int n = 0;
+ n += copyRankValues(wb, "璐ц繍閲忔帓鍚�", exportFreightRank(period, mode), new int[][]{{0, 0}, {22, 0}});
+ n += copyRankValues(wb, "璐ц繍鍛ㄨ浆閲忔帓鍚�", exportTurnoverRank(period, mode), new int[][]{{0, 0}, {22, 0}});
+ n += copyRankValues(wb, "涓彛寰勬帓鍚�", exportPassengerMidRank(period, mode), new int[][]{{0, 0}, {0, 10}});
+ return n;
+ }
+
+ /**
+ * 鎶婄嫭绔嬫帓鍚嶈〃鐨勫悇涓潡鎸夋爣棰樺榻愭惉杩涙眹鎬诲ぇ琛ㄥ搴旈〉銆�
+ * srcBlocks[i] = 婧愬潡 i 鐨勮捣濮� {琛�, 鍒梷锛�0 鍩猴級锛涚洰鏍囧潡鎸夋爣棰橀『搴忥紙绱鍧楀湪鍓嶃�佸綋鏈堝潡鍦ㄥ悗锛夊搴斻��
+ * 鏁板�兼牸鐩存帴鎼�硷紱婧愪晶鏄叕寮忕殑锛堟帓鍚�/鍗犳瘮绛夛級鎸夌洰鏍囧潡鍋忕Щ鏁翠綋骞崇Щ鍚庡啓鍏ュ叕寮忥紝鎵撳紑鏃舵寜姹囨�昏〃鑷韩鏁版嵁閲嶇畻銆�
+ */
+ private int copyRankValues(XSSFWorkbook dstWb, String dstSheetName, byte[] srcBytes, int[][] srcBlocks) throws Exception {
+ XSSFSheet dst = dstWb.getSheet(dstSheetName);
+ if (dst == null) return 0;
+ List<XSSFCell> dstTitles = rankTitleCells(dst);
+ if (dstTitles.isEmpty()) return 0;
+ int copied = 0;
+ FormulaEvaluator dstEv = dstWb.getCreationHelper().createFormulaEvaluator();
+ try (InputStream sin = new ByteArrayInputStream(srcBytes);
+ XSSFWorkbook srcWb = new XSSFWorkbook(sin)) {
+ XSSFSheet src = srcWb.getSheetAt(0);
+ FormulaEvaluator ev = srcWb.getCreationHelper().createFormulaEvaluator();
+ int blocks = Math.min(srcBlocks.length, dstTitles.size());
+ for (int b = 0; b < blocks; b++) {
+ int sr0 = srcBlocks[b][0];
+ int sc0 = srcBlocks[b][1];
+ XSSFCell dstTitle = dstTitles.get(b);
+ int rowOff = dstTitle.getRowIndex() - sr0;
+ int colOff = dstTitle.getColumnIndex() - sc0;
+ int h = rankBlockHeight(src, sr0, sc0);
+ int w = rankBlockWidth(src, sr0, sc0);
+ for (int r = 0; r < h; r++) {
+ Row srcRow = src.getRow(sr0 + r);
+ if (srcRow == null) continue;
+ Row dstRow = dst.getRow(sr0 + r + rowOff);
+ if (dstRow == null) dstRow = dst.createRow(sr0 + r + rowOff);
+ for (int c = 0; c < w; c++) {
+ Cell sc = srcRow.getCell(sc0 + c);
+ if (sc == null) continue;
+ int dc = sc0 + c + colOff;
+ if (r == 0) {
+ // 鏍囬琛岋細鍚屾鍧楁爣棰樻枃妗堛�傛瘝鐗堟爣棰樻槸 inlineStr锛孭OI 鐨� setCellValue 鍙啓 <v>銆�
+ // 涓嶆洿鏂� <is>锛孍xcel 浼氱户缁樉绀烘棫鏈堜唤锛屽繀椤诲厛 setBlank 娓呮帀鍐嶅啓銆�
+ Cell dt = dstRow.getCell(dc);
+ if (dt == null) dt = rankCell(dstRow, dc);
+ if (sc.getCellType() == CellType.STRING && dt.getCellType() != CellType.FORMULA) {
+ String text = sc.getStringCellValue();
+ String old = dt.getCellType() == CellType.STRING ? dt.getStringCellValue() : null;
+ if (text != null && !text.equals(old)) {
+ dt.setBlank();
+ dt.setCellValue(text);
+ }
+ }
+ continue;
+ }
+ Cell dcCell = dstRow.getCell(dc);
+ if (dcCell != null && dcCell.getCellType() == CellType.FORMULA) continue; // 淇濈暀姣嶇増鑷繁鐨勫叕寮�
+ if (sc.getCellType() == CellType.FORMULA) {
+ // 婧愪晶鍏紡锛堟帓鍚�/鍗犳瘮锛夛細鎸夌洰鏍囧潡鍋忕Щ骞崇Щ鍚庡師鏍峰啓鍏ワ紝鍐嶆寜姹囨�昏〃鑷韩鏁版嵁姹傚�肩紦瀛樸��
+ // 涓嶇洿鎺ユ惉 POI 瀵规簮琛ㄧ殑姹傚�肩粨鏋滐紙濡� RANK 瀵规墜宸ョ暀绌虹殑鍚屾瘮涓�寰嬭繑鍥� 1锛夈��
+ String f = sc.getCellFormula();
+ if (f == null || f.isEmpty()) continue;
+ String shifted = shiftFormula(f, colOff, rowOff);
+ if (dcCell == null) dcCell = rankCell(dstRow, dc);
+ dcCell.setCellFormula(shifted);
+ try {
+ dstEv.evaluateFormulaCell(dcCell);
+ } catch (Exception ignore) {
+ // 姹傚�煎け璐ヤ笉闃诲瀵煎嚭锛氭墦寮�鏃剁敱 Excel/WPS 閲嶇畻
+ }
+ copied++;
+ continue;
+ }
+ Double v = rankNumeric(sc, ev);
+ if (v == null) continue;
+ if (dcCell == null) dcCell = rankCell(dstRow, dc);
+ dcCell.setCellValue(v);
+ copied++;
+ }
+ }
+ }
+ }
+ return copied;
+ }
+
+ /** 鐩爣鍧楃己鏍兼椂鏂板缓锛屽苟娌跨敤鍚岃宸﹂偦鏍兼牱寮忥紙闃叉柊鏍间涪杈规/鐧惧垎鏁版牸寮忥級 */
+ private Cell rankCell(Row row, int col) {
+ Cell c = row.createCell(col);
+ Cell left = col > 0 ? row.getCell(col - 1) : null;
+ if (left != null) c.setCellStyle(left.getCellStyle());
+ return c;
+ }
+
+ /** 鍏紡鍐呮墍鏈� A1 寮曠敤鏁翠綋骞崇Щ锛氬垪 +dCol銆佽 +dRow锛圫UM/RANK 绛夊嚱鏁板悕鍚庢帴鎷彿涓嶄細琚尮閰嶏級 */
+ private String shiftFormula(String formula, int dCol, int dRow) {
+ if (formula == null || (dCol == 0 && dRow == 0)) return formula;
+ java.util.regex.Matcher m = java.util.regex.Pattern
+ .compile("(?<![A-Za-z0-9_$])([$]?)([A-Z]{1,3})([$]?)([0-9]+)")
+ .matcher(formula);
+ StringBuffer sb = new StringBuffer();
+ while (m.find()) {
+ String col = m.group(2);
+ int idx = 0;
+ for (int i = 0; i < col.length(); i++) idx = idx * 26 + (col.charAt(i) - 'A' + 1);
+ int nidx = Math.max(1, idx + dCol);
+ StringBuilder nc = new StringBuilder();
+ while (nidx > 0) {
+ int rem = (nidx - 1) % 26;
+ nc.insert(0, (char) ('A' + rem));
+ nidx = (nidx - 1) / 26;
+ }
+ int nrow = Math.max(1, Integer.parseInt(m.group(4)) + dRow);
+ m.appendReplacement(sb, java.util.regex.Matcher.quoteReplacement(m.group(1) + nc + m.group(3) + nrow));
+ }
+ m.appendTail(sb);
+ return sb.toString();
+ }
+
+ /** 鎺掑悕椤甸噷鐨勨�滃潡鏍囬鈥濆崟鍏冩牸锛堝惈鈥滃叏鐪佸垎甯傚窞鈥濈殑璇存槑鏂囧瓧锛夛紝鎸夎銆佸垪椤哄簭杩斿洖 */
+ private List<XSSFCell> rankTitleCells(Sheet sh) {
+ List<XSSFCell> out = new ArrayList<>();
+ for (int r = sh.getFirstRowNum(); r <= sh.getLastRowNum(); r++) {
+ Row row = sh.getRow(r);
+ if (row == null) continue;
+ for (int c = row.getFirstCellNum(); c < row.getLastCellNum(); c++) {
+ Cell cell = row.getCell(c);
+ if (cell == null || cell.getCellType() != CellType.STRING) continue;
+ String t = cell.getStringCellValue();
+ if (t != null && t.contains("鍏ㄧ渷鍒嗗競宸�")) out.add((XSSFCell) cell);
+ }
+ }
+ return out;
+ }
+
+ /** 鍧楅珮搴︼細浠庤捣濮嬭鍚戜笅鐩村埌鏁磋涓虹┖锛堝湪鍧楀垪鑼冨洿鍐咃級 */
+ private int rankBlockHeight(Sheet sh, int r0, int c0) {
+ int h = 0;
+ for (int r = r0; r <= sh.getLastRowNum(); r++) {
+ Row row = sh.getRow(r);
+ boolean any = false;
+ if (row != null) {
+ int last = row.getLastCellNum();
+ for (int c = c0; c < last; c++) {
+ if (rankHasContent(row.getCell(c))) { any = true; break; }
+ }
+ }
+ if (!any) break;
+ h++;
+ }
+ return h;
+ }
+
+ /** 鍧楀搴︼細浠庤捣濮嬪垪鍚戝彸鐩村埌鏁村垪涓虹┖锛堝湪鍧楄鑼冨洿鍐咃紝鎵弿涓婇檺 40 鍒楋級 */
+ private int rankBlockWidth(Sheet sh, int r0, int c0) {
+ int w = 0;
+ for (int c = c0; c < c0 + 40; c++) {
+ boolean any = false;
+ for (int r = r0; r < r0 + 30; r++) {
+ Row row = sh.getRow(r);
+ if (row != null && rankHasContent(row.getCell(c))) { any = true; break; }
+ }
+ if (!any) break;
+ w++;
+ }
+ return w;
+ }
+
+ private boolean rankHasContent(Cell c) {
+ if (c == null) return false;
+ CellType t = c.getCellType();
+ if (t == CellType.BLANK) return false;
+ if (t == CellType.STRING) {
+ String v = c.getStringCellValue();
+ return v != null && !v.trim().isEmpty();
+ }
+ return true;
+ }
+
+ /** 鍙栧崟鍏冩牸鏁板�硷紙鍏紡鍙栨眰鍊肩粨鏋滐紝绾暟瀛楁枃鏈寜鏁板�艰В鏋愶級锛屽彇涓嶅埌杩斿洖 null */
+ private Double rankNumeric(Cell c, FormulaEvaluator ev) {
+ try {
+ CellType t = c.getCellType();
+ if (t == CellType.NUMERIC) return c.getNumericCellValue();
+ if (t == CellType.FORMULA) {
+ org.apache.poi.ss.usermodel.CellValue cv = ev.evaluate(c);
+ return cv != null && cv.getCellType() == CellType.NUMERIC ? cv.getNumberValue() : null;
+ }
+ if (t == CellType.STRING) {
+ String v = c.getStringCellValue();
+ if (v == null) return null;
+ String x = v.replace(",", "").trim();
+ if (x.isEmpty()) return null;
+ try { return Double.parseDouble(x); } catch (NumberFormatException ignore) { return null; }
+ }
+ } catch (Exception ignore) {
+ return null;
+ }
+ return null;
+ }
+
/** 瀹氫綅鐗堝紡鍙傜収浠� docs/鐢熸垚姹囨�诲ぇ琛�/鐢熸垚_閬撹矾杩愯緭閲忔眹鎬昏〃.xlsx锛堜紭鍏堢骇鍚屾瘝鐗堬細閰嶇疆鐩綍 鈫� user.dir 鐩稿 鈫� 涓婄骇锛� */
private File resolveSummaryLayoutRef() {
String rel = summaryTemplateDir;
--
Gitblit v1.9.1