"""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,'一、售前支持｜把需求、产品适配和交付投入提前讲清','本周支持归纳为四类共性工作；具体项目用于说明成果，完整明细在本Sheet底部展开查看。')
box(s,r+4,1,r+6,12,'本周售前的主要成果：从客户需求出发，形成可讨论的方案、可核对的参数、可评估的开发投入和可直接使用的产品资料，支持销售判断项目能否承接、如何推进。',LIGHT,BLUE,True)
para(s,r+8,1,6,'1. 需求澄清与方案设计','把场景、流程、设备和系统范围表达清楚。容城形成可调整的3D设备方案；县级教委、广东体科所、大庆和大兴分别开展建设方案、升级需求及功能范围支持。',3)
para(s,r+8,7,12,'2. 产品适配与投入评估','核对现有能力、硬件偏差、定制内容和开发周期。苏美达、中煤完成参数匹配；上海第五医院形成7项需求与三周实施条件评估，明确投入前提。',3)
para(s,r+14,1,6,'3. 产品资料与投标支撑','让销售介绍、投标响应和技术对接有成套资料。安达泰康形成彩页、手册、视频和接口包；河北体校补投标材料；场景材料首批3份PPT完成。',3)
para(s,r+14,7,12,'4. 提前识别落地条件','把网络、部署、接口、设备与预算问题前移。宣武医院审阅聚焦4项可行性问题；项目采集表覆盖营养、食安、采购三条产品线，便于提前补齐客户输入。',3)
box(s,r+20,1,r+22,12,'共性问题：客户需求、硬件参数、现场条件和交付周期需要一起确认。中煤存在硬件不匹配；医院项目的工期取决于设备、支付资料和业务范围，不能仅凭软件功能相似承诺交付。',LIGHT,ORANGE)
box(s,r+23,1,r+25,12,'下一步：各项目将成果收成“需求与偏差清单 + 配置/报价 + 定制周期 + 客户待办”；补齐客户反馈和成单状态，复用本周方案、资料与调研表。',color=BLUE)
box(s,r+26,1,r+26,12,'江南大学、秦皇岛等支持保留在备查明细；细节不足的项目继续补录，不虚构成果。',source='售前统计33条、9/18周会、两份在线表及本周项目产物。')
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)

refs=json.loads((HERE/'presales-reference.json').read_text())
box(s,57,1,57,12,'售前项目备查｜点击左侧“＋”展开13条原始归纳明细（不进入打印主报告）',LIGHT,BLUE,True)
for i,row in enumerate(refs['sales1']+refs['sales2']):
 q=58+i*3
 for (a,b),v in zip([(1,2),(3,7),(8,10),(11,12)],row):box(s,q,a,q+2,b,v)
 for rr in range(q,q+3):s.row_dimensions[rr].height=20;s.row_dimensions[rr].hidden=True;s.row_dimensions[rr].outlineLevel=1
s.row_dimensions[57].collapsed=True
s.sheet_properties.outlinePr.summaryBelow=False
s.print_area='A1:L56'

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,'下一步按项目收齐测试结果、客户确认和现场资料。交付物建设、素材回收及案例归档的统一要求单列在下一部分。',LIGHT,BLUE)

s=sheet('交付物建设');r=page(s,'三、交付物建设｜从项目条件采集到案例资料回收','已形成统一表单与操作要求；下一步重点是逐项目使用、回传和检查完整性。')
box(s,r+4,1,r+6,12,'这项工作把交付资料贯穿项目全过程：进场前问清条件、备齐软硬件与操作物料；实施时记录部署和培训；完成后回收现场素材与客户反馈，供后续交接、案例包装和销售复用。',LIGHT,BLUE,True)
for a,b,title,body in [(1,3,'① 采集项目条件','网络与部署、业务流程、接口、设备环境、初始化数据'),(4,6,'② 准备交付包','服务器/小程序前提、410物料、操作手册与备件'),(7,9,'③ 回收实施素材','改造前、实施中、完成后的图片视频及培训记录'),(10,12,'④ 形成项目案例','7项核心信息、实际配置、服务人群、甲方效果反馈')]:
 box(s,r+8,a,r+9,b,title,BLUE,WHITE,True);box(s,r+10,a,r+13,b,body,LIGHT)
para(s,r+15,1,6,'已经形成的内容','《项目采集表》覆盖智慧营养、智慧食安、智慧采购；《交付物料准备包》包含服务器、410设备、素材回收使用说明、素材规范、项目核心信息5个子表。',3)
para(s,r+15,7,12,'已经开始落地的内容','重庆和滨州已填写背景、服务内容、设备数量与服务人群。重庆甲方仍在体验，滨州效果反馈未填；照片视频是否齐全，需按项目目录逐项核对。',3)
box(s,r+21,1,r+23,12,'业务价值：把交付准备和资料交接的要求明确到表，帮助减少遗漏；把现场实施过程留下来，为推广中心制作案例、销售讲解真实项目提供来源。实际返工减少与复用效果需后续统计。',LIGHT,TEAL)
box(s,r+24,1,r+26,6,'打开项目采集表 ↗',link=COLLECT,color=BLUE)
box(s,r+24,7,r+26,12,'打开交付物料准备包 ↗',link=PACK,color=BLUE)
r=page(s,'三、交付物建设｜准备什么、谁收口、下一步查什么','表单要求与项目完成状态分别管理；模板已形成，实际交付物仍需逐项目回收。')
bands=[(1,2,'交付环节'),(3,7,'已明确的交付内容'),(8,12,'执行与检查重点')]
for a,b,t in bands:box(s,r+4,a,r+4,b,t,BLUE,WHITE,True)
rows=[
('项目启动前','营养/食安/采购分别采集网络、服务器、国产化、部署、小程序、支付/接口、规模和初始化数据。','逐项目填写答复并确认缺项；不同产品的网络/部署要求分别核实，不能直接套成所有项目共用条件。'),
('进场准备','服务器与小程序前置清单；410指示牌、流程易拉宝、Word/PDF手册、餐垫餐夹、替换餐盆与易损备件。','提前确认样式、Logo和更换方法；表内要求部分物料备3—5个，遥控器每项目备1个，按实际设备适用。'),
('实施与开餐','按交付前/中/后采集现场、部署调试、培训及真实就餐流程；改造项目同机位拍前后对比。','交付负责人收口；原图原视频归档，采完勾选；按现场许可采集，保留真实操作和培训画面。'),
('案例信息','单位名称/简介、场景、背景、服务内容、设备数量、规模人群、甲方效果反馈共7项。','项目启动后逐项填，交付完成后3个工作日内归档；效果数字须甲方认可。重庆、滨州继续补反馈。'),
('包装与复用','资料回传指定微盘；推广中心据此制作案例、图文与短视频。','交付实施部提供素材及项目情况；推广中心鲁洁收口包装与补拍需求。尚未证明所有项目已回传完整。')]
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='本次两份在线表逐行读取。')
box(s,r+21,1,r+23,12,'下周建议验收：项目交付负责人逐项核对重庆、滨州的资料目录，补齐缺件与甲方反馈；推广中心确认哪些素材可用、哪些需补拍，并形成首批可复用案例包。',LIGHT,BLUE)
box(s,r+24,1,r+26,12,'需统一的执行口径：原表同时写“当日返图”和“最晚次日回传，全部不晚于验收后3个工作日”。建议以当日为日常目标、次日为最迟回传，验收后3个工作日做总归档；由交付与推广确认。',color=ORANGE,source='使用说明第5、7、9、26行；核心信息表标题。此为建议，未修改源表。')

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':10,'presales_summary_themes':4,'presales_reference_rows':13,'presales_primary_records_reviewed':33,'product_state':'政企营养、学校营养：设计完成，开发中；依据用户9/19更正','sha256':hashlib.sha256(out.read_bytes()).hexdigest(),'bytes':out.stat().st_size}
(HERE/'summary-validation.json').write_text(json.dumps(receipt,ensure_ascii=False,indent=2)+'\n')
print(json.dumps(receipt,ensure_ascii=False,indent=2))
