_gen_mdp_support_plan_docx.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. """生成《Ai-DOP 数据中台支撑层建设项目方案》Word 文档。"""
  2. from __future__ import annotations
  3. import os
  4. from docx import Document
  5. from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_LINE_SPACING
  6. from docx.oxml.ns import qn
  7. from docx.shared import Cm, Pt, RGBColor
  8. BASE = os.path.dirname(os.path.abspath(__file__))
  9. OUT = os.path.join(BASE, "plan", "Ai-DOP数据中台支撑层建设项目方案.docx")
  10. doc = Document()
  11. sec = doc.sections[0]
  12. sec.page_width = Cm(21.0)
  13. sec.page_height = Cm(29.7)
  14. sec.top_margin = Cm(2.54)
  15. sec.bottom_margin = Cm(2.54)
  16. sec.left_margin = Cm(2.8)
  17. sec.right_margin = Cm(2.8)
  18. def set_run_font(run, name_cn="宋体", name_en="Times New Roman", size=12, bold=False, color=None):
  19. run.font.name = name_en
  20. run._element.rPr.rFonts.set(qn("w:eastAsia"), name_cn)
  21. run.font.size = Pt(size)
  22. run.bold = bold
  23. if color is not None:
  24. run.font.color.rgb = color
  25. def style_normal():
  26. style = doc.styles["Normal"]
  27. style.font.name = "Times New Roman"
  28. style.font.size = Pt(12)
  29. style._element.rPr.rFonts.set(qn("w:eastAsia"), "宋体")
  30. pf = style.paragraph_format
  31. pf.line_spacing_rule = WD_LINE_SPACING.ONE_POINT_FIVE
  32. pf.space_after = Pt(6)
  33. def add_title(text: str):
  34. p = doc.add_paragraph()
  35. p.alignment = WD_ALIGN_PARAGRAPH.CENTER
  36. p.paragraph_format.space_after = Pt(12)
  37. run = p.add_run(text)
  38. set_run_font(run, "黑体", "SimHei", 18, True)
  39. def add_meta(text: str):
  40. p = doc.add_paragraph()
  41. p.alignment = WD_ALIGN_PARAGRAPH.CENTER
  42. p.paragraph_format.space_after = Pt(4)
  43. run = p.add_run(text)
  44. set_run_font(run, "宋体", "Times New Roman", 10.5)
  45. def add_h1(text: str):
  46. p = doc.add_paragraph()
  47. p.paragraph_format.space_before = Pt(14)
  48. p.paragraph_format.space_after = Pt(8)
  49. run = p.add_run(text)
  50. set_run_font(run, "黑体", "SimHei", 14, True)
  51. def add_h2(text: str):
  52. p = doc.add_paragraph()
  53. p.paragraph_format.space_before = Pt(10)
  54. p.paragraph_format.space_after = Pt(6)
  55. run = p.add_run(text)
  56. set_run_font(run, "黑体", "SimHei", 12, True)
  57. def add_body(text: str, indent=True):
  58. p = doc.add_paragraph()
  59. p.paragraph_format.first_line_indent = Pt(24) if indent else Pt(0)
  60. p.paragraph_format.space_after = Pt(6)
  61. run = p.add_run(text)
  62. set_run_font(run, "宋体", "Times New Roman", 12)
  63. def add_bullet(text: str, ordered=False, index=None):
  64. p = doc.add_paragraph()
  65. p.paragraph_format.left_indent = Cm(0.74)
  66. p.paragraph_format.first_line_indent = Pt(0)
  67. p.paragraph_format.space_after = Pt(3)
  68. prefix = f"{index}." if ordered else "•"
  69. run = p.add_run(f"{prefix} {text}")
  70. set_run_font(run, "宋体", "Times New Roman", 12)
  71. def add_table(headers, rows, col_widths=None):
  72. table = doc.add_table(rows=1 + len(rows), cols=len(headers))
  73. table.style = "Table Grid"
  74. table.autofit = True
  75. for i, h in enumerate(headers):
  76. cell = table.rows[0].cells[i]
  77. cell.text = ""
  78. p = cell.paragraphs[0]
  79. p.alignment = WD_ALIGN_PARAGRAPH.CENTER
  80. run = p.add_run(h)
  81. set_run_font(run, "宋体", "Times New Roman", 10.5, True)
  82. # light header fill
  83. tc = cell._tc
  84. tcPr = tc.get_or_add_tcPr()
  85. shd = tcPr.makeelement(qn("w:shd"), {
  86. qn("w:val"): "clear",
  87. qn("w:color"): "auto",
  88. qn("w:fill"): "D9E2F3",
  89. })
  90. tcPr.append(shd)
  91. for r_idx, row in enumerate(rows):
  92. for c_idx, val in enumerate(row):
  93. cell = table.rows[r_idx + 1].cells[c_idx]
  94. cell.text = ""
  95. p = cell.paragraphs[0]
  96. run = p.add_run(str(val))
  97. set_run_font(run, "宋体", "Times New Roman", 10.5)
  98. if c_idx == len(row) - 1 and len(headers) == 2 and "人月" in str(val):
  99. p.alignment = WD_ALIGN_PARAGRAPH.RIGHT
  100. if col_widths:
  101. for row in table.rows:
  102. for i, w in enumerate(col_widths):
  103. row.cells[i].width = Cm(w)
  104. doc.add_paragraph()
  105. style_normal()
  106. add_title("Ai-DOP 数据中台支撑层建设项目方案")
  107. add_meta("文档版本:V3.0  编制日期:2026 年 7 月")
  108. add_meta("适用范围:第一阶段交付")
  109. add_h1("一、项目必要性与价值")
  110. add_body(
  111. "Ai-DOP 业务运行依赖订单、工单、物料、采购、库存、质量等多类数据,"
  112. "这些数据通常来自 ERP、MES、WMS 等外部系统,字段、编码和口径不一致。"
  113. )
  114. add_body("若不建设统一数据中台支撑层,各业务模块分别对接外部系统,将导致:")
  115. for i, t in enumerate(
  116. [
  117. "同一数据重复接入、重复整理。",
  118. "不同模块对同一业务数据口径不一致。",
  119. "外部系统变更时,多个模块需同时改造。",
  120. "数据异常难以定位到具体环节。",
  121. ],
  122. 1,
  123. ):
  124. add_bullet(t, ordered=True, index=i)
  125. add_body(
  126. "本项目建设统一的数据中台支撑层,实现外部系统统一对接、数据统一整理、业务统一消费,"
  127. "并提供基本的任务配置与运行状态查看能力。"
  128. )
  129. add_body("项目价值如下:", indent=True)
  130. add_table(
  131. ["方面", "价值"],
  132. [
  133. ["业务", "为产销、制造、供应、采购、仓储等协同提供一致数据基础"],
  134. ["建设", "减少重复接口与重复整理,新增模块可复用已有数据能力"],
  135. ["运维", "集中配置数据任务,集中查看运行状态与失败原因"],
  136. ],
  137. col_widths=[2.5, 13],
  138. )
  139. add_h1("二、目标与范围")
  140. add_h2("2.1 项目定位")
  141. add_body("本项目在 Ai-DOP 系统内部建设数据中台支撑层,不建设独立软件。")
  142. add_body("沿用 Ai-DOP 现有用户、权限、菜单、数据库、任务调度和部署环境。")
  143. add_h2("2.2 建设目标")
  144. for i, t in enumerate(
  145. [
  146. "支持数据中台与第三方系统对接。",
  147. "支持 Ai-DOP 内部业务正常消费中台数据。",
  148. "提供基本的数据任务配置能力。",
  149. "提供基本的任务运行状态显示能力。",
  150. ],
  151. 1,
  152. ):
  153. add_bullet(t, ordered=True, index=i)
  154. add_h2("2.3 建设范围")
  155. add_body("本阶段包含:")
  156. for i, t in enumerate(
  157. [
  158. "数据中台管理入口。",
  159. "数据来源和数据任务管理。",
  160. "主要业务领域的数据标准化和共享数据服务。",
  161. "数据任务自动运行和人工触发。",
  162. "数据任务运行监控和问题追踪。",
  163. ],
  164. 1,
  165. ):
  166. add_bullet(t, ordered=True, index=i)
  167. add_body("本阶段不包含:")
  168. for i, t in enumerate(
  169. [
  170. "数据中台工作台大屏和数据流向可视化展示。",
  171. "Ai-DOP 各业务模块自身页面、业务流程、业务表单和 BI 展示建设。",
  172. "独立的用户、权限、部署和运维体系。",
  173. "全部历史数据一次性治理。",
  174. "未确认接口资料的外部系统深度联调(可作为条件验收或后续阶段)。",
  175. ],
  176. 1,
  177. ):
  178. add_bullet(t, ordered=True, index=i)
  179. add_h2("2.4 范围边界说明")
  180. add_table(
  181. ["类型", "说明"],
  182. [
  183. ["第三方对接", "支持数据库直连和 API 两种接入方式;具体对接对象以双方确认清单为准"],
  184. ["内部消费", "以双方确认的业务模块为主,保证可从中台标准数据取数使用"],
  185. ["任务配置", "支持任务、关联对象、调度策略的配置与维护"],
  186. ["状态显示", "支持查看任务最近运行状态、处理数量和失败原因"],
  187. ],
  188. col_widths=[3, 12.5],
  189. )
  190. add_h1("三、主要建设内容")
  191. add_h2("3.1 数据中台管理入口")
  192. add_body("在 Ai-DOP 中提供数据中台管理菜单和功能入口,统一进入数据来源、任务配置和运行监控相关功能。")
  193. add_h2("3.2 数据来源和数据任务管理")
  194. add_body("集中管理接入 Ai-DOP 的数据来源和数据任务,包括:")
  195. for t in [
  196. "数据来源名称、类型和用途",
  197. "数据任务名称、业务范围和启用状态",
  198. "数据任务服务的业务模块",
  199. "数据任务与定时计划的关联",
  200. "数据对象及关键字段对应关系",
  201. ]:
  202. add_bullet(t)
  203. add_h2("3.3 业务数据标准化和共享服务")
  204. add_body("对来自不同系统的数据进行统一整理,重点覆盖:")
  205. for t in [
  206. "销售订单和交付数据",
  207. "工单、工序和排程数据",
  208. "物料、供应商和采购数据",
  209. "送货、收货、检验和退货数据",
  210. "原材料、在制品和成品库存数据",
  211. "生产执行和质量相关数据",
  212. ]:
  213. add_bullet(t)
  214. add_body("整理后形成可供业务页面、跨模块协同、异常监控和运营指标使用的标准数据服务。")
  215. add_h2("3.4 数据任务运行")
  216. add_body("复用 Ai-DOP 现有任务调度能力,实现:")
  217. for t in [
  218. "数据任务按计划自动运行",
  219. "必要时人工触发",
  220. "记录最近运行时间和状态",
  221. "记录处理数量、运行时长和失败原因",
  222. ]:
  223. add_bullet(t)
  224. add_h2("3.5 运行监控和问题追踪")
  225. add_body("提供统一的数据任务监控入口,支持:")
  226. for t in [
  227. "按任务、状态和时间查询",
  228. "查看运行结果和处理数量",
  229. "查看失败原因",
  230. "按批次定位数据处理问题",
  231. ]:
  232. add_bullet(t)
  233. add_h1("四、成本评估")
  234. add_h2("4.1 项目团队")
  235. add_table(
  236. ["角色", "主要职责"],
  237. [
  238. ["项目经理", "计划、协调、范围和交付管理"],
  239. ["产品/实施顾问", "业务梳理、口径确认和用户沟通"],
  240. ["数据工程师", "数据盘点、标准化、数据整理和核对"],
  241. ["后端开发工程师", "对接任务、共享服务和运行监控"],
  242. ["前端开发工程师", "管理入口、任务配置和状态显示界面"],
  243. ["测试工程师", "功能测试、数据核对和验收支持"],
  244. ["运维工程师", "环境、部署、调度和运行保障"],
  245. ],
  246. col_widths=[4, 11.5],
  247. )
  248. add_h2("4.2 工作量估算")
  249. add_body("工作量按本阶段功能建设测算,合计控制在 12 人月以内。下表仅列功能项,不含需求评估、测试、上线等项目事务性工作。")
  250. add_table(
  251. ["功能项", "参考工作量"],
  252. [
  253. ["数据中台管理入口", "0.5—1 人月"],
  254. ["数据来源与任务管理", "1.5—2.5 人月"],
  255. ["业务数据标准化和共享服务", "5—6.5 人月"],
  256. ["数据任务运行(自动运行与人工触发)", "1—1.5 人月"],
  257. ["运行监控和问题追踪", "1—1.5 人月"],
  258. ["合计", "9—12 人月"],
  259. ],
  260. col_widths=[11, 4.5],
  261. )
  262. add_h2("4.3 成本影响因素")
  263. for t in [
  264. "接入系统和数据来源数量",
  265. "外部系统接口资料完整程度",
  266. "历史数据质量和数据量",
  267. "业务口径确认难度",
  268. "第三方厂商配合程度",
  269. "是否需要现场实施、专线或额外安全措施",
  270. ]:
  271. add_bullet(t)
  272. add_body("具体商务报价根据最终确认的数据来源、业务范围和实施条件确定。")
  273. add_h1("五、项目计划")
  274. add_body("建议项目周期为 10—14 周。")
  275. add_table(
  276. ["阶段", "参考周期", "主要成果"],
  277. [
  278. ["范围确认与数据盘点", "2—3 周", "数据来源、任务、口径和验收清单"],
  279. ["基础能力建设", "2—3 周", "管理入口、任务配置、调度接入、基础监控"],
  280. ["业务数据接入", "4—6 周", "主要业务数据标准化和共享服务"],
  281. ["联调与验收", "2—3 周", "数据核对、测试报告、操作及运维资料"],
  282. ],
  283. col_widths=[4.5, 2.5, 8.5],
  284. )
  285. add_body("如外部系统接口、测试数据或业务口径确认延迟,项目计划相应调整。")
  286. add_h1("六、交付与验收")
  287. add_h2("6.1 系统交付")
  288. for i, t in enumerate(
  289. [
  290. "集成在 Ai-DOP 内的数据中台管理入口。",
  291. "数据来源和数据任务管理功能。",
  292. "主要业务领域的数据标准化和共享数据服务。",
  293. "数据任务自动运行和人工触发能力。",
  294. "数据任务运行监控和问题追踪功能。",
  295. ],
  296. 1,
  297. ):
  298. add_bullet(t, ordered=True, index=i)
  299. add_h2("6.2 文档交付")
  300. for i, t in enumerate(
  301. [
  302. "数据中台支撑层建设方案",
  303. "数据来源和数据任务清单",
  304. "主要业务数据标准说明",
  305. "部署和配置说明",
  306. "用户操作及运维说明",
  307. "测试和数据核对报告",
  308. "项目验收报告",
  309. ],
  310. 1,
  311. ):
  312. add_bullet(t, ordered=True, index=i)
  313. add_h2("6.3 验收原则")
  314. for i, t in enumerate(
  315. [
  316. "以双方确认的数据来源、数据任务和业务范围为依据。",
  317. "主要数据任务能够按计划运行或人工触发。",
  318. "能够查看任务运行状态、处理数量和错误信息。",
  319. "主要业务数据按确认口径完成整理,并通过抽样核对。",
  320. "确认范围内的业务模块能够正常使用中台数据。",
  321. "因外部系统不可用、源数据缺失或第三方接口变化产生的问题,先确认责任边界。",
  322. "不以全部历史数据一次性完全一致作为验收前提,差异可解释并有处理意见即可。",
  323. ],
  324. 1,
  325. ):
  326. add_bullet(t, ordered=True, index=i)
  327. os.makedirs(os.path.dirname(OUT), exist_ok=True)
  328. doc.save(OUT)
  329. print(OUT)