From b945d6234d1f84331d38656d35322c88a97597b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=B8=88?= Date: Tue, 9 Jun 2026 04:40:23 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=81=A2=E5=A4=8DGROUPBY+FILTER?= =?UTF-8?q?=E5=85=AC=E5=BC=8F(=E6=8C=89=E9=9C=80=E6=B7=B7=E7=94=A8COUNTIF)?= =?UTF-8?q?+@=E6=8F=90=E7=A4=BA=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cleaned/危大方案看板数据工作簿.xlsx | Bin 69110 -> 70115 bytes src/gen_workbook.py | 65 ++++++++---------- 2 files changed, 29 insertions(+), 36 deletions(-) diff --git a/data/2026-06-08/cleaned/危大方案看板数据工作簿.xlsx b/data/2026-06-08/cleaned/危大方案看板数据工作簿.xlsx index 9579ebb1e3dd33bf4e0f6b5a4fa919b0e90023fd..7635feec875051924bda540c6ebe9b9a2d455362 100644 GIT binary patch delta 6666 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 delta 5692 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 F{{w2xMT7tV diff --git a/src/gen_workbook.py b/src/gen_workbook.py index 8182135..f7a9805 100644 --- a/src/gen_workbook.py +++ b/src/gen_workbook.py @@ -154,34 +154,26 @@ TECH_COLS=['所属国别','项目名称','方案名称','编制单位','工程 write_data_sheet(s5,tech_valid.reset_index(drop=True), f'2026年度公司认定技术方案明细(ⅠⅡⅢ类·{tech_tot}项)',TECH_COLS) -# ═══ S6-S10b: 公式(全部用COUNTIF/COUNTIFS·不用GROUPBY/UNIQUE/FILTER避免@兼容问题) ═══ +# ═══ S6-S10b: 公式(GROUPBY用于分组聚合 + COUNTIF用于多指标混合) ═══ # ── S6: 公式-年度认定 ── s6=wb.create_sheet('公式-年度认定') -s6.merge_cells('A1:B1'); s6.cell(1,1,'OA年度认定(≥2026开工·COUNTIF公式)').font=TITLE_F; s6.cell(1,1).border=GOLD_BD -hdr_row(s6,3,['分类','方案数']) -s6.cell(4,1,'一般类').font=DATA_F; s6.cell(4,1).border=BORDER -s6.cell(4,2,f'=COUNTIF({REF}!$K$4:$K$200,"否")').font=FORMULA_F; s6.cell(4,2).border=BORDER -s6.cell(5,1,'超规类').font=DATA_F; s6.cell(5,1).border=BORDER -s6.cell(5,2,f'=COUNTIF({REF}!$K$4:$K$200,"是")').font=FORMULA_F; s6.cell(5,2).border=BORDER -s6.cell(6,1,'合计').font=BOLD_F; s6.cell(6,1).border=BORDER -s6.cell(6,2,'=B4+B5').font=BOLD_F; s6.cell(6,2).border=BORDER -for w,c in zip([14,10],'AB'): s6.column_dimensions[c].width=w +s6.merge_cells('A1:C1'); s6.cell(1,1,'OA年度认定(≥2026开工·GROUPBY公式)').font=TITLE_F; s6.cell(1,1).border=GOLD_BD +s6.merge_cells('A2:C2'); s6.cell(2,1,'=GROUPBY(有效≥2026!K3:K200,有效≥2026!A3:A200,COUNTA,3,0)').font=GRAY_F +s6.cell(4,1,f'=GROUPBY({REF}!K3:K200,{REF}!A3:A200,COUNTA,3,0)').font=FORMULA_F; s6.cell(4,1).border=BORDER +for w,c in zip([18,12],'AB'): s6.column_dimensions[c].width=w +# 提示行 +s6.merge_cells('A10:C10'); s6.cell(10,1,'💡 若WPS显示@前缀,选中单元格→删除@即可正常溢出').font=GRAY_F; s6.cell(10,1).fill=INFO_BG # ── S7: 公式-国别分布 ── s7=wb.create_sheet('公式-国别分布') -s7.merge_cells('A1:B1'); s7.cell(1,1,'OA国别分布(COUNTIF公式)').font=TITLE_F; s7.cell(1,1).border=GOLD_BD -hdr_row(s7,3,['国别','方案数']) -country_list = sorted(m['所属国别'].unique(), key=lambda x: m[m['所属国别']==x].shape[0], reverse=True) -for ri,cn in enumerate(country_list): - r = ri+4 - s7.cell(r,1,cn).font=DATA_F; s7.cell(r,1).border=BORDER - s7.cell(r,2,f'=COUNTIF({REF}!$C$4:$C$200,"{cn}")').font=FORMULA_F; s7.cell(r,2).border=BORDER -s7.cell(len(country_list)+4,1,'合计').font=BOLD_F; s7.cell(len(country_list)+4,1).border=BORDER -s7.cell(len(country_list)+4,2,f'=SUM(B4:B{len(country_list)+3})').font=BOLD_F; s7.cell(len(country_list)+4,2).border=BORDER +s7.merge_cells('A1:C1'); s7.cell(1,1,'OA国别分布(自动排序·GROUPBY公式)').font=TITLE_F; s7.cell(1,1).border=GOLD_BD +s7.merge_cells('A2:C2'); s7.cell(2,1,'=GROUPBY(有效≥2026!C3:C200,有效≥2026!A3:A200,COUNTA,3,0,-2)').font=GRAY_F +s7.cell(4,1,f'=GROUPBY({REF}!C3:C200,{REF}!A3:A200,COUNTA,3,0,-2)').font=FORMULA_F; s7.cell(4,1).border=BORDER for w,c in zip([30,12],'AB'): s7.column_dimensions[c].width=w +s7.merge_cells('A10:C10'); s7.cell(10,1,'💡 若WPS显示@前缀,选中单元格→删除@即可正常溢出').font=GRAY_F; s7.cell(10,1).fill=INFO_BG -# ── S8: 公式-审批进度(COUNTIF·无GROUPBY) ── +# ── S8: 公式-审批进度(多指标混合·COUNTIF) ── s8=wb.create_sheet('公式-审批进度') s8.merge_cells('A1:C1'); s8.cell(1,1,'OA审批进度 & 预警(COUNTIF公式)').font=TITLE_F; s8.cell(1,1).border=GOLD_BD hdr_row(s8,3,['指标','数值','备注']) @@ -200,29 +192,30 @@ for ri,(lab,fm,note) in enumerate(rows8): s8.cell(r,3,note).font=GRAY_F; s8.cell(r,3).border=BORDER for w,c in zip([18,10,35],'ABC'): s8.column_dimensions[c].width=w -# ── S9: 公式-预警明细 ── 改用Python静态写(FILTER同样有@问题) -# 保留Static sheet "预警明细" 足够用;公式版跳过 +# ── S9: 公式-预警明细 ── FILTER 动态筛选 +s9=wb.create_sheet('公式-预警明细') +s9.merge_cells('A1:C1'); s9.cell(1,1,'OA预警明细(FILTER动态筛选)').font=TITLE_F; s9.cell(1,1).border=GOLD_BD +s9.merge_cells('A2:C2'); s9.cell(2,1,'=FILTER(有效≥2026!A3:AD200,有效≥2026!AD3:AD200<>"none","无预警")').font=GRAY_F +s9.cell(4,1,f'=FILTER({REF}!A3:AD200,{REF}!AD3:AD200<>"none","🎉 无预警项")').font=FORMULA_F; s9.cell(4,1).border=BORDER +for w,c in zip([22],'A'): s9.column_dimensions[c].width=w +s9.merge_cells('A10:C10'); s9.cell(10,1,'💡 若WPS显示@前缀,选中单元格→删除@即可正常溢出').font=GRAY_F; s9.cell(10,1).fill=INFO_BG # ── S10: 公式-认定分类 ── s10=wb.create_sheet('公式-认定分类') -s10.merge_cells('A1:B1'); s10.cell(1,1,'认定危大方案分类(COUNTIF公式)').font=TITLE_F; s10.cell(1,1).border=GOLD_BD -hdr_row(s10,3,['分类','方案数']) -s10.cell(4,1,'一般类').font=DATA_F; s10.cell(4,1).border=BORDER -s10.cell(4,2,f'=COUNTIF({CREF}!$H$4:$H$200,"否")').font=FORMULA_F; s10.cell(4,2).border=BORDER -s10.cell(5,1,'超规类').font=DATA_F; s10.cell(5,1).border=BORDER -s10.cell(5,2,f'=COUNTIF({CREF}!$H$4:$H$200,"是")').font=FORMULA_F; s10.cell(5,2).border=BORDER -s10.cell(6,1,'合计').font=BOLD_F; s10.cell(6,1).border=BORDER -s10.cell(6,2,'=B4+B5').font=BOLD_F; s10.cell(6,2).border=BORDER -for w,c in zip([14,10],'AB'): s10.column_dimensions[c].width=w +s10.merge_cells('A1:C1'); s10.cell(1,1,'认定危大方案分类(GROUPBY公式)').font=TITLE_F; s10.cell(1,1).border=GOLD_BD +s10.merge_cells('A2:C2'); s10.cell(2,1,'=GROUPBY(认定数据!H3:H200,认定数据!D3:D200,COUNTA,3,0)').font=GRAY_F +s10.cell(4,1,f'=GROUPBY({CREF}!H3:H200,{CREF}!D3:D200,COUNTA,3,0)').font=FORMULA_F; s10.cell(4,1).border=BORDER +for w,c in zip([20,12],'AB'): s10.column_dimensions[c].width=w +s10.merge_cells('A10:C10'); s10.cell(10,1,'💡 若WPS显示@前缀,选中单元格→删除@即可正常溢出').font=GRAY_F; s10.cell(10,1).fill=INFO_BG # ── S10b: 公式-技术方案分类 ── s10b=wb.create_sheet('公式-技术方案分类') TREF="'认定技术方案'" -s10b.merge_cells('A1:B1'); s10b.cell(1,1,'认定技术方案等级分布(COUNTIF公式)').font=TITLE_F; s10b.cell(1,1).border=GOLD_BD -hdr_row(s10b,3,['等级','方案数']) -s10b.cell(4,1,'Ⅲ类').font=DATA_F; s10b.cell(4,1).border=BORDER -s10b.cell(4,2,f'=COUNTIF({TREF}!$F$4:$F$200,"Ⅲ")').font=FORMULA_F; s10b.cell(4,2).border=BORDER +s10b.merge_cells('A1:C1'); s10b.cell(1,1,'认定技术方案等级分布(GROUPBY公式)').font=TITLE_F; s10b.cell(1,1).border=GOLD_BD +s10b.merge_cells('A2:C2'); s10b.cell(2,1,'=GROUPBY(认定技术方案!F3:F200,认定技术方案!C3:C200,COUNTA,3,0,-2)').font=GRAY_F +s10b.cell(4,1,f'=GROUPBY({TREF}!F3:F200,{TREF}!C3:C200,COUNTA,3,0,-2)').font=FORMULA_F; s10b.cell(4,1).border=BORDER for w,c in zip([12,12],'AB'): s10b.column_dimensions[c].width=w +s10b.merge_cells('A10:C10'); s10b.cell(10,1,'💡 若WPS显示@前缀,选中单元格→删除@即可正常溢出').font=GRAY_F; s10b.cell(10,1).fill=INFO_BG # ═══ 静态汇总 ═══ s11=wb.create_sheet('年度认定汇总') @@ -282,5 +275,5 @@ print(f"\n✅ {OUT}") print(f" S1-S3 数据源: OA{len(valid_all)}/{len(valid_2026)} + 认定{cert_tot}+技术{tech_tot}") print(f" S4 公式-认定vsOA: COUNTIFS项目级对比") print(f" S5 认定技术方案(表2): {tech_tot}行") -print(f" S6-S10b 公式: COUNTIF/COUNTIFS(全部无GROUPBY/UNIQUE/FILTER)") +print(f" S6-S10b 公式: GROUPBY+COUNTIF+FILTER(@问题有提示行)") print(f" S11-S14 静态汇总: 交叉验证") \ No newline at end of file