| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- from pathlib import Path
- from zipfile import ZipFile, ZIP_DEFLATED
- import html
- OUT = Path("docs/供应监测评分卡QA质量评分机制_两页汇报_修正版.pptx")
- OUT.parent.mkdir(parents=True, exist_ok=True)
- def esc(value):
- return html.escape(str(value), quote=True)
- shape_id = 10
- def next_id():
- global shape_id
- shape_id += 1
- return shape_id
- def text_box(x, y, cx, cy, text, size=1800, bold=False, color="1F2937"):
- sid = next_id()
- runs = []
- for line in text.split("\n"):
- b = ' b="1"' if bold else ""
- runs.append(
- f'<a:p><a:r><a:rPr lang="zh-CN" sz="{size}"{b}>'
- f'<a:solidFill><a:srgbClr val="{color}"/></a:solidFill>'
- f'<a:latin typeface="Microsoft YaHei"/><a:ea typeface="Microsoft YaHei"/></a:rPr>'
- f"<a:t>{esc(line)}</a:t></a:r></a:p>"
- )
- return (
- f'<p:sp><p:nvSpPr><p:cNvPr id="{sid}" name="TextBox {sid}"/>'
- f'<p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr><p:spPr>'
- f'<a:xfrm><a:off x="{x}" y="{y}"/><a:ext cx="{cx}" cy="{cy}"/></a:xfrm>'
- f'<a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/>'
- f'<a:ln><a:noFill/></a:ln></p:spPr><p:txBody><a:bodyPr wrap="square"/>'
- f"<a:lstStyle/>{''.join(runs)}</p:txBody></p:sp>"
- )
- def rect(x, y, cx, cy, fill="FFFFFF", line="D9E2F1", rounded=True):
- sid = next_id()
- prst = "roundRect" if rounded else "rect"
- return (
- f'<p:sp><p:nvSpPr><p:cNvPr id="{sid}" name="Shape {sid}"/>'
- f"<p:cNvSpPr/><p:nvPr/></p:nvSpPr><p:spPr>"
- f'<a:xfrm><a:off x="{x}" y="{y}"/><a:ext cx="{cx}" cy="{cy}"/></a:xfrm>'
- f'<a:prstGeom prst="{prst}"><a:avLst/></a:prstGeom>'
- f'<a:solidFill><a:srgbClr val="{fill}"/></a:solidFill>'
- f'<a:ln w="12700"><a:solidFill><a:srgbClr val="{line}"/></a:solidFill></a:ln>'
- f"</p:spPr><p:txBody><a:bodyPr/><a:lstStyle/><a:p/></p:txBody></p:sp>"
- )
- def card(x, y, cx, cy, title, body, accent="2563EB"):
- return (
- rect(x, y, cx, cy)
- + text_box(x + 180000, y + 130000, cx - 360000, 230000, title, 1500, True, accent)
- + text_box(x + 180000, y + 420000, cx - 360000, cy - 520000, body, 1120, False, "475569")
- )
- def slide(title, subtitle, shapes):
- return f'''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
- <p:sld xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
- xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
- xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
- <p:cSld>
- <p:bg><p:bgPr><a:solidFill><a:srgbClr val="F4F7FB"/></a:solidFill><a:effectLst/></p:bgPr></p:bg>
- <p:spTree>
- <p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr>
- <p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr>
- {rect(0, 0, 12192000, 760000, "1F4E79", "1F4E79", False)}
- {text_box(520000, 170000, 9500000, 340000, title, 2300, True, "FFFFFF")}
- {text_box(520000, 545000, 9800000, 200000, subtitle, 1050, False, "DBEAFE")}
- {shapes}
- </p:spTree>
- </p:cSld>
- <p:clrMapOvr><a:masterClrMapping/></p:clrMapOvr>
- </p:sld>'''
- slide1_shapes = ""
- slide1_shapes += card(
- 520000,
- 1060000,
- 3500000,
- 1700000,
- "数据可以接入",
- "QA 表包含供应商、商品编码、验货日期、来货数量、抽检个数、不合格个数、大批次品和问题描述,可支撑供应商质量维度统计。",
- )
- slide1_shapes += card(
- 4300000,
- 1060000,
- 3500000,
- 1700000,
- "核心计算口径",
- "抽检总数 = SUM(抽检/个数)\n不合格总数 = SUM(不合格/个 + 大批次品)\nQA合格率 = 合格数 / 抽检总数",
- "059669",
- )
- slide1_shapes += card(
- 8080000,
- 1060000,
- 3500000,
- 1700000,
- "供应商匹配",
- "QA 表常用简称,如“顾舒家华”。系统供应商可能是公司全称。采用包含关系匹配:全称包含简称即可归属。",
- "7C3AED",
- )
- slide1_shapes += rect(520000, 3200000, 11150000, 2500000)
- slide1_shapes += text_box(820000, 3430000, 10300000, 260000, "落地数据流", 1600, True, "1F4E79")
- slide1_shapes += text_box(
- 850000,
- 3920000,
- 10200000,
- 850000,
- "QA Excel 多月份 Sheet → 读取所有月份 → 按供应商汇总抽检/不合格 → 宽松匹配供应商评分卡 → 输出 QA合格率、质量分、不合格数",
- 1400,
- False,
- "334155",
- )
- slide1_shapes += text_box(
- 850000,
- 5030000,
- 10200000,
- 450000,
- "无 QA 数据的供应商:QA合格率显示“暂无”,质量分按 80 分中性值处理,避免误伤。",
- 1250,
- False,
- "64748B",
- )
- slide2_shapes = ""
- slide2_shapes += rect(520000, 1040000, 11150000, 1200000)
- slide2_shapes += text_box(850000, 1260000, 10200000, 280000, "综合评分新权重", 1750, True, "1F4E79")
- slide2_shapes += text_box(
- 850000,
- 1680000,
- 10200000,
- 360000,
- "综合分 = 成本分 × 30% + 交付分 × 30% + 账期分 × 15% + 质量分 × 25%",
- 1550,
- True,
- "2563EB",
- )
- slide2_shapes += card(520000, 2550000, 2550000, 1900000, "页面新增字段", "质量分\nQA合格率\n不合格数\n可扩展:QA抽检数、QA来货数")
- slide2_shapes += card(3370000, 2550000, 2550000, 1900000, "质量预警规则", "QA抽检数 > 0\n且 QA合格率 < 95%\n则标记:质量预警", "DC2626")
- slide2_shapes += card(6220000, 2550000, 2550000, 1900000, "业务价值", "识别低价但质量不稳的供应商\n避免评分只被成本和交付主导\n支持整改、淘汰、谈判", "059669")
- slide2_shapes += card(9070000, 2550000, 2550000, 1900000, "后续建议", "将 QA Excel 入库\n建立质量检验明细表\n扩展质量趋势和问题类型分析", "7C3AED")
- slide2_shapes += rect(520000, 5050000, 11150000, 850000, "EFF6FF", "BFDBFE")
- slide2_shapes += text_box(
- 820000,
- 5290000,
- 10500000,
- 300000,
- "结论:QA 数据可以纳入供应监测评分卡,推荐以 QA 合格率形成质量分,并作为 25% 权重参与综合评分。",
- 1350,
- True,
- "1E3A8A",
- )
- slide1 = slide("供应监测评分卡新增 QA 质量维度", "数据来源与计算逻辑", slide1_shapes)
- slide2 = slide("评分机制与页面落地", "新增质量分、QA合格率与质量预警", slide2_shapes)
- content_types = '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
- <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
- <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
- <Default Extension="xml" ContentType="application/xml"/>
- <Override PartName="/ppt/presentation.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml"/>
- <Override PartName="/ppt/slides/slide1.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slide+xml"/>
- <Override PartName="/ppt/slides/slide2.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slide+xml"/>
- </Types>'''
- rels = '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
- <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
- <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="ppt/presentation.xml"/>
- </Relationships>'''
- pres = '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
- <p:presentation xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
- xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
- xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
- <p:sldIdLst><p:sldId id="256" r:id="rId1"/><p:sldId id="257" r:id="rId2"/></p:sldIdLst>
- <p:sldSz cx="12192000" cy="6858000" type="screen4x3"/>
- <p:notesSz cx="6858000" cy="9144000"/>
- </p:presentation>'''
- pres_rels = '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
- <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
- <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide" Target="slides/slide1.xml"/>
- <Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide" Target="slides/slide2.xml"/>
- </Relationships>'''
- empty_rels = '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
- <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"/>'''
- with ZipFile(OUT, "w", ZIP_DEFLATED) as z:
- z.writestr("[Content_Types].xml", content_types.encode("utf-8"))
- z.writestr("_rels/.rels", rels.encode("utf-8"))
- z.writestr("ppt/presentation.xml", pres.encode("utf-8"))
- z.writestr("ppt/_rels/presentation.xml.rels", pres_rels.encode("utf-8"))
- z.writestr("ppt/slides/slide1.xml", slide1.encode("utf-8"))
- z.writestr("ppt/slides/slide2.xml", slide2.encode("utf-8"))
- z.writestr("ppt/slides/_rels/slide1.xml.rels", empty_rels.encode("utf-8"))
- z.writestr("ppt/slides/_rels/slide2.xml.rels", empty_rels.encode("utf-8"))
- print(OUT.resolve())
|