""" Ai-DOP 项目周报 PPT 生成脚本 当前周期:2026.05.11 — 2026.05.15 """ from pptx import Presentation from pptx.util import Inches, Pt, Emu from pptx.dml.color import RGBColor from pptx.enum.text import PP_ALIGN, MSO_ANCHOR from pptx.enum.shapes import MSO_SHAPE import datetime # ============ 配色方案 ============ PRIMARY = RGBColor(0x1A, 0x56, 0xDB) # 深蓝主色 ACCENT = RGBColor(0x10, 0xB9, 0x81) # 绿色-完成 WARNING = RGBColor(0xF5, 0x9E, 0x0B) # 橙色-进行中 DANGER = RGBColor(0xEF, 0x44, 0x44) # 红色-风险 DARK = RGBColor(0x1E, 0x29, 0x3B) # 深色文字 GRAY = RGBColor(0x6B, 0x72, 0x80) # 灰色 LIGHT_BG = RGBColor(0xF8, 0xFA, 0xFC) # 浅灰背景 WHITE = RGBColor(0xFF, 0xFF, 0xFF) prs = Presentation() prs.slide_width = Inches(13.333) # 16:9 宽屏 prs.slide_height = Inches(7.5) def add_bg(slide, color): """设置幻灯片背景色""" bg = slide.background fill = bg.fill fill.solid() fill.fore_color.rgb = color def add_rect(slide, left, top, width, height, color, transparency=0): """添加矩形色块""" shape = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, left, top, width, height) shape.fill.solid() shape.fill.fore_color.rgb = color shape.line.fill.background() return shape def add_text(slide, left, top, width, height, text, font_size=14, color=DARK, bold=False, alignment=PP_ALIGN.LEFT, font_name='Microsoft YaHei'): """添加文本框""" txBox = slide.shapes.add_textbox(left, top, width, height) tf = txBox.text_frame tf.word_wrap = True p = tf.paragraphs[0] p.text = text p.font.size = Pt(font_size) p.font.color.rgb = color p.font.bold = bold p.font.name = font_name p.alignment = alignment return txBox def add_table(slide, left, top, width, height, rows, cols, data, col_widths=None): """添加表格""" table_shape = slide.shapes.add_table(rows, cols, left, top, width, height) table = table_shape.table if col_widths: for i, w in enumerate(col_widths): table.columns[i].width = w for r in range(rows): for c in range(cols): cell = table.cell(r, c) cell.text = str(data[r][c]) if r < len(data) and c < len(data[r]) else '' for paragraph in cell.text_frame.paragraphs: paragraph.font.size = Pt(11) paragraph.font.name = 'Microsoft YaHei' if r == 0: # 表头 paragraph.font.bold = True paragraph.font.color.rgb = WHITE paragraph.font.size = Pt(12) else: paragraph.font.color.rgb = DARK # 表头背景 if r == 0: cell.fill.solid() cell.fill.fore_color.rgb = PRIMARY elif r % 2 == 0: cell.fill.solid() cell.fill.fore_color.rgb = LIGHT_BG return table_shape def add_module_bar(slide, left, top, width, progress_pct, color=ACCENT): """添加进度条""" # 背景条 add_rect(slide, left, top, width, Pt(16), RGBColor(0xE5, 0xE7, 0xEB)) # 进度条 if progress_pct > 0: add_rect(slide, left, top, int(width * progress_pct / 100), Pt(16), color) # 百分比文字 add_text(slide, left + width + Pt(6), top - Pt(1), Pt(40), Pt(16), f'{progress_pct}%', font_size=10, color=GRAY) # ============================================================ # 第 1 页:封面 # ============================================================ slide1 = prs.slides.add_slide(prs.slide_layouts[6]) # 空白布局 add_bg(slide1, PRIMARY) # 顶部装饰条 add_rect(slide1, Inches(0), Inches(0), prs.slide_width, Inches(0.08), ACCENT) # 标题 add_text(slide1, Inches(1.5), Inches(1.8), Inches(10), Inches(1.2), 'Ai-DOP 企业智慧运营管理平台', font_size=44, color=WHITE, bold=True) # 副标题 add_text(slide1, Inches(1.5), Inches(2.9), Inches(10), Inches(0.8), '产互联项目 · 周报', font_size=28, color=RGBColor(0xBF, 0xDB, 0xFE)) # 分隔线 add_rect(slide1, Inches(1.5), Inches(3.9), Inches(3), Inches(0.04), ACCENT) # 周期信息 add_text(slide1, Inches(1.5), Inches(4.3), Inches(5), Inches(0.5), '周期:2026.05.11 — 2026.05.15', font_size=18, color=RGBColor(0xBF, 0xDB, 0xFE)) # 右下角信息 add_text(slide1, Inches(1.5), Inches(5.8), Inches(5), Inches(0.4), '项目整体周期:2026.04.15 — 2026.07.31 | 当前进度约 20%', font_size=14, color=RGBColor(0x93, 0xAD, 0xD6)) add_text(slide1, Inches(9.5), Inches(6.5), Inches(3), Inches(0.4), '2026.05.15', font_size=12, color=RGBColor(0x93, 0xAD, 0xD6), alignment=PP_ALIGN.RIGHT) # ============================================================ # 第 2 页:项目整体里程碑 # ============================================================ slide2 = prs.slides.add_slide(prs.slide_layouts[6]) add_bg(slide2, WHITE) # 页眉 add_rect(slide2, Inches(0), Inches(0), prs.slide_width, Inches(0.08), PRIMARY) add_text(slide2, Inches(0.8), Inches(0.35), Inches(10), Inches(0.6), '项目整体里程碑', font_size=28, color=DARK, bold=True) add_text(slide2, Inches(10), Inches(6.9), Inches(3), Inches(0.4), 'Ai-DOP 项目周报 | 2026.05.11-05.15', font_size=9, color=GRAY, alignment=PP_ALIGN.RIGHT) # 里程碑时间轴数据 milestones = [ ('需求沟通\n与项目准备', '04/15 - 04/20', '已完成', ACCENT, 100), ('项目启动', '04/20 - 04/24', '已完成', ACCENT, 100), ('功能实现与\n业务模块测试', '04/27 - 07/17', '进行中', WARNING, 15), ('UAT\n集成测试', '07/17 - 07/28', '待启动', GRAY, 0), ('系统部署\n与上线', '07/29 - 07/31', '待启动', GRAY, 0), ] bar_y = Inches(1.6) for i, (name, date, status, color, pct) in enumerate(milestones): x = Inches(1.2 + i * 2.4) # 阶段卡片 card = add_rect(slide2, x, bar_y, Inches(2.0), Inches(2.8), WHITE) card.shadow.inherit = False # 顶部色条 add_rect(slide2, x, bar_y, Inches(2.0), Inches(0.06), color) add_text(slide2, x + Inches(0.15), bar_y + Inches(0.2), Inches(1.7), Inches(0.8), name, font_size=14, color=DARK, bold=True) add_text(slide2, x + Inches(0.15), bar_y + Inches(1.1), Inches(1.7), Inches(0.4), date, font_size=11, color=GRAY) add_text(slide2, x + Inches(0.15), bar_y + Inches(1.5), Inches(1.7), Inches(0.4), status, font_size=13, color=color, bold=True) # 进度条 add_module_bar(slide2, x + Inches(0.15), bar_y + Inches(2.1), Inches(1.3), pct, color) # 箭头连接符(除了最后一个) if i < len(milestones) - 1: add_text(slide2, x + Inches(2.05), bar_y + Inches(1.1), Inches(0.3), Inches(0.4), '▶', font_size=16, color=GRAY) # 关键数据 data_y = Inches(5.0) add_rect(slide2, Inches(0.8), data_y, Inches(11.7), Inches(0.01), RGBColor(0xE5, 0xE7, 0xEB)) metrics = [ ('15 个', '业务模块'), ('S0-S9', '业务域覆盖'), ('3.5 个月', '项目总周期'), ('20%', '当前总进度'), ('5/8-6/12', '数据库迁移中'), ] for i, (num, label) in enumerate(metrics): x = Inches(1.0 + i * 2.4) add_text(slide2, x, data_y + Inches(0.3), Inches(2.0), Inches(0.5), num, font_size=24, color=PRIMARY, bold=True) add_text(slide2, x, data_y + Inches(0.8), Inches(2.0), Inches(0.4), label, font_size=12, color=GRAY) # ============================================================ # 第 3 页:本周摘要 (5/11-5/17) # ============================================================ slide3 = prs.slides.add_slide(prs.slide_layouts[6]) add_bg(slide3, WHITE) add_rect(slide3, Inches(0), Inches(0), prs.slide_width, Inches(0.08), PRIMARY) add_text(slide3, Inches(0.8), Inches(0.35), Inches(10), Inches(0.6), '本周核心摘要', font_size=28, color=DARK, bold=True) add_text(slide3, Inches(10), Inches(6.9), Inches(3), Inches(0.4), 'Ai-DOP 项目周报 | 2026.05.11-05.15', font_size=9, color=GRAY, alignment=PP_ALIGN.RIGHT) # 三列布局 col_data = [ ('✅ 本周已完成', ACCENT, [ '数据库模型迁移完成\n(SQL Server → MySQL)', 'S0/S1 技术方案设计交付', 'S2 制造协同蓝图设计交付', 'S8/S9 蓝图设计推进过半', ]), ('🔄 持续推进中', WARNING, [ 'S0/S1 功能开发启动', 'S8 全流程即时异常监控\n蓝图(截止 5/22)', 'S9 九宫格智慧运营看板\n蓝图(截止 5/22)', '存储过程重构 + 程序迁移\n(5/11-6/12)', ]), ('⚠️ 重点', DANGER, [ '5 月多条线并行\nS0/S1开发 + S2方案 +\nS8/S9蓝图', ]), ] for i, (title, color, items) in enumerate(col_data): x = Inches(0.7 + i * 4.2) # 标题 add_rect(slide3, x, Inches(1.3), Inches(3.6), Inches(0.5), color) add_text(slide3, x + Inches(0.15), Inches(1.32), Inches(3.3), Inches(0.45), title, font_size=16, color=WHITE, bold=True) # 条目 y = Inches(2.1) for item in items: item_box = add_rect(slide3, x, y, Inches(3.6), Inches(0.82), LIGHT_BG) add_text(slide3, x + Inches(0.12), y + Inches(0.05), Inches(3.35), Inches(0.72), f'• {item}', font_size=12, color=DARK) y += Inches(0.92) # ============================================================ # 第 4 页:模块进度详情 # ============================================================ slide4 = prs.slides.add_slide(prs.slide_layouts[6]) add_bg(slide4, WHITE) add_rect(slide4, Inches(0), Inches(0), prs.slide_width, Inches(0.08), PRIMARY) add_text(slide4, Inches(0.8), Inches(0.35), Inches(10), Inches(0.6), '各模块进度详情', font_size=28, color=DARK, bold=True) add_text(slide4, Inches(10), Inches(6.9), Inches(3), Inches(0.4), 'Ai-DOP 项目周报 | 2026.05.11-05.15', font_size=9, color=GRAY, alignment=PP_ALIGN.RIGHT) # 表格数据 table_data = [ ['模块', '蓝图设计', '技术方案', '功能开发', '功能测试', '整体进度', '状态'], ['S0 运营建模', '4/27-5/6', '5/7-5/13', '5/14-5/27', '5/28-6/3', '45%', '正常'], ['S1 产销协同', '4/27-5/6', '5/7-5/13', '5/14-5/27', '5/28-6/3', '45%', '正常'], ['S2 制造协同', '5/6-5/12', '5/13-5/19', '5/20-6/2', '6/3-6/9', '30%', '正常'], ['S3 供应协同', '5/25-5/29', '6/1-6/5', '6/8-6/22', '6/23-6/29', '0%', '待启动'], ['S4 采购执行', '6/8-6/12', '6/15-6/22', '6/23-7/6', '7/7-7/13', '0%', '待启动'], ['S5 物料仓储', '6/1-6/5', '6/8-6/12', '6/15-6/19', '6/22-6/26', '0%', '待启动'], ['S6 生产执行', '6/15-6/19', '6/22-6/26', '6/29-7/3', '7/6-7/10', '0%', '待启动'], ['S7 成品仓储', '6/22-6/26', '6/29-7/3', '7/6-7/10', '7/13-7/17', '0%', '待启动'], ['S8 异常监控', '5/11-5/22', '5/25-5/29', '6/1-7/3', '7/6-7/10', '15%', '正常'], ['S9 智慧看板', '5/11-5/22', '5/25-5/29', '6/1-7/3', '7/6-7/10', '15%', '正常'], ] add_table(slide4, Inches(0.5), Inches(1.3), Inches(12.3), Inches(4.4), len(table_data), len(table_data[0]), table_data) # 数据库迁移专项 add_text(slide4, Inches(0.8), Inches(5.9), Inches(4), Inches(0.4), '📦 数据库迁移专项 (SQL Server → MySQL)', font_size=14, color=DARK, bold=True) db_data = [ ['任务', '时间', '进度', '状态'], ['数据库模型迁移', '5/8 - 5/15', '100%', '已完成'], ['存储过程重构', '5/11 - 6/12', '20%', '进行中'], ['程序调用迁移', '5/11 - 6/12', '20%', '进行中'], ] add_table(slide4, Inches(0.5), Inches(6.3), Inches(12.3), Inches(0), len(db_data), len(db_data[0]), db_data) # ============================================================ # 第 5 页:交付物时间计划 # ============================================================ slide5 = prs.slides.add_slide(prs.slide_layouts[6]) add_bg(slide5, WHITE) add_rect(slide5, Inches(0), Inches(0), prs.slide_width, Inches(0.08), PRIMARY) add_text(slide5, Inches(0.8), Inches(0.35), Inches(10), Inches(0.6), '交付物时间计划', font_size=28, color=DARK, bold=True) add_text(slide5, Inches(10), Inches(6.9), Inches(3), Inches(0.4), 'Ai-DOP 项目周报 | 2026.05.11-05.15', font_size=9, color=GRAY, alignment=PP_ALIGN.RIGHT) # 根据各模块测试结束日期 + 1 周后的周五计算交付日期 import datetime as _dt def _next_friday_after_one_week(d): one_week = d + _dt.timedelta(days=7) days_to_fri = (4 - one_week.weekday()) % 7 if days_to_fri == 0 and one_week.weekday() != 4: days_to_fri = 7 return one_week + _dt.timedelta(days=days_to_fri) # 交付物数据:(交付物名称, 测试/阶段结束日期) _deliverables = [ ('S0运营建模模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 6, 3)), ('S1产销协同模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 6, 3)), ('S2制造协同模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 6, 9)), ('S3供应协同模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 6, 29)), ('S4采购执行模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 7, 13)), ('S5物料仓储和内物流模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 6, 26)), ('S6生产执行模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 7, 10)), ('S7成品仓储和外物流模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 7, 17)), ('S8全流程即时异常监控模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 7, 10)), ('S9九宫格智慧运营看板模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 7, 10)), ('运营诊断模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 7, 17)), ('运营改善模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 7, 17)), ('ChatBI智能报表模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 7, 17)), ('APP端模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 7, 17)), ('系统集成:《概要设计说明书》《集成测试报告》', _dt.date(2026, 7, 17)), ('UAT集成测试:《UAT测试报告》', _dt.date(2026, 7, 23)), ('系统部署和上线:《验收报告》、《操作手册》、《运维手册》', _dt.date(2026, 7, 31)), ] delivery_data = [['交付物', '测试完成日期', '计划交付日期']] for name, end_date in _deliverables: delivery = _next_friday_after_one_week(end_date) delivery_data.append([ name, end_date.strftime('%m/%d'), delivery.strftime('%m/%d'), ]) delivery_tbl = add_table(slide5, Inches(0.5), Inches(1.2), Inches(12.3), Inches(5.5), len(delivery_data), len(delivery_data[0]), delivery_data, col_widths=[Inches(7.5), Inches(2.4), Inches(2.4)]) # 日期列居中对齐 for row_idx, row in enumerate(delivery_tbl.table.rows): for col_idx in (1, 2): # 测试完成日期、计划交付日期两列 cell = row.cells[col_idx] for paragraph in cell.text_frame.paragraphs: paragraph.alignment = PP_ALIGN.CENTER # ============================================================ # 第 6 页:风险与问题 # ============================================================ slide6 = prs.slides.add_slide(prs.slide_layouts[6]) add_bg(slide6, WHITE) add_rect(slide6, Inches(0), Inches(0), prs.slide_width, Inches(0.08), PRIMARY) add_text(slide6, Inches(0.8), Inches(0.35), Inches(10), Inches(0.6), '关键风险与问题', font_size=28, color=DARK, bold=True) add_text(slide6, Inches(10), Inches(6.9), Inches(3), Inches(0.4), 'Ai-DOP 项目周报 | 2026.05.11-05.15', font_size=9, color=GRAY, alignment=PP_ALIGN.RIGHT) risk_data = [ ['风险项', '影响范围', '严重度', '应对措施', '需支持'], ['', '', '', '', ''], ['', '', '', '', ''], ['', '', '', '', ''], ['', '', '', '', ''], ] tbl = add_table(slide6, Inches(0.5), Inches(1.3), Inches(12.3), Inches(3.5), len(risk_data), len(risk_data[0]), risk_data) # 调整列宽 tbl.table.columns[0].width = Inches(3.0) tbl.table.columns[1].width = Inches(2.2) tbl.table.columns[2].width = Inches(1.0) tbl.table.columns[3].width = Inches(3.5) tbl.table.columns[4].width = Inches(2.6) # ============================================================ # 第 7 页:下周计划 (5/18-5/24) # ============================================================ slide7 = prs.slides.add_slide(prs.slide_layouts[6]) add_bg(slide7, WHITE) add_rect(slide7, Inches(0), Inches(0), prs.slide_width, Inches(0.08), PRIMARY) add_text(slide7, Inches(0.8), Inches(0.35), Inches(10), Inches(0.6), '下周计划(5/18 — 5/24)', font_size=28, color=DARK, bold=True) add_text(slide7, Inches(10), Inches(6.9), Inches(3), Inches(0.4), 'Ai-DOP 项目周报 | 2026.05.11-05.15', font_size=9, color=GRAY, alignment=PP_ALIGN.RIGHT) # 三列:业务开发 / 蓝图设计 / 基础建设 columns = [ ('业务开发 (S0/S1)', ACCENT, [ ('S0 运营建模功能开发', '完成核心建模页面\n及基础 CRUD 接口'), ('S1 产销协同功能开发', '完成产销计划\n编制页面开发'), ]), ('蓝图设计 (S2/S8/S9 + 新增)', WARNING, [ ('S2 技术方案设计', '输出《概要设计说明书》'), ('S8/S9 蓝图收尾', '5/22 前完成\n《业务需求说明书》'), ('运营诊断 · 改善 · ChatBI\n· APP 端蓝图启动', '需求调研 + 启动'), ]), ('平台基建', GRAY, [ ('数据库存储过程重构', '完成率达 40%'), ('数据库程序调用迁移', '完成率达 40%'), ('S3 供应协同准备', '提前熟悉需求,\n5/25 蓝图启动'), ]), ] for i, (title, color, items) in enumerate(columns): x = Inches(0.5 + i * 4.2) add_rect(slide7, x, Inches(1.3), Inches(3.8), Inches(0.5), color) add_text(slide7, x + Inches(0.12), Inches(1.33), Inches(3.5), Inches(0.45), title, font_size=15, color=WHITE, bold=True) y = Inches(2.1) for item_title, item_desc in items: add_text(slide7, x + Inches(0.1), y, Inches(3.5), Inches(0.35), f'▸ {item_title}', font_size=13, color=DARK, bold=True) add_text(slide7, x + Inches(0.25), y + Inches(0.35), Inches(3.3), Inches(0.5), item_desc, font_size=11, color=GRAY) y += Inches(1.1) # ============================================================ # 第 8 页:需协调 / 决策事项 # ============================================================ slide8 = prs.slides.add_slide(prs.slide_layouts[6]) add_bg(slide8, WHITE) add_rect(slide8, Inches(0), Inches(0), prs.slide_width, Inches(0.08), PRIMARY) add_text(slide8, Inches(0.8), Inches(0.35), Inches(10), Inches(0.6), '需要协调 / 决策事项', font_size=28, color=DARK, bold=True) add_text(slide8, Inches(10), Inches(6.9), Inches(3), Inches(0.4), 'Ai-DOP 项目周报 | 2026.05.11-05.15', font_size=9, color=GRAY, alignment=PP_ALIGN.RIGHT) # 决策事项 add_rect(slide8, Inches(0.8), Inches(1.3), Inches(5.5), Inches(0.45), DANGER) add_text(slide8, Inches(0.95), Inches(1.32), Inches(5), Inches(0.4), '📋 需决策', font_size=16, color=WHITE, bold=True) decisions = [ '1. ', '2. ', '3. ', ] for i, d in enumerate(decisions): add_text(slide8, Inches(1.1), Inches(2.0 + i * 0.45), Inches(5), Inches(0.4), d, font_size=13, color=DARK) # 协调事项 add_rect(slide8, Inches(7.0), Inches(1.3), Inches(5.5), Inches(0.45), WARNING) add_text(slide8, Inches(7.15), Inches(1.32), Inches(5), Inches(0.4), '🤝 需协调', font_size=16, color=WHITE, bold=True) coordinations = [ '1. ', '2. ', '3. ', '4. ', ] for i, c in enumerate(coordinations): add_text(slide8, Inches(7.3), Inches(2.0 + i * 0.45), Inches(5), Inches(0.4), c, font_size=13, color=DARK) # ============ 保存 ============ output_path = r'd:\Projects\Ai-DOP\SourceCode\ZZYDOP\doc\ppt\Ai-DOP项目周报_20260511-0515.pptx' prs.save(output_path) print(f'✅ PPT 已生成:{output_path}')