| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- # -*- coding: utf-8 -*-
- """生成《附件五 技术方案》《附件六 实施与服务方案》各章 Word(格式自拟部分)。
- 用法:
- python doc/_gen_bid_tech.py 生成全部已就绪章节(单章成文)
- python doc/_gen_bid_tech.py 五2 六1 只生成指定章节
- python doc/_gen_bid_tech.py --merge 生成并入响应文件用的改号版,
- 输出到 _bid_merge_parts/
- """
- import importlib
- import os
- import re
- import shutil
- import sys
- sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
- import _bid_docx_kit as kit # noqa: E402
- from _bid_docx_kit import Counter, h1, new_doc, para, render # noqa: E402
- HERE = os.path.dirname(os.path.abspath(__file__))
- SYNC_DIR = r"C:\Users\skygu\OneDrive\Projects\AIDOP\项目\项目招投标"
- MERGE_DIR = os.path.join(HERE, "_bid_merge_parts")
- # (附件, 章号, 章标题, 分值, 内容模块, 模块内变量名, 并入后的六(三)序号)
- CHAPTERS = [
- ("五", 1, "项目需求理解及综合分析", 9, ("_bid_ch1_a", "_bid_ch1_b"),
- ("BLOCKS_A", "BLOCKS_B"), 4),
- ("五", 2, "系统功能展示", 6, ("_bid_ch2",), ("BLOCKS_CH2",), 5),
- ("五", 3, "系统建设方案", 3, ("_bid_ch3",), ("BLOCKS_CH3",), 6),
- ("五", 4, "智能诊断与分析方案", 3, ("_bid_ch4",), ("BLOCKS_CH4",), 7),
- ("五", 5, "UAT 测试与质量保障", 3, ("_bid_ch5",), ("BLOCKS_CH5",), 8),
- ("六", 1, "质量与工期保障", 2, ("_bid_att6",), ("BLOCKS_CH6",), 9),
- ("六", 2, "应急支撑方案", 2, ("_bid_att6",), ("BLOCKS_CH7",), 10),
- ("六", 3, "售后服务方案", 3, ("_bid_att6",), ("BLOCKS_CH8",), 11),
- ("六", 4, "项目培训方案", 3, ("_bid_att6",), ("BLOCKS_CH9",), 12),
- ]
- # 并入总册后的大纲级别(0 起算):章标题→3 级,小节→4 级,
- # 更细的层次压到 5、6 级,使总目录只显示到「x.y」。
- MERGE_OUTLINE = {1: 2, 2: 3, 3: 4, 4: 5}
- LEAD = {
- ("五", 1): "本章依据询比文件第五章采购需求与评审办法中技术部分“项目需求理解及综合分析”"
- "的评分要素编写,逐一阐述我方对项目现状、应用环境、体系结构需求、功能需求、"
- "性能要求、实施要求的理解,对制造业核心业务场景、智能诊断场景、闭环管理逻辑与"
- "数据分析需求的理解,并在此基础上输出本项目的总体设计蓝图。",
- }
- PH = re.compile(r"【[^】]*】|待填|TODO|待补|xxx|XXX")
- def _flatten(x):
- if isinstance(x, (list, tuple)):
- for i in x:
- yield from _flatten(i)
- elif x is not None:
- yield x
- def check(blocks):
- bad = []
- for kind, payload in blocks:
- text = " ".join(str(s) for s in _flatten(payload))
- for m in PH.finditer(text):
- bad.append((kind, m.group(0), text[:48]))
- return bad
- def stats(doc):
- n = sum(len(p.text) for p in doc.paragraphs)
- for tb in doc.tables:
- for row in tb.rows:
- for c in row.cells:
- n += len(c.text)
- return n
- def build(entry, merge=False):
- att, no, title, score, mods, names, mno = entry
- blocks = []
- for mod, var in zip(mods, names):
- try:
- m = importlib.import_module(mod)
- except ModuleNotFoundError:
- return None
- blocks += getattr(m, var)
- bad = check(blocks)
- if bad:
- for kind, tok, ctx in bad:
- print(f" !残留占位 {tok!r} [{kind}] {ctx}")
- raise SystemExit(f"附件{att}第 {no} 章存在未填写内容,已中止")
- # 改号与大纲级别只影响并入总册的那一份,单章成文的编号保持原样
- kit.set_renum(no if merge else None, mno)
- kit.set_outline(MERGE_OUTLINE if merge else None)
- doc = new_doc()
- cnt = Counter(chapter=mno if merge else no)
- h1(doc, f"{mno}、{title}" if merge else f"第 {no} 章 {title}")
- lead = LEAD.get((att, no))
- if lead:
- para(doc, lead)
- render(doc, cnt, blocks)
- kit.set_renum(None, None)
- kit.set_outline(None)
- kind = "技术方案" if att == "五" else "实施与服务方案"
- if merge:
- os.makedirs(MERGE_DIR, exist_ok=True)
- out = os.path.join(MERGE_DIR, f"六3-{mno:02d} {title}.docx")
- else:
- out = os.path.join(HERE, f"附件{att}-{kind}-第{no}章 {title}.docx")
- doc.save(out)
- tag = f"六(三){mno}、" if merge else f"第{no}章 "
- print(f"[完成] {tag}{title}({score} 分)"
- f" 约 {stats(doc):,} 字 图 {cnt.fig} 张 表 {cnt.tbl} 张")
- if not merge and os.path.isdir(SYNC_DIR):
- shutil.copy2(out, os.path.join(SYNC_DIR, os.path.basename(out)))
- return out
- def main():
- args = sys.argv[1:]
- merge = "--merge" in args
- want = [a for a in args if a != "--merge"]
- done = skipped = 0
- for e in CHAPTERS:
- tag = f"{e[0]}{e[1]}"
- if want and tag not in want:
- continue
- if build(e, merge=merge) is None:
- print(f"[待写] 附件{e[0]} 第{e[1]}章 {e[2]}({e[3]} 分)")
- skipped += 1
- else:
- done += 1
- mode = "并入版" if merge else "单章版"
- print(f"\n生成 {done} 章({mode}),待写 {skipped} 章")
- if __name__ == "__main__":
- main()
|