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''
f''
f''
f"{esc(line)}"
)
return (
f''
f''
f''
f''
f''
f"{''.join(runs)}"
)
def rect(x, y, cx, cy, fill="FFFFFF", line="D9E2F1", rounded=True):
sid = next_id()
prst = "roundRect" if rounded else "rect"
return (
f''
f""
f''
f''
f''
f''
f""
)
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'''
{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}
'''
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 = '''
'''
rels = '''
'''
pres = '''
'''
pres_rels = '''
'''
empty_rels = '''
'''
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())