From afed4dfc3b1b79ba1beec26e68a1ba6ac1192c15 Mon Sep 17 00:00:00 2001
From: zhizhijie <zhizhijie@users.noreply.gitee.com>
Date: 星期四, 17 九月 2026 14:39:59 +0800
Subject: [PATCH] fix(投资): 修复两级表头导致的取列错位 + 新增《弹窗提示》机制(14 条规则)
---
docs/投资/工具/市州月报解析.py | 75 ++++++++++++++++++++++++++++++++-----
1 files changed, 64 insertions(+), 11 deletions(-)
diff --git "a/docs/\346\212\225\350\265\204/\345\267\245\345\205\267/\345\270\202\345\267\236\346\234\210\346\212\245\350\247\243\346\236\220.py" "b/docs/\346\212\225\350\265\204/\345\267\245\345\205\267/\345\270\202\345\267\236\346\234\210\346\212\245\350\247\243\346\236\220.py"
index fcc2043..ce0f819 100644
--- "a/docs/\346\212\225\350\265\204/\345\267\245\345\205\267/\345\270\202\345\267\236\346\234\210\346\212\245\350\247\243\346\236\220.py"
+++ "b/docs/\346\212\225\350\265\204/\345\267\245\345\205\267/\345\270\202\345\267\236\346\234\210\346\212\245\350\247\243\346\236\220.py"
@@ -76,21 +76,45 @@
return str(v)
-def pick_columns(cell, nrows, ncols):
- """鎸夎〃澶村叧閿瓧瀹氫綅鍒楋紱鍚屼竴瀛楁鍛戒腑澶氭鏃讹紝鍙栤�滆鍙锋渶灏忋�佸叾娆℃槸鍛戒腑璇嶆渶鐭�濈殑閭d釜銆�"""
+def pick_columns(cell, nrows, ncols, merges=None):
+ """鎸夎〃澶村叧閿瓧瀹氫綅鍒楋紱鍚屼竴瀛楁鍛戒腑澶氭鏃讹紝鍙栤�滆鍙锋渶灏忋�佸叾娆℃槸鍛戒腑璇嶆渶鐭�濈殑閭d釜銆�
+
+ 涓ょ骇琛ㄥご锛堢粍琛ㄥご锛夊鐞嗭細鑻ユ煇瀛楁鐨勫懡涓惤鍦�**璺ㄥ鍒楃殑鍚堝苟鍗曞厓鏍�**閲岋紝璇存槑瀹冩槸缁勮〃澶达紝
+ 涓嶈兘鐩存帴褰撴垚璇ュ瓧娈电殑鍒楋紱姝ゆ椂鍦ㄦ湰鍚堝苟鍖哄唴鎺掗櫎鈥滃叾瀹冨瓧娈垫洿娣辩殑瀛愯〃澶粹�濇墍鍗犵殑鍒楋紝
+ 鑻ュ彧鍓╁敮涓�涓�鍒楋紝鍒欒鍒楀氨鏄湰瀛楁鐨勫垪銆�
+ 渚嬶細閯傚窞銆婁紒涓氭湀鎶ユ眹鎬汇�婻5 缁勮〃澶淬�岃嚜骞村垵绱瀹屾垚鎶曡祫锛堜竾鍏冿級銆嶅悎骞� I:J:K锛�
+ 瀛愯〃澶� I=鏈勾璁″垝鎶曡祫锛堜竾鍏冿級銆丣=鍚堣銆並=鍏朵腑锛氭湰鏈堝畬鎴愭姇璧� 鈫�
+ 銆岃嚜骞村垵绱銆嶅簲钀藉湪 J锛堜笌鎶曡祫绯荤粺 G 鍒� 5507.5 涓�鑷达級锛岃�屼笉鏄� I锛�8000锛岄偅鍏跺疄鏄湰骞磋鍒掓姇璧勶級銆�
+ """
hits = F.scan_fields(cell, nrows, ncols)
- cols = {}
+ best = {}
for f in FIELDS:
- if f not in hits:
- continue
- best = sorted(hits[f], key=lambda h: (h[0], len(h[2])))[0]
- cols[f] = F.colindex(best[1])
+ if f in hits:
+ best[f] = sorted(hits[f], key=lambda h: (h[0], len(h[2])))[0]
+ cols = {}
+ for f, h in best.items():
+ row1, letter, _txt = h
+ c0 = F.colindex(letter)
+ span = F.merge_span(merges, row1, c0)
+ if span and (span[1] - span[0]) > 1:
+ taken = set()
+ for f2, h2 in best.items():
+ if f2 == f or h2[0] <= row1:
+ continue
+ c2 = F.colindex(h2[1])
+ if span[0] <= c2 < span[1]:
+ taken.add(c2)
+ free = [c for c in range(span[0], span[1]) if c not in taken]
+ if len(free) == 1:
+ cols[f] = free[0]
+ continue
+ cols[f] = c0
return cols, hits
-def parse_sheet(cell, nrows, ncols, city=None):
+def parse_sheet(cell, nrows, ncols, city=None, merges=None):
"""瑙f瀽涓�寮犲伐浣滆〃 鈫� (椤圭洰琛屽垪琛�, 娈典俊鎭�, 鏍¢獙淇℃伅)"""
- cols, hits = pick_columns(cell, nrows, ncols)
+ cols, hits = pick_columns(cell, nrows, ncols, merges)
namec = cols.get('椤圭洰鍚嶇О')
if namec is None:
return [], {}, {}
@@ -181,7 +205,7 @@
bodies = [a.body] if a.body else ['瀹㈣繍锛堝杩愮珯锛�', '鐗╂祦锛堢墿娴佸洯鍖猴級']
md = '%d鏈�' % int(a.month.split('-')[1])
- records, report = [], []
+ records, report, checks = [], [], []
report.append('# 甯傚窞鏈堟姤瑙f瀽鎶ュ憡锛�%s锛�' % a.month)
report.append('')
report.append('锛堝彧璇昏В鏋愶紱涓�琛屼竴涓」鐩锛屾槑缁嗚鍚屽悕 `.tsv`锛�')
@@ -207,23 +231,37 @@
sel = F.pick_sheet(sheets, ym=ym)
if not sel:
report.append('| %s | 锛堟湭閫変腑宸ヤ綔琛級 | | | | | |' % f[:44])
+ checks.append({'鍝佺被': body_key, '甯傚窞': city_file or '', '鏂囦欢': f, '宸ヤ綔琛�': '',
+ '鐘舵��': '鏈�変腑宸ヤ綔琛�', '椤圭洰琛屾暟': 0, '涓�鑷存��': '鈥�'})
continue
nm, nr, nc, cell, _hits = sel
- rows, seg, extra = parse_sheet(cell, nr, nc, city=city_file)
+ merges = F.sheet_merges(path).get(nm, [])
+ rows, seg, extra = parse_sheet(cell, nr, nc, city=city_file, merges=merges)
city = seg.get('甯傚窞') or city_file or city_by_override(f) or ''
sums = {k: sum(num(r.get(k)) or 0 for r in rows) for k in NUM_FIELDS}
sub = extra.get('灏忚鍚堣琛�') or {}
sub_txt, ok = [], '鈥�'
if not sub and extra.get('甯傚窞琛屽��'):
sub = {'R%s(甯傚窞琛�)' % (seg.get('甯傚窞琛�') or '?'): extra['甯傚窞琛屽��']}
+ tok = tval = None
if sub:
key, val = pick_total(sub)
+ tok, tval = key, val
sub_txt.append('%s=%s' % (key, '/'.join(pretty(val.get(k)) for k in ('鑷紑濮嬪缓璁剧疮璁�', '鑷勾鍒濈疮璁�', '鏈湀瀹屾垚'))))
if len(sub) > 1:
sub_txt.append('锛堝彟鏈� %d 琛屽皬璁�/鍚堣锛�' % (len(sub) - 1))
same = all(abs((val.get(k) or 0) - sums[k]) < 0.05
for k in ('鑷紑濮嬪缓璁剧疮璁�', '鑷勾鍒濈疮璁�', '鏈湀瀹屾垚'))
ok = '鉁� 涓�鑷�' if same else '鈿狅笍 涓嶄竴鑷�'
+ ck = {'鍝佺被': body_key, '甯傚窞': city, '鏂囦欢': f, '宸ヤ綔琛�': nm, '鐘舵��': 'OK',
+ '椤圭洰琛屾暟': len(rows), '鍚堣琛�': '', '涓�鑷存��': ok}
+ for k in ('鑷紑濮嬪缓璁剧疮璁�', '鑷勾鍒濈疮璁�', '鏈湀瀹屾垚'):
+ ck['姹傚拰_' + k] = sums[k]
+ if sub:
+ ck['鍚堣琛�'] = tok
+ for k in ('鑷紑濮嬪缓璁剧疮璁�', '鑷勾鍒濈疮璁�', '鏈湀瀹屾垚'):
+ ck['鍚堣_' + k] = tval.get(k)
+ checks.append(ck)
report.append('| %s | %s | %s | %d | %s | %s | %s |' % (
f[:44], nm[:14], city, len(rows),
'/'.join(pretty(sums[k]) for k in ('鑷紑濮嬪缓璁剧疮璁�', '鑷勾鍒濈疮璁�', '鏈湀瀹屾垚')),
@@ -234,6 +272,9 @@
records.append(rec)
except Exception as e:
report.append('| %s | 锛堣В鏋愬け璐ワ細%s: %s锛� | | | | | |' % (f[:44], type(e).__name__, str(e)[:60]))
+ checks.append({'鍝佺被': body_key, '甯傚窞': city_file or '', '鏂囦欢': f, '宸ヤ綔琛�': '',
+ '鐘舵��': '瑙f瀽澶辫触锛�%s: %s' % (type(e).__name__, str(e)[:80]),
+ '椤圭洰琛屾暟': 0, '涓�鑷存��': '鈥�'})
report.append('')
# 甯傚窞姹囨�伙紙璺ㄦ枃浠跺悎骞跺悓甯傚窞锛�
@@ -254,6 +295,17 @@
*(pretty(s[f]) for f in ('鎬绘姇璧�', '鑷紑濮嬪缓璁剧疮璁�', '鏈勾璁″垝鎶曡祫', '鑷勾鍒濈疮璁�', '鏈湀瀹屾垚'))))
report.append('')
+ ck_cols = ['鍝佺被', '甯傚窞', '鏂囦欢', '宸ヤ綔琛�', '鐘舵��', '椤圭洰琛屾暟', '涓�鑷存��', '鍚堣琛�',
+ '姹傚拰_鑷紑濮嬪缓璁剧疮璁�', '姹傚拰_鑷勾鍒濈疮璁�', '姹傚拰_鏈湀瀹屾垚',
+ '鍚堣_鑷紑濮嬪缓璁剧疮璁�', '鍚堣_鑷勾鍒濈疮璁�', '鍚堣_鏈湀瀹屾垚']
+ p_ck = os.path.join(out, '瑙f瀽鏍¢獙_%s.tsv' % a.month)
+ with io.open(p_ck, 'w', encoding='utf-8-sig') as fh:
+ fh.write('\t'.join(ck_cols) + '\n')
+ for c in checks:
+ fh.write('\t'.join(pretty(c.get(k, '')) if isinstance(c.get(k), float) else str(c.get(k, ''))
+ for k in ck_cols) + '\n')
+ print('鏍¢獙璁板綍鏁� = %d' % len(checks))
+
cols = ['鍝佺被', '甯傚窞', '鏂囦欢', '宸ヤ綔琛�', '琛屽彿', '搴忓彿', '鍒嗙被'] + FIELDS
tsv = os.path.join(out, '瑙f瀽缁撴灉_%s.tsv' % a.month)
with io.open(tsv, 'w', encoding='utf-8-sig') as fh:
@@ -265,6 +317,7 @@
print('椤圭洰琛屽悎璁� = %d' % len(records))
print('wrote', p_md)
print('wrote', tsv)
+ print('wrote', p_ck)
if __name__ == '__main__':
--
Gitblit v1.9.1