function generateMultiHeaderTable(options) {
const { headers, data, containerId } = options;
const container = document.getElementById(containerId);
if (!container) return;
const headerLevels = calculateHeaderLevels(headers);
const processedHeaders = processHeaders(headers, headerLevels);
const theadHtml = generateThead(processedHeaders, headerLevels);
const tbodyHtml = generateTbody(data, processedHeaders);
const tableHtml = `
<table border="1" cellpadding="8" cellspacing="0">
${theadHtml}
${tbodyHtml}
</table>
`;
container.innerHTML = tableHtml;
}
function calculateHeaderLevels(headers) {
let maxLevel = 1;
function traverse(header, currentLevel) {
if (currentLevel > maxLevel) {
maxLevel = currentLevel;
}
if (header.children && header.children.length) {
header.children.forEach(child => traverse(child, currentLevel + 1));
}
}
headers.forEach(header => traverse(header, 1));
return maxLevel;
}
function processHeaders(headers, totalLevels) {
const result = [];
function traverse(headers, currentLevel, parent) {
headers.forEach(header => {
header.level = currentLevel;
if (!header.children || !header.children.length) {
header.rowspan = totalLevels - currentLevel + 1;
header.colspan = 1;
result.push(header);
} else {
header.rowspan = 1;
header.colspan = countLeafNodes(header.children);
result.push(header);
traverse(header.children, currentLevel + 1, header);
}
});
}
traverse(headers, 1, null);
return result;
}
function countLeafNodes(headers) {
let count = 0;
function traverse(headers) {
headers.forEach(header => {
if (!header.children || !header.children.length) {
count++;
} else {
traverse(header.children);
}
});
}
traverse(headers);
return count;
}
function generateThead(headers, totalLevels) {
let thead = '<thead>';
for (let level = 1; level <= totalLevels; level++) {
const levelHeaders = headers.filter(header => header.level === level);
thead += '<tr>';
levelHeaders.forEach(header => {
thead += `<th rowspan="${header.rowspan}" colspan="${header.colspan}">${header.name}</th>`;
});
thead += '</tr>';
}
thead += '</thead>';
return thead;
}
function generateTbody(data, headers) {
const leafHeaders = headers.filter(header => !header.children || !header.children.length);
let tbody = '<tbody>';
data.forEach(row => {
tbody += '<tr>';
leafHeaders.forEach(header => {
tbody += `<td>${row[header.key] !== undefined ? row[header.key] : ''}</td>`;
});
tbody += '</tr>';
});
tbody += '</tbody>';
return tbody;
}
const headers = [
{
name: '日期',
key: 'date',
},
{
name: '产品A',
children: [
{ name: '销量', key: 'a_sales' },
{ name: '销售额', key: 'a_revenue' }
]
},
{
name: '产品B',
children: [
{ name: '销量', key: 'b_sales' },
{ name: '销售额', key: 'b_revenue' },
{
name: '增长率',
children: [
{ name: '周环比', key: 'b_week_growth' },
{ name: '月环比', key: 'b_month_growth' }
]
}
]
},
{
name: '总计',
key: 'total'
}
];
const tableData = [
{
date: '2023-01-01',
a_sales: 120,
a_revenue: 6000,
b_sales: 80,
b_revenue: 4000,
b_week_growth: '12%',
b_month_growth: '8%',
total: 10000
},
{
date: '2023-01-02',
a_sales: 150,
a_revenue: 7500,
b_sales: 95,
b_revenue: 4750,
b_week_growth: '8%',
b_month_growth: '5%',
total: 12250
}
];
window.onload = () => {
generateMultiHeaderTable({
headers: headers,
data: tableData,
containerId: 'tableContainer'
});
};