| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- const ExcelJS = require('exceljs');
- const wb = new ExcelJS.Workbook();
- // ── 样式工具 ──
- const hf = { name: '微软雅黑', size: 11, bold: true };
- const tf = { name: '微软雅黑', size: 14, bold: true };
- const nf = { name: '微软雅黑', size: 10 };
- const sf = { name: '微软雅黑', size: 9 };
- const ca = { horizontal: 'center', vertical: 'middle', wrapText: true };
- const la = { horizontal: 'left', vertical: 'middle', wrapText: true };
- const hfill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFD9E1F2' } };
- const lfill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF2F2F2' } };
- const yfill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFF2CC' } };
- const thinBorder = { top: { style: 'thin' }, bottom: { style: 'thin' }, left: { style: 'thin' }, right: { style: 'thin' } };
- function writeMerged(ws, row, colStart, colEnd, value, font = nf, alignment = ca, fill = null) {
- if (colStart !== colEnd) {
- ws.mergeCells(row, colStart, row, colEnd);
- }
- const cell = ws.getCell(row, colStart);
- cell.value = value;
- cell.font = font;
- cell.alignment = alignment;
- if (fill) cell.fill = fill;
- cell.border = thinBorder;
- for (let c = colStart; c <= colEnd; c++) {
- const cc = ws.getCell(row, c);
- cc.border = thinBorder;
- if (fill) cc.fill = fill;
- }
- }
- // ── 模块数据 ──
- const modules = [
- ["S1产销协同", [
- ["产品设计", [
- ["产品设计列表查询", "1.进入产品设计菜单\n2.输入产品编码/名称查询\n3.点击重置", "列表查询", "可按编码、名称筛选,显示单据号、产品信息、状态"],
- ["新建产品设计-BOM自动填充", "1.点击新建\n2.选择产品编码\n3.观察BOM和工艺子表", "自动填充", "选择产品后BOM子表自动填入物料清单,工艺子表自动填入工序"],
- ["产品设计保存与编辑", "1.填写完整信息后保存\n2.选择记录点击编辑\n3.修改后保存", "增删改", "保存后列表刷新;编辑后字段正确更新;删除后记录移除"],
- ]],
- ["合同评审", [
- ["合同评审列表查询", "1.进入合同评审菜单\n2.输入合同号/客户查询", "列表查询", "可按合同号、客户、日期筛选,显示状态、创建时间等"],
- ["合同评审新增与提交审批", "1.点击新增\n2.填写合同信息\n3.保存后提交审批", "新增+审批", "保存成功;提交后状态变为审批中,审批流自动创建"],
- ["合同评审编辑与删除", "1.选择记录编辑修改后保存\n2.选择未审批记录删除", "编辑/删除", "编辑后字段正确更新;已审批记录不可删除"],
- ]],
- ["订单评审", [
- ["订单评审列表查询", "1.进入订单评审\n2.输入订单号/客户查询", "列表查询", "可按订单号、客户、状态筛选,显示审批进度标签"],
- ["订单评审新增与变更", "1.新增订单评审并保存\n2.对已审批订单发起变更\n3.修改内容后保存", "新增+变更", "保存成功;变更后变更次数+1,审批流重新发起"],
- ["订单评审-交期确认", "1.选择审批完成的订单\n2.点击交期确认\n3.确认操作", "交期确认", "确认后订单状态更新"],
- ]],
- ["订单交付与发货", [
- ["订单交付列表查询", "1.进入订单交付菜单\n2.按状态筛选", "列表查询", "显示交付状态(待交付/部分/已交付),筛选条件生效"],
- ["订单发货新增", "1.点击新增\n2.选择销售单号\n3.填写发货信息\n4.保存", "新增发货", "销售单号下拉搜索回显正确;保存后发货单号自动生成"],
- ["发货单编辑与删除", "1.编辑修改后保存\n2.删除未发货单据", "编辑/删除", "编辑后字段更新;已发货单据不可删除"],
- ]],
- ["工单下达与计划联动", [
- ["工单下达操作", "1.勾选待下达工单\n2.点击下达\n3.确认", "工单下达", "下达后状态变更,不可重复下达,MES可见"],
- ["计划联动看板查询", "1.进入计划联动看板\n2.按计划编号查询", "列表查询", "显示联动计划列表,来源和目标关系正确"],
- ]],
- ]],
- ["S2制造协同", [
- ["生产排程", [
- ["排程列表查询", "1.进入生产排程菜单\n2.按工单号/产线/日期查询", "列表查询", "可按工单号、产线、日期筛选,显示排产状态"],
- ["执行排产操作", "1.选择待排产工单\n2.点击排产按钮\n3.确认", "排产执行", "排产完成后工单状态更新,排产结果写入"],
- ["订单生产排程看板", "1.进入订单排程看板\n2.查看甘特图展示", "甘特图", "按工单维度显示甘特图,包含时间轴、产线、状态"],
- ["产线生产排程看板", "1.进入产线排程看板\n2.查看甘特图展示", "甘特图", "按产线维度显示甘特图,设备占用信息正确"],
- ]],
- ["可执行日计划", [
- ["可执行日计划查询", "1.进入可执行日计划\n2.按日期/产线筛选", "列表查询", "显示当日可执行工单,状态过滤正确"],
- ["日计划状态操作", "1.选择日计划记录\n2.执行状态变更操作", "状态管理", "状态正确流转,不可跳过中间状态"],
- ]],
- ["排产基础配置", [
- ["产线工作日历管理", "1.进入工作日历\n2.查看/编辑日历", "日历管理", "显示各产线工作日历,编辑后保存正确"],
- ["产线节假日管理", "1.进入节假日管理\n2.新增/编辑节假日", "节假日", "节假日设置正确,排产时自动跳过"],
- ]],
- ["工单执行看板", [
- ["工单执行进度看板", "1.进入工单进度看板\n2.观察进度数据", "进度看板", "显示各工单完成进度百分比,数据实时更新"],
- ["工单执行追踪", "1.进入工单追踪\n2.查看工单物料/工序明细", "工单追踪", "显示工单物料明细和工序明细,数据关联正确"],
- ]],
- ]],
- ["S3供应协同", [
- ["物料需求与采购", [
- ["物料需求计划查询", "1.进入物料需求计划\n2.按物料/日期查询", "列表查询", "显示物料需求清单,需求量、在途量、缺口量正确"],
- ["物料采购申请新增", "1.点击新增采购申请\n2.选择物料\n3.填写数量/交期\n4.保存", "新增申请", "保存成功,申请编号自动生成,审批流发起"],
- ["物料采购订单查询", "1.进入采购订单\n2.按订单号/供应商查询", "列表查询", "显示采购订单列表,状态、供应商信息正确"],
- ]],
- ["要货令与交货", [
- ["要货令新增", "1.点击新增要货令\n2.选择采购订单\n3.填写要求信息\n4.保存", "新增要货令", "保存成功,关联采购订单正确"],
- ["物料交货计划查询", "1.进入交货计划\n2.按供应商/物料查询", "列表查询", "显示交货计划列表,计划/实际数量对比"],
- ["交货单异常记录", "1.进入交货异常\n2.查看异常记录", "异常记录", "显示交货延迟、数量偏差等异常记录"],
- ]],
- ["委外加工", [
- ["委外加工订单管理", "1.进入委外订单\n2.新增/编辑委外订单", "委外管理", "保存成功,BOM自动填充,状态流转正确"],
- ["工序外协订单管理", "1.进入工序外协\n2.新增/编辑外协订单", "外协管理", "保存成功,工序信息关联正确"],
- ]],
- ["看板与齐套", [
- ["供应协同看板", "1.进入S3看板\n2.查看指标卡片", "看板展示", "显示采购相关KPI指标"],
- ["齐套看板", "1.进入齐套看板\n2.查看物料齐套状态", "齐套展示", "显示工单物料齐套率,缺料项高亮"],
- ]],
- ]],
- ["S4采购执行", [
- ["供应商交货管理", [
- ["供应商交货列表查询", "1.进入供应商交货管理\n2.按供应商/物料查询", "列表查询", "显示交货计划列表,支持发布操作"],
- ["供应商交期回复", "1.查看供应商回复的交期\n2.确认交期", "交期回复", "供应商回复后数据正确显示,确认操作生效"],
- ]],
- ["供应商发货单", [
- ["供应商发货单新增", "1.点击新增\n2.选择供应商\n3.填写发货信息\n4.保存", "新增发货", "保存成功,编号自动生成,物料明细正确"],
- ["发货单编辑与删除", "1.编辑修改后保存\n2.删除草稿状态单据", "编辑/删除", "编辑后字段更新;已提交单据不可删除"],
- ["发货单打印标签", "1.选择发货单\n2.点击打印标签", "标签打印", "标签数据正确生成,包含物料/数量/批次信息"],
- ]],
- ["采购退货与IQC", [
- ["采购退货单管理", "1.新增退货单\n2.选择收货单\n3.填写退货信息\n4.保存", "退货管理", "保存成功,关联收货单正确,退货数量校验通过"],
- ["IQC退货查询", "1.进入IQC退货\n2.按检验单/物料查询", "IQC查询", "显示IQC检验记录,不合格判定数据正确"],
- ]],
- ["供应商欠料看板", [
- ["欠料看板列表查询", "1.进入欠料看板\n2.按物料/供应商查询", "列表查询", "显示D0-D14欠料明细,供应商/物料信息正确"],
- ["欠料看板刷新", "1.点击刷新按钮\n2.观察数据更新", "数据刷新", "刷新后数据重新加载,显示最新欠料情况"],
- ["生成催料待办", "1.点击生成催料待办按钮\n2.观察提示", "生成待办", "创建快照记录并自动发起审批流"],
- ["审批中心查看欠料信息", "1.进入审批中心\n2.找到催料待办\n3.点击查看欠料信息", "欠料快照", "弹窗显示待办基本信息和欠料列表快照"],
- ["催料待办审批", "1.在待办中点击同意/拒绝\n2.填写意见\n3.确认", "审批操作", "审批完成后状态变更,从待办移至已办"],
- ]],
- ]],
- ["S5物料仓储", [
- ["来料检验", [
- ["IQC检验任务列表", "1.进入IQC任务列表\n2.查看待检任务", "任务列表", "显示待检来料任务,物料/供应商/数量信息正确"],
- ["IQC检验录入", "1.选择检验任务\n2.录入检验结果\n3.提交", "检验录入", "检验数据保存正确,判定结果自动生成"],
- ["IQC检验结果查询", "1.进入检验结果列表\n2.按物料/日期查询", "结果查询", "显示历史检验记录,合格率统计正确"],
- ]],
- ["仓库单据", [
- ["采购收货单管理", "1.进入采购收货\n2.新增/编辑收货单", "收货管理", "保存成功,关联采购订单,数量校验通过"],
- ["生产领料单管理", "1.进入生产领料\n2.新增领料单\n3.填写物料明细", "领料管理", "保存成功,关联工单,库存扣减正确"],
- ["生产退料单管理", "1.进入生产退料\n2.新增退料单", "退料管理", "保存成功,退料数量不超过已领数量"],
- ["生产入库单管理", "1.进入生产入库\n2.新增入库单", "入库管理", "保存成功,库存增加,批次号正确"],
- ]],
- ["库存查询", [
- ["库存查询", "1.进入库存查询\n2.按物料/库位查询", "库存查询", "显示实时库存数量,支持多维度筛选"],
- ["进出存查询", "1.进入进出存查询\n2.按日期范围查询", "进出存", "显示进/出/存三期数据,合计正确"],
- ["暂收在检列表", "1.进入暂收在检\n2.查看在检物料", "暂收在检", "显示IQC检验中的物料列表"],
- ]],
- ["盘点管理", [
- ["盘点标签确认", "1.进入盘点标签确认\n2.确认/驳回标签", "标签确认", "确认后标签状态变更,数据正确"],
- ["盘点结果查询", "1.进入盘点结果\n2.查看盈亏情况", "盘点结果", "显示盘点盈亏数据,差异分析正确"],
- ]],
- ]],
- ["S6生产执行", [
- ["生产指令与质检", [
- ["生产指令单查询", "1.进入生产指令单\n2.按工单号/日期查询", "指令单", "显示生产指令列表,工单/产线/数量信息正确"],
- ["过程检验单管理", "1.进入过程检验\n2.查看/录入检验数据", "过程检验", "检验数据保存正确,IPQC流程完整"],
- ]],
- ["设备与模工具", [
- ["生产设备台账", "1.进入设备台账\n2.查看设备列表\n3.新增/编辑设备", "设备管理", "设备信息完整(编号、名称、状态、产线)"],
- ["模工具台账管理", "1.进入模工具台账\n2.查看/管理模工具", "模工具", "模工具信息完整,状态流转正确"],
- ]],
- ["生产执行看板", [
- ["工单执行看板", "1.进入工单执行看板\n2.查看执行状态", "执行看板", "显示各工单实时执行进度"],
- ["车间效率看板", "1.进入效率看板\n2.查看效率指标", "效率看板", "显示产线效率、设备利用率等指标"],
- ]],
- ]],
- ["S7成品仓储", [
- ["FQC检验", [
- ["FQC检验任务列表", "1.进入FQC任务列表\n2.查看待检任务", "任务列表", "显示FQC待检任务,产品信息正确"],
- ["FQC检验录入", "1.选择检验任务\n2.录入检验结果\n3.提交审核", "检验录入", "检验数据保存正确,审批流触发"],
- ["FQC检验结果查询", "1.进入检验结果\n2.按产品/日期查询", "结果查询", "显示历史FQC检验记录"],
- ["成品报检", "1.进入成品报检\n2.新增报检申请", "成品报检", "保存成功,自动生成检验任务"],
- ]],
- ["成品入库与发货", [
- ["生产入库单管理", "1.进入生产入库\n2.新增入库单\n3.填写入库信息", "入库管理", "保存成功,库存增加,批次追溯正确"],
- ["销售发货通知", "1.进入发货通知\n2.查看/处理发货通知", "发货通知", "显示待发货通知列表,处理流程正确"],
- ]],
- ["成品仓储看板", [
- ["发货任务看板", "1.进入发货任务看板\n2.查看任务状态", "发货看板", "显示待发货/已发货任务,状态正确"],
- ["成品滞销看板", "1.进入滞销看板\n2.查看滞销产品", "滞销看板", "显示库龄超标的成品列表"],
- ]],
- ]],
- ["S8异常监控", [
- ["异常看板与大屏", [
- ["异常监控看板", "1.进入S8看板\n2.查看异常统计", "异常看板", "显示异常数量、分类、趋势统计"],
- ["交付异常大屏", "1.进入交付异常大屏\n2.查看异常数据", "交付大屏", "显示交付延迟、偏差等异常指标"],
- ["生产异常大屏", "1.进入生产异常大屏\n2.查看异常数据", "生产大屏", "显示排产异常、设备故障等指标"],
- ["供应异常大屏", "1.进入供应异常大屏\n2.查看异常数据", "供应大屏", "显示供应延迟、欠料等异常指标"],
- ]],
- ["异常管理", [
- ["异常列表查询", "1.进入异常列表\n2.按类型/日期查询", "异常列表", "显示异常记录列表,分类/状态/影响范围正确"],
- ["主动提报异常", "1.点击主动提报\n2.填写异常信息\n3.提交", "主动提报", "保存成功,异常自动分配处理人"],
- ["异常任务处理", "1.在待办中打开异常任务\n2.填写处理方案\n3.提交", "任务处理", "处理后任务状态更新,处理记录保存"],
- ]],
- ["订单追踪", [
- ["订单执行档案", "1.进入订单执行档案\n2.搜索订单号\n3.查看执行详情", "订单档案", "显示订单全生命周期执行数据"],
- ["订单链路全景", "1.进入订单链路\n2.查看全链路\n3.点击节点查看详情", "链路全景", "显示订单从评审→排产→采购→交付的全链路视图"],
- ]],
- ["配置管理", [
- ["场景配置管理", "1.进入场景配置\n2.新增/编辑场景\n3.保存", "场景配置", "保存成功,场景规则生效"],
- ["报警规则配置", "1.进入报警规则\n2.配置阈值和通知\n3.保存", "报警规则", "保存成功,规则触发时自动生成异常"],
- ]],
- ]],
- ];
- // ═══════════════════════════════════════════
- // Sheet 0: 目录
- // ═══════════════════════════════════════════
- const wsDir = wb.addWorksheet('目录');
- wsDir.columns = [{ width: 6 }, { width: 20 }, { width: 18 }, { width: 14 }, { width: 18 }, { width: 16 }];
- let row = 1;
- writeMerged(wsDir, row++, 1, 6, 'AiDOP系统 UAT 测试报告', tf, ca);
- writeMerged(wsDir, row++, 1, 6, 'S1-S8 全模块综合测试', hf, ca);
- row++;
- const dirHeaders = ['序号', '模块名称', '测试场景数', '用例总数', '计划完成时间', '责任人'];
- for (let ci = 0; ci < dirHeaders.length; ci++) {
- const cell = wsDir.getCell(row, ci + 1);
- cell.value = dirHeaders[ci]; cell.font = hf; cell.alignment = ca; cell.fill = hfill; cell.border = thinBorder;
- }
- row++;
- let totalScenarios = 0, totalCasesAll = 0;
- for (let idx = 0; idx < modules.length; idx++) {
- const [mname, cats] = modules[idx];
- const tc = cats.reduce((s, c) => s + c[1].length, 0);
- totalScenarios += cats.length;
- totalCasesAll += tc;
- writeMerged(wsDir, row, 1, 1, String(idx + 1), nf, ca);
- writeMerged(wsDir, row, 2, 2, mname, nf, ca);
- writeMerged(wsDir, row, 3, 3, String(cats.length), nf, ca);
- writeMerged(wsDir, row, 4, 4, String(tc), nf, ca);
- writeMerged(wsDir, row, 5, 5, '', nf, ca);
- writeMerged(wsDir, row, 6, 6, '', nf, ca);
- row++;
- }
- row++;
- writeMerged(wsDir, row, 1, 2, '合计', hf, ca, yfill);
- writeMerged(wsDir, row, 3, 3, String(totalScenarios), hf, ca, yfill);
- writeMerged(wsDir, row, 4, 4, String(totalCasesAll), hf, ca, yfill);
- writeMerged(wsDir, row, 5, 6, '', nf, ca, yfill);
- row += 2;
- ['图例说明:', 'Y : 实际结果与预期结果一致', 'H : 严重缺陷(系统崩溃/数据错误影响其他流程)',
- 'M : 中等缺陷(功能可用但有错误/不影响其他流程)', 'L : 低程度缺陷(界面/提示/帮助文档问题)',
- '- : 不属于本次测试范围'].forEach(l => { writeMerged(wsDir, row++, 1, 6, l, sf, la); });
- row += 2;
- ['测试账号:', 'Web地址:', '账号: 密码:', '库存组织:'].forEach(l => {
- writeMerged(wsDir, row++, 1, 6, l, sf, la);
- });
- row += 2;
- writeMerged(wsDir, row, 1, 3, '测试人姓名:', sf, ca);
- writeMerged(wsDir, row, 4, 6, '负责顾问:', sf, ca);
- // ═══════════════════════════════════════════
- // 各模块 Sheet
- // ═══════════════════════════════════════════
- for (let midx = 0; midx < modules.length; midx++) {
- const [mname, cats] = modules[midx];
- const ws = wb.addWorksheet(`${midx + 1} ${mname}`);
- ws.columns = [
- { width: 8 }, { width: 8 }, { width: 20 }, { width: 20 }, { width: 20 },
- { width: 20 }, { width: 14 }, { width: 14 }, { width: 24 },
- { width: 10 }, { width: 10 }, { width: 12 },
- ];
- let r = 1;
- // 顶部信息行
- writeMerged(ws, r++, 1, 8, '详细测试结果', hf, ca, hfill);
- writeMerged(ws, r - 1, 9, 9, '第一轮测试', hf, ca, hfill);
- writeMerged(ws, r - 1, 10, 11, '第二轮测试', hf, ca, hfill);
- writeMerged(ws, r - 1, 12, 12, '测试内容', hf, ca, hfill);
- writeMerged(ws, r++, 1, 8, '计数', nf, ca, lfill);
- const totalC = cats.reduce((s, c) => s + c[1].length, 0);
- writeMerged(ws, r - 1, 9, 9, '第一轮', nf, ca, lfill);
- writeMerged(ws, r - 1, 10, 11, '第二轮', nf, ca, lfill);
- writeMerged(ws, r - 1, 12, 12, `${mname}(${totalC}例)`, nf, ca, yfill);
- writeMerged(ws, r++, 1, 12, '测试人', nf, ca);
- writeMerged(ws, r++, 1, 12, '测试日期', nf, ca);
- ['高(H)', '中(M)', '低(L)'].forEach(dv => {
- writeMerged(ws, r++, 1, 8, '缺陷', nf, ca);
- writeMerged(ws, r - 1, 9, 9, dv, nf, ca);
- writeMerged(ws, r - 1, 10, 11, dv, nf, ca);
- writeMerged(ws, r - 1, 12, 12, '', nf, ca);
- });
- writeMerged(ws, r++, 1, 12, '', nf, ca);
- // 表头
- [[1,1,'用例编号'],[2,3,'测试内容'],[4,6,'测试步骤'],[7,8,'系统功能'],[9,9,'预期结果'],[10,10,'结果1st'],[11,11,'结果2nd'],[12,12,'角色']].forEach(([cs,ce,h]) => {
- writeMerged(ws, r, cs, ce, h, hf, ca, hfill);
- });
- r++;
- // 用例数据
- let caseSeq = 1;
- for (const [cname, cases] of cats) {
- writeMerged(ws, r++, 1, 12, `▸ ${cname}`, hf, la, lfill);
- for (const [content, steps, func, expected] of cases) {
- const cid = `${midx + 1}.${caseSeq}`;
- writeMerged(ws, r, 1, 1, cid, nf, ca);
- writeMerged(ws, r, 2, 3, content, nf, la);
- writeMerged(ws, r, 4, 6, steps, nf, la);
- writeMerged(ws, r, 7, 8, func, nf, ca);
- writeMerged(ws, r, 9, 9, expected, nf, la);
- const c10 = ws.getCell(r, 10); c10.value = 'Y'; c10.font = nf; c10.alignment = ca; c10.border = thinBorder;
- const c11 = ws.getCell(r, 11); c11.font = nf; c11.alignment = ca; c11.border = thinBorder;
- writeMerged(ws, r, 12, 12, '操作员', nf, ca);
- ws.getRow(r).height = Math.max(40, (steps.match(/\n/g) || []).length * 14 + 28);
- r++;
- caseSeq++;
- }
- }
- r++;
- ['Y : 一致', 'H : 严重缺陷', 'M : 中等缺陷', 'L : 低程度缺陷', '- : 不在范围'].forEach(l => {
- writeMerged(ws, r++, 1, 8, l, sf, la);
- });
- }
- // ── 保存 ──
- const outPath = 'd:\\DEMONET\\doc\\UAT测试报告.xlsx';
- wb.xlsx.writeFile(outPath).then(() => {
- console.log(`✅ 已生成: ${outPath} (${totalScenarios}场景 / ${totalCasesAll}用例)`);
- }).catch(err => {
- console.error('❌ 生成失败:', err.message);
- });
|