_bid_extract_figs.py 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. # -*- coding: utf-8 -*-
  2. """从各模块蓝图设计方案中抽取主线流程图,存到 doc/_bid_assets/ 供技术方案引用。"""
  3. import os
  4. import shutil
  5. import sys
  6. import tempfile
  7. sys.stdout.reconfigure(encoding="utf-8", errors="replace")
  8. from docx import Document
  9. from docx.oxml.ns import qn
  10. ROOT = r"C:\Users\skygu\OneDrive\Projects\AIDOP\项目\项目管理\产互联项目管理\交付文档"
  11. ASSETS = os.path.join(os.path.dirname(os.path.abspath(__file__)), "_bid_assets")
  12. os.makedirs(ASSETS, exist_ok=True)
  13. # (蓝图相对路径, 图序号(1起), 输出名, 说明)
  14. PICKS = [
  15. ("S0/S0-基础主数据建模-业务蓝图设计方案-V0.2.docx", 1, "s0_master_dataflow",
  16. "S0 主数据与下游 S1–S9 数据流关系"),
  17. ("S1/S1产销协同模块蓝图设计方案.docx", 1, "s1_otd_mainline",
  18. "S1 产销协同 订单履约全链路主线流程"),
  19. ("S1/S1产销协同模块蓝图设计方案.docx", 3, "s1_order_delivery",
  20. "S1 订单交付 8Tab 全景追踪流程"),
  21. ("S1/S1产销协同模块蓝图设计方案.docx", 8, "s1_kanban",
  22. "S1 产销协同看板 L1–L4 指标下钻"),
  23. ("S2/S2制造协同模块蓝图设计方案.docx", 1, "s2_plan_to_exec",
  24. "S2 制造协同 排程到执行主线流程"),
  25. ("S3/S3供应协同模块蓝图设计方案.docx", 1, "s3_domains",
  26. "S3 供应协同 物料计划/采购管理/协同看板三域关系"),
  27. ("S3/S3供应协同模块蓝图设计方案.docx", 11, "s3_shortage",
  28. "S3 齐套计算与缺料预警流程"),
  29. ("S4/S4采购执行模块蓝图设计方案.docx", 1, "s4_domains",
  30. "S4 采购执行 交货执行/退货闭环/执行看板三域关系"),
  31. ("S5/S5-物料仓储-业务蓝图设计方案.docx", 1, "s5_lifecycle",
  32. "S5 物料仓储 贴源同步只读生命周期"),
  33. ("S6/S6-生产执行-业务蓝图设计方案.docx", 1, "s6_ipqc",
  34. "S6 生产执行 贴源同步与 IPQC 检验流转"),
  35. ("S7/S7-成品仓储-业务蓝图设计方案.docx", 1, "s7_lifecycle",
  36. "S7 成品仓储 贴源同步只读生命周期"),
  37. ]
  38. tmpdir = tempfile.mkdtemp()
  39. cache = {}
  40. manifest = []
  41. for rel, idx, name, desc in PICKS:
  42. src = os.path.join(ROOT, rel.replace("/", os.sep))
  43. if src not in cache:
  44. local = os.path.join(tmpdir, os.path.basename(src))
  45. shutil.copy2(src, local)
  46. cache[src] = Document(local)
  47. doc = cache[src]
  48. found = 0
  49. blob = ext = None
  50. for p in doc.paragraphs:
  51. for blip in p._p.findall(".//" + qn("a:blip")):
  52. found += 1
  53. if found == idx:
  54. rid = blip.get(qn("r:embed"))
  55. part = doc.part.related_parts[rid]
  56. blob = part.blob
  57. ext = os.path.splitext(str(part.partname))[1] or ".png"
  58. break
  59. if blob is not None:
  60. break
  61. if blob is None:
  62. print(f" [缺] {rel} 第 {idx} 张图未找到")
  63. continue
  64. out = os.path.join(ASSETS, name + ext)
  65. with open(out, "wb") as f:
  66. f.write(blob)
  67. manifest.append((name + ext, len(blob) // 1024, desc, rel))
  68. print(f" [OK] {name + ext:<28} {len(blob) // 1024:>6} KB {desc}")
  69. shutil.rmtree(tmpdir, ignore_errors=True)
  70. with open(os.path.join(ASSETS, "_manifest.txt"), "w", encoding="utf-8") as f:
  71. for n, kb, d, r in manifest:
  72. f.write(f"{n}\t{kb}KB\t{d}\t来源:{r}\n")
  73. print(f"\n共抽取 {len(manifest)} 张 -> {ASSETS}")