#!/usr/bin/env python3
"""
干部任免无纸化上会PAD系统 - 项目方案PPT
深色政务风格，14页，python-pptx生成
"""

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
from pptx.enum.shapes import MSO_SHAPE
from pptx.oxml.ns import qn
import os

# ═════════════════════════════════════════════════════════════
#  配色方案：政务深蓝主题
# ═════════════════════════════════════════════════════════════
C_BG_DARK    = RGBColor(0x0F, 0x1B, 0x2D)   # 深蓝黑背景
C_BG_DARK2   = RGBColor(0x14, 0x21, 0x36)   # 次深背景
C_BG_CARD    = RGBColor(0x1A, 0x2A, 0x44)   # 卡片背景
C_BG_CARD2   = RGBColor(0x22, 0x33, 0x52)   # 卡片背景亮
C_GOLD       = RGBColor(0xC9, 0xA9, 0x61)   # 金色强调
C_GOLD_DARK  = RGBColor(0x9E, 0x84, 0x3D)   # 暗金
C_RED        = RGBColor(0x8B, 0x1A, 0x1A)   # 政务红
C_RED_LIGHT  = RGBColor(0xB8, 0x32, 0x32)   # 亮红
C_WHITE      = RGBColor(0xFF, 0xFF, 0xFF)
C_TEXT_LIGHT = RGBColor(0xD5, 0xDC, 0xE6)   # 浅灰蓝文字
C_TEXT_MUTED = RGBColor(0x8A, 0x9A, 0xB5)   # 暗灰蓝文字
C_TEXT_BODY  = RGBColor(0xC0, 0xCC, 0xDD)   # 正文文字
C_TEAL       = RGBColor(0x2A, 0x9D, 0x8F)   # 青色辅助
C_BLUE       = RGBColor(0x3B, 0x6E, 0xA8)   # 蓝色辅助
C_BORDER     = RGBColor(0x2A, 0x3A, 0x55)   # 边框色

# ═════════════════════════════════════════════════════════════
#  字体
# ═════════════════════════════════════════════════════════════
FONT_TITLE = '微软雅黑'
FONT_BODY  = '微软雅黑'

# ═════════════════════════════════════════════════════════════
#  尺寸常量 (13.333 x 7.5 inches, LAYOUT_WIDE)
# ═════════════════════════════════════════════════════════════
SLIDE_W = 13.333
SLIDE_H = 7.5

# ═════════════════════════════════════════════════════════════
#  辅助函数
# ═════════════════════════════════════════════════════════════

def set_bg(slide, color):
    """设置幻灯片背景色"""
    slide.background.fill.solid()
    slide.background.fill.fore_color.rgb = color

def add_rect(slide, l, t, w, h, color, shape_type=MSO_SHAPE.RECTANGLE):
    """添加矩形"""
    shape = slide.shapes.add_shape(shape_type, Inches(l), Inches(t), Inches(w), Inches(h))
    shape.fill.solid()
    shape.fill.fore_color.rgb = color
    shape.line.fill.background()
    if shape_type == MSO_SHAPE.ROUNDED_RECTANGLE:
        shape.adjustments[0] = 0.06
    return shape

def add_rect_bordered(slide, l, t, w, h, fill_color, border_color, border_w=1.0, shape_type=MSO_SHAPE.RECTANGLE):
    """添加带边框矩形"""
    shape = slide.shapes.add_shape(shape_type, Inches(l), Inches(t), Inches(w), Inches(h))
    shape.fill.solid()
    shape.fill.fore_color.rgb = fill_color
    shape.line.color.rgb = border_color
    shape.line.width = Pt(border_w)
    if shape_type == MSO_SHAPE.ROUNDED_RECTANGLE:
        shape.adjustments[0] = 0.06
    return shape

def add_text(slide, l, t, w, h, text, size=14, bold=False, color=C_TEXT_BODY, 
             align=PP_ALIGN.LEFT, valign=MSO_ANCHOR.TOP, font=FONT_BODY, 
             line_spacing=1.0, space_after=4):
    """添加文本框"""
    txBox = slide.shapes.add_textbox(Inches(l), Inches(t), Inches(w), Inches(h))
    tf = txBox.text_frame
    tf.word_wrap = True
    tf.auto_size = None
    # 设置垂直对齐
    tf.vertical_anchor = valign
    # 设置内边距为0
    tf.margin_left = 0
    tf.margin_right = 0
    tf.margin_top = 0
    tf.margin_bottom = 0
    
    # 处理多行文本
    lines = text.split('\n') if isinstance(text, str) else [text]
    for i, line in enumerate(lines):
        if i == 0:
            p = tf.paragraphs[0]
        else:
            p = tf.add_paragraph()
        p.text = line
        p.alignment = align
        p.space_after = Pt(space_after)
        p.space_before = Pt(0)
        p.line_spacing = line_spacing
        for run in p.runs:
            run.font.size = Pt(size)
            run.font.bold = bold
            run.font.color.rgb = color
            run.font.name = font
            # 设置东亚字体
            rPr = run._r.get_or_add_rPr()
            eaFont = rPr.find(qn('a:ea'))
            if eaFont is None:
                eaFont = rPr.makeelement(qn('a:ea'), {})
                rPr.append(eaFont)
            eaFont.set('typeface', font)
    return txBox

def add_line(slide, x1, y1, x2, y2, color, width=1.5):
    """添加线条"""
    connector = slide.shapes.add_connector(1, Inches(x1), Inches(y1), Inches(x2), Inches(y2))
    connector.line.color.rgb = color
    connector.line.width = Pt(width)
    return connector

def add_footer(slide, page_num, total=14):
    """添加页脚"""
    # 底部细线
    add_line(slide, 0.5, 7.15, SLIDE_W - 0.5, 7.15, C_BORDER, 0.75)
    # 左侧文字
    add_text(slide, 0.5, 7.18, 6, 0.3, '干部任免无纸化上会PAD系统  |  项目方案', 
             size=9, color=C_TEXT_MUTED)
    # 右侧页码
    add_text(slide, SLIDE_W - 2.5, 7.18, 2, 0.3, f'{page_num} / {total}', 
             size=9, color=C_TEXT_MUTED, align=PP_ALIGN.RIGHT)

def add_page_title(slide, title, subtitle='', icon_num=None):
    """添加页面标题区域"""
    # 顶部金色短线
    add_rect(slide, 0.5, 0.45, 0.06, 0.55, C_GOLD)
    # 标题
    add_text(slide, 0.75, 0.4, 10, 0.6, title, size=26, bold=True, color=C_WHITE, font=FONT_TITLE)
    # 副标题
    if subtitle:
        add_text(slide, 0.75, 1.0, 10, 0.35, subtitle, size=13, color=C_TEXT_MUTED)
    # 右上角圆形序号
    if icon_num:
        circle = slide.shapes.add_shape(MSO_SHAPE.OVAL, Inches(SLIDE_W - 1.1), Inches(0.4), Inches(0.55), Inches(0.55))
        circle.fill.solid()
        circle.fill.fore_color.rgb = C_GOLD
        circle.line.fill.background()
        tf = circle.text_frame
        tf.word_wrap = False
        tf.margin_left = 0
        tf.margin_right = 0
        tf.margin_top = 0
        tf.margin_bottom = 0
        tf.vertical_anchor = MSO_ANCHOR.MIDDLE
        p = tf.paragraphs[0]
        p.alignment = PP_ALIGN.CENTER
        p.text = str(icon_num)
        for run in p.runs:
            run.font.size = Pt(18)
            run.font.bold = True
            run.font.color.rgb = C_BG_DARK
            run.font.name = FONT_TITLE

def add_section_label(slide, l, t, text, color=C_GOLD):
    """添加小节标签（带竖线）"""
    add_rect(slide, l, t, 0.04, 0.28, color)
    add_text(slide, l + 0.15, t - 0.02, 4, 0.35, text, size=14, bold=True, color=color)

def add_bullet_text(slide, l, t, w, h, items, size=12, color=C_TEXT_BODY, gap=6):
    """添加带圆点列表"""
    txBox = slide.shapes.add_textbox(Inches(l), Inches(t), Inches(w), Inches(h))
    tf = txBox.text_frame
    tf.word_wrap = True
    tf.margin_left = 0
    tf.margin_right = 0
    tf.margin_top = 0
    tf.margin_bottom = 0
    for i, item in enumerate(items):
        if i == 0:
            p = tf.paragraphs[0]
        else:
            p = tf.add_paragraph()
        p.space_after = Pt(gap)
        p.space_before = Pt(0)
        p.line_spacing = 1.15
        # 添加圆点
        run_dot = p.add_run()
        run_dot.text = '▸ '
        run_dot.font.size = Pt(size)
        run_dot.font.color.rgb = C_GOLD
        run_dot.font.name = FONT_BODY
        rPr = run_dot._r.get_or_add_rPr()
        eaFont = rPr.find(qn('a:ea'))
        if eaFont is None:
            eaFont = rPr.makeelement(qn('a:ea'), {})
            rPr.append(eaFont)
        eaFont.set('typeface', FONT_BODY)
        # 添加文本
        run = p.add_run()
        run.text = item
        run.font.size = Pt(size)
        run.font.color.rgb = color
        run.font.name = FONT_BODY
        rPr2 = run._r.get_or_add_rPr()
        eaFont2 = rPr2.find(qn('a:ea'))
        if eaFont2 is None:
            eaFont2 = rPr2.makeelement(qn('a:ea'), {})
            rPr2.append(eaFont2)
        eaFont2.set('typeface', FONT_BODY)
    return txBox


# ═════════════════════════════════════════════════════════════
#  页面生成
# ═════════════════════════════════════════════════════════════

def create_presentation():
    prs = Presentation()
    prs.slide_width = Inches(SLIDE_W)
    prs.slide_height = Inches(SLIDE_H)
    blank = prs.slide_layouts[6]

    # ─────────────────────────────────────────────
    # 页1: 封面
    # ─────────────────────────────────────────────
    s = prs.slides.add_slide(blank)
    set_bg(s, C_BG_DARK)
    # 顶部装饰条
    add_rect(s, 0, 0, SLIDE_W, 0.08, C_GOLD)
    # 中间大色块装饰
    add_rect(s, 0, 3.8, SLIDE_W, 0.02, C_GOLD_DARK)
    # 左侧金色竖线
    add_rect(s, 1.0, 2.2, 0.08, 2.0, C_GOLD)
    # 主标题
    add_text(s, 1.4, 2.2, 10, 1.0, '干部任免无纸化上会', size=44, bold=True, color=C_WHITE, font=FONT_TITLE)
    add_text(s, 1.4, 3.15, 10, 0.8, 'PAD系统项目方案', size=44, bold=True, color=C_GOLD, font=FONT_TITLE)
    # 副标题
    add_text(s, 1.4, 4.1, 10, 0.5, '市委常委会干部任免议题 · 无纸化阅卷 · 安全保密', size=16, color=C_TEXT_LIGHT)
    # 底部信息
    add_text(s, 1.4, 6.2, 6, 0.4, '汇报单位：信息技术部', size=12, color=C_TEXT_MUTED)
    add_text(s, 8.5, 6.2, 4, 0.4, '2026年7月', size=12, color=C_TEXT_MUTED, align=PP_ALIGN.RIGHT)
    # 右下角装饰
    add_rect(s, SLIDE_W - 1.5, SLIDE_H - 0.08, 1.5, 0.08, C_RED)

    # ─────────────────────────────────────────────
    # 页2: 目录
    # ─────────────────────────────────────────────
    s = prs.slides.add_slide(blank)
    set_bg(s, C_BG_DARK)
    add_page_title(s, '目录', 'CONTENTS', icon_num=None)
    # 目录项 - 两列布局
    toc_items = [
        ('01', '项目背景与政策依据', '政策环境 · 合规要求'),
        ('02', '业务场景分析', '使用场景 · 用户角色 · 材料类型'),
        ('03', '系统总体架构', '三层架构 · 技术方案'),
        ('04', '核心功能详述', '会前 · 会中 · 会后 全流程'),
        ('05', '安全保密体系', '五重保障 · 国密标准'),
        ('06', 'PAD界面设计', '交互方案 · 适老化设计'),
        ('07', '部署方案与硬件', '网络架构 · 设备选型'),
        ('08', '实施路线与计划', '分期建设 · 里程碑'),
    ]
    col1 = toc_items[:4]
    col2 = toc_items[4:]
    for i, (num, title, desc) in enumerate(col1):
        y = 1.8 + i * 1.15
        # 序号圆
        circle = s.shapes.add_shape(MSO_SHAPE.OVAL, Inches(0.8), Inches(y), Inches(0.5), Inches(0.5))
        circle.fill.solid()
        circle.fill.fore_color.rgb = C_BG_CARD
        circle.line.color.rgb = C_GOLD
        circle.line.width = Pt(1.5)
        tf = circle.text_frame
        tf.margin_left = 0; tf.margin_right = 0; tf.margin_top = 0; tf.margin_bottom = 0
        tf.vertical_anchor = MSO_ANCHOR.MIDDLE
        p = tf.paragraphs[0]
        p.alignment = PP_ALIGN.CENTER
        p.text = num
        for run in p.runs:
            run.font.size = Pt(13); run.font.bold = True
            run.font.color.rgb = C_GOLD; run.font.name = FONT_TITLE
        # 标题
        add_text(s, 1.5, y - 0.02, 4.5, 0.35, title, size=15, bold=True, color=C_WHITE)
        add_text(s, 1.5, y + 0.33, 4.5, 0.3, desc, size=10, color=C_TEXT_MUTED)
    for i, (num, title, desc) in enumerate(col2):
        y = 1.8 + i * 1.15
        circle = s.shapes.add_shape(MSO_SHAPE.OVAL, Inches(7.0), Inches(y), Inches(0.5), Inches(0.5))
        circle.fill.solid()
        circle.fill.fore_color.rgb = C_BG_CARD
        circle.line.color.rgb = C_GOLD
        circle.line.width = Pt(1.5)
        tf = circle.text_frame
        tf.margin_left = 0; tf.margin_right = 0; tf.margin_top = 0; tf.margin_bottom = 0
        tf.vertical_anchor = MSO_ANCHOR.MIDDLE
        p = tf.paragraphs[0]
        p.alignment = PP_ALIGN.CENTER
        p.text = num
        for run in p.runs:
            run.font.size = Pt(13); run.font.bold = True
            run.font.color.rgb = C_GOLD; run.font.name = FONT_TITLE
        add_text(s, 7.7, y - 0.02, 4.5, 0.35, title, size=15, bold=True, color=C_WHITE)
        add_text(s, 7.7, y + 0.33, 4.5, 0.3, desc, size=10, color=C_TEXT_MUTED)
    add_footer(s, 2)

    # ─────────────────────────────────────────────
    # 页3: 项目背景与政策依据
    # ─────────────────────────────────────────────
    s = prs.slides.add_slide(blank)
    set_bg(s, C_BG_DARK)
    add_page_title(s, '项目背景与政策依据', '基于国家干部选任法规体系，构建合规、安全、高效的无纸化审议平台', icon_num=1)
    
    # 左侧：政策依据
    add_section_label(s, 0.5, 1.7, '政策依据')
    policies = [
        ('《党政领导干部选拔任用工作条例》', '2019年修订版，明确动议、民主推荐、考察、讨论决定程序'),
        ('《干部任用工作监督检查和责任追究办法》', '要求干部任用过程可追溯、有记录'),
        ('干部任免审批表3.0版标准', '中组部统一格式标准，2019版后统一为3.0'),
        ('保密管理规定', '干部任免材料属内部敏感信息，常委会前属绝密级'),
    ]
    for i, (name, desc) in enumerate(policies):
        y = 2.2 + i * 1.0
        card = add_rect_bordered(s, 0.5, y, 6.0, 0.85, C_BG_CARD, C_BORDER, 0.75, MSO_SHAPE.ROUNDED_RECTANGLE)
        add_rect(s, 0.5, y, 0.06, 0.85, C_GOLD)
        add_text(s, 0.75, y + 0.08, 5.5, 0.35, name, size=11, bold=True, color=C_WHITE)
        add_text(s, 0.75, y + 0.42, 5.5, 0.35, desc, size=9.5, color=C_TEXT_MUTED)
    
    # 右侧：核心合规约束
    add_section_label(s, 7.0, 1.7, '核心合规约束', C_RED_LIGHT)
    constraints = [
        ('信息保密', '上会材料会前会中会后均严格保密\nPAD不得留存数据'),
        ('数据只读', '常委仅审阅签批\n无编辑/修改/导出权限'),
        ('痕迹管理', '谁在何时查看了哪份材料\n需留痕审计'),
        ('材料完整', '每位干部4类材料\n必须完整呈现不得遗漏'),
        ('会议效率', '常委会节奏紧凑\n翻页/切换响应≤2秒'),
    ]
    for i, (title, desc) in enumerate(constraints):
        y = 2.2 + i * 0.92
        card = add_rect_bordered(s, 7.0, y, 5.8, 0.78, C_BG_CARD, C_BORDER, 0.75, MSO_SHAPE.ROUNDED_RECTANGLE)
        add_rect(s, 7.0, y, 0.06, 0.78, C_RED_LIGHT)
        add_text(s, 7.25, y + 0.06, 1.5, 0.35, title, size=11, bold=True, color=C_GOLD)
        add_text(s, 7.25, y + 0.38, 5.3, 0.38, desc, size=9.5, color=C_TEXT_LIGHT, line_spacing=1.1)
    
    add_footer(s, 3)

    # ─────────────────────────────────────────────
    # 页4: 业务场景分析
    # ─────────────────────────────────────────────
    s = prs.slides.add_slide(blank)
    set_bg(s, C_BG_DARK)
    add_page_title(s, '业务场景分析', '市委常委会干部任免议题审议场景全画像', icon_num=2)
    
    # 上方：场景画像卡片
    add_section_label(s, 0.5, 1.6, '使用场景')
    scene_items = [
        ('会议类型', '市委常委会议事\n（干部任免议题）'),
        ('参会人员', '市委常委\n约15人'),
        ('使用角色', '仅查看数据\n不做其他操作'),
        ('会议时长', '单次议题\n约30-60分钟'),
        ('材料数量', '单次涉及干部\n通常5-20人不等'),
        ('使用方式', '人手一台PAD\n会前分发会后收回'),
    ]
    for i, (title, desc) in enumerate(scene_items):
        x = 0.5 + i * 2.07
        card = add_rect_bordered(s, x, 2.05, 1.92, 1.35, C_BG_CARD, C_BORDER, 0.75, MSO_SHAPE.ROUNDED_RECTANGLE)
        add_text(s, x + 0.15, 2.15, 1.6, 0.3, title, size=11, bold=True, color=C_GOLD, align=PP_ALIGN.CENTER)
        add_text(s, x + 0.15, 2.48, 1.6, 0.8, desc, size=9.5, color=C_TEXT_LIGHT, align=PP_ALIGN.CENTER, line_spacing=1.15)
    
    # 下方：用户角色定义
    add_section_label(s, 0.5, 3.75, '用户角色定义')
    roles = [
        ('常委领导（查看者）', '15人', '只读', '浏览全部任免材料\n支持翻页、缩放'),
        ('会议管理员（操作者）', '1-2人', '管理', '会前推送材料、会后清除\n数据、查看留痕'),
        ('系统管理员', '1人', '运维', '设备管理、用户绑定\n日志管理'),
    ]
    # 表头
    add_rect(s, 0.5, 4.25, 12.33, 0.5, C_BG_CARD2)
    headers = ['角色', '人数', '权限', '职责说明']
    hx = [0.7, 4.5, 5.5, 6.5]
    hw = [3.7, 0.9, 0.9, 5.5]
    for j, (h, xx, ww) in enumerate(zip(headers, hx, hw)):
        add_text(s, xx, 4.3, ww, 0.4, h, size=11, bold=True, color=C_GOLD, align=PP_ALIGN.LEFT if j > 0 else PP_ALIGN.LEFT)
    
    for i, (role, num, perm, desc) in enumerate(roles):
        y = 4.85 + i * 0.65
        bg = C_BG_CARD if i % 2 == 0 else C_BG_CARD2
        add_rect(s, 0.5, y, 12.33, 0.58, bg)
        add_text(s, 0.7, y + 0.08, 3.7, 0.42, role, size=11, bold=True, color=C_WHITE, valign=MSO_ANCHOR.MIDDLE)
        add_text(s, 4.5, y + 0.08, 0.9, 0.42, num, size=11, color=C_TEXT_LIGHT, valign=MSO_ANCHOR.MIDDLE)
        add_text(s, 5.5, y + 0.08, 0.9, 0.42, perm, size=11, color=C_GOLD, bold=True, valign=MSO_ANCHOR.MIDDLE)
        add_text(s, 6.5, y + 0.08, 5.5, 0.42, desc, size=10, color=C_TEXT_BODY, valign=MSO_ANCHOR.MIDDLE, line_spacing=1.1)
    
    add_footer(s, 4)

    # ─────────────────────────────────────────────
    # 页5: 四类材料说明
    # ─────────────────────────────────────────────
    s = prs.slides.add_slide(blank)
    set_bg(s, C_BG_DARK)
    add_page_title(s, '四类上会材料说明', '每次常委会干部任免议题涉及的4类标准材料', icon_num=2)
    
    materials = [
        ('01', '汇报材料说明', 'Word', '组织部起草', 
         '任免方案总体说明、任免理由、常委会审议报告', 
         '处理方案：Word→PDF→图片化\n保留原文档分页排版'),
        ('02', '临时名册', 'Excel', '组织部编制', 
         '本次上会全部干部名册\n含姓名/原职务/拟任职务等', 
         '处理方案：Excel→PDF→图片化\n支持横向滑动查看更多列'),
        ('03', '任免审批表（3.0）', '3.0标准', '中组部统一格式', 
         '标准格式表格，含基本信息/简历\n奖惩/家庭成员等',
         '处理方案：3.0标准格式100%原样还原\n固定A4竖版布局，含照片字段'),
        ('04', '考察材料', 'Word', '考察组撰写', 
         '干部考察报告\n含德能勤绩廉评价', 
         '处理方案：Word→PDF→图片化\n通常3-5页，支持目录跳转'),
    ]
    
    for i, (num, name, fmt, src, content, tech) in enumerate(materials):
        x = 0.5 + i * 3.15
        # 卡片
        card = add_rect_bordered(s, x, 1.8, 2.95, 4.8, C_BG_CARD, C_BORDER, 0.75, MSO_SHAPE.ROUNDED_RECTANGLE)
        # 顶部色条
        add_rect(s, x, 1.8, 2.95, 0.5, C_GOLD if i < 2 else C_RED_LIGHT, MSO_SHAPE.ROUNDED_RECTANGLE)
        add_rect(s, x, 2.05, 2.95, 0.25, C_GOLD if i < 2 else C_RED_LIGHT)  # 覆盖下半圆角
        # 序号
        add_text(s, x + 0.2, 1.85, 1, 0.4, num, size=20, bold=True, color=C_BG_DARK)
        # 材料名
        add_text(s, x + 1.1, 1.85, 1.7, 0.4, name, size=13, bold=True, color=C_BG_DARK, valign=MSO_ANCHOR.MIDDLE)
        
        # 格式/来源
        add_text(s, x + 0.2, 2.5, 1.2, 0.25, '格式', size=9, color=C_TEXT_MUTED)
        add_text(s, x + 0.2, 2.72, 2.5, 0.25, fmt, size=11, bold=True, color=C_GOLD)
        add_text(s, x + 0.2, 3.05, 1.2, 0.25, '来源', size=9, color=C_TEXT_MUTED)
        add_text(s, x + 0.2, 3.27, 2.5, 0.25, src, size=11, bold=True, color=C_GOLD)
        
        # 分割线
        add_line(s, x + 0.2, 3.65, x + 2.75, 3.65, C_BORDER, 0.75)
        
        # 内容特点
        add_text(s, x + 0.2, 3.75, 2.5, 0.25, '内容特点', size=9, color=C_TEXT_MUTED)
        add_text(s, x + 0.2, 3.98, 2.5, 0.8, content, size=10, color=C_TEXT_LIGHT, line_spacing=1.2)
        
        # 技术处理
        add_line(s, x + 0.2, 4.9, x + 2.75, 4.9, C_BORDER, 0.75)
        add_text(s, x + 0.2, 5.0, 2.5, 0.25, '技术处理方案', size=9, color=C_TEXT_MUTED)
        add_text(s, x + 0.2, 5.25, 2.5, 1.2, tech, size=9.5, color=C_TEAL, line_spacing=1.25)
    
    add_footer(s, 5)

    # ─────────────────────────────────────────────
    # 页6: 系统总体架构
    # ─────────────────────────────────────────────
    s = prs.slides.add_slide(blank)
    set_bg(s, C_BG_DARK)
    add_page_title(s, '系统总体架构', '三层架构设计：管理端 · 服务端 · PAD端', icon_num=3)
    
    # 三层架构
    layers = [
        ('管理端（Web浏览器）', '组织部会务管理人员使用', 
         ['会议创建与管理', '材料上传与关联', '设备绑定与推送', '会后清除与归档'],
         C_BLUE),
        ('服务端（Docker容器化部署）', '部署在专用服务器，局域网内运行',
         ['文档转换引擎（Word/Excel→PDF→图片）', '推送服务（一对多局域网推送）', 
          '安全服务（国密加密/水印/擦除）', '日志服务（留痕审计）'],
         C_GOLD_DARK),
        ('PAD端（Android/鸿蒙原生APP）', '15台PAD，常委领导只读使用',
         ['4类材料查看', '翻页/缩放/搜索', '屏幕水印叠加', '离线缓存查看'],
         C_TEAL),
    ]
    
    for i, (title, desc, items, color) in enumerate(layers):
        y = 1.7 + i * 1.65
        # 大卡片
        card = add_rect_bordered(s, 0.5, y, 12.33, 1.45, C_BG_CARD, C_BORDER, 0.75, MSO_SHAPE.ROUNDED_RECTANGLE)
        # 左侧色条
        add_rect(s, 0.5, y, 0.08, 1.45, color)
        # 层名
        add_text(s, 0.8, y + 0.1, 4, 0.35, title, size=14, bold=True, color=C_WHITE)
        add_text(s, 0.8, y + 0.48, 4, 0.3, desc, size=10, color=C_TEXT_MUTED)
        # 功能项
        add_bullet_text(s, 5.2, y + 0.15, 7.3, 1.2, items, size=10.5, color=C_TEXT_LIGHT, gap=2)
    
    # 右侧数据流箭头说明
    add_text(s, 0.5, 6.65, 12, 0.3, '数据流向：管理端上传材料 → 服务端转换加密 → 推送至PAD端 → 会后服务端远程擦除PAD数据', 
            size=11, color=C_GOLD, align=PP_ALIGN.CENTER)
    
    add_footer(s, 6)

    # ─────────────────────────────────────────────
    # 页7: 核心功能-会前准备
    # ─────────────────────────────────────────────
    s = prs.slides.add_slide(blank)
    set_bg(s, C_BG_DARK)
    add_page_title(s, '核心功能：会前准备', '管理员完成会议创建、材料上传、设备绑定与推送', icon_num=4)
    
    # 流程步骤
    steps = [
        ('创建会议', '会议名称\n时间/地点\n议题数量'),
        ('参会人员', '15位常委\n姓名/职务\n座位号录入'),
        ('干部录入', '本次任免干部\n名单录入\n原职务/拟任职务'),
        ('材料上传', '4类材料上传\n按干部关联\n自动格式转换'),
        ('设备绑定', 'PAD编号\n↔常委身份\n绑定确认'),
        ('一键推送', '推送至全部\n或选定PAD\n完成准备'),
    ]
    
    for i, (title, desc) in enumerate(steps):
        x = 0.5 + i * 2.07
        # 步骤卡片
        card = add_rect_bordered(s, x, 1.9, 1.92, 2.6, C_BG_CARD, C_BORDER, 0.75, MSO_SHAPE.ROUNDED_RECTANGLE)
        # 顶部圆圈序号
        circle = s.shapes.add_shape(MSO_SHAPE.OVAL, Inches(x + 0.66), Inches(1.8), Inches(0.6), Inches(0.6))
        circle.fill.solid()
        circle.fill.fore_color.rgb = C_GOLD
        circle.line.color.rgb = C_BG_DARK
        circle.line.width = Pt(2)
        tf = circle.text_frame
        tf.margin_left = 0; tf.margin_right = 0; tf.margin_top = 0; tf.margin_bottom = 0
        tf.vertical_anchor = MSO_ANCHOR.MIDDLE
        p = tf.paragraphs[0]
        p.alignment = PP_ALIGN.CENTER
        p.text = str(i + 1)
        for run in p.runs:
            run.font.size = Pt(16); run.font.bold = True
            run.font.color.rgb = C_BG_DARK; run.font.name = FONT_TITLE
        
        add_text(s, x + 0.1, 2.6, 1.72, 0.35, title, size=12, bold=True, color=C_WHITE, align=PP_ALIGN.CENTER)
        add_text(s, x + 0.15, 3.0, 1.62, 1.3, desc, size=10, color=C_TEXT_LIGHT, align=PP_ALIGN.CENTER, line_spacing=1.3)
        
        # 箭头（除最后一个）
        if i < len(steps) - 1:
            add_text(s, x + 1.88, 2.7, 0.25, 0.4, '→', size=18, bold=True, color=C_GOLD_DARK, align=PP_ALIGN.CENTER)
    
    # 下方：关键功能明细
    add_section_label(s, 0.5, 4.85, '关键功能明细')
    detail_items = [
        '会议创建：会议名称、时间、地点、议题数量等信息录入',
        '材料上传：支持Word/Excel/审批表3.0格式，按干部一一关联',
        '材料预览校验：上传后预览检查格式是否正确，确保排版无误',
        '一键推送：局域网内推送至全部15台PAD，3分钟内完成',
    ]
    add_bullet_text(s, 0.5, 5.25, 12, 1.6, detail_items, size=11, gap=8)
    
    add_footer(s, 7)

    # ─────────────────────────────────────────────
    # 页8: 核心功能-会中查看（PAD端）
    # ─────────────────────────────────────────────
    s = prs.slides.add_slide(blank)
    set_bg(s, C_BG_DARK)
    add_page_title(s, '核心功能：会中查看（PAD端）', '15位常委领导使用PAD进行只读浏览，极简交互', icon_num=4)
    
    # 功能列表 - 两列
    pad_funcs = [
        ('登录认证', 'P0', 'PIN码/人脸/刷卡登录\n绑定常委身份'),
        ('首页仪表板', 'P0', '会议信息+干部列表\n+材料统计一览'),
        ('干部列表', 'P0', '以干部为维度的卡片列表\n可快速选择切换'),
        ('材料分类查看', 'P0', '选中干部后展示\n4类材料标签页'),
        ('Word文档查看', 'P0', '汇报材料/考察材料\n原样呈现，保留分页'),
        ('Excel名册查看', 'P0', '临时名册表格呈现\n支持横滑/筛选'),
        ('审批表3.0查看', 'P0', '严格按照3.0标准\n格式100%还原'),
        ('翻页浏览', 'P0', '上下/左右滑动翻页\n响应≤0.5秒'),
        ('手势缩放', 'P0', '双指缩放查看细节\n+双击放大缩小'),
        ('同步控制', 'P1', '管理员可同步所有PAD\n翻到同一页面'),
        ('全局搜索', 'P1', '按干部姓名\n快速定位材料'),
        ('防截屏水印', 'P0', '系统级防截屏\n屏幕叠加常委姓名水印'),
    ]
    
    for i, (name, pri, desc) in enumerate(pad_funcs):
        col = i % 3
        row = i // 3
        x = 0.5 + col * 4.15
        y = 1.85 + row * 1.55
        # 卡片
        card = add_rect_bordered(s, x, y, 3.95, 1.35, C_BG_CARD, C_BORDER, 0.75, MSO_SHAPE.ROUNDED_RECTANGLE)
        # 优先级标签
        pri_color = C_RED_LIGHT if pri == 'P0' else C_TEAL
        add_rect(s, x + 3.45, y + 0.1, 0.4, 0.25, pri_color, MSO_SHAPE.ROUNDED_RECTANGLE)
        add_text(s, x + 3.45, y + 0.11, 0.4, 0.23, pri, size=9, bold=True, color=C_WHITE, align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE)
        # 功能名
        add_text(s, x + 0.2, y + 0.1, 3.0, 0.35, name, size=12, bold=True, color=C_WHITE)
        # 描述
        add_text(s, x + 0.2, y + 0.48, 3.55, 0.8, desc, size=9.5, color=C_TEXT_LIGHT, line_spacing=1.2)
    
    # 底部说明
    add_text(s, 0.5, 6.6, 12.33, 0.35, 
            'P0 = 必做（一期MVP）  |  P1 = 重要（二期）  |  核心原则：极简交互，常委只需翻页和缩放，操作门槛极低', 
            size=10, color=C_GOLD, align=PP_ALIGN.CENTER)
    
    add_footer(s, 8)

    # ─────────────────────────────────────────────
    # 页9: 核心功能-会后管理
    # ─────────────────────────────────────────────
    s = prs.slides.add_slide(blank)
    set_bg(s, C_BG_DARK)
    add_page_title(s, '核心功能：会后管理', '会议结束后数据清除、设备回收、留痕归档全流程', icon_num=4)
    
    # 三个阶段卡片
    post_steps = [
        ('数据清除', C_RED_LIGHT, [
            '所有PAD一键远程擦除',
            '服务端清除临时缓存',
            '清除确认与状态回显',
            '确保无残留数据',
        ]),
        ('设备回收', C_GOLD, [
            '解除PAD与常委身份绑定',
            'PAD恢复至待机状态',
            '设备状态检查与登记',
            '统一收入充电柜',
        ]),
        ('留痕归档', C_TEAL, [
            '查看留痕日志导出',
            '材料+日志打包加密',
            '会议归档存储管理',
            '支持后续审计追溯',
        ]),
    ]
    
    for i, (title, color, items) in enumerate(post_steps):
        x = 0.5 + i * 4.15
        # 大卡片
        card = add_rect_bordered(s, x, 1.85, 3.95, 4.3, C_BG_CARD, C_BORDER, 0.75, MSO_SHAPE.ROUNDED_RECTANGLE)
        # 顶部色条
        add_rect(s, x, 1.85, 3.95, 0.6, color, MSO_SHAPE.ROUNDED_RECTANGLE)
        add_rect(s, x, 2.15, 3.95, 0.3, color)  # 覆盖下半圆角
        add_text(s, x + 0.2, 1.92, 3.5, 0.45, title, size=16, bold=True, color=C_BG_DARK, valign=MSO_ANCHOR.MIDDLE)
        
        # 功能项
        add_bullet_text(s, x + 0.3, 2.7, 3.4, 3.0, items, size=11, color=C_TEXT_LIGHT, gap=10)
    
    # 底部时间线
    add_text(s, 0.5, 6.35, 12.33, 0.35, 
            '会议结束 → 管理员一键清除 → 设备回收解除绑定 → 留痕日志导出 → 材料归档加密存储', 
            size=11, color=C_GOLD, align=PP_ALIGN.CENTER)
    
    add_footer(s, 9)

    # ─────────────────────────────────────────────
    # 页10: 安全保密体系
    # ─────────────────────────────────────────────
    s = prs.slides.add_slide(blank)
    set_bg(s, C_BG_DARK)
    add_page_title(s, '安全保密体系', '五重保障 · 国密标准 · 全流程安全防护', icon_num=5)
    
    # 五重保障 - 横向卡片
    sec_items = [
        ('物理隔离', '专用局域网部署\n不连互联网\n会议室物理隔离', C_RED_LIGHT),
        ('国密加密', 'SM4加密存储\nSM2加密传输\nSM3完整性校验', C_GOLD),
        ('防截屏水印', '系统级防截屏\n屏幕叠加水印\n常委姓名+时间', C_BLUE),
        ('远程擦除', '管理员远程\n清除任意/全部\nPAD数据', C_TEAL),
        ('会后清零', '会议结束后\n所有PAD数据\n自动清除', C_RED_LIGHT),
    ]
    
    for i, (title, desc, color) in enumerate(sec_items):
        x = 0.5 + i * 2.47
        # 卡片
        card = add_rect_bordered(s, x, 1.9, 2.32, 2.8, C_BG_CARD, C_BORDER, 0.75, MSO_SHAPE.ROUNDED_RECTANGLE)
        # 顶部图标圆
        circle = s.shapes.add_shape(MSO_SHAPE.OVAL, Inches(x + 0.81), Inches(2.1), Inches(0.7), Inches(0.7))
        circle.fill.solid()
        circle.fill.fore_color.rgb = color
        circle.line.fill.background()
        tf = circle.text_frame
        tf.margin_left = 0; tf.margin_right = 0; tf.margin_top = 0; tf.margin_bottom = 0
        tf.vertical_anchor = MSO_ANCHOR.MIDDLE
        p = tf.paragraphs[0]
        p.alignment = PP_ALIGN.CENTER
        p.text = str(i + 1)
        for run in p.runs:
            run.font.size = Pt(22); run.font.bold = True
            run.font.color.rgb = C_BG_DARK; run.font.name = FONT_TITLE
        # 标题
        add_text(s, x + 0.1, 2.95, 2.12, 0.35, title, size=13, bold=True, color=C_WHITE, align=PP_ALIGN.CENTER)
        # 描述
        add_text(s, x + 0.15, 3.35, 2.02, 1.2, desc, size=10, color=C_TEXT_LIGHT, align=PP_ALIGN.CENTER, line_spacing=1.3)
    
    # 下方：安全需求指标表
    add_section_label(s, 0.5, 5.05, '安全指标')
    
    sec_metrics = [
        ('数据加密', '国密SM4加密存储，SM2加密传输'),
        ('留痕审计', '所有查看行为留痕，不可篡改'),
        ('防截屏', '系统级防截屏，屏幕叠加水印'),
        ('远程擦除', '管理员可远程清除任意/全部PAD'),
        ('网络隔离', '专用局域网部署，与互联网物理隔离'),
        ('会后清零', '会议结束后所有PAD数据自动清除'),
    ]
    
    for i, (metric, desc) in enumerate(sec_metrics):
        col = i % 2
        row = i // 2
        x = 0.5 + col * 6.2
        y = 5.5 + row * 0.5
        add_rect(s, x, y, 0.06, 0.35, C_GOLD)
        add_text(s, x + 0.2, y - 0.02, 1.5, 0.4, metric, size=11, bold=True, color=C_GOLD, valign=MSO_ANCHOR.MIDDLE)
        add_text(s, x + 1.8, y - 0.02, 4.0, 0.4, desc, size=10, color=C_TEXT_LIGHT, valign=MSO_ANCHOR.MIDDLE)
    
    add_footer(s, 10)

    # ─────────────────────────────────────────────
    # 页11: PAD界面设计
    # ─────────────────────────────────────────────
    s = prs.slides.add_slide(blank)
    set_bg(s, C_BG_DARK)
    add_page_title(s, 'PAD界面设计方案', '适老化设计 · 极简交互 · 大字号大手势', icon_num=6)
    
    # 左侧：界面结构示意
    add_section_label(s, 0.5, 1.7, '界面结构示意')
    
    # PAD框架
    pad_x, pad_y, pad_w, pad_h = 0.8, 2.2, 5.0, 4.2
    add_rect_bordered(s, pad_x, pad_y, pad_w, pad_h, C_BG_CARD, C_GOLD, 1.5, MSO_SHAPE.ROUNDED_RECTANGLE)
    
    # 顶部栏
    add_rect(s, pad_x + 0.15, pad_y + 0.15, pad_w - 0.3, 0.4, C_BG_CARD2)
    add_text(s, pad_x + 0.3, pad_y + 0.18, 2, 0.35, 'XX市委常委会', size=9, bold=True, color=C_GOLD, valign=MSO_ANCHOR.MIDDLE)
    add_text(s, pad_x + 3.5, pad_y + 0.18, 1.2, 0.35, '议题 2/5', size=9, color=C_TEXT_MUTED, valign=MSO_ANCHOR.MIDDLE, align=PP_ALIGN.RIGHT)
    
    # 左侧导航
    add_rect(s, pad_x + 0.15, pad_y + 0.65, 1.3, 3.4, C_BG_DARK2)
    nav_items = ['干部A', '干部B', '干部C', '干部D']
    for j, item in enumerate(nav_items):
        ny = pad_y + 0.8 + j * 0.5
        if j == 1:
            add_rect(s, pad_x + 0.2, ny, 1.2, 0.38, C_GOLD_DARK, MSO_SHAPE.ROUNDED_RECTANGLE)
            add_text(s, pad_x + 0.3, ny + 0.02, 1.0, 0.35, item, size=9, bold=True, color=C_WHITE, valign=MSO_ANCHOR.MIDDLE)
        else:
            add_text(s, pad_x + 0.3, ny + 0.02, 1.0, 0.35, item, size=9, color=C_TEXT_MUTED, valign=MSO_ANCHOR.MIDDLE)
    
    # 主内容区
    add_rect(s, pad_x + 1.55, pad_y + 0.65, 3.25, 3.4, C_BG_DARK2)
    add_text(s, pad_x + 1.75, pad_y + 0.8, 2.8, 0.3, '任免审批表（3.0）', size=10, bold=True, color=C_GOLD)
    add_text(s, pad_x + 1.75, pad_y + 1.2, 2.8, 2.0, 
             '姓    名：张某某\n原职务：XX局副局长\n拟任职务：XX局党组书记\n出生年月：1975年5月\n籍    贯：四川成都\n\n[此处展示审批表\n 原版格式内容]', 
             size=8, color=C_TEXT_LIGHT, line_spacing=1.4)
    
    # 底部材料标签
    tabs = ['汇报说明', '名册', '审批表', '考察材料']
    for j, tab in enumerate(tabs):
        tx = pad_x + 0.15 + j * 1.2
        if j == 2:
            add_rect(s, tx, pad_y + 4.2, 1.1, 0.3, C_GOLD, MSO_SHAPE.ROUNDED_RECTANGLE)
            add_text(s, tx, pad_y + 4.2, 1.1, 0.3, tab, size=8, bold=True, color=C_BG_DARK, align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE)
        else:
            add_text(s, tx, pad_y + 4.2, 1.1, 0.3, tab, size=8, color=C_TEXT_MUTED, align=PP_ALIGN.CENTER, valign=MSO_ANCHOR.MIDDLE)
    
    # 右侧：设计要点
    add_section_label(s, 6.5, 1.7, '交互设计要点')
    design_points = [
        ('字号足够', '60岁左右领导使用\n正文不小于16pt，标题不小于24pt'),
        ('对比度高', '深色文字浅色背景\nWCAG AA标准以上'),
        ('触摸区域大', '按钮可触摸区域≥44pt×44pt\n符合iOS HIG标准'),
        ('操作简单', '翻页优先用左右滑手势\n不需要精准点击'),
        ('防误触', '关键操作（如退出）\n需二次确认'),
        ('横屏为主', 'A4竖版文档横屏左右分页\n审批表可竖屏'),
        ('加载提示', '切换材料时显示加载状态\n避免白屏'),
    ]
    
    for i, (title, desc) in enumerate(design_points):
        y = 2.1 + i * 0.62
        add_rect(s, 6.5, y, 0.06, 0.5, C_GOLD)
        add_text(s, 6.7, y - 0.02, 1.8, 0.3, title, size=11, bold=True, color=C_GOLD, valign=MSO_ANCHOR.MIDDLE)
        add_text(s, 8.6, y - 0.02, 4.2, 0.55, desc, size=9.5, color=C_TEXT_LIGHT, valign=MSO_ANCHOR.MIDDLE, line_spacing=1.1)
    
    add_footer(s, 11)

    # ─────────────────────────────────────────────
    # 页12: 部署方案与硬件配置
    # ─────────────────────────────────────────────
    s = prs.slides.add_slide(blank)
    set_bg(s, C_BG_DARK)
    add_page_title(s, '部署方案与硬件配置', '专用局域网部署 · 完整硬件选型方案', icon_num=7)
    
    # 上方：网络架构图（简化）
    add_section_label(s, 0.5, 1.6, '网络架构')
    
    # 管理端PC
    add_rect_bordered(s, 0.5, 2.1, 2.2, 0.7, C_BG_CARD2, C_BLUE, 1.0, MSO_SHAPE.ROUNDED_RECTANGLE)
    add_text(s, 0.6, 2.15, 2.0, 0.3, '管理端PC', size=11, bold=True, color=C_WHITE, align=PP_ALIGN.CENTER)
    add_text(s, 0.6, 2.43, 2.0, 0.3, '组织部操作', size=9, color=C_TEXT_MUTED, align=PP_ALIGN.CENTER)
    
    # 服务器
    add_rect_bordered(s, 3.5, 2.1, 2.2, 0.7, C_BG_CARD2, C_GOLD, 1.0, MSO_SHAPE.ROUNDED_RECTANGLE)
    add_text(s, 3.6, 2.15, 2.0, 0.3, '专用服务器', size=11, bold=True, color=C_WHITE, align=PP_ALIGN.CENTER)
    add_text(s, 3.6, 2.43, 2.0, 0.3, '材料管理+推送', size=9, color=C_TEXT_MUTED, align=PP_ALIGN.CENTER)
    
    # 交换机+AP
    add_rect_bordered(s, 6.5, 2.1, 2.2, 0.7, C_BG_CARD2, C_TEAL, 1.0, MSO_SHAPE.ROUNDED_RECTANGLE)
    add_text(s, 6.6, 2.15, 2.0, 0.3, '交换机+AP', size=11, bold=True, color=C_WHITE, align=PP_ALIGN.CENTER)
    add_text(s, 6.6, 2.43, 2.0, 0.3, '千兆有线+WiFi', size=9, color=C_TEXT_MUTED, align=PP_ALIGN.CENTER)
    
    # PAD
    add_rect_bordered(s, 9.5, 2.1, 3.3, 0.7, C_BG_CARD2, C_RED_LIGHT, 1.0, MSO_SHAPE.ROUNDED_RECTANGLE)
    add_text(s, 9.6, 2.15, 3.1, 0.3, '15台PAD终端', size=11, bold=True, color=C_WHITE, align=PP_ALIGN.CENTER)
    add_text(s, 9.6, 2.43, 3.1, 0.3, '局域网内只读终端', size=9, color=C_TEXT_MUTED, align=PP_ALIGN.CENTER)
    
    # 连接线
    add_line(s, 2.7, 2.45, 3.5, 2.45, C_GOLD, 1.5)
    add_line(s, 5.7, 2.45, 6.5, 2.45, C_GOLD, 1.5)
    add_line(s, 8.7, 2.45, 9.5, 2.45, C_GOLD, 1.5)
    
    # 下方：硬件配置表
    add_section_label(s, 0.5, 3.2, '硬件配置清单')
    
    # 表头
    add_rect(s, 0.5, 3.7, 12.33, 0.45, C_BG_CARD2)
    hds = ['设备', '配置要求', '数量']
    hpos = [0.7, 3.5, 10.0]
    hwidth = [2.7, 6.3, 2.5]
    for hd, hp, hw in zip(hds, hpos, hwidth):
        add_text(s, hp, 3.73, hw, 0.4, hd, size=11, bold=True, color=C_GOLD, valign=MSO_ANCHOR.MIDDLE)
    
    hw_items = [
        ('服务器', '2U机架式，至强银牌/金牌CPU，32G内存，2T SSD', '1台'),
        ('管理端PC', '普通办公电脑', '1台'),
        ('无线AP', '企业级AP，支持15+终端并发', '2-3个'),
        ('PAD硬件', '10.8-13寸，安卓/鸿蒙系统，4G+64G以上', '15台'),
        ('交换机', '千兆24口管理型', '1台'),
        ('充电柜', '15槽一体充电柜', '1个'),
    ]
    
    for i, (dev, cfg, qty) in enumerate(hw_items):
        y = 4.25 + i * 0.42
        bg = C_BG_CARD if i % 2 == 0 else C_BG_CARD2
        add_rect(s, 0.5, y, 12.33, 0.38, bg)
        add_text(s, 0.7, y + 0.03, 2.7, 0.32, dev, size=10.5, bold=True, color=C_WHITE, valign=MSO_ANCHOR.MIDDLE)
        add_text(s, 3.5, y + 0.03, 6.3, 0.32, cfg, size=10, color=C_TEXT_LIGHT, valign=MSO_ANCHOR.MIDDLE)
        add_text(s, 10.0, y + 0.03, 2.5, 0.32, qty, size=10.5, bold=True, color=C_GOLD, valign=MSO_ANCHOR.MIDDLE)
    
    # PAD选型要点
    add_section_label(s, 0.5, 6.8, 'PAD选型要点', C_RED_LIGHT)
    add_text(s, 0.5, 7.18, 12, 0.0, '', size=1)  # 占位
    
    # 改为放在右侧
    pad_tips = '屏幕≥10.8寸 | 分辨率≥2560×1600 | 支持MDM管控 | 配防窥膜 | 续航≥8小时 | 统一充电柜管理'
    add_text(s, 6.5, 6.85, 6.3, 0.3, pad_tips, size=9.5, color=C_TEXT_LIGHT, align=PP_ALIGN.RIGHT)
    
    add_footer(s, 12)

    # ─────────────────────────────────────────────
    # 页13: 实施路线与分期建设
    # ─────────────────────────────────────────────
    s = prs.slides.add_slide(blank)
    set_bg(s, C_BG_DARK)
    add_page_title(s, '实施路线与分期建设', '三期递进 · 快速上线 · 逐步完善', icon_num=8)
    
    # 三期卡片
    phases = [
        ('一期（MVP）', '1-2月', '核心查看功能上线', C_GOLD,
         ['会议创建+材料上传', '4类材料查看+翻页缩放', '设备绑定+推送', '会后清除', '留痕日志', '屏幕水印'],
         '能用、安全、简单'),
        ('二期（增强）', '+1月', '安全加固', C_RED_LIGHT,
         ['国密SM2/SM4加密', '防截屏（系统级）', '远程擦除', '留痕审计完善', '自动锁屏', '设备离开区域锁屏'],
         '安全达标'),
        ('三期（完善）', '+1月', '体验优化', C_TEAL,
         ['主席台同步控制', '全局搜索', '书签标记', '目录导航', '统计报表', '会议归档系统'],
         '体验卓越'),
    ]
    
    for i, (name, dur, goal, color, items, tag) in enumerate(phases):
        x = 0.5 + i * 4.15
        # 卡片
        card = add_rect_bordered(s, x, 1.8, 3.95, 4.5, C_BG_CARD, C_BORDER, 0.75, MSO_SHAPE.ROUNDED_RECTANGLE)
        # 顶部色条
        add_rect(s, x, 1.8, 3.95, 0.7, color, MSO_SHAPE.ROUNDED_RECTANGLE)
        add_rect(s, x, 2.15, 3.95, 0.35, color)
        # 阶段名
        add_text(s, x + 0.2, 1.85, 2.5, 0.35, name, size=16, bold=True, color=C_BG_DARK)
        add_text(s, x + 0.2, 2.18, 2.5, 0.3, dur, size=11, bold=True, color=C_BG_DARK)
        # 目标
        add_text(s, x + 2.7, 1.9, 1.1, 0.35, goal, size=9, color=C_BG_DARK, align=PP_ALIGN.RIGHT, valign=MSO_ANCHOR.MIDDLE)
        
        # 功能列表
        add_bullet_text(s, x + 0.3, 2.75, 3.4, 2.8, items, size=11, color=C_TEXT_LIGHT, gap=8)
        
        # 底部标签
        add_line(s, x + 0.2, 5.55, x + 3.75, 5.55, C_BORDER, 0.75)
        add_text(s, x + 0.2, 5.7, 3.5, 0.3, '目标定位', size=9, color=C_TEXT_MUTED)
        add_text(s, x + 0.2, 5.95, 3.5, 0.35, tag, size=13, bold=True, color=color)
    
    # 底部时间线
    add_text(s, 0.5, 6.5, 12.33, 0.35, 
            '建议：一期锁定MVP快速上线，切勿过度设计 · 以"能用、安全、简单"为首要目标', 
            size=11, color=C_GOLD, align=PP_ALIGN.CENTER)
    
    add_footer(s, 13)

    # ─────────────────────────────────────────────
    # 页14: 封底
    # ─────────────────────────────────────────────
    s = prs.slides.add_slide(blank)
    set_bg(s, C_BG_DARK)
    # 顶部装饰条
    add_rect(s, 0, 0, SLIDE_W, 0.08, C_GOLD)
    add_rect(s, 0, SLIDE_H - 0.08, SLIDE_W, 0.08, C_RED)
    # 中间分割线
    add_rect(s, 0, 3.5, SLIDE_W, 0.02, C_GOLD_DARK)
    
    # 主文字
    add_text(s, 1, 2.2, 11.33, 0.8, '感谢聆听', size=40, bold=True, color=C_WHITE, align=PP_ALIGN.CENTER, font=FONT_TITLE)
    add_text(s, 1, 3.1, 11.33, 0.5, 'THANK YOU', size=18, color=C_GOLD, align=PP_ALIGN.CENTER, font=FONT_TITLE)
    
    # 联系信息
    add_text(s, 1, 4.0, 11.33, 0.4, '干部任免无纸化上会PAD系统', size=14, color=C_TEXT_LIGHT, align=PP_ALIGN.CENTER)
    add_text(s, 1, 4.5, 11.33, 0.4, '安全 · 极简 · 格式保真 · 留痕可审', size=13, color=C_GOLD, align=PP_ALIGN.CENTER)
    
    # 底部
    add_text(s, 1, 6.0, 11.33, 0.35, '汇报单位：信息技术部', size=11, color=C_TEXT_MUTED, align=PP_ALIGN.CENTER)
    add_text(s, 1, 6.4, 11.33, 0.35, '2026年7月', size=11, color=C_TEXT_MUTED, align=PP_ALIGN.CENTER)

    # ═════════════════════════════════════════════════════════════
    #  保存
    # ═════════════════════════════════════════════════════════════
    output_path = '/data/www/files/干部任免无纸化上会PAD系统项目方案.pptx'
    prs.save(output_path)
    print(f'PPT已生成: {output_path}')
    print(f'总页数: {len(prs.slides)}')
    return output_path


if __name__ == '__main__':
    create_presentation()
