160 lines
7.5 KiB
Python
160 lines
7.5 KiB
Python
#!/usr/bin/env python3
|
||
"""危大方案独立看板 - 2026开工版 · 简化状态"""
|
||
import pandas as pd, warnings, json
|
||
from pathlib import Path
|
||
warnings.filterwarnings('ignore')
|
||
|
||
DATA_DATE = '2026-06-08'
|
||
BASE = Path(f'/mnt/y/Openclaw_Hub/05_表达Express/专项施工方案数据看板/data/{DATA_DATE}/cleaned')
|
||
|
||
df = pd.read_parquet(BASE / 'methods_cleaned.parquet')
|
||
valid = df[df['是否有效登记'] == True].copy()
|
||
valid['开工年份'] = pd.to_datetime(valid['分部分项工程计划开工日期'], errors='coerce').dt.year
|
||
y2026 = valid[valid['开工年份'] == 2026].copy()
|
||
|
||
def simple_status(s):
|
||
s = str(s)
|
||
if any(kw in s for kw in ['已审批', '已备案']):
|
||
return '已完成'
|
||
return '未完成'
|
||
|
||
y2026['简化状态'] = y2026['方案状态_clean'].apply(simple_status)
|
||
completed = (y2026['简化状态'] == '已完成').sum()
|
||
total = len(y2026)
|
||
oversized = (y2026['是否超一定规模'].astype(str) == '是').sum()
|
||
|
||
# By country
|
||
country_stats = y2026.groupby('所属国别').agg(
|
||
项目数=('项目名称', 'nunique'),
|
||
方案总数=('方案名称', 'count'),
|
||
已完成=('简化状态', lambda x: (x == '已完成').sum()),
|
||
超规=('是否超一定规模', lambda x: (x.astype(str) == '是').sum()),
|
||
).reset_index()
|
||
country_stats['审批率'] = (country_stats['已完成'] / country_stats['方案总数'] * 100).round(0).astype(int)
|
||
|
||
# Project summary
|
||
ps = y2026.groupby('项目名称').agg(
|
||
方案总数=('方案名称', 'count'),
|
||
已完成=('简化状态', lambda x: (x == '已完成').sum()),
|
||
超规=('是否超一定规模', lambda x: (x.astype(str) == '是').sum()),
|
||
).reset_index()
|
||
ps['未完成'] = ps['方案总数'] - ps['已完成']
|
||
ps['审批率'] = (ps['已完成'] / ps['方案总数'] * 100).round(0).astype(int)
|
||
ps['国别'] = ps['项目名称'].map(y2026.groupby('项目名称')['所属国别'].first())
|
||
ps = ps.sort_values('方案总数', ascending=False)
|
||
|
||
# Status breakdown
|
||
status_counts = y2026['方案状态_clean'].value_counts().to_dict()
|
||
|
||
# Generate HTML
|
||
rows = []
|
||
for _, r in ps.iterrows():
|
||
name = r['项目名称'][:60]
|
||
total_n = int(r['方案总数'])
|
||
done = int(r['已完成'])
|
||
undone = int(r['未完成'])
|
||
sz = int(r['超规'])
|
||
rate = int(r['审批率'])
|
||
country = r.get('国别', '')
|
||
|
||
if rate >= 80: cls = 'badge-ok'
|
||
elif rate >= 50: cls = 'badge-warn'
|
||
else: cls = 'badge-alert'
|
||
|
||
rows.append(f'<tr><td>{name}</td><td class="num">{total_n}</td><td class="num">{done}</td><td class="num">{sz}</td><td class="num"><span class="badge {cls}">{rate}%</span></td><td>{country}</td></tr>')
|
||
|
||
country_rows = []
|
||
for _, r in country_stats.iterrows():
|
||
name = r['所属国别']
|
||
c = int(r['审批率'])
|
||
if c >= 80: cls = 'badge-ok'
|
||
elif c >= 50: cls = 'badge-warn'
|
||
else: cls = 'badge-alert'
|
||
country_rows.append(f'<tr><td>{name}</td><td class="num">{int(r[\"项目数\"])}</td><td class="num">{int(r[\"方案总数\"])}</td><td class="num">{int(r[\"已完成\"])}</td><td class="num">{int(r[\"超规\"])}</td><td class="num"><span class="badge {cls}">{c}%</span></td></tr>')
|
||
|
||
approved_pct = round(completed/total*100) if total else 0
|
||
approved_color = '#22c55e' if approved_pct >= 80 else '#f59e0b' if approved_pct >= 50 else '#ef4444'
|
||
|
||
html = f'''<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||
<title>危大方案编审进度看板 | 2026年开工 | 中东区域公司</title>
|
||
<style>
|
||
*{{margin:0;padding:0;box-sizing:border-box}}
|
||
body{{font-family:'Microsoft YaHei','PingFang SC',sans-serif;background:#0f172a;color:#e2e8f0;padding:24px}}
|
||
.header{{text-align:center;padding:28px 0;border-bottom:2px solid #1e3a5f;margin-bottom:28px}}
|
||
.header h1{{color:#c8962e;font-size:26px}}
|
||
.header p{{color:#64748b;margin-top:6px;font-size:14px}}
|
||
.kpi-grid{{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:24px}}
|
||
.kpi{{background:#1e293b;border-radius:10px;padding:18px;border:1px solid #334155;text-align:center}}
|
||
.kpi .num{{font-size:32px;font-weight:bold;margin:6px 0}}
|
||
.kpi .label{{color:#94a3b8;font-size:13px}}
|
||
.table-wrap{{background:#1e293b;border-radius:10px;padding:20px;margin-bottom:20px;border:1px solid #334155}}
|
||
.table-wrap h2{{color:#c8962e;font-size:17px;margin-bottom:14px;padding-bottom:10px;border-bottom:1px solid #334155}}
|
||
table{{width:100%;border-collapse:collapse;font-size:13px}}
|
||
th{{background:#0f172a;color:#c8962e;padding:9px 8px;text-align:left}}
|
||
td{{padding:7px 8px;border-bottom:1px solid #1e3a5a}}
|
||
tr:hover{{background:#1a2e44}}
|
||
.num{{text-align:right}}
|
||
.badge{{padding:2px 8px;border-radius:4px;font-size:11px;font-weight:bold}}
|
||
.badge-ok{{background:#166534;color:#86efac}}
|
||
.badge-warn{{background:#78350f;color:#fbbf24}}
|
||
.badge-alert{{background:#7f1d1d;color:#fca5a5}}
|
||
.bar-wrap{{background:#334155;border-radius:3px;width:100%;height:8px;display:inline-block}}
|
||
.bar{{display:inline-block;height:8px;border-radius:3px}}
|
||
.footer{{text-align:center;color:#475569;padding:16px;font-size:12px}}
|
||
.note{{background:#1a2e44;border-left:3px solid #c8962e;padding:12px 16px;margin-bottom:20px;border-radius:0 8px 8px 0;font-size:13px;color:#94a3b8}}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="header">
|
||
<h1>🏗️ 危大方案编审进度看板</h1>
|
||
<p>中国港湾中东区域公司 · 2026年开工项目 · 数据日期:{DATA_DATE}</p>
|
||
</div>
|
||
|
||
<div class="kpi-grid">
|
||
<div class="kpi"><div class="label">2026开工方案</div><div class="num" style="color:#c8962e">{total}</div><div class="label">覆盖{len(ps)}个项目</div></div>
|
||
<div class="kpi"><div class="label">超一定规模</div><div class="num" style="color:#f59e0b">{oversized}</div><div class="label">占比 {round(oversized/total*100)}%</div></div>
|
||
<div class="kpi"><div class="label">已完成审批</div><div class="num" style="color:{approved_color}">{completed}</div><div class="label">{total-completed}项未完成</div></div>
|
||
<div class="kpi"><div class="label">审批完成率</div><div class="num" style="color:{approved_color}">{approved_pct}%</div><div class="label">{completed}/{total}</div></div>
|
||
</div>
|
||
|
||
<div class="note">
|
||
📌 <b>状态说明</b>:已完成 = 已审批或已备案;未完成 = 未审批 / 审批中 / 未知。已作废方案已排除。<br>
|
||
📌 <b>范围说明</b>:仅显示分部分项工程计划开工日期在2026年的方案(共{total}项,占全部有效方案{len(valid)}项的{round(total/len(valid)*100)}%)。
|
||
</div>
|
||
|
||
<!-- 项目明细 -->
|
||
<div class="table-wrap">
|
||
<h2>📋 项目明细(按方案总数排序)</h2>
|
||
<table>
|
||
<tr><th>项目名称</th><th class="num">方案</th><th class="num">已完成</th><th class="num">超规</th><th class="num">审批率</th><th>国别</th></tr>
|
||
{rows_html}
|
||
<tr style="font-weight:bold;background:#1a2e44"><td>合计</td><td class="num">{total}</td><td class="num">{completed}</td><td class="num">{oversized}</td><td class="num">{approved_pct}%</td><td></td></tr>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- 按国别 -->
|
||
<div class="table-wrap">
|
||
<h2>🌍 按国别汇总</h2>
|
||
<table>
|
||
<tr><th>国别</th><th class="num">项目数</th><th class="num">方案总数</th><th class="num">已完成</th><th class="num">超规</th><th class="num">审批率</th></tr>
|
||
{country_rows_html}
|
||
</table>
|
||
</div>
|
||
|
||
<div class="footer">
|
||
<p>中国港湾中东区域公司 技术部 | 2026开工项目 | 自动生成于 {DATA_DATE}</p>
|
||
</div>
|
||
|
||
</body></html>'''
|
||
|
||
out = BASE / 'certified_schemes_dashboard.html'
|
||
out.write_text(html, encoding='utf-8')
|
||
print(f'✅ {out}')
|
||
print(f' {len(html):,} bytes')
|
||
print(f' {total} schemes, {len(ps)} projects, {approved_pct}% completion')
|