spec: 认定数据固化+工作簿双数据源+GROUPBY动态公式
This commit is contained in:
parent
91d82ac475
commit
b0fd2f26e2
80
README.md
80
README.md
@ -6,9 +6,9 @@
|
||||
|
||||
| 文件 | 说明 | 更新频率 |
|
||||
|:------|:------|:------|
|
||||
| `certified_schemes_dashboard.html` | 危大方案独立看板(双页PPT宽屏) | 每月 |
|
||||
| `危大方案看板数据工作簿.xlsx` | 清洗数据 + 6数据透视表 | 每月 |
|
||||
| `dashboard.html` | 三合一综合看板 | 每月 |
|
||||
| `certified_schemes_dashboard.html` | 危大方案独立看板(双页PPT宽屏·1280px) | 每月 |
|
||||
| `危大方案看板数据工作簿.xlsx` | 双数据源+动态公式+静态汇总(13Sheet) | 每月 |
|
||||
| `危大方案编审进度看板.pptx` | 可编辑PPTX(原生图表/表格/形状) | 每月 |
|
||||
|
||||
## 项目结构
|
||||
|
||||
@ -17,27 +17,32 @@
|
||||
├── .gitignore
|
||||
├── run_all.py ← 一键管线
|
||||
├── src/
|
||||
│ ├── b1_methods.py ← 技术方案统计表清洗
|
||||
│ ├── b1_methods.py ← 技术方案统计表清洗(→ methods_cleaned.csv)
|
||||
│ ├── b2_tracking.py ← 项目启动动态跟踪
|
||||
│ ├── b3_revenue.py ← 营业额产值统计
|
||||
│ ├── b4_dashboard_html.py ← 综合看板HTML生成
|
||||
│ ├── b4b_certified_dashboard_2026.py ← 危大方案独立看板
|
||||
│ ├── gen_workbook.py ← 数据透视工作簿
|
||||
│ ├── clean_certified.py ← 年度认定表清洗
|
||||
│ ├── clean_methods.py ← 方案统计表清洗(旧版)
|
||||
│ └── run_methods_2026-06-08.py ← 06-08适配器
|
||||
├── raw/ ← OA原始台账
|
||||
│ ├── b4b_certified_dashboard_2026.py ← 危大方案独立看板HTML
|
||||
│ ├── gen_workbook.py ← 工作簿(数据源+GROUPBY公式+静态汇总)
|
||||
│ ├── gen_pptx.py ← PPTX看板生成
|
||||
│ ├── clean_certified.py ← 年度认定表清洗(→ 认定数据/YYYY/)
|
||||
│ └── clean_methods.py ← 方案统计表清洗(旧版)
|
||||
├── raw/ ← OA原始台账(每月放入)
|
||||
│ └── YYYY-MM-DD/
|
||||
│ ├── 技术方案统计表.xlsx
|
||||
│ ├── 动态跟踪表_REPORT3.xlsx
|
||||
│ └── 2026年XX月项目营业额、产值统计表.xls
|
||||
└── data/ ← 清洗后输出
|
||||
└── data/ ← 输出数据
|
||||
├── 认定数据/ ← 年度固定·一年一次
|
||||
│ └── 2026/
|
||||
│ ├── certified_schemes_detail.csv (43行方案级)
|
||||
│ └── certified_schemes.csv (项目级对比)
|
||||
└── YYYY-MM-DD/
|
||||
└── cleaned/
|
||||
├── methods_cleaned.csv (OA登记清洗后)
|
||||
├── methods_cleaned.parquet
|
||||
├── methods_cleaned.csv
|
||||
├── certified_schemes_dashboard.html
|
||||
├── 危大方案看板数据工作簿.xlsx
|
||||
├── 危大方案编审进度看板.pptx
|
||||
└── *_validation.json
|
||||
```
|
||||
|
||||
@ -51,19 +56,20 @@
|
||||
│ 总数 超规16 │ 总数 超规22 │
|
||||
│ 覆盖7项目 │ 登记率121% │
|
||||
├─ 3.按国别 ──────┼─ 4.审批进度&预警 ──┤
|
||||
│ 阿联酋45 ▓▓▓▓ │ 5 🔴0 🟠1 🟡4 │
|
||||
│ 阿联酋45 ▓▓▓▓ │ 5 🟠1 🟡4 │
|
||||
│ 沙特 6 ▓ │ 23 未完成审批 │
|
||||
│ 卡塔尔 1 ▏ │ 56% 审批完成率 │
|
||||
└─────────────────┴──────────────────┘
|
||||
```
|
||||
|
||||
- **年度认定**:依据中港科技便〔2026〕6号,统计口径 ≥2026年开工
|
||||
- **年度认定**:中港科技便〔2026〕6号,统计口径 ≥2026年开工
|
||||
- **OA登记**:OA技术方案统计表,排除已作废
|
||||
- **预警**:🟠≤30天未审批 · 🟡≤45天 · 🔴在实施未审批
|
||||
- **预警**:🟠 ≤30天未审批 · 🟡 ≤45天 · 🔴 在实施未审批(本月0项)
|
||||
- **登记率**:121% = OA登记52 / 认定43
|
||||
|
||||
### 页面2:预警明细
|
||||
|
||||
5项预警方案清单,含项目全称、方案名称、距开工天数。
|
||||
5项预警方案清单,含项目全称、方案名称、当前状态、计划开工日期、距开工天数。
|
||||
|
||||
## 使用方式
|
||||
|
||||
@ -74,27 +80,41 @@ cp *.xlsx raw/YYYY-MM-DD/
|
||||
# 2. 运行清洗管线
|
||||
python3 run_all.py YYYY-MM-DD
|
||||
|
||||
# 3. 生成工作簿(含数据透视表)
|
||||
# 3. 生成工作簿(含动态公式 + 静态汇总)
|
||||
python3 src/gen_workbook.py
|
||||
|
||||
# 4. 生成PPTX
|
||||
python3 src/gen_pptx.py
|
||||
```
|
||||
|
||||
## 数据工作簿 (Sheet清单)
|
||||
## 数据工作簿 Sheet清单(13个)
|
||||
|
||||
| Sheet | 内容 |
|
||||
|:------|:------|
|
||||
| 清洗后数据 | 52条有效方案全字段 |
|
||||
| 年度认定透视 | 按一般/超规 + 项目明细 |
|
||||
| OA登记透视 | 按分类 + 国别×分类交叉 |
|
||||
| 国别分布 | 阿联酋·沙特·卡塔尔 |
|
||||
| 审批进度 | 完成率+OA状态细分 |
|
||||
| 预警明细 | 6项预警+汇总 |
|
||||
| Sheet | 类型 | 内容 |
|
||||
|:------|:-----|:------|
|
||||
| 清洗后数据 | 数据源 | OA登记·全量有效(135行×30列) |
|
||||
| 有效≥2026 | 数据源 | OA登记·≥2026年开工(52行) |
|
||||
| **认定数据** | 数据源 | **公司认定·43行(中港科技便〔2026〕6号)** |
|
||||
| 认定vsOA | 对比 | 项目级认定vs登记差额(7项·差额高亮) |
|
||||
| 公式-年度认定 | 🔄 GROUPBY | `=GROUPBY(…!K3:K200, …,COUNTA,3,0)` |
|
||||
| 公式-国别分布 | 🔄 GROUPBY | `=GROUPBY(…!C3:C200, …,COUNTA,3,0,-2)` |
|
||||
| 公式-审批进度 | 🔄 COUNTIF | 6项指标(完成/未完成/橙/黄/合计) |
|
||||
| 公式-预警明细 | 🔄 FILTER | `=FILTER(…!A3:AD200, …!AD3:AD200<>"none")` |
|
||||
| 公式-认定分类 | 🔄 GROUPBY | 认定数据分类统计 |
|
||||
| 年度认定汇总 | 📌 静态 | 一般类/超规类(可交叉验证公式) |
|
||||
| 国别×分类 | 📌 静态 | 阿联酋/沙特/卡塔尔×分类交叉 |
|
||||
| 审批进度 | 📌 静态 | 完成率56%·预警明细 |
|
||||
| 预警明细 | 📌 静态 | 5项预警清单 |
|
||||
|
||||
> 🔄 动态公式在WPS新版/Excel 365中打开后自动刷新——源数据更新零Python重跑。
|
||||
|
||||
## 数据来源
|
||||
|
||||
- 技术方案统计表 → 危大方案编审进度
|
||||
- 动态跟踪表_REPORT3 → 项目启动阶段跟踪
|
||||
- 项目营业额、产值统计表 → 营收财务数据
|
||||
- 年度认定 → 中港科技便〔2026〕6号
|
||||
| 数据 | 来源 | 路径 |
|
||||
|:------|:------|:------|
|
||||
| OA登记 | 技术方案统计表 | `raw/YYYY-MM-DD/`(每月更新) |
|
||||
| 年度认定 | 中港科技便〔2026〕6号 | `data/认定数据/2026/`(年度固定) |
|
||||
| 项目启动 | 动态跟踪表_REPORT3 | `raw/YYYY-MM-DD/` |
|
||||
| 营业额 | 项目营业额产值统计表 | `raw/YYYY-MM-DD/` |
|
||||
|
||||
## Gitea
|
||||
|
||||
|
||||
@ -103,9 +103,9 @@ tr:nth-child(even) td{background:var(--bg)}
|
||||
<div class="panel"><div class="panel-head">4. 审批进度 & 三色预警信号</div><div class="panel-body" style="display:flex;flex-direction:column;gap:14px">
|
||||
<!-- Row 1: 预警信号 -->
|
||||
<div style="display:flex;align-items:center;gap:16px">
|
||||
<div class="card"><div class="n" style="color:var(--red);font-size:44px">6</div><div class="l">预警总计</div></div>
|
||||
<div class="card"><div class="n" style="color:var(--red);font-size:44px">5</div><div class="l">预警总计</div></div>
|
||||
<div class="card"><div class="ico" style="font-size:22px;line-height:1">🔴</div><div class="n" style="color:var(--red)">0</div><div class="l">红色</div></div>
|
||||
<div class="card"><div class="ico" style="font-size:22px;line-height:1">🟠</div><div class="n" style="color:var(--red)">2</div><div class="l">橙色</div></div>
|
||||
<div class="card"><div class="ico" style="font-size:22px;line-height:1">🟠</div><div class="n" style="color:var(--red)">1</div><div class="l">橙色</div></div>
|
||||
<div class="card"><div class="ico" style="font-size:22px;line-height:1">🟡</div><div class="n" style="color:var(--gold)">4</div><div class="l">黄色</div></div>
|
||||
<div class="card"><div class="n" style="color:var(--gray);font-size:36px">23</div><div class="l">未完成审批</div></div>
|
||||
<div style="font-size:11px;color:var(--gray);margin-left:auto;text-align:right;line-height:1.6;display:flex;flex-direction:column;gap:4px"><span>🔴 在实施未审批</span><span>🟠 ≤30天</span><span>🟡 ≤45天</span></div>
|
||||
@ -133,10 +133,9 @@ tr:nth-child(even) td{background:var(--bg)}
|
||||
|
||||
<div class="slide">
|
||||
<div class="nav"><span>关键指标</span><span>国别分布</span><span class="cur">预警明细</span></div>
|
||||
<div class="title-area"><div class="line"></div><h1>预警信号明细清单</h1><span class="date">共 6 项预警</span></div>
|
||||
<div class="title-area"><div class="line"></div><h1>预警信号明细清单</h1><span class="date">共 5 项预警</span></div>
|
||||
<div style="margin:0 48px 20px"><div class="panel" style="flex:1"><div class="panel-body" style="padding:0"><table class="main"><tr><th class="main">信号</th><th class="main">类型</th><th class="main">项目名称</th><th class="main">方案名称</th><th class="main">当前状态</th><th class="main" style="text-align:right">计划开工</th><th class="main num">距开工</th></tr>
|
||||
<tr class="warn-row"><td class="wicon">🟠</td><td class="fs">超规类</td><td class="fs">阿联酋迪拜马克图姆国际机场地下结构工程项目</td><td class="fs">BHS处理中心/GSE隧道现浇板专项施工方案(4包)</td><td class="fs">已添加、未实施</td><td class="num">2026-06-10</td><td class="num r">2天</td></tr>
|
||||
<tr><td class="wicon">🟠</td><td class="fs">一般类</td><td class="fs">阿联酋迪拜马克图姆国际机场地下结构工程项目</td><td class="fs">钢筋加工厂桥式起重机安装专项施工方案(2包)</td><td class="fs">已审批、未实施</td><td class="num">2026-06-30</td><td class="num r">22天</td></tr>
|
||||
<tr class="warn-row"><td class="wicon">🟡</td><td class="fs">超规类</td><td class="fs">阿联酋阿布扎比汽车基地房建项目</td><td class="fs">模板支立工程专项方案</td><td class="fs">未审批、未实施</td><td class="num">2026-07-10</td><td class="num r">32天</td></tr>
|
||||
<tr class="warn-row"><td class="wicon">🟡</td><td class="fs">超规类</td><td class="fs">阿联酋阿布扎比汽车基地房建项目</td><td class="fs">深基坑开挖方案</td><td class="fs">未审批、未实施</td><td class="num">2026-07-15</td><td class="num r">37天</td></tr>
|
||||
<tr><td class="wicon">🟡</td><td class="fs">超规类</td><td class="fs">阿联酋迪拜马克图姆国际机场地下结构工程项目</td><td class="fs">处理中心现浇倒T梁专项施工方案(4包)</td><td class="fs">审批中、未实施</td><td class="num">2026-07-20</td><td class="num r">42天</td></tr>
|
||||
|
||||
Binary file not shown.
8
data/认定数据/2026/certified_schemes.csv
Normal file
8
data/认定数据/2026/certified_schemes.csv
Normal file
@ -0,0 +1,8 @@
|
||||
项目名称,认定_危大方案总数,认定_超规数,所属国别,平台_匹配项目,平台_方案总数,平台_超规数,差额,匹配状态
|
||||
沙特利雅得德拉伊耶门二期多功能场馆及办公楼房建项目,5,2,沙特,沙特利雅得德拉伊耶门二期多功能场馆及办公楼房建项目,3,1,-2,✅
|
||||
沙特吉赞基础下游工业城3区1巷独栋别墅一期项目,1,0,沙特,沙特吉赞基础下游工业城3区1巷独栋别墅一期项目,3,2,2,✅
|
||||
沙特达曼港第一和第二集装箱码头升级改造工程项目,1,1,沙特,沙特达曼港第一和第二集装箱码头升级改造工程,3,2,2,✅
|
||||
阿联酋沙迦卡尔巴摩托艇码头项目,2,0,阿联酋,阿联酋沙迦卡尔巴摩托艇港开发项目,3,1,1,✅
|
||||
阿联酋迪拜马克图姆国际机场地下结构工程项目,31,12,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,35,13,4,✅
|
||||
阿联酋阿布扎比哈里发港EGA泊位翻新项目,1,0,阿联酋,阿联酋阿布扎比哈里发港EGA泊位翻新工程项目,1,0,0,✅
|
||||
阿联酋阿布扎比马斯努阿岛水工项目,2,1,阿联酋,阿联酋阿布扎比马斯努阿岛水工项目,0,0,-2,✅
|
||||
|
44
data/认定数据/2026/certified_schemes_detail.csv
Normal file
44
data/认定数据/2026/certified_schemes_detail.csv
Normal file
@ -0,0 +1,44 @@
|
||||
所属区域,所属国别,项目名称,方案名称,编制单位,工程类别,分部工程类别,是否超一定规模,计划开工日期
|
||||
中东,沙特,沙特利雅得德拉伊耶门二期多功能场馆及办公楼房建项目,预制看台安装方案,中交第二公路工程局有限公司,房屋建设和市政基础设施工程,起重吊装及起重机械安装拆卸工程,否,2026-07-01
|
||||
中东,沙特,沙特利雅得德拉伊耶门二期多功能场馆及办公楼房建项目,钢结构施工方案,中建钢构承包有限公司,房屋建设和市政基础设施工程,起重吊装及起重机械安装拆卸工程,是,2026-05-23
|
||||
中东,沙特,沙特利雅得德拉伊耶门二期多功能场馆及办公楼房建项目,幕墙施工方案,中建装饰绿创科技有限公司,房屋建设和市政基础设施工程,其它,否,2026-08-22
|
||||
中东,沙特,沙特利雅得德拉伊耶门二期多功能场馆及办公楼房建项目,高支模专项施工方案,中交第二公路工程局有限公司,房屋建设和市政基础设施工程,模板工程及支撑体系,是,2026-03-20
|
||||
中东,沙特,沙特利雅得德拉伊耶门二期多功能场馆及办公楼房建项目,650t履带吊安拆施工方案,中建钢构承包有限公司,房屋建设和市政基础设施工程,起重吊装及起重机械安装拆卸工程,否,2026-07-25
|
||||
中东,沙特,沙特吉赞基础下游工业城3区1巷独栋别墅一期项目,别墅主体结构安装专项施工方案,中交四航局二公司,房屋建设和市政基础设施工程,起重吊装及起重机械安装拆卸工程,否,2026-04-01
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,处理中心专项施工方案(4包),中交四航局二公司(4包),民航工程,模板工程及支撑体系,否,2026-03-10
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,GSE&BHS隧道施工专项施工方案(4包),中交四航局二公司(4包),民航工程,模板工程及支撑体系,否,2026-03-28
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,T梁预制、运输和安装专项施工方案(4包),中交四航局二公司(4包),民航工程,起重吊装及安装拆卸工程,否,2026-05-13
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,临时用电施工组织设计(4包),中交四航局二公司(4包),电力工程,其他,否,2026-02-28
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,BHS处理中心/GSE隧道现浇板专项施工方案(4包),中交四航局二公司(4包),民航工程,模板工程及支撑体系,是,2026-05-15
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,处理中心现浇倒T梁专项施工方案(4包),中交四航局二公司(4包),民航工程,模板工程及支撑体系,是,2026-04-15
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,塔吊施工监管方案(4包),中交四航局二公司(4包),民航工程,起重吊装及安装拆卸工程,否,2026-03-25
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,龙门吊施工监管方案(4包),中交四航局二公司(4包),民航工程,起重吊装及安装拆卸工程,是,2026-03-20
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,混凝土拌和站施工监管方案(4包),中交四航局二公司(4包),民航工程,起重吊装及安装拆卸工程,否,2026-03-18
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,履带吊安装和拆卸专项施工方案(4包),中交四航局二公司(4包),民航工程,起重吊装及安装拆卸工程,是,2026-03-25
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,APM隧道现浇段顶板模板及支撑体系专项施工方案(2包),中交一航局三公司(2包),民航工程,模板工程和支撑体系,是,2026-11-20
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,GSE隧道现浇段顶板模板及支撑体系专项施工方案(2包),中交一航局三公司(2包),民航工程,模板工程和支撑体系,是,2026-04-20
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,APM隧道预制梁安装专项施工方案(2包),中交一航局三公司(2包),民航工程,起重吊装及安装拆卸工程,否,2026-11-15
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,GSE隧道预制梁安装专项施工方案(2包),中交一航局三公司(2包),民航工程,起重吊装及安装拆卸工程,否,2026-04-30
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,混凝土拌合站钢结构料仓大棚安装专项施工方案(2包),中交一航局三公司(2包),民航工程,起重吊装及安装拆卸工程,否,2026-03-25
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,钢筋加工厂钢结构大棚专项施工方案(2包),中交一航局三公司(2包),民航工程,起重吊装及安装拆卸工程,否,2026-03-25
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,预制场龙门吊安装专项施工方案,中交一航局三公司(2包),民航工程,起重吊装及安装拆卸工程,是,2026.3.25
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,预制场龙门吊拆卸专项施工方案,中交一航局三公司(2包),民航工程,起重吊装及安装拆卸工程,否,2027-06-25
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,履带吊安装专项施工方案,中交一航局三公司(2包),民航工程,起重吊装及安装拆卸工程,是,2026-04-20
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,履带吊拆除专项施工方案,中交一航局三公司(2包),民航工程,起重吊装及安装拆卸工程,否,2027-06-25
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,临时用电施工组织设计(2包),中交一航局三公司(2包),电力工程,电力通用_其他,否,2026-03-10
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,隧道顶板专项施工方案(3包),中交二航局一公司(3包),民航工程,模板工程及支撑体系,是,2026-04-25
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,预制构件安装专项施工方案(3包),中交二航局一公司(3包),民航工程,起重吊装及安装拆卸工程,是,2026-04-30
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,搅拌站建设专项施工方案(3包),中交二航局一公司(3包),民航工程,起重吊装及安装拆卸工程,否,2026-03-10
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,场站建设施工方案(3包),中交二航局一公司(3包),民航工程,起重吊装及安装拆卸工程,否,2026-03-10
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,塔吊安装专项施工方案(3包),中交二航局一公司(3包),民航工程,起重吊装及安装拆卸工程,否,2026-03-10
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,塔吊拆除专项施工方案(3包),中交二航局一公司(3包),民航工程,起重吊装及安装拆卸工程,否,2027-06-15
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,门机安装专项施工方案(3包),中交二航局一公司(3包),民航工程,起重吊装及安装拆卸工程,是,2026-03-10
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,门机拆除专项施工方案(3包),中交二航局一公司(3包),民航工程,起重吊装及安装拆卸工程,否,2027-06-15
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,履带吊安拆专项施工方案(3包),中交二航局一公司(3包),民航工程,起重吊装及安装拆卸工程,是,2026-03-10
|
||||
中东,阿联酋,阿联酋迪拜马克图姆国际机场地下结构工程项目,临时用电专项施工方案(3包),中交二航局一公司(3包),电力工程,电力通用_其他,否,2026-03-10
|
||||
中东,沙特,沙特达曼港第一和第二集装箱码头升级改造工程项目,厂棚D钢结构安装专项施工方案,中交二航局一公司,房屋建设和市政基础设施工程,其它,是,2026-03-05
|
||||
中东,阿联酋,阿联酋阿布扎比马斯努阿岛水工项目,钢管桩打设专项施工方案,中交一航局三公司,水运工程,桥涵工程,否,2026-09-10
|
||||
中东,阿联酋,阿联酋阿布扎比马斯努阿岛水工项目,方块吊装专项施工方案,中交一航局三公司,水运工程,起重吊装工程,是,2026-06-01
|
||||
中东,阿联酋,阿联酋沙迦卡尔巴摩托艇码头项目,卡尔巴钢板桩围堰专项施工方案,中交一航局三公司,水运工程,大型临时工程,否,2026-05-01
|
||||
中东,阿联酋,阿联酋沙迦卡尔巴摩托艇码头项目,卡尔巴方块安装起重吊装专项施工方案,中交一航局三公司,水运工程,起重吊装工程,否,2026-08-15
|
||||
中东,阿联酋,阿联酋阿布扎比哈里发港EGA泊位翻新项目,临时用电施工组织设计,中交一航局三公司(2包),水运工程,临时用电工程,否,2026-02-20
|
||||
|
@ -16,7 +16,7 @@ import difflib
|
||||
# ============================================================
|
||||
RAW_DIR = Path("/mnt/y/WorkingEmail/OA收文_Incoming")
|
||||
CERT_SRC_DIR = RAW_DIR / "2026-03-16_关于公布公司2026年度技术方案编制计划的通知"
|
||||
OUT_DIR = CERT_SRC_DIR / "cleaned"
|
||||
OUT_DIR = Path("/mnt/y/Openclaw_Hub/03.资源/实施项目 wiki/dashboard/data/认定数据/2026") # 年度固定输出
|
||||
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
CERT_FILES = [
|
||||
|
||||
@ -1,161 +1,226 @@
|
||||
#!/usr/bin/env python3
|
||||
"""危大方案看板数据工作簿 v3 — 数据源完整镜像源表结构 + 汇总表"""
|
||||
"""危大方案看板数据工作簿 v5 — 双数据源(OA登记+公司认定) + GROUPBY/FILTER动态公式"""
|
||||
import pandas as pd
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
|
||||
from openpyxl.utils import get_column_letter
|
||||
|
||||
BASE = "/mnt/y/Openclaw_Hub/03.资源/实施项目 wiki/dashboard/data/2026-06-08"
|
||||
CERT_DIR = "/mnt/y/Openclaw_Hub/03.资源/实施项目 wiki/dashboard/data/认定数据/2026" # 年度固定目录·一年一次
|
||||
OUT = f"{BASE}/cleaned/危大方案看板数据工作簿.xlsx"
|
||||
REPORT_DATE = "2026-06-08"
|
||||
REF = "'有效≥2026'" # OA公式引用
|
||||
CREF = "'认定数据'" # 认定公式引用
|
||||
|
||||
# ── Read raw source ──
|
||||
raw = pd.read_excel("/mnt/y/Openclaw_Hub/03.资源/实施项目 wiki/dashboard/raw/2026-06-08/技术方案统计表.xlsx", header=1)
|
||||
raw.columns = [str(c).strip() for c in raw.columns]
|
||||
print(f"Source rows: {len(raw)}, cols: {list(raw.columns)[:5]}...")
|
||||
# ════ 数据源1: OA登记(methods_cleaned.csv) ════
|
||||
df = pd.read_csv(f"{BASE}/cleaned/methods_cleaned.csv")
|
||||
SRC_COLS = list(df.columns[:24])
|
||||
valid_all = df[df['是否有效登记'] == True].copy()
|
||||
valid_2026 = valid_all[valid_all['开工年份'] >= 2026].copy()
|
||||
m = valid_2026
|
||||
tot = len(m); gen = (m['是否超一定规模']!='是').sum(); sup = tot-gen
|
||||
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}黄")
|
||||
|
||||
# ── Read cleaned data for filtering ──
|
||||
cl = pd.read_parquet(f"{BASE}/cleaned/methods_cleaned.parquet")
|
||||
valid_idx = cl[cl['是否有效登记'] == True].index.tolist()
|
||||
cl['开工年份'] = pd.to_datetime(cl['分部分项工程计划开工日期'], errors='coerce').dt.year
|
||||
yr_idx = cl[(cl['是否有效登记'] == True) & (cl['开工年份'] >= 2026)].index.tolist()
|
||||
# ════ 数据源2: 公司认定(certified_schemes_detail.csv) ════
|
||||
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")
|
||||
print(f"公司认定: {cert_tot}项(一般{cert_gen}/超规{cert_sup}) 项目{cert_comp['项目名称'].nunique()}")
|
||||
|
||||
# Merge back to raw columns (align by index)
|
||||
raw_clean = raw.loc[raw.index.isin(valid_idx)].copy()
|
||||
raw_2026 = raw.loc[raw.index.isin(yr_idx)].copy()
|
||||
# ════ 样式 ════
|
||||
HDR_F=Font(name='微软雅黑',bold=True,size=10,color='FFFFFF'); HDR_BG=PatternFill('solid',fgColor='1A3A5C')
|
||||
TITLE_F=Font(name='微软雅黑',bold=True,size=14,color='1A3A5C'); DATA_F=Font(name='微软雅黑',size=10)
|
||||
BOLD_F=Font(name='微软雅黑',bold=True,size=10); GRAY_F=Font(name='微软雅黑',size=9,color='8899AA')
|
||||
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')
|
||||
WARN_BG=PatternFill('solid',fgColor='FFF3E0'); INFO_BG=PatternFill('solid',fgColor='F0F4FA')
|
||||
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'))
|
||||
|
||||
print(f"Valid rows: {len(raw_clean)}, >=2026: {len(raw_2026)}")
|
||||
def hdr_row(ws,r,cols):
|
||||
for i,h in enumerate(cols):
|
||||
c=ws.cell(r,i+1,h); c.font=HDR_F; c.fill=HDR_BG; c.border=BORDER; c.alignment=CENTER
|
||||
|
||||
# ── For summary sheets, use cleaned data ──
|
||||
m = cl[(cl['是否有效登记'] == True) & (cl['开工年份'] >= 2026)].copy()
|
||||
m['简化状态'] = m['方案状态_clean'].apply(lambda s: '已完成' if '已完成' in str(s) else '未完成')
|
||||
m['是否超规'] = m['是否超一定规模'].astype(str).apply(lambda x: '超规类' if x == '是' else '一般类')
|
||||
today = pd.Timestamp('2026-06-08')
|
||||
m['距开工天'] = (pd.to_datetime(m['分部分项工程计划开工日期']) - today).dt.days.astype(int)
|
||||
def write_data_sheet(ws,df_out,title,cols):
|
||||
ncol=len(cols)
|
||||
ws.merge_cells(start_row=1,start_column=1,end_row=1,end_column=ncol)
|
||||
ws.cell(1,1,title).font=TITLE_F; ws.cell(1,1).border=GOLD_BD
|
||||
hdr_row(ws,3,cols)
|
||||
for ri,(_,row) in enumerate(df_out.iterrows()):
|
||||
rr=ri+4
|
||||
for ci,col in enumerate(cols):
|
||||
v=row.get(col,'')
|
||||
if pd.isna(v): v=''
|
||||
elif isinstance(v,(pd.Timestamp,)): v=str(v)[:10]
|
||||
elif isinstance(v,(float,)) and v==int(v): v=int(v)
|
||||
ws.cell(rr,ci+1,v).font=DATA_F; ws.cell(rr,ci+1,v).border=BORDER
|
||||
ws.auto_filter.ref=f'A3:{get_column_letter(ncol)}{len(df_out)+3}'
|
||||
ws.freeze_panes='A4'
|
||||
for i,col in enumerate(cols):
|
||||
ws.column_dimensions[get_column_letter(i+1)].width=max(10,min(40,len(str(col))*2.2))
|
||||
|
||||
# Warning
|
||||
def warn_lev(d, s):
|
||||
s = str(s); d = int(d)
|
||||
if '未实施' not in s and '审批中' not in s: return ''
|
||||
if d <= 30: return '🟠'
|
||||
if d <= 45: return '🟡'
|
||||
return ''
|
||||
m['预警'] = m.apply(lambda r: warn_lev(r['距开工天'], r['方案状态_clean']), axis=1)
|
||||
|
||||
# ── Styles ──
|
||||
HDR_F = Font(name='微软雅黑', bold=True, size=10, color='FFFFFF')
|
||||
HDR_BG = PatternFill('solid', fgColor='1A3A5C')
|
||||
TITLE_F = Font(name='微软雅黑', bold=True, size=14, color='1A3A5C')
|
||||
SUB_F = Font(name='微软雅黑', bold=True, size=12, color='1A3A5C')
|
||||
GRAY_F = Font(name='微软雅黑', size=9, color='8899AA')
|
||||
DATA_F = Font(name='微软雅黑', size=10)
|
||||
BOLD_F = Font(name='微软雅黑', bold=True, size=10)
|
||||
RED_F = Font(name='微软雅黑', bold=True, size=10, color='D94E34')
|
||||
GREEN_F = Font(name='微软雅黑', bold=True, size=10, color='2E7D32')
|
||||
BLUE_F = Font(name='微软雅黑', bold=True, size=10, color='1A3A5C')
|
||||
WARN_BG = PatternFill('solid', fgColor='FFF3E0')
|
||||
BORDER = Border(left=Side('thin', 'DBE2EA'), right=Side('thin', 'DBE2EA'),
|
||||
top=Side('thin', 'DBE2EA'), bottom=Side('thin', 'DBE2EA'))
|
||||
CENTER = Alignment(horizontal='center', vertical='center')
|
||||
GOLD_BD = Border(bottom=Side(style='medium', color='C8962E'))
|
||||
|
||||
def hdr_row(ws, r, cols):
|
||||
for i, h in enumerate(cols):
|
||||
c = ws.cell(r, i+1, h); c.font = HDR_F; c.fill = HDR_BG; c.border = BORDER; c.alignment = CENTER
|
||||
|
||||
def write_data_sheet(ws, df, title):
|
||||
"""Write a full data sheet from dataframe"""
|
||||
ws.merge_cells(start_row=1, start_column=1, end_row=1, end_column=len(df.columns))
|
||||
ws.cell(1, 1, title).font = TITLE_F
|
||||
ws.cell(1, 1).border = GOLD_BD
|
||||
|
||||
cols = list(df.columns)
|
||||
hdr_row(ws, 3, cols)
|
||||
for r, (_, row) in enumerate(df.iterrows()):
|
||||
for c, col in enumerate(cols):
|
||||
v = row[col]
|
||||
if pd.isna(v): v = ''
|
||||
elif isinstance(v, (pd.Timestamp,)): v = str(v)[:10]
|
||||
cell = ws.cell(r+4, c+1, v); cell.font = DATA_F; cell.border = BORDER
|
||||
ws.auto_filter.ref = f'A3:{get_column_letter(len(cols))}{len(df)+3}'
|
||||
ws.freeze_panes = 'A4'
|
||||
for i in range(len(cols)):
|
||||
ws.column_dimensions[get_column_letter(i+1)].width = max(12, min(35, len(str(cols[i]))*2))
|
||||
def write_formula_sheet(ws,title,subtitle,formulas,col_widths):
|
||||
ws.merge_cells(start_row=1,start_column=1,end_row=1,end_column=4)
|
||||
ws.cell(1,1,title).font=TITLE_F; ws.cell(1,1).border=GOLD_BD
|
||||
if subtitle:
|
||||
ws.merge_cells(start_row=2,start_column=1,end_row=2,end_column=4)
|
||||
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
|
||||
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()
|
||||
|
||||
# ════ Sheet 1: 源表清洗后(完整列) ════
|
||||
s1 = wb.active; s1.title = '源表清洗后'
|
||||
write_data_sheet(s1, raw_clean, '技术方案统计表 · 清洗后(有效登记 全部年份)')
|
||||
# ════════ S1: OA清洗后数据 ════════
|
||||
s1=wb.active; s1.title='清洗后数据'
|
||||
write_data_sheet(s1,valid_all.reset_index(drop=True),
|
||||
f'OA登记·清洗后数据(有效登记·全部年份·{len(valid_all)}行)',
|
||||
SRC_COLS+['方案状态_clean','是否完成审批','是否有效登记','开工年份','开工月份','预警信号'])
|
||||
|
||||
# ════ Sheet 2: 有效2026+ ════
|
||||
s2 = wb.create_sheet('有效≥2026')
|
||||
write_data_sheet(s2, raw_2026, '技术方案统计表 · 有效登记 ≥2026年开工')
|
||||
# ════════ 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','是否完成审批','是否有效登记','开工年份','开工月份','预警信号'])
|
||||
|
||||
# ════ Sheet 3: 年度认定汇总 ════
|
||||
s3 = wb.create_sheet('年度认定汇总')
|
||||
s3.merge_cells('A1:D1'); s3.cell(1, 1, '年度认定(≥2026开工)').font = TITLE_F; s3.cell(1, 1).border = GOLD_BD
|
||||
hdr_row(s3, 3, ['分类', '方案数', '项目数', '占比'])
|
||||
tot = len(m)
|
||||
for r, (cat, sub) in enumerate([('一般类', m[m['是否超规'] == '一般类']), ('超规类', m[m['是否超规'] == '超规类'])]):
|
||||
cnt = len(sub); proj = sub['项目名称'].nunique()
|
||||
for c, (v, f) in enumerate(zip([cat, cnt, proj, f'{cnt/tot*100:.0f}%'], [DATA_F, DATA_F, DATA_F, DATA_F])):
|
||||
cell = s3.cell(r+4, c+1, v); cell.font = f; cell.border = BORDER
|
||||
for c, (v, f) in enumerate(zip(['合计', tot, m['项目名称'].nunique(), '100%'], [BOLD_F]*4)):
|
||||
cell = s3.cell(6, c+1, v); cell.font = f; cell.border = BORDER
|
||||
for w, c in zip([12, 10, 10, 10], 'ABCD'): s3.column_dimensions[c].width = w
|
||||
# ════════ 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)
|
||||
|
||||
# ════ Sheet 4: 国别×分类 ════
|
||||
s4 = wb.create_sheet('国别×分类')
|
||||
s4.merge_cells('A1:D1'); s4.cell(1, 1, '国别×分类分布').font = TITLE_F; s4.cell(1, 1).border = GOLD_BD
|
||||
ct = m.groupby(['所属国别', '是否超规']).size().unstack(fill_value=0)
|
||||
ct['合计'] = ct.sum(1); ct.loc['合计'] = ct.sum()
|
||||
hdr_row(s4, 3, ['国别'] + list(ct.columns))
|
||||
for r, (idx, row) in enumerate(ct.iterrows()):
|
||||
for c, v in enumerate([idx] + [int(x) for x in row]):
|
||||
cell = s4.cell(r+4, c+1, v); cell.font = DATA_F; cell.border = BORDER
|
||||
s4.column_dimensions['A'].width = 25
|
||||
# ════════ S4: 认定vsOA ════════
|
||||
s4=wb.create_sheet('认定vsOA')
|
||||
COMP_COLS=['项目名称','认定_危大方案总数','认定_超规数','所属国别','平台_方案总数','平台_超规数','差额','匹配状态']
|
||||
ncol_c=len(COMP_COLS)
|
||||
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})').font=TITLE_F; s4.cell(1,1).border=GOLD_BD
|
||||
hdr_row(s4,3,COMP_COLS)
|
||||
for ri,(_,row) in enumerate(cert_comp.iterrows()):
|
||||
for ci,col in enumerate(COMP_COLS):
|
||||
v=row[col]
|
||||
if pd.isna(v): v=''
|
||||
cell=s4.cell(ri+4,ci+1,v); cell.font=DATA_F; cell.border=BORDER
|
||||
if col=='差额' and isinstance(v,(int,float)) and v!=0:
|
||||
cell.font=RED_F if v<0 else GREEN_F
|
||||
if col=='匹配状态': cell.font=GREEN_F if '✅' in str(v) else DATA_F
|
||||
s4.auto_filter.ref=f'A3:{get_column_letter(ncol_c)}{len(cert_comp)+3}'
|
||||
for i,col in enumerate(COMP_COLS):
|
||||
s4.column_dimensions[get_column_letter(i+1)].width=max(14,min(45,len(str(col))*2.5))
|
||||
|
||||
# ════ Sheet 5: 审批进度 & 预警 ════
|
||||
s5 = wb.create_sheet('审批进度')
|
||||
s5.merge_cells('A1:D1'); s5.cell(1, 1, '审批进度 & 三色预警').font = TITLE_F; s5.cell(1, 1).border = GOLD_BD
|
||||
hdr_row(s5, 3, ['指标', '数值', '占比', '备注'])
|
||||
completed = (m['简化状态'] == '已完成').sum(); unfinished = tot - completed
|
||||
rn = (m['预警'] != '').sum(); orn = (m['预警'] == '🟠').sum(); ye = (m['预警'] == '🟡').sum()
|
||||
rows = [
|
||||
('方案总数', tot, '100%', '≥2026年开工·排除已作废'),
|
||||
('已完成审批', completed, f'{completed/tot*100:.0f}%', ''),
|
||||
('未完成审批', unfinished, f'{unfinished/tot*100:.0f}%', '含审批中+未审批'),
|
||||
('🟠 橙色预警', orn, f'{orn/tot*100:.0f}%', '≤30天未审批'),
|
||||
('🟡 黄色预警', ye, f'{ye/tot*100:.0f}%', '≤45天未审批'),
|
||||
('预警合计', rn, f'{rn/tot*100:.0f}%', f'🟠{orn}项+🟡{ye}项'),
|
||||
]
|
||||
for r, (lab, val, pct, note) in enumerate(rows):
|
||||
fmts = [DATA_F, DATA_F, DATA_F, GRAY_F]
|
||||
if '完成' in lab and '未' not in lab: fmts = [GREEN_F, BOLD_F, BOLD_F, GRAY_F]
|
||||
if '预警' in lab: fmts = [RED_F, BOLD_F, BOLD_F, GRAY_F]
|
||||
if '总数' in lab: fmts = [BLUE_F, BOLD_F, BOLD_F, GRAY_F]
|
||||
for c, (v, f) in enumerate(zip([lab, val, pct, note], fmts)):
|
||||
cell = s5.cell(r+4, c+1, v); cell.font = f; cell.border = BORDER
|
||||
for w, c in zip([18, 10, 10, 35], 'ABCD'): s5.column_dimensions[c].width = w
|
||||
# ════════ S5-S8: 动态公式 ════════
|
||||
|
||||
# ════ Sheet 6: 预警明细 ════
|
||||
s6 = wb.create_sheet('预警明细')
|
||||
s6.merge_cells('A1:G1'); s6.cell(1, 1, f'三色预警明细(共{rn}项)').font = TITLE_F; s6.cell(1, 1).border = GOLD_BD
|
||||
hdr_row(s6, 3, ['信号', '类型', '项目名称', '方案名称', '状态', '计划开工', '距开工'])
|
||||
warned = m[m['预警'] != ''].sort_values('距开工天')
|
||||
for r, (_, row) in enumerate(warned.iterrows()):
|
||||
is_w = '未审批' in str(row['方案状态_clean'])
|
||||
bg = WARN_BG if is_w else None
|
||||
vals = [row['预警'], row['是否超规'], row['项目名称'], row['方案名称'],
|
||||
row['方案状态_clean'], str(row['分部分项工程计划开工日期'])[:10], f"{int(row['距开工天'])}天"]
|
||||
for c, v in enumerate(vals):
|
||||
cell = s6.cell(r+4, c+1, v); cell.font = RED_F if c == 6 else DATA_F; cell.border = BORDER
|
||||
if bg: cell.fill = bg
|
||||
s6.auto_filter.ref = f'A3:G{len(warned)+3}'
|
||||
for w, c in zip([6, 8, 40, 35, 18, 12, 8], 'ABCDEFG'): s6.column_dimensions[c].width = w
|
||||
# ── S5: 公式-年度认定 ──
|
||||
s5=wb.create_sheet('公式-年度认定')
|
||||
write_formula_sheet(s5,f'OA年度认定(≥2026开工)',
|
||||
f'GROUPBY({REF}!K3:K200,{REF}!A3:A200,COUNTA,3,0)',
|
||||
[('A',4,f'=GROUPBY({REF}!K3:K200,{REF}!A3:A200,COUNTA,3,0)','')],[('A',18),('B',12)])
|
||||
|
||||
# ── S6: 公式-国别分布 ──
|
||||
s6=wb.create_sheet('公式-国别分布')
|
||||
write_formula_sheet(s6,f'OA国别×分类(自动排序)',
|
||||
f'GROUPBY({REF}!C3:C200,{REF}!A3:A200,COUNTA,3,0,-2)',
|
||||
[('A',4,f'=GROUPBY({REF}!C3:C200,{REF}!A3:A200,COUNTA,3,0,-2)','')],[('A',30),('B',12)])
|
||||
|
||||
# ── S7: 公式-审批进度 ──
|
||||
s7=wb.create_sheet('公式-审批进度')
|
||||
write_formula_sheet(s7,f'OA审批进度 & 预警',
|
||||
f'引用 {REF}!Z:Z + AD:AD',
|
||||
[('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)',''),
|
||||
('A',7,'橙色预警',''),('B',7,f'=COUNTIF({REF}!AD4:AD200,"orange")',''),
|
||||
('A',8,'黄色预警',''),('B',8,f'=COUNTIF({REF}!AD4:AD200,"yellow")',''),
|
||||
('A',9,'预警合计',''),('B',9,'=B7+B8','')],[('A',20),('B',14)])
|
||||
|
||||
# ── S8: 公式-预警明细 ──
|
||||
s8=wb.create_sheet('公式-预警明细')
|
||||
write_formula_sheet(s8,f'OA预警明细(FILTER)',
|
||||
f'FILTER({REF}!A3:AD200,{REF}!AD3:AD200<>"none","无预警")',
|
||||
[('A',4,f'=FILTER({REF}!A3:AD200,{REF}!AD3:AD200<>"none","🎉 无预警项")','')],[('A',22)])
|
||||
|
||||
# ── S9: 公式-认定分类 ──
|
||||
s9=wb.create_sheet('公式-认定分类')
|
||||
write_formula_sheet(s9,f'公司认定方案分类(GROUPBY·{cert_tot}项)',
|
||||
f'GROUPBY({CREF}!H3:H200,{CREF}!D3:D200,COUNTA,3,0)',
|
||||
[('A',4,f'=GROUPBY({CREF}!H3:H200,{CREF}!D3:D200,COUNTA,3,0)','')],[('A',20),('B',12)])
|
||||
|
||||
# ════════ S10-S13: 静态汇总表(可交叉验证) ════════
|
||||
|
||||
# ── S10: 年度认定汇总 ──
|
||||
s10=wb.create_sheet('年度认定汇总')
|
||||
s10.merge_cells('A1:E1'); s10.cell(1,1,f'OA年度认定(≥2026·静态)').font=TITLE_F; s10.cell(1,1).border=GOLD_BD
|
||||
hdr_row(s10,3,['分类','方案数','项目数','占比','备注'])
|
||||
for r,(lab,val,proj,pct,note) in enumerate([
|
||||
('一般类',gen,valid_2026[valid_2026['是否超一定规模']!='是']['项目名称'].nunique(),f'{gen/tot*100:.0f}%','非超一定规模'),
|
||||
('超规类',sup,valid_2026[valid_2026['是否超一定规模']=='是']['项目名称'].nunique(),f'{sup/tot*100:.0f}%','超一定规模'),
|
||||
('合计',tot,projects,'100%',f'涵盖{len(countries)}国')]):
|
||||
fmts=[BOLD_F if '合计' in lab else DATA_F]*5
|
||||
for c,(v,f) in enumerate(zip([lab,val,proj,pct,note],fmts)):
|
||||
cell=s10.cell(r+4,c+1,v); cell.font=f; cell.border=BORDER; cell.alignment=CENTER
|
||||
for w,col in zip([12,10,10,10,20],'ABCDE'): s10.column_dimensions[col].width=w
|
||||
|
||||
# ── S11: 国别×分类 ──
|
||||
s11=wb.create_sheet('国别×分类')
|
||||
s11.merge_cells('A1:D1'); s11.cell(1,1,'OA国别×分类·静态').font=TITLE_F; s11.cell(1,1).border=GOLD_BD
|
||||
ct=m.groupby(['所属国别','是否超一定规模']).size().unstack(fill_value=0)
|
||||
ct.columns=['一般类' if c=='否' else '超规类' for c in ct.columns]; ct['合计']=ct.sum(1); ct.loc['合计']=ct.sum()
|
||||
hdr_row(s11,3,['国别']+list(ct.columns))
|
||||
for r,(idx,row) in enumerate(ct.iterrows()):
|
||||
for c,v in enumerate([idx]+[int(x) for x in row]):
|
||||
cell=s11.cell(r+4,c+1,v); cell.font=BOLD_F if '合计' in str(idx) else DATA_F; cell.border=BORDER; cell.alignment=CENTER
|
||||
s11.column_dimensions['A'].width=25
|
||||
|
||||
# ── S12: 审批进度 ──
|
||||
s12=wb.create_sheet('审批进度')
|
||||
s12.merge_cells('A1:D1'); s12.cell(1,1,f'OA审批进度·静态({REPORT_DATE})').font=TITLE_F; s12.cell(1,1).border=GOLD_BD
|
||||
hdr_row(s12,3,['指标','数值','占比','备注'])
|
||||
for r,(lab,val,pct,note,fmts) in enumerate([
|
||||
('方案总数',tot,'100%','≥2026年开工',[BLUE_F]*3+[GRAY_F]),
|
||||
('已完成审批',int(completed),f'{completed/tot*100:.0f}%','含"已完成"',[GREEN_F]*3+[GRAY_F]),
|
||||
('未完成审批',int(unfinished),f'{unfinished/tot*100:.0f}%','审批中+未审批',[DATA_F]*3+[GRAY_F]),
|
||||
('🟠 橙色预警',int(orange),f'{orange/tot*100:.0f}%','≤30天',[ORANGE_F]*3+[GRAY_F]),
|
||||
('🟡 黄色预警',int(yellow),f'{yellow/tot*100:.0f}%','≤45天',[Font(name='微软雅黑',bold=True,size=10,color='F9A825')]*3+[GRAY_F]),
|
||||
('预警合计',int(warn_total),f'{warn_total/tot*100:.0f}%',f'🟠{orange}+🟡{yellow}',[RED_F]*3+[GRAY_F])]):
|
||||
for c,(v,f) in enumerate(zip([lab,val,pct,note],fmts)):
|
||||
cell=s12.cell(r+4,c+1,v); cell.font=f; cell.border=BORDER; cell.alignment=CENTER
|
||||
for w,col in zip([18,10,10,35],'ABCD'): s12.column_dimensions[col].width=w
|
||||
|
||||
# ── S13: 预警明细 ──
|
||||
s13=wb.create_sheet('预警明细')
|
||||
s13.merge_cells('A1:H1'); s13.cell(1,1,f'OA预警明细·静态(共{warn_total}项)').font=TITLE_F; s13.cell(1,1).border=GOLD_BD
|
||||
hdr_row(s13,3,['信号','距开工','项目名称','方案名称','方案状态','计划开工','超规/一般','国别'])
|
||||
today=pd.Timestamp(REPORT_DATE)
|
||||
for r,(_,row) in enumerate(warn_df.iterrows()):
|
||||
days=(pd.to_datetime(row['分部分项工程计划开工日期'])-today).days
|
||||
vals=[{'orange':'🟠','yellow':'🟡','red':'🔴'}.get(row['预警信号'],''),f'{int(days)}天',
|
||||
row['项目名称'],row['方案名称'],
|
||||
row['方案状态_clean'] if pd.notna(row.get('方案状态_clean')) else row['方案状态'],
|
||||
str(row['分部分项工程计划开工日期'])[:10],
|
||||
'超规类' if row['是否超一定规模']=='是' else '一般类',row['所属国别']]
|
||||
for c,v in enumerate(vals):
|
||||
cell=s13.cell(r+4,c+1,v); cell.font=RED_F if c==1 and days<=3 else DATA_F; cell.border=BORDER; cell.fill=WARN_BG
|
||||
s13.auto_filter.ref=f'A3:H{warn_total+3}'
|
||||
for w,col in zip([6,8,40,35,18,12,10,20],'ABCDEFGH'): s13.column_dimensions[col].width=w
|
||||
|
||||
wb.save(OUT)
|
||||
print(f"✅ {OUT}")
|
||||
print(f" Sheet1: 源表清洗后 ({len(raw_clean)}行 × {len(raw_clean.columns)}列)")
|
||||
print(f" Sheet2: 有效≥2026 ({len(raw_2026)}行)")
|
||||
print(f" Sheet3-6: 汇总表 + 预警明细")
|
||||
print(f"\n✅ {OUT}")
|
||||
print(f" S1-S2 OA登记: {len(valid_all)}全量 + {len(valid_2026)}≥2026")
|
||||
print(f" S3 公司认定: {cert_tot}行({cert_gen}一般+{cert_sup}超规)")
|
||||
print(f" S4 认定vsOA: {len(cert_comp)}项目")
|
||||
print(f" S5-S9 GROUPBY/FILTER 动态公式")
|
||||
print(f" S10-S13 静态汇总表(交叉验证)")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user