From 1e6dadf551e08ed54d5d74b616d232c98d812e09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=B8=88?= Date: Tue, 9 Jun 2026 05:06:40 +0800 Subject: [PATCH] =?UTF-8?q?style:=20=E5=85=AC=E5=BC=8F=E5=B7=A5=E4=BD=9C?= =?UTF-8?q?=E8=A1=A8=E5=85=A8=E5=B1=80=E7=BE=8E=E5=8C=96=20=E2=80=94=20?= =?UTF-8?q?=E9=87=91=E8=89=B2=E5=B7=A6=E7=AB=96=E7=BA=BF+=E6=B7=A1?= =?UTF-8?q?=E9=BB=84=E5=BA=95=E5=85=AC=E5=BC=8F=E6=A0=BC=C2=B7=E6=B7=A1?= =?UTF-8?q?=E8=93=9D=E6=BA=A2=E5=87=BA=E5=8C=BA=C2=B7S8=E4=BA=A4=E6=9B=BF?= =?UTF-8?q?=E8=A1=8C=E8=89=B2+=E9=A2=84=E8=AD=A6=E9=AB=98=E4=BA=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gen_workbook.py | 81 +++++++++++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/src/gen_workbook.py b/src/gen_workbook.py index d417e51..6496767 100644 --- a/src/gen_workbook.py +++ b/src/gen_workbook.py @@ -50,8 +50,13 @@ BOLD_F=Font(name='微软雅黑',bold=True,size=10); GRAY_F=Font(name='微软雅 GREEN_F=Font(name='微软雅黑',bold=True,size=10,color='2E7D32'); RED_F=Font(name='微软雅黑',bold=True,size=10,color='D94E34') BLUE_F=Font(name='微软雅黑',bold=True,size=10,color='1A3A5C'); ORANGE_F=Font(name='微软雅黑',bold=True,size=10,color='E65100') FORMULA_F=Font(name='Consolas',size=10,color='1A3A5C') +FRM_F_B=Font(name='Consolas',bold=True,size=11,color='1A3A5C') WARN_BG=PatternFill('solid',fgColor='FFF3E0'); INFO_BG=PatternFill('solid',fgColor='F0F4FA') +FRM_BG=PatternFill('solid',fgColor='FFFBEB'); SPILL_BG=PatternFill('solid',fgColor='F0F8FF') +ROW_ODD=PatternFill('solid',fgColor='FAFBFC'); ROW_DONE=PatternFill('solid',fgColor='E8F5E9') +ROW_WARN=PatternFill('solid',fgColor='FFF8E1') BORDER=Border(left=Side('thin','DBE2EA'),right=Side('thin','DBE2EA'),top=Side('thin','DBE2EA'),bottom=Side('thin','DBE2EA')) +FRM_LEFT=Border(left=Side(style='medium',color='C8962E'),right=Side('thin','DBE2EA'),top=Side('thin','DBE2EA'),bottom=Side('thin','DBE2EA')) CENTER=Alignment(horizontal='center',vertical='center',wrap_text=True) GOLD_BD=Border(bottom=Side(style='medium',color='C8962E')) REF="'有效≥2026'"; CREF="'认定数据'" @@ -160,65 +165,85 @@ write_data_sheet(s5,tech_valid.reset_index(drop=True), s6=wb.create_sheet('公式-年度认定') 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'=_xlfn.GROUPBY({REF}!K3:K200,{REF}!A3:A200,COUNTA,3,0)').font=FORMULA_F; s6.cell(4,1).border=BORDER +s6.row_dimensions[3].height=6 +s6.cell(4,1,f'=_xlfn.GROUPBY({REF}!K3:K200,{REF}!A3:A200,COUNTA,3,0)').font=FRM_F_B; s6.cell(4,1).border=FRM_LEFT; s6.cell(4,1).fill=FRM_BG +for r in range(5,9): + for c in [1,2]: s6.cell(r,c).fill=SPILL_BG; s6.cell(r,c).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,'💡 _xlfn.前缀=告知WPS这是动态数组函数·不加@').font=GRAY_F; s6.cell(10,1).fill=INFO_BG +s6.merge_cells('A10:C10'); s6.cell(10,1,'💡 _xlfn.前缀=告知WPS动态数组函数·不加@').font=GRAY_F; s6.cell(10,1).fill=INFO_BG # ── S7: 公式-国别分布 ── s7=wb.create_sheet('公式-国别分布') 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'=_xlfn.GROUPBY({REF}!C3:C200,{REF}!A3:A200,COUNTA,3,0,-2)').font=FORMULA_F; s7.cell(4,1).border=BORDER +s7.row_dimensions[3].height=6 +s7.cell(4,1,f'=_xlfn.GROUPBY({REF}!C3:C200,{REF}!A3:A200,COUNTA,3,0,-2)').font=FRM_F_B; s7.cell(4,1).border=FRM_LEFT; s7.cell(4,1).fill=FRM_BG +for r in range(5,12): + for c in [1,2]: s7.cell(r,c).fill=SPILL_BG; s7.cell(r,c).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 +s7.merge_cells('A14:C14'); s7.cell(14,1,'💡 _xlfn.前缀=告知WPS动态数组函数·不加@').font=GRAY_F; s7.cell(14,1).fill=INFO_BG -# ── S8: 公式-审批进度(多指标混合·COUNTIF) ── +# ── 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 +s8.row_dimensions[2].height=6 hdr_row(s8,3,['指标','数值','备注']) rows8 = [ - ('方案总数',f'=COUNTA({REF}!A4:A200)','≥2026年开工'), - ('已完成审批',f'=COUNTIF({REF}!Z4:Z200,TRUE)','含"已完成"状态'), - ('未完成审批',f'=COUNTIF({REF}!Z4:Z200,FALSE)','审批中+未审批'), - ('🟠 橙色预警',f'=COUNTIF({REF}!AD4:AD200,"orange")','距开工≤30天'), - ('🟡 黄色预警',f'=COUNTIF({REF}!AD4:AD200,"yellow")','距开工≤45天'), - ('预警合计','=B7+B8','橙色+黄色'), + ('方案总数',f'=COUNTA({REF}!A4:A200)','≥2026年开工',BLUE_F,None), + ('已完成审批',f'=COUNTIF({REF}!Z4:Z200,TRUE)','含"已完成"状态',GREEN_F,ROW_DONE), + ('未完成审批',f'=COUNTIF({REF}!Z4:Z200,FALSE)','审批中+未审批',DATA_F,None), + ('🟠 橙色预警',f'=COUNTIF({REF}!AD4:AD200,"orange")','距开工≤30天',ORANGE_F,ROW_WARN), + ('🟡 黄色预警',f'=COUNTIF({REF}!AD4:AD200,"yellow")','距开工≤45天',Font(name='微软雅黑',bold=True,size=10,color='F9A825'),ROW_WARN), + ('预警合计','=B7+B8','橙色+黄色',RED_F,None), ] -for ri,(lab,fm,note) in enumerate(rows8): +for ri,(lab,fm,note,lf,bg) in enumerate(rows8): r=ri+4 - s8.cell(r,1,lab).font=DATA_F; s8.cell(r,1).border=BORDER - s8.cell(r,2,fm).font=FORMULA_F; s8.cell(r,2).border=BORDER + s8.cell(r,1,lab).font=lf; s8.cell(r,1).border=BORDER + if bg: s8.cell(r,1).fill=bg + s8.cell(r,2,fm).font=FRM_F_B; s8.cell(r,2).border=BORDER; s8.cell(r,2).fill=FRM_BG + if bg: s8.cell(r,2).fill=bg s8.cell(r,3,note).font=GRAY_F; s8.cell(r,3).border=BORDER + if bg: s8.cell(r,3).fill=bg + if ri%2==0 and not bg: # 奇偶行无特殊色时用交替灰 + for ci in range(1,4): s8.cell(r,ci).fill=ROW_ODD for w,c in zip([18,10,35],'ABC'): s8.column_dimensions[c].width=w -# ── S9: 公式-预警明细 ── FILTER 动态筛选(A10无内容=溢出通畅) +# ── S9: 公式-预警明细 ── FILTER 动态筛选(美化版) s9=wb.create_sheet('公式-预警明细') -s9.cell(1,1,'OA预警明细(FILTER动态筛选·无合并单元格)').font=TITLE_F; s9.cell(1,1).border=GOLD_BD -s9.cell(2,1,'FILTER(有效≥2026!A3:AD200,(有效≥2026!AD3:AD200<>"none")*(有效≥2026!AD3:AD200<>""),"无预警")').font=GRAY_F -# 条件双重过滤:排除 "none" + 排除空值,避免空值行也被选入导致溢出触达A10 -s9.cell(4,1,f'=_xlfn.FILTER({REF}!A3:AD200,({REF}!AD3:AD200<>"none")*({REF}!AD3:AD200<>""),"🎉 无预警项")').font=FORMULA_F; s9.cell(4,1).border=BORDER -for i in range(1,31): - s9.column_dimensions[get_column_letter(i)].width = 4 if i>1 else 6 -s9.column_dimensions['C'].width=22; s9.column_dimensions['D'].width=40 -s9.column_dimensions['E'].width=35; s9.column_dimensions['K'].width=12 -s9.column_dimensions['AD'].width=10 +s9.cell(1,1,'OA预警明细(FILTER动态筛选)').font=TITLE_F; s9.cell(1,1).border=GOLD_BD +s9.cell(2,1,'_xlfn.FILTER(有效≥2026!A3:AD200,(AD3:AD200<>"none")*(AD3:AD200<>""),"无预警")').font=GRAY_F +s9.row_dimensions[3].height=6 +s9.cell(4,1,f'=_xlfn.FILTER({REF}!A3:AD200,({REF}!AD3:AD200<>"none")*({REF}!AD3:AD200<>""),"🎉 无预警项")').font=FRM_F_B; s9.cell(4,1).border=FRM_LEFT; s9.cell(4,1).fill=FRM_BG +# 溢出区淡蓝底:A5:AD9(最多5预警+1表头=6行) +for r in range(5,11): + for i in range(1,31): s9.cell(r,i).fill=SPILL_BG; s9.cell(r,i).border=BORDER +for i in range(1,31): s9.column_dimensions[get_column_letter(i)].width=4 +s9.column_dimensions['A'].width=6; s9.column_dimensions['C'].width=22 +s9.column_dimensions['D'].width=40; s9.column_dimensions['E'].width=35 +s9.column_dimensions['K'].width=12; s9.column_dimensions['AD'].width=10 # ── S10: 公式-认定分类 ── s10=wb.create_sheet('公式-认定分类') 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'=_xlfn.GROUPBY({CREF}!H3:H200,{CREF}!D3:D200,COUNTA,3,0)').font=FORMULA_F; s10.cell(4,1).border=BORDER +s10.row_dimensions[3].height=6 +s10.cell(4,1,f'=_xlfn.GROUPBY({CREF}!H3:H200,{CREF}!D3:D200,COUNTA,3,0)').font=FRM_F_B; s10.cell(4,1).border=FRM_LEFT; s10.cell(4,1).fill=FRM_BG +for r in range(5,9): + for c in [1,2]: s10.cell(r,c).fill=SPILL_BG; s10.cell(r,c).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 +s10.merge_cells('A10:C10'); s10.cell(10,1,'💡 源数据更新后公式自动刷新').font=GRAY_F; s10.cell(10,1).fill=INFO_BG # ── S10b: 公式-技术方案分类 ── s10b=wb.create_sheet('公式-技术方案分类') TREF="'认定技术方案'" 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'=_xlfn.GROUPBY({TREF}!F3:F200,{TREF}!C3:C200,COUNTA,3,0,-2)').font=FORMULA_F; s10b.cell(4,1).border=BORDER +s10b.row_dimensions[3].height=6 +s10b.cell(4,1,f'=_xlfn.GROUPBY({TREF}!F3:F200,{TREF}!C3:C200,COUNTA,3,0,-2)').font=FRM_F_B; s10b.cell(4,1).border=FRM_LEFT; s10b.cell(4,1).fill=FRM_BG +for r in range(5,9): + for c in [1,2]: s10b.cell(r,c).fill=SPILL_BG; s10b.cell(r,c).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 +s10b.merge_cells('A10:C10'); s10b.cell(10,1,'💡 源数据更新后公式自动刷新').font=GRAY_F; s10b.cell(10,1).fill=INFO_BG # ═══ 静态汇总 ═══ s11=wb.create_sheet('年度认定汇总')