| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378 |
- """生成《Ai-DOP 数据中台支撑层建设项目方案》Word 文档。"""
- from __future__ import annotations
- import os
- from docx import Document
- from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_LINE_SPACING
- from docx.oxml.ns import qn
- from docx.shared import Cm, Pt, RGBColor
- BASE = os.path.dirname(os.path.abspath(__file__))
- OUT = os.path.join(BASE, "plan", "Ai-DOP数据中台支撑层建设项目方案.docx")
- doc = Document()
- sec = doc.sections[0]
- sec.page_width = Cm(21.0)
- sec.page_height = Cm(29.7)
- sec.top_margin = Cm(2.54)
- sec.bottom_margin = Cm(2.54)
- sec.left_margin = Cm(2.8)
- sec.right_margin = Cm(2.8)
- def set_run_font(run, name_cn="宋体", name_en="Times New Roman", size=12, bold=False, color=None):
- run.font.name = name_en
- run._element.rPr.rFonts.set(qn("w:eastAsia"), name_cn)
- run.font.size = Pt(size)
- run.bold = bold
- if color is not None:
- run.font.color.rgb = color
- def style_normal():
- style = doc.styles["Normal"]
- style.font.name = "Times New Roman"
- style.font.size = Pt(12)
- style._element.rPr.rFonts.set(qn("w:eastAsia"), "宋体")
- pf = style.paragraph_format
- pf.line_spacing_rule = WD_LINE_SPACING.ONE_POINT_FIVE
- pf.space_after = Pt(6)
- def add_title(text: str):
- p = doc.add_paragraph()
- p.alignment = WD_ALIGN_PARAGRAPH.CENTER
- p.paragraph_format.space_after = Pt(12)
- run = p.add_run(text)
- set_run_font(run, "黑体", "SimHei", 18, True)
- def add_meta(text: str):
- p = doc.add_paragraph()
- p.alignment = WD_ALIGN_PARAGRAPH.CENTER
- p.paragraph_format.space_after = Pt(4)
- run = p.add_run(text)
- set_run_font(run, "宋体", "Times New Roman", 10.5)
- def add_h1(text: str):
- p = doc.add_paragraph()
- p.paragraph_format.space_before = Pt(14)
- p.paragraph_format.space_after = Pt(8)
- run = p.add_run(text)
- set_run_font(run, "黑体", "SimHei", 14, True)
- def add_h2(text: str):
- p = doc.add_paragraph()
- p.paragraph_format.space_before = Pt(10)
- p.paragraph_format.space_after = Pt(6)
- run = p.add_run(text)
- set_run_font(run, "黑体", "SimHei", 12, True)
- def add_body(text: str, indent=True):
- p = doc.add_paragraph()
- p.paragraph_format.first_line_indent = Pt(24) if indent else Pt(0)
- p.paragraph_format.space_after = Pt(6)
- run = p.add_run(text)
- set_run_font(run, "宋体", "Times New Roman", 12)
- def add_bullet(text: str, ordered=False, index=None):
- p = doc.add_paragraph()
- p.paragraph_format.left_indent = Cm(0.74)
- p.paragraph_format.first_line_indent = Pt(0)
- p.paragraph_format.space_after = Pt(3)
- prefix = f"{index}." if ordered else "•"
- run = p.add_run(f"{prefix} {text}")
- set_run_font(run, "宋体", "Times New Roman", 12)
- def add_table(headers, rows, col_widths=None):
- table = doc.add_table(rows=1 + len(rows), cols=len(headers))
- table.style = "Table Grid"
- table.autofit = True
- for i, h in enumerate(headers):
- cell = table.rows[0].cells[i]
- cell.text = ""
- p = cell.paragraphs[0]
- p.alignment = WD_ALIGN_PARAGRAPH.CENTER
- run = p.add_run(h)
- set_run_font(run, "宋体", "Times New Roman", 10.5, True)
- # light header fill
- tc = cell._tc
- tcPr = tc.get_or_add_tcPr()
- shd = tcPr.makeelement(qn("w:shd"), {
- qn("w:val"): "clear",
- qn("w:color"): "auto",
- qn("w:fill"): "D9E2F3",
- })
- tcPr.append(shd)
- for r_idx, row in enumerate(rows):
- for c_idx, val in enumerate(row):
- cell = table.rows[r_idx + 1].cells[c_idx]
- cell.text = ""
- p = cell.paragraphs[0]
- run = p.add_run(str(val))
- set_run_font(run, "宋体", "Times New Roman", 10.5)
- if c_idx == len(row) - 1 and len(headers) == 2 and "人月" in str(val):
- p.alignment = WD_ALIGN_PARAGRAPH.RIGHT
- if col_widths:
- for row in table.rows:
- for i, w in enumerate(col_widths):
- row.cells[i].width = Cm(w)
- doc.add_paragraph()
- style_normal()
- add_title("Ai-DOP 数据中台支撑层建设项目方案")
- add_meta("文档版本:V3.0 编制日期:2026 年 7 月")
- add_meta("适用范围:第一阶段交付")
- add_h1("一、项目必要性与价值")
- add_body(
- "Ai-DOP 业务运行依赖订单、工单、物料、采购、库存、质量等多类数据,"
- "这些数据通常来自 ERP、MES、WMS 等外部系统,字段、编码和口径不一致。"
- )
- add_body("若不建设统一数据中台支撑层,各业务模块分别对接外部系统,将导致:")
- for i, t in enumerate(
- [
- "同一数据重复接入、重复整理。",
- "不同模块对同一业务数据口径不一致。",
- "外部系统变更时,多个模块需同时改造。",
- "数据异常难以定位到具体环节。",
- ],
- 1,
- ):
- add_bullet(t, ordered=True, index=i)
- add_body(
- "本项目建设统一的数据中台支撑层,实现外部系统统一对接、数据统一整理、业务统一消费,"
- "并提供基本的任务配置与运行状态查看能力。"
- )
- add_body("项目价值如下:", indent=True)
- add_table(
- ["方面", "价值"],
- [
- ["业务", "为产销、制造、供应、采购、仓储等协同提供一致数据基础"],
- ["建设", "减少重复接口与重复整理,新增模块可复用已有数据能力"],
- ["运维", "集中配置数据任务,集中查看运行状态与失败原因"],
- ],
- col_widths=[2.5, 13],
- )
- add_h1("二、目标与范围")
- add_h2("2.1 项目定位")
- add_body("本项目在 Ai-DOP 系统内部建设数据中台支撑层,不建设独立软件。")
- add_body("沿用 Ai-DOP 现有用户、权限、菜单、数据库、任务调度和部署环境。")
- add_h2("2.2 建设目标")
- for i, t in enumerate(
- [
- "支持数据中台与第三方系统对接。",
- "支持 Ai-DOP 内部业务正常消费中台数据。",
- "提供基本的数据任务配置能力。",
- "提供基本的任务运行状态显示能力。",
- ],
- 1,
- ):
- add_bullet(t, ordered=True, index=i)
- add_h2("2.3 建设范围")
- add_body("本阶段包含:")
- for i, t in enumerate(
- [
- "数据中台管理入口。",
- "数据来源和数据任务管理。",
- "主要业务领域的数据标准化和共享数据服务。",
- "数据任务自动运行和人工触发。",
- "数据任务运行监控和问题追踪。",
- ],
- 1,
- ):
- add_bullet(t, ordered=True, index=i)
- add_body("本阶段不包含:")
- for i, t in enumerate(
- [
- "数据中台工作台大屏和数据流向可视化展示。",
- "Ai-DOP 各业务模块自身页面、业务流程、业务表单和 BI 展示建设。",
- "独立的用户、权限、部署和运维体系。",
- "全部历史数据一次性治理。",
- "未确认接口资料的外部系统深度联调(可作为条件验收或后续阶段)。",
- ],
- 1,
- ):
- add_bullet(t, ordered=True, index=i)
- add_h2("2.4 范围边界说明")
- add_table(
- ["类型", "说明"],
- [
- ["第三方对接", "支持数据库直连和 API 两种接入方式;具体对接对象以双方确认清单为准"],
- ["内部消费", "以双方确认的业务模块为主,保证可从中台标准数据取数使用"],
- ["任务配置", "支持任务、关联对象、调度策略的配置与维护"],
- ["状态显示", "支持查看任务最近运行状态、处理数量和失败原因"],
- ],
- col_widths=[3, 12.5],
- )
- add_h1("三、主要建设内容")
- add_h2("3.1 数据中台管理入口")
- add_body("在 Ai-DOP 中提供数据中台管理菜单和功能入口,统一进入数据来源、任务配置和运行监控相关功能。")
- add_h2("3.2 数据来源和数据任务管理")
- add_body("集中管理接入 Ai-DOP 的数据来源和数据任务,包括:")
- for t in [
- "数据来源名称、类型和用途",
- "数据任务名称、业务范围和启用状态",
- "数据任务服务的业务模块",
- "数据任务与定时计划的关联",
- "数据对象及关键字段对应关系",
- ]:
- add_bullet(t)
- add_h2("3.3 业务数据标准化和共享服务")
- add_body("对来自不同系统的数据进行统一整理,重点覆盖:")
- for t in [
- "销售订单和交付数据",
- "工单、工序和排程数据",
- "物料、供应商和采购数据",
- "送货、收货、检验和退货数据",
- "原材料、在制品和成品库存数据",
- "生产执行和质量相关数据",
- ]:
- add_bullet(t)
- add_body("整理后形成可供业务页面、跨模块协同、异常监控和运营指标使用的标准数据服务。")
- add_h2("3.4 数据任务运行")
- add_body("复用 Ai-DOP 现有任务调度能力,实现:")
- for t in [
- "数据任务按计划自动运行",
- "必要时人工触发",
- "记录最近运行时间和状态",
- "记录处理数量、运行时长和失败原因",
- ]:
- add_bullet(t)
- add_h2("3.5 运行监控和问题追踪")
- add_body("提供统一的数据任务监控入口,支持:")
- for t in [
- "按任务、状态和时间查询",
- "查看运行结果和处理数量",
- "查看失败原因",
- "按批次定位数据处理问题",
- ]:
- add_bullet(t)
- add_h1("四、成本评估")
- add_h2("4.1 项目团队")
- add_table(
- ["角色", "主要职责"],
- [
- ["项目经理", "计划、协调、范围和交付管理"],
- ["产品/实施顾问", "业务梳理、口径确认和用户沟通"],
- ["数据工程师", "数据盘点、标准化、数据整理和核对"],
- ["后端开发工程师", "对接任务、共享服务和运行监控"],
- ["前端开发工程师", "管理入口、任务配置和状态显示界面"],
- ["测试工程师", "功能测试、数据核对和验收支持"],
- ["运维工程师", "环境、部署、调度和运行保障"],
- ],
- col_widths=[4, 11.5],
- )
- add_h2("4.2 工作量估算")
- add_body("工作量按本阶段功能建设测算,合计控制在 12 人月以内。下表仅列功能项,不含需求评估、测试、上线等项目事务性工作。")
- add_table(
- ["功能项", "参考工作量"],
- [
- ["数据中台管理入口", "0.5—1 人月"],
- ["数据来源与任务管理", "1.5—2.5 人月"],
- ["业务数据标准化和共享服务", "5—6.5 人月"],
- ["数据任务运行(自动运行与人工触发)", "1—1.5 人月"],
- ["运行监控和问题追踪", "1—1.5 人月"],
- ["合计", "9—12 人月"],
- ],
- col_widths=[11, 4.5],
- )
- add_h2("4.3 成本影响因素")
- for t in [
- "接入系统和数据来源数量",
- "外部系统接口资料完整程度",
- "历史数据质量和数据量",
- "业务口径确认难度",
- "第三方厂商配合程度",
- "是否需要现场实施、专线或额外安全措施",
- ]:
- add_bullet(t)
- add_body("具体商务报价根据最终确认的数据来源、业务范围和实施条件确定。")
- add_h1("五、项目计划")
- add_body("建议项目周期为 10—14 周。")
- add_table(
- ["阶段", "参考周期", "主要成果"],
- [
- ["范围确认与数据盘点", "2—3 周", "数据来源、任务、口径和验收清单"],
- ["基础能力建设", "2—3 周", "管理入口、任务配置、调度接入、基础监控"],
- ["业务数据接入", "4—6 周", "主要业务数据标准化和共享服务"],
- ["联调与验收", "2—3 周", "数据核对、测试报告、操作及运维资料"],
- ],
- col_widths=[4.5, 2.5, 8.5],
- )
- add_body("如外部系统接口、测试数据或业务口径确认延迟,项目计划相应调整。")
- add_h1("六、交付与验收")
- add_h2("6.1 系统交付")
- for i, t in enumerate(
- [
- "集成在 Ai-DOP 内的数据中台管理入口。",
- "数据来源和数据任务管理功能。",
- "主要业务领域的数据标准化和共享数据服务。",
- "数据任务自动运行和人工触发能力。",
- "数据任务运行监控和问题追踪功能。",
- ],
- 1,
- ):
- add_bullet(t, ordered=True, index=i)
- add_h2("6.2 文档交付")
- for i, t in enumerate(
- [
- "数据中台支撑层建设方案",
- "数据来源和数据任务清单",
- "主要业务数据标准说明",
- "部署和配置说明",
- "用户操作及运维说明",
- "测试和数据核对报告",
- "项目验收报告",
- ],
- 1,
- ):
- add_bullet(t, ordered=True, index=i)
- add_h2("6.3 验收原则")
- for i, t in enumerate(
- [
- "以双方确认的数据来源、数据任务和业务范围为依据。",
- "主要数据任务能够按计划运行或人工触发。",
- "能够查看任务运行状态、处理数量和错误信息。",
- "主要业务数据按确认口径完成整理,并通过抽样核对。",
- "确认范围内的业务模块能够正常使用中台数据。",
- "因外部系统不可用、源数据缺失或第三方接口变化产生的问题,先确认责任边界。",
- "不以全部历史数据一次性完全一致作为验收前提,差异可解释并有处理意见即可。",
- ],
- 1,
- ):
- add_bullet(t, ordered=True, index=i)
- os.makedirs(os.path.dirname(OUT), exist_ok=True)
- doc.save(OUT)
- print(OUT)
|