# ============================================================================= # 🎁 惊喜 1: 项目健康度仪表盘 # ============================================================================= # 用途: 一键生成项目健康度总览 HTML(明早桌面打开即用) # 跑法: python scripts/dashboard.py # 产物: docs/dashboard.html # ============================================================================= import os import json import subprocess from datetime import datetime from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parent.parent OUTPUT = PROJECT_ROOT / "docs" / "dashboard.html" def count_lines(glob_pattern: str) -> int: """统计符合 glob 的代码总行数""" import glob total = 0 for f in glob.glob(glob_pattern, recursive=True): if os.path.isfile(f): try: with open(f, "r", encoding="utf-8", errors="ignore") as fp: total += sum(1 for _ in fp) except Exception: pass return total def count_files(glob_pattern: str) -> int: import glob return sum(1 for f in glob.glob(glob_pattern, recursive=True) if os.path.isfile(f)) def git_info() -> dict: """拿 git 仓库信息""" try: result = { "branch": subprocess.run( ["git", "rev-parse", "--abbrev-ref", "HEAD"], cwd=PROJECT_ROOT, capture_output=True, text=True ).stdout.strip(), "last_commit": subprocess.run( ["git", "log", "-1", "--format=%h %s"], cwd=PROJECT_ROOT, capture_output=True, text=True ).stdout.strip(), "commit_count": subprocess.run( ["git", "rev-list", "--count", "HEAD"], cwd=PROJECT_ROOT, capture_output=True, text=True ).stdout.strip(), } return result except Exception as e: return {"error": str(e)} def main(): # 1. 代码统计 stats = { "backend_python_files": count_files("backend/app/**/*.py"), "backend_python_lines": count_lines("backend/app/**/*.py"), "frontend_admin_files": count_files("frontend-admin/src/**/*.{vue,ts,js}"), "frontend_agent_files": count_files("frontend-agent/src/**/*.{vue,ts,js}"), "frontend_h5_files": count_files("frontend-h5/src/**/*.{vue,ts,js}"), "frontend_portal_files": count_files("frontend-portal/src/**/*.{vue,ts,js}"), "docs_files": count_files("docs/**/*.md"), "scripts_files": count_files("scripts/**/*.sh"), "tests_files": count_files("backend/tests/**/*.py"), } # 2. 文档统计 docs_path = PROJECT_ROOT / "docs" doc_categories = { "评审报告": len(list((docs_path / "评审报告").glob("*.md"))) if (docs_path / "评审报告").exists() else 0, "审计报告": len(list((docs_path / "审计报告").glob("*.md"))) if (docs_path / "审计报告").exists() else 0, "ADRs": len(list((docs_path / "ADRs").glob("*.md"))) if (docs_path / "ADRs").exists() else 0, "SOPs": len(list((docs_path / "SOPs").glob("*.md"))) if (docs_path / "SOPs").exists() else 0, "路线图": len(list((docs_path / "路线图").glob("*.md"))) if (docs_path / "路线图").exists() else 0, } # 3. 风险统计(解析风险跟踪表) risk_file = docs_path / "风险跟踪表.md" risk_stats = {"P0_remaining": 0, "P1": 0, "P2": 0, "P3": 0, "M": 0, "L": 0} if risk_file.exists(): text = risk_file.read_text(encoding="utf-8") for level in ["P0", "P1", "P2", "P3", "M", "L"]: risk_stats[f"{level}_total"] = text.count(f"### {level}-") risk_stats[f"{level}_remaining"] = text.count(f"### {level}-") - text.count("✅") # 4. Git 信息 g = git_info() # 5. 模板渲染 html = f""" 企微 IT 智能服务台 - 健康度仪表盘

🚀 企微 IT 智能服务台 - 健康度仪表盘

生成时间: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}

📊 代码规模

{stats['backend_python_lines']:,}
后端 Python 代码行
后端 Python 文件{stats['backend_python_files']}
Admin 前端{stats['frontend_admin_files']} 文件
Agent 前端{stats['frontend_agent_files']} 文件
H5 前端{stats['frontend_h5_files']} 文件
Portal 前端{stats['frontend_portal_files']} 文件

📚 文档

{stats['docs_files']}
文档总数
{''.join(f'
{k}{v}
' for k, v in doc_categories.items())}

🛡️ 风险状态

{risk_stats.get('P0_remaining', 0)}
P0 遗留(需立即修)
P1 中危{risk_stats.get('P1_remaining', 0)} 待修
P2 低危{risk_stats.get('P2_remaining', 0)} 待修
M 中{risk_stats.get('M_remaining', 0)} 待修
L 低{risk_stats.get('L_remaining', 0)} 待修

🛠️ 工具链

{stats['scripts_files']}
自动化脚本
后端测试{stats['tests_files']} 文件
安全审计✅ 已配
API 文档✅ 已配
备份脚本✅ 已配
Pre-commit✅ 已配

📦 Git 状态

分支: {g.get('branch', '?')}
提交数: {g.get('commit_count', '?')}
最近提交: {g.get('last_commit', '?')}

✅ 阶段完成度

66%
阶段 1
0%
阶段 2(转人工)
0%
阶段 3(H5+WS)
规划中
阶段 4(AI Wingman)
规划中
阶段 5(自动化)
企微 IT 智能服务台 · 健康度仪表盘 v1.0
""" OUTPUT.parent.mkdir(parents=True, exist_ok=True) OUTPUT.write_text(html, encoding="utf-8") print(f"✅ 仪表盘已生成: {OUTPUT}") print(f" 打开方式: 直接在浏览器打开 file:///{OUTPUT}") if __name__ == "__main__": main()