#!/usr/bin/env python3
"""生成5页精简版汇报PPT"""
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

prs = Presentation()
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)

# 配色
DARK_BG = RGBColor(0x1A, 0x27, 0x44)
GOLD = RGBColor(0xC9, 0xA9, 0x61)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
LIGHT_BG = RGBColor(0x23, 0x33, 0x56)
RED_ACCENT = RGBColor(0xC4, 0x1E, 0x3A)
LIGHT_TEXT = RGBColor(0xA0, 0xB0, 0xD0)

def add_bg(slide, color=DARK_BG):
    bg = slide.background
    fill = bg.fill
    fill.solid()
    fill.fore_color.rgb = color

def add_textbox(slide, left, top, width, height, text, font_size=18, color=WHITE, bold=False, alignment=PP_ALIGN.LEFT, font_name='微软雅黑'):
    txBox = slide.shapes.add_textbox(Inches(left), Inches(top), Inches(width), Inches(height))
    tf = txBox.text_frame
    tf.word_wrap = True
    p = tf.paragraphs[0]
    p.text = text
    p.font.size = Pt(font_size)
    p.font.color.rgb = color
    if bold:
        p.font.bold = True
    p.font.name = font_name
    p.alignment = alignment
    return txBox

def add_rect(slide, left, top, width, height, color):
    shape = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, Inches(left), Inches(top), Inches(width), Inches(height))
    shape.fill.solid()
    shape.fill.fore_color.rgb = color
    shape.line.fill.background()
    return shape

def add_notes(slide, text):
    notes_slide = slide.notes_slide
    notes_slide.notes_text_frame.text = text

# ═══════════════════════════════════════
# 第1页：封面
# ═══════════════════════════════════════
slide1 = prs.slides.add_slide(prs.slide_layouts[6])
add_bg(slide1, DARK_BG)
add_rect(slide1, 0, 0, 13.333, 0.08, GOLD)
add_rect(slide1, 0, 7.42, 13.333, 0.08, GOLD)
add_rect(slide1, 5.5, 2.8, 2.3, 0.04, GOLD)

add_textbox(slide1, 1.5, 1.8, 10, 1.2, '干部任免无纸化上会PAD系统', 44, WHITE, True, PP_ALIGN.CENTER)
add_textbox(slide1, 1.5, 3.1, 10, 0.8, '建 设 方 案 汇 报', 28, GOLD, False, PP_ALIGN.CENTER)
add_textbox(slide1, 1.5, 5.0, 10, 0.5, '海东市委组织部', 20, LIGHT_TEXT, False, PP_ALIGN.CENTER)
add_textbox(slide1, 1.5, 5.5, 10, 0.5, '2026年7月', 16, LIGHT_TEXT, False, PP_ALIGN.CENTER)

add_notes(slide1, '各位领导，大家好。今天向各位汇报干部任免无纸化上会PAD系统的建设方案。本系统旨在利用信息化手段，实现干部任免上会材料的无纸化呈现，提升常委会审议效率和保密水平。')

# ═══════════════════════════════════════
# 第2页：建设背景与目标
# ═══════════════════════════════════════
slide2 = prs.slides.add_slide(prs.slide_layouts[6])
add_bg(slide2, DARK_BG)
add_rect(slide2, 0, 0, 13.333, 0.08, GOLD)
add_textbox(slide2, 0.8, 0.3, 10, 0.7, '一、建设背景与目标', 30, GOLD, True)

# 左列：背景
add_rect(slide2, 0.8, 1.3, 5.6, 5.5, LIGHT_BG)
add_textbox(slide2, 1.0, 1.5, 5.2, 0.5, '建设背景', 22, GOLD, True)

bg_items = [
    ('政策依据', '《党政领导干部选拔任用工作条例》\n（2019修订版）要求规范任用程序'),
    ('现实需求', '传统纸质材料印制耗时、分发繁琐、\n保密风险高、不便于查阅比对'),
    ('技术条件', 'PAD终端+局域网+国密加密技术成熟，\n具备无纸化上会的可行性'),
]
y = 2.2
for title, desc in bg_items:
    add_textbox(slide2, 1.2, y, 4.8, 0.4, f'▶ {title}', 16, WHITE, True)
    add_textbox(slide2, 1.5, y+0.45, 4.6, 0.8, desc, 13, LIGHT_TEXT)
    y += 1.5

# 右列：目标
add_rect(slide2, 6.9, 1.3, 5.6, 5.5, LIGHT_BG)
add_textbox(slide2, 7.1, 1.5, 5.2, 0.5, '建设目标', 22, GOLD, True)

goal_items = [
    ('安全保密', '物理隔离+国密加密+水印+远程擦除，\n五重保障材料安全'),
    ('极简体验', '15位常委只需翻页和缩放，\n大字号大按钮，操作门槛极低'),
    ('格式保真', '4类材料100%还原原版排版，\n审批表3.0标准格式完整呈现'),
]
y = 2.2
for title, desc in goal_items:
    add_textbox(slide2, 7.3, y, 4.8, 0.4, f'▶ {title}', 16, WHITE, True)
    add_textbox(slide2, 7.6, y+0.45, 4.6, 0.8, desc, 13, LIGHT_TEXT)
    y += 1.5

add_notes(slide2, '建设背景方面，2019年修订的《干部任用条例》对任用程序提出了更高要求。传统纸质材料存在印制耗时、分发繁琐、保密风险高等问题。目前PAD加局域网加国密加密的技术已经成熟，具备无纸化上会条件。建设目标有三点：一是安全保密，通过五重保障确保材料安全；二是极简体验，15位常委只需翻页和缩放；三是格式保真，四类材料原版还原，审批表严格按3.0标准呈现。')

# ═══════════════════════════════════════
# 第3页：系统功能与界面
# ═══════════════════════════════════════
slide3 = prs.slides.add_slide(prs.slide_layouts[6])
add_bg(slide3, DARK_BG)
add_rect(slide3, 0, 0, 13.333, 0.08, GOLD)
add_textbox(slide3, 0.8, 0.3, 10, 0.7, '二、系统功能与界面展示', 30, GOLD, True)

# 左侧：功能列表
add_rect(slide3, 0.8, 1.3, 5.8, 5.5, LIGHT_BG)
add_textbox(slide3, 1.0, 1.5, 5.4, 0.5, '七大功能模块', 22, GOLD, True)

funcs = [
    ('① 首页仪表板', '会议信息、功能入口、议程概览'),
    ('② 干部名册', '12位干部卡片列表，支持搜索定位'),
    ('③ 材料查看', '汇报材料、任免审批表、考察材料'),
    ('④ 审批表3.0', '严格按中组部标准格式完整呈现'),
    ('⑤ 安全管理', '水印、远程擦除、会后清零'),
    ('⑥ 操作留痕', '查看行为全程记录，可审计追溯'),
    ('⑦ 个人中心', '设备信息、安全说明、退出登录'),
]
y = 2.2
for title, desc in funcs:
    add_textbox(slide3, 1.2, y, 5.0, 0.35, title, 15, WHITE, True)
    add_textbox(slide3, 1.5, y+0.35, 4.8, 0.35, desc, 12, LIGHT_TEXT)
    y += 0.65

# 右侧：截图
import os
screenshots = [
    ('/data/www/files/screenshots/pad_01_home.png', '系统首页'),
    ('/data/www/files/screenshots/pad_04_approval.png', '任免审批表3.0格式'),
]
x = 7.0
for img_path, label in screenshots:
    if os.path.exists(img_path):
        slide3.shapes.add_picture(img_path, Inches(x), Inches(1.5), height=Inches(2.4))
        add_textbox(slide3, x-0.2, 3.95, 3.5, 0.35, label, 12, GOLD, True, PP_ALIGN.CENTER)
        x += 3.2

# 底部补充说明
add_rect(slide3, 7.0, 4.5, 5.6, 2.3, LIGHT_BG)
add_textbox(slide3, 7.2, 4.6, 5.2, 0.4, '审批表3.0标准格式', 16, GOLD, True)
features_30 = [
    '• 基本信息：姓名/性别/民族/出生年月/籍贯等',
    '• 学历学位：全日制教育 + 在职教育',
    '• 简历：完整工作履历（8-10段经历）',
    '• 奖惩情况、年度考核结果',
    '• 家庭主要成员及重要社会关系',
    '• 呈报单位、审批机关意见、行政机关任免意见',
]
y = 5.05
for f in features_30:
    add_textbox(slide3, 7.3, y, 5.0, 0.25, f, 11, LIGHT_TEXT)
    y += 0.28

add_notes(slide3, '系统共七大功能模块。首页仪表板展示会议信息和功能入口；干部名册以卡片形式展示12位干部，支持搜索；材料查看包含汇报材料、任免审批表、考察材料三类；审批表严格按照中组部3.0标准格式完整呈现，包含基本信息、学历学位、简历、奖惩情况、年度考核、家庭成员、呈报单位、审批机关意见等全部字段；安全管理模块提供水印、远程擦除、会后清零功能；操作留痕全程记录查看行为；个人中心展示设备信息和安全说明。右侧是系统实际运行截图。')

# ═══════════════════════════════════════
# 第4页：安全保密与实施计划
# ═══════════════════════════════════════
slide4 = prs.slides.add_slide(prs.slide_layouts[6])
add_bg(slide4, DARK_BG)
add_rect(slide4, 0, 0, 13.333, 0.08, GOLD)
add_textbox(slide4, 0.8, 0.3, 10, 0.7, '三、安全保密与实施计划', 30, GOLD, True)

# 左侧：安全体系
add_rect(slide4, 0.8, 1.3, 5.6, 5.5, LIGHT_BG)
add_textbox(slide4, 1.0, 1.5, 5.2, 0.5, '五重安全保障体系', 22, GOLD, True)

security = [
    ('① 物理隔离', '专用局域网部署，与互联网物理隔离'),
    ('② 国密加密', 'SM2/SM3/SM4国密算法加密传输与存储'),
    ('③ 屏幕水印', '全屏叠加常委姓名+时间戳水印，可追溯'),
    ('④ 远程擦除', '管理员可远程一键清除任意/全部PAD数据'),
    ('⑤ 会后清零', '会议结束后所有PAD数据自动清除，不留痕迹'),
]
y = 2.2
for title, desc in security:
    add_textbox(slide4, 1.2, y, 5.0, 0.35, title, 15, WHITE, True)
    add_textbox(slide4, 1.5, y+0.35, 4.8, 0.35, desc, 12, LIGHT_TEXT)
    y += 0.85

# 右侧：实施计划
add_rect(slide4, 6.9, 1.3, 5.6, 5.5, LIGHT_BG)
add_textbox(slide4, 7.1, 1.5, 5.2, 0.5, '三期建设计划', 22, GOLD, True)

phases = [
    ('一期（MVP）', '第1-2月', '核心功能上线', '会议创建、材料上传推送、PAD查看、会后清除'),
    ('二期（增强）', '第3月', '安全加固', '水印/防截屏/远程擦除/留痕审计/国密加密'),
    ('三期（完善）', '第3月', '体验优化', '同步控制/搜索定位/书签标记/统计报表'),
]
y = 2.2
colors = [RGBColor(0x4A, 0x90, 0xD9), RGBColor(0xC4, 0x1E, 0x3A), RGBColor(0x5C, 0xB8, 0x5C)]
for i, (phase, time, focus, detail) in enumerate(phases):
    add_rect(slide4, 7.1, y, 0.06, 1.2, colors[i])
    add_textbox(slide4, 7.3, y, 2.0, 0.35, phase, 16, WHITE, True)
    add_textbox(slide4, 9.3, y, 1.5, 0.35, time, 13, GOLD)
    add_textbox(slide4, 7.3, y+0.35, 5.0, 0.3, focus, 13, colors[i], True)
    add_textbox(slide4, 7.3, y+0.65, 5.0, 0.5, detail, 11, LIGHT_TEXT)
    y += 1.5

# 底部总结
add_rect(slide4, 0.8, 6.2, 11.7, 0.6, RGBColor(0x2A, 0x3A, 0x5C))
add_textbox(slide4, 1.0, 6.25, 11.3, 0.5, '总工期：3个月  |  一期上线即可满足上会使用需求  |  二期三期逐步完善安全与体验', 14, GOLD, True, PP_ALIGN.CENTER)

add_notes(slide4, '安全保密是本系统的核心。我们设计了五重保障：第一，物理隔离，专用局域网不连互联网；第二，国密加密，采用SM2/SM3/SM4算法；第三，屏幕水印，全屏叠加常委姓名和时间戳；第四，远程擦除，管理员可远程清除数据；第五，会后清零，会议结束自动清除。实施计划分三期：一期两个月完成核心功能，二期一个月完成安全加固，三期一个月完成体验优化。总工期3个月，一期上线即可满足上会使用。')

# ═══════════════════════════════════════
# 第5页：投资预算
# ═══════════════════════════════════════
slide5 = prs.slides.add_slide(prs.slide_layouts[6])
add_bg(slide5, DARK_BG)
add_rect(slide5, 0, 0, 13.333, 0.08, GOLD)
add_textbox(slide5, 0.8, 0.3, 10, 0.7, '四、投资预算', 30, GOLD, True)

# 预算表
add_rect(slide5, 0.8, 1.3, 11.7, 0.5, RGBColor(0x2A, 0x3A, 0x5C))
headers = [('序号', 0.8, 1.0), ('费用项目', 1.8, 3.0), ('内容说明', 4.8, 5.0), ('金额(元)', 9.8, 2.7)]
for h, x, w in headers:
    add_textbox(slide5, x, 1.35, w, 0.4, h, 16, GOLD, True, PP_ALIGN.CENTER)

items = [
    ('1', '软件开发费', 'PAD端APP+管理端Web+服务端，含4类材料渲染、安全管理、留痕审计', '30,000'),
    ('2', '系统部署费', '服务器环境搭建、局域网配置、PAD设备注册调试', '8,000'),
    ('3', '数据迁移费', '历史干部材料格式转换、审批表3.0模板适配', '5,000'),
    ('4', '培训服务费', '管理员操作培训2场+常委使用指导+操作手册', '4,000'),
    ('5', '一年运维费', '系统维护、Bug修复、小功能调整（一年期）', '3,000'),
]
y = 1.9
for i, (no, item, desc, amount) in enumerate(items):
    bg_color = LIGHT_BG if i % 2 == 0 else RGBColor(0x1D, 0x2A, 0x48)
    add_rect(slide5, 0.8, y, 11.7, 0.7, bg_color)
    add_textbox(slide5, 0.8, y+0.15, 1.0, 0.4, no, 14, WHITE, False, PP_ALIGN.CENTER)
    add_textbox(slide5, 1.8, y+0.15, 3.0, 0.4, item, 14, WHITE, True)
    add_textbox(slide5, 4.8, y+0.1, 5.0, 0.5, desc, 11, LIGHT_TEXT)
    add_textbox(slide5, 9.8, y+0.15, 2.7, 0.4, amount, 16, GOLD, True, PP_ALIGN.CENTER)
    y += 0.72

# 合计行
add_rect(slide5, 0.8, y, 11.7, 0.6, RGBColor(0x8B, 0x1A, 0x1A))
add_textbox(slide5, 0.8, y+0.1, 8.7, 0.4, '合  计', 18, WHITE, True, PP_ALIGN.CENTER)
add_textbox(slide5, 9.8, y+0.1, 2.7, 0.4, '50,000', 20, GOLD, True, PP_ALIGN.CENTER)
y += 0.65
add_textbox(slide5, 0.8, y, 11.7, 0.4, '人民币伍万元整', 14, GOLD, False, PP_ALIGN.CENTER)

# 备注
add_rect(slide5, 0.8, y+0.6, 11.7, 0.8, LIGHT_BG)
add_textbox(slide5, 1.0, y+0.65, 11.3, 0.7, '备注：\n1. 以上报价含软件开发、部署、培训及一年运维费用\n2. 硬件设备（服务器/PAD/交换机等）由采购方自行采购，我方提供选型建议\n3. 一年期满后运维费用另行协商，预计每年3,000-5,000元', 11, LIGHT_TEXT)

add_notes(slide5, '投资预算总计5万元，含五项费用：软件开发费3万元，占大头，包含PAD端、管理端、服务端全套开发；系统部署费8千元；数据迁移费5千元；培训服务费4千元；一年运维费3千元。硬件设备由采购方自行采购，我方提供选型建议。一年运维期满后，每年运维费预计3到5千元。以上汇报完毕，请各位领导审议。')

# 保存
output_path = '/data/www/files/cadre-report-short.pptx'
prs.save(output_path)
print(f'PPT saved: {output_path}')

import os
print(f'File size: {os.path.getsize(output_path)} bytes')
