#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""通用版公司简介 PPT 润色 V02（第一轮 8 页）
- P1 封面：按 2026-11-03 确认版式，白 Logo、两行标题、2026版、右下 slogan
- P4 公司简介：四段空话改成四条事实
- P6 资质与荣誉：证书拼贴改成 8 张资质卡，移除已过期的“小巨人”牌匾
- P7 人员概况：修正错字，重画两组结构条形图
- P8 业务布局：空装饰页改成三业务线矩阵
- P10 生命科学：从“酶进化平台”改成四类科研试剂，平台放底部
- P13 创新成果 / P14 市场覆盖：重排，补口径与脚注

不重建其余 15 页，保留原模板、原背景、原图片。
"""
from copy import deepcopy
from pathlib import Path

from pptx import Presentation
from pptx.dml.color import RGBColor
from pptx.enum.shapes import MSO_SHAPE
from pptx.enum.text import MSO_ANCHOR, PP_ALIGN
from pptx.oxml.ns import qn
from pptx.util import Inches, Pt
from lxml import etree

ROOT = Path('/Users/liuxinyuan/Desktop/Hermes输出-工作类')
SRC = Path('/Users/liuxinyuan/.hermes/profiles/zone-b/cache/documents/native-inputs/d1327ff4a3e027044f78c0e3f8df52e39dcf594d72fb7610f4d377fe1cc04b8f/doc_67a3f0968d75_珠海宝锐生物科技有限公司简介PPT-通用版.pptx')
OUT = ROOT / 'PPT撰写任务/公司简介PPT_通用版_润色_20261103/珠海宝锐生物科技有限公司简介PPT-通用版_20261103_V02.pptx'
LOGO_WHITE = Path('/Users/liuxinyuan/work/公司资料/logo_white_transparent.png')

NAVY = RGBColor(0x1F, 0x38, 0x64)
BLUE = RGBColor(0x1F, 0x4E, 0x79)
TEAL = RGBColor(0x2A, 0x9D, 0x8F)
GREY = RGBColor(0x59, 0x59, 0x59)
MID = RGBColor(0x9E, 0xB3, 0xC8)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
PALE = RGBColor(0xF2, 0xF7, 0xFC)
ORANGE = RGBColor(0xC5, 0x6A, 0x1F)
LINE = RGBColor(0xD8, 0xE6, 0xEF)


def set_run(run, size, bold=False, color=NAVY, font='微软雅黑'):
    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()
    for tag in ('a:latin', 'a:ea', 'a:cs'):
        el = rPr.find(qn(tag))
        if el is None:
            el = etree.SubElement(rPr, qn(tag))
        el.set('typeface', font)


def add_text(slide, x, y, w, h, text, size=14, bold=False, color=NAVY,
             align=PP_ALIGN.LEFT, anchor=MSO_ANCHOR.TOP, line=1.35,
             space_after=4, font='微软雅黑'):
    box = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h))
    tf = box.text_frame
    tf.clear()
    tf.word_wrap = True
    tf.margin_left = tf.margin_right = 0
    tf.margin_top = tf.margin_bottom = 0
    tf.vertical_anchor = anchor
    p = tf.paragraphs[0]
    p.alignment = align
    p.line_spacing = line
    p.space_after = Pt(space_after)
    r = p.add_run()
    r.text = text
    set_run(r, size, bold, color, font)
    return box


def no_bullet(p):
    pPr = p._p.get_or_add_pPr()
    for tag in ('a:buChar', 'a:buAutoNum', 'a:buNone'):
        for el in pPr.findall(qn(tag)):
            pPr.remove(el)
    etree.SubElement(pPr, qn('a:buNone'))


def add_rect(slide, x, y, w, h, fill=WHITE, line_color=LINE, radius=True):
    shape = slide.shapes.add_shape(
        MSO_SHAPE.ROUNDED_RECTANGLE if radius else MSO_SHAPE.RECTANGLE,
        Inches(x), Inches(y), Inches(w), Inches(h)
    )
    shape.fill.solid()
    shape.fill.fore_color.rgb = fill
    if line_color is None:
        shape.line.fill.background()
    else:
        shape.line.color.rgb = line_color
        shape.line.width = Pt(0.8)
    return shape


def add_line(slide, x1, y1, x2, y2, color=LINE, width=0.8):
    shp = slide.shapes.add_connector(1, Inches(x1), Inches(y1), Inches(x2), Inches(y2))
    shp.line.color.rgb = color
    shp.line.width = Pt(width)
    return shp


def clear_except(slide, keep):
    for i in range(len(slide.shapes) - 1, -1, -1):
        if i not in keep:
            shp = slide.shapes[i]
            shp._element.getparent().remove(shp._element)


def replace_title(slide, title):
    sh = slide.shapes[1]
    tf = sh.text_frame
    tf.clear()
    p = tf.paragraphs[0]
    r = p.add_run()
    r.text = title
    set_run(r, 20, True, NAVY)


def p4_rewrite(slide):
    # 保留原有 Logo、标题、圆角底板、总部照片，只重写正文
    sh = slide.shapes[2]
    tf = sh.text_frame
    tf.clear()
    tf.word_wrap = True
    tf.margin_left = tf.margin_right = 0
    tf.margin_top = tf.margin_bottom = 0
    entries = [
        ('2012 年成立于珠海', '为工业和科研客户提供生物原料与试剂。'),
        ('三条业务线', '诊断原料、生命科学、生物医药。'),
        ('规模与体系', '总部园区 2.6 万㎡，9 套 GMP 洁净车间；通过 ISO 9001、ISO 13485 认证。'),
        ('资质与平台', '国家高新技术企业、广东省专精特新中小企业、广东省分子诊断原料酶工程技术研究中心。'),
    ]
    for i, (head, body) in enumerate(entries):
        p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
        p.alignment = PP_ALIGN.LEFT
        p.line_spacing = 1.45
        p.space_after = Pt(10)
        r1 = p.add_run(); r1.text = head + '：'
        set_run(r1, 14, True, BLUE)
        r2 = p.add_run(); r2.text = body
        set_run(r2, 14, False, RGBColor(0x33, 0x33, 0x33))
        no_bullet(p)


def p6_cards(slide):
    clear_except(slide, [0, 1])
    replace_title(slide, '资质与荣誉')
    cards = [
        ('国家高新技术企业', '2017 年首次认定'),
        ('广东省专精特新中小企业', '2021 年'),
        ('广东省分子诊断原料酶工程技术研究中心', '2023 年'),
        ('珠海市企业技术中心', '2023 年'),
        ('广东省博士后创新实践基地', '2024 年'),
        ('ISO 9001:2015', '质量管理体系认证'),
        ('ISO 13485:2016', '医疗器械质量管理体系'),
        ('珠海市创新百强企业', '2022–2024 连续三年'),
    ]
    xs = [0.75, 3.90, 7.05, 10.20]
    ys = [1.55, 3.62]
    for i, (title, sub) in enumerate(cards):
        x = xs[i % 4]; y = ys[i // 4]
        add_rect(slide, x, y, 2.90, 1.82, WHITE, LINE, True)
        add_rect(slide, x, y, 0.06, 1.82, TEAL if i < 5 else BLUE, None, False)
        _ts = 11.5 if len(title) > 16 else 13.5
        add_text(slide, x + 0.22, y + 0.16, 2.45, 0.78, title, _ts, True, NAVY, line=1.2)
        add_text(slide, x + 0.22, y + 1.12, 2.45, 0.35, sub, 10.5, False, GREY)
    add_text(slide, 0.75, 6.25, 11.8, 0.3,
             '按公司公开资料整理；对外使用时以现行有效证书为准。', 9.5, False, MID)


def p7_charts(slide):
    clear_except(slide, [0, 1])
    replace_title(slide, '人员概况')
    panels = [
        ('按岗位', [('研发', 50), ('生产质量', 20), ('营销', 18), ('管理', 12)], 0.80),
        ('按学历', [('本科', 40), ('硕士 / 博士', 35), ('大专', 20), ('其他', 5)], 6.85),
    ]
    colors = [BLUE, TEAL, ORANGE, MID]
    for title, rows, x in panels:
        add_rect(slide, x, 1.58, 5.65, 4.55, WHITE, LINE, True)
        add_text(slide, x + 0.35, 1.82, 4.9, 0.35, title, 17, True, NAVY)
        add_text(slide, x + 0.35, 2.20, 4.9, 0.25, '占全员比例', 9.5, False, GREY)
        for i, (label, value) in enumerate(rows):
            y = 2.78 + i * 0.72
            add_text(slide, x + 0.35, y, 1.55, 0.3, label, 12.5, False, RGBColor(0x33, 0x33, 0x33))
            add_rect(slide, x + 2.0, y + 0.08, 2.55, 0.18, PALE, None, False)
            add_rect(slide, x + 2.0, y + 0.08, 2.55 * value / 100, 0.18, colors[i], None, False)
            add_text(slide, x + 4.70, y - 0.02, 0.65, 0.3, f'{value}%', 11.5, True, colors[i], PP_ALIGN.RIGHT)
    add_text(slide, 0.80, 6.35, 11.7, 0.3,
             '数据口径：按公司现有人力结构统计，四舍五入到整数百分比。', 9.5, False, MID)


def p8_matrix(slide):
    clear_except(slide, [0, 1])
    replace_title(slide, '业务布局')
    headers = ['业务线', '核心产品', '客户与场景']
    widths = [2.20, 5.75, 3.75]
    xs = [0.80, 3.10, 8.95]
    rows = [
        ('诊断原料', '分子酶、qPCR/RT-qPCR/LAMP 预混、冻干保护剂', 'IVD、POCT、病原检测'),
        ('生命科学', '工具酶、核酸提取、测序试剂、蛋白质研究', '高校、科研院所、CRO'),
        ('生物医药', 'mRNA/circRNA 原料、HCD/HCP、质量检测', '疫苗、细胞与基因治疗、生物药'),
    ]
    # 表头
    add_rect(slide, 0.80, 1.45, 11.70, 0.52, BLUE, None, False)
    for x, w, h in zip(xs, widths, headers):
        add_text(slide, x + 0.18, 1.56, w - 0.25, 0.3, h, 12, True, WHITE)
    colors = [BLUE, TEAL, ORANGE]
    for i, (dept, products, customers) in enumerate(rows):
        y = 2.10 + i * 1.38
        add_rect(slide, 0.80, y, 11.70, 1.22, WHITE if i % 2 == 0 else PALE, LINE, True)
        add_rect(slide, 0.80, y, 0.08, 1.22, colors[i], None, False)
        add_text(slide, xs[0] + 0.20, y + 0.18, widths[0] - 0.3, 0.35, dept, 16, True, colors[i])
        add_text(slide, xs[1] + 0.05, y + 0.16, widths[1] - 0.25, 0.85, products, 12.5, False, RGBColor(0x33, 0x33, 0x33), line=1.35)
        add_text(slide, xs[2] + 0.05, y + 0.35, widths[2] - 0.25, 0.65, customers, 12.5, False, RGBColor(0x33, 0x33, 0x33), line=1.35)
    add_text(slide, 0.80, 6.45, 11.7, 0.3,
             '三条业务线共用酶工程、重组表达、工艺开发与质量管理平台。', 10.5, True, TEAL)


def p10_life_science(slide):
    clear_except(slide, [])
    # 右侧标题条，沿用原页的版式
    add_rect(slide, 8.35, 0.38, 3.35, 0.42, BLUE, None, False)
    add_text(slide, 8.48, 0.47, 3.05, 0.25, '生命科学', 15, True, WHITE, PP_ALIGN.RIGHT)
    add_line(slide, 5.65, 0.59, 8.30, 0.59, MID, 0.8)
    add_text(slide, 0.80, 1.15, 11.7, 0.35, '科研试剂：从提取、扩增、建库到蛋白研究', 20, True, NAVY)
    cards = [
        ('01', '分子生物学', 'qPCR、RT-qPCR 预混液，工具酶与反转录酶'),
        ('02', '核酸提取与纯化', '磁珠法、柱式提取，样本前处理'),
        ('03', '测序试剂', '建库、纯化、质控'),
        ('04', '蛋白质研究', '蛋白纯化、电泳、检测'),
    ]
    coords = [(0.80, 1.85), (6.60, 1.85), (0.80, 3.55), (6.60, 3.55)]
    for (num, title, body), (x, y) in zip(cards, coords):
        add_rect(slide, x, y, 5.50, 1.45, WHITE, LINE, True)
        add_text(slide, x + 0.25, y + 0.16, 0.55, 0.4, num, 18, True, TEAL)
        add_text(slide, x + 0.85, y + 0.15, 4.3, 0.35, title, 15, True, NAVY)
        add_text(slide, x + 0.85, y + 0.63, 4.3, 0.55, body, 12, False, RGBColor(0x33, 0x33, 0x33), line=1.35)
    add_rect(slide, 0.80, 5.55, 11.30, 0.72, PALE, None, True)
    add_text(slide, 1.05, 5.75, 10.8, 0.3,
             '底层平台：蛋白进化 · 重组表达 · 工艺开发 · 应用验证', 12, True, BLUE)
    add_text(slide, 0.80, 6.60, 11.7, 0.3,
             '覆盖科研试剂从提取、扩增、建库到蛋白研究的主要环节。', 9.5, False, MID)


def p13_innovation(slide):
    clear_except(slide, [0, 1])
    replace_title(slide, '创新成果')
    cols = [
        ('国内首发', ['T7 RNA 聚合酶', 'RNase R', 'Bsp Q Ⅰ', 'EcoR Ⅰ'], 'FDA DMF 备案'),
        ('国内首创', ['螺原体 DNA 检测试剂', 'RNA Ladder', 'RNA 完整性检测试剂盒', 'circRNA 合成试剂盒'], ''),
        ('国内首款', ['2–8℃ 液态保存分子诊断试剂', '冻干型超灵敏分子诊断试剂', '冻干型高灵敏直扩试剂', '全血直扩分型检测试剂', '单管稳定高灵敏试剂'], ''),
    ]
    xs = [0.80, 4.55, 8.30]
    colors = [BLUE, TEAL, ORANGE]
    for i, (head, items, badge) in enumerate(cols):
        x = xs[i]
        add_rect(slide, x, 1.50, 3.45, 4.55, WHITE, LINE, True)
        add_rect(slide, x, 1.50, 3.45, 0.08, colors[i], None, False)
        add_text(slide, x + 0.25, 1.75, 3.0, 0.35, head, 17, True, colors[i])
        if badge:
            add_text(slide, x + 0.25, 2.15, 2.9, 0.25, badge, 9.5, True, GREY)
        for j, item in enumerate(items):
            y = 2.52 + j * 0.58
            add_text(slide, x + 0.25, y, 0.25, 0.3, '·', 14, True, colors[i])
            add_text(slide, x + 0.48, y, 2.75, 0.5, item, 11.5, False, RGBColor(0x33, 0x33, 0x33), line=1.25)
    add_text(slide, 0.80, 6.35, 11.7, 0.5,
             '截至 2026-10，按公司公开资料整理；对外引用前请以注册/备案信息为准。',
             9.5, False, MID, line=1.3)


def p14_market(slide):
    clear_except(slide, [0, 1])
    replace_title(slide, '市场覆盖')
    add_text(slide, 0.80, 1.45, 11.7, 0.3, '截至 2026 年 10 月', 10.5, False, GREY)
    kpis = [('130+', '上市公司客户'), ('2,000+', '工业与科研客户'), ('3,000+', '上线产品品类')]
    xs = [0.80, 4.55, 8.30]
    for (num, label), x in zip(kpis, xs):
        add_rect(slide, x, 1.95, 3.45, 1.95, WHITE, LINE, True)
        add_text(slide, x + 0.3, 2.20, 2.85, 0.65, num, 34, True, BLUE)
        add_text(slide, x + 0.3, 3.05, 2.85, 0.35, label, 12, False, GREY)
    add_text(slide, 0.80, 4.35, 11.7, 0.35, '主要客户类型', 12, True, NAVY)
    chips = ['IVD / POCT', '疫苗 / 细胞与基因治疗', '高校 / 科研院所']
    xs2 = [0.80, 4.55, 8.30]
    for text, x in zip(chips, xs2):
        add_rect(slide, x, 4.85, 3.45, 0.65, PALE, None, True)
        add_text(slide, x + 0.15, 5.02, 3.15, 0.3, text, 11.5, True, BLUE, PP_ALIGN.CENTER)
    add_text(slide, 0.80, 6.25, 11.7, 0.5,
             '客户覆盖生物医药、体外诊断与科研院所；具体客户名单以授权口径为准。',
             9.5, False, MID, line=1.3)


def p1_cover(slide):
    # 保留第一张全屏背景图，其余旧标题/日期/Loog 全部移除
    clear_except(slide, [0])
    slide.shapes.add_picture(str(LOGO_WHITE), Inches(0.62), Inches(0.38), width=Inches(1.75))
    add_text(slide, 2.30, 2.30, 8.75, 0.80, '宝锐生物', 50, True, WHITE, PP_ALIGN.CENTER)
    add_text(slide, 2.30, 3.18, 8.75, 0.80, '公司简介', 50, True, WHITE, PP_ALIGN.CENTER)
    add_text(slide, 2.30, 4.30, 8.75, 0.40, '2026版', 22, False, WHITE, PP_ALIGN.CENTER)
    add_text(slide, 7.10, 6.82, 5.60, 0.30, '守护生命健康 · 缔造美好生活', 12, False, WHITE, PP_ALIGN.RIGHT)


def main():
    prs = Presentation(str(SRC))
    slides = list(prs.slides)
    p1_cover(slides[0])
    p4_rewrite(slides[3])
    p6_cards(slides[5])
    p7_charts(slides[6])
    p8_matrix(slides[7])
    p10_life_science(slides[9])
    p13_innovation(slides[12])
    p14_market(slides[13])
    prs.save(str(OUT))
    print('written', OUT, OUT.stat().st_size, 'slides', len(prs.slides))


if __name__ == '__main__':
    main()
