generate_uat_report_all.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. """
  2. 生成 S1-S8 综合 UAT 测试报告
  3. """
  4. from openpyxl import Workbook
  5. from openpyxl.styles import Font, Alignment, Border, Side, PatternFill
  6. from openpyxl.utils import get_column_letter
  7. wb = Workbook()
  8. # ── 样式 ──
  9. thin = Border(left=Side('thin'), right=Side('thin'), top=Side('thin'), bottom=Side('thin'))
  10. hf = Font(name='微软雅黑', size=11, bold=True)
  11. tf = Font(name='微软雅黑', size=14, bold=True)
  12. nf = Font(name='微软雅黑', size=10)
  13. sf = Font(name='微软雅黑', size=9)
  14. ca = Alignment(horizontal='center', vertical='center', wrap_text=True)
  15. la = Alignment(horizontal='left', vertical='center', wrap_text=True)
  16. hfill = PatternFill(start_color='D9E1F2', end_color='D9E1F2', fill_type='solid')
  17. lfill = PatternFill(start_color='F2F2F2', end_color='F2F2F2', fill_type='solid')
  18. yfill = PatternFill(start_color='FFF2CC', end_color='FFF2CC', fill_type='solid')
  19. def wm(ws, r, cs, ce, v, font=nf, align=ca, fill=None):
  20. if cs != ce:
  21. ws.merge_cells(start_row=r, start_column=cs, end_row=r, end_column=ce)
  22. c = ws.cell(row=r, column=cs, value=v)
  23. c.font = font; c.alignment = align
  24. if fill: c.fill = fill
  25. for x in range(cs, ce+1):
  26. ws.cell(row=r, column=x).border = thin
  27. if fill: ws.cell(row=r, column=x).fill = fill
  28. def ab(ws, r, cs, ce):
  29. for x in range(cs, ce+1): ws.cell(row=r, column=x).border = thin
  30. # ── 场景定义: (用例编号, 测试内容, 测试步骤, 系统功能, 预期结果) ──
  31. modules = [
  32. ("S1产销协同", [
  33. ("产品设计", [
  34. ("产品设计列表查询", "1.进入产品设计菜单\n2.输入产品编码/名称查询\n3.点击重置", "列表查询", "可按编码、名称筛选,显示单据号、产品信息、状态"),
  35. ("新建产品设计-BOM自动填充", "1.点击新建\n2.选择产品编码\n3.观察BOM和工艺子表", "自动填充", "选择产品后BOM子表自动填入物料清单,工艺子表自动填入工序"),
  36. ("产品设计保存与编辑", "1.填写完整信息后保存\n2.选择记录点击编辑\n3.修改后保存", "增删改", "保存后列表刷新;编辑后字段正确更新;删除后记录移除"),
  37. ]),
  38. ("合同评审", [
  39. ("合同评审列表查询", "1.进入合同评审菜单\n2.输入合同号/客户查询", "列表查询", "可按合同号、客户、日期筛选,显示状态、创建时间等"),
  40. ("合同评审新增与提交审批", "1.点击新增\n2.填写合同信息\n3.保存后提交审批", "新增+审批", "保存成功;提交后状态变为审批中,审批流自动创建"),
  41. ("合同评审编辑与删除", "1.选择记录编辑修改后保存\n2.选择未审批记录删除", "编辑/删除", "编辑后字段正确更新;已审批记录不可删除"),
  42. ]),
  43. ("订单评审", [
  44. ("订单评审列表查询", "1.进入订单评审\n2.输入订单号/客户查询", "列表查询", "可按订单号、客户、状态筛选,显示审批进度标签"),
  45. ("订单评审新增与变更", "1.新增订单评审并保存\n2.对已审批订单发起变更\n3.修改内容后保存", "新增+变更", "保存成功;变更后变更次数+1,审批流重新发起"),
  46. ("订单评审-交期确认", "1.选择审批完成的订单\n2.点击交期确认\n3.确认操作", "交期确认", "确认后订单状态更新"),
  47. ]),
  48. ("订单交付与发货", [
  49. ("订单交付列表查询", "1.进入订单交付菜单\n2.按状态筛选", "列表查询", "显示交付状态(待交付/部分/已交付),筛选条件生效"),
  50. ("订单发货新增", "1.点击新增\n2.选择销售单号\n3.填写发货信息\n4.保存", "新增发货", "销售单号下拉搜索回显正确;保存后发货单号自动生成"),
  51. ("发货单编辑与删除", "1.编辑修改后保存\n2.删除未发货单据", "编辑/删除", "编辑后字段更新;已发货单据不可删除"),
  52. ]),
  53. ("工单下达与计划联动", [
  54. ("工单下达操作", "1.勾选待下达工单\n2.点击下达\n3.确认", "工单下达", "下达后状态变更,不可重复下达,MES可见"),
  55. ("计划联动看板查询", "1.进入计划联动看板\n2.按计划编号查询", "列表查询", "显示联动计划列表,来源和目标关系正确"),
  56. ]),
  57. ]),
  58. ("S2制造协同", [
  59. ("生产排程", [
  60. ("排程列表查询", "1.进入生产排程菜单\n2.按工单号/产线/日期查询", "列表查询", "可按工单号、产线、日期筛选,显示排产状态"),
  61. ("执行排产操作", "1.选择待排产工单\n2.点击排产按钮\n3.确认", "排产执行", "排产完成后工单状态更新,排产结果写入"),
  62. ("订单生产排程看板", "1.进入订单排程看板\n2.查看甘特图展示", "甘特图", "按工单维度显示甘特图,包含时间轴、产线、状态"),
  63. ("产线生产排程看板", "1.进入产线排程看板\n2.查看甘特图展示", "甘特图", "按产线维度显示甘特图,设备占用信息正确"),
  64. ]),
  65. ("可执行日计划", [
  66. ("可执行日计划查询", "1.进入可执行日计划\n2.按日期/产线筛选", "列表查询", "显示当日可执行工单,状态过滤正确"),
  67. ("日计划状态操作", "1.选择日计划记录\n2.执行状态变更操作", "状态管理", "状态正确流转,不可跳过中间状态"),
  68. ]),
  69. ("排产基础配置", [
  70. ("产线工作日历管理", "1.进入工作日历\n2.查看/编辑日历", "日历管理", "显示各产线工作日历,编辑后保存正确"),
  71. ("产线节假日管理", "1.进入节假日管理\n2.新增/编辑节假日", "节假日", "节假日设置正确,排产时自动跳过"),
  72. ]),
  73. ("工单执行看板", [
  74. ("工单执行进度看板", "1.进入工单进度看板\n2.观察进度数据", "进度看板", "显示各工单完成进度百分比,数据实时更新"),
  75. ("工单执行追踪", "1.进入工单追踪\n2.查看工单物料/工序明细", "工单追踪", "显示工单物料明细和工序明细,数据关联正确"),
  76. ]),
  77. ]),
  78. ("S3供应协同", [
  79. ("物料需求与采购", [
  80. ("物料需求计划查询", "1.进入物料需求计划\n2.按物料/日期查询", "列表查询", "显示物料需求清单,需求量、在途量、缺口量正确"),
  81. ("物料采购申请新增", "1.点击新增采购申请\n2.选择物料\n3.填写数量/交期\n4.保存", "新增申请", "保存成功,申请编号自动生成,审批流发起"),
  82. ("物料采购订单查询", "1.进入采购订单\n2.按订单号/供应商查询", "列表查询", "显示采购订单列表,状态、供应商信息正确"),
  83. ]),
  84. ("要货令与交货", [
  85. ("要货令新增", "1.点击新增要货令\n2.选择采购订单\n3.填写要求信息\n4.保存", "新增要货令", "保存成功,关联采购订单正确"),
  86. ("物料交货计划查询", "1.进入交货计划\n2.按供应商/物料查询", "列表查询", "显示交货计划列表,计划/实际数量对比"),
  87. ("交货单异常记录", "1.进入交货异常\n2.查看异常记录", "异常记录", "显示交货延迟、数量偏差等异常记录"),
  88. ]),
  89. ("委外加工", [
  90. ("委外加工订单管理", "1.进入委外订单\n2.新增/编辑委外订单", "委外管理", "保存成功,BOM自动填充,状态流转正确"),
  91. ("工序外协订单管理", "1.进入工序外协\n2.新增/编辑外协订单", "外协管理", "保存成功,工序信息关联正确"),
  92. ]),
  93. ("看板与齐套", [
  94. ("供应协同看板", "1.进入S3看板\n2.查看指标卡片", "看板展示", "显示采购相关KPI指标"),
  95. ("齐套看板", "1.进入齐套看板\n2.查看物料齐套状态", "齐套展示", "显示工单物料齐套率,缺料项高亮"),
  96. ]),
  97. ]),
  98. ("S4采购执行", [
  99. ("供应商交货管理", [
  100. ("供应商交货列表查询", "1.进入供应商交货管理\n2.按供应商/物料查询", "列表查询", "显示交货计划列表,支持发布操作"),
  101. ("供应商交期回复", "1.查看供应商回复的交期\n2.确认交期", "交期回复", "供应商回复后数据正确显示,确认操作生效"),
  102. ]),
  103. ("供应商发货单", [
  104. ("供应商发货单新增", "1.点击新增\n2.选择供应商\n3.填写发货信息\n4.保存", "新增发货", "保存成功,编号自动生成,物料明细正确"),
  105. ("发货单编辑与删除", "1.编辑修改后保存\n2.删除草稿状态单据", "编辑/删除", "编辑后字段更新;已提交单据不可删除"),
  106. ("发货单打印标签", "1.选择发货单\n2.点击打印标签", "标签打印", "标签数据正确生成,包含物料/数量/批次信息"),
  107. ]),
  108. ("采购退货与IQC", [
  109. ("采购退货单管理", "1.新增退货单\n2.选择收货单\n3.填写退货信息\n4.保存", "退货管理", "保存成功,关联收货单正确,退货数量校验通过"),
  110. ("IQC退货查询", "1.进入IQC退货\n2.按检验单/物料查询", "IQC查询", "显示IQC检验记录,不合格判定数据正确"),
  111. ]),
  112. ("供应商欠料看板", [
  113. ("欠料看板列表查询", "1.进入欠料看板\n2.按物料/供应商查询", "列表查询", "显示D0-D14欠料明细,供应商/物料信息正确"),
  114. ("欠料看板刷新", "1.点击刷新按钮\n2.观察数据更新", "数据刷新", "刷新后数据从WorkOrdDetailTotalKB重新加载"),
  115. ("生成催料待办", "1.点击生成催料待办按钮\n2.观察提示", "生成待办", "创建快照记录并自动发起审批流,提示信息正确"),
  116. ("审批中心查看欠料信息", "1.进入审批中心\n2.找到催料待办\n3.点击查看欠料信息", "欠料快照", "弹窗显示待办基本信息和欠料列表快照表格"),
  117. ("催料待办审批", "1.在待办中点击同意/拒绝\n2.填写意见\n3.确认", "审批操作", "审批完成后状态变更,从待办移至已办"),
  118. ]),
  119. ]),
  120. ("S5物料仓储", [
  121. ("来料检验", [
  122. ("IQC检验任务列表", "1.进入IQC任务列表\n2.查看待检任务", "任务列表", "显示待检来料任务,物料/供应商/数量信息正确"),
  123. ("IQC检验录入", "1.选择检验任务\n2.录入检验结果\n3.提交", "检验录入", "检验数据保存正确,判定结果自动生成"),
  124. ("IQC检验结果查询", "1.进入检验结果列表\n2.按物料/日期查询", "结果查询", "显示历史检验记录,合格率统计正确"),
  125. ]),
  126. ("仓库单据", [
  127. ("采购收货单管理", "1.进入采购收货\n2.新增/编辑收货单", "收货管理", "保存成功,关联采购订单,数量校验通过"),
  128. ("生产领料单管理", "1.进入生产领料\n2.新增领料单\n3.填写物料明细", "领料管理", "保存成功,关联工单,库存扣减正确"),
  129. ("生产退料单管理", "1.进入生产退料\n2.新增退料单", "退料管理", "保存成功,退料数量不超过已领数量"),
  130. ("生产入库单管理", "1.进入生产入库\n2.新增入库单", "入库管理", "保存成功,库存增加,批次号正确"),
  131. ]),
  132. ("库存查询", [
  133. ("库存查询", "1.进入库存查询\n2.按物料/库位查询", "库存查询", "显示实时库存数量,支持多维度筛选"),
  134. ("进出存查询", "1.进入进出存查询\n2.按日期范围查询", "进出存", "显示进/出/存三期数据,合计正确"),
  135. ("暂收在检列表", "1.进入暂收在检\n2.查看在检物料", "暂收在检", "显示IQC检验中的物料列表"),
  136. ]),
  137. ("盘点管理", [
  138. ("盘点标签确认", "1.进入盘点标签确认\n2.确认/驳回标签", "标签确认", "确认后标签状态变更,数据正确"),
  139. ("盘点结果查询", "1.进入盘点结果\n2.查看盈亏情况", "盘点结果", "显示盘点盈亏数据,差异分析正确"),
  140. ]),
  141. ]),
  142. ("S6生产执行", [
  143. ("生产指令与质检", [
  144. ("生产指令单查询", "1.进入生产指令单\n2.按工单号/日期查询", "指令单", "显示生产指令列表,工单/产线/数量信息正确"),
  145. ("过程检验单管理", "1.进入过程检验\n2.查看/录入检验数据", "过程检验", "检验数据保存正确,IPQC流程完整"),
  146. ]),
  147. ("设备与模工具", [
  148. ("生产设备台账", "1.进入设备台账\n2.查看设备列表\n3.新增/编辑设备", "设备管理", "设备信息完整(编号、名称、状态、产线)"),
  149. ("模工具台账管理", "1.进入模工具台账\n2.查看/管理模工具", "模工具", "模工具信息完整,状态流转正确"),
  150. ]),
  151. ("生产执行看板", [
  152. ("工单执行看板", "1.进入工单执行看板\n2.查看执行状态", "执行看板", "显示各工单实时执行进度"),
  153. ("车间效率看板", "1.进入效率看板\n2.查看效率指标", "效率看板", "显示产线效率、设备利用率等指标"),
  154. ]),
  155. ]),
  156. ("S7成品仓储", [
  157. ("FQC检验", [
  158. ("FQC检验任务列表", "1.进入FQC任务列表\n2.查看待检任务", "任务列表", "显示FQC待检任务,产品信息正确"),
  159. ("FQC检验录入", "1.选择检验任务\n2.录入检验结果\n3.提交审核", "检验录入", "检验数据保存正确,审批流触发"),
  160. ("FQC检验结果查询", "1.进入检验结果\n2.按产品/日期查询", "结果查询", "显示历史FQC检验记录"),
  161. ("成品报检", "1.进入成品报检\n2.新增报检申请", "成品报检", "保存成功,自动生成检验任务"),
  162. ]),
  163. ("成品入库与发货", [
  164. ("生产入库单管理", "1.进入生产入库\n2.新增入库单\n3.填写入库信息", "入库管理", "保存成功,库存增加,批次追溯正确"),
  165. ("销售发货通知", "1.进入发货通知\n2.查看/处理发货通知", "发货通知", "显示待发货通知列表,处理流程正确"),
  166. ]),
  167. ("成品仓储看板", [
  168. ("发货任务看板", "1.进入发货任务看板\n2.查看任务状态", "发货看板", "显示待发货/已发货任务,状态正确"),
  169. ("成品滞销看板", "1.进入滞销看板\n2.查看滞销产品", "滞销看板", "显示库龄超标的成品列表"),
  170. ]),
  171. ]),
  172. ("S8异常监控", [
  173. ("异常看板与大屏", [
  174. ("异常监控看板", "1.进入S8看板\n2.查看异常统计", "异常看板", "显示异常数量、分类、趋势统计"),
  175. ("交付异常大屏", "1.进入交付异常大屏\n2.查看异常数据", "交付大屏", "显示交付延迟、偏差等异常指标"),
  176. ("生产异常大屏", "1.进入生产异常大屏\n2.查看异常数据", "生产大屏", "显示排产异常、设备故障等指标"),
  177. ("供应异常大屏", "1.进入供应异常大屏\n2.查看异常数据", "供应大屏", "显示供应延迟、欠料等异常指标"),
  178. ]),
  179. ("异常管理", [
  180. ("异常列表查询", "1.进入异常列表\n2.按类型/日期查询", "异常列表", "显示异常记录列表,分类/状态/影响范围正确"),
  181. ("主动提报异常", "1.点击主动提报\n2.填写异常信息\n3.提交", "主动提报", "保存成功,异常自动分配处理人"),
  182. ("异常任务处理", "1.在待办中打开异常任务\n2.填写处理方案\n3.提交", "任务处理", "处理后任务状态更新,处理记录保存"),
  183. ]),
  184. ("订单追踪", [
  185. ("订单执行档案", "1.进入订单执行档案\n2.搜索订单号\n3.查看执行详情", "订单档案", "显示订单全生命周期执行数据"),
  186. ("订单链路全景", "1.进入订单链路\n2.查看全链路\n3.点击节点查看详情", "链路全景", "显示订单从评审→排产→采购→交付的全链路视图"),
  187. ]),
  188. ("配置管理", [
  189. ("场景配置管理", "1.进入场景配置\n2.新增/编辑场景\n3.保存", "场景配置", "保存成功,场景规则生效"),
  190. ("报警规则配置", "1.进入报警规则\n2.配置阈值和通知\n3.保存", "报警规则", "保存成功,规则触发时自动生成异常"),
  191. ]),
  192. ]),
  193. ]
  194. # ═══════════════════════════════════════════
  195. # Sheet 0: 目录
  196. # ═══════════════════════════════════════════
  197. ws_dir = wb.active
  198. ws_dir.title = "目录"
  199. for i, w in enumerate([6, 20, 20, 18, 18, 18], 1):
  200. ws_dir.column_dimensions[get_column_letter(i)].width = w
  201. row = 1
  202. wm(ws_dir, row, 1, 6, "AiDOP系统 UAT 测试报告", tf, ca)
  203. row += 1
  204. wm(ws_dir, row, 1, 6, "S1-S8 全模块综合测试", hf, ca)
  205. row += 2
  206. dh = ["序号", "模块名称", "测试场景数", "用例总数", "计划完成时间", "责任人"]
  207. for ci, h in enumerate(dh, 1):
  208. ws_dir.cell(row=row, column=ci, value=h).font = hf
  209. ws_dir.cell(row=row, column=ci).alignment = ca
  210. ws_dir.cell(row=row, column=ci).fill = hfill
  211. ab(ws_dir, row, ci, ci)
  212. row += 1
  213. for idx, (mname, cats) in enumerate(modules, 1):
  214. total_cases = sum(len(cs) for _, cs in cats)
  215. wm(ws_dir, row, 1, 1, str(idx), nf, ca)
  216. wm(ws_dir, row, 2, 2, mname, nf, ca)
  217. wm(ws_dir, row, 3, 3, str(len(cats)), nf, ca)
  218. wm(ws_dir, row, 4, 4, str(total_cases), nf, ca)
  219. wm(ws_dir, row, 5, 5, "", nf, ca)
  220. wm(ws_dir, row, 6, 6, "", nf, ca)
  221. row += 1
  222. # 汇总
  223. total_scenarios = sum(len(cats) for _, cats in modules)
  224. total_cases_all = sum(sum(len(cs) for _, cs in cats) for _, cats in modules)
  225. row += 1
  226. wm(ws_dir, row, 1, 2, "合计", hf, ca, yfill)
  227. wm(ws_dir, row, 3, 3, str(total_scenarios), hf, ca, yfill)
  228. wm(ws_dir, row, 4, 4, str(total_cases_all), hf, ca, yfill)
  229. wm(ws_dir, row, 5, 6, "", nf, ca, yfill)
  230. row += 2
  231. info = [
  232. "图例说明:",
  233. "Y : 实际结果与预期结果一致",
  234. "H : 严重缺陷(系统崩溃/数据错误影响其他流程)",
  235. "M : 中等缺陷(功能可用但有错误/不影响其他流程)",
  236. "L : 低程度缺陷(界面/提示/帮助文档问题)",
  237. "- : 不属于本次测试范围",
  238. ]
  239. for line in info:
  240. wm(ws_dir, row, 1, 6, line, sf, la)
  241. row += 1
  242. row += 1
  243. for line in ["测试账号:", "Web地址:", "账号: 密码:", "库存组织:"]:
  244. wm(ws_dir, row, 1, 6, line, sf, la)
  245. row += 1
  246. row += 1
  247. wm(ws_dir, row, 1, 3, "测试人姓名:", sf, ca)
  248. wm(ws_dir, row, 4, 6, "负责顾问:", sf, ca)
  249. # ═══════════════════════════════════════════
  250. # 各模块 Sheet
  251. # ═══════════════════════════════════════════
  252. for midx, (mname, cats) in enumerate(modules, 1):
  253. ws = wb.create_sheet(title=f"{midx} {mname}")
  254. widths = [8, 8, 20, 20, 20, 20, 14, 14, 24, 10, 10, 12]
  255. for i, w in enumerate(widths, 1):
  256. ws.column_dimensions[get_column_letter(i)].width = w
  257. row = 1
  258. # 标题行
  259. wm(ws, row, 1, 8, "详细测试结果", hf, ca, hfill)
  260. wm(ws, row, 9, 9, "第一轮测试", hf, ca, hfill)
  261. wm(ws, row, 10, 11, "第二轮测试", hf, ca, hfill)
  262. wm(ws, row, 12, 12, "测试内容", hf, ca, hfill)
  263. row += 1
  264. # 计数行
  265. wm(ws, row, 1, 8, "计数", nf, ca, lfill)
  266. wm(ws, row, 9, 9, "第一轮", nf, ca, lfill)
  267. wm(ws, row, 10, 11, "第二轮", nf, ca, lfill)
  268. total_c = sum(len(cs) for _, cs in cats)
  269. wm(ws, row, 12, 12, f"{mname}({total_c}例)", nf, ca, yfill)
  270. row += 1
  271. # 测试人/日期
  272. wm(ws, row, 1, 8, "测试人", nf, ca)
  273. for cs2, ce2 in [(9,9),(10,11),(12,12)]:
  274. wm(ws, row, cs2, ce2, "", nf, ca)
  275. row += 1
  276. wm(ws, row, 1, 8, "测试日期", nf, ca)
  277. for cs2, ce2 in [(9,9),(10,11),(12,12)]:
  278. wm(ws, row, cs2, ce2, "", nf, ca)
  279. row += 1
  280. # 缺陷统计行
  281. for dlbl, dval in [("缺陷","高(H)"),("缺陷","中(M)"),("缺陷","低(L)")]:
  282. wm(ws, row, 1, 8, dlbl, nf, ca)
  283. wm(ws, row, 9, 9, dval, nf, ca)
  284. wm(ws, row, 10, 11, dval, nf, ca)
  285. wm(ws, row, 12, 12, "", nf, ca)
  286. row += 1
  287. # 空行
  288. wm(ws, row, 1, 12, "", nf, ca)
  289. row += 1
  290. # 表头行
  291. hdr = [(1,1,"用例编号"),(2,3,"测试内容"),(4,6,"测试步骤"),(7,8,"系统功能"),
  292. (9,9,"预期结果"),(10,10,"测试结果\n1st"),(11,11,"测试结果\n2nd"),(12,12,"角色")]
  293. for cs2, ce2, htxt in hdr:
  294. wm(ws, row, cs2, ce2, htxt, hf, ca, hfill)
  295. row += 1
  296. # 用例数据
  297. case_seq = 1
  298. for cname, cases in cats:
  299. # 分类标题行
  300. wm(ws, row, 1, 12, f"▸ {cname}", hf, la, lfill)
  301. row += 1
  302. for content, steps, func, expected in cases:
  303. cid = f"{midx}.{case_seq}"
  304. wm(ws, row, 1, 1, cid, nf, ca)
  305. wm(ws, row, 2, 3, content, nf, la)
  306. wm(ws, row, 4, 6, steps, nf, la)
  307. wm(ws, row, 7, 8, func, nf, ca)
  308. wm(ws, row, 9, 9, expected, nf, la)
  309. ws.cell(row=row, column=10, value="Y").font = nf
  310. ws.cell(row=row, column=10).alignment = ca
  311. ws.cell(row=row, column=10).border = thin
  312. ws.cell(row=row, column=11).font = nf
  313. ws.cell(row=row, column=11).alignment = ca
  314. ws.cell(row=row, column=11).border = thin
  315. wm(ws, row, 12, 12, "操作员", nf, ca)
  316. ws.row_dimensions[row].height = max(40, steps.count('\n') * 14 + 28)
  317. row += 1
  318. case_seq += 1
  319. # 图例行
  320. row += 1
  321. for line in ["Y : 一致", "H : 严重缺陷", "M : 中等缺陷", "L : 低程度缺陷", "- : 不在范围"]:
  322. wm(ws, row, 1, 8, line, sf, la)
  323. row += 1
  324. # ── 保存 ──
  325. out = r"d:\DEMONET\doc\UAT测试报告.xlsx"
  326. wb.save(out)
  327. print(f"✅ 已生成: {out} ({total_scenarios}场景 / {total_cases_all}用例)")