# -*- coding: utf-8 -*- import json import os from datetime import date from docx import Document from docx.shared import Inches, Pt, RGBColor from docx.enum.text import WD_ALIGN_PARAGRAPH from docx.oxml.ns import qn from PIL import Image HERE = os.path.dirname(os.path.abspath(__file__)) ROOT = os.path.abspath(os.path.join(HERE, "..", "..")) SHOTS = os.path.join(ROOT, "shots") OUT = os.path.join(ROOT, "滨化智慧招标平台-前端界面截图汇总.docx") BRAND = RGBColor(0x15, 0x65, 0xC0) BRAND_HEX = "1565C0" PAGE_W_IN = 6.3 with open(os.path.join(SHOTS, "manifest.json"), "r", encoding="utf-8") as f: manifest = json.load(f) order = [] for m in manifest: if m["section"] not in order: order.append(m["section"]) manifest.sort(key=lambda x: order.index(x["section"])) doc = Document() style = doc.styles["Normal"] style.font.name = "Microsoft YaHei" style.font.size = Pt(10.5) style.element.rPr.rFonts.set(qn("w:eastAsia"), "Microsoft YaHei") for sec in doc.sections: sec.top_margin = Inches(0.8) sec.bottom_margin = Inches(0.8) sec.left_margin = Inches(0.8) sec.right_margin = Inches(0.8) def set_font(run, size=None, bold=None, color=None): run.font.name = "Microsoft YaHei" run._element.rPr.rFonts.set(qn("w:eastAsia"), "Microsoft YaHei") if size: run.font.size = Pt(size) if bold is not None: run.font.bold = bold if color is not None: run.font.color.rgb = color # 封面 for _ in range(4): doc.add_paragraph() p = doc.add_paragraph() p.alignment = WD_ALIGN_PARAGRAPH.CENTER r = p.add_run("滨化集团智慧招标平台") set_font(r, size=30, bold=True, color=BRAND) p = doc.add_paragraph() p.alignment = WD_ALIGN_PARAGRAPH.CENTER r = p.add_run("Smart Tendering Platform (STP)") set_font(r, size=14, color=RGBColor(0x88, 0x88, 0x88)) doc.add_paragraph() p = doc.add_paragraph() p.alignment = WD_ALIGN_PARAGRAPH.CENTER r = p.add_run("前端界面截图汇总") set_font(r, size=22, bold=True) for _ in range(6): doc.add_paragraph() sections_order = [] for m in manifest: if m["section"] not in sections_order: sections_order.append(m["section"]) meta = [ ("文档类型", "前端界面(UI)截图汇总"), ("覆盖范围", "门户页 / 登录页 / 新增导航页 / 工作台 / 业务页 / 弹窗"), ("截图数量", f"{len(manifest)} 张"), ("章节数量", f"{len(sections_order)} 章"), ("生成日期", date.today().strftime("%Y 年 %m 月 %d 日")), ] for k, v in meta: p = doc.add_paragraph() p.alignment = WD_ALIGN_PARAGRAPH.CENTER r = p.add_run(f"{k}:") set_font(r, size=11, bold=True) r = p.add_run(v) set_font(r, size=11, color=RGBColor(0x44, 0x44, 0x44)) # 目录 doc.add_page_break() p = doc.add_paragraph() r = p.add_run("目 录") set_font(r, size=18, bold=True, color=BRAND) doc.add_paragraph() for sec in sections_order: cnt = sum(1 for m in manifest if m["section"] == sec) p = doc.add_paragraph() r = p.add_run(sec) set_font(r, size=12, bold=True) r = p.add_run(f" ({cnt} 张)") set_font(r, size=10.5, color=RGBColor(0x88, 0x88, 0x88)) fig_no = 0 current = None for m in manifest: img = os.path.join(SHOTS, m["file"]) if not os.path.exists(img): continue if m["section"] != current: current = m["section"] doc.add_page_break() p = doc.add_paragraph() r = p.add_run(current) set_font(r, size=17, bold=True, color=BRAND) pPr = p._p.get_or_add_pPr() pbdr = pPr.makeelement(qn("w:pBdr"), {}) bottom = pbdr.makeelement(qn("w:bottom"), { qn("w:val"): "single", qn("w:sz"): "12", qn("w:space"): "4", qn("w:color"): BRAND_HEX, }) pbdr.append(bottom) pPr.append(pbdr) doc.add_paragraph() fig_no += 1 cap = doc.add_paragraph() r = cap.add_run(f"图 {fig_no} {m['title']}") set_font(r, size=11, bold=True, color=RGBColor(0x22, 0x22, 0x22)) with Image.open(img) as im: w, h = im.size ratio = h / w width_in = PAGE_W_IN height_in = width_in * ratio max_h = 8.6 if height_in > max_h: height_in = max_h width_in = height_in / ratio p = doc.add_paragraph() p.alignment = WD_ALIGN_PARAGRAPH.CENTER p.add_run().add_picture(img, width=Inches(width_in)) doc.add_paragraph() doc.save(OUT) print(f"已生成:{OUT}") print(f"共 {fig_no} 张截图,{len(sections_order)} 个章节")