Files
tianpu-ems/docs/create_pptx.cjs

318 lines
22 KiB
JavaScript
Raw Normal View History

const pptxgen = require("pptxgenjs");
const path = require("path");
const pres = new pptxgen();
pres.layout = "LAYOUT_16x9";
pres.author = "Tianpu EMS Team";
pres.title = "天普EMS企业级功能增强 — 开发团队晨会";
// Color palette — Ocean Gradient theme for energy/tech
const C = {
navy: "0A1628",
darkBlue: "0F2440",
blue: "1565C0",
lightBlue: "42A5F5",
teal: "00897B",
green: "43A047",
white: "FFFFFF",
offWhite: "F5F7FA",
lightGray: "E8ECF1",
gray: "8898AA",
darkGray: "32325D",
accent: "FF6F00",
red: "E53935",
};
const makeShadow = () => ({ type: "outer", blur: 6, offset: 2, angle: 135, color: "000000", opacity: 0.12 });
// ============================================================
// SLIDE 1: Title
// ============================================================
let s1 = pres.addSlide();
s1.background = { color: C.navy };
// Top accent bar
s1.addShape(pres.shapes.RECTANGLE, { x: 0, y: 0, w: 10, h: 0.06, fill: { color: C.lightBlue } });
// Title block
s1.addText("天普零碳园区", { x: 0.8, y: 1.2, w: 8.4, h: 0.8, fontSize: 44, fontFace: "Microsoft YaHei", color: C.white, bold: true, margin: 0 });
s1.addText("智慧能源管理平台", { x: 0.8, y: 1.9, w: 8.4, h: 0.8, fontSize: 44, fontFace: "Microsoft YaHei", color: C.lightBlue, bold: true, margin: 0 });
s1.addText("企业级功能增强项目 — 开发团队晨会", { x: 0.8, y: 2.9, w: 8.4, h: 0.5, fontSize: 20, fontFace: "Microsoft YaHei", color: C.gray, margin: 0 });
// Bottom info bar
s1.addShape(pres.shapes.RECTANGLE, { x: 0, y: 4.8, w: 10, h: 0.825, fill: { color: C.darkBlue } });
s1.addText("React 19 + FastAPI + PostgreSQL/TimescaleDB + Redis", { x: 0.8, y: 4.85, w: 8.4, h: 0.7, fontSize: 14, fontFace: "Consolas", color: C.lightBlue, align: "left", valign: "middle" });
// ============================================================
// SLIDE 2: Project Overview
// ============================================================
let s2 = pres.addSlide();
s2.background = { color: C.offWhite };
s2.addShape(pres.shapes.RECTANGLE, { x: 0, y: 0, w: 10, h: 0.06, fill: { color: C.blue } });
s2.addText("项目概述", { x: 0.7, y: 0.3, w: 8.6, h: 0.6, fontSize: 32, fontFace: "Microsoft YaHei", color: C.darkGray, bold: true, margin: 0 });
// 4 KPI cards
const kpis = [
{ label: "增强阶段", value: "12", sub: "全部完成", color: C.green },
{ label: "新增API", value: "80+", sub: "端点", color: C.blue },
{ label: "新增页面", value: "16", sub: "前端组件", color: C.teal },
{ label: "数据库表", value: "37", sub: "总计", color: C.accent },
];
kpis.forEach((k, i) => {
const cx = 0.7 + i * 2.3;
s2.addShape(pres.shapes.RECTANGLE, { x: cx, y: 1.15, w: 2.0, h: 1.5, fill: { color: C.white }, shadow: makeShadow() });
s2.addShape(pres.shapes.RECTANGLE, { x: cx, y: 1.15, w: 2.0, h: 0.06, fill: { color: k.color } });
s2.addText(k.value, { x: cx, y: 1.35, w: 2.0, h: 0.7, fontSize: 36, fontFace: "Arial Black", color: k.color, align: "center", valign: "middle", bold: true, margin: 0 });
s2.addText(k.sub, { x: cx, y: 1.95, w: 2.0, h: 0.3, fontSize: 12, fontFace: "Microsoft YaHei", color: C.gray, align: "center", margin: 0 });
s2.addText(k.label, { x: cx, y: 2.3, w: 2.0, h: 0.3, fontSize: 11, fontFace: "Microsoft YaHei", color: C.darkGray, align: "center", bold: true, margin: 0 });
});
// Description bullets
s2.addText([
{ text: "参考系统: cp-ems-ruoyi (Java/Spring Boot 企业级EMS)", options: { bullet: true, breakLine: true, fontSize: 14 } },
{ text: "目标: 以现代Python/React技术栈实现同等企业级功能深度", options: { bullet: true, breakLine: true, fontSize: 14 } },
{ text: "技术优势保留: 3D可视化、多协议采集、TypeScript、i18n、暗色模式", options: { bullet: true, breakLine: true, fontSize: 14 } },
{ text: "全部编译验证通过: 后端0错误、前端0 TS错误、所有API已测试", options: { bullet: true, fontSize: 14 } },
], { x: 0.7, y: 2.9, w: 8.6, h: 2.5, fontFace: "Microsoft YaHei", color: C.darkGray, valign: "top" });
// ============================================================
// SLIDE 3: New Modules Overview (Table)
// ============================================================
let s3 = pres.addSlide();
s3.background = { color: C.offWhite };
s3.addShape(pres.shapes.RECTANGLE, { x: 0, y: 0, w: 10, h: 0.06, fill: { color: C.blue } });
s3.addText("新增功能模块一览", { x: 0.7, y: 0.2, w: 8.6, h: 0.55, fontSize: 28, fontFace: "Microsoft YaHei", color: C.darkGray, bold: true, margin: 0 });
const hdrOpts = { fill: { color: C.blue }, color: C.white, bold: true, fontSize: 11, fontFace: "Microsoft YaHei", align: "center", valign: "middle" };
const cellOpts = { fontSize: 10, fontFace: "Microsoft YaHei", color: C.darkGray, valign: "middle" };
const cellC = { ...cellOpts, align: "center" };
const altFill = { fill: { color: C.lightGray } };
const tableRows = [
[
{ text: "功能模块", options: hdrOpts },
{ text: "后端", options: hdrOpts },
{ text: "前端", options: hdrOpts },
{ text: "状态", options: hdrOpts },
],
[{ text: "基础设施 (Redis/队列/聚合)", options: cellOpts }, { text: "3 files", options: cellC }, { text: "-", options: cellC }, { text: "✅", options: cellC }],
[{ text: "定额管理", options: { ...cellOpts, ...altFill } }, { text: "model+API+service", options: { ...cellC, ...altFill } }, { text: "1 page (3 tabs)", options: { ...cellC, ...altFill } }, { text: "✅", options: { ...cellC, ...altFill } }],
[{ text: "费用分析", options: cellOpts }, { text: "model+API+service", options: cellC }, { text: "1 component", options: cellC }, { text: "✅", options: cellC }],
[{ text: "分项分析", options: { ...cellOpts, ...altFill } }, { text: "extended energy.py", options: { ...cellC, ...altFill } }, { text: "1 component", options: { ...cellC, ...altFill } }, { text: "✅", options: { ...cellC, ...altFill } }],
[{ text: "充电桩管理", options: cellOpts }, { text: "8 models + API", options: cellC }, { text: "6 pages", options: cellC }, { text: "✅", options: cellC }],
[{ text: "能耗分析增强 (损耗/同比/环比)", options: { ...cellOpts, ...altFill } }, { text: "extended energy.py", options: { ...cellC, ...altFill } }, { text: "3 components", options: { ...cellC, ...altFill } }, { text: "✅", options: { ...cellC, ...altFill } }],
[{ text: "告警分析", options: cellOpts }, { text: "extended alarms.py", options: cellC }, { text: "enhanced page", options: cellC }, { text: "✅", options: cellC }],
[{ text: "运维管理", options: { ...cellOpts, ...altFill } }, { text: "4 models + API", options: { ...cellC, ...altFill } }, { text: "1 page (5 tabs)", options: { ...cellC, ...altFill } }, { text: "✅", options: { ...cellC, ...altFill } }],
[{ text: "数据查询", options: cellOpts }, { text: "extended energy.py", options: cellC }, { text: "1 page", options: cellC }, { text: "✅", options: cellC }],
[{ text: "设备拓扑", options: { ...cellOpts, ...altFill } }, { text: "extended devices.py", options: { ...cellC, ...altFill } }, { text: "1 component", options: { ...cellC, ...altFill } }, { text: "✅", options: { ...cellC, ...altFill } }],
[{ text: "管理体系", options: cellOpts }, { text: "4 models + API", options: cellC }, { text: "1 page (4 tabs)", options: cellC }, { text: "✅", options: cellC }],
[{ text: "生产加固 (限流/幂等/请求ID)", options: { ...cellOpts, ...altFill } }, { text: "middleware.py", options: { ...cellC, ...altFill } }, { text: "-", options: { ...cellC, ...altFill } }, { text: "✅", options: { ...cellC, ...altFill } }],
];
s3.addTable(tableRows, { x: 0.5, y: 0.85, w: 9.0, colW: [3.8, 2.2, 1.8, 0.8], border: { pt: 0.5, color: "D0D5DD" }, rowH: [0.35, 0.32, 0.32, 0.32, 0.32, 0.32, 0.32, 0.32, 0.32, 0.32, 0.32, 0.32, 0.32, 0.32] });
// ============================================================
// SLIDE 4: Tech Architecture
// ============================================================
let s4 = pres.addSlide();
s4.background = { color: C.offWhite };
s4.addShape(pres.shapes.RECTANGLE, { x: 0, y: 0, w: 10, h: 0.06, fill: { color: C.blue } });
s4.addText("技术架构", { x: 0.7, y: 0.25, w: 8.6, h: 0.55, fontSize: 28, fontFace: "Microsoft YaHei", color: C.darkGray, bold: true, margin: 0 });
// Architecture layers as horizontal blocks
const layers = [
{ label: "前端展示层", tech: "React 19 + TypeScript + Ant Design 5 + ECharts + Three.js (3D)", color: C.lightBlue, y: 1.0 },
{ label: "API网关层", tech: "FastAPI + JWT Auth + RBAC + Rate Limiting + Request ID", color: C.blue, y: 1.85 },
{ label: "业务服务层", tech: "定额检查 | 费用计算 | 告警引擎 | 报表生成 | 数据聚合", color: C.teal, y: 2.7 },
{ label: "数据采集层", tech: "Modbus TCP + MQTT + HTTP API + Redis Streams Queue", color: C.green, y: 3.55 },
{ label: "存储层", tech: "PostgreSQL 16 (TimescaleDB) + Redis 7 + File Storage", color: C.accent, y: 4.4 },
];
layers.forEach(l => {
s4.addShape(pres.shapes.RECTANGLE, { x: 0.7, y: l.y, w: 2.2, h: 0.65, fill: { color: l.color } });
s4.addText(l.label, { x: 0.7, y: l.y, w: 2.2, h: 0.65, fontSize: 13, fontFace: "Microsoft YaHei", color: C.white, align: "center", valign: "middle", bold: true, margin: 0 });
s4.addShape(pres.shapes.RECTANGLE, { x: 3.0, y: l.y, w: 6.3, h: 0.65, fill: { color: C.white }, shadow: makeShadow() });
s4.addText(l.tech, { x: 3.2, y: l.y, w: 5.9, h: 0.65, fontSize: 12, fontFace: "Consolas", color: C.darkGray, valign: "middle", margin: 0 });
});
// ============================================================
// SLIDE 5: Frontend Team
// ============================================================
let s5 = pres.addSlide();
s5.background = { color: C.offWhite };
s5.addShape(pres.shapes.RECTANGLE, { x: 0, y: 0, w: 10, h: 0.06, fill: { color: C.lightBlue } });
s5.addText("前端开发组 — 代码Review清单", { x: 0.7, y: 0.2, w: 8.6, h: 0.5, fontSize: 26, fontFace: "Microsoft YaHei", color: C.darkGray, bold: true, margin: 0 });
s5.addText("Git: http://100.108.180.60:3300/tianpu/tianpu-ems | 目录: frontend/src/", { x: 0.7, y: 0.65, w: 8.6, h: 0.3, fontSize: 11, fontFace: "Consolas", color: C.blue, margin: 0 });
const feFiles = [
["pages/Quota/index.tsx", "定额管理 (3 tabs: 配置/监控/分析)"],
["pages/Charging/*", "充电管理 (Dashboard, Stations, Piles, Orders, Pricing)"],
["pages/Maintenance/index.tsx", "运维管理 (5 tabs: 概览/巡检/工单/值班)"],
["pages/DataQuery/index.tsx", "数据查询 (树形选择器 + 多参数查询)"],
["pages/Management/index.tsx", "管理体系 (4 tabs: 规章/标准/流程/预案)"],
["pages/Analysis/CostAnalysis.tsx", "费用分析组件"],
["pages/Analysis/SubitemAnalysis.tsx", "分项分析组件"],
["pages/Analysis/Loss|Yoy|Mom.tsx", "损耗/同比/环比分析 (3组件)"],
["pages/Alarms/index.tsx", "告警分析增强 + 规则Toggle"],
["pages/Devices/Topology.tsx", "设备拓扑树"],
["layouts/MainLayout.tsx", "菜单导航 (14项)"],
["App.tsx + services/api.ts", "路由配置 + API调用函数"],
];
const feHdr = [
{ text: "文件路径", options: hdrOpts },
{ text: "功能说明", options: hdrOpts },
];
const feRows = [feHdr];
feFiles.forEach((f, i) => {
const bg = i % 2 === 1 ? altFill : {};
feRows.push([
{ text: f[0], options: { fontSize: 10, fontFace: "Consolas", color: C.blue, valign: "middle", ...bg } },
{ text: f[1], options: { fontSize: 10, fontFace: "Microsoft YaHei", color: C.darkGray, valign: "middle", ...bg } },
]);
});
s5.addTable(feRows, { x: 0.5, y: 1.05, w: 9.0, colW: [3.8, 5.2], border: { pt: 0.5, color: "D0D5DD" }, rowH: 0.32 });
// ============================================================
// SLIDE 6: Backend Team
// ============================================================
let s6 = pres.addSlide();
s6.background = { color: C.offWhite };
s6.addShape(pres.shapes.RECTANGLE, { x: 0, y: 0, w: 10, h: 0.06, fill: { color: C.teal } });
s6.addText("后端开发组 — 代码Review清单", { x: 0.7, y: 0.2, w: 8.6, h: 0.5, fontSize: 26, fontFace: "Microsoft YaHei", color: C.darkGray, bold: true, margin: 0 });
s6.addText("Git: http://100.108.180.60:3300/tianpu/tianpu-ems | 目录: backend/app/", { x: 0.7, y: 0.65, w: 8.6, h: 0.3, fontSize: 11, fontFace: "Consolas", color: C.teal, margin: 0 });
// Three columns: Models | APIs | Services
const colW = 2.9;
const colGap = 0.15;
const colY = 1.1;
const colH = 4.3;
// Models column
s6.addShape(pres.shapes.RECTANGLE, { x: 0.5, y: colY, w: colW, h: colH, fill: { color: C.white }, shadow: makeShadow() });
s6.addShape(pres.shapes.RECTANGLE, { x: 0.5, y: colY, w: colW, h: 0.4, fill: { color: C.blue } });
s6.addText("数据模型 (6 files)", { x: 0.5, y: colY, w: colW, h: 0.4, fontSize: 13, fontFace: "Microsoft YaHei", color: C.white, align: "center", valign: "middle", bold: true, margin: 0 });
s6.addText([
{ text: "models/quota.py", options: { breakLine: true, fontSize: 9, fontFace: "Consolas", color: C.blue } },
{ text: " EnergyQuota, QuotaUsage", options: { breakLine: true, fontSize: 9, color: C.gray } },
{ text: "models/pricing.py", options: { breakLine: true, fontSize: 9, fontFace: "Consolas", color: C.blue } },
{ text: " Pricing, PricingPeriod", options: { breakLine: true, fontSize: 9, color: C.gray } },
{ text: "models/charging.py", options: { breakLine: true, fontSize: 9, fontFace: "Consolas", color: C.blue } },
{ text: " 8 charging models", options: { breakLine: true, fontSize: 9, color: C.gray } },
{ text: "models/maintenance.py", options: { breakLine: true, fontSize: 9, fontFace: "Consolas", color: C.blue } },
{ text: " Plan, Record, Order, Duty", options: { breakLine: true, fontSize: 9, color: C.gray } },
{ text: "models/management.py", options: { breakLine: true, fontSize: 9, fontFace: "Consolas", color: C.blue } },
{ text: " Regulation, Standard, etc.", options: { breakLine: true, fontSize: 9, color: C.gray } },
{ text: "models/energy.py", options: { breakLine: true, fontSize: 9, fontFace: "Consolas", color: C.blue } },
{ text: " EnergyCategory (new)", options: { fontSize: 9, color: C.gray } },
], { x: 0.65, y: colY + 0.5, w: colW - 0.3, h: colH - 0.6, valign: "top" });
// APIs column
const col2X = 0.5 + colW + colGap;
s6.addShape(pres.shapes.RECTANGLE, { x: col2X, y: colY, w: colW, h: colH, fill: { color: C.white }, shadow: makeShadow() });
s6.addShape(pres.shapes.RECTANGLE, { x: col2X, y: colY, w: colW, h: 0.4, fill: { color: C.teal } });
s6.addText("API接口 (7 files)", { x: col2X, y: colY, w: colW, h: 0.4, fontSize: 13, fontFace: "Microsoft YaHei", color: C.white, align: "center", valign: "middle", bold: true, margin: 0 });
s6.addText([
{ text: "api/v1/quota.py", options: { breakLine: true, fontSize: 9, fontFace: "Consolas", color: C.teal } },
{ text: " 定额管理 CRUD", options: { breakLine: true, fontSize: 9, color: C.gray } },
{ text: "api/v1/cost.py", options: { breakLine: true, fontSize: 9, fontFace: "Consolas", color: C.teal } },
{ text: " 费用分析 API", options: { breakLine: true, fontSize: 9, color: C.gray } },
{ text: "api/v1/charging.py", options: { breakLine: true, fontSize: 9, fontFace: "Consolas", color: C.teal } },
{ text: " 充电管理 20+ endpoints", options: { breakLine: true, fontSize: 9, color: C.gray } },
{ text: "api/v1/maintenance.py", options: { breakLine: true, fontSize: 9, fontFace: "Consolas", color: C.teal } },
{ text: " 运维管理 API", options: { breakLine: true, fontSize: 9, color: C.gray } },
{ text: "api/v1/management.py", options: { breakLine: true, fontSize: 9, fontFace: "Consolas", color: C.teal } },
{ text: " 管理体系 CRUD", options: { breakLine: true, fontSize: 9, color: C.gray } },
{ text: "api/v1/energy.py (扩展)", options: { breakLine: true, fontSize: 9, fontFace: "Consolas", color: C.teal } },
{ text: " 分类/损耗/同比/环比/参量", options: { breakLine: true, fontSize: 9, color: C.gray } },
{ text: "api/v1/alarms.py (扩展)", options: { breakLine: true, fontSize: 9, fontFace: "Consolas", color: C.teal } },
{ text: " 分析/排名/MTTR/Toggle", options: { fontSize: 9, color: C.gray } },
], { x: col2X + 0.15, y: colY + 0.5, w: colW - 0.3, h: colH - 0.6, valign: "top" });
// Services column
const col3X = col2X + colW + colGap;
s6.addShape(pres.shapes.RECTANGLE, { x: col3X, y: colY, w: colW, h: colH, fill: { color: C.white }, shadow: makeShadow() });
s6.addShape(pres.shapes.RECTANGLE, { x: col3X, y: colY, w: colW, h: 0.4, fill: { color: C.green } });
s6.addText("服务 + 中间件 (6 files)", { x: col3X, y: colY, w: colW, h: 0.4, fontSize: 13, fontFace: "Microsoft YaHei", color: C.white, align: "center", valign: "middle", bold: true, margin: 0 });
s6.addText([
{ text: "core/cache.py", options: { breakLine: true, fontSize: 9, fontFace: "Consolas", color: C.green } },
{ text: " Redis缓存层", options: { breakLine: true, fontSize: 9, color: C.gray } },
{ text: "core/middleware.py", options: { breakLine: true, fontSize: 9, fontFace: "Consolas", color: C.green } },
{ text: " 限流/幂等/请求ID", options: { breakLine: true, fontSize: 9, color: C.gray } },
{ text: "collectors/queue.py", options: { breakLine: true, fontSize: 9, fontFace: "Consolas", color: C.green } },
{ text: " Redis Streams消息队列", options: { breakLine: true, fontSize: 9, color: C.gray } },
{ text: "services/aggregation.py", options: { breakLine: true, fontSize: 9, fontFace: "Consolas", color: C.green } },
{ text: " 时/日/月数据聚合引擎", options: { breakLine: true, fontSize: 9, color: C.gray } },
{ text: "services/quota_checker.py", options: { breakLine: true, fontSize: 9, fontFace: "Consolas", color: C.green } },
{ text: " 定额合规检查", options: { breakLine: true, fontSize: 9, color: C.gray } },
{ text: "services/cost_calculator.py", options: { breakLine: true, fontSize: 9, fontFace: "Consolas", color: C.green } },
{ text: " 分时电价费用计算", options: { breakLine: true, fontSize: 9, color: C.gray } },
{ text: "alembic/versions/003-008", options: { breakLine: true, fontSize: 9, fontFace: "Consolas", color: C.green } },
{ text: " 6个新数据库迁移文件", options: { fontSize: 9, color: C.gray } },
], { x: col3X + 0.15, y: colY + 0.5, w: colW - 0.3, h: colH - 0.6, valign: "top" });
// ============================================================
// SLIDE 7: Next Steps
// ============================================================
let s7 = pres.addSlide();
s7.background = { color: C.offWhite };
s7.addShape(pres.shapes.RECTANGLE, { x: 0, y: 0, w: 10, h: 0.06, fill: { color: C.accent } });
s7.addText("下一步行动计划", { x: 0.7, y: 0.3, w: 8.6, h: 0.55, fontSize: 28, fontFace: "Microsoft YaHei", color: C.darkGray, bold: true, margin: 0 });
const steps = [
{ num: "1", title: "注册Gitea账号", desc: "访问 http://100.108.180.60:3300 注册开发者账号" },
{ num: "2", title: "Clone仓库", desc: "git clone http://100.108.180.60:3300/tianpu/tianpu-ems.git" },
{ num: "3", title: "阅读负责代码", desc: "前端组看Slide 5、后端组看Slide 6中列出的文件" },
{ num: "4", title: "本地运行项目", desc: "backend: uvicorn app.main:app --port 8000\nfrontend: npm install && npm run dev" },
{ num: "5", title: "登录体验", desc: "http://localhost:3000 账号: admin / admin123" },
{ num: "6", title: "API文档", desc: "http://localhost:8000/docs (Swagger自动生成)" },
];
steps.forEach((s, i) => {
const sy = 1.1 + i * 0.72;
// Number circle
s7.addShape(pres.shapes.OVAL, { x: 0.7, y: sy + 0.05, w: 0.45, h: 0.45, fill: { color: C.blue } });
s7.addText(s.num, { x: 0.7, y: sy + 0.05, w: 0.45, h: 0.45, fontSize: 18, fontFace: "Arial", color: C.white, align: "center", valign: "middle", bold: true, margin: 0 });
// Title + desc
s7.addText(s.title, { x: 1.35, y: sy, w: 2.0, h: 0.55, fontSize: 15, fontFace: "Microsoft YaHei", color: C.darkGray, valign: "middle", bold: true, margin: 0 });
s7.addText(s.desc, { x: 3.4, y: sy, w: 6.0, h: 0.55, fontSize: 11, fontFace: "Consolas", color: C.gray, valign: "middle", margin: 0 });
});
// ============================================================
// SLIDE 8: Verification Results
// ============================================================
let s8 = pres.addSlide();
s8.background = { color: C.navy };
s8.addShape(pres.shapes.RECTANGLE, { x: 0, y: 0, w: 10, h: 0.06, fill: { color: C.green } });
s8.addText("验证结果 — 全部通过", { x: 0.7, y: 0.3, w: 8.6, h: 0.6, fontSize: 28, fontFace: "Microsoft YaHei", color: C.white, bold: true, margin: 0 });
const checks = [
{ icon: "✅", label: "Backend", value: "120+ API routes, 0 errors" },
{ icon: "✅", label: "Frontend", value: "12 pages, 27 tabs, 0 TS errors" },
{ icon: "✅", label: "Database", value: "37 tables, seed data populated" },
{ icon: "✅", label: "API Test", value: "All 20 endpoint groups return real data" },
{ icon: "✅", label: "Modals", value: "Create / Edit / Delete all functional" },
{ icon: "✅", label: "Console", value: "0 runtime errors (only antd deprecation warnings)" },
];
checks.forEach((c, i) => {
const cy = 1.2 + i * 0.65;
s8.addShape(pres.shapes.RECTANGLE, { x: 0.7, y: cy, w: 8.6, h: 0.5, fill: { color: C.darkBlue } });
s8.addText(c.icon, { x: 0.9, y: cy, w: 0.5, h: 0.5, fontSize: 18, align: "center", valign: "middle", margin: 0 });
s8.addText(c.label, { x: 1.5, y: cy, w: 1.5, h: 0.5, fontSize: 14, fontFace: "Microsoft YaHei", color: C.lightBlue, valign: "middle", bold: true, margin: 0 });
s8.addText(c.value, { x: 3.2, y: cy, w: 6.0, h: 0.5, fontSize: 13, fontFace: "Consolas", color: C.white, valign: "middle", margin: 0 });
});
// Bottom tagline
s8.addText("准备就绪 — 开始代码Review", { x: 0.7, y: 5.0, w: 8.6, h: 0.4, fontSize: 16, fontFace: "Microsoft YaHei", color: C.accent, align: "center", bold: true, margin: 0 });
// Save
const outPath = path.resolve("E:/AI_Projects/01.Tianpu_EMS/docs/天普EMS开发任务分配_晨会.pptx");
pres.writeFile({ fileName: outPath }).then(() => {
console.log("Presentation saved to: " + outPath);
}).catch(err => {
console.error("Error:", err);
});