#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""生成「全员数字员工培养提案」汇报 PPT（16:9）"""

from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR

# ---------- 视觉规范 ----------
FONT = "Noto Sans CJK SC"
NAVY = RGBColor(0x1B, 0x2A, 0x4A)      # 主色 深蓝
BLUE = RGBColor(0x2E, 0x5C, 0x9A)      # 辅助蓝
ACCENT = RGBColor(0xD9, 0x7A, 0x2B)    # 强调橙
GREEN = RGBColor(0x2E, 0x7D, 0x5B)     # 正向绿
GREY = RGBColor(0x5A, 0x62, 0x70)      # 正文灰
LIGHT = RGBColor(0xF2, 0xF4, 0xF7)     # 浅底
LINE = RGBColor(0xD8, 0xDD, 0xE5)      # 分隔线
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
RED = RGBColor(0xB3, 0x3A, 0x3A)

W, H = Inches(13.333), Inches(7.5)

prs = Presentation()
prs.slide_width = W
prs.slide_height = H
BLANK = prs.slide_layouts[6]


def tb(slide, x, y, w, h, align=PP_ALIGN.LEFT, anchor=MSO_ANCHOR.TOP):
    box = slide.shapes.add_textbox(x, y, w, h)
    tf = box.text_frame
    tf.word_wrap = True
    tf.vertical_anchor = anchor
    tf.margin_left = tf.margin_right = tf.margin_top = tf.margin_bottom = 0
    p = tf.paragraphs[0]
    p.alignment = align
    return tf


def put(tf, text, size=14, color=GREY, bold=False, space_before=0,
        space_after=4, align=PP_ALIGN.LEFT, first=False, line=1.25):
    p = tf.paragraphs[0] if first else tf.add_paragraph()
    p.alignment = align
    p.space_before = Pt(space_before)
    p.space_after = Pt(space_after)
    p.line_spacing = line
    r = p.add_run()
    r.text = text
    r.font.size = Pt(size)
    r.font.bold = bold
    r.font.color.rgb = color
    r.font.name = FONT
    return p


def rect(slide, x, y, w, h, fill=None, line_color=None, line_w=0.75):
    from pptx.enum.shapes import MSO_SHAPE
    sh = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, x, y, w, h)
    if fill is None:
        sh.fill.background()
    else:
        sh.fill.solid()
        sh.fill.fore_color.rgb = fill
    if line_color is None:
        sh.line.fill.background()
    else:
        sh.line.color.rgb = line_color
        sh.line.width = Pt(line_w)
    sh.shadow.inherit = False
    return sh


def bar(slide, x, y, w=Inches(0.055), h=Inches(0.34), color=ACCENT):
    return rect(slide, x, y, w, h, fill=color)


def header(slide, idx, title, sub=None):
    """页眉：序号 + 标题 + 副标题 + 分隔线"""
    rect(slide, Inches(0), Inches(0), W, Inches(1.12), fill=NAVY)
    t = tb(slide, Inches(0.62), Inches(0.26), Inches(1.0), Inches(0.6))
    put(t, f"{idx:02d}", 26, RGBColor(0x7E, 0x93, 0xB8), bold=True, first=True)
    t = tb(slide, Inches(1.42), Inches(0.22), Inches(9.6), Inches(0.72))
    put(t, title, 24, WHITE, bold=True, first=True, space_after=0)
    if sub:
        put(t, sub, 11.5, RGBColor(0xA8, 0xBA, 0xD8), space_before=3)


def footer(slide, note=None):
    if note:
        t = tb(slide, Inches(0.62), Inches(6.92), Inches(12.1), Inches(0.34))
        put(t, note, 9.5, RGBColor(0x9A, 0xA2, 0xB0), first=True)


def table(slide, x, y, w, rows, col_w, head_fill=NAVY, font=11.5,
          row_h=Inches(0.42), head_h=Inches(0.46), zebra=True,
          col_align=None, col_color=None, col_bold=None):
    """手绘表格：rows[0] 为表头"""
    cx = x
    n = len(rows)
    # 底
    total_h = head_h + row_h * (n - 1)
    for j, cw in enumerate(col_w):
        pass
    # 表头
    cx = x
    for j, cw in enumerate(col_w):
        rect(slide, cx, y, cw, head_h, fill=head_fill)
        tf = tb(slide, cx + Inches(0.1), y, cw - Inches(0.2), head_h,
                anchor=MSO_ANCHOR.MIDDLE)
        al = (col_align or {}).get(j, PP_ALIGN.LEFT)
        put(tf, rows[0][j], font, WHITE, bold=True, first=True,
            align=al, space_after=0)
        cx += cw
    # 数据行
    yy = y + head_h
    for i in range(1, n):
        cx = x
        f = LIGHT if (zebra and i % 2 == 1) else WHITE
        for j, cw in enumerate(col_w):
            rect(slide, cx, yy, cw, row_h, fill=f, line_color=LINE, line_w=0.5)
            tf = tb(slide, cx + Inches(0.1), yy, cw - Inches(0.2), row_h,
                    anchor=MSO_ANCHOR.MIDDLE)
            al = (col_align or {}).get(j, PP_ALIGN.LEFT)
            cc = (col_color or {}).get(j, GREY)
            bd = (col_bold or {}).get(j, False)
            txt = rows[i][j]
            c = cc
            if txt.startswith("!"):        # 前缀 ! = 强调橙
                txt = txt[1:]
                c, bd = ACCENT, True
            elif txt.startswith("^"):      # 前缀 ^ = 正向绿
                txt = txt[1:]
                c, bd = GREEN, True
            elif txt.startswith("~"):      # 前缀 ~ = 弱化
                txt = txt[1:]
                c = RGBColor(0x94, 0x9C, 0xAA)
            put(tf, txt, font, c, bold=bd, first=True, align=al,
                space_after=0, line=1.05)
            cx += cw
        yy += row_h
    return yy


# ============================================================
# P1 封面
# ============================================================
s = prs.slides.add_slide(BLANK)
rect(s, Inches(0), Inches(0), W, H, fill=NAVY)
rect(s, Inches(0), Inches(0), Inches(0.16), H, fill=ACCENT)

tf = tb(s, Inches(1.15), Inches(2.02), Inches(11), Inches(0.5))
put(tf, "华腾 · 产研团队", 13, RGBColor(0x8E, 0xA5, 0xCC), first=True, bold=True)

tf = tb(s, Inches(1.15), Inches(2.55), Inches(11.2), Inches(1.5))
put(tf, "全员数字员工培养提案", 44, WHITE, bold=True, first=True, space_after=8)
put(tf, "四周试点 · 用真实数据验证 AI 进交付链的收益", 17,
    RGBColor(0xB8, 0xC8, 0xE4))

rect(s, Inches(1.15), Inches(4.42), Inches(2.2), Inches(0.035), fill=ACCENT)

tf = tb(s, Inches(1.15), Inches(4.82), Inches(11), Inches(1.0))
put(tf, "衡量主线：交付效率　·　人力成本　·　产品力", 15,
    RGBColor(0xD5, 0xDF, 0xEF), bold=True, first=True)

tf = tb(s, Inches(1.15), Inches(6.35), Inches(11), Inches(0.6))
put(tf, "汇报人：霍海明　　2026 年 7 月 29 日", 12.5,
    RGBColor(0x8E, 0xA5, 0xCC), first=True)


# ============================================================
# P2 结论与承诺
# ============================================================
s = prs.slides.add_slide(BLANK)
header(s, 1, "结论与承诺", "一次投入，两个方向的回报")

# 一句话结论
rect(s, Inches(0.62), Inches(1.38), Inches(12.1), Inches(1.02),
     fill=LIGHT, line_color=LINE)
rect(s, Inches(0.62), Inches(1.38), Inches(0.06), Inches(1.02), fill=ACCENT)
tf = tb(s, Inches(0.92), Inches(1.56), Inches(11.6), Inches(0.7))
put(tf, "用四周试点验证「AI 数字员工进交付链」的真实收益", 17, NAVY,
    bold=True, first=True, space_after=5)
put(tf, "对内：不增员条件下的交付吞吐提升　　对外：智能体工厂与 DTMP 的产品力验证与素材沉淀",
    12.5, GREY)

# 三组指标
tf = tb(s, Inches(0.62), Inches(2.66), Inches(6), Inches(0.32))
put(tf, "三组指标", 13.5, NAVY, bold=True, first=True)

rows = [
    ["方向", "指标", "基线", "四周后目标"],
    ["交付效率", "同类事项交付周期（日历天）", "第 1 周实测", "下降 __%"],
    ["人力成本", "单位功能点投入人工时", "第 1 周实测", "下降 __%"],
    ["!产品力", "!非技术角色独立完成率", "第 1 周实测", "!提升至 __%"],
    ["产品力", "可复用资产数（skill / 模板）", "0", "__ 个"],
    ["产品力", "智能体工厂缺陷清单", "—", "提交并修复 __ 项"],
]
table(s, Inches(0.62), Inches(3.06), Inches(12.1), rows,
      [Inches(1.6), Inches(5.3), Inches(2.4), Inches(2.8)],
      col_align={2: PP_ALIGN.CENTER, 3: PP_ALIGN.CENTER})

# 主动划掉
rect(s, Inches(0.62), Inches(6.02), Inches(12.1), Inches(0.72),
     fill=RGBColor(0xFD, 0xF4, 0xEC), line_color=RGBColor(0xE8, 0xC4, 0x9E))
tf = tb(s, Inches(0.92), Inches(6.13), Inches(11.6), Inches(0.55))
put(tf, "本提案不承诺减员", 14, RED, bold=True, first=True, space_after=2)
put(tf, "承诺的是同等人力下的交付吞吐提升，并给出可核查的度量口径。", 11.5, GREY)

footer(s, "指标目标值待第 1 周基线实测后填写")


# ============================================================
# P3 交付成本花在哪
# ============================================================
s = prs.slides.add_slide(BLANK)
header(s, 2, "交付成本花在哪", "AI 只对其中一部分有效，其余不做承诺")

rows = [
    ["交付环节", "是否重复劳动", "AI 是否有效", "说明"],
    ["需求澄清 / 客户沟通", "否", "~无效", "依赖人的现场判断与关系"],
    ["方案与架构决策", "否", "~无效", "责任必须在人"],
    ["原型 / 界面设计", "部分", "有效", "同类页面反复画"],
    ["!表单与流程配置", "!高度重复", "!显著有效", "同类事项跨项目反复配"],
    ["编码", "部分", "有效", "样板代码、接口对接"],
    ["!测试用例编写", "!高度重复", "!显著有效", "同类业务用例反复写"],
    ["!现场实施配置", "!高度重复", "!显著有效", "换个学校再配一遍"],
    ["!交付文档 / 培训材料", "!高度重复", "!显著有效", "结构固定，内容换名"],
    ["变更响应", "部分", "有效", "影响面分析"],
]
table(s, Inches(0.62), Inches(1.42), Inches(12.1), rows,
      [Inches(3.5), Inches(2.0), Inches(2.0), Inches(4.6)],
      row_h=Inches(0.395),
      col_align={1: PP_ALIGN.CENTER, 2: PP_ALIGN.CENTER})

rect(s, Inches(0.62), Inches(5.72), Inches(12.1), Inches(0.92),
     fill=LIGHT, line_color=LINE)
rect(s, Inches(0.62), Inches(5.72), Inches(0.06), Inches(0.92), fill=ACCENT)
tf = tb(s, Inches(0.92), Inches(5.86), Inches(11.6), Inches(0.7))
put(tf, "战场只有四段：表单流程配置 · 测试用例 · 现场实施 · 交付文档", 14.5,
    NAVY, bold=True, first=True, space_after=3)
put(tf, "只声称对约三分之一的环节有效，是为了让结论可信、可验证。", 11.5, GREY)


# ============================================================
# P4 产品力（逻辑链）
# ============================================================
s = prs.slides.add_slide(BLANK)
header(s, 3, "产品力：不是副产品", "智能体工厂的 skill 与 MCP 全部基于 DTMP 封装")

# 逻辑链
chain = [
    ("员工在智能体工厂搭 skill", "封装 DTMP 能力"),
    ("skill 即交付现场可用之物", "实施带 skill 进项目"),
    ("配置速度、一次通过率提升", "交付效率↑（对内）"),
    ("沉淀为行业场景模板", "可演示、可交付（对外）"),
]
x = Inches(0.62)
cw = Inches(2.86)
gap = Inches(0.28)
for i, (a, b) in enumerate(chain):
    fill = LIGHT if i < 2 else RGBColor(0xEC, 0xF2, 0xEA)
    edge = LINE if i < 2 else RGBColor(0xBF, 0xD6, 0xC6)
    rect(s, x, Inches(1.42), cw, Inches(1.16), fill=fill, line_color=edge)
    tf = tb(s, x + Inches(0.16), Inches(1.56), cw - Inches(0.32),
            Inches(0.9))
    put(tf, a, 12.5, NAVY, bold=True, first=True, space_after=4, line=1.15)
    put(tf, b, 10.5, GREY, line=1.15)
    if i < 3:
        ar = tb(s, x + cw + Inches(0.02), Inches(1.78), gap, Inches(0.4),
                align=PP_ALIGN.CENTER)
        put(ar, "▶", 12, ACCENT, bold=True, first=True)
    x += cw + gap

tf = tb(s, Inches(0.62), Inches(2.76), Inches(12.1), Inches(0.34))
put(tf, "同一份投入，产出同时落在成本表和产品线上。", 13.5, ACCENT,
    bold=True, first=True)

# 三项产出
tf = tb(s, Inches(0.62), Inches(3.28), Inches(6), Inches(0.32))
put(tf, "三项产品力产出", 13.5, NAVY, bold=True, first=True)

items = [
    ("对「人人都会用」的第一次内部实测",
     "白皮书对高校承诺「人人都会用」，目前无任何内部数据支撑。\n"
     "非技术角色独立完成率即为这句承诺的第一个真实数字。\n"
     "好 → 可直接进方案与投标；差 → 提前暴露，代价远低于现场暴露。"),
    ("智能体工厂真实可用性缺陷清单",
     "内部 50 余人是最近、最坦诚、不受项目节奏牵制的用户群。\n"
     "重点记录：卡在哪一步、第几步流失、哪些 DTMP 能力封装不足。\n"
     "客户只会说「不好用」，不会说「卡在第三步」。"),
    ("可打包进产品的真实场景模板库",
     "经过真实工时与真实返工检验的模板，与设想的模板有本质差别。\n"
     "四周后形成一批带「解决什么场景 / 省多少时间」标注的模板，\n"
     "可直接用于产品演示与交付预置。"),
]
x = Inches(0.62)
cw = Inches(3.93)
for i, (t, d) in enumerate(items):
    rect(s, x, Inches(3.68), cw, Inches(2.28), fill=WHITE, line_color=LINE)
    rect(s, x, Inches(3.68), cw, Inches(0.05), fill=ACCENT if i == 0 else BLUE)
    tf = tb(s, x + Inches(0.2), Inches(3.9), cw - Inches(0.4), Inches(0.6))
    put(tf, f"{i+1}　{t}", 12.5, NAVY, bold=True, first=True, space_after=6,
        line=1.15)
    for ln in d.split("\n"):
        put(tf, ln, 10.5, GREY, space_after=2, line=1.2)
    x += cw + Inches(0.155)

# 前提
rect(s, Inches(0.62), Inches(6.12), Inches(12.1), Inches(0.7),
     fill=RGBColor(0xFD, 0xF4, 0xEC), line_color=RGBColor(0xE8, 0xC4, 0x9E))
tf = tb(s, Inches(0.92), Inches(6.22), Inches(11.6), Inches(0.55))
put(tf, "一个前提：amis 为自研改造，公开文档无法直接喂给 AI", 13, RED,
    bold=True, first=True, space_after=2)
put(tf, "「事项规范 → schema」类能力成立的地基是一份完整的自研组件 schema 文档；"
        "若尚无，整理它就是第一个题目。", 11, GREY)


# ============================================================
# P5 已具备的基础
# ============================================================
s = prs.slides.add_slide(BLANK)
header(s, 4, "我们已具备的基础", "这层底座是多数 AI 应用团队需从零补的部分")

cards = [
    ("amis 组件引擎自主可控",
     "自研成分较多，已达自主可控层级。不受上游开源项目路线牵制，"
     "具备长期演进与安全合规解释能力。"),
    ("前端主力 Vue 3，无重大包袱",
     "Vue 2 仅平台上一个很小模块在用，不构成技术债负担。"),
    ("业务底座已成型",
     "流程引擎、表单引擎、消息待办中台、数据中台等能力已上线运行，"
     "是 AI 能「真办事」的前提。"),
]
y = Inches(1.46)
for i, (t, d) in enumerate(cards):
    rect(s, Inches(0.62), y, Inches(7.4), Inches(1.28), fill=WHITE,
         line_color=LINE)
    rect(s, Inches(0.62), y, Inches(0.055), Inches(1.28), fill=GREEN)
    tf = tb(s, Inches(0.92), y + Inches(0.2), Inches(6.9), Inches(0.9))
    put(tf, t, 14, NAVY, bold=True, first=True, space_after=5, line=1.15)
    put(tf, d, 11.5, GREY, line=1.25)
    y += Inches(1.44)

# 右侧判断
rect(s, Inches(8.28), Inches(1.46), Inches(4.44), Inches(4.16),
     fill=NAVY)
tf = tb(s, Inches(8.6), Inches(1.76), Inches(3.8), Inches(3.6))
put(tf, "关键判断", 13, RGBColor(0x8E, 0xA5, 0xCC), bold=True, first=True,
    space_after=12)
put(tf, "对话能力已趋于廉价。", 16, WHITE, bold=True, space_after=10, line=1.3)
put(tf, "「AI 能否真办成事」取决于事项元数据与流程可编排程度。",
    15, WHITE, bold=True, space_after=12, line=1.35)
put(tf, "这是华腾已有、而竞品需从零补的部分。", 13,
    RGBColor(0xE0, 0xB6, 0x8A), bold=True, line=1.35)

rect(s, Inches(0.62), Inches(5.82), Inches(12.1), Inches(0.78),
     fill=LIGHT, line_color=LINE)
tf = tb(s, Inches(0.92), Inches(5.96), Inches(11.6), Inches(0.55))
put(tf, "内部全员实践 = 用自己的团队检验自己的产品，同时把检验过程变成交付效率提升",
    13, NAVY, bold=True, first=True)


# ============================================================
# P6 四阶段 + 双轨
# ============================================================
s = prs.slides.add_slide(BLANK)
header(s, 5, "实施路径：四阶段 + 双轨", "全员适配打底，重点人员攻坚出资产")

# 双轨表
rows = [
    ["", "全员轨", "重点人员轨"],
    ["范围", "全公司 50 余人", "__ 人（五角色各 1–2 人）"],
    ["目标", "会用，且各自找到 1 个真实省时场景", "^产出可复用资产、成为角色内传导点"],
    ["投入", "2h / 周 × 4 周", "4–6h / 周 × 4 周"],
    ["交付物", "个人场景记录", "^可复制 skill / 模板 + 失败清单"],
    ["挂载", "日常工作", "!挂在真实项目上"],
]
table(s, Inches(0.62), Inches(1.42), Inches(12.1), rows,
      [Inches(1.3), Inches(5.4), Inches(5.4)],
      row_h=Inches(0.4))

tf = tb(s, Inches(0.62), Inches(4.06), Inches(12), Inches(0.3))
put(tf, "重点人员按传导能力选，不按职级选。", 11.5, GREY, first=True)

# 四阶段
stages = [
    ("阶段一", "认知拉起", "第 1 周 · 1 小时内",
     "讲清能干什么、更要讲不能干什么：幻觉、责任边界、数据红线。现场演示优于讲义。"),
    ("阶段二", "上手实践", "第 1–2 周",
     "关键是发场景清单而非发工具。按角色分层配工具，非技术角色不给重型工具。"),
    ("阶段三", "分享交换", "第 3 周",
     "硬规则：必须报告失败案例与真实耗时。设「翻车分享」正向激励。"),
    ("阶段四", "资产沉淀", "第 2 周即开始",
     "资产 = 可直接复制运行的件，附「解决什么场景 / 省多少时间」。心得文档不计入。"),
]
x = Inches(0.62)
cw = Inches(2.955)
for i, (n, t, when, d) in enumerate(stages):
    rect(s, x, Inches(4.5), cw, Inches(1.72), fill=WHITE, line_color=LINE)
    rect(s, x, Inches(4.5), cw, Inches(0.05), fill=BLUE)
    tf = tb(s, x + Inches(0.18), Inches(4.68), cw - Inches(0.36), Inches(1.4))
    put(tf, f"{n}　{t}", 13, NAVY, bold=True, first=True, space_after=2,
        line=1.1)
    put(tf, when, 10, ACCENT, bold=True, space_after=6, line=1.1)
    put(tf, d, 10.5, GREY, line=1.22)
    x += cw + Inches(0.145)

# 投入对比
rect(s, Inches(0.62), Inches(6.38), Inches(12.1), Inches(0.66),
     fill=LIGHT, line_color=LINE)
tf = tb(s, Inches(0.92), Inches(6.5), Inches(11.6), Inches(0.45))
put(tf, "投入对比：试点 6 人 ≈ 6 人日　|　全员 50 人 ≈ 50 人日（2.3 人月）　—　"
        "建议首月只批试点，全员轨按试点结果分批推进",
    12, NAVY, bold=True, first=True)


# ============================================================
# P7 度量口径
# ============================================================
s = prs.slides.add_slide(BLANK)
header(s, 6, "度量口径", "本提案唯一会被真正检验的部分")

rows = [
    ["指标", "定义", "基线测法", "样本", "记录人"],
    ["同类事项配置工时", "单事项从接需求到可用的人工时", "第 1 周记录 5 个未用 AI 的事项", "≥5", "__"],
    ["测试用例编写工时", "单模块用例集编写人工时", "同上", "≥5", "__"],
    ["现场实施配置工时", "单校单模块配置人工时", "取最近一次同类项目记录", "≥3", "__"],
    ["交付文档工时", "单份文档从空白到可交付人工时", "第 1 周记录 3 份", "≥3", "__"],
    ["一次通过率", "配置后无需返工的比例", "第 1 周统计", "—", "__"],
    ["!非技术角色独立完成率", "!无研发协助完成配置的事项占比", "第 1 周统计现状", "≥10", "__"],
]
table(s, Inches(0.62), Inches(1.42), Inches(12.1), rows,
      [Inches(2.95), Inches(4.0), Inches(3.35), Inches(0.9), Inches(0.9)],
      row_h=Inches(0.44),
      col_align={3: PP_ALIGN.CENTER, 4: PP_ALIGN.CENTER})

rect(s, Inches(0.62), Inches(4.72), Inches(12.1), Inches(0.86),
     fill=LIGHT, line_color=LINE)
rect(s, Inches(0.62), Inches(4.72), Inches(0.06), Inches(0.86), fill=ACCENT)
tf = tb(s, Inches(0.92), Inches(4.86), Inches(11.6), Inches(0.62))
put(tf, "记录方式", 13, NAVY, bold=True, first=True, space_after=3)
put(tf, "试点期内所有相关任务登记三个字段：是否使用 AI / 实际工时 / 是否需研发协助。"
        "第 4 周出对比。", 11.5, GREY)

rect(s, Inches(0.62), Inches(5.78), Inches(12.1), Inches(0.9),
     fill=RGBColor(0xFD, 0xF4, 0xEC), line_color=RGBColor(0xE8, 0xC4, 0x9E))
tf = tb(s, Inches(0.92), Inches(5.92), Inches(11.6), Inches(0.66))
put(tf, "为什么这一页必须存在", 13, RED, bold=True, first=True, space_after=3)
put(tf, "没有口径、基线、样本、来源的百分比不具备验证价值，也无法支撑后续决策。"
        "本提案的每个数字都必须可核查。", 11.5, GREY)


# ============================================================
# P8 资源与红线
# ============================================================
s = prs.slides.add_slide(BLANK)
header(s, 7, "资源与数据红线", "需要什么，以及必须先立的规矩")

tf = tb(s, Inches(0.62), Inches(1.4), Inches(5.6), Inches(0.32))
put(tf, "需要什么", 14, NAVY, bold=True, first=True)

needs = [
    ("工具预算", "__ / 月"),
    ("工时授权", "试点 6 人日 / 首月；全员阶段一 1 小时"),
    ("试点载体项目", "一个正在进行的真实项目"),
]
y = Inches(1.82)
for i, (a, b) in enumerate(needs):
    rect(s, Inches(0.62), y, Inches(5.7), Inches(0.92), fill=WHITE,
         line_color=LINE)
    rect(s, Inches(0.62), y, Inches(0.055), Inches(0.92), fill=BLUE)
    tf = tb(s, Inches(0.92), y + Inches(0.15), Inches(5.2), Inches(0.66))
    put(tf, a, 13, NAVY, bold=True, first=True, space_after=3, line=1.1)
    put(tf, b, 11.5, GREY, line=1.15)
    y += Inches(1.04)

rect(s, Inches(0.62), Inches(4.96), Inches(5.7), Inches(0.82),
     fill=RGBColor(0xFD, 0xF4, 0xEC), line_color=RGBColor(0xE8, 0xC4, 0x9E))
tf = tb(s, Inches(0.92), Inches(5.08), Inches(5.2), Inches(0.62))
put(tf, "无真实项目载体，则所有数字失去可信度", 12, RED, bold=True,
    first=True, space_after=2)
put(tf, "度量会退化为自述，第 4 周无法向老板交付结论。", 10.5, GREY)

# 红线
tf = tb(s, Inches(6.68), Inches(1.4), Inches(6.04), Inches(0.32))
put(tf, "数据红线（先立规矩，再推工具）", 14, NAVY, bold=True, first=True)

rows = [
    ["级别", "内容", "可用工具"],
    ["L0 公开", "已公开产品介绍、通用技术资料", "全部"],
    ["L1 内部", "内部文档、非客户设计稿", "全部"],
    ["!L2 客户相关", "!项目方案、投标文件、客户需求", "!仅本地/私有化"],
    ["!L3 敏感", "!高校真实数据、源码、凭据", "!禁止外部工具"],
]
table(s, Inches(6.68), Inches(1.82), Inches(6.04), rows,
      [Inches(1.5), Inches(3.0), Inches(1.54)],
      row_h=Inches(0.56), font=10.5)

rect(s, Inches(6.68), Inches(4.5), Inches(6.04), Inches(1.28),
     fill=NAVY)
tf = tb(s, Inches(6.98), Inches(4.66), Inches(5.5), Inches(1.0))
put(tf, "这一页同时是提案的防护栏", 12.5, RGBColor(0xE0, 0xB6, 0x8A),
    bold=True, first=True, space_after=5)
put(tf, "公司对外承诺等保三级与全链路安全管控。全员推 AI 工具而无数据分级，"
        "风险是真实高校数据、源码、投标文件被贴入第三方模型。"
        "任一发生即为合规事故，足以使试点中止。", 10.5, WHITE, line=1.3)

footer(s, "违规处理流程：待定")


# ============================================================
# P9 下一步
# ============================================================
s = prs.slides.add_slide(BLANK)
header(s, 8, "请老板确认的事项", "确认后本周内启动第 1 周基线测量")

asks = [
    ("1", "批准试点范围与工时", "重点人员 __ 人 × 4 周 ≈ 6 人日；全员阶段一 1 小时",
     ACCENT),
    ("2", "指定试点载体项目", "需为正在进行、可取得工时数据的真实项目", ACCENT),
    ("3", "批准工具预算", "__ / 月", BLUE),
    ("4", "认可数据红线制度", "L0–L3 分级与工具白名单，违规处理流程需配套", BLUE),
]
y = Inches(1.5)
for n, t, d, c in asks:
    rect(s, Inches(0.62), y, Inches(12.1), Inches(1.0), fill=WHITE,
         line_color=LINE)
    rect(s, Inches(0.62), y, Inches(0.06), Inches(1.0), fill=c)
    tf = tb(s, Inches(1.0), y + Inches(0.24), Inches(0.5), Inches(0.5))
    put(tf, n, 20, c, bold=True, first=True)
    tf = tb(s, Inches(1.62), y + Inches(0.18), Inches(10.8), Inches(0.7))
    put(tf, t, 15, NAVY, bold=True, first=True, space_after=3, line=1.1)
    put(tf, d, 11.5, GREY, line=1.2)
    y += Inches(1.14)

rect(s, Inches(0.62), Inches(6.1), Inches(12.1), Inches(0.82),
     fill=NAVY)
tf = tb(s, Inches(0.92), Inches(6.24), Inches(11.6), Inches(0.6))
put(tf, "四周后交付：两组效率数字 + 一份产品缺陷清单 + 一批可复用资产", 15,
    WHITE, bold=True, first=True)


prs.save("/home/ubuntu/.openclaw/workspace/output/全员数字员工培养提案-20260729.pptx")
print("saved:", len(prs.slides.__iter__.__self__._sldIdLst), "slides")
