feat: split orders into base info table + channel x product matrix

This commit is contained in:
王源
2026-09-07 12:46:34 +08:00
parent f14a200a4c
commit 70bd03f3af
+80 -11
View File
@@ -403,8 +403,10 @@
<div class="tab-panel" id="tab-orders"> <div class="tab-panel" id="tab-orders">
<div class="order-stats" id="orderStats"></div> <div class="order-stats" id="orderStats"></div>
<div class="table-section">
<h2>Moboost广告投放</h2> <!-- 模块1:产品订单基础信息 -->
<div class="table-section" style="margin-bottom:24px;">
<h2>产品订单基础信息</h2>
<div class="table-wrapper"> <div class="table-wrapper">
<table id="orderTable"> <table id="orderTable">
<thead> <thead>
@@ -418,15 +420,28 @@
<th>日预算</th> <th>日预算</th>
<th>状态</th> <th>状态</th>
<th>MMP</th> <th>MMP</th>
<th>代投渠道</th>
<th>平台自投渠道</th>
<th>数据来源</th>
</tr> </tr>
</thead> </thead>
<tbody></tbody> <tbody></tbody>
</table> </table>
</div> </div>
</div> </div>
<!-- 模块2:渠道投放矩阵 -->
<div class="table-section">
<h2>渠道投放矩阵(渠道 × 产品)</h2>
<p style="font-size:12px;color:#94a3b8;margin:-8px 0 14px;">
<span class="status-badge status-active" style="padding:1px 8px;">Active</span> 投放中 
<span class="status-badge status-pause" style="padding:1px 8px;">Pause</span> 投过已停 
空白 = 未投放
</p>
<div class="table-wrapper">
<table id="matrixTable">
<thead></thead>
<tbody></tbody>
</table>
</div>
</div>
</div><!-- /tab-orders --> </div><!-- /tab-orders -->
<div class="updated-time" id="updatedTime"></div> <div class="updated-time" id="updatedTime"></div>
@@ -513,9 +528,6 @@
// Table // Table
const tbody = document.querySelector('#orderTable tbody'); const tbody = document.querySelector('#orderTable tbody');
const chipList = (arr) => (arr && arr.length)
? arr.map(c => `<span class="channel-chip">${c}</span>`).join('')
: '<span class="no-channel">—</span>';
tbody.innerHTML = orderData.map(o => { tbody.innerHTML = orderData.map(o => {
const statusClass = o.status === 'Active' ? 'status-active' : 'status-pause'; const statusClass = o.status === 'Active' ? 'status-active' : 'status-pause';
return ` return `
@@ -529,12 +541,69 @@
<td class="num-cell">${o.budget}</td> <td class="num-cell">${o.budget}</td>
<td><span class="status-badge ${statusClass}">${o.status}</span></td> <td><span class="status-badge ${statusClass}">${o.status}</span></td>
<td>${o.mmp}</td> <td>${o.mmp}</td>
<td style="max-width:220px;white-space:normal">${chipList(o.agency_channels)}</td>
<td style="max-width:180px;white-space:normal">${chipList(o.self_channels)}</td>
<td style="font-size:11px;color:#94a3b8">${o.source}</td>
</tr> </tr>
`; `;
}).join(''); }).join('');
renderMatrix();
}
function renderMatrix() {
// 列 = 产品(按 pkg 区分,同名产品用地区区分显示);行 = 渠道
// 每个订单条目是一列
const cols = orderData.map(o => ({
key: o.pkg,
label: o.product,
sub: o.geo,
status: o.status,
channels: new Set([...(o.agency_channels||[]), ...(o.self_channels||[])])
}));
// 收集所有渠道,分代投 / 自投两组
const agencySet = new Set();
const selfSet = new Set();
orderData.forEach(o => {
(o.agency_channels||[]).forEach(c => agencySet.add(c));
(o.self_channels||[]).forEach(c => selfSet.add(c));
});
const agencyChannels = [...agencySet];
const selfChannels = [...selfSet];
// 表头
const thead = document.querySelector('#matrixTable thead');
thead.innerHTML = `
<tr>
<th style="position:sticky;left:0;background:#f1f5f9;z-index:2;">渠道 \\ 产品</th>
${cols.map(c => `<th style="text-align:center;min-width:90px;">
<div>${c.label}</div>
<div style="font-weight:400;font-size:10px;color:#94a3b8;">${c.sub}</div>
</th>`).join('')}
</tr>
`;
// 单元格生成
const cell = (col, channel) => {
if (!col.channels.has(channel)) return '<td></td>';
const cls = col.status === 'Active' ? 'status-active' : 'status-pause';
return `<td style="text-align:center;"><span class="status-badge ${cls}" style="padding:2px 8px;font-size:10px;">${col.status}</span></td>`;
};
const groupRows = (title, channels) => {
if (!channels.length) return '';
let html = `<tr><td colspan="${cols.length+1}" style="background:#eef2ff;font-weight:700;color:#4338ca;font-size:12px;">${title}</td></tr>`;
html += channels.map(ch => `
<tr>
<td style="position:sticky;left:0;background:#fff;font-weight:500;">${ch}</td>
${cols.map(col => cell(col, ch)).join('')}
</tr>
`).join('');
return html;
};
const tbody = document.querySelector('#matrixTable tbody');
tbody.innerHTML =
groupRows('代投渠道', agencyChannels) +
groupRows('平台自投渠道', selfChannels);
} }
function populateFilters() { function populateFilters() {