From 595b31273d583fbe367b3bfbebb6fc02e318abc0 Mon Sep 17 00:00:00 2001
From: zhizhijie <zhizhijie@users.noreply.gitee.com>
Date: 星期二, 22 九月 2026 16:51:25 +0800
Subject: [PATCH] fix(投资): 明细表取数三处静默缺陷 + 导入两处丢数/选错页签缺陷

---
 HANDOFF.md                                                                                        |    7 +
 docs/功能测试报告/功能测试报告_投资明细表取数修复_2026-09-22.md                                                        |   91 ++++++++++++++++++
 traffic-audit-server/src/main/java/com/trafficaudit/dataimport/service/DataImportService.java     |   75 +++++++++++---
 traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java |   58 +++++++++++
 docs/工作日结/工作日结_2026-09-22.md                                                                      |   18 +++
 5 files changed, 230 insertions(+), 19 deletions(-)

diff --git a/HANDOFF.md b/HANDOFF.md
index b71484c..88daa9d 100644
--- a/HANDOFF.md
+++ b/HANDOFF.md
@@ -11,6 +11,13 @@
 - **浠婃棩宸插畬鎴愶紙杩滅鎻愪氦锛�**锛氭暟鎹煡鐪嬭ˉ榻愮綉绾﹁溅/涓綋瀹㈣繍銆佹寜甯傚窞姹囨�讳笌瀵煎嚭 Excel銆佹眹鎬诲ぇ琛ㄨ繘搴﹀脊绐椾笌缁撴灉钀界洏缂撳瓨銆�
 - **鏈畬鎴愰噸鐐逛笉鍙�**锛歅0-2銆婁嚎鍏冩姇璧勯」鐩�嬫寜 Q7 杩藉垪銆丳0-3 瀵煎嚭鍓嶅熀鏁颁綋妫�銆丳0-4 2026-09 姣嶇増锛涘叾浣欒 `docs/浜ゆ帴鏂囨。_2026-09-21.md` 绗� 4 绔犮��
 
+### 琛ュ厖锛�2026-09-22 涓嬪崍锛屾姇璧勫彇鏁颁慨澶嶇涓�杞級
+
+- **宸蹭慨锛堜唬鐮� + 閲嶅 + 鍥炲綊锛�**锛氣憼 瀵煎嚭鍘绘爣鐐瑰綊涓�鍖栧尮閰嶏紙鑽嗗窞锛夛紱鈶� 鍚屽悕鍙屾。浼樺厛鍙栧綋鏈堟湁鏁版嵁鐨勬。锛堝崄鍫板揩閫掍骇涓氬洯浜屾湡锛夛紱鈶� 鏈鐩栬閫愯 WARN 鐣欑棔锛涒懀 瀵煎叆琛ㄥご鍘绘崲琛岋紙澶╅棬 H/J/K 涓嶅啀涓級锛涒懁 瀵煎叆鎸夎〃鍐呮姤琛ㄦ湡閫� sheet锛�**娼滄睙涓嶅啀鎶� 2018 骞存暟鎹綋 2026-08**锛夈��
+- **缁撴灉**锛�2026-08 鐗╂祦/瀹㈣繍鏄庣粏閫愭牸宸紓 **156 鈫� 129**锛屾棤鏂板宸紓锛涙湭瑕嗙洊娓呭崟宸茶兘鑷姩鍒楀嚭锛堢墿娴佹姹� 6 琛岋紱瀹㈣繍榛勭煶1/榛勫唸9/鎭╂柦1/浠欐1锛夈��
+- **閬楃暀锛堜笅涓�杞級**锛歀/D/E/F 瑕嗙洊鍙e緞锛堥渶銆婂缓璁鹃樁娈靛綊涓�琛ㄣ�嬶級銆佹姹夌墿娴佷笌榛勫唸瀹㈣繍 8 鏈堟簮鏁版嵁銆佹綔姹� 2026-06/07 鍘嗗彶閿欏�奸噸瀵笺�佹湭瑕嗙洊娓呭崟鍑烘枃浠�/椤甸潰鎻愮ず锛圥1-9锛夈��
+- **鎶ュ憡**锛歚docs/鍔熻兘娴嬭瘯鎶ュ憡/鍔熻兘娴嬭瘯鎶ュ憡_鎶曡祫鏄庣粏琛ㄥ彇鏁颁慨澶峗2026-09-22.md`銆�
+
 ### 琛ュ厖锛�2026-09-22 涓嬪崍锛屾姇璧勬槑缁嗚〃姣斿锛�
 
 - **宸插畬鎴�**锛氳蒋浠躲�婂杩愮珯鎶曡祫鏄庣粏琛ㄣ�嬨�婄墿娴佺珯鍦烘姇璧勬槑缁嗐�嬩笌浜哄伐鐗堥�愭牸姣斿锛�156 鏍煎樊寮傦級锛屾姤鍛� `docs/鍔熻兘娴嬭瘯鎶ュ憡/鏁版嵁姣斿鎶ュ憡_鎶曡祫鏄庣粏琛ㄨ蒋浠剁敓鎴愪笌浜哄伐鐗坃2026-09-22.md`銆�
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\212\225\350\265\204\346\230\216\347\273\206\350\241\250\345\217\226\346\225\260\344\277\256\345\244\215_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\212\225\350\265\204\346\230\216\347\273\206\350\241\250\345\217\226\346\225\260\344\277\256\345\244\215_2026-09-22.md"
new file mode 100644
index 0000000..abc52ff
--- /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\212\225\350\265\204\346\230\216\347\273\206\350\241\250\345\217\226\346\225\260\344\277\256\345\244\215_2026-09-22.md"
@@ -0,0 +1,91 @@
+# 鍔熻兘娴嬭瘯鎶ュ憡 鈥� 鎶曡祫鏄庣粏琛ㄥ彇鏁颁慨澶嶏紙杞欢鐢熸垚 vs 浜哄伐鐗� 宸紓鏀舵暃锛�
+> 娴嬭瘯鏃ユ湡锛�2026-09-22
+> 琚祴瀵硅薄锛氭姤琛ㄧ敓鎴� 鈫� 鎶曡祫銆婂杩愮珯鎶曡祫鏄庣粏琛ㄣ�嬨�婄墿娴佺珯鍦烘姇璧勬槑缁嗐�嬪鍑� + 鎶曡祫鏈堟姤锛堝競宸炲崟琛級瀵煎叆
+> 鑳屾櫙锛氥�婃暟鎹瘮瀵规姤鍛奯鎶曡祫鏄庣粏琛ㄨ蒋浠剁敓鎴愪笌浜哄伐鐗坃2026-09-22.md銆嬪畾浣嶅嚭 156 鏍煎樊寮備笌 3 绫�"浼氶潤榛樺嚭鏁�"鐨勫彇鏁扮己闄凤紝鏈姤鍛婁负绗竴杞慨澶嶄笌鍥炲綊楠岃瘉銆�
+
+## 涓�銆佸姛鑳借鏄庯紙鏈鏀逛簡浠�涔堬級
+
+### 1. 瀵煎嚭锛歚traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java`
+| # | 鏀瑰姩 | 璇存槑 |
+| --- | --- | --- |
+| 1-1 | `normInvestName()` 褰掍竴鍖栬ˉ鏍囩偣 | 澧炲姞鍗�/鍏ㄨ鍙ョ偣銆侀】鍙枫�侀�楀彿銆佸垎鍙枫�佸啋鍙风瓑锛堝師鍙幓 `路鈥⑩�旓紞_-`锛夈�傚簱鍐呴」鐩悕銆屼腑鍥戒緵閿�**.**鍏畨鍟嗚锤鐗╂祦鍥�嶄笌鏄庣粏琛ㄨ鍚嶃�屼腑鍥戒緵閿�鍏畨鍟嗚锤鐗╂祦鍥紙鍏畨鍘垮煙闆嗛噰闆嗛厤涓績锛夈�嶅綊涓�鍖栧悗鍓嶇紑涓�鑷� 鈫� 鍙尮閰� |
+| 1-2 | 鏂板 `preferMonthlyCandidate()` | 鍖归厤鍒扮殑妗e湪**褰撴湀鏃犳暟鎹�**鏃讹紝鏀归�夈�屽綊涓�鍖栧悓鍚嶄笖褰撴湀鏈夋暟鎹�嶇殑妗o紙鍙� id 鏈�澶ц�咃級銆備慨澶嶅崄鍫般�屽揩閫掔墿娴佷骇涓氬洯浜屾湡銆嶅彇鍒版棫妗� id=154锛堟湀搴﹀彧鍒� 7 鏈堬級鐨勯棶棰� |
+| 1-3 | 鏂板 `logSkippedRows()` + 瀹㈣繍/鐗╂祦瀵煎嚭鐣欑棔 | 鏈寜褰撴湀鏁版嵁瑕嗙洊鐨勮**閫愯 WARN**锛歚[鏈鐩朷 绗琋琛� 甯傚窞 椤圭洰鍚� 鈫� 鍘熷洜`锛屽苟缁欏嚭鎸夊競宸炵粺璁°�傚交搴曟秷闄�"闈欓粯缁撹浆涓婃湡鍊�" |
+
+### 2. 瀵煎叆锛歚traffic-audit-server/src/main/java/com/trafficaudit/dataimport/service/DataImportService.java`
+| # | 鏀瑰姩 | 璇存槑 |
+| --- | --- | --- |
+| 2-1 | `investHeaderKey()` 鍏堝幓绌虹櫧鍐嶅垽瀹� | 琛ㄥご鍗曞厓鏍煎父鍚崲琛�/鍏ㄨ绌烘牸锛堝ぉ闂ㄣ�岃嚜寮�濮嬪缓\n璁剧疮璁″畬\n鎴愭姇璧刓n(涓囧厓)銆嶏級锛屽師閫昏緫 `v.contains("鑷紑濮嬪缓璁�")` 鍖归厤涓嶄笂 鈫� H/J/K 涓夊垪鏄犲皠钀藉埌 -1 琚啓鎴� 0銆傛敼涓� `replaceAll("[\\s\\u3000]+","")` 鍚庡啀鍒ゅ畾 |
+| 2-2 | 鏂板 `investSheetPeriodCellHit()` + 璇勫垎鍔犳潈 | 澶� sheet 鍘嗗彶鏂囦欢鎸� sheet 鍚嶅尮閰嶆湀浠戒細鎶� 2018 骞寸殑銆屾綔姹燂紙8鏈堬級銆嶅綋鎴� 2026-08銆傛柊澧�"琛ㄥ唴鎶ヨ〃鏈�"鍛戒腑锛坰heet 鍓� 8 琛岀殑 `2026.08.24` / `2026骞�8鏈坄 / 鏃ユ湡鍗曞厓鏍硷級锛屾潈閲� 2000000 楂樹簬 sheet 鍚嶅尮閰嶏紙1000000锛� |
+
+## 浜屻�佹祴璇曠幆澧�
+- 鍚庣锛歚mvn spring-boot:run`锛�8090锛夛紝閲嶅惎鍚庢棩蹇楀嚭鐜� `Started TrafficAuditApplication`锛涘墠绔� 8080 鍦ㄨ繍琛�
+- 鏁版嵁搴擄細`localhost:3308/traffic_audit`锛堟湰鏈哄紑鍙戝簱锛夛紱鐧诲綍 `admin/123456` 鍙� JWT
+- 浜哄伐鐗堝熀鍑嗭細`D:\05_鏁版嵁鍒嗙被\鎶曡祫\8鏈圽8鏈堝杩愮珯鎶曡祫鏄庣粏琛�.xlsx`銆乣8鏈堢墿娴佺珯鍦烘姇璧勬槑缁�.xls`
+- 淇鍓嶈蒋浠剁増锛歚D:\妗岄潰\鐢熸垚鏁版嵁\鐢熸垚_鎵�閫夋姤琛╛2026-08 (1)\鈥
+- 淇鍚庤蒋浠剁増锛歚_tmp/gen_new_0922/鈥锛堟湰娆¢噸璺戝鍑猴級
+- 姣斿鑴氭湰锛歚_tmp_diff_invest_0922.py`锛堜慨澶嶅墠锛夈�乣_tmp_diff_after_fix_0922.py`锛堜慨澶嶅悗锛�
+
+## 涓夈�佹祴璇曠敤渚嬩笌缁撴灉
+
+| # | 鐢ㄤ緥 | 杈撳叆 | 棰勬湡 | 瀹為檯 | 缁撹 |
+| --- | --- | --- | --- | --- | --- |
+| 1 | 瀵煎嚭-椤圭洰鍚嶅甫鏍囩偣 | 2026-08 鐗╂祦鏄庣粏瀵煎嚭 | 绗�119/120琛屻�屼腑鍥戒緵閿�鍏畨鍟嗚锤鐗╂祦鍥�嶆寜搴撳唴褰撴湀鍐欏叆 | 淇鍓嶏細鏈鐩栵紝淇濈暀搴曠 7758.5/7758.5/1600.1锛涗慨澶嶅悗锛氬啓鍏� **15986/15986/8227.5** 涓庢簮琛ㄤ竴鑷达紱鏃ュ織涓嶅啀鍒楄琛� | 鉁� |
+| 2 | 瀵煎嚭-鍚屽悕鍙屾。 | 鍚屼笂 | 鍙栥�屽綋鏈堟湁鏁版嵁銆嶇殑妗o紙id=181锛� | 淇鍓嶏細20081/2900/214銆佺宸� 2026锛涗慨澶嶅悗锛�**20377/3196/296銆佺宸� 2029**锛�= 鍗佸牥婧愯〃 R71锛� | 鉁� |
+| 3 | 瀵煎嚭-鏈鐩栫暀鐥曪紙鐗╂祦锛� | 鍚屼笂 | 鏈鐩栬鍒楀嚭琛屽彿+甯傚窞+椤圭洰鍚�+鍘熷洜 | 鏃ュ織锛歚鐗╂祦绔欏満鎶曡祫鏄庣粏 2026-08锛氬啓鍏� 93 琛岋紝缁撹浆姣嶇増鍘熷�� 6 琛宍 + 6 鏉� `[鏈鐩朷 绗�12琛� 姝︽眽甯� 鑸彂鏅烘収鐗╂祦鍥� 鈫� 搴撳唴鏃� 2026-08 鏈堝害鏁版嵁`锛堟寜甯傚窞缁熻 `{姝︽眽甯�=6}`锛� | 鉁� |
+| 4 | 瀵煎嚭-鏈鐩栫暀鐥曪紙瀹㈣繍锛� | 鍚屼笂 | 鍚屼笂 | `鍐欏叆 37 琛岋紝缁撹浆姣嶇増鍘熷�� 12 琛岋紙鍏朵腑搴撳唴鏈夐」鐩絾褰撴湀鏃犳暟鎹� 9 琛岋級` + 12 鏉℃槑缁嗭紙榛勭煶 1 / 榛勫唸 9 / 鎭╂柦 1 / 浠欐 1锛� | 鉁� |
+| 5 | 瀵煎叆-琛ㄥご鍚崲琛岋紙澶╅棬锛� | `8鏈堜唤鐗╂祦鍥腑蹇冨缓璁鹃」鐩�(澶╅棬).xlsx`锛宲eriod=2026-08锛宼ype=investmentLogistics | 鍏ュ簱 16677.7 / 16677.7 / 500 | 淇鍓嶅簱鍐� 0/0/0锛涗慨澶嶅悗 `investment_monthly` = **16677.7 / 16677.7 / 500**锛屾帴鍙h繑鍥� success=1 | 鉁� |
+| 6 | 瀵煎叆-鍘嗗彶椤电锛堟綔姹燂級 | `娼滄睙2026.08.xlsx`锛堝惈 20 涓巻鍙� sheet锛� | 閫夊綋鏈� sheet锛堣〃鍐呮姤琛ㄦ湡 2026.08.24锛� | 淇鍓嶏細鍏ュ簱 **2018 骞�**銆屾綔姹熷競鍏矾椤圭洰銆�5173/5173/1440锛堥敊锛夛紱淇鍚庯細鍏ュ簱銆�**涓浗铏捐胺鍐烽摼浠撳偍鐗╂祦鍥�**銆�11947.9/1135/0锛�= 婧愯〃褰撴湡 sheet锛夛紝鏃ч敊琛岃鍚屽競宸炲悓鏈熼棿娓呯悊 | 鉁� |
+| 7 | 鍥炲綊-閫愭牸姣斿 | 淇鍚庡鍑� vs 浜哄伐鐗� | 宸紓鏁颁笅闄嶄笖鏃犳柊澧炲樊寮� | 156 鏍� 鈫� **129 鏍�**锛堥檷 27锛夛紝鍓╀綑宸紓涓庝慨澶嶅墠閫愭潯瀵瑰簲锛屾棤鏂板 | 鉁� |
+| 8 | 璐熷悜-鏈尮閰嶈涓嶅啓閿欏�� | 姝︽眽 6 琛岋紙搴撳唴鏃� 2026-08 鏁版嵁锛� | 淇濇寔搴曠鍘熷�间笖蹇呴』鏈夋棩蹇楀憡璀� | 6 琛屼繚鎸佸師鍊硷紝鏃ュ織閫愯鍛婅锛堜笉闈欓粯锛� | 鉁� |
+
+### 淇鍓嶅悗閫愰〉绛惧鐓�
+
+| 鏂囦欢 / 椤电 | 淇鍓� | 淇鍚� | 璇存槑 |
+| --- | --- | --- | --- |
+| 瀹㈣繍-鏄庣粏 | 12 | 12 | 鏈鏈姩瀹㈣繍鍖归厤閫昏緫锛堝樊寮傚睘鍙栨暣/鏂囨湰鍙e緞锛� |
+| 瀹㈣繍-姹囨�� | 4 | 4 | 鍚屼笂 |
+| 鐗╂祦-鏈�2 | 0 | 0 | 鈥� |
+| 鐗╂祦-鍒嗛」鐩姇璧勫畬鎴愭儏鍐� | 108 | **91** | 鑽嗗窞 鈭�10銆佸崄鍫� 鈭�5銆佸ぉ闂� 鈭�2 |
+| 鐗╂祦-鍒嗗競宸炶鍒掑唴澶栭」鐩畬鎴愭儏鍐� | 15 | **11** | 鑽嗗窞銆佸ぉ闂ㄩ殢鏄庣粏椤靛綊浣� |
+| 鐗╂祦-甯傚窞姹囨�� | 17 | **11** | 鍚屼笂 |
+| **鍚堣** | **156** | **129** | 鏀舵暃 27 鏍� |
+
+## 鍥涖�佸墿浣欏樊寮傦紙129 鏍硷級鍒嗙被涓庤矗浠�
+
+| 绫诲埆 | 鏍兼暟 | 鍘熷洜 | 璐d换鏂� / 涓嬩竴姝� |
+| --- | --- | --- | --- |
+| 姝︽眽鏁存锛堟槑缁� 24 + 鍚堣 3锛� | 27 | 搴撳唴**鏃犳姹夌墿娴佸綋鏈堟暟鎹�**锛�8 鏈堟姹夋棤鍗曡〃锛夛紝瀵煎嚭鍙兘缁撹浆搴曠 7 鏈堝�� | 涓氬姟琛ユ姹夊崟琛紱鎴栨槑纭�"姝︽眽鐢变汉宸ュ~"锛堢幇宸叉湁鍛婅锛� |
+| 鍗佸牥鏋㈢航 2 涓囧厓宸紓 | 3 | 浜哄伐鐗堢敤鏃у�� 11047/589/0锛屾簮琛ㄤ笌搴撳唴鏄� 11049/591/2 | **杞欢瀵�**锛屼汉宸ョ増闇�鏇存柊锛堝凡鍒楀叆宸紓娓呭崟锛� |
+| L 鍒楋紙寤鸿闃舵锛夋湭瑕嗙洊 | 3 | 瀵煎嚭鎸� 2026-09-18 鍙e緞涓嶅啓 L锛屾部鐢ㄥ簳绋� | 闇�銆婂缓璁鹃樁娈靛綊涓�琛ㄣ�嬪悗鏀惧紑锛堣绗簲鑺傦級 |
+| D 鍒楋紙寤鸿鎬ц川锛夋湭瑕嗙洊 | 3 | 鍚屼笂锛圛/L/G/D/E/F 涓嶅啓锛� | 鍚屼笂 |
+| 宸ユ湡 E/F 鍐欐硶锛堟棩鏈� vs 骞翠唤锛� | 4 | 浜哄伐鐗堟槸鏃ユ湡搴忓垪鍙凤紝杞欢鍐欏勾浠�/鏂囨湰 | 鏍煎紡鍙e緞锛屽缓璁互婧愯〃鍘熸牱涓哄噯 |
+| 鍒嗙粍灏忚琛岋紙6 涓競宸烇級 | 25 | 杞欢鎸夋笭閬撴眰鍜屼笉濉�=甯傚窞鍚堣锛屼汉宸ョ増鐣欑┖ | 鍙e緞宸紓锛屽缓璁汉宸ョ増琛ラ綈锛堣蒋浠惰鍒欎笌姝︽眽 R11/R16 瀹屽叏涓�鑷达級 |
+| 0 涓庣┖鐧� | 11 | 鍐欐硶涓嶅悓 | 缁熶竴瑙勫垯锛氭簮琛ㄧ┖鈫掔┖銆佹簮琛� 0鈫�0 |
+| 瀹㈣繍鍙栨暣 + 鏂囨湰 | 16 | 浜哄伐鐗堟墜鍐欏彇鏁达紙203/2531/43225.9锛夛紱M26/M85 浜哄伐鐗堢┖銆丩91 搴曠鏃у�� | 浜哄伐鐗堝榻愶紱L91 闇�褰掍竴琛� |
+| 鏈鐩栬锛堟暟鎹己鍙f竻鍗曪級 | 18 琛� | 鐗╂祦锛氭姹� 6锛涘杩愶細榛勭煶 1銆侀粍鍐� 9銆佹仼鏂� 1銆佷粰妗� 1 | 琛ユ簮鏂囦欢/椤圭洰涓绘。鍚庨噸瀵硷紙鏃ュ織宸查�愯鍒楀嚭锛� |
+
+## 浜斻�侀仐鐣欓棶棰樹笌澶勭疆
+
+1. **銆愭柊鍙戠幇锛屽凡淇�+閲嶅銆戞綔姹熷鍏ラ�夐敊鍘嗗彶椤电**锛�2026-08 鏇惧鍏� 2018 骞淬�屾綔姹熷競鍏矾椤圭洰銆嶇殑鏁版嵁锛涘凡淇閫夐〉绛鹃�昏緫骞堕噸瀵� 2026-08銆�
+   - **浠嶉仐鐣�**锛氭綔姹� **2026-06 / 2026-07** 涓や釜鏈堢殑鏈堝害鏁版嵁浠嶆槸鍘嗗彶 sheet 閿欏�硷紝闇�鐢� 6/7 鏈堟簮琛ㄩ噸瀵硷紙涓嶈鐢� 8 鏈堟枃浠堕噸瀵硷紝浼氭妸 8 鏈堟暟鍐欐垚 7 鏈堬級銆�
+2. **銆愰渶鍙e緞鎷嶆澘銆�"鍏ㄩ噺瑕嗙洊"鏈疄鏂�**锛氱幇琛屽彛寰勶紙2026-09-18 纭锛夋槸鍙啓 H/J/K/M锛孖/L/G 涓嶅姩銆傝嫢瑕佷笌浜哄伐鐗堝畬鍏ㄤ竴鑷达紝闇�纭 L/D/E/F/I 鏄惁涔熸寜褰撴湀鍐欙紝涓� L 闇�瑕併�婃簮琛ㄧ敤璇嶁啋杈撳嚭鐢ㄨ瘝銆嬪綊涓�琛紙婧愯〃鏈� 涓讳綋鏂藉伐/绔e伐鏀跺熬/鏈紑宸�/鏈勾姝e紡鏂藉伐/鏆傚仠鏂藉伐/鍓嶆湡 绛夛紝浜哄伐鐗堝啓 鍦ㄥ缓/瀹屽伐/鍓嶆湡/鏆傚仠鏂藉伐锛夈��
+3. **銆愭暟鎹己鍙c�戦粍鍐堝杩� 8 鏈堟棤婧愭枃浠�**锛�9 琛岋級銆侀粍鐭�/鎭╂柦/浠欐 3 琛屽簱鍐呮棤瀵瑰簲椤圭洰涓绘。銆佹姹夌墿娴佹棤鍗曡〃 鈥斺�� 瀵煎嚭宸茶兘鑷姩鍛婅锛屼絾鏁版嵁鏈韩闇�瑕佷笟鍔℃彁渚涖��
+4. **銆愬姣斿伐鍏峰寲銆�** 鐩墠"鏈鐩栬"鍙繘鍚庣鏃ュ織锛涘缓璁寜 P1-9 绾﹀畾锛屽湪瀵煎嚭缁撴灉鏃佺敓鎴愩�婃牎楠屾姤閿檁<骞存湀>.xlsx銆嬫垨鍓嶇寮圭獥鎻愮ず锛堢敤鎴疯姹�"澶辫触瑕佹樉绀鸿鍙�"锛屾湰娆″凡鍋氬埌鏃ュ織鐣欑棔锛岄〉闈㈡彁绀哄緟鍋氾級銆�
+
+## 鍏�佺粨璁�
+
+- 鏈淇鍚庯紝**閫愭牸宸紓鐢� 156 鏍奸檷鑷� 129 鏍�**锛涗笁澶�"浼氬奖鍝嶆暟瀛�"鐨勫彇鏁扮己闄凤紙鑽嗗窞椤圭洰鍚嶅尮閰嶅け璐ャ�佸崄鍫板悓鍚嶅弻妗e彇鏃у�笺�佸ぉ闂ㄥ鍏ヤ涪 H/J/K锛夊叏閮ㄩ棴鐜苟閫愭潯鍥炴函婧愭枃浠堕獙璇併��
+- 鍚屾椂绔埌绔毚闇插苟淇浜嗕竴涓洿涓ラ噸鐨勯棶棰橈細**娼滄睙瀵煎叆閫夊埌 2018 骞村巻鍙查〉绛�**锛堝睘"鎶婃棫骞翠唤鏁版嵁褰撳綋鏈熸暟鎹叆搴�"锛夛紱鏈鐩栬鐜板凡鍦ㄦ棩蹇椾腑閫愯鍒楀嚭锛堣鍙�+甯傚窞+椤圭洰鍚�+鍘熷洜锛夛紝涓嶅啀闈欓粯銆�
+- 鍓╀綑 129 鏍煎樊寮備腑锛�**鍙湁姝︽眽 27 鏍煎睘"缂烘暟鎹�"銆丩/D 鍒� 6 鏍煎睘"寰呮斁寮�鍙e緞"**锛屽叾浣欎负濉〃涔犳儻锛堝垎缁勮/0 涓庣┖鐧�/鍙栨暣锛変笌浜哄伐鐗堣嚜韬棫鍊硷紝鍧囧凡鍦ㄣ�婃暟鎹瘮瀵规姤鍛娿�嬩腑閫愭潯鏍囨敞"浠ヨ皝涓哄噯"銆�
+- 寤鸿涓嬩竴姝ワ細鈶� 涓氬姟纭 L/D/E/F 瑕嗙洊鍙e緞骞跺嚭銆婂缓璁鹃樁娈靛綊涓�琛ㄣ�嬶紱鈶� 琛ユ姹夌墿娴併�侀粍鍐堝杩愭簮鏁版嵁锛涒憿 鎸� P1-9 鎶婃湭瑕嗙洊娓呭崟杈撳嚭鎴愭牎楠屾枃浠�/椤甸潰鎻愮ず銆�
+
+## 涓冦�佹湰娆℃暟鎹彉鏇磋鏄庯紙鏈垹闄や换浣曢」鐩富妗o級
+
+| 琛� | 鍙樻洿 | 淇鍓� | 淇鍚� |
+| --- | --- | --- | --- |
+| `investment_monthly`锛堝ぉ闂ㄥ競鐗╂祦涓績寤鸿椤圭洰 2026-08锛� | 閲嶅淇 | start_cum/year_cum/month_done = 0/0/0 | **16677.7 / 16677.7 / 500** |
+| `investment_monthly`锛堟綔姹熷競 2026-08锛� | 閲嶅淇锛堟棫閿欒鍒犻櫎銆佹柊琛屽啓鍏ワ級 | 娼滄睙甯傚叕璺」鐩� 5173/5173/1440 | **涓浗铏捐胺鍐烽摼浠撳偍鐗╂祦鍥� 11947.9/1135/0** |
+
+- 鏈垹闄や换浣� `investment_project` 椤圭洰涓绘。锛涙湭鏀瑰姩鍏朵粬甯傚窞銆佸叾浠栨湡闂存暟鎹��
+- 澶嶇幇鍛戒护锛歚POST /api/import/batch?type=investmentLogistics&period=2026-08`锛坢ultipart锛屽瓧娈靛悕 `files`锛�+ `GET /api/report/export/investLogisticsDetail?period=2026-08`锛涘潎闇� `Authorization: Bearer <JWT>`銆�
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 62a0e41..eda8821 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"
@@ -160,3 +160,21 @@
 - **褰卞搷閲戦**锛氳蒋浠剁増鐗╂祦銆岃嚜寮�濮嬬疮璁°�嶃�岃嚜骞村垵绱銆嶅悇灏� **34399.2 涓囧厓**銆併�屾湰鏈堝畬鎴愩�嶅皯 **6291.4 涓囧厓**銆�
 - **鎶ュ憡**锛歚docs/鍔熻兘娴嬭瘯鎶ュ憡/鏁版嵁姣斿鎶ュ憡_鎶曡祫鏄庣粏琛ㄨ蒋浠剁敓鎴愪笌浜哄伐鐗坃2026-09-22.md`锛堝惈 156 鏍煎叏閲忔竻鍗� + 閫愭潯鏍稿缁撹 + 澶勭疆寤鸿锛夈��
 - **涓存椂鑴氭湰锛堜繚鐣欙級**锛歚_tmp_diff_invest_0922.py`銆乣_tmp_dump_invest_full_0922.py`銆乣_tmp_diff_invest_annot_0922.py`銆乣_tmp_diff_tables_0922.py`銆乣_tmp_src_spotcheck_0922.py`銆乣_tmp_src_spotcheck2_0922.py`銆乣_tmp_db_probe*_0922.py`銆乣_tmp_tpl_*_0922.py` 鍙婂搴� `_*.txt` 杈撳嚭銆�
+
+
+## 涓冦�佹姇璧勬槑缁嗚〃鍙栨暟淇锛堢涓�杞紝宸茬紪璇�/閲嶅惎/绔埌绔獙璇侊級
+
+鎸夌鍏妭姣斿缁撹鍔ㄦ墜淇簡涓夊"浼氶潤榛樺嚭鏁�"鐨勫彇鏁扮己闄凤紝骞堕『甯︾鍒扮鏆撮湶+淇浜嗘綔姹熷鍏ラ�夐敊鍘嗗彶椤电銆�
+
+- **瀵煎嚭**锛坄ReportExportService.java`锛夛細
+  1. `normInvestName()` 褰掍竴鍖栬ˉ鏍囩偣锛堝崐/鍏ㄨ鍙ョ偣銆侀】鍙枫�佸垎鍙风瓑锛夆啋 鑽嗗窞銆屼腑鍥戒緵閿�.鍏畨鍟嗚锤鐗╂祦鍥�嶅彲鍖归厤锛屽啓鍏ュ簱鍐� 15986/15986/8227.5锛�
+  2. 鏂板 `preferMonthlyCandidate()`锛氬悓鍚嶅妗d紭鍏堝彇銆屽綋鏈堟湁鏁版嵁銆嶇殑妗� 鈫� 鍗佸牥銆屽揩閫掔墿娴佷骇涓氬洯浜屾湡銆嶆敼鍙� id=181锛屽啓鍏� 20377/3196/296銆佺宸� 2029锛�
+  3. 鏂板 `logSkippedRows()`锛氭湭瑕嗙洊琛岄�愯 WARN锛坄[鏈鐩朷 绗琋琛� 甯傚窞 椤圭洰鍚� 鈫� 鍘熷洜` + 鎸夊競宸炵粺璁★級锛屼笉鍐嶉潤榛樼粨杞笂鏈熷�笺��
+- **瀵煎叆**锛坄DataImportService.java`锛夛細
+  1. `investHeaderKey()` 鍏堝幓鍏ㄩ儴绌虹櫧锛堝惈鎹㈣/鍏ㄨ绌烘牸锛夊啀鍒ゅ畾鍏抽敭璇� 鈫� 澶╅棬 H/J/K 涓夊垪鎭㈠璇嗗埆锛�2026-08 鍏ュ簱 16677.7/16677.7/500锛堝師涓� 0/0/0锛夛紱
+  2. 鏂板 `investSheetPeriodCellHit()` + 璇勫垎鍔犳潈 2000000锛氭寜琛ㄥ唴鎶ヨ〃鏈燂紙`2026.08.24`锛夐�� sheet锛屼紭鍏堜簬銆宻heet 鍚嶅惈鍚屾湀銆嶁啋 娼滄睙涓嶅啀鎶� **2018 骞�**銆屾綔姹燂紙8鏈堬級銆嶅綋 2026-08锛岄噸瀵煎悗 2026-08 鍏ュ簱銆屼腑鍥借櫨璋峰喎閾句粨鍌ㄧ墿娴佸洯銆�11947.9/1135/0銆�
+- **楠岃瘉**锛歚mvn -o compile` 閫氳繃锛涘仠鏃ц捣鏂板悗绔紙8090 灏辩华锛夛紱鎺ュ彛閲嶅 + 閲嶈窇 2026-08 瀵煎嚭锛涢�愭牸姣斿**156 鏍� 鈫� 129 鏍�**锛堥檷 27 鏍硷細鐗╂祦鍒嗛」鐩� 108鈫�91銆佸垎甯傚窞 15鈫�11銆佸競宸炴眹鎬� 17鈫�11锛夛紝鏃犳柊澧炲樊寮傘��
+- **鏈鐩栨竻鍗曪紙鏂板鑳藉姏锛屾潵鑷棩蹇楋級**锛氱墿娴� 6 琛岋紙鍏ㄩ儴姝︽眽锛屽簱鍐呮棤褰撴湀鏁版嵁锛夛紱瀹㈣繍 12 琛岋紙榛勭煶 1銆岄槼鏂扮患鍚堝杩愭灑绾界珯銆嶃�侀粍鍐� 9銆佹仼鏂� 1銆屽捀涓板幙鍧潩钀ユ梾娓稿杩愮珯銆嶃�佷粰妗� 1銆屼粰妗冨競姣涘槾瀹㈣繍绔欍�嶏級銆�
+- **鎶ュ憡**锛歚docs/鍔熻兘娴嬭瘯鎶ュ憡/鍔熻兘娴嬭瘯鎶ュ憡_鎶曡祫鏄庣粏琛ㄥ彇鏁颁慨澶峗2026-09-22.md`銆�
+- **閬楃暀锛堥渶鎷嶆澘/琛ユ暟锛�**锛氣憼 L/D/E/F 鏄惁鎸夊綋鏈堣鐩栵紙闇�銆婂缓璁鹃樁娈靛綊涓�琛ㄣ�嬶級锛涒憽 姝︽眽鐗╂祦銆侀粍鍐堝杩� 8 鏈堟簮鏁版嵁缂哄け锛涒憿 娼滄睙 2026-06/07 鏈堝害浠嶆槸鍘嗗彶 sheet 閿欏�硷紝闇�鐢� 6/7 鏈堟簮琛ㄩ噸瀵硷紙**涓嶈**鐢� 8 鏈堟枃浠堕噸瀵硷級锛涒懀 鏈鐩栨竻鍗曠洰鍓嶅彧杩涙棩蹇楋紝寤鸿鎸� P1-9 鍑恒�婃牎楠屾姤閿檁<骞存湀>.xlsx銆嬫垨椤甸潰鎻愮ず銆�
+- **鏁版嵁鍙樻洿**锛氫粎閲嶅淇浜嗗ぉ闂ㄣ�佹綔姹熶袱澶� 2026-08 鏈堝害鍊硷紝鏈垹闄や换浣曢」鐩富妗c�佹湭鍔ㄥ叾浠栧競宸�/鏈熼棿锛涗复鏃惰剼鏈笌浜х墿淇濈暀锛坄_tmp_*_0922.*`銆乣_tmp/gen_new_0922/`锛夈��
diff --git a/traffic-audit-server/src/main/java/com/trafficaudit/dataimport/service/DataImportService.java b/traffic-audit-server/src/main/java/com/trafficaudit/dataimport/service/DataImportService.java
index 446043d..da66293 100644
--- a/traffic-audit-server/src/main/java/com/trafficaudit/dataimport/service/DataImportService.java
+++ b/traffic-audit-server/src/main/java/com/trafficaudit/dataimport/service/DataImportService.java
@@ -2442,6 +2442,41 @@
             || normDash.contains(period) || normDash.contains(period.replace("-0", "-"));
     }
 
+    /**
+     * 鎶ヨ〃鏈熷崟鍏冩牸鍛戒腑锛氭壂鎻� sheet 鍓� 8 琛岋紝鎵惧舰濡� 2026.08 / 2026骞�8鏈� / 2026-08-24 鐨勬姤琛ㄦ湡鏂囧瓧鎴栨棩鏈熷崟鍏冩牸銆�
+     * 鑳屾櫙锛�2026-09-22锛夛細娼滄睙鍗曡〃鍚� 20 涓巻鍙� sheet锛堟綔姹燂紙1鏈堬級鈥︽綔姹燂紙8鏈堬級鈥︼級锛屾棫閫昏緫鍙寜銆�8鏈堛�嶅尮閰� sheet 鍚嶏紝
+     * 浼氭妸 2018 骞寸殑銆屾綔姹燂紙8鏈堬級銆嶅綋鎴� 2026-08锛屽鍏ユ垚 2018 骞存暟鎹紱褰撴湡 sheet 鍚嶆槸銆屾綔姹燂紙2022.3锛夈�嶏紝
+     * 鍙兘闈犺〃鍐呮姤琛ㄦ湡锛�2026.08.24锛夎瘑鍒��
+     */
+    private boolean investSheetPeriodCellHit(Sheet sh, String period) {
+        if (sh == null || period == null || !period.matches("\\d{4}-\\d{2}")) return false;
+        String year = period.substring(0, 4);
+        int month = Integer.parseInt(period.substring(5, 7));
+        int last = Math.min(sh.getLastRowNum(), 7);
+        for (int r = 0; r <= last; r++) {
+            Row row = sh.getRow(r);
+            if (row == null) continue;
+            int lastCell = Math.max(1, row.getLastCellNum());
+            for (int c = 0; c < Math.min(lastCell, 12); c++) {
+                Cell cell = row.getCell(c);
+                if (cell == null) continue;
+                if (cell.getCellType() == CellType.NUMERIC && DateUtil.isCellDateFormatted(cell)) {
+                    java.time.LocalDate d = cell.getLocalDateTimeCellValue().toLocalDate();
+                    if (d.getYear() == Integer.parseInt(year) && d.getMonthValue() == month) return true;
+                    continue;
+                }
+                String v = cellStr(row, c);
+                if (v == null) continue;
+                String t = v.trim().replace(" ", "");
+                if (t.isEmpty() || t.length() > 30) continue;
+                java.util.regex.Matcher mm = java.util.regex.Pattern
+                        .compile("(\\d{4})\\s*[骞�.\\-/]\\s*(\\d{1,2})").matcher(t);
+                if (mm.find() && year.equals(mm.group(1)) && month == Integer.parseInt(mm.group(2))) return true;
+            }
+        }
+        return false;
+    }
+
     /** 瑙f瀽鍗曚釜甯傚窞鎶ヨ〃锛氶�� sheet锛堟姤琛ㄦ湡鍚嶄紭鍏� + 鏁版嵁琛屾暟锛夛紝鎸夊垪鍚嶆槧灏勬彁鍙栭」鐩 */
     private void parseInvestCityWorkbook(Workbook wb, String fileName, String category, String period,
                                          Set<String> fiveYearNames, List<InvestCityRow> rows, Map<String, Object> fr) {
@@ -2453,7 +2488,10 @@
             Map<String, Integer> col = findInvestHeader(sh);
             if (col == null) continue;
             int cnt = countInvestRows(sh, col);
-            int score = cnt + (cnt > 0 && investSheetMatchesPeriod(sh, period) ? 1000000 : 0);
+            // 2026-09-22锛氳〃鍐呮姤琛ㄦ湡锛堝崟鍏冩牸锛夊懡涓潈閲嶆渶楂樷�斺�斿巻鍙插悓鏈� sheet锛堝娼滄睙锛�8鏈堬級锛変笉鑳界洊杩囧綋鏈� sheet
+            boolean cellHit = cnt > 0 && investSheetPeriodCellHit(sh, period);
+            int score = cnt + (cnt > 0 && investSheetMatchesPeriod(sh, period) ? 1000000 : 0)
+                    + (cellHit ? 2000000 : 0);
             if (cnt > 0 && investSheetMatchesPeriod(sh, period)) {
                 // 褰撴湡鐪熷疄鎶ヨ〃 sheet 鍚嶉�氬父甯﹀勾浠斤紙濡� 2026.8/2026骞�8鏈堬級锛屽巻鍙瞫heet澶氫负绾湀浠藉悕锛�8鏈堬級锛氬甫骞翠唤鐨勪紭鍏�
                 String norm = sh.getSheetName() == null ? "" : sh.getSheetName().replace(" ", "");
@@ -2618,25 +2656,28 @@
     /** 鍗曚釜琛ㄥご鍗曞厓鏍� -> 瀛楁閿紙null 琛ㄧず涓嶆槸琛ㄥご瀛楁锛夛紱渚涜〃澶磋鍒ゅ畾涓庡垪鏄犲皠鍏辩敤 */
     private String investHeaderKey(String v) {
         if (v == null) return null;
-        String flat = v.replace(" ", "");
-        if (v.contains("椤圭洰鍚嶇О")) return "name";
+        // 2026-09-22锛氳〃澶村崟鍏冩牸甯稿甫鎹㈣/鍏ㄨ绌烘牸锛堝澶╅棬銆岃嚜寮�濮嬪缓\n璁剧疮璁″畬\n鎴愭姇璧刓n(涓囧厓)銆嶏級锛�
+        // 缁熶竴鍘绘帀鍏ㄩ儴绌虹櫧鍚庡啀鍒ゅ畾鍏抽敭璇嶏紱鍚﹀垯 H(鑷紑濮嬪缓璁剧疮璁�)/J(鑷勾鍒濈疮璁�)/K(鏈湀瀹屾垚) 浼氬尮閰嶅け璐ワ紝
+        // 鍒楁槧灏勮惤鍒� -1 鈫� 涓変釜鏁板�艰鍐欐垚 0锛堝ぉ闂� 2026-08 灏辨槸杩欐牱涓㈢殑 16677.7/16677.7/500锛夈��
+        String flat = v.replaceAll("[\\s\\u3000]+", "");
+        if (flat.contains("椤圭洰鍚嶇О")) return "name";
         // 銆屽幙锛堝競銆佸尯锛夈�嶇殑鍚勭鍐欐硶锛氬崐/鍏ㄨ鎷彿銆侀】鍙�/閫楀彿銆佹湁鏃犳嫭鍙凤紝缁熶竴褰掍竴鍖栧悗鍐嶅垽瀹�
         String flatCounty = flat.replace("锛�", "(").replace("锛�", ")").replace("銆�", "").replace("锛�", "").replace(",", "");
         if (flatCounty.contains("鍘�(甯傚尯)") || flatCounty.contains("鍘垮競鍖�") || flatCounty.contains("鍖哄幙")) return "county";
-        if (v.contains("鎶曡祫寤鸿") || v.contains("寤鸿鍗曚綅") || v.contains("椤圭洰涓氫富")) return "builder";
-        if (v.contains("寤鸿鎬ц川")) return "nature";
-        if (v.contains("寮�宸�")) return "start";
-        if (v.contains("绔e伐") || v.contains("寤烘垚")) return "end";
-        if ((v.contains("璁″垝鎬绘姇璧�") || v.contains("鎬绘姇璧�")) && !v.contains("绱")) return "total";
-        if (v.contains("鑷紑濮嬪缓璁�")) return "startcum";
-        if (v.contains("鏈勾璁″垝")) return "yearplan";
-        if (v.contains("鑷勾鍒濈疮璁�")) return "yearcum";
-        if (v.contains("鏈湀瀹屾垚")) return "monthdone";
-        if (v.contains("寤鸿闃舵")) return "stage";
-        if (v.contains("褰㈣薄杩涘害") || v.contains("寤鸿杩涘睍")) return "desc";
-        if (v.contains("宸ュ彲") && !v.contains("椤圭洰鍚嶇О")) return "gk";
-        if (v.contains("鍒濊") && !v.contains("椤圭洰鍚嶇О")) return "cs";
-        if (v.contains("寤虹瓚闈㈢Н") && !v.contains("鏂板")) return "area";
+        if (flat.contains("鎶曡祫寤鸿") || flat.contains("寤鸿鍗曚綅") || flat.contains("椤圭洰涓氫富")) return "builder";
+        if (flat.contains("寤鸿鎬ц川")) return "nature";
+        if (flat.contains("寮�宸�")) return "start";
+        if (flat.contains("绔e伐") || flat.contains("寤烘垚")) return "end";
+        if ((flat.contains("璁″垝鎬绘姇璧�") || flat.contains("鎬绘姇璧�")) && !flat.contains("绱")) return "total";
+        if (flat.contains("鑷紑濮嬪缓璁�")) return "startcum";
+        if (flat.contains("鏈勾璁″垝")) return "yearplan";
+        if (flat.contains("鑷勾鍒濈疮璁�")) return "yearcum";
+        if (flat.contains("鏈湀瀹屾垚")) return "monthdone";
+        if (flat.contains("寤鸿闃舵")) return "stage";
+        if (flat.contains("褰㈣薄杩涘害") || flat.contains("寤鸿杩涘睍")) return "desc";
+        if (flat.contains("宸ュ彲") && !flat.contains("椤圭洰鍚嶇О")) return "gk";
+        if (flat.contains("鍒濊") && !flat.contains("椤圭洰鍚嶇О")) return "cs";
+        if (flat.contains("寤虹瓚闈㈢Н") && !flat.contains("鏂板")) return "area";
         return null;
     }
 
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 bbe8df3..42e5bf2 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
@@ -5781,6 +5781,8 @@
             String curCity = null;
             Set<Long> used = new HashSet<>();
             int filled = 0, kept = 0, dup = 0;
+            List<String> skipped = new ArrayList<>();
+            Map<String, Integer> skippedByCity = new LinkedHashMap<>();
             for (int r = 8; r <= sheet.getLastRowNum(); r++) {
                 Row row = sheet.getRow(r);
                 if (row == null) continue;
@@ -5792,11 +5794,16 @@
                 if (!a.matches("\\d+(\\.\\d+)?")) continue;
                 if (b.isEmpty() || curCity == null) continue;
                 InvestmentProject p = matchInvest(projects, b, curCity, "瀹㈣繍绔欏満", used);
+                p = preferMonthlyCandidate(projects, p, mByProject, "瀹㈣繍绔欏満", used);
                 InvestmentMonthly m = p == null ? null : mByProject.get(p.getId());
                 if (p == null || m == null) {
                     kept++;
                     // 鏈夊簱鍐呴」鐩絾褰撴湀鏃犳暟鎹� 鈫� 璁颁负寰呮牳瀵癸紱鏃犲尮閰嶉」鐩� 鈫� 缁撹浆涓婃湀
                     if (p != null) dup++;
+                    // 2026-09-22锛氫笉鍐嶉潤榛樼粨杞笂鏈堬紝鏈鐩栫殑琛屽繀椤荤暀鐥曪紙琛屽彿+甯傚窞+椤圭洰鍚�+鍘熷洜锛�
+                    skipped.add("绗�" + (r + 1) + "琛� " + curCity + " " + b
+                            + (p == null ? " 鈫� 搴撳唴鏃犲尮閰嶉」鐩�" : " 鈫� 搴撳唴鏃� " + period + " 鏈堝害鏁版嵁"));
+                    skippedByCity.merge(curCity, 1, Integer::sum);
                     continue;
                 }
                 used.add(p.getId());
@@ -5826,6 +5833,7 @@
             }
             log.info("瀹㈣繍绔欐姇璧勬槑缁嗚〃 {}锛氬啓鍏� {} 琛岋紝缁撹浆姣嶇増鍘熷�� {} 琛岋紙鍏朵腑搴撳唴鏈夐」鐩絾褰撴湀鏃犳暟鎹� {} 琛岋級",
                     period, filled, kept, dup);
+            logSkippedRows("瀹㈣繍绔欐姇璧勬槑缁嗚〃", period, skipped, skippedByCity);
             return toBytes(wb);
         }
     }
@@ -5866,6 +5874,8 @@
         Map<String, double[]> cityStats = new LinkedHashMap<>();  // 鍏ㄥ悕 -> {鎬绘暟, 绱, 瑙勫垝鍐呮暟, 瑙勫垝鍐呯疮璁�, 瑙勫垝澶栨暟, 瑙勫垝澶栫疮璁
         Set<Long> used = new HashSet<>();
         int filled = 0, kept = 0;
+        List<String> skipped = new ArrayList<>();
+        Map<String, Integer> skippedByCity = new LinkedHashMap<>();
         for (int i = 0; i < cityRows.size(); i++) {
             int cr = cityRows.get(i);
             String cityLabel = nvl(cellText(sheet.getRow(cr).getCell(0)));
@@ -5888,8 +5898,16 @@
                 if (!a.matches("\\d+(\\.\\d+)?")) continue;
                 if (b.isEmpty()) continue;
                 InvestmentProject p = matchInvest(projects, b, city, "鐗╂祦鍥尯", used);
+                p = preferMonthlyCandidate(projects, p, mByProject, "鐗╂祦鍥尯", used);
                 InvestmentMonthly m = p == null ? null : mByProject.get(p.getId());
-                if (p == null || m == null) { kept++; continue; }
+                if (p == null || m == null) {
+                    kept++;
+                    // 2026-09-22锛氫笉鍐嶉潤榛樼粨杞笂鏈堬紝鏈鐩栫殑琛屽繀椤荤暀鐥�
+                    skipped.add("绗�" + (r + 1) + "琛� " + city + " " + b
+                            + (p == null ? " 鈫� 搴撳唴鏃犲尮閰嶉」鐩�" : " 鈫� 搴撳唴鏃� " + period + " 鏈堝害鏁版嵁"));
+                    skippedByCity.merge(city, 1, Integer::sum);
+                    continue;
+                }
                 used.add(p.getId());
                 // 鍙e緞鍚屽杩愮珯鏄庣粏琛細鍙鐩� H 鑷紑濮嬪缓璁剧疮璁� / J 鑷勾鍒濈疮璁� / K 鏈湀瀹屾垚 / M 褰㈣薄杩涘害
                 if (m.getStartCum() != null) putNum(row, 7, m.getStartCum());
@@ -6020,6 +6038,7 @@
             log.warn("鐗╂祦绔欏満鎶曡祫鏄庣粏鍏紡姹傚�煎け璐�: {}", e.getMessage());
         }
         log.info("鐗╂祦绔欏満鎶曡祫鏄庣粏 {}锛氬啓鍏� {} 琛岋紝缁撹浆姣嶇増鍘熷�� {} 琛�", period, filled, kept);
+        logSkippedRows("鐗╂祦绔欏満鎶曡祫鏄庣粏", period, skipped, skippedByCity);
         return toBytesHssf(wb);
     }
 
@@ -6314,6 +6333,40 @@
         return full != null && RegionUtil.cityList().contains(full);
     }
 
+    /**
+     * 鍚屽悕锛堝綊涓�鍖栧悗涓�鑷达級澶氭。鏃讹紝浼樺厛閫夈�屽綋鏈堟湁鏁版嵁銆嶇殑閭d竴妗c��
+     * 鑳屾櫙锛�2026-09-22锛夛細鍗佸牥銆屽揩閫掔墿娴佷骇涓氬洯浜屾湡銆嶅湪搴撳唴鏈変袱妗� id=154锛堢宸� 2026锛屾湀搴﹀彧鍒� 7 鏈堬級涓�
+     * id=181锛堢宸� 2029锛屾湁 8 鏈堬級锛屾ā鏉胯鍚嶅墠缂�涓� 154 涓�鑷� 鈫� 瀵煎嚭鍙栧埌 154 鐨� 7 鏈堝�笺��
+     */
+    private InvestmentProject preferMonthlyCandidate(List<InvestmentProject> pool, InvestmentProject p,
+                                                    Map<Long, InvestmentMonthly> mByProject,
+                                                    String category, Set<Long> excludeIds) {
+        if (p == null || mByProject.containsKey(p.getId())) return p;
+        String norm = normInvestName(p.getProjectName());
+        if (norm.isEmpty()) return p;
+        InvestmentProject better = null;
+        for (InvestmentProject c : pool) {
+            if (c == null || c.getId().equals(p.getId())) continue;
+            if (excludeIds != null && excludeIds.contains(c.getId())) continue;
+            if (category != null && !category.equals(c.getCategory())) continue;
+            if (!mByProject.containsKey(c.getId())) continue;
+            if (!norm.equals(normInvestName(c.getProjectName()))) continue;
+            if (better == null || c.getId() > better.getId()) better = c;
+        }
+        return better != null ? better : p;
+    }
+
+    /** 鏈寜褰撴湀鏁版嵁瑕嗙洊鐨勮蹇呴』鐣欑棔锛氶�愯鍒楀嚭琛屽彿+甯傚窞+椤圭洰鍚嶏紝閬垮厤銆岄潤榛樼粨杞笂鏈熷�笺�嶅啀娆″彂鐢� */
+    private void logSkippedRows(String reportName, String period, List<String> skipped, Map<String, Integer> byCity) {
+        if (skipped == null || skipped.isEmpty()) return;
+        log.warn("{} {}锛歿} 琛屾湭鎸夊綋鏈堟暟鎹鐩栵紙缁撹浆姣嶇増鍘熷�硷級锛岄渶浜哄伐鏍稿婧愭枃浠�/搴撳唴鏁版嵁锛�",
+                reportName, period, skipped.size());
+        int limit = Math.min(skipped.size(), 50);
+        for (int i = 0; i < limit; i++) log.warn("  [鏈鐩朷 {}", skipped.get(i));
+        if (skipped.size() > limit) log.warn("  鈥﹀彟鏈� {} 琛屾湭閫愯鍒楀嚭", skipped.size() - limit);
+        if (byCity != null && !byCity.isEmpty()) log.warn("  鏈鐩栬鎸夊競宸炵粺璁★細{}", byCity);
+    }
+
     /** 鍦ㄥ�欓�夐」鐩睜涓寜鍚嶇О鍖归厤 DB 椤圭洰锛堝彲閫� 甯傚窞/绫诲埆 杩囨护 + 鍘垮尯鍓嶇紑娑堟锛夛紝鏈懡涓繑鍥� null */
     private InvestmentProject matchInvest(List<InvestmentProject> pool, String name, String cityFull, String category) {
         return matchInvest(pool, name, cityFull, category, null);
@@ -6362,7 +6415,8 @@
         if (name == null) return "";
         String s = name.trim();
         s = s.replaceAll("[锛�(]", "").replaceAll("[锛�)]", "");
-        s = s.replaceAll("[路鈥⑩�旓紞_\\-]", "");
+        // 2026-09-22锛氳ˉ鍏呭崐/鍏ㄨ鍙ョ偣銆侀】鍙枫�佸垎鍙风瓑锛堝簱鍐呫�屼腑鍥戒緵閿�.鍏畨鍟嗚锤鐗╂祦鍥�嶅洜鍗婅鍙ョ偣鍖归厤涓嶄笂妯℃澘琛岋級
+        s = s.replaceAll("[路鈥⑩�旓紞_\\-锛�.銆傘�侊紝,;锛�:锛歖", "");
         s = s.replaceAll("[鈪犫叀鈪⑩叄鈪も叆鈪︹収鈪ㄢ叐鈪扳叡鈪测叧鈪粹叺鈪垛叿鈪糕吂]", "I");
         s = s.replaceAll("^(婀栧寳鐪亅姝︽眽甯倈榛勭煶甯倈鍗佸牥甯倈瀹滄槍甯倈瑗勯槼甯倈閯傚窞甯倈鑽嗛棬甯倈瀛濇劅甯倈鑽嗗窞甯倈榛勫唸甯倈鍜稿畞甯倈闅忓窞甯倈鎭╂柦宸瀨浠欐甯倈娼滄睙甯倈澶╅棬甯倈绁炲啘鏋舵灄鍖�)", "");
         s = s.replaceAll("^(?:[\\u4e00-\\u9fa5]{2,4}(?:鍘縷甯倈鍖�))", "");

--
Gitblit v1.9.1