"""W38 evidence-backed illustrated workbook. Raw sources and artifacts stay local."""
from pathlib import Path
from copy import copy
import json,hashlib,shutil,math
from openpyxl import Workbook,load_workbook
from openpyxl.styles import Font,PatternFill,Alignment,Border,Side
from openpyxl.comments import Comment
from openpyxl.drawing.image import Image as XImage
from openpyxl.drawing.spreadsheet_drawing import OneCellAnchor,AnchorMarker
from openpyxl.drawing.xdr import XDRPositiveSize2D
from openpyxl.utils import get_column_letter
from openpyxl.worksheet.pagebreak import Break
from PIL import Image,ImageOps

HERE=Path(__file__).resolve().parent; ROOT=HERE.parents[3]; OUT=HERE/'output'; A=OUT/'assets'; DEL=OUT/'修订版'; DEL.mkdir(exist_ok=True)
NAVY='193A4D';BLUE='216F92';TEAL='277D73';ORANGE='AC6224';GRAY='566875';LIGHT='EDF4F7';LINE='DCE5EA';WHITE='FFFFFF'
MEETING='https://zhctpmt.yyangpt.cn/work/2026-09-18-weekly-meeting/weekly-meeting-content.html'
SPACE='https://doc.weixin.qq.com/smartsheet/s3_AHkAH3hlAHwCNUzm1hPTKQQGwNBft_a'
COLLECT='https://doc.weixin.qq.com/sheet/e3_Ac0AJgaVAEYCN2YUa9YSsQKC6Sx37'
PACK='https://doc.weixin.qq.com/sheet/e3_AdYAzAZnACUCNCp19nO7KSR6LnvvB'
# Preserve the latest illustrated template's navy/blue 12-column card layout.
wb=Workbook();wb.remove(wb.active)
images=json.loads((OUT/'image-manifest.json').read_text());image_map={m['key']:Path(m['local']) for m in images}
for key,source in [('harbin-health','work/weekly-reports/2026-W36/weekly-0907-project-photos/assets/harbin-health.jpg'),('offline','work_android/CusumptionMachine/announcements/assets/offline-order-release/02-offline-order-list.png'),('school','work/weekly-reports/2026-W37/project-cockpit/output/项目驾驶舱周报包/assets/proto-school-analysis.jpg')]:
 src=ROOT/source; dst=A/(key+src.suffix);shutil.copy2(src,dst);image_map[key]=dst
 images.append(dict(key=key,source=source,local=str(dst),sha256=hashlib.sha256(src.read_bytes()).hexdigest()))
for i in range(3):image_map[f'certificate-{i}']=A/f'certificate-{i}.png'

def box(s,r1,c1,r2,c2,text='',bg=None,color=GRAY,bold=False,link=None,source=None):
 s.merge_cells(start_row=r1,start_column=c1,end_row=r2,end_column=c2)
 c=s.cell(r1,c1,text);c.font=Font(name='微软雅黑',size=12,bold=bold,color=color)
 c.alignment=Alignment(vertical='center',wrap_text=True,indent=1)
 if bg:
  for row in s.iter_rows(min_row=r1,max_row=r2,min_col=c1,max_col=c2):
   for q in row:q.fill=PatternFill('solid',fgColor=bg)
 if link:c.hyperlink=link
 if source:c.comment=Comment(source,'证据来源')
 return c

def sheet(name):
 s=wb.create_sheet(name);s.sheet_view.showGridLines=False;s.sheet_view.zoomScale=85
 for c in range(1,13):s.column_dimensions[get_column_letter(c)].width=13
 s.sheet_properties.pageSetUpPr.fitToPage=True
 s.page_setup.orientation='landscape';s.page_setup.paperSize=s.PAPERSIZE_A4;s.page_setup.fitToWidth=1;s.page_setup.fitToHeight=0
 s.page_margins.left=s.page_margins.right=.28;s.page_margins.top=s.page_margins.bottom=.28
 s.freeze_panes='A5';s.oddFooter.center.text='康比特数字技术中心  |  内部周报  |  &P'
 s.oddFooter.center.size=9
 return s

def page(s,title,subtitle):
 n=getattr(s,'_pages',0);r=n*28+1;s._pages=n+1
 for i in range(r,r+28):s.row_dimensions[i].height=20
 if n:s.row_breaks.append(Break(id=r-1))
 box(s,r,1,r+1,12,title,NAVY,WHITE,True)
 box(s,r+2,1,r+3,12,subtitle,LIGHT,GRAY)
 box(s,r+27,1,r+27,12,'本周：9月14—20日  |  更新：9月19日  |  售前支持 → 交付项目 → 产品',color=GRAY)
 s.print_area=f'A1:L{r+27}'
 return r

def picture(s,key,r,c,maxw,maxh):
 src=image_map[key]
 im=ImageOps.exif_transpose(Image.open(src)).convert('RGB');im.thumbnail((1900,1900))
 dest=A/(key+'-display.jpg');im.save(dest,quality=93)
 x=XImage(dest);f=min(maxw/x.width,maxh/x.height);x.width*=f;x.height*=f
 # Center inside its reserved box, without stretching or cropping evidence.
 x.anchor=OneCellAnchor(_from=AnchorMarker(col=c-1,row=r-1,colOff=int((maxw-x.width)/2*9525),rowOff=int((maxh-x.height)/2*9525)),ext=XDRPositiveSize2D(int(x.width*9525),int(x.height*9525)))
 s.add_image(x)

def para(s,r,c1,c2,title,body,height=3,color=BLUE):
 box(s,r,c1,r,c2,title,LIGHT,color,True)
 box(s,r+1,c1,r+height,c2,body)

# The user's latest order and product-state correction override older report conventions.
for key,source in [('rongcheng','modules/product/products/smart-canteen/product-solutions/2026-09-17-cad-canteen-3d/v2/local-assets/preview-final.png'),('scale','output/inventory-scale-20260916/assets/cpt-inventory-scale-brochure.png'),('gov','work/weekly-reports/2026-W37/project-cockpit/output/项目驾驶舱周报包/assets/proto-supply.jpg')]:
 image_map[key]=ROOT/source

def grid(s,r,rows,source):
 bands=[(1,2,'客户 / 项目'),(3,7,'本周工作与形成结果'),(8,10,'当前问题 / 下一步'),(11,12,'责任人')]
 for a,b,t in bands:box(s,r+4,a,r+4,b,t,BLUE,WHITE,True)
 for i,row in enumerate(rows):
  q=r+5+i*3
  for (a,b,_),v in zip(bands,row):box(s,q,a,q+2,b,v,LIGHT if i%2==0 else None,color=BLUE if a==1 else GRAY,bold=a==1,source=source)

s=sheet('售前支持');r=page(s,'一、售前支持｜本周方案、资料与适配评估集中产出','按在线“售前支撑工作统计”及本周成果逐项整理；先讲做成了什么，再讲项目下一步。')
sales1=[
('雄安容城中学','补齐二、三层动力图；9/17完成V1空间漫游与V2设备/系统3D方案，支持增删、摆位与导出。目录83条，默认57台设备、31种产品。','两版已供客户查看；设备配置与摆位继续现场深化。','姜阳、王朔'),
('北京安达泰康','9/16提供智能出入库秤康比特彩页、电子说明书、操作视频及31页V1.0.6接口文档，形成完整介绍与对接资料包。','确认客户对接需求；继续补充商务反馈。','姜阳'),
('雄安宣武医院','9/17完成食安监管建设方案可行性审阅，输出4处标红意见：远程访问、4G接入、水浸网关预算、供货报价范围。','逐项确认网络/设备路径及预算，作为方案收口条件。','姜阳、王朔'),
('南京苏美达','9/15按招标参数查找硬件清单并核对功能匹配；在线记录注明为新开普自有项目。','成单转化当前记“否”；匹配结论作为后续筛选依据。','李潇'),
('广东体科所','9/15启动科训系统升级售前支持，整理产品需求、方案概述和报价单；本周周会确认完成相关支持。','继续确认升级边界与报价反馈。','王朔'),
('县级教委项目','9/17启动建设方案、产品介绍PPT和项目采集表支持；对应在线表“宁夏安吉县县级教委项目”原名。','核对客户正式名称及具体学校范围；完善资料。','王朔'),
('上海第五医院','9/18完成7项需求适配与三周全量交付评估：桌位点餐、院内配送、甜品核销等；估算96—119人天，核心8人并行。','15工作日为条件估算；先确认设备、支付资料及业务边界。','赖清涛')]
grid(s,r,sales1,'9/19实时读取售前支撑工作统计；9/16登记回执；上海第五医院9/18适配评估。')
box(s,r+26,1,r+26,12,'以上是本周资料和方案成果；成交状态按商务记录，不把售前支持当作签约。',color=GRAY)
r=page(s,'一、售前支持｜持续商机与本周支撑全部展开','持续项目以9/18周会确认本周参与，再从在线售前台账补充具体工作内容。')
sales2=[
('大庆油田','本周继续项目支持，售前工作聚焦软件功能定义与范围确认。','冻结软件范围与定制边界，继续形成开发评估。','李潇'),
('张家口中煤','本周继续报价及参数核对；在线台账明确“硬件要求满足不了”。','列清硬件响应偏差，评估可替代方案与商务去留。','李潇'),
('河北体育局 / 体校','持续输出投标材料；已登记带三角参数截图及进销存系统确认材料，本周继续售前支持。','核对材料与当前招标要求，补齐差异响应。','李潇、王朔'),
('大兴易迅博慧','本周继续建设方案与立项材料支持；在线台账累计列示10余份材料。','明确本轮新增/修订项及客户反馈；10余份不作本周新增数。','王朔'),
('江南大学','9/18周会记录本周项目支持；在线售前台账列有该项目，但任务描述与成果附件未填写。','补录本周具体需求、已交付材料和客户反馈。','李潇、孙海琴'),
('秦皇岛 / 教育局平台','王朔本周周会列有相关售前售后支持；秦皇岛具体成果未展开，教育局条目尚不能确认与前页县级教委是否同一项目。','补具体项目名、工作内容和结果；本页不另加重复项目数。','王朔')]
grid(s,r,sales2,'9/18在线周会逐人明细；9/19实时售前支撑工作统计。秦皇岛等保留原始模糊程度。')
box(s,r+23,1,r+25,12,'共用售前资产：明确AI营养智慧食堂6类应用场景，规划18组材料、首批3份PPT已完成；本周另形成社区营养方案、三产品线项目采集表与县域学校调研模板，供销售后续复用。',LIGHT,BLUE)
box(s,r+26,1,r+26,12,'旧台账中早期已结束的工作不重复计入本周；仍挂账但没有本周新记录的项目保留在内部核对表。',color=GRAY)
r=page(s,'一、售前成果展示｜容城交互方案与出入库秤资料包','本页均为本周产出的售前材料；用可查看的方案和产品资料支撑客户讨论。')
box(s,r+4,1,r+4,8,'雄安容城中学｜从CAD到可调整的设备方案',BLUE,WHITE,True)
picture(s,'rongcheng',r+5,1,730,335)
box(s,r+18,1,r+21,8,'V1用于看空间和动线，V2用于讨论设备、系统和配置。设备增加、删除、位置调整与Excel导出已验证；销售与客户可以围绕同一份方案修改。',source='售前表9/17追加记录；V2 README及发布回执。')
box(s,r+22,1,r+24,8,'下一步：确认现场尺寸、点位和最终配置。当前数量为方案建议，未作为最终供货清单。',LIGHT,ORANGE)
box(s,r+25,1,r+26,8,'打开容城V2交互方案 ↗',link='https://img.kxunpt.cn/public/ai-marketing-platform/modules/product/products/smart-canteen/product-solutions/2026-09-17-cad-canteen-3d/v2/smart-canteen-3d-v2.html',color=BLUE)
box(s,r+4,9,r+4,12,'北京安达泰康｜出入库秤',BLUE,WHITE,True)
picture(s,'scale',r+5,9,360,395)
box(s,r+20,9,r+24,12,'彩页 + 说明书 + 操作视频 + 接口文档已成套交付。既支持销售介绍，也为下一步技术对接提供资料。',source='9/16安达泰康售前登记及附件回读。')
box(s,r+25,9,r+26,12,'打开电子说明书 ↗',link='https://img.kxunpt.cn/public/ai-marketing-platform/modules/product/products/smart-canteen/product-solutions/2026-09-16-inventory-scale-branding/manual.html',color=BLUE)

s=sheet('项目');r=page(s,'二、交付项目｜哈尔滨、三全的本周实际进展','本周重点：现场安装调试、机器人对接、支付权限和交付范围收口。')
delivery=[
('哈尔滨膳质舍','harbin-health','现场完成体检一体机、称重台和绑盘机安装测试，配合机器人培训；研发完成小程序/档案收尾上线、食物成分及调味品同步联调。','现场周报：机器人数据对接测试50%，全流程测试80%；现有菜品尚待清理同步。','赵野协调现场；兰海军、郭东伟、李潇补菜品数据、全流程复测和交付视频。'),
('三全集团','sanquan-weigh','研发侧支付宝配置已完成；现场协调访问权限、确认食安摄像头点位。钉钉组织人员同步及PC功能已拆为开发清单。','魔点、商米、钉钉和食安尚未全部闭环；商米利旧、碰一碰本周未推进。','先完成小餐台支付宝测试与食安摄像头部署；赵野、赖清涛、尹旭亮、田亚辉收敛交付顺序。')]
for j,(name,im,fact,risk,nxt) in enumerate(delivery):
 q=r+4+j*11;box(s,q,1,q,12,name,BLUE,WHITE,True);picture(s,im,q+1,1,360,200)
 box(s,q+1,5,q+3,12,'本周结果｜'+fact,source='9/18在线周会；实时赵野本周周报。')
 box(s,q+4,5,q+6,12,'当前差距｜'+risk,LIGHT,ORANGE)
 box(s,q+7,5,q+9,12,'下一步｜'+nxt)
 box(s,q+9,1,q+10,4,'项目历史现场图，仅说明设备场景；进展以右侧本周记录为准。')
r=page(s,'二、交付项目｜部署、联调与终端闭环','重点关注四方达、重庆、保康、央美等本周产生实际变化的项目。')
d2=[
('四方达','组织/人员初始化、VPN远程协调完成；研发完成人脸配置及端口适配；端口替代方案现场测试50%。','确认替代443访问方案，通过整链路测试后试运行；补人员、人脸、卡号同步。','赵野；赖清涛、尹旭亮'),
('重庆环卫','450推荐量、跨端能量统一和重量限制已上线；扫码身份认证约70%；赠送余额接口已上线，终端显示待完成。','完成扫码真机验证及余额展示，关闭客户验收问题。','赖清涛、尹旭亮；李潇'),
('保康中学','进销存系统部署完成；食安进场，完成一楼摄像头调试；研发完成保康食安部署支持。','完成一楼、二楼及职工餐厅全部设备联调。','张帅；孙倩倩'),
('中央美院','完成一卡通消费失败补传、消费前卡同步、消费记录同步和日志；本周现场联调晨检仪、留样秤。','完成异常恢复及食安终端复测，收齐客户确认。','尹旭亮、张帅'),
('张家港农商行','结算接口与部署包已完成；接口部署进入现场准备阶段。','下周完成客户现场部署和业务验证。','赖清涛'),
('机场项目','13台新配壁挂消费机完成软件安装联调，支持运动会临时摊位；账户流水查询VWCG-1381已明确。','姜阳、赖清涛推进查询实现；李潇、赖清涛确认上线排期。','张帅；姜阳、赖清涛')]
grid(s,r,d2,'9/18在线周会；张帅/赵野9.14—9.20实时周报。')
box(s,r+24,1,r+26,12,'重庆项目资料已补：14台450、2台绑盘机、1台体检一体机、1台消费机等；甲方仍在体验，效果待反馈。设备范围可讲清，降本和健康成效尚不量化。',LIGHT,BLUE,source='交付物料准备包/2-项目核心信息表。')
r=page(s,'二、交付项目｜持续优化与交付资料闭环','分别写清本周结果和下一步，不把累计设备数量或历史照片当作本周新增交付。')
d3=[
('滨州','本周仍需收口核销功能和营养数据；产品支持运营大屏。在线核心表补充当前410单秤80台、绑盘8台、消费机30台等配置。','兰海军完成核销测试上线；结合客户访谈核对实际使用与产教融合需求。','兰海军、李潇；王金洋'),
('金斯瑞','小票补打、送餐地址查看及相关异常修复已完成，订单处理信息更完整。','现场核对版本和复测结果；历史退款问题单独回归。','赖清涛'),
('国康医院','售卖柜联调完成；称重流程简化与赠送余额终端显示仍需开发配合。','完成终端流程验证并开展客户访谈。','赖清涛、尹旭亮、孙海琴'),
('国信','小卖店补单已上线；本周继续个性化报表支持。','开发充值、扣款、销户统计；完善人员批量调部门、全局搜索与订单区分。','兰海军、郭东伟'),
('江西体科所','体重管理、InBody对接和体能模块完成开发。另有医务系统部署任务，属于持续实施。','输出InBody手册，完成测试上线；医务部署按独立实施范围管理。','兰海军'),
('其他现场支持','安庆部队大屏调试及日期兼容完成；城市副中心返厂设备重新配置入网；兴海留样秤返修；北体大、崇明、广州、旧宫等有运维处理。','分别跟进现场复测、返修检测及客户确认，不合并为全部故障关闭。','孙倩倩、赵野、张帅')]
grid(s,r,d3,'9/18在线周会；赵野/张帅本周周报；项目核心表。')
box(s,r+23,1,r+26,12,'交付准备已细化到执行清单：服务器与小程序前置条件、410标识/手册/易损备件、交付前—中—后照片视频、同机位前后对比、完成后3个工作日归档及7项项目核心信息。重庆、滨州已填写核心信息，继续回收现场成果。',LIGHT,BLUE,source='本次完整读取交付物料准备包五个子表。')

s=sheet('产品');r=page(s,'三、产品｜政企营养、学校营养均已设计完成，正在开发','两条营养产品线均已转入研发实现，重点推进功能开发、联调与测试。')
for a,b,title,key,body,nextstep in [
(1,6,'政企营养｜设计完成 · 开发中','gov','政企营养产品设计已完成，正在开发。围绕带量食谱、食谱解读及营养分析，推进页面与接口实现。','按已定方案完成食谱解读与相关页面、接口联调；结合真实菜谱验证结果。'),
(7,12,'学校营养｜设计完成 · 开发中','school','需求、接口、数据库、测试和推荐算法方案均已完成，正在集中开发。范围覆盖供餐模板、食谱编制、营养分析、审核发布及版本追溯。','完成食材净用量与配餐推荐等主流程，按9月底目标开展开发、联调与测试。')]:
 box(s,r+4,a,r+5,b,title,BLUE,WHITE,True);picture(s,key,r+6,a,550,235)
 box(s,r+16,a,r+19,b,body,source='用户最新明确确认优先；9/18周会与方案目录补充功能范围。')
 box(s,r+20,a,r+23,b,'下一步｜'+nextstep,LIGHT,ORANGE)
 box(s,r+24,a,r+26,b,'设计界面展示；产品已进入开发，截图本身不代表生产上线。',color=GRAY)
r=page(s,'三、产品｜本周标准能力、移动端与研发协作','已上线能力、设计成果和工程建设分开说明；不将“AI已生成材料”写成已完成生产验收。')
box(s,r+4,1,r+4,8,'交易与结算｜异常恢复和订单处理能力补齐',BLUE,WHITE,True);picture(s,'offline',r+5,1,730,205)
box(s,r+13,1,r+15,8,'消费机离线订单、扫码支付超时配置已完成；PC订单详情、多菜品展示、补打小票已有上线成果。央美一卡通补传/同步与金斯瑞订单信息在项目部分对应说明。',source='9/18在线周会、9/17功能演示界面。')
box(s,r+16,1,r+18,8,'菜品与营养｜菜品识别纠错、菜品库互通、AI问答异常优化完成；手机订餐体验优化已上线，搜索待开发；华为运动健康指标获取完成演示。')
box(s,r+19,1,r+22,8,'AI与工程｜形成售前调研模板、需求—接口—测试资料、原型追踪及任务台账；下一步用真实任务验证自动测试、SQL部署和部署Agent。三级等保仍待网安审核，密评继续补材料。',LIGHT,BLUE)
box(s,r+23,1,r+26,8,'下周重点：把已完成设计转成可运行流程，把已上线功能整理成版本、测试与操作资料；按实际发布范围做跨项目复用。',color=ORANGE)
box(s,r+4,9,r+4,12,'商户移动管理｜原型完成',BLUE,WHITE,True);picture(s,'merchant',r+5,9,360,335)
box(s,r+18,9,r+22,12,'经营数据、订单管理和补打小票原型已形成；完成9家竞品分析。下一步评审移动端范围、权限与接口。',source='孙海琴9/18周会、商户移动端设计目录。')
box(s,r+23,9,r+26,12,'截图为静态原型，经营数字用于展示，不作为公司营业数据。',LIGHT,GRAY)
r=page(s,'三、产品资质｜本周新增两项软著登记','营养点餐、消费终端营养结算于9月16日登记；称重结算系统8月20日已登记，作为已有资质保留。')
for i,(key,title,num) in enumerate([('certificate-0','智慧食堂营养点餐系统 V1.0','2026SR0946678'),('certificate-1','智慧食堂消费终端营养结算系统 V1.0','2026SR0946737')]):
 a=1+i*6;b=a+5;box(s,r+4,a,r+5,b,title,BLUE,WHITE,True);picture(s,key,r+6,a,550,475)
 box(s,r+24,a,r+26,b,f'登记号：{num}  |  2026-09-16\n著作权人：北京康比特体育科技股份有限公司',LIGHT,TEAL)

for s in wb:
 for row in s:
  for c in row:
   f=copy(c.font);f.name='微软雅黑';f.sz=12;c.font=f
wb.active=0
out=DEL/'本周周报_售前-交付-产品_20260914-0920_修订版.xlsx';wb.save(out)
w=load_workbook(out)
assert w.sheetnames==['售前支持','项目','产品']
assert all(c.font.name=='微软雅黑' and c.font.sz==12 for s in w for row in s for c in row if c.value is not None)
assert not any(c.data_type=='e' for s in w for row in s for c in row)
receipt={'file':out.name,'sheets':w.sheetnames,'images':{s.title:len(s._images) for s in w},'pages':9,'presales_rows':13,'presales_primary_records_reviewed':33,'product_state':'政企营养、学校营养：设计完成，开发中；依据用户9/19更正','sha256':hashlib.sha256(out.read_bytes()).hexdigest(),'bytes':out.stat().st_size}
(HERE/'revision-validation.json').write_text(json.dumps(receipt,ensure_ascii=False,indent=2)+'\n')
print(json.dumps(receipt,ensure_ascii=False,indent=2))
