From 381b4c740f58ef090ed843d43438493157ca6ba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=B8=88?= Date: Tue, 9 Jun 2026 04:26:30 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=85=AC=E5=BC=8F-=E8=AE=A4=E5=AE=9AvsO?= =?UTF-8?q?A=E9=87=8D=E5=86=99-=E9=A1=B9=E7=9B=AE=E5=90=8D=E9=A2=84?= =?UTF-8?q?=E5=A1=AB+COUNTIFS=E7=9B=B4=E5=86=99(=E6=97=A0IF=E5=8C=85?= =?UTF-8?q?=E8=A3=85)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cleaned/危大方案看板数据工作簿.xlsx | Bin 69602 -> 69846 bytes src/gen_workbook.py | 104 +++++++++--------- 2 files changed, 50 insertions(+), 54 deletions(-) diff --git a/data/2026-06-08/cleaned/危大方案看板数据工作簿.xlsx b/data/2026-06-08/cleaned/危大方案看板数据工作簿.xlsx index 13b3b7a6a728e5b441e70327de669199462fe380..b248c61151494392c7fd6f109bab72a097a3f2b8 100644 GIT binary patch delta 15595 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 OMFpb4lpp}XM*lxQLL5{8 delta 15356 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 diff --git a/src/gen_workbook.py b/src/gen_workbook.py index 99d0700..68edfec 100644 --- a/src/gen_workbook.py +++ b/src/gen_workbook.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""危大方案看板数据工作簿 v5 — 双数据源(OA登记+公司认定) + GROUPBY/FILTER动态公式""" +"""危大方案看板数据工作簿 v5 — 双数据源 + 纯Excel公式(认定vsOA用COUNTIFS直写)""" import sys import pandas as pd from openpyxl import Workbook @@ -15,10 +15,8 @@ else: BASE = f"/mnt/y/Openclaw_Hub/03.资源/实施项目 wiki/dashboard/data/{REPORT_DATE}" CERT_DIR = "/mnt/y/Openclaw_Hub/03.资源/实施项目 wiki/dashboard/data/认定数据/2026" OUT = f"{BASE}/cleaned/危大方案看板数据工作簿.xlsx" -REF = "'有效≥2026'" -CREF = "'认定数据'" -# ════ 数据源1: OA登记 ════ +# ════ 数据源 ════ df = pd.read_csv(f"{BASE}/cleaned/methods_cleaned.csv") SRC_COLS = list(df.columns[:24]) valid_all = df[df['是否有效登记'] == True].copy() @@ -29,20 +27,19 @@ completed = m['是否完成审批'].sum(); unfinished = tot-completed projects = m['项目名称'].nunique(); countries = m['所属国别'].value_counts().to_dict() warn_df = m[m['预警信号']!='none'].sort_values('分部分项工程计划开工日期') warn_total = len(warn_df); orange = (warn_df['预警信号']=='orange').sum(); yellow = warn_total-orange -print(f"OA登记: {tot}项(一般{gen}/超规{sup}) 完成{completed} 预警{orange}橙{yellow}黄") -# ════ 数据源2: 公司认定 ════ cert_raw = pd.read_csv(f"{CERT_DIR}/certified_schemes_detail.csv") cert_raw['计划开工日期_p'] = pd.to_datetime(cert_raw['计划开工日期'].astype(str).str.replace('.','-'), errors='coerce') cert_valid = cert_raw[cert_raw['计划开工日期_p'].dt.year >= 2026].copy() cert_tot = len(cert_valid) cert_sup = (cert_valid['是否超一定规模']=='是').sum(); cert_gen = cert_tot-cert_sup -cert_comp = pd.read_csv(f"{CERT_DIR}/certified_schemes.csv") + tech_raw = pd.read_csv(f"{CERT_DIR}/certified_tech_schemes_detail.csv") tech_raw['计划开工日期_p'] = pd.to_datetime(tech_raw['计划开工日期'].astype(str).str.replace('.','-'), errors='coerce') tech_valid = tech_raw[tech_raw['计划开工日期_p'].dt.year >= 2026].copy() tech_tot = len(tech_valid) -print(f"公司认定: 表1危大{cert_tot}项({cert_gen}一般/{cert_sup}超规) + 表2技术{tech_tot}项 = {cert_tot+tech_tot}总计") + +print(f"OA: {tot}(一般{gen}/超规{sup}) 完成{completed} | 认定: 表1{cert_tot}+表2{tech_tot}={cert_tot+tech_tot}") # ════ 样式 ════ HDR_F=Font(name='微软雅黑',bold=True,size=10,color='FFFFFF'); HDR_BG=PatternFill('solid',fgColor='1A3A5C') @@ -55,6 +52,7 @@ WARN_BG=PatternFill('solid',fgColor='FFF3E0'); INFO_BG=PatternFill('solid',fgCol BORDER=Border(left=Side('thin','DBE2EA'),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="'认定数据'" def hdr_row(ws,r,cols): for i,h in enumerate(cols): @@ -86,82 +84,85 @@ def write_formula_sheet(ws,title,subtitle,formulas,col_widths): ws.cell(2,1,subtitle).font=Font(name='微软雅黑',size=9,color='8899AA') for col_letter,row_num,formula,label in formulas: cell=ws.cell(row_num,ord(col_letter)-64,formula); cell.font=FORMULA_F; cell.border=BORDER - if label: - ws.cell(row_num,ord(col_letter)-63,label).font=GRAY_F - for col_letter,w in col_widths: - ws.column_dimensions[col_letter].width=w + if label: ws.cell(row_num,ord(col_letter)-63,label).font=GRAY_F + for col_letter,w in col_widths: ws.column_dimensions[col_letter].width=w ws.merge_cells(start_row=12,start_column=1,end_row=12,end_column=4) ws.cell(12,1,'💡 源数据更新后公式自动刷新(WPS新版/Excel 365)').font=GRAY_F; ws.cell(12,1).fill=INFO_BG wb = Workbook() -# ═══ S1: OA清洗后数据 ═══ +# ═══ S1-S3 数据源 ═══ s1=wb.active; s1.title='清洗后数据' write_data_sheet(s1,valid_all.reset_index(drop=True), f'OA登记·清洗后数据(有效登记·全部年份·{len(valid_all)}行)', SRC_COLS+['方案状态_clean','是否完成审批','是否有效登记','开工年份','开工月份','预警信号']) -# ═══ S2: OA有效≥2026 ═══ s2=wb.create_sheet('有效≥2026') write_data_sheet(s2,valid_2026.reset_index(drop=True), f'OA登记·有效≥2026年开工({len(valid_2026)}行)', SRC_COLS+['方案状态_clean','是否完成审批','是否有效登记','开工年份','开工月份','预警信号']) -# ═══ S3: 认定数据 ═══ s3=wb.create_sheet('认定数据') CERT_COLS=['所属区域','所属国别','项目名称','方案名称','编制单位','工程类别','分部工程类别','是否超一定规模','计划开工日期'] write_data_sheet(s3,cert_valid.reset_index(drop=True), f'2026年度公司认定危大方案明细(中港科技便〔2026〕6号·{cert_tot}项)',CERT_COLS) -# ═══ S4: 公式-认定vsOA(纯Excel公式·COUNTIFS动态对比) ═══ +# ═══ S4: 公式-认定vsOA ═══ +# 项目名从认定数据 C4:C200 提取,省去 UNIQUE(WPS兼容性更好) +# 用 COUNTIFS 统计 超规("是") 和 一般("否") s4=wb.create_sheet('公式-认定vsOA') COMP_HDR=['项目名称','认定超规','认定一般','OA超规','OA一般','差额超规','差额一般'] ncol_c=len(COMP_HDR) s4.merge_cells(start_row=1,start_column=1,end_row=1,end_column=ncol_c) -s4.cell(1,1,f'认定 vs OA登记 项目级对比({REPORT_DATE}·Excel公式自动计算)').font=TITLE_F -s4.cell(1,1).border=GOLD_BD +s4.cell(1,1,f'认定 vs OA登记 项目级对比({REPORT_DATE}·COUNTIFS公式)').font=TITLE_F; s4.cell(1,1).border=GOLD_BD s4.merge_cells(start_row=2,start_column=1,end_row=2,end_column=ncol_c) -s4.cell(2,1,'COUNTIFS(认定数据!C:C,项目,H:H,"是"/"否") vs COUNTIFS(有效≥2026!D:D,项目,K:K,"是"/"否")').font=GRAY_F +s4.cell(2,1,'A列=项目 | B=认定超规 | C=认定一般 | D=OA超规 | E=OA一般 | F=差额超规 | G=差额一般').font=GRAY_F hdr_row(s4,3,COMP_HDR) -# A4: UNIQUE动态获取项目列表 -s4.cell(4,1,"=UNIQUE('认定数据'!C4:C200)").font=FORMULA_F; s4.cell(4,1).border=BORDER +# 用 Python 预填项目名(因为 UNIQUE 在部分WPS版本不支持) +# 然后 COUNTIFS 引用项目名列 +proj_list = sorted(cert_valid['项目名称'].unique()) +for ri, proj_name in enumerate(proj_list): + r = ri + 4 + s4.cell(r, 1, proj_name).font=DATA_F; s4.cell(r, 1).border=BORDER -# B4-G23: COUNTIFS + 差额公式(预填20行,超UNIQUE范围自动留空) +# 公式行:B-H 全部用 =COUNTIFS / =差额(预填20行) for r in range(4, 24): - ar = f'$A{r}' if r > 4 else 'A4' - pref = f'IF({ar}="","",' - s4.cell(r,2,f'={pref}COUNTIFS(' + "'认定数据'!$C$4:$C$200," + f'{ar},' + "'认定数据'!$H$4:$H$200," + '"是"))').font=FORMULA_F; s4.cell(r,2).border=BORDER - s4.cell(r,3,f'={pref}COUNTIFS(' + "'认定数据'!$C$4:$C$200," + f'{ar},' + "'认定数据'!$H$4:$H$200," + '"否"))').font=FORMULA_F; s4.cell(r,3).border=BORDER - s4.cell(r,4,f'={pref}COUNTIFS(' + "'有效≥2026'!$D$4:$D$200," + f'{ar},' + "'有效≥2026'!$K$4:$K$200," + '"是"))').font=FORMULA_F; s4.cell(r,4).border=BORDER - s4.cell(r,5,f'={pref}COUNTIFS(' + "'有效≥2026'!$D$4:$D$200," + f'{ar},' + "'有效≥2026'!$K$4:$K$200," + '"否"))').font=FORMULA_F; s4.cell(r,5).border=BORDER - s4.cell(r,6,f'={pref}D{r}-B{r})').font=FORMULA_F; s4.cell(r,6).border=BORDER - s4.cell(r,7,f'={pref}E{r}-C{r})').font=FORMULA_F; s4.cell(r,7).border=BORDER + ar = f'$A{r}' + sr = str(r) + # B: 认定超规 + s4.cell(r, 2, f'=COUNTIFS(' + "'认定数据'!C4:C200," + f'{ar},' + "'认定数据'!H4:H200," + '"是")').font=FORMULA_F; s4.cell(r, 2).border=BORDER + # C: 认定一般 + s4.cell(r, 3, f'=COUNTIFS(' + "'认定数据'!C4:C200," + f'{ar},' + "'认定数据'!H4:H200," + '"否")').font=FORMULA_F; s4.cell(r, 3).border=BORDER + # D: OA超规 + s4.cell(r, 4, f'=COUNTIFS(' + "'有效≥2026'!D4:D200," + f'{ar},' + "'有效≥2026'!K4:K200," + '"是")').font=FORMULA_F; s4.cell(r, 4).border=BORDER + # E: OA一般 + s4.cell(r, 5, f'=COUNTIFS(' + "'有效≥2026'!D4:D200," + f'{ar},' + "'有效≥2026'!K4:K200," + '"否")').font=FORMULA_F; s4.cell(r, 5).border=BORDER + # F: 差额超规 = D - B + s4.cell(r, 6, f'=D{sr}-B{sr}').font=FORMULA_F; s4.cell(r, 6).border=BORDER + # G: 差额一般 = E - C + s4.cell(r, 7, f'=E{sr}-C{sr}').font=FORMULA_F; s4.cell(r, 7).border=BORDER s4.auto_filter.ref='A3:G23' for w,col in zip([40,12,12,12,12,12,12],'ABCDEFG'): s4.column_dimensions[col].width=w -# ═══ S5: 认定技术方案(表2) ═══ +# ═══ S5: 认定技术方案 ═══ s5=wb.create_sheet('认定技术方案') TECH_COLS=['所属国别','项目名称','方案名称','编制单位','工程类别','方案等级','工程特点/说明','计划开工日期'] write_data_sheet(s5,tech_valid.reset_index(drop=True), - f'2026年度公司认定技术方案明细(ⅠⅡⅢ类·中港科技便〔2026〕6号·{tech_tot}项)',TECH_COLS) - -# ═══ S6-S10: 动态公式 ═══ + f'2026年度公司认定技术方案明细(ⅠⅡⅢ类·{tech_tot}项)',TECH_COLS) +# ═══ S6-S10b: 动态公式 ═══ s6=wb.create_sheet('公式-年度认定') -write_formula_sheet(s6,f'OA年度认定(≥2026开工)', - f'GROUPBY({REF}!K3:K200,{REF}!A3:A200,COUNTA,3,0)', +write_formula_sheet(s6,'OA年度认定','GROUPBY on 是否超一定规模', [('A',4,f'=GROUPBY({REF}!K3:K200,{REF}!A3:A200,COUNTA,3,0)','')],[('A',18),('B',12)]) s7=wb.create_sheet('公式-国别分布') -write_formula_sheet(s7,f'OA国别×分类(自动排序)', - f'GROUPBY({REF}!C3:C200,{REF}!A3:A200,COUNTA,3,0,-2)', +write_formula_sheet(s7,'OA国别×分类','GROUPBY on 所属国别', [('A',4,f'=GROUPBY({REF}!C3:C200,{REF}!A3:A200,COUNTA,3,0,-2)','')],[('A',30),('B',12)]) s8=wb.create_sheet('公式-审批进度') -write_formula_sheet(s8,f'OA审批进度 & 预警', - f'引用 {REF}!Z:Z + AD:AD', +write_formula_sheet(s8,'OA审批进度 & 预警','COUNTIF on 是否完成审批', [('A',4,'方案总数',''),('B',4,f'=COUNTA({REF}!A4:A200)',''), ('A',5,'已完成审批',''),('B',5,f'=COUNTIF({REF}!Z4:Z200,TRUE)',''), ('A',6,'未完成审批',''),('B',6,f'=COUNTIF({REF}!Z4:Z200,FALSE)',''), @@ -170,23 +171,20 @@ write_formula_sheet(s8,f'OA审批进度 & 预警', ('A',9,'预警合计',''),('B',9,'=B7+B8','')],[('A',20),('B',14)]) s9=wb.create_sheet('公式-预警明细') -write_formula_sheet(s9,f'OA预警明细(FILTER)', - f'FILTER({REF}!A3:AD200,{REF}!AD3:AD200<>"none","无预警")', +write_formula_sheet(s9,'OA预警明细','FILTER on 预警信号', [('A',4,f'=FILTER({REF}!A3:AD200,{REF}!AD3:AD200<>"none","🎉 无预警项")','')],[('A',22)]) s10=wb.create_sheet('公式-认定分类') -write_formula_sheet(s10,f'公司认定方案分类(GROUPBY·{cert_tot}项)', - f'GROUPBY({CREF}!H3:H200,{CREF}!D3:D200,COUNTA,3,0)', +write_formula_sheet(s10,'公司认定分类','GROUPBY on 认定数据', [('A',4,f'=GROUPBY({CREF}!H3:H200,{CREF}!D3:D200,COUNTA,3,0)','')],[('A',20),('B',12)]) s10b=wb.create_sheet('公式-技术方案分类') -TREF = "'认定技术方案'" -write_formula_sheet(s10b,f'认定技术方案等级分布(GROUPBY·{tech_tot}项)', +TREF="'认定技术方案'" +write_formula_sheet(s10b,'认定技术方案等级分布', f'GROUPBY({TREF}!F3:F200,{TREF}!C3:C200,COUNTA,3,0)', [('A',4,f'=GROUPBY({TREF}!F3:F200,{TREF}!C3:C200,COUNTA,3,0)','')],[('A',20),('B',12)]) -# ═══ S11-S14: 静态汇总(交叉验证) ═══ - +# ═══ 静态汇总 ═══ s11=wb.create_sheet('年度认定汇总') s11.merge_cells('A1:E1'); s11.cell(1,1,f'OA年度认定(≥2026·静态)').font=TITLE_F; s11.cell(1,1).border=GOLD_BD hdr_row(s11,3,['分类','方案数','项目数','占比','备注']) @@ -241,9 +239,7 @@ for w,col in zip([6,8,40,35,18,12,10,20],'ABCDEFGH'): s14.column_dimensions[col] wb.save(OUT) print(f"\n✅ {OUT}") -print(f" S1-S2 OA登记: {len(valid_all)}全量 + {len(valid_2026)}≥2026") -print(f" S3 认定危大方案(表1): {cert_tot}行({cert_gen}一般+{cert_sup}超规)") -print(f" S4 公式-认定vsOA: COUNTIFS动态对比") -print(f" S5 认定技术方案(表2): {tech_tot}行") -print(f" S6-S10 GROUPBY/FILTER 动态公式(含表1+表2)") -print(f" S11-S14 静态汇总表(交叉验证)") +print(f" S1-S3 数据源: OA{len(valid_all)}/{len(valid_2026)} + 认定{cert_tot}+技术{tech_tot}") +print(f" S4 公式-认定vsOA: COUNTIFS对比(项目名预填+公式自动计算)") +print(f" S5-S10b 动态公式: GROUPBY/FILTER/COUNTIF") +print(f" S11-S14 静态汇总: 交叉验证") \ No newline at end of file