本文详解如何基于原始数据动态构建结构严谨的矩阵表格:按 process 分组、按 date 列横向展开,正确处理 pareto/fail 多值合并与 rowspan 布局,避免列溢出和单元格错位。
本文详解如何基于原始数据动态构建结构严谨的矩阵表格:按 process 分组、按 date 列横向展开,正确处理 pareto/fail 多值合并与 rowspan 布局,避免列溢出和单元格错位。
在质量分析或制程看板场景中,常需将离散的工序(Process)与时间(DATE)交叉组织为矩阵视图——即每行代表一个 Process,每列代表一个日期,每个“单元格”内再细分为 Qty、FPY、RTY、Pareto、Fail 五个子列。但原始代码存在两个关键缺陷:一是 document.write 导致 DOM 写入失控,引发右侧列延伸溢出;二是 rowspan="5" 的粗暴复用导致 Pareto/Fail 行无法独立填充多条记录(如 ESS 在 29 Nov 有两条 Pareto),原逻辑仅在首行渲染全部值,其余四行为空白,破坏表格语义与可读性。
核心修复思路:
- ✅ 弃用 document.write:改用标准 DOM API(createElement, insertRow, insertCell)确保渲染可控;
- ✅ 按“子行”逐层构建:不再对 Qty/FPY/RTY 统一设 rowspan=5,而是为每个 Process + Date 组合生成 5 行(对应 5 个指标),其中仅 Qty/FPY/RTY 行在无数据时留空,而 Pareto/Fail 行逐条展开(即一行一值),真正实现“一值一行”;
- ✅ 精准计算列数:表头
与数据行 数量严格匹配,避免列宽错乱; - ✅ Pareto/Fail 多值分隔优化:使用
替代默认逗号连接,提升可读性(如 Client BER Lane 12
Client BER)。以下是完整、可直接运行的解决方案:
<style> table { border-collapse: collapse; width: 100%; } table, th, td { border: 1px solid #333; } th, td { padding: 8px 12px; text-align: left; vertical-align: top; } th { background-color: #f5f5f5; font-weight: bold; } </style><script> const data = [ { Process: 'PCAL', DATE: '29 Nov 2023', FPY: '0.0', QTY: '1', RTY: '0.0', Pareto: 'Client BER META 1 Serdes 142', Fail: '1' }, { Process: 'CAL', DATE: '28 Nov 2023', FPY: '100.0', QTY: '2', RTY: '100.0', Pareto: 'None', Fail: 'None' }, { Process: 'FVT', DATE: '28 Nov 2023', FPY: '50.0', QTY: '2', RTY: '50.0', Pareto: 'Client BER Lane 12', Fail: '3' }, { Process: 'FVT', DATE: '28 Nov 2023', FPY: '50.0', QTY: '2', RTY: '50.0', Pareto: 'Client BER', Fail: '1' }, { Process: 'ESS', DATE: '28 Nov 2023', FPY: '100.0', QTY: '1', RTY: '100.0', Pareto: 'None', Fail: 'None' }, { Process: 'ESS', DATE: '29 Nov 2023', FPY: '0.0', QTY: '1', RTY: '0.0', Pareto: 'Module Power', Fail: '4' }, { Process: 'ESS', DATE: '29 Nov 2023', FPY: '0.0', QTY: '1', RTY: '0.0', Pareto: 'Module A Power', Fail: '14' }, { Process: 'EXS', DATE: '30 Nov 2023', FPY: '100.0', QTY: '3', RTY: '100.0', Pareto: 'None', Fail: 'None' } ]; // 提取唯一 Process 和排序后 DATE const uniqueProcesses = [...new Set(data.map(d => d.Process))].sort(); const uniqueDates = [...new Set(data.map(d => d.DATE))].sort(); // 创建表格 const table = document.createElement('table'); const thead = table.createTHead(); const headerRow1 = thead.insertRow(); headerRow1.innerHTML = '<th rowspan="2">Process'; // 注意:此处应为 Process(非 DATE),符合业务逻辑 uniqueDates.forEach(date => { headerRow1.innerHTML += `<th colspan="5">${date}`; }); const headerRow2 = thead.insertRow(); for (let i = 0; i < uniqueDates.length; i++) { headerRow2.innerHTML += '<th>Qty<th>FPY<th>RTY<th>Pareto<th>Fail'; } // 构建 tbody const tbody = table.createTBody(); uniqueProcesses.forEach(process => { // 每个 Process 对应 5 行(Qty, FPY, RTY, Pareto, Fail) const rows = Array.from({ length: 5 }, () => tbody.insertRow()); // 第 1 列:Process 名称(仅首行显示,rowSpan=5) const procCell = rows[0].insertCell(0); procCell.innerHTML = process; procCell.rowSpan = 5; // 遍历每个日期列 uniqueDates.forEach(date => { const colOffset = 1 + (uniqueDates.indexOf(date) * 5); // 当前列起始索引(0-based) // 获取该 Process+Date 的所有数据 const matching = data.filter(d => d.Process === process && d.DATE === date); // Qty 行:取第一个匹配项(若存在),否则留空 const qtyCell = rows[0].insertCell(colOffset); qtyCell.innerHTML = matching.length ? matching[0].QTY : ''; // FPY 行 const fpyCell = rows[1].insertCell(colOffset); fpyCell.innerHTML = matching.length ? matching[0].FPY : ''; // RTY 行 const rtyCell = rows[2].insertCell(colOffset); rtyCell.innerHTML = matching.length ? matching[0].RTY : ''; // Pareto 行:逐条渲染,用 <br> 分隔 const paretoCell = rows[3].insertCell(colOffset); paretoCell.innerHTML = matching.length ? matching.map(d => d.Pareto).join('<br>') : ''; // Fail 行:同理 const failCell = rows[4].insertCell(colOffset); failCell.innerHTML = matching.length ? matching.map(d => d.Fail).join('<br>') : ''; }); }); document.body.appendChild(table); </script>关键注意事项:
- 表头第一列语义应为 Process(非 DATE),已修正,符合典型矩阵布局(Process 为行维度,DATE 为列维度);
- rowspan 仅用于 Process 列,其他指标均按 5 行独立渲染,彻底解决 Pareto/Fail 多值堆叠与空白行问题;
- 使用 vertical-align: top 确保多行文本对齐顶部,提升视觉一致性;
- 若需支持空数据占位符(如 -),可在 matching.length ? ... : '-' 中替换;
- 后续扩展建议:添加 CSS 类名便于主题定制、集成 sorttable 库支持列排序、导出为 Excel 等。
此方案兼顾语义正确性、视觉整洁性与工程健壮性,适用于生产环境的质量矩阵看板开发。
- ✅ Pareto/Fail 多值分隔优化:使用
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











