generate_weekly_report.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. """
  2. Ai-DOP 项目周报 PPT 生成脚本
  3. 当前周期:2026.05.11 — 2026.05.15
  4. """
  5. from pptx import Presentation
  6. from pptx.util import Inches, Pt, Emu
  7. from pptx.dml.color import RGBColor
  8. from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
  9. from pptx.enum.shapes import MSO_SHAPE
  10. import datetime
  11. # ============ 配色方案 ============
  12. PRIMARY = RGBColor(0x1A, 0x56, 0xDB) # 深蓝主色
  13. ACCENT = RGBColor(0x10, 0xB9, 0x81) # 绿色-完成
  14. WARNING = RGBColor(0xF5, 0x9E, 0x0B) # 橙色-进行中
  15. DANGER = RGBColor(0xEF, 0x44, 0x44) # 红色-风险
  16. DARK = RGBColor(0x1E, 0x29, 0x3B) # 深色文字
  17. GRAY = RGBColor(0x6B, 0x72, 0x80) # 灰色
  18. LIGHT_BG = RGBColor(0xF8, 0xFA, 0xFC) # 浅灰背景
  19. WHITE = RGBColor(0xFF, 0xFF, 0xFF)
  20. prs = Presentation()
  21. prs.slide_width = Inches(13.333) # 16:9 宽屏
  22. prs.slide_height = Inches(7.5)
  23. def add_bg(slide, color):
  24. """设置幻灯片背景色"""
  25. bg = slide.background
  26. fill = bg.fill
  27. fill.solid()
  28. fill.fore_color.rgb = color
  29. def add_rect(slide, left, top, width, height, color, transparency=0):
  30. """添加矩形色块"""
  31. shape = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, left, top, width, height)
  32. shape.fill.solid()
  33. shape.fill.fore_color.rgb = color
  34. shape.line.fill.background()
  35. return shape
  36. def add_text(slide, left, top, width, height, text, font_size=14, color=DARK, bold=False, alignment=PP_ALIGN.LEFT, font_name='Microsoft YaHei'):
  37. """添加文本框"""
  38. txBox = slide.shapes.add_textbox(left, top, width, height)
  39. tf = txBox.text_frame
  40. tf.word_wrap = True
  41. p = tf.paragraphs[0]
  42. p.text = text
  43. p.font.size = Pt(font_size)
  44. p.font.color.rgb = color
  45. p.font.bold = bold
  46. p.font.name = font_name
  47. p.alignment = alignment
  48. return txBox
  49. def add_table(slide, left, top, width, height, rows, cols, data, col_widths=None):
  50. """添加表格"""
  51. table_shape = slide.shapes.add_table(rows, cols, left, top, width, height)
  52. table = table_shape.table
  53. if col_widths:
  54. for i, w in enumerate(col_widths):
  55. table.columns[i].width = w
  56. for r in range(rows):
  57. for c in range(cols):
  58. cell = table.cell(r, c)
  59. cell.text = str(data[r][c]) if r < len(data) and c < len(data[r]) else ''
  60. for paragraph in cell.text_frame.paragraphs:
  61. paragraph.font.size = Pt(11)
  62. paragraph.font.name = 'Microsoft YaHei'
  63. if r == 0: # 表头
  64. paragraph.font.bold = True
  65. paragraph.font.color.rgb = WHITE
  66. paragraph.font.size = Pt(12)
  67. else:
  68. paragraph.font.color.rgb = DARK
  69. # 表头背景
  70. if r == 0:
  71. cell.fill.solid()
  72. cell.fill.fore_color.rgb = PRIMARY
  73. elif r % 2 == 0:
  74. cell.fill.solid()
  75. cell.fill.fore_color.rgb = LIGHT_BG
  76. return table_shape
  77. def add_module_bar(slide, left, top, width, progress_pct, color=ACCENT):
  78. """添加进度条"""
  79. # 背景条
  80. add_rect(slide, left, top, width, Pt(16), RGBColor(0xE5, 0xE7, 0xEB))
  81. # 进度条
  82. if progress_pct > 0:
  83. add_rect(slide, left, top, int(width * progress_pct / 100), Pt(16), color)
  84. # 百分比文字
  85. add_text(slide, left + width + Pt(6), top - Pt(1), Pt(40), Pt(16),
  86. f'{progress_pct}%', font_size=10, color=GRAY)
  87. # ============================================================
  88. # 第 1 页:封面
  89. # ============================================================
  90. slide1 = prs.slides.add_slide(prs.slide_layouts[6]) # 空白布局
  91. add_bg(slide1, PRIMARY)
  92. # 顶部装饰条
  93. add_rect(slide1, Inches(0), Inches(0), prs.slide_width, Inches(0.08), ACCENT)
  94. # 标题
  95. add_text(slide1, Inches(1.5), Inches(1.8), Inches(10), Inches(1.2),
  96. 'Ai-DOP 企业智慧运营管理平台', font_size=44, color=WHITE, bold=True)
  97. # 副标题
  98. add_text(slide1, Inches(1.5), Inches(2.9), Inches(10), Inches(0.8),
  99. '产互联项目 · 周报', font_size=28, color=RGBColor(0xBF, 0xDB, 0xFE))
  100. # 分隔线
  101. add_rect(slide1, Inches(1.5), Inches(3.9), Inches(3), Inches(0.04), ACCENT)
  102. # 周期信息
  103. add_text(slide1, Inches(1.5), Inches(4.3), Inches(5), Inches(0.5),
  104. '周期:2026.05.11 — 2026.05.15', font_size=18, color=RGBColor(0xBF, 0xDB, 0xFE))
  105. # 右下角信息
  106. add_text(slide1, Inches(1.5), Inches(5.8), Inches(5), Inches(0.4),
  107. '项目整体周期:2026.04.15 — 2026.07.31 | 当前进度约 20%', font_size=14, color=RGBColor(0x93, 0xAD, 0xD6))
  108. add_text(slide1, Inches(9.5), Inches(6.5), Inches(3), Inches(0.4),
  109. '2026.05.15', font_size=12, color=RGBColor(0x93, 0xAD, 0xD6), alignment=PP_ALIGN.RIGHT)
  110. # ============================================================
  111. # 第 2 页:项目整体里程碑
  112. # ============================================================
  113. slide2 = prs.slides.add_slide(prs.slide_layouts[6])
  114. add_bg(slide2, WHITE)
  115. # 页眉
  116. add_rect(slide2, Inches(0), Inches(0), prs.slide_width, Inches(0.08), PRIMARY)
  117. add_text(slide2, Inches(0.8), Inches(0.35), Inches(10), Inches(0.6),
  118. '项目整体里程碑', font_size=28, color=DARK, bold=True)
  119. add_text(slide2, Inches(10), Inches(6.9), Inches(3), Inches(0.4),
  120. 'Ai-DOP 项目周报 | 2026.05.11-05.15', font_size=9, color=GRAY, alignment=PP_ALIGN.RIGHT)
  121. # 里程碑时间轴数据
  122. milestones = [
  123. ('需求沟通\n与项目准备', '04/15 - 04/20', '已完成', ACCENT, 100),
  124. ('项目启动', '04/20 - 04/24', '已完成', ACCENT, 100),
  125. ('功能实现与\n业务模块测试', '04/27 - 07/17', '进行中', WARNING, 15),
  126. ('UAT\n集成测试', '07/17 - 07/28', '待启动', GRAY, 0),
  127. ('系统部署\n与上线', '07/29 - 07/31', '待启动', GRAY, 0),
  128. ]
  129. bar_y = Inches(1.6)
  130. for i, (name, date, status, color, pct) in enumerate(milestones):
  131. x = Inches(1.2 + i * 2.4)
  132. # 阶段卡片
  133. card = add_rect(slide2, x, bar_y, Inches(2.0), Inches(2.8), WHITE)
  134. card.shadow.inherit = False
  135. # 顶部色条
  136. add_rect(slide2, x, bar_y, Inches(2.0), Inches(0.06), color)
  137. add_text(slide2, x + Inches(0.15), bar_y + Inches(0.2), Inches(1.7), Inches(0.8),
  138. name, font_size=14, color=DARK, bold=True)
  139. add_text(slide2, x + Inches(0.15), bar_y + Inches(1.1), Inches(1.7), Inches(0.4),
  140. date, font_size=11, color=GRAY)
  141. add_text(slide2, x + Inches(0.15), bar_y + Inches(1.5), Inches(1.7), Inches(0.4),
  142. status, font_size=13, color=color, bold=True)
  143. # 进度条
  144. add_module_bar(slide2, x + Inches(0.15), bar_y + Inches(2.1), Inches(1.3), pct, color)
  145. # 箭头连接符(除了最后一个)
  146. if i < len(milestones) - 1:
  147. add_text(slide2, x + Inches(2.05), bar_y + Inches(1.1), Inches(0.3), Inches(0.4),
  148. '▶', font_size=16, color=GRAY)
  149. # 关键数据
  150. data_y = Inches(5.0)
  151. add_rect(slide2, Inches(0.8), data_y, Inches(11.7), Inches(0.01), RGBColor(0xE5, 0xE7, 0xEB))
  152. metrics = [
  153. ('15 个', '业务模块'),
  154. ('S0-S9', '业务域覆盖'),
  155. ('3.5 个月', '项目总周期'),
  156. ('20%', '当前总进度'),
  157. ('5/8-6/12', '数据库迁移中'),
  158. ]
  159. for i, (num, label) in enumerate(metrics):
  160. x = Inches(1.0 + i * 2.4)
  161. add_text(slide2, x, data_y + Inches(0.3), Inches(2.0), Inches(0.5),
  162. num, font_size=24, color=PRIMARY, bold=True)
  163. add_text(slide2, x, data_y + Inches(0.8), Inches(2.0), Inches(0.4),
  164. label, font_size=12, color=GRAY)
  165. # ============================================================
  166. # 第 3 页:本周摘要 (5/11-5/17)
  167. # ============================================================
  168. slide3 = prs.slides.add_slide(prs.slide_layouts[6])
  169. add_bg(slide3, WHITE)
  170. add_rect(slide3, Inches(0), Inches(0), prs.slide_width, Inches(0.08), PRIMARY)
  171. add_text(slide3, Inches(0.8), Inches(0.35), Inches(10), Inches(0.6),
  172. '本周核心摘要', font_size=28, color=DARK, bold=True)
  173. add_text(slide3, Inches(10), Inches(6.9), Inches(3), Inches(0.4),
  174. 'Ai-DOP 项目周报 | 2026.05.11-05.15', font_size=9, color=GRAY, alignment=PP_ALIGN.RIGHT)
  175. # 三列布局
  176. col_data = [
  177. ('✅ 本周已完成', ACCENT, [
  178. '数据库模型迁移完成\n(SQL Server → MySQL)',
  179. 'S0/S1 技术方案设计交付',
  180. 'S2 制造协同蓝图设计交付',
  181. 'S8/S9 蓝图设计推进过半',
  182. ]),
  183. ('🔄 持续推进中', WARNING, [
  184. 'S0/S1 功能开发启动',
  185. 'S8 全流程即时异常监控\n蓝图(截止 5/22)',
  186. 'S9 九宫格智慧运营看板\n蓝图(截止 5/22)',
  187. '存储过程重构 + 程序迁移\n(5/11-6/12)',
  188. ]),
  189. ('⚠️ 重点', DANGER, [
  190. '5 月多条线并行\nS0/S1开发 + S2方案 +\nS8/S9蓝图',
  191. ]),
  192. ]
  193. for i, (title, color, items) in enumerate(col_data):
  194. x = Inches(0.7 + i * 4.2)
  195. # 标题
  196. add_rect(slide3, x, Inches(1.3), Inches(3.6), Inches(0.5), color)
  197. add_text(slide3, x + Inches(0.15), Inches(1.32), Inches(3.3), Inches(0.45),
  198. title, font_size=16, color=WHITE, bold=True)
  199. # 条目
  200. y = Inches(2.1)
  201. for item in items:
  202. item_box = add_rect(slide3, x, y, Inches(3.6), Inches(0.82), LIGHT_BG)
  203. add_text(slide3, x + Inches(0.12), y + Inches(0.05), Inches(3.35), Inches(0.72),
  204. f'• {item}', font_size=12, color=DARK)
  205. y += Inches(0.92)
  206. # ============================================================
  207. # 第 4 页:模块进度详情
  208. # ============================================================
  209. slide4 = prs.slides.add_slide(prs.slide_layouts[6])
  210. add_bg(slide4, WHITE)
  211. add_rect(slide4, Inches(0), Inches(0), prs.slide_width, Inches(0.08), PRIMARY)
  212. add_text(slide4, Inches(0.8), Inches(0.35), Inches(10), Inches(0.6),
  213. '各模块进度详情', font_size=28, color=DARK, bold=True)
  214. add_text(slide4, Inches(10), Inches(6.9), Inches(3), Inches(0.4),
  215. 'Ai-DOP 项目周报 | 2026.05.11-05.15', font_size=9, color=GRAY, alignment=PP_ALIGN.RIGHT)
  216. # 表格数据
  217. table_data = [
  218. ['模块', '蓝图设计', '技术方案', '功能开发', '功能测试', '整体进度', '状态'],
  219. ['S0 运营建模', '4/27-5/6', '5/7-5/13', '5/14-5/27', '5/28-6/3', '45%', '正常'],
  220. ['S1 产销协同', '4/27-5/6', '5/7-5/13', '5/14-5/27', '5/28-6/3', '45%', '正常'],
  221. ['S2 制造协同', '5/6-5/12', '5/13-5/19', '5/20-6/2', '6/3-6/9', '30%', '正常'],
  222. ['S3 供应协同', '5/25-5/29', '6/1-6/5', '6/8-6/22', '6/23-6/29', '0%', '待启动'],
  223. ['S4 采购执行', '6/8-6/12', '6/15-6/22', '6/23-7/6', '7/7-7/13', '0%', '待启动'],
  224. ['S5 物料仓储', '6/1-6/5', '6/8-6/12', '6/15-6/19', '6/22-6/26', '0%', '待启动'],
  225. ['S6 生产执行', '6/15-6/19', '6/22-6/26', '6/29-7/3', '7/6-7/10', '0%', '待启动'],
  226. ['S7 成品仓储', '6/22-6/26', '6/29-7/3', '7/6-7/10', '7/13-7/17', '0%', '待启动'],
  227. ['S8 异常监控', '5/11-5/22', '5/25-5/29', '6/1-7/3', '7/6-7/10', '15%', '正常'],
  228. ['S9 智慧看板', '5/11-5/22', '5/25-5/29', '6/1-7/3', '7/6-7/10', '15%', '正常'],
  229. ]
  230. add_table(slide4, Inches(0.5), Inches(1.3), Inches(12.3), Inches(4.4),
  231. len(table_data), len(table_data[0]), table_data)
  232. # 数据库迁移专项
  233. add_text(slide4, Inches(0.8), Inches(5.9), Inches(4), Inches(0.4),
  234. '📦 数据库迁移专项 (SQL Server → MySQL)', font_size=14, color=DARK, bold=True)
  235. db_data = [
  236. ['任务', '时间', '进度', '状态'],
  237. ['数据库模型迁移', '5/8 - 5/15', '100%', '已完成'],
  238. ['存储过程重构', '5/11 - 6/12', '20%', '进行中'],
  239. ['程序调用迁移', '5/11 - 6/12', '20%', '进行中'],
  240. ]
  241. add_table(slide4, Inches(0.5), Inches(6.3), Inches(12.3), Inches(0),
  242. len(db_data), len(db_data[0]), db_data)
  243. # ============================================================
  244. # 第 5 页:交付物时间计划
  245. # ============================================================
  246. slide5 = prs.slides.add_slide(prs.slide_layouts[6])
  247. add_bg(slide5, WHITE)
  248. add_rect(slide5, Inches(0), Inches(0), prs.slide_width, Inches(0.08), PRIMARY)
  249. add_text(slide5, Inches(0.8), Inches(0.35), Inches(10), Inches(0.6),
  250. '交付物时间计划', font_size=28, color=DARK, bold=True)
  251. add_text(slide5, Inches(10), Inches(6.9), Inches(3), Inches(0.4),
  252. 'Ai-DOP 项目周报 | 2026.05.11-05.15', font_size=9, color=GRAY, alignment=PP_ALIGN.RIGHT)
  253. # 根据各模块测试结束日期 + 1 周后的周五计算交付日期
  254. import datetime as _dt
  255. def _next_friday_after_one_week(d):
  256. one_week = d + _dt.timedelta(days=7)
  257. days_to_fri = (4 - one_week.weekday()) % 7
  258. if days_to_fri == 0 and one_week.weekday() != 4:
  259. days_to_fri = 7
  260. return one_week + _dt.timedelta(days=days_to_fri)
  261. # 交付物数据:(交付物名称, 测试/阶段结束日期)
  262. _deliverables = [
  263. ('S0运营建模模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 6, 3)),
  264. ('S1产销协同模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 6, 3)),
  265. ('S2制造协同模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 6, 9)),
  266. ('S3供应协同模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 6, 29)),
  267. ('S4采购执行模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 7, 13)),
  268. ('S5物料仓储和内物流模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 6, 26)),
  269. ('S6生产执行模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 7, 10)),
  270. ('S7成品仓储和外物流模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 7, 17)),
  271. ('S8全流程即时异常监控模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 7, 10)),
  272. ('S9九宫格智慧运营看板模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 7, 10)),
  273. ('运营诊断模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 7, 17)),
  274. ('运营改善模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 7, 17)),
  275. ('ChatBI智能报表模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 7, 17)),
  276. ('APP端模块:《业务需求说明书》《概要设计说明书》《功能测试报告》', _dt.date(2026, 7, 17)),
  277. ('系统集成:《概要设计说明书》《集成测试报告》', _dt.date(2026, 7, 17)),
  278. ('UAT集成测试:《UAT测试报告》', _dt.date(2026, 7, 23)),
  279. ('系统部署和上线:《验收报告》、《操作手册》、《运维手册》', _dt.date(2026, 7, 31)),
  280. ]
  281. delivery_data = [['交付物', '测试完成日期', '计划交付日期']]
  282. for name, end_date in _deliverables:
  283. delivery = _next_friday_after_one_week(end_date)
  284. delivery_data.append([
  285. name,
  286. end_date.strftime('%m/%d'),
  287. delivery.strftime('%m/%d'),
  288. ])
  289. delivery_tbl = add_table(slide5, Inches(0.5), Inches(1.2), Inches(12.3), Inches(5.5),
  290. len(delivery_data), len(delivery_data[0]), delivery_data,
  291. col_widths=[Inches(7.5), Inches(2.4), Inches(2.4)])
  292. # 日期列居中对齐
  293. for row_idx, row in enumerate(delivery_tbl.table.rows):
  294. for col_idx in (1, 2): # 测试完成日期、计划交付日期两列
  295. cell = row.cells[col_idx]
  296. for paragraph in cell.text_frame.paragraphs:
  297. paragraph.alignment = PP_ALIGN.CENTER
  298. # ============================================================
  299. # 第 6 页:风险与问题
  300. # ============================================================
  301. slide6 = prs.slides.add_slide(prs.slide_layouts[6])
  302. add_bg(slide6, WHITE)
  303. add_rect(slide6, Inches(0), Inches(0), prs.slide_width, Inches(0.08), PRIMARY)
  304. add_text(slide6, Inches(0.8), Inches(0.35), Inches(10), Inches(0.6),
  305. '关键风险与问题', font_size=28, color=DARK, bold=True)
  306. add_text(slide6, Inches(10), Inches(6.9), Inches(3), Inches(0.4),
  307. 'Ai-DOP 项目周报 | 2026.05.11-05.15', font_size=9, color=GRAY, alignment=PP_ALIGN.RIGHT)
  308. risk_data = [
  309. ['风险项', '影响范围', '严重度', '应对措施', '需支持'],
  310. ['', '', '', '', ''],
  311. ['', '', '', '', ''],
  312. ['', '', '', '', ''],
  313. ['', '', '', '', ''],
  314. ]
  315. tbl = add_table(slide6, Inches(0.5), Inches(1.3), Inches(12.3), Inches(3.5),
  316. len(risk_data), len(risk_data[0]), risk_data)
  317. # 调整列宽
  318. tbl.table.columns[0].width = Inches(3.0)
  319. tbl.table.columns[1].width = Inches(2.2)
  320. tbl.table.columns[2].width = Inches(1.0)
  321. tbl.table.columns[3].width = Inches(3.5)
  322. tbl.table.columns[4].width = Inches(2.6)
  323. # ============================================================
  324. # 第 7 页:下周计划 (5/18-5/24)
  325. # ============================================================
  326. slide7 = prs.slides.add_slide(prs.slide_layouts[6])
  327. add_bg(slide7, WHITE)
  328. add_rect(slide7, Inches(0), Inches(0), prs.slide_width, Inches(0.08), PRIMARY)
  329. add_text(slide7, Inches(0.8), Inches(0.35), Inches(10), Inches(0.6),
  330. '下周计划(5/18 — 5/24)', font_size=28, color=DARK, bold=True)
  331. add_text(slide7, Inches(10), Inches(6.9), Inches(3), Inches(0.4),
  332. 'Ai-DOP 项目周报 | 2026.05.11-05.15', font_size=9, color=GRAY, alignment=PP_ALIGN.RIGHT)
  333. # 三列:业务开发 / 蓝图设计 / 基础建设
  334. columns = [
  335. ('业务开发 (S0/S1)', ACCENT, [
  336. ('S0 运营建模功能开发', '完成核心建模页面\n及基础 CRUD 接口'),
  337. ('S1 产销协同功能开发', '完成产销计划\n编制页面开发'),
  338. ]),
  339. ('蓝图设计 (S2/S8/S9 + 新增)', WARNING, [
  340. ('S2 技术方案设计', '输出《概要设计说明书》'),
  341. ('S8/S9 蓝图收尾', '5/22 前完成\n《业务需求说明书》'),
  342. ('运营诊断 · 改善 · ChatBI\n· APP 端蓝图启动', '需求调研 + 启动'),
  343. ]),
  344. ('平台基建', GRAY, [
  345. ('数据库存储过程重构', '完成率达 40%'),
  346. ('数据库程序调用迁移', '完成率达 40%'),
  347. ('S3 供应协同准备', '提前熟悉需求,\n5/25 蓝图启动'),
  348. ]),
  349. ]
  350. for i, (title, color, items) in enumerate(columns):
  351. x = Inches(0.5 + i * 4.2)
  352. add_rect(slide7, x, Inches(1.3), Inches(3.8), Inches(0.5), color)
  353. add_text(slide7, x + Inches(0.12), Inches(1.33), Inches(3.5), Inches(0.45),
  354. title, font_size=15, color=WHITE, bold=True)
  355. y = Inches(2.1)
  356. for item_title, item_desc in items:
  357. add_text(slide7, x + Inches(0.1), y, Inches(3.5), Inches(0.35),
  358. f'▸ {item_title}', font_size=13, color=DARK, bold=True)
  359. add_text(slide7, x + Inches(0.25), y + Inches(0.35), Inches(3.3), Inches(0.5),
  360. item_desc, font_size=11, color=GRAY)
  361. y += Inches(1.1)
  362. # ============================================================
  363. # 第 8 页:需协调 / 决策事项
  364. # ============================================================
  365. slide8 = prs.slides.add_slide(prs.slide_layouts[6])
  366. add_bg(slide8, WHITE)
  367. add_rect(slide8, Inches(0), Inches(0), prs.slide_width, Inches(0.08), PRIMARY)
  368. add_text(slide8, Inches(0.8), Inches(0.35), Inches(10), Inches(0.6),
  369. '需要协调 / 决策事项', font_size=28, color=DARK, bold=True)
  370. add_text(slide8, Inches(10), Inches(6.9), Inches(3), Inches(0.4),
  371. 'Ai-DOP 项目周报 | 2026.05.11-05.15', font_size=9, color=GRAY, alignment=PP_ALIGN.RIGHT)
  372. # 决策事项
  373. add_rect(slide8, Inches(0.8), Inches(1.3), Inches(5.5), Inches(0.45), DANGER)
  374. add_text(slide8, Inches(0.95), Inches(1.32), Inches(5), Inches(0.4),
  375. '📋 需决策', font_size=16, color=WHITE, bold=True)
  376. decisions = [
  377. '1. ',
  378. '2. ',
  379. '3. ',
  380. ]
  381. for i, d in enumerate(decisions):
  382. add_text(slide8, Inches(1.1), Inches(2.0 + i * 0.45), Inches(5), Inches(0.4),
  383. d, font_size=13, color=DARK)
  384. # 协调事项
  385. add_rect(slide8, Inches(7.0), Inches(1.3), Inches(5.5), Inches(0.45), WARNING)
  386. add_text(slide8, Inches(7.15), Inches(1.32), Inches(5), Inches(0.4),
  387. '🤝 需协调', font_size=16, color=WHITE, bold=True)
  388. coordinations = [
  389. '1. ',
  390. '2. ',
  391. '3. ',
  392. '4. ',
  393. ]
  394. for i, c in enumerate(coordinations):
  395. add_text(slide8, Inches(7.3), Inches(2.0 + i * 0.45), Inches(5), Inches(0.4),
  396. c, font_size=13, color=DARK)
  397. # ============ 保存 ============
  398. output_path = r'd:\Projects\Ai-DOP\SourceCode\ZZYDOP\doc\ppt\Ai-DOP项目周报_20260511-0515.pptx'
  399. prs.save(output_path)
  400. print(f'✅ PPT 已生成:{output_path}')