feat: matrix status driven by real data + product order status (B2: only show channels with data)

This commit is contained in:
王源
2026-09-08 23:22:00 +08:00
parent fb24195233
commit 367eeda50c
2 changed files with 41 additions and 9 deletions
+24 -9
View File
@@ -209,7 +209,8 @@
<p class="hint"> <p class="hint">
<span class="badge badge-active">Active</span> 投放中  <span class="badge badge-active">Active</span> 投放中 
<span class="badge badge-pause">Pause</span> 投过已停  <span class="badge badge-pause">Pause</span> 投过已停 
空白 = 未投放 空白 = 暂无数据(未接入或未投放)<br>
状态依据实际投放数据判定:产品订单为 Pause 直接判停;产品在投则看该渠道近期展示趋势(掉到个位数/断更视为已停)。仅显示已接入数据的渠道。
</p> </p>
<div class="table-wrapper"> <div class="table-wrapper">
<table id="matrixTable"><thead></thead><tbody></tbody></table> <table id="matrixTable"><thead></thead><tbody></tbody></table>
@@ -251,17 +252,18 @@
</div> </div>
<script> <script>
let perfData = [], orderData = [], campaignData = []; let perfData = [], orderData = [], campaignData = [], matrixOverrides = {};
let impChart = null; let impChart = null;
async function load() { async function load() {
try { try {
const [p, o, c] = await Promise.all([ const [p, o, c, m] = await Promise.all([
fetch('mtg_data.json?' + Date.now()).then(r => r.json()).catch(() => []), fetch('mtg_data.json?' + Date.now()).then(r => r.json()).catch(() => []),
fetch('orders.json?' + Date.now()).then(r => r.json()).catch(() => []), fetch('orders.json?' + Date.now()).then(r => r.json()).catch(() => []),
fetch('campaigns.json?' + Date.now()).then(r => r.json()).catch(() => []) fetch('campaigns.json?' + Date.now()).then(r => r.json()).catch(() => []),
fetch('matrix_overrides.json?' + Date.now()).then(r => r.json()).catch(() => ({}))
]); ]);
perfData = p; orderData = o; campaignData = c; perfData = p; orderData = o; campaignData = c; matrixOverrides = m;
initTabs(); initTabs();
renderPerformance(); renderPerformance();
renderOrders(); renderOrders();
@@ -401,8 +403,9 @@
} }
function renderMatrix() { function renderMatrix() {
// 列 = 产品(带 pkg 用于查数据状态)
const cols = orderData.map(o => ({ const cols = orderData.map(o => ({
label: o.product, sub: o.geo, status: o.status, label: o.product, sub: o.geo, pkg: o.pkg,
channels: new Set([...(o.agency_channels||[]), ...(o.self_channels||[])]) channels: new Set([...(o.agency_channels||[]), ...(o.self_channels||[])])
})); }));
const channels = []; const channels = [];
@@ -413,10 +416,22 @@
<th style="position:sticky;left:0;background:#f9fafb;z-index:2;">渠道 \\ 产品</th> <th style="position:sticky;left:0;background:#f9fafb;z-index:2;">渠道 \\ 产品</th>
${cols.map(c => `<th style="text-align:center;min-width:88px;"><div>${c.label}</div><div style="font-weight:400;font-size:10px;color:#9ca3af;">${c.sub}</div></th>`).join('')} ${cols.map(c => `<th style="text-align:center;min-width:88px;"><div>${c.label}</div><div style="font-weight:400;font-size:10px;color:#9ca3af;">${c.sub}</div></th>`).join('')}
</tr>`; </tr>`;
// 单元格:仅当该「渠道|包名」在 matrixOverrides 有记录时才显示状态(遵从事实:接了数据才判定)
// 产品 pkg 可能是 "a / b" 合并形式,任一命中即取用
const lookup = (ch, pkg) => {
const parts = String(pkg).replace(/\s/g,'').split('/');
for (const p of parts) {
const k = ch + '|' + p;
if (k in matrixOverrides) return matrixOverrides[k];
}
return undefined;
};
const cell = (col, ch) => { const cell = (col, ch) => {
if (!col.channels.has(ch)) return '<td></td>'; const st = lookup(ch, col.pkg);
const cls = col.status === 'Active' ? 'badge-active' : 'badge-pause'; if (st === undefined || st === 'none') return '<td></td>'; // 无数据 / 零曝光 -> 留空
return `<td style="text-align:center;"><span class="badge ${cls}">${col.status}</span></td>`; const cls = st === 'Active' ? 'badge-active' : 'badge-pause';
return `<td style="text-align:center;"><span class="badge ${cls}">${st}</span></td>`;
}; };
document.querySelector('#matrixTable tbody').innerHTML = channels.map(ch => ` document.querySelector('#matrixTable tbody').innerHTML = channels.map(ch => `
<tr> <tr>
+17
View File
@@ -0,0 +1,17 @@
{
"Mintegral|com.levelinfinite.sgameGlobal": "Pause",
"Mintegral|water.sort.color.puzzle.offline.games": "Pause",
"Mintegral|com.igg.android.lordsmobile": "Pause",
"Mintegral|net.mbc.shahid": "Pause",
"Mintegral|com.luizalabs.mlapp": "Pause",
"Mintegral|br.com.netshoes.app": "Pause",
"Mintegral|id891130066": "Pause",
"Mintegral|id886443637": "Pause",
"Mintegral|com.sialiagames.xczyw.gp.tw": "Active",
"Mintegral|com.qookkagames.xczyw.gp.hk": "Active",
"MediaGo|com.igg.android.lordsmobile": "Pause",
"Bigo|com.ddup.zombiewaves.zw": "Pause",
"MediaGo|com.qookkagames.xczyw.gp.hk": "Active",
"MediaGo|com.sialiagames.xczyw.gp.tw": "Active",
"Mintegral|com.ddup.zombiewaves.zw": "Pause"
}