from pathlib import Path
from copy import copy
from datetime import datetime
import json,hashlib,csv,io
from PIL import Image as PILImage, ImageOps
from openpyxl import load_workbook
from openpyxl.styles import Font,PatternFill,Alignment,Border,Side
from openpyxl.drawing.image import Image
from openpyxl.comments import Comment
from openpyxl.worksheet.pagebreak import Break
P=Path(__file__).resolve().parent
SRC=Path('/Users/jack/Desktop/数字技术中心&交付实施部周报20260907.xlsx')
HW=Path('/Users/jack/Downloads/保盘系统硬件工作周报_20260904.xlsx')
OUT=P/'数字技术中心&交付实施部周报20260907_项目图文与确收版.xlsx'
assets=P/'assets';assets.mkdir(exist_ok=True)
source_hash=hashlib.sha256(SRC.read_bytes()).hexdigest();w=load_workbook(SRC)
NAVY='17365D';TEAL='004D45';BLUE='1557A0';BLUE_BG='E7F1FC';ORANGE='A84B0F';ORANGE_BG='FFF0DE';LINE='CCD9E6';WHITE='FFFFFF'
title_style=copy(w['交付中项目']['A1']._style)
head_style=copy(w['交付中项目']['A4']._style)
source_url='https://doc.weixin.qq.com/sheet/e3_AG0Afwa2ANQCNXfl3b4G9Q7ua8RV8?tab=4d72sg'
def c(s,r,col,value,bg=None,color='243347',bold=False):
 q=s.cell(r,col,value);q.font=Font(name='微软雅黑',size=12,color=color,bold=bold);q.fill=PatternFill('solid',fgColor=bg) if bg else PatternFill();q.alignment=Alignment(wrap_text=True,vertical='center');q.border=Border(left=Side(style='thin',color=LINE),right=Side(style='thin',color=LINE),top=Side(style='thin',color=LINE),bottom=Side(style='thin',color=LINE));return q

def m(s,r,a,b,value,bg=None,color='243347',bold=False):
 s.merge_cells(start_row=r,start_column=a,end_row=r,end_column=b);return c(s,r,a,value,bg,color,bold)

def base(name,title,subtitle,n=14):
 s=w.create_sheet(name);s.sheet_view.showGridLines=False;s.sheet_view.zoomScale=85
 for j in range(1,n+1):s.column_dimensions[__import__('openpyxl').utils.get_column_letter(j)].width=11
 m(s,1,1,n,title,NAVY,WHITE,True);s.row_dimensions[1].height=34
 m(s,2,1,n,subtitle,'DDEBF7',bold=True);s.row_dimensions[2].height=45
 m(s,3,1,n,'9/7周会｜蓝色：8/31—9/6进展；橙色：9/7—9/13计划。后续日期单独列明。','F4F7FA');s.row_dimensions[3].height=28
 s.page_setup.orientation='landscape';s.page_setup.paperSize=s.PAPERSIZE_A3;s.page_setup.fitToWidth=1;s.page_setup.fitToHeight=1;s.sheet_properties.pageSetUpPr.fitToPage=True
 s.page_margins.left=.25;s.page_margins.right=.25;s.page_margins.top=.35;s.page_margins.bottom=.4
 s.oddFooter.center.text='数字技术中心&交付实施部｜9月7日周报';s.oddFooter.right.text='&P / &N';s.freeze_panes='A4';return s

def band(s,row,text):m(s,row,1,14,text,NAVY,WHITE,True);s.row_dimensions[row].height=26

def internal(q,sheet):q.hyperlink="#'%s'!A1"%sheet;q.font=Font(name='微软雅黑',size=12,color=BLUE,underline='single',bold=True)
# Preserve Jack's current workbook, including revised 10-project target and dashboard screenshot.
assert '10个项目' in str(w['交付实施部管理概况']['A3'].value)
for s in w:
 if s.sheet_state!='visible':continue
 for row in s:
  for q in row:
   if not isinstance(q.value,str):continue
   q.value=q.value.replace('本周：8/31—9/6（资料截至9/5）  ｜  下周：9/7—9/13  ｜  蓝色：本周已发生；橙色：下周计划。','9/7周会｜蓝色：8/31—9/6进展；橙色：9/7—9/13计划（资料更新至9/6）。')
   if q.value=='本周进展':q.value='上周进展'
   elif q.value=='下周目标':q.value='本周目标'
   elif q.value=='下周节点':q.value='本周节点'
# Correct the known metric interpretation without replacing the user-restored dashboard image.
w['项目经营大屏']['A2']='已交付系统是否真正运行、形成了什么价值。注：大屏“累计活跃”按日去重后累加，应读为人次；分享链接日期未自动带入。'
w['项目经营大屏'].row_dimensions[2].height=42
w['项目经营大屏']['A2'].comment=Comment('保留用户9/7文件中的原截图。本次不重新抓取运营数据；9/5已核查8451为人次、非独立人数，日期参数也未进入首次请求。详见work_store/data-queries/active-user-breakdown-20260905/analysis.md。','Codex')
# Freeze and prepare photo assets. EXIF orientation is honored; originals are untouched.
photo_specs=[
('cafa-line','中央美院','30 台 410 设备.jpg','现场照片','成排称重设备与餐线布置；数量需与签收单核对'),
('cafa-ui','中央美院','410 设备效果图.jpg','现场界面照片','设备屏显示取用量、金额和营养信息；不作为全流程验收'),
('cafa-safety','中央美院','食安驾驶舱.jpg','现场照片','现场屏幕已展示食安驾驶舱'),
('cafa-sign-effect','中央美院','央美-口水罩温馨提示牌-康比特橙色粗体版-设备效果.png','提示牌效果示意','提醒夹子归位、减少多计费争议；不证明已安装'),
('cafa-sign-print','中央美院','央美-口水罩温馨提示牌-康比特橙色粗体版-打印店高清300dpi.png','设计稿','提示牌打印稿'),
('cafa-architecture','中央美院','绑盘机结算模式架构图.png','流程架构说明','一卡通、设备端、业务服务的职责说明，实施状态另核'),
('cafa-flow','中央美院','央美-绑盘打餐流程.png','操作说明图','订餐/绑盘及错误提示说明，不单独证明当前能力'),
('harbin-robot','哈尔滨','炒菜机器人.png','厂商产品图','TC-40EA产品介绍，不能作为现场安装证明'),
('harbin-health','哈尔滨','健康体检一体机.jpg','实物照片','体检设备外观，照片未提供拍摄日期和现场位置')]
manifest=[];prepared={}
for key,project,filename,kind,claim in photo_specs:
 src=Path('/Users/jack/Desktop')/project/filename
 im=ImageOps.exif_transpose(PILImage.open(src)).convert('RGB');im.thumbnail((1800,4500));dst=assets/(key+'.jpg');im.save(dst,'JPEG',quality=93,optimize=True)
 prepared[key]=dst;manifest.append({'key':key,'project':project,'filename':filename,'source':str(src),'source_sha256':hashlib.sha256(src.read_bytes()).hexdigest(),'classification':kind,'caption':claim,'date':'用户9/6提供；图片自身日期除界面可见外未独立核验','display_asset':str(dst.relative_to(P))})

def pic(s,key,anchor,maxw,maxh):
 p=prepared[key];im=Image(str(p));factor=min(maxw/im.width,maxh/im.height);im.width*=factor;im.height*=factor;s.add_image(im,anchor)

# Cafa overview: four pictures, visible state + concrete next action.
s=base('中央美院项目图解','中央美院｜用现场照片讲清交付进展','现场餐线与设备界面已有展示；本周重点完成培训、跟餐、差异核对和验收资料收尾。')
for r in range(4,40):s.row_dimensions[r].height=18
m(s,5,1,7,'餐线布置｜现场照片',NAVY,WHITE,True);m(s,5,8,14,'410终端｜现场界面',NAVY,WHITE,True)
pic(s,'cafa-line','A6',530,250);pic(s,'cafa-ui','H6',530,250)
m(s,17,1,7,'照片可见多台设备成排布置。文件名“30台”与历史数量不同，最终以签收清单为准。',BLUE_BG,BLUE)
m(s,17,8,14,'屏端已显示菜品、取用量、金额及营养信息；现场培训要讲清取餐、计费和异常处理。',BLUE_BG,BLUE);s.row_dimensions[17].height=52
m(s,19,1,7,'食安驾驶舱｜现场展示',NAVY,WHITE,True);m(s,19,8,14,'防误计费提示｜效果示意',NAVY,WHITE,True)
pic(s,'cafa-safety','A20',530,250);pic(s,'cafa-sign-effect','H20',530,250)
m(s,31,1,7,'现场大屏已展示食安页面；继续核对设备接入、事件记录及处置过程。',BLUE_BG,BLUE)
m(s,31,8,14,'提示牌说明“离开时将夹子放回餐炉”。此图为安装效果示意，实际安装情况待确认。',BLUE_BG,BLUE);s.row_dimensions[31].height=52
m(s,33,1,14,'本周目标：柴玉龙/李潇先核10个差异工作包，完成用户培训、跟餐及剩余工期确认。',ORANGE_BG,ORANGE);s.row_dimensions[33].height=34
m(s,34,1,14,'确收协同：9月冲刺表已填央美实际达成23.6万元，但验收栏仍为“等验收单”；杜佳与交付/销管继续补单据。',ORANGE_BG,ORANGE);s.row_dimensions[34].height=36
m(s,36,1,14,'补充流程图、架构图和打印稿已嵌入“项目附图”参考页；现场照片与方案图分开标注。','F4F7FA');s.row_dimensions[36].height=28;s.print_area='A1:N36'
# Harbin overview: an actual equipment photograph + a vendor image, with a product thesis.
s=base('哈尔滨项目图解','哈尔滨｜借项目完善政企版本营养模块','以体检数据接入为起点，完善个人档案、供餐营养分析与多端反馈；9/15设备联调联试是下一关键节点。')
for r in range(4,31):s.row_dimensions[r].height=20
m(s,5,1,6,'健康体检一体机｜实物照片',NAVY,WHITE,True);m(s,5,8,14,'TC-40EA炒菜机器人｜厂商产品图',NAVY,WHITE,True)
pic(s,'harbin-health','B6',390,390);pic(s,'harbin-robot','H7',545,370)
m(s,22,1,6,'体检设备承接检测数据；项目下一步验证人员绑定、报告接收和档案展示。照片不证明接口已验收。',BLUE_BG,BLUE)
m(s,22,8,14,'机器人服务后厨工艺与出品，需验证任务下发、执行回执及异常恢复；厂商图不代表已到货安装。',BLUE_BG,BLUE);s.row_dimensions[22].height=65
band(s,24,'产品如何完善：项目验证 → 三SPU共用能力')
m(s,25,1,14,'前厅营养：菜单营养计算、餐段分析、超标提醒 → PC管理、手机报告、营养大屏使用同一数据口径。',ORANGE_BG,ORANGE);s.row_dimensions[25].height=38
m(s,26,1,14,'后厨运营：菜谱/工艺 → 炒菜任务 → 执行回执；机器人接口独立验证，不把方案当作已交付功能。',ORANGE_BG,ORANGE);s.row_dimensions[26].height=38
m(s,28,1,14,'本周（9/7—13）：锁定到货与接口责任，完成体测→档案→PC/手机展示样例、营养三项功能评审和设备预检。',ORANGE_BG,ORANGE);s.row_dimensions[28].height=42
m(s,29,1,14,'里程碑：9/15设备联调联试、运行无误为用户目标；9/22整体交付与总表9/23上线需统一。海宇/赵野统筹，李潇、兰海军等配合。','F4F7FA');s.row_dimensions[29].height=44
m(s,31,1,14,'确收清单中的“哈尔滨增订”预估4500元，是增订单独项目，不与本体合同金额混算。','F4F7FA');s.row_dimensions[31].height=34;s.print_area='A1:N31'
# Appendix keeps all supplied diagrams embedded without expanding the main speech.
a=base('项目附图','项目附图｜央美流程、架构与打印稿','原理/操作/设计参考。页面内容不替代当前版本功能核验，取消隐藏后可查看完整图。')
pic(a,'cafa-architecture','A5',950,560);m(a,35,1,14,'绑盘机结算模式架构图｜方案说明，实施状态另核。','F4F7FA')
pic(a,'cafa-sign-print','A38',950,330);m(a,59,1,14,'提示牌高清打印稿｜不等于现场安装完成。','F4F7FA')
pic(a,'cafa-flow','A62',950,2250);a.sheet_state='hidden'
# Revenue: use the user-provided September source, preserving blanks and exact scope.
revenue=json.loads((P/'revenue-source.json').read_text());numrows=[r for r in revenue if r['department']=='数科业务中心'];assert len(numrows)==14
assert sum(r['plan'] or 0 for r in numrows)==3128000
assert sum(r['forecast'] or 0 for r in numrows)==2809665
assert sum(r['actual'] or 0 for r in numrows)==27170
s=base('9月确收清单','9月确收清单｜数科业务中心（用户指定名单）','本月重点盯北体大209万元、浙江体科所50万元；两项合计259万元，占预计完成约92.2%。',10)
width=[9,42,15,18,19,18,23,27,42,33]
for j,v in enumerate(width,1):s.column_dimensions[__import__('openpyxl').utils.get_column_letter(j)].width=v
m(s,4,1,10,'源表：9月销售冲刺表。金额单位：元；“预估完成”与“实际达成/已确收”分列，空白保留为未填。','F4F7FA');s.row_dimensions[4].height=32
for j,v in enumerate(['源行','客户/项目','负责人','月度计划','预估完成','实际达成','项目验收（源表）','当前分类','本周跟进事项','备注'],1):c(s,6,j,v,NAVY,WHITE,True)
action={7:'核实本月能否形成确收，补预估金额与时间。',8:'核对增订范围与交付凭据，锁增订单确收日。',9:'确认实训室范围、供货/交付及预计确收时间。',10:'确认设备/实训室交付与验收安排，补预估。',11:'确认食安项目供货、部署、验收及确收安排。',12:'核对13万计划与12.5万预估差异，锁验收时间。',13:'补预估金额和当前阶段，明确本月推进结论。',14:'孔令颖锁定209万项目确收日、验收资料与合同对应范围。',15:'源表已确收；继续补回合同原件。',16:'源表已确收，按已有单据归档。',17:'源表正在采购；跟进到货、交付和验收。',18:'锁定50万项目的交付/验收安排及确收日期。',19:'跟进签约与采购，明确交付及确收安排。',20:'源表已确收，完成单据归档。'}
for rr,r in enumerate(numrows,7):
 state='源表已确收' if r['acceptance']=='已确收' else '有预估，待达成' if r['forecast'] is not None else '计划内，预估待填'
 note='同名客户的不同合同须单独核对。' if r['project']=='北京体育大学' else '只统计增订；不是哈尔滨本体合同。' if '增订' in r['project'] else '未提供具体确收日。' if state!='源表已确收' else '原表明确标注已确收。'
 vals=[r['source_row'],r['project'],r['owner'],r['plan'] if r['plan']is not None else None,r['forecast'],r['actual'],r['acceptance'] or '未填',state,action[r['source_row']],note]
 for j,value in enumerate(vals,1):
  q=c(s,rr,j,value,BLUE_BG if j==6 and value is not None else ORANGE_BG if j==9 else None,BLUE if j==6 else ORANGE if j==9 else '243347')
  if j in [4,5,6]:q.number_format='#,##0.00;[Red]-#,##0.00;0.00';q.comment=Comment('源表9月页，行'+str(r['source_row'])+'。空白表示未填，参与SUM时被忽略，不能当作业务实际0。','Codex')
 s.row_dimensions[rr].height=51
s['B7'].comment=Comment('用户URL指向1月页，但用户截图和明确文字要求9月，因此通过子表列表定位“9月销售冲刺表”后读取。'+source_url,'Codex')
c(s,21,2,'数科合计',NAVY,WHITE,True)
for col in ['D','E','F']:s[col+'21']='=SUM('+col+'7:'+col+'20)';s[col+'21'].number_format='#,##0.00';s[col+'21'].font=Font(name='微软雅黑',size=12,bold=True);s[col+'21'].fill=PatternFill('solid',fgColor='DDEBF7')
m(s,23,1,3,'计划与预估缺口（计划−预估）',bg='DDEBF7',bold=True);s['D23']='=D21-E21';s['D23'].number_format='#,##0.00'
m(s,24,1,3,'预估尚待达成（预估−已填实际）',bg='DDEBF7',bold=True);s['D24']='=E21-F21';s['D24'].number_format='#,##0.00'
m(s,26,1,10,'原表“实际达成”合计27170元，且三个项目明确标“已确收”。其余项目按用户要求列入9月跟进，不替代财务最终确认。','F4F7FA');s.row_dimensions[26].height=34
m(s,27,1,10,'交付10项目/月是用户周报管理目标；本页14条是数科销售冲刺项目，两者范围不同。哈尔滨增订、北体大不同合同不可混同。','F4F7FA');s.row_dimensions[27].height=34
s.freeze_panes='C7';s.auto_filter.ref='A6:J20';s.print_area='A1:J27';s.page_setup.fitToHeight=1
# Cafeteria items are shown separately to avoid mixing their revenue with the selected digital-business scope.
s=base('团餐确收协同','团餐确收协同｜与交付周报关联的项目','央美、人大附中重点补验收单据；滨州增购与每月软件确收分开跟进，不计入数科280.9665万元。',8)
for j,width in enumerate([36,16,17,17,18,27,38,40],1):s.column_dimensions[__import__('openpyxl').utils.get_column_letter(j)].width=width
for j,v in enumerate(['项目','负责人','月度计划','预估完成','实际达成','源表验收备注','交付/单据跟进','口径说明'],1):c(s,5,j,v,NAVY,WHITE,True)
selected=[21,22,24,26,34,35,36,37]
notes={21:('按9/30节点准备本月软件确收。','月度8333元，不是整笔10万元。'),22:('按9/30节点准备本月软件确收。','月度2875元，不是整笔6.9万元。'),24:('源表写10月交付；9月先锁范围和接口。','预估空白，不作9月确定确收。'),26:('确认二期增购交付与确收凭据。','二期增购不等于滨州一期合同。'),34:('跟进验收单回收并与财务确认状态。','实际已填9400，验收列仍等单。'),35:('杜佳与交付/销管补验收单。','实际已填236000，仍等验收单。'),36:('取得盖章验收单，核对归档与确收。','实际已填49800，验收单未盖章。'),37:('确认新增5万元是否进入本月汇总。','源表团餐汇总G21:G36未包含第37行。')}
for rr,sr in enumerate(selected,6):
 r=next(x for x in revenue if x['source_row']==sr);a,b=notes[sr]
 for j,value in enumerate([r['project'],r['owner'],r['plan'],r['forecast'],r['actual'],r['acceptance'] or '未填',a,b],1):
  q=c(s,rr,j,value,ORANGE_BG if j==7 else BLUE_BG if j==5 and value is not None else None)
  if j in [3,4,5]:q.number_format='#,##0.00'
 s.row_dimensions[rr].height=66
m(s,15,1,8,'源表团餐汇总预计480408元、实际295200元；中债金石第37行5万元未计入该汇总。此处保留原口径并列出漏计待核，不改在线原表。','F4F7FA');s.row_dimensions[15].height=44;s.print_area='A1:H15'
# Rebuild only the existing hardware summary with the eight verified rows from the separate workbook.
s=w['硬件与证书申请']
for rg in list(s.merged_cells.ranges):s.unmerge_cells(str(rg))
s.delete_rows(1,s.max_row);s._images=[]
m(s,1,1,14,'第四部分｜旭亮硬件研发进度（产品、后端协同）',NAVY,WHITE,True);s.row_dimensions[1].height=34
m(s,2,1,14,'本周重点：设备端能处理异常、离线订单可追溯、人员同步可定位；代码完成与真机验收分开汇报。','DDEBF7',bold=True);s.row_dimensions[2].height=42
for a,b,t in [(1,3,'工作项'),(4,7,'上周实际（8/31—9/6）'),(8,9,'当前状态'),(10,13,'本周目标（9/7—13）'),(14,14,'协同')]:m(s,4,a,b,t,NAVY,WHITE,True)
hardware=[
('现场异常处理分支','明确克重异常、退款等需在设备端处理。','方案/开发待补','形成设备端流程与页面；明确设备、PC、审核边界。','产品/后端'),
('450/460逃单迁移','410已有项目验证；450/460范围已明确。','待迁移/回归','按型号迁移，补单双秤与异常流程测试。','硬件/测试'),
('支付宝碰一碰','统一支付接口方案明确，硬件端到端待联调。','待联调','接入消费设备并验证支付、退款和对账。','支付后端'),
('离线订单手动同步','自动补传已有180秒轮询代码；手动入口未闭环。','部分完成','补手动同步入口、异常列表与回读结果。','后端/测试'),
('一卡通人员全量同步','分页、字段映射、批量转发已有代码及构建证据。','真机待验','目标设备跑全量同步，记录失败步骤与服务端回执。','一卡通/后端'),
('同步耗时与日志','已拆分拉取、服务端同步、本地保存三段日志。','代码级完成','实测2000人/批的内存与耗时，定位瓶颈。','硬件/测试'),
('锁卡离线与异常追溯','识别卡状态未同步、异常消费记录缺口。','待设计','确认卡状态字段、本地判断、异常订单上报与处理。','产品/后端'),
('推荐与累计取用量','称重设备已接入推荐量与累计取用量字段。','接口/真机待验','确认后端返回和真机显示，再形成跨型号配置。','后端/产品')]
for rr,r in enumerate(hardware,5):
 for (a,b),value in zip([(1,3),(4,7),(8,9),(10,13),(14,14)],r):m(s,rr,a,b,value,BLUE_BG if a==4 else ORANGE_BG if a==10 else None,BLUE if a==4 else ORANGE if a==10 else '243347')
 s.row_dimensions[rr].height=77
m(s,14,1,14,'支付口径：三全“付款码”已有用户上线确认；“碰一碰”仍按硬件专项待联调，不能合并成全部支付已完成。','F4F7FA');s.row_dimensions[14].height=35
m(s,15,1,14,'来源：保盘系统硬件工作周报_20260904.xlsx（8条项目事项）。旭亮作为硬件汇报入口，具体后端/产品责任由团队共同落实。','F4F7FA');s.row_dimensions[15].height=38
q=m(s,17,1,14,'三级等保进度：查看单独工作表',ORANGE_BG,ORANGE,True);internal(q,'三级等保进度');s.row_dimensions[17].height=30
m(s,18,1,14,'软著：盘点三SPU及设备版本的证书与申请状态。一键部署V1.0.0：继续做测试环境安装、回滚与可复现验证。',ORANGE_BG,ORANGE);s.row_dimensions[18].height=40
s.print_area='A1:N18';s.page_setup.fitToHeight=1
# Detailed level-3 security schedule from the maintained four-week plan.
s=base('三级等保进度','三级等保｜备案、整改、测评与报告','已确认前置环境和8/27线上进场检查完成；9/6备案目标的实际结果待回读，9/25测评报告仍按目标推进。',7)
for j,wd in enumerate([24,46,48,43,42,27,27],1):s.column_dimensions[__import__('openpyxl').utils.get_column_letter(j)].width=wd
for j,v in enumerate(['事项','已知进展','9/7—9/13','9/14—9/20','9/21—9/30','责任','完成确认'],1):c(s,5,j,v,NAVY,WHITE,True)
mlps=[
('环境与材料前置','开发、独立服务器、域名与测试账号交付已完成。','复核版本与材料一致性。','随测评补充。','归档。','王朔/赖清涛','前置已完成'),
('网安进场检查','8/27线上检查完成。','回读整改通知和问题清单。','跟进外部问题确认。','归档。','王朔/赖清涛/网安','检查已完成'),
('整改通知与整改','原计划9/1—4接收并整改；完成证据未回读。','取得通知后按责任整改，留复测结果。','关闭主体测评发现的问题。','9/21—24补充复测。','王朔/赖清涛','待回读'),
('证明材料与用章回函','原目标9/5发出；本次材料未证明已发。','核实证明材料、用章和回函。','按测评反馈补齐。','完成归档。','王朔/审批人','待回读'),
('电子备案证','原目标9/6取得；本次未见证书原件。','9/7原定签发缓冲；核对实际签发。','未签发项升级跟进。','保留签发记录。','王朔/网安','目标非已取得'),
('等保测评','前置与进场窗口需确认。','争取测评进场、首轮核验。','主体测评、问题确认、整改复测。','9/21—24补充复测与定稿。','赖清涛/测评机构','待按实际推进'),
('测评报告','未见已取得报告事实。','锁定报告所需条件。','启动报告编制。','9/25取得报告为目标；9/26—30缓冲。','王朔/测评机构','目标非已取得')]
for rr,row in enumerate(mlps,6):
 for j,val in enumerate(row,1):c(s,rr,j,val,BLUE_BG if j==2 else ORANGE_BG if j==3 else None,BLUE if j==2 else ORANGE if j==3 else '243347')
 s.row_dimensions[rr].height=77
m(s,14,1,7,'依据：三级等保备案及测评进度表（8/27进度基准、9月四周计划）＋本次周报。外部签发日期以实际回读为准，未拿到原件不写成已取得。','F4F7FA');s.row_dimensions[14].height=43;s.print_area='A1:G14'
# Product section: the Harbin project now drives concrete government/enterprise nutrition work.
s=w['02-前厅营养结算'];s['A2']='以哈尔滨项目完善政企版本营养模块：菜单营养计算、餐段分析、超标提醒，与体检档案及PC/手机/大屏反馈连成完整流程。';s.row_dimensions[2].height=58
s['C8']='政企营养设计及大屏评审已有进展；哈尔滨部署、体检指标接口继续推进。'
s['H8']='完善菜单营养计算、餐段分析和超标提醒；核对体检指标、人员档案与统计口径。';s['M8']='哈尔滨（重点）'
s['H9']='跑通体检报告接收、人员绑定和手机档案展示，补异常与补传验证。'
s['H10']='用同一组样例核对PC和营养大屏，确认菜单/餐段指标一致。'
s['H11']='9/15前完成体检机联调预检；结算设备继续验证支付、同步和离线恢复。'
s['A14']='9月目标：借哈尔滨形成政企营养模块可演示版本、测试样例和操作说明；项目验证通过的共性能力回到标准产品。'
s['A16']='汇报重点｜哈尔滨既是交付项目，也是政企营养模块的验证场景：把体检数据与供餐营养分析做完整，再形成标准版本。'
s['A18']='炒菜机器人归入进销存与后厨运营的接口集成；体检档案和营养反馈归入前厅营养。新流程以项目联调结果验证。'
internal(s['M9'],'哈尔滨项目图解')
s=w['04-智慧进销存'];s['A2']='上周批量排菜等功能已有产出；本周先锁三全/哈尔滨范围，再做业务联调。';s['H11']='以哈尔滨TC-40EA为样例，冻结工艺/任务/回执范围，完成厂商接口联调。';s['A14']='9月重点：三全先完成总部业务流程；哈尔滨验证炒菜机器人任务与回执，成熟后沉淀后厨设备接入标准。'
# User-supplied meeting updates and exact monthly target are preserved.
s=w['交付实施部管理概况'];assert '10个项目' in s['A3'].value
s['E3']='数科9月计划312.8万元；预估280.9665万元；源表已达成2.717万元。重点抓北体大209万元、浙江体科所50万元。';s.row_dimensions[3].height=60
s['A19']='本周售前/售后：准备固安宣武医院9/14—18食安监管售前；北体大9/15后培训；令颖/王金洋/赵野核对上海一体机事项；仙龙潭争取9/13前修复；补商户号/证书配置培训。';s.row_dimensions[19].height=46
q=s['A2'];q.comment=Comment('交付目标保留用户主文件“10项目/月”；确收计划以本次用户指定的9月销售冲刺表为准，范围不同。','Codex')
s=w['交付中项目'];s['A2']='上周以现场联调和运营准备为主；本周锁定交付日期、处理遗留问题，并取得客户确认。';internal(s['C5'],'哈尔滨项目图解');internal(s['C6'],'中央美院项目图解');s['E6']='现场餐线、410界面、食安驾驶舱已有照片；运营准备与差异核对同步推进。'
s['G5']='借项目完善政企营养模块，锁定到货与接口责任，完成9/15设备联调预检。'
s['E11']='9/8交付30台动感单车为目标；海宇本次不在现场，安装资源需落实。'
s['K11']='明确现场安装负责人、差旅与安装费用，确保30台逐台签收。'
s['G12']='按34个摄像头与留样秤锁点位、物料和进场日，6天倒排交付。'
s['D16']='江西体科医：9/24、9/28节点须统一，医务侧提供服务器；劲玮锁定到位时间与版本边界。'
# Add a small intake index for future project photo batches.
s=base('图片接入清单','项目图片接入清单｜后续继续按项目追加','央美7张、哈尔滨2张已嵌入；后续项目沿用现场事实、流程说明、设备图片及下一步动作的组织方式。',6)
for j,v in enumerate(['项目','已收图片','主汇报页','图片说明','后续补充','状态'],1):c(s,5,j,v,NAVY,WHITE,True)
intake=[('中央美院',7,'中央美院项目图解','4张主图；3张流程/设计附图','数量签收、照片时间、运营说明','已接入'),('哈尔滨',2,'哈尔滨项目图解','体检实物照片、机器人厂商图','实际到货/安装、联调与营养界面','已接入')]
for name in ['大庆油田','安徽体职院','富士康','江西体科医','北体大','上海崇明','固安宣武医院','仙龙潭','张家港','滨州','彩育3校','金斯瑞','四方达','三全','城市副中心']:intake.append((name,None,'待提供图片后建立','按用户后续说明归类','现场图、设备、问题前后、操作流程','待提供'))
for rr,row in enumerate(intake,6):
 for j,val in enumerate(row,1):c(s,rr,j,val)
 s.row_dimensions[rr].height=36
s.sheet_state='hidden'
# Leadership rewrite of the newly supplied weekly and monthly plans.
rnd=json.loads((P/'rnd-plan-source.json').read_text());month_tasks=[];proj=''
for r in rnd['month']:
 v=r['values']+[None]*12
 if r['row']<=2:continue
 if v[0]:proj=v[0]
 if not v[3]:continue
 month_tasks.append({'source_row':r['row'],'project':proj,'task':v[3],'product_status':v[4] or '未填','product_date':v[5],'product_owner':v[6],'dev_status':v[7] or '未填','dev_date':v[8],'dev_owner':v[9],'project_date':v[1]})
assert len(month_tasks)==63
assert not any(t['product_date'] or t['dev_date'] for t in month_tasks)
har=[t for t in month_tasks if '哈尔滨' in t['project']];assert len(har)==10 and sum(t['dev_status']=='待开发' for t in har)==9
s=base('产研9月重点','产品开发部｜9月重点与本周安排','建议9月抓三件事：保交付与确收、做出哈尔滨政企营养样板、沉淀可复用标准版本。',5)
for j,wd in enumerate([35,42,52,49,26],1):s.column_dimensions[__import__('openpyxl').utils.get_column_letter(j)].width=wd
m(s,4,1,5,'目前月表63条任务，产品/开发交付日期均未填；哈尔滨10条中1条标开发完成、9条待开发。先把任务池变成有交付日的计划。','DDEBF7',bold=True);s.row_dimensions[4].height=46
for j,v in enumerate(['9月要交出的结果','当前差距','本周动作与节点','负责人及需要的支持','业务价值'],1):c(s,6,j,v,NAVY,WHITE,True)
leadership=[
 ('优先1｜营养样板','哈尔滨形成体测→档案→PC/手机营养反馈的可用流程，完善政企营养模块。','上禾接口标完成开发；展示、机器人、450等仍列待开发，部分接口项重复，需先核清。','确认一期范围和排期；把菜单营养计算、餐段分析、超标提醒与体检展示的样例跑通；完成联调预检。','将产品、前后端、设备厂商的联调窗口对齐；先保9/15必须项，扩展需求分期。','李潇/孙海琴；兰海军/郭东伟；海宇/赵野','9/15设备联调（已定目标）；完整发布范围9/7确认','交付一个项目，同时形成政企营养可复用版本。'),
 ('优先2｜交付收口','央美、滨州、重庆等具备稳定运营条件；确收项目所需资料有人跟、日期明确。','月表仍有手机管理端、离线、营养历史数据、消费机异常等欠项；确收名单与研发任务未按合同一一关联。','央美核10项差异与培训；滨州/国康优先修异常；四方达补试运行与对账；给每项剩余工作写完成日。','销售/销管明确确收项目及合同范围；产品和交付确认必须完成的功能，研发优先处理阻断项。','李潇/海琴；赖清涛/兰海军/尹旭亮；各项目交付','9/7锁剩余清单；四方达暂排9/9试运行','先保障客户使用和单据收口，不把已写代码等同于验收。'),
 ('优先3｜三全总部','在已确认范围内完成总部结算与接口联调，再决定其他基地复制。','付款码有用户上线确认；周/月表仍保留支付宝计划项；钉钉、魔点、商米及食安部署缺统一状态。','核对已上线支付范围、退款对账及剩余接口；确认总部业务蓝图和客户配合条件。','客户信息与使用部门确认同一需求基线；厂商/后端排联合测试，新增外采接口单独估时。','李潇/赵野；赖清涛/尹旭亮','本周先锁基线和联调日；全项目交付日另定','避免需求持续扩张，形成可复制的总部配置。'),
 ('优先4｜标准版本','形成三SPU的标准功能/版本清单和设备适配清单，交付时能直接选用。','批量排菜、计价/营养重量、辣度、Logo、多端入口、同步/离线功能分散在项目任务中。','先合并共性需求与版本范围；修复计价/营养口径和设备稳定性；输出安装、测试、操作材料。','确认本期版本负责人和跨机型测试窗口；新界面与低优优化集中排期，减少现场插单。','产品组；两个开发组；尹旭亮','建议9/11版本评审；9月底完成选定版本交付包','减少重复开发、重复部署和重复培训。'),
 ('优先5｜合规与售前','三级等保按9/25报告目标推进；5项软著跟踪；标准PPT、参数、功能手册成套。','周表列5项软著跟进；备案整改仍依赖外部；学校膳食/新产品设计与交付工作竞争同一批人员。','回读9/6备案结果；推进整改、测评；先支持浙江体科、大庆等当前售前项目，给新产品评审排窗口。','王朔统筹合规与新产品评审资源；销售确认售前优先级；外部通知、用章和测评窗口须落实。','王朔/孙海琴/李潇；赖清涛','9/25报告为目标；本周锁评审/材料节点','支撑投标、合同要求和标准产品销售。')]
for rr,row in enumerate(leadership,7):
 display=[row[0]+'\n'+row[1],row[2],row[3]+'\n节点：'+row[6],row[5]+'\n支持：'+row[4],row[7]]
 for j,value in enumerate(display,1):c(s,rr,j,value,BLUE_BG if j==2 else ORANGE_BG if j in [3,4] else None,BLUE if j==2 else ORANGE if j in [3,4] else '243347')
 s.row_dimensions[rr].height=110
m(s,13,1,5,'这周请领导重点确认：哈尔滨一期范围与联调资源；确收项目对应的研发必需项；三全总部范围；标准版本负责人；等保与新产品的资源顺序。',ORANGE_BG,ORANGE,True);s.row_dimensions[13].height=50
m(s,14,1,5,'以上优先顺序及新补节点为整理建议；已明确的9/15、9/25目标保留。月表状态须负责人回填，不按任务数算完成率。劲玮/产品组补运动员、教学、团餐版本与3SPU的对应边界。','F4F7FA');s.row_dimensions[14].height=42
s.print_area='A1:E14'
# A detailed traceability sheet remains available behind the leadership page.
ref=base('产研规划明细','产研规划原始任务｜按9月表逐行保留','领导页看交付结果；本页保留63条任务、原状态与负责人，日期1899-12-30视为无有效计划日期。',9)
for j,head in enumerate(['源行','项目/主题','任务','产品状态','产品交付日','产品负责人','开发状态','开发交付日','开发负责人'],1):c(ref,5,j,head,NAVY,WHITE,True)
for rr,t in enumerate(month_tasks,6):
 for j,value in enumerate([t['source_row'],t['project'],t['task'],t['product_status'],t['product_date'],t['product_owner'],t['dev_status'],t['dev_date'],t['dev_owner']],1):c(ref,rr,j,value)
ref.sheet_state='hidden'
# Replace the old export completion ratio with the newly verified planning fact.
s=w['交付实施部管理概况'];s['C11']='9月月表有63条任务；产品和开发交付日期尚未填齐，尚不能直接判断月度能否完成。';s['I11']='本周先锁哈尔滨一期范围、交付阻断项和标准版本排期；按结果和日期跟进。';s.row_dimensions[11].height=82
s['C11'].comment=Comment('本次两份新规划回读与旧HTML 96/68/28统计不是同一数据快照，故主汇报替换为当前月表事实；旧统计仅在历史底稿保留。月表B列有1899-12-30占位，F/I列未填有效日期。','Codex')
s=w['哈尔滨项目图解'];s['A28']='本周：月表10项先拆清一期必需范围（1项标开发完成、9项待开发），锁PC/手机展示与机器人、450联调资源，保证9/15设备联调目标。';s.row_dimensions[28].height=50
s=w['02-前厅营养结算'];s['A14']='9月要交出的产品效果：管理员能看菜单/餐段营养与超标提醒；用餐人能在手机查看体检档案和营养反馈，PC/大屏口径一致。以哈尔滨先验证。';s.row_dimensions[14].height=64
s['A16']='领导关注：上禾接口“开发完成”只是一个环节，多端展示和端到端联调仍需排期。9/7先确认一期必须交付范围与负责人。';s.row_dimensions[16].height=60
s=w['03-智慧食安监管'];s['A2']='9月先保障在途项目的食安部署、预警与整改闭环；新功能先确认客户场景和评审窗口，不以规划清单代替产品发布。';s.row_dimensions[2].height=54
s=w['04-智慧进销存'];s['A16']='领导关注：三全先确认菜单、采购、库存的总部范围；哈尔滨机器人目前月表仍待开发，必须先锁厂商接口与联合测试时间。';s.row_dimensions[16].height=60
s=w['硬件与证书申请'];s['D6']='410已有验证记录；较早周表曾报450单秤上线，450/460当前整体范围仍需核清。';s['D6'].comment=Comment('周表8/17—24的450单秤已上线记录，与硬件专项450/460待迁移不是同一范围；本次保留型号/单双秤差异，不直接判所有机型都未做。','Codex')
s['A18']='软著：按周表跟进5项申请，逐项确认受理/证书状态。一键部署：优先验证标准环境安装和回滚；学校膳食新品先锁评审与开发窗口。'
# Fit the user's restored dashboard screenshot to a single page without changing its content.
s=w['项目经营大屏']
old=s._images[0];replacement=Image(io.BytesIO(old._data()));scale=min(1160/replacement.width,610/replacement.height);replacement.width*=scale;replacement.height*=scale;s._images=[replacement];replacement.anchor='A6'
for col in range(1,19):s.column_dimensions[__import__('openpyxl').utils.get_column_letter(col)].width=9
for row in range(4,41):s.row_dimensions[row].height=17
s.row_dimensions[1].height=32;s.row_dimensions[2].height=48;s.row_dimensions[3].height=35
m(s,4,1,18,'保留原稿截图，未刷新为本周运营数据；活跃字段按累计人次理解，日期范围以实际接口筛选为准。','F4F7FA');s.row_dimensions[4].height=32
s.page_setup.orientation='landscape';s.page_setup.paperSize=s.PAPERSIZE_A3;s.page_setup.fitToWidth=1;s.page_setup.fitToHeight=1;s.sheet_properties.pageSetUpPr.fitToPage=True;s.print_area='A1:R40'

# Order the additions where Jack will talk about them, leaving existing reference tabs hidden.
visible_order=['项目经营大屏','交付实施部管理概况','9月确收清单','团餐确收协同','产研9月重点','交付中项目','中央美院项目图解','哈尔滨项目图解','硬件与证书申请','三级等保进度','02-前厅营养结算','03-智慧食安监管','04-智慧进销存']
w._sheets=[w[n] for n in visible_order]+[s for s in w if s.title not in visible_order]
for s in w:
 for row in s:
  for q in row:
   if q.value is not None:
    f=copy(q.font);f.name='微软雅黑';f.sz=12;q.font=f
 s.sheet_view.tabSelected=False
w.active=w.sheetnames.index('产研9月重点');w['产研9月重点'].sheet_view.tabSelected=True
w.save(OUT)
assert hashlib.sha256(SRC.read_bytes()).hexdigest()==source_hash
(P/'image-manifest.json').write_text(json.dumps(manifest,ensure_ascii=False,indent=2))
(P/'receipt.json').write_text(json.dumps({'input':str(SRC),'input_sha256':source_hash,'output':str(OUT),'output_sha256':hashlib.sha256(OUT.read_bytes()).hexdigest(),'visible_sheets':visible_order,'images_added':len(manifest),'monthly_delivery_target':'10个项目/月（保留用户主表）','revenue_scope':'数科业务中心14项目；团餐关联项单列','revenue_plan':3128000,'revenue_forecast':2809665,'revenue_actual':27170,'hardware_source':str(HW),'hardware_rows':8,'mlps_rows':7,'monthly_task_rows':len(month_tasks),'leadership_lanes':len(leadership),'user_input_unchanged':True},ensure_ascii=False,indent=2))
(P/'.gitignore').write_text('*.xlsx\n*.pdf\n*.png\n*.csv\nassets/\nrevenue-source.json\nrnd-plan-source.json\n')
print(json.dumps({'output':str(OUT),'bytes':OUT.stat().st_size,'images_added':9,'visible_sheets':len(visible_order),'total_sheets':len(w.sheetnames)},ensure_ascii=False))
