import argparse
from copy import copy
from pathlib import Path

from openpyxl import load_workbook
from openpyxl.drawing.image import Image as XLImage
from openpyxl.styles import Alignment, Border, Font, PatternFill, Side
from openpyxl.utils import get_column_letter


ROOT = Path(__file__).resolve().parents[4]
TEMPLATE = Path("/Users/jack/同步空间/cpt/05_经营管理与会议/005_日常管理/周例会（事业部层面）/2026年/周报模板.xlsx")
OUTPUT = Path(__file__).with_name("数字技术中心周报_姜阳_20260824-20260830.xlsx")

TITLE = "数字技术中心周工作汇报（20260824-20260830）"
MEETING_URL = "https://zhctpmt.yyangpt.cn/work/2026-08-28-weekly-meeting/weekly-meeting-minutes.html"
DELIVERY_SOURCE = "/Users/jack/Downloads/交付实施部-项目管理空间.xlsx"

BLUE = "17365D"
TEAL = "0F6B68"
SKY = "DCEAF7"
PALE_TEAL = "DDEFE9"
PALE_GOLD = "FFF1CC"
PALE_RED = "FCE4E4"
PALE_GRAY = "F1F3F5"
WHITE = "FFFFFF"
TEXT = "243447"
MUTED = "5B6573"
THIN = Side(style="thin", color="B7C1CC")


PROJECT_ROWS = [
    [1, "学校", "交付/联调", "中央美院", "8/30前完成安卓调试、服务器部署与业务验证", "待商务确认", "柴玉龙 / 孙海琴 / 赖清涛", "待商务确认", "设备已到场，采购状态待回读", "一卡通服务端接口、局域网测试和先取餐后绑盘主流程已完成", "客户上线待现场验证", "未验收", "待商务/财务确认", "上周完成Windows方案与接口测试，安卓、部署和业务验证未闭环", "完成安卓调试、服务器部署、现场一卡通联调及业务流程回读", "原计划8/20节点已过；真实一卡通、客户网络与现场窗口仍是外部门禁", "项目总表标记筹备中；不得把局域网测试写成客户验收", MEETING_URL],
    [2, "企业", "交付/方案冻结", "三全集团", "8/31前锁定大餐厅刷脸与支付宝方案", "待商务确认", "赵野 / 李潇 / 赖清涛 / 兰海军", "待商务确认", "设备与外部系统清单待确认", "已对齐人力、财务、业务流程，1台AI结算台接入正式系统", "部分设备接入正式系统；整体未验收", "未验收", "待商务/财务确认", "上周聚焦需求范围、白屏问题和多系统链路梳理", "形成进销存开发对接方案，敲定刷脸结算、支付宝、钉钉、魔点及商米消费机联调计划", "多系统、高复杂度；人脸资格与支付宝真实资金链必须分开验收", "项目总表标记很高复杂度，建议专项里程碑推进", MEETING_URL],
    [3, "企业", "交付/上线准备", "四方达项目", "下周完成正式环境测试、数据导入和系统切换", "待商务确认", "赵野 / 王朔 / 赖清涛 / 郭东伟", "待商务确认", "硬件安装完成", "终端应用安装完成，测试环境通过；补贴核算与导出能力完成开发", "正式环境待验证", "未验收", "待商务/财务确认", "上周完成部署及域名/证书推进，达标补贴转入本周", "完成正式环境测试、数据导入、系统切换和跟餐运维", "小程序违规投诉、安全证书和客户局域网开通仍影响上线节奏", "消费达标补贴能力可沉淀为标准核算与导入资产", MEETING_URL],
    [4, "职业学校", "交付/开学保障", "滨州健康科技职业学院", "8/24-8/28开学现场保障", 550000, "王金洋 / 张帅 / 兰海军", "待商务确认", "设备配件更换中", "完成软装调整、410配件更换、现场跟餐、一卡通信息纠错和软件升级", "现场运行中", "未验收", "待商务/财务确认", "上周1500+餐盘投入使用，扫码器、进销存和开学保障待闭环", "持续做新生开学保障，形成硬件问题闭环表并验证打印机出餐方案", "72台设备、多接口并行；开餐窗口和厂商整改优先级高", "本周将手机号纠错方法移交信息中心，降低重复支持依赖", DELIVERY_SOURCE],
    [5, "政府", "售后/迁移联调", "江西206", "下周完成服务器迁移、回归与留样柜联调", 399820, "张帅 / 王金洋 / 侯世伟 / 赖清涛 / 孙倩倩", "待商务确认", "不涉及/待确认", "系统升级、压力测试、餐厅ID升级及前厅菜品/菜谱下发留样柜联调", "历史环境在用；本轮变更待回归", "待回读", "待商务/财务确认", "上周设备网络与留样柜问题持续影响联调", "冻结迁移清单，完成设备连通、业务回归和厂商联合验收", "网络、设备和厂商配合是前置门禁；不能以压力测试替代业务验收", "政府本地部署场景，可沉淀迁移与设备联调SOP", MEETING_URL],
    [6, "部队", "交付/需求开发", "安徽武警部队", "9/2前完成第一阶段门槛回读", "待商务确认", "侯世伟 / 赵野 / 李潇 / 赖清涛", "待商务确认", "设备点位与清单已梳理", "完成资料研读、软硬件边界梳理、需求文档和网络/电源/设备点位确认", "待部署/测试", "未验收", "待商务/财务确认", "上周完成服务器规划与部署准备，业务验收未提供", "按冻结需求完成开发测试，明确本地服务器、前厅大屏与食安范围", "项目总表上线日期早于开始日期，计划基线需校正", "部队场景同时覆盖智慧营养与进销存，需分模块验收", DELIVERY_SOURCE],
    [7, "企业", "交付/标准版部署", "哈尔滨膳质舍", "合同生效后30天交货；目标9/23", 123000, "赵野 / 李潇 / 兰海军", "合同扫描件日期待确认", "软硬件清单已锁，付款/发票待确认", "完成合同核验、范围补录和餐盘利旧方案；本周转入部署准备", "待上线", "未验收", "合同约定签后3个工作日付款，到账待确认", "上周明确项目范围、设备清单和餐盘利旧方向", "部署标准产品，推进体检一体机、炒菜机器人和政企营养PC/移动端联调", "合同生效日、交付地点、付款到账和外部设备接口尚未冻结", "标准版复制候选；当前定制化比例记录为80%，需控制范围", MEETING_URL],
    [8, "企业", "交付/运维", "金斯瑞", "下周完成取餐柜安装调试及交互大屏维修", 454250, "张帅 / 王金洋 / 李潇 / 赖清涛", "待商务确认", "取餐柜制作发货中", "镇江交互大屏厂家维修，持续跟进取餐柜制作发货和日常运维", "在用环境持续运维", "未验收/待回读", "待商务/财务确认", "前期已完成多设备、食安与南京/镇江联调", "取餐柜到货安装调试，关闭大屏触摸异常并回读现场运行", "历史计划周期已明显超过；验收与服务边界需重新核对", "AI生成菜品图存在现场一致性解释风险，本周未采纳", DELIVERY_SOURCE],
    [9, "医院", "交付/运维", "国康医院", "下周上线绑盘机修复版本", "待商务确认", "张帅 / 柴玉龙 / 孙海琴 / 王朔", "待商务确认", "设备已交付，状态待回读", "设备端人工补单上线并完成培训；记录称重机需求与绑盘刷卡异常", "补单已上线；绑盘问题待修复", "待验收回读", "待商务/财务确认", "上周完成设备版本升级与现场问题处置", "上线绑盘机新版本，验证刷卡异常关闭并形成回归记录", "人工补单上线不等于整体项目验收；绑盘异常仍影响现场体验", "补单管理已回收到标准产品能力", DELIVERY_SOURCE],
    [10, "政府", "运维/安全整改", "城市副中心（C08）", "8/30前形成修复、验证及复扫材料", "待商务确认", "赵野 / 李潇 / 赖清涛", "待商务确认", "设备维护中", "现场跟餐、称重串口稳定性更新、流程视频、大屏错版优化及断网恢复", "运营中", "待回读", "待商务/财务确认", "上周漏洞整改仍进行中，未取得复扫结论", "完成漏洞修复验证、复扫材料和断网恢复证据", "复扫结论和外部窗口未锁；未取得报告不得写安全闭环", "政务云高复杂度项目，需保持发布/复扫四态口径", DELIVERY_SOURCE],
    [11, "企业", "运维/需求回收", "机场团餐项目", "下周完成负值补贴批量导入功能", "待商务确认", "张帅 / 李潇 / 赖清涛", "一期已签，二期待确认", "一期已完成", "记录新需求并评估可上线边界", "运营中", "待回读", "待商务/财务确认", "本周AI辅助确认两份报表109.40元差异来自新增审核退款", "上线并回归表格批量负数补贴功能，补齐报表口径说明", "需求是否进入标准产品尚需产品评审；退款口径需持续防止误判", "机场报表核对案例已沉淀为AI辅助数据诊断方法", MEETING_URL],
    [12, "企业", "交付/性能验证", "重庆环卫", "下周继续压力测试和客户环境回验", "待商务确认", "柴玉龙 / 李潇 / 赖清涛 / 孙倩倩", "待商务确认", "设备安装包持续完善", "完成450页面变更、小票备注、小程序登录调整、SQL修复和压力测试模拟", "部分变更上线；客户整体状态待确认", "未验收", "待商务/财务确认", "上周咖啡机在演示环境联调，域名/证书与小程序发布有记录", "完成客户环境压力测试，统一演示上线、客户上线和验收口径", "演示环境与客户环境容易混淆；正式压力测试证据仍需补齐", "450称重与多设备场景可形成回归基线", MEETING_URL],
    [13, "企业", "交付/高优需求", "国信智慧食堂", "下周回读5项高优需求客户环境状态", 561380, "柴玉龙 / 赵野 / 孙海琴 / 兰海军", "待商务确认", "已交付设备，状态待回读", "完成高优需求与安全整改；外卖、补单等功能已有培训与测试记录", "客户环境状态待逐项回读", "未验收/待回读", "待商务/财务确认", "上周5项高优需求完成确认，计划测试上线", "逐项补齐清单、回归、发布、回滚和验收人，关闭安全整改遗留", "项目周期长；不能把开发完成或培训完成等同于验收", "复杂企业样板，适合沉淀交付与安全整改证据包", MEETING_URL],
    [14, "学校", "交付/筹备", "保康中学（项目表为保康三中）", "下周锁定施工进度与进场时间", "待商务确认", "张帅 / 赵野 / 王朔 / 兰海军", "待商务确认", "发货与供应商进度跟进中", "完成项目情况回读并跟进发货", "待上线", "未验收", "待商务/财务确认", "上周产品侧推进一体机帮助与学校线材料", "确认施工进度和进场时间，制作进销存标签并冻结多模块验收顺序", "来源中存在保康中学/保康三中命名差异，需项目负责人确认", "学校食安+进销存标准包候选", DELIVERY_SOURCE],
    [15, "职业教育", "交付/现场整改", "国防科技大学", "本周完成现场小项整改", "待商务确认", "张帅 / 刘劲玮", "待商务确认", "待确认", "完成会议室墙面修复及卫生间挡水条安装", "待项目整体回读", "待验收回读", "待商务/财务确认", "来源未提供上周对照", "补齐项目整体阶段、验收范围和关闭证据", "当前只证明两项现场整改，不代表项目整体交付完成", "非智慧食堂主线，作为交付实施事实保留", DELIVERY_SOURCE],
    [16, "体育训练", "售后/备件", "先农坛体校", "下周完成划船机、攀爬机配件供货", "待商务确认", "张帅", "维修合同已签，细节待回读", "备货与采购中", "跟进维修合同、备货，现场勘察并测量离心机绳索尺寸", "运营中", "不适用/待确认", "待商务/财务确认", "历史为持续运维项目", "完成配件供货并回读维修结果", "备件到货与现场安装时间待确认", "运维事项，不升级为产品成果", DELIVERY_SOURCE],
    [17, "高校", "产品功能验证", "湖南体职院", "本周运动课程视频功能已上线可播放", "待商务确认", "郭东伟 / 项目负责人待确认", "待商务确认", "不涉及", "视频审核字段调整并生成OSS链接，过审视频可播放", "功能已上线，项目验收待回读", "待回读", "待商务/财务确认", "上周未见本项完成证据", "补齐内容资质、长期审核规则和用户使用反馈", "视频资质审核仍是持续边界；本周上线不等于整体项目验收", "视频功能可作为内容运营能力验证", MEETING_URL],
    [18, "学校", "交付/远程支持", "采育三小", "本周完成进销存远程指导", "待商务确认", "张帅", "待商务确认", "不涉及", "远程指导客户使用进销存系统", "在用状态待回读", "待回读", "待商务/财务确认", "来源未提供上周对照", "回访客户操作结果，判断是否需要沉淀FAQ或短视频", "只有指导记录，暂无客户独立使用或验收证据", "可沉淀进销存培训资产", DELIVERY_SOURCE],
    [19, "高校/康养", "售后/报价支持", "贵州康养大学", "本周形成体适能设备维修报价沟通", "待商务确认", "张帅", "待商务确认", "维修配件待确认", "与经销商沟通体适能设备维修报价并同步业务", "不适用", "待回读", "待商务/财务确认", "来源未提供上周对照", "确认报价、维修责任和执行窗口", "尚未形成维修完成或客户确认事实", "作为售后支持记录保留", DELIVERY_SOURCE],
]


PRODUCT_ROWS = [
    [1, "产品差异性", "政企营养版", "完成政企营养竞品分析与原型评审，明确哈尔滨膳质舍应用范围，并继续推进PC/移动端开发", "哈尔滨膳质舍、企业/机关场景", "下周形成可开发范围与评审记录", "李潇 / 兰海军", "从多轮原型评审推进到范围收敛；前端开发状态仍需回读", "Build；暂无成熟度升级证据"],
    [2, "产品差异性", "AI菜品导入与营养匹配", "标准产品AI一键菜品导入上线，支持模板批量导入、同名菜品图片更新；菜品分类与100g组分匹配继续优化", "人大附中、标准产品", "下次周报前补准确率测试数据", "孙海琴 / 孙倩倩", "已形成可演示功能；同名菜品价格覆盖规则待确认", "Validate；AI生成菜品图因现场一致性风险暂不实施"],
    [3, "产品标准化", "标准产品补单管理", "支持按消费策略自动结算并生成消费订单，国康医院人工补单流程已上线并培训", "国康医院、标准产品", "下周补回归证据并验证异常边界", "孙海琴 / 孙倩倩 / 尹旭亮", "项目需求已回收到标准能力", "Standardize候选；客户整体验收未确认"],
    [4, "产品标准化", "消费补贴核算与订单导出", "形成充值、退款、提现订单一键导出，以及部门消费、开发人员补贴明细、批量导入与审核发放流程", "四方达", "下周完成正式环境回验", "孙海琴 / 郭东伟", "核算、导出和补贴发放链路已形成", "Standardize候选；资金与客户验收仍需真实环境证据"],
    [5, "产品标准化", "软件SKU与销售演示", "收敛为3个SPU×3个功能版本的9行SKU简表，并形成28项目映射和功能包矩阵", "智慧食堂销售体系", "确认版本权益、价格、Owner、Demo账号和首批试点", "姜阳 / 待确认Owner", "把项目清单转成可筛选、可演示的销售产品结构", "L1→L2候选；DoR BLOCKED"],
    [6, "产品标准化", "按餐线定义套餐包", "完成餐线主骨架、设备版本和测算Excel，形成零开发试运行路径", "企业/学校/机关餐线", "补录项目参数并关闭460免绑盘等P0", "姜阳 / 待确认Owner", "套餐测算可用于内部方案试算", "V0.9.2；正式自动测算BLOCKED"],
    [7, "产品标准化", "Odoo产品与客户门户", "上线产品、组合、案例和客户门户受控试点；专用报价、客户方案PDF和Product Documents已生效", "内部销售、受控客户验收", "完成微信真机验收、TTL策略和案例授权", "姜阳 / 销售运营待确认", "建立从产品资料到报价与客户分享的数字货架", "Scale候选；全量客户外发BLOCKED"],
    [8, "产品标准化", "产品大学与助销材料", "32门课程审核工作台、五级认证及考核材料齐备；24项助销细项和14门新手村课程完成建档/规划", "销售、售前、交付新人", "选10门成交必修课试点，逐门Review并冻结审核责任", "姜阳 / 内容Owner待确认", "从零散材料转向可审核、可训练、可考核的上岗体系", "L2候选；正式课程和价格/资质仍待确认"],
    [9, "产品标准化", "三级等保备案及测评", "已完成认证环境开发、独立服务器部署、域名配置、测试账号交付和公安网安线上进场检查；当前等待整改通知", "智慧营养健康餐厅管理系统", "9/1-9/3预计收通知；9/6前争取电子备案证；9/25前目标取得测评报告，9/26-9/30缓冲", "王朔 / 赖清涛", "形成四周进度表：整改回函→电子备案证→首轮核验→主体测评/整改复测→报告定稿", "当前状态是等待外部整改通知；备案证和测评报告日期均为目标，不写成已取得"],
    [10, "产品标准化", "低版本SQL升级SOP", "形成目标Tag冻结、差异清单、预检备份、分段执行、逐段回读和业务冒烟的升级主线", "低版本客户项目", "选一次真实交付复验并接入检查流程", "郭东伟", "把个人经验沉淀为研发与交付共用SOP", "Standardize；未替代生产授权与现场验收"],
    [11, "AI赋能", "复杂任务模式路由", "形成常规Codex与Ruflo+Codex Harness按复杂度分流的团队判断，Ruflo上禾试点已留回归与审计证据", "跨仓库、高风险、长周期任务", "完成第二个量化对照试点", "兰海军", "从工具偏好转向风险、角色和证据驱动的执行模式", "Validate；真实设备门禁未闭环"],
    [12, "AI赋能", "AI可执行Use Case与云效", "建立UC标准、Skill、模板、eval和云效正文回读规则，将需求主/分支/异常/恢复、验收和测试直接带入执行", "产品需求、研发任务、缺陷", "用下一条真实需求做首次完整回读验收", "姜阳 / 产品团队", "把自然语言需求转成可验证执行契约", "Standardize；真实需求首验待完成"],
    [13, "AI赋能", "Agent Skills流程选型", "形成Superpowers自动挡与mattpocock/skills手动挡的任务选型边界，一次任务明确一套主流程", "日常开发、大型新项目、跨会话协作", "在真实任务中验证路由准确性和重复流程减少情况", "尹旭亮", "减少简单任务过度流程化和复杂任务缺少决策留痕", "方法已分享；量化数据待补"],
    [14, "AI赋能", "AI参与交付与验证", "AI已用于需求边界拆解、上下游代码分析、最小修改、Docker语法/测试验证和报表差异定位", "大兴、三全、机场等", "统一记录已验证项、现场门禁、返工与时长", "赖清涛", "从写材料/查问题进入需求、开发、验证和知识沉淀闭环", "团队方法形成；真实环境验收仍由业务负责"],
    [15, "AI赋能", "企业微盘知识入口", "三大微盘源完成元数据索引刷新，为项目、产品和交付资料定向检索提供统一入口", "项目交付管理共享空间、数字技术中心知识库", "按周报/项目任务定向转换少量正文材料", "姜阳", "降低资料定位成本，避免批量复制原始文件", "Scale；当前只证明元数据索引，不证明正文已读取"],
    [16, "经营治理", "四个月新增2000万作战系统", "经营结论收敛为先建立唯一CRM商机主表和收入作战节奏，月均500万等数字仅作待校准目标", "数科业务销售增长", "冻结字段、Owner、阶段口径和销售周节奏", "姜阳 / 销售负责人待确认", "把课程扩张和零散动作收敛到成交主线", "战略假设；必须由真实CRM校准"],
    [17, "市场洞察", "阳光智园竞品深研", "确认其从校服O2O延伸为区县教委校园餐治理方案商，并对冲突规模数据做降级处理", "学校/教委食安营养监管包", "拆解校园监管包与企事业食堂包的差异化能力", "姜阳", "为学校线产品边界和投标表达提供B/C级竞争情报", "收入、毛利、续费仍缺证据"],
    [18, "产品差异性", "炒菜机器人设备对接", "完成组织/门店/设备同步、控制、进度查询和cook_log Webhook方案", "哈尔滨膳质舍、智能后厨", "补coId/mobile/SN、测试设备与签名并轮换密钥", "兰海军 / 赖清涛", "形成设备接口方案，为后厨自动化集成建立边界", "Build；测试设备和签名待确认"],
    [19, "产品差异性", "政企五大场景图", "形成前厅、后厨、库存仓库、运营管理中心、办公区5张5120×2880场景图及HTML画廊", "政企智慧营养健康餐厅方案、销售演示", "纳入受控产品资料库并补版本、Owner和外发门禁", "Owner待确认", "把营养结算、食安、进销存、运营与办公健康服务放入统一空间叙事", "方案视觉/概念图，不作为真实项目现场、设备数量或客户验收证据"],
]


SOURCES = [
    ["S01", "周会纪要", "2026-08-28", "产品团队周会纪要（线上与本地SHA-256一致）", "B", "本周产品、开发、项目、AI分享、新功能与下周安排", "会议陈述与演示证据；不替代客户验收、财务或生产回读", "HTTP 200；SHA-256一致", MEETING_URL],
    ["S02", "项目管理Excel", "截至2026-08-28", "交付实施部-项目管理空间.xlsx｜2-项目管理总表", "B", "项目类型、产品/设备、负责人、阶段、金额、复杂度和交付门槛", "内部管理表；缺失状态统一标待确认", "可打开；53行×69列", DELIVERY_SOURCE],
    ["S03", "个人周报Excel", "2026-08-24至2026-08-30", "交付实施部-项目管理空间.xlsx｜张帅/王金洋/赵野周报", "B", "滨州、三全、四方达、城市副中心、国康、金斯瑞等现场进展", "个人自报；只作为进度线索，不自动视为上线/验收", "提取13条本周记录", DELIVERY_SOURCE],
    ["S04", "团队周汇总", "2026-W35", "智慧食堂团队周汇总", "B/D", "SKU、Odoo、套餐、产品大学、助销、竞品、AI治理与经营假设", "事实与战略假设分列；金额目标需CRM校准", "本地Markdown可读", str(ROOT / "work/weekly-reports/outputs/2026-W35/team-weekly-summary.md")],
    ["S05", "上周周报", "2026-W34", "智慧食堂团队周汇总", "B/D", "上周基线、延续项和风险连续性", "用于判断变化，不把重复承诺写成本周完成", "本地Markdown可读", str(ROOT / "work/weekly-reports/outputs/2026-W34/team-weekly-summary.md")],
    ["S06", "月度周会", "2026-08-10", "数科与团餐业务周会跟进", "B", "8月主线：15天标准交付、1周跟餐、合同前锁边界、一键安装包", "经营数字冲突项保留待确认", "摘要可读", str(ROOT / "work/2026-08-08-digital-sports-business-weekly-meeting/summary.md")],
    ["S07", "组长周会", "2026-08-14", "组长周会主持材料生成记录", "B", "产品、研发、交付的决策型周会结构和8/17-23计划", "主持材料，不等于会后完成证据", "摘要可读", str(ROOT / "work/2026-08-14-weekly-leads-meeting/summary.md")],
    ["S08", "事业部月会", "2026-08-17", "华亭11层数科事业部八月周会纪要", "A/B/C分层", "部门经营、领导要求、行动清单和后续周报连续性规则", "OCR歧义项保留待确认；正式责任人与截止日期待人审", "摘要可读", str(ROOT / "work/2026-08-17-huating-11f-digital-business-august-meeting-minutes/summary.md")],
    ["S09", "周会主持材料", "2026-08-24", "组长周会材料/产品开发周会主持稿", "B/D", "本周计划、三项决策目标、项目优先级和关闭口径", "属于会前计划与建议；完成状态必须由8/28新证据确认", "本地Markdown可读", str(ROOT / "work/weekly-meetings/2026-08-24/2026-08-24-weekly-leads-meeting-v2.md")],
    ["S10", "用户进度输入", "2026-08-29", "智慧营养健康餐厅管理系统三级等保认证工作及进度截图", "A", "已完成前置工作、网安线上进场检查、当前等待整改通知，以及9月四周目标计划", "已完成事实与目标日期分开；外部通知、用章、备案证和测评报告受外部流程约束", "用户直接提供；截图可读", "/var/folders/mg/qq5pkw2d36n0gfbq68sl2jbc0000gn/T/codex-clipboard-61459df4-7d96-4932-837e-3483cfe0f81e.png"],
    ["S11", "产品视觉资产", "2026-08-29", "政企场景图 2.zip（5张5K PNG + HTML画廊）", "D-方案视觉", "前厅、后厨、库存仓库、运营管理中心、办公区五大政企场景叙事", "只支持方案表达；不证明真实项目、设备数量、上线、验收或客户使用", "ZIP可解压；5图均为5120×2880", "/Users/jack/Library/Containers/com.tencent.WeWorkMac/Data/Documents/Profiles/A74DF84611CC2ED79C4C206E40B5D80E/Caches/Files/2026-08/39e1881fcca53dcc66e443aa419d1f38/政企场景图 2.zip"],
]


def unmerge_all(ws):
    for rng in list(ws.merged_cells.ranges):
        ws.unmerge_cells(str(rng))


def set_font(cell, *, bold=None, color=None, size=12):
    old = copy(cell.font)
    old.name = "微软雅黑"
    old.sz = size
    if bold is not None:
        old.b = bold
    if color is not None:
        old.color = color
    cell.font = old


def style_cell(cell, fill=None, bold=None, color=None, horizontal="left", vertical="center", size=12):
    set_font(cell, bold=bold, color=color, size=size)
    if fill:
        cell.fill = PatternFill("solid", fgColor=fill)
    cell.alignment = Alignment(horizontal=horizontal, vertical=vertical, wrap_text=True)
    cell.border = Border(left=THIN, right=THIN, top=THIN, bottom=THIN)


def clear_range(ws, min_row, max_row, min_col, max_col):
    for row in ws.iter_rows(min_row=min_row, max_row=max_row, min_col=min_col, max_col=max_col):
        for cell in row:
            cell.value = None
            cell.fill = PatternFill(fill_type=None)
            cell.border = Border()


def build_project_sheet(ws):
    unmerge_all(ws)
    if ws.max_row > 5:
        ws.delete_rows(6, ws.max_row - 5)
    clear_range(ws, 1, 5, 1, 18)

    ws.merge_cells("A1:R1")
    ws["A1"] = TITLE
    style_cell(ws["A1"], fill=BLUE, bold=True, color=WHITE, horizontal="center", size=12)
    ws.row_dimensions[1].height = 30

    cards = [
        ("A2:F3", "结论1｜项目闭环\n滨州开学保障、中央美院一卡通、三全多系统、四方达切换是下周优先门槛；开发完成、客户上线、验收必须分开表述。", SKY),
        ("G2:L3", "结论2｜产品标准化\n补单、补贴核算、AI菜品导入、SKU、餐线套餐和Odoo门户开始形成可销售、可交付资产，但价格、Owner与真实验收仍未冻结。", PALE_TEAL),
        ("M2:R3", "结论3｜经营与AI\n团队AI已进入需求、验证、交付和知识治理；经营增长仍以CRM商机、回款、复用率、交付成本等真实指标为准。", PALE_GOLD),
    ]
    for rng, text, fill in cards:
        ws.merge_cells(rng)
        cell = ws[rng.split(":")[0]]
        cell.value = text
        style_cell(cell, fill=fill, bold=True, color=TEXT, horizontal="left")
    ws.row_dimensions[2].height = 42
    ws.row_dimensions[3].height = 42

    ws.merge_cells("A4:R4")
    ws["A4"] = "一、项目工作｜按“合同—采购—交付—上线—验收—回款”六节点回读；本周事实与下周门槛一一对应"
    style_cell(ws["A4"], fill=TEAL, bold=True, color=WHITE, horizontal="left", size=13)
    ws.row_dimensions[4].height = 28

    headers = ["序号", "项目类型", "项目阶段", "项目名称", "关键时间", "项目金额", "负责人", "合同", "采购", "交付", "上线", "验收", "回款", "上周进展", "本周计划/后续动作", "问题与偏差", "备注", "链接"]
    for col, value in enumerate(headers, 1):
        c = ws.cell(5, col, value)
        style_cell(c, fill=BLUE, bold=True, color=WHITE, horizontal="center")
    ws.row_dimensions[5].height = 38

    for r_idx, row in enumerate(PROJECT_ROWS, 6):
        for c_idx, value in enumerate(row, 1):
            c = ws.cell(r_idx, c_idx, value)
            fill = WHITE if r_idx % 2 == 0 else "F8FAFC"
            if c_idx in (15,):
                fill = PALE_TEAL
            if c_idx in (16,) and value:
                fill = PALE_RED
            if c_idx in (17,):
                fill = PALE_GRAY
            style_cell(c, fill=fill, color=TEXT, horizontal="center" if c_idx <= 13 else "left")
            if c_idx == 18 and isinstance(value, str) and value.startswith("http"):
                c.hyperlink = value
                c.style = "Hyperlink"
                c.alignment = Alignment(vertical="center", wrap_text=True)
                set_font(c, color="0563C1")
        ws.row_dimensions[r_idx].height = 108

    widths = [6, 11, 14, 24, 18, 13, 22, 13, 15, 28, 19, 13, 16, 32, 34, 33, 30, 28]
    for i, width in enumerate(widths, 1):
        ws.column_dimensions[get_column_letter(i)].width = width
    ws.freeze_panes = "A6"
    ws.auto_filter.ref = f"A5:R{5 + len(PROJECT_ROWS)}"
    ws.print_area = f"A1:R{5 + len(PROJECT_ROWS)}"
    ws.sheet_view.showGridLines = False
    ws.page_setup.orientation = "landscape"
    ws.page_setup.fitToWidth = 1
    ws.page_setup.fitToHeight = 2
    ws.sheet_properties.pageSetUpPr.fitToPage = True
    ws.print_title_rows = "1:5"
    ws.sheet_properties.tabColor = BLUE


def build_product_sheet(ws):
    unmerge_all(ws)
    if ws.max_row > 4:
        ws.delete_rows(5, ws.max_row - 4)
    clear_range(ws, 1, 4, 1, 9)

    ws.merge_cells("A1:I1")
    ws["A1"] = TITLE
    style_cell(ws["A1"], fill=BLUE, bold=True, color=WHITE, horizontal="center", size=12)
    ws.row_dimensions[1].height = 30

    ws.merge_cells("A2:I2")
    ws["A2"] = "二、产品工作｜以产品差异性、产品标准化、AI赋能和经营治理为主线；每项写清本周变化、证据边界和下一能力门槛"
    style_cell(ws["A2"], fill=TEAL, bold=True, color=WHITE, horizontal="left", size=13)
    ws.row_dimensions[2].height = 34
    ws.row_dimensions[3].height = 8

    headers = ["序号", "一级分类", "二级分类", "工作内容", "对应项目/场景", "时间节点", "负责人", "本周输出/目标", "备注"]
    for col, value in enumerate(headers, 1):
        c = ws.cell(4, col, value)
        style_cell(c, fill=BLUE, bold=True, color=WHITE, horizontal="center")
    ws.row_dimensions[4].height = 38

    category_fills = {
        "产品差异性": SKY,
        "产品标准化": PALE_TEAL,
        "AI赋能": "E9E1F7",
        "经营治理": PALE_GOLD,
        "市场洞察": "E8F1D7",
    }
    for r_idx, row in enumerate(PRODUCT_ROWS, 5):
        category = row[1]
        for c_idx, value in enumerate(row, 1):
            c = ws.cell(r_idx, c_idx, value)
            fill = WHITE if r_idx % 2 else "F8FAFC"
            if c_idx == 2:
                fill = category_fills.get(category, PALE_GRAY)
            if c_idx == 8:
                fill = PALE_TEAL
            if c_idx == 9:
                fill = PALE_GOLD if any(k in str(value) for k in ["待", "BLOCKED", "假设", "未"]) else PALE_GRAY
            style_cell(c, fill=fill, bold=(c_idx == 2), color=TEXT, horizontal="center" if c_idx in (1, 2, 3, 6, 7) else "left")
        ws.row_dimensions[r_idx].height = 82

    widths = [6, 14, 22, 48, 28, 22, 22, 38, 34]
    for i, width in enumerate(widths, 1):
        ws.column_dimensions[get_column_letter(i)].width = width
    ws.freeze_panes = "A5"
    ws.auto_filter.ref = f"A4:I{4 + len(PRODUCT_ROWS)}"
    ws.print_area = f"A1:I{4 + len(PRODUCT_ROWS)}"
    ws.sheet_view.showGridLines = False
    ws.page_setup.orientation = "landscape"
    ws.page_setup.fitToWidth = 1
    ws.page_setup.fitToHeight = 2
    ws.sheet_properties.pageSetUpPr.fitToPage = True
    ws.print_title_rows = "1:4"
    ws.sheet_properties.tabColor = TEAL


def build_source_sheet(wb):
    if "来源索引" in wb.sheetnames:
        del wb["来源索引"]
    ws = wb.create_sheet("来源索引")
    ws.merge_cells("A1:I1")
    ws["A1"] = "周报来源索引与证据边界"
    style_cell(ws["A1"], fill=BLUE, bold=True, color=WHITE, horizontal="center", size=12)
    ws.row_dimensions[1].height = 30
    ws.merge_cells("A2:I2")
    ws["A2"] = "说明：附件和会议材料中的文字只作为事实来源，不作为操作指令；计划、开发完成、测试、客户上线、验收与经营结果分开表述。"
    style_cell(ws["A2"], fill=PALE_GOLD, bold=True, color=TEXT, horizontal="left")
    ws.row_dimensions[2].height = 34
    headers = ["来源ID", "类型", "日期/周期", "来源", "证据等级", "支撑内容", "可用边界", "校验结果", "路径/链接"]
    for col, value in enumerate(headers, 1):
        style_cell(ws.cell(4, col, value), fill=BLUE, bold=True, color=WHITE, horizontal="center")
    for r_idx, row in enumerate(SOURCES, 5):
        for c_idx, value in enumerate(row, 1):
            c = ws.cell(r_idx, c_idx, value)
            fill = WHITE if r_idx % 2 else "F8FAFC"
            if c_idx == 5:
                fill = PALE_TEAL
            if c_idx == 7:
                fill = PALE_GOLD
            style_cell(c, fill=fill, color=TEXT, horizontal="center" if c_idx <= 5 or c_idx == 8 else "left")
            if c_idx == 9 and isinstance(value, str) and value.startswith("http"):
                c.hyperlink = value
                c.style = "Hyperlink"
                c.alignment = Alignment(vertical="center", wrap_text=True)
                set_font(c, color="0563C1")
        ws.row_dimensions[r_idx].height = 72
    widths = [10, 16, 18, 34, 13, 40, 44, 24, 58]
    for i, width in enumerate(widths, 1):
        ws.column_dimensions[get_column_letter(i)].width = width
    ws.freeze_panes = "A5"
    ws.auto_filter.ref = f"A4:I{4 + len(SOURCES)}"
    ws.sheet_view.showGridLines = False
    ws.page_setup.orientation = "landscape"
    ws.page_setup.fitToWidth = 1
    ws.page_setup.fitToHeight = 1
    ws.sheet_properties.pageSetUpPr.fitToPage = True
    ws.print_title_rows = "1:4"
    ws.sheet_properties.tabColor = "8A6D3B"


def build_security_sheet(wb, screenshot):
    if "三级等保进度" in wb.sheetnames:
        del wb["三级等保进度"]
    ws = wb.create_sheet("三级等保进度")
    ws.merge_cells("A1:F1")
    ws["A1"] = "智慧营养健康餐厅管理系统三级等保备案及测评进度表"
    style_cell(ws["A1"], fill=BLUE, bold=True, color=WHITE, horizontal="center", size=12)
    ws.row_dimensions[1].height = 30
    ws.merge_cells("A2:F2")
    ws["A2"] = "进度基准：2026-08-27｜负责人：王朔、赖清涛｜当前状态：线上进场检查已完成，等待整改通知"
    style_cell(ws["A2"], fill=PALE_GOLD, bold=True, color=TEXT, horizontal="left")
    ws.row_dimensions[2].height = 34
    ws.merge_cells("A3:F3")
    ws["A3"] = "管理边界：已完成事项、外部待办和目标日期分开记录；9月6日电子备案证、9月25日测评报告均为争取目标，不是已取得结果。"
    style_cell(ws["A3"], fill=PALE_RED, bold=True, color=TEXT, horizontal="left")
    ws.row_dimensions[3].height = 38

    headers = ["任务/节点", "第一周\n08.27-09.06", "第二周\n09.07-09.13", "第三周\n09.14-09.20", "第四周\n09.21-09.30", "相关负责人/状态"]
    fills = [BLUE, "E2F2EA", "E2EEF7", "E8EDF7", "FFF1CC", BLUE]
    for col, value in enumerate(headers, 1):
        c = ws.cell(4, col, value)
        style_cell(c, fill=fills[col - 1], bold=True, color=WHITE if col in (1, 6) else ("136E4B" if col == 2 else BLUE), horizontal="center")
    ws.row_dimensions[4].height = 52

    rows = [
        ["前置准备", "认证环境开发、独立服务器部署、域名配置及测试账号交付已完成", "—", "—", "—", "王朔、赖清涛｜已完成"],
        ["网安进场检查", "08.27公安网安线上进场检查已完成", "—", "—", "—", "王朔、赖清涛、公安网安｜已完成"],
        ["整改通知与整改", "预计09.01-09.03收到整改通知；收到后立即整改，内部目标09.04前完成", "—", "—", "—", "王朔、赖清涛、公安网安｜外部待办"],
        ["证明材料、用章及回函", "完成证明材料、公司用章及正式回函，内部目标09.05前发出", "—", "—", "—", "王朔、赖清涛、审批人｜待办"],
        ["电子备案证", "争取09.06前取得电子备案证", "09.07作为备案证签发缓冲", "—", "—", "王朔、赖清涛、公安网安｜外部流程"],
        ["等保测评", "—", "备案证取得后测评机构立即进场，完成首轮核验", "完成主体测评、问题确认、整改及复测", "09.21-09.24完成补充复测和报告定稿", "王朔、赖清涛、测评机构｜待启动"],
        ["测评报告", "—", "—", "启动报告编制", "09.25前目标取得报告；09.26-09.30作为最终缓冲", "王朔、赖清涛、测评机构｜外部流程"],
    ]
    for r_idx, row in enumerate(rows, 5):
        for c_idx, value in enumerate(row, 1):
            fill = WHITE if r_idx % 2 else "F8FAFC"
            if c_idx == 2 and value != "—":
                fill = PALE_TEAL
            elif c_idx == 3 and value != "—":
                fill = SKY
            elif c_idx == 4 and value != "—":
                fill = "E8EDF7"
            elif c_idx == 5 and value != "—":
                fill = PALE_GOLD
            elif c_idx == 6:
                fill = PALE_GRAY
            style_cell(ws.cell(r_idx, c_idx, value), fill=fill, bold=(c_idx == 1), color=TEXT, horizontal="center" if c_idx != 6 else "left")
        ws.row_dimensions[r_idx].height = 76

    ws.merge_cells("A13:F13")
    ws["A13"] = "原始进度图（用户于2026-08-29提供；用于回读计划，不替代整改通知、备案证或测评报告原件）"
    style_cell(ws["A13"], fill=TEAL, bold=True, color=WHITE, horizontal="left")
    ws.row_dimensions[13].height = 28
    if screenshot and Path(screenshot).exists():
        img = XLImage(screenshot)
        img.width = 1120
        img.height = round(1120 * 1450 / 2476)
        img.anchor = "A14"
        ws.add_image(img)
        for row in range(14, 48):
            ws.row_dimensions[row].height = 20
    widths = [22, 34, 31, 31, 32, 27]
    for i, width in enumerate(widths, 1):
        ws.column_dimensions[get_column_letter(i)].width = width
    ws.freeze_panes = "A5"
    ws.sheet_view.showGridLines = False
    ws.print_area = "A1:F47"
    ws.page_setup.orientation = "landscape"
    ws.page_setup.fitToWidth = 1
    ws.page_setup.fitToHeight = 2
    ws.sheet_properties.pageSetUpPr.fitToPage = True
    ws.print_title_rows = "1:4"
    ws.sheet_properties.tabColor = "2E75B6"


def build_scene_sheet(wb, assets_dir):
    if "政企场景图" in wb.sheetnames:
        del wb["政企场景图"]
    ws = wb.create_sheet("政企场景图")
    ws.merge_cells("A1:N1")
    ws["A1"] = "政企智慧营养健康餐厅五大场景图"
    style_cell(ws["A1"], fill=BLUE, bold=True, color=WHITE, horizontal="center", size=12)
    ws.row_dimensions[1].height = 30
    ws.merge_cells("A2:N2")
    ws["A2"] = "证据边界：以下均为5120×2880产品方案视觉，用于统一前厅、后厨、仓库、运营和办公场景叙事；不得当作真实项目现场、设备数量、上线或验收证据。"
    style_cell(ws["A2"], fill=PALE_GOLD, bold=True, color=TEXT, horizontal="left")
    ws.row_dimensions[2].height = 38
    scenes = [
        ("01｜前厅", "营养结算、AI识别、称重消费、订餐/取餐、营养/食安大屏和入口通行", "01-front-hall-flow-adjusted-4k.png"),
        ("02｜后厨", "晨检、温湿度、明厨亮灶、余量、留样、食品安全检测和AI视觉巡检", "02-kitchen-flow-adjusted-4k.png"),
        ("03｜库存仓库", "AI收货、温湿度、库存盘点及卸货—验收—入库动线", "03-warehouse-sensors-adjusted-4k.png"),
        ("04｜运营管理中心", "营销营养、食安监管、采购进销存和系统运营后台", "04-operations-center-4k.png"),
        ("05｜办公区", "手机订餐、营养报告、智能取餐柜、健康小屋和体测设备", "05-office-4k.png"),
    ]
    assets = Path(assets_dir) if assets_dir else None
    start_rows = [4, 40, 76, 112, 148]
    for (title, note, filename), start in zip(scenes, start_rows):
        ws.merge_cells(start_row=start, start_column=1, end_row=start, end_column=14)
        c = ws.cell(start, 1, f"{title}｜{note}")
        style_cell(c, fill=TEAL, bold=True, color=WHITE, horizontal="left")
        ws.row_dimensions[start].height = 28
        image_path = assets / filename if assets else None
        if image_path and image_path.exists():
            img = XLImage(image_path)
            img.width = 1180
            img.height = round(1180 * 2880 / 5120)
            img.anchor = f"A{start + 1}"
            ws.add_image(img)
        for row in range(start + 1, start + 35):
            ws.row_dimensions[row].height = 19
        ws.merge_cells(start_row=start + 35, start_column=1, end_row=start + 35, end_column=14)
        cap = ws.cell(start + 35, 1, f"原始文件：{filename}｜5120×2880｜方案视觉，非现场证据")
        style_cell(cap, fill=PALE_GRAY, color=MUTED, horizontal="left")
        ws.row_dimensions[start + 35].height = 24
    for i in range(1, 15):
        ws.column_dimensions[get_column_letter(i)].width = 13
    ws.freeze_panes = "A3"
    ws.sheet_view.showGridLines = False
    ws.print_area = "A1:N183"
    ws.page_setup.orientation = "landscape"
    ws.page_setup.fitToWidth = 1
    ws.page_setup.fitToHeight = 5
    ws.sheet_properties.pageSetUpPr.fitToPage = True
    ws.sheet_properties.tabColor = "1F7A53"


def normalize_fonts(wb):
    for ws in wb.worksheets:
        for row in ws.iter_rows():
            for cell in row:
                if cell.value not in (None, ""):
                    set_font(cell, size=12)


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--output", type=Path, default=OUTPUT)
    parser.add_argument("--assets-dir", type=Path)
    parser.add_argument("--security-image", type=Path)
    args = parser.parse_args()
    if not TEMPLATE.exists():
        raise FileNotFoundError(TEMPLATE)
    wb = load_workbook(TEMPLATE)
    build_project_sheet(wb["项目"])
    build_product_sheet(wb["产品"])
    if args.security_image:
        build_security_sheet(wb, args.security_image)
    if args.assets_dir:
        build_scene_sheet(wb, args.assets_dir)
    build_source_sheet(wb)
    normalize_fonts(wb)
    wb.calculation.fullCalcOnLoad = True
    wb.calculation.forceFullCalc = True
    args.output.parent.mkdir(parents=True, exist_ok=True)
    wb.save(args.output)
    print(args.output)


if __name__ == "__main__":
    main()
