feat: add Campaign ID detail module (campid -> pkg + geo + channel)
This commit is contained in:
+330
@@ -0,0 +1,330 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"campid": "91530535",
|
||||||
|
"product": "Honor of Kings",
|
||||||
|
"pkg": "com.levelinfinite.sgameGlobal",
|
||||||
|
"geo": "IN",
|
||||||
|
"channel": "Mintegral",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91539877",
|
||||||
|
"product": "Honor of Kings",
|
||||||
|
"pkg": "com.levelinfinite.sgameGlobal",
|
||||||
|
"geo": "IN",
|
||||||
|
"channel": "SPDragon(代投)",
|
||||||
|
"mode": "代投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91530534",
|
||||||
|
"product": "Honor of Kings",
|
||||||
|
"pkg": "com.levelinfinite.sgameGlobal",
|
||||||
|
"geo": "PH",
|
||||||
|
"channel": "Mintegral",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91539876",
|
||||||
|
"product": "Honor of Kings",
|
||||||
|
"pkg": "com.levelinfinite.sgameGlobal",
|
||||||
|
"geo": "PH",
|
||||||
|
"channel": "SPDragon(代投)",
|
||||||
|
"mode": "代投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91546637",
|
||||||
|
"product": "IGG (Lords Mobile)",
|
||||||
|
"pkg": "com.igg.android.lordsmobile",
|
||||||
|
"geo": "RU",
|
||||||
|
"channel": "MediaGo",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91530536",
|
||||||
|
"product": "IGG (Lords Mobile)",
|
||||||
|
"pkg": "com.igg.android.lordsmobile",
|
||||||
|
"geo": "RU",
|
||||||
|
"channel": "Mintegral",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91539867",
|
||||||
|
"product": "IGG (Lords Mobile)",
|
||||||
|
"pkg": "com.igg.android.lordsmobile",
|
||||||
|
"geo": "RU",
|
||||||
|
"channel": "SPDragon(代投)",
|
||||||
|
"mode": "代投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91544868",
|
||||||
|
"product": "IGG (Lords Mobile)",
|
||||||
|
"pkg": "com.igg.android.lordsmobile",
|
||||||
|
"geo": "RU",
|
||||||
|
"channel": "传音",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91530547",
|
||||||
|
"product": "Magalu_BR (Android)",
|
||||||
|
"pkg": "com.luizalabs.mlapp",
|
||||||
|
"geo": "BR",
|
||||||
|
"channel": "Mintegral",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91539871",
|
||||||
|
"product": "Magalu_BR (Android)",
|
||||||
|
"pkg": "com.luizalabs.mlapp",
|
||||||
|
"geo": "BR",
|
||||||
|
"channel": "SPDragon(代投)",
|
||||||
|
"mode": "代投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91530548",
|
||||||
|
"product": "Magalu_BR (iOS)",
|
||||||
|
"pkg": "id891130066",
|
||||||
|
"geo": "BR",
|
||||||
|
"channel": "Mintegral",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91539872",
|
||||||
|
"product": "Magalu_BR (iOS)",
|
||||||
|
"pkg": "id891130066",
|
||||||
|
"geo": "BR",
|
||||||
|
"channel": "SPDragon(代投)",
|
||||||
|
"mode": "代投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91530549",
|
||||||
|
"product": "Netshoes_BR (Android)",
|
||||||
|
"pkg": "br.com.netshoes.app",
|
||||||
|
"geo": "BR",
|
||||||
|
"channel": "Mintegral",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91539873",
|
||||||
|
"product": "Netshoes_BR (Android)",
|
||||||
|
"pkg": "br.com.netshoes.app",
|
||||||
|
"geo": "BR",
|
||||||
|
"channel": "SPDragon(代投)",
|
||||||
|
"mode": "代投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91530550",
|
||||||
|
"product": "Netshoes_BR (iOS)",
|
||||||
|
"pkg": "id886443637",
|
||||||
|
"geo": "BR",
|
||||||
|
"channel": "Mintegral",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91539874",
|
||||||
|
"product": "Netshoes_BR (iOS)",
|
||||||
|
"pkg": "id886443637",
|
||||||
|
"geo": "BR",
|
||||||
|
"channel": "SPDragon(代投)",
|
||||||
|
"mode": "代投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91546638",
|
||||||
|
"product": "Shahid",
|
||||||
|
"pkg": "net.mbc.shahid",
|
||||||
|
"geo": "SA",
|
||||||
|
"channel": "MediaGo",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91530537",
|
||||||
|
"product": "Shahid",
|
||||||
|
"pkg": "net.mbc.shahid",
|
||||||
|
"geo": "SA",
|
||||||
|
"channel": "Mintegral",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91539868",
|
||||||
|
"product": "Shahid",
|
||||||
|
"pkg": "net.mbc.shahid",
|
||||||
|
"geo": "SA",
|
||||||
|
"channel": "SPDragon(代投)",
|
||||||
|
"mode": "代投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91550107",
|
||||||
|
"product": "Shahid",
|
||||||
|
"pkg": "net.mbc.shahid",
|
||||||
|
"geo": "SA",
|
||||||
|
"channel": "Smartyads",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91544867",
|
||||||
|
"product": "Shahid",
|
||||||
|
"pkg": "net.mbc.shahid",
|
||||||
|
"geo": "SA",
|
||||||
|
"channel": "传音",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91530538",
|
||||||
|
"product": "Water Sort",
|
||||||
|
"pkg": "water.sort.color.puzzle.offline.games",
|
||||||
|
"geo": "US",
|
||||||
|
"channel": "Mintegral",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91552556",
|
||||||
|
"product": "Zombie",
|
||||||
|
"pkg": "com.ddup.zombiewaves.zw",
|
||||||
|
"geo": "US",
|
||||||
|
"channel": "Bigo",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91551606",
|
||||||
|
"product": "Zombie",
|
||||||
|
"pkg": "com.ddup.zombiewaves.zw",
|
||||||
|
"geo": "US",
|
||||||
|
"channel": "Mintegral",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91551412",
|
||||||
|
"product": "Zombie",
|
||||||
|
"pkg": "com.ddup.zombiewaves.zw",
|
||||||
|
"geo": "US",
|
||||||
|
"channel": "Newsbreak",
|
||||||
|
"mode": "其他"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91551413",
|
||||||
|
"product": "Zombie",
|
||||||
|
"pkg": "com.ddup.zombiewaves.zw",
|
||||||
|
"geo": "US",
|
||||||
|
"channel": "SPDragon(代投)",
|
||||||
|
"mode": "代投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91551415",
|
||||||
|
"product": "Zombie",
|
||||||
|
"pkg": "com.ddup.zombiewaves.zw",
|
||||||
|
"geo": "US",
|
||||||
|
"channel": "传音",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91534918",
|
||||||
|
"product": "灵犀互动",
|
||||||
|
"pkg": "com.qookkagames.xczyw.gp.hk",
|
||||||
|
"geo": "HK",
|
||||||
|
"channel": "Bigo",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91533908",
|
||||||
|
"product": "灵犀互动",
|
||||||
|
"pkg": "com.qookkagames.xczyw.gp.hk",
|
||||||
|
"geo": "HK",
|
||||||
|
"channel": "Kwai",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91546640",
|
||||||
|
"product": "灵犀互动",
|
||||||
|
"pkg": "com.qookkagames.xczyw.gp.hk",
|
||||||
|
"geo": "HK",
|
||||||
|
"channel": "MediaGo",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91534913",
|
||||||
|
"product": "灵犀互动",
|
||||||
|
"pkg": "com.qookkagames.xczyw.gp.hk",
|
||||||
|
"geo": "HK",
|
||||||
|
"channel": "Mintegral",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91539869",
|
||||||
|
"product": "灵犀互动",
|
||||||
|
"pkg": "com.qookkagames.xczyw.gp.hk",
|
||||||
|
"geo": "HK",
|
||||||
|
"channel": "SPDragon(代投)",
|
||||||
|
"mode": "代投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91550105",
|
||||||
|
"product": "灵犀互动",
|
||||||
|
"pkg": "com.qookkagames.xczyw.gp.hk",
|
||||||
|
"geo": "HK",
|
||||||
|
"channel": "Smartyads",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91544865",
|
||||||
|
"product": "灵犀互动",
|
||||||
|
"pkg": "com.qookkagames.xczyw.gp.hk",
|
||||||
|
"geo": "HK",
|
||||||
|
"channel": "传音",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91534919",
|
||||||
|
"product": "灵犀互动",
|
||||||
|
"pkg": "com.sialiagames.xczyw.gp.tw",
|
||||||
|
"geo": "TW",
|
||||||
|
"channel": "Bigo",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91533907",
|
||||||
|
"product": "灵犀互动",
|
||||||
|
"pkg": "com.sialiagames.xczyw.gp.tw",
|
||||||
|
"geo": "TW",
|
||||||
|
"channel": "Kwai",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91546639",
|
||||||
|
"product": "灵犀互动",
|
||||||
|
"pkg": "com.sialiagames.xczyw.gp.tw",
|
||||||
|
"geo": "TW",
|
||||||
|
"channel": "MediaGo",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91533906",
|
||||||
|
"product": "灵犀互动",
|
||||||
|
"pkg": "com.sialiagames.xczyw.gp.tw",
|
||||||
|
"geo": "TW",
|
||||||
|
"channel": "Mintegral",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91539870",
|
||||||
|
"product": "灵犀互动",
|
||||||
|
"pkg": "com.sialiagames.xczyw.gp.tw",
|
||||||
|
"geo": "TW",
|
||||||
|
"channel": "SPDragon(代投)",
|
||||||
|
"mode": "代投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91550106",
|
||||||
|
"product": "灵犀互动",
|
||||||
|
"pkg": "com.sialiagames.xczyw.gp.tw",
|
||||||
|
"geo": "TW",
|
||||||
|
"channel": "Smartyads",
|
||||||
|
"mode": "自投"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"campid": "91544866",
|
||||||
|
"product": "灵犀互动",
|
||||||
|
"pkg": "com.sialiagames.xczyw.gp.tw",
|
||||||
|
"geo": "TW",
|
||||||
|
"channel": "传音",
|
||||||
|
"mode": "自投"
|
||||||
|
}
|
||||||
|
]
|
||||||
+70
-2
@@ -442,6 +442,36 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 模块3:Campaign ID 明细 -->
|
||||||
|
<div class="table-section" style="margin-top:24px;">
|
||||||
|
<h2>Campaign ID 明细(唯一识别值)</h2>
|
||||||
|
<div class="controls" style="box-shadow:none;padding:0 0 14px;background:transparent;">
|
||||||
|
<div class="control-group">
|
||||||
|
<label>产品</label>
|
||||||
|
<select id="campProductFilter"><option value="all">全部</option></select>
|
||||||
|
</div>
|
||||||
|
<div class="control-group">
|
||||||
|
<label>渠道</label>
|
||||||
|
<select id="campChannelFilter"><option value="all">全部</option></select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="table-wrapper">
|
||||||
|
<table id="campaignTable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Campaign ID</th>
|
||||||
|
<th>Product</th>
|
||||||
|
<th>Pkg / 包名</th>
|
||||||
|
<th>投放国家</th>
|
||||||
|
<th>渠道</th>
|
||||||
|
<th>投放方式</th>
|
||||||
|
</tr>
|
||||||
|
</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>
|
||||||
@@ -455,16 +485,19 @@
|
|||||||
|
|
||||||
let rawData = [];
|
let rawData = [];
|
||||||
let orderData = [];
|
let orderData = [];
|
||||||
|
let campaignData = [];
|
||||||
let charts = {};
|
let charts = {};
|
||||||
|
|
||||||
async function loadData() {
|
async function loadData() {
|
||||||
try {
|
try {
|
||||||
const [dResp, oResp] = await Promise.all([
|
const [dResp, oResp, cResp] = await Promise.all([
|
||||||
fetch('data.json?' + Date.now()),
|
fetch('data.json?' + Date.now()),
|
||||||
fetch('orders.json?' + Date.now())
|
fetch('orders.json?' + Date.now()),
|
||||||
|
fetch('campaigns.json?' + Date.now())
|
||||||
]);
|
]);
|
||||||
rawData = await dResp.json();
|
rawData = await dResp.json();
|
||||||
orderData = await oResp.json();
|
orderData = await oResp.json();
|
||||||
|
campaignData = await cResp.json();
|
||||||
init();
|
init();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.error('Failed to load data:', e);
|
console.error('Failed to load data:', e);
|
||||||
@@ -475,6 +508,7 @@
|
|||||||
populateFilters();
|
populateFilters();
|
||||||
renderAll();
|
renderAll();
|
||||||
renderOrders();
|
renderOrders();
|
||||||
|
renderCampaigns();
|
||||||
setupTabs();
|
setupTabs();
|
||||||
document.getElementById('pkgFilter').addEventListener('change', renderAll);
|
document.getElementById('pkgFilter').addEventListener('change', renderAll);
|
||||||
document.getElementById('dateFilter').addEventListener('change', renderAll);
|
document.getElementById('dateFilter').addEventListener('change', renderAll);
|
||||||
@@ -595,6 +629,40 @@
|
|||||||
`).join('');
|
`).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderCampaigns() {
|
||||||
|
// 填充筛选器
|
||||||
|
const prods = [...new Set(campaignData.map(c => c.product))].sort();
|
||||||
|
const chans = [...new Set(campaignData.map(c => c.channel))].sort();
|
||||||
|
const pf = document.getElementById('campProductFilter');
|
||||||
|
const cf = document.getElementById('campChannelFilter');
|
||||||
|
prods.forEach(p => { const o=document.createElement('option'); o.value=p; o.textContent=p; pf.appendChild(o); });
|
||||||
|
chans.forEach(c => { const o=document.createElement('option'); o.value=c; o.textContent=c; cf.appendChild(o); });
|
||||||
|
pf.addEventListener('change', drawCampaignRows);
|
||||||
|
cf.addEventListener('change', drawCampaignRows);
|
||||||
|
drawCampaignRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawCampaignRows() {
|
||||||
|
const pf = document.getElementById('campProductFilter').value;
|
||||||
|
const cf = document.getElementById('campChannelFilter').value;
|
||||||
|
let data = campaignData;
|
||||||
|
if (pf !== 'all') data = data.filter(c => c.product === pf);
|
||||||
|
if (cf !== 'all') data = data.filter(c => c.channel === cf);
|
||||||
|
|
||||||
|
const modeColor = m => m === '自投' ? 'status-active' : (m === '代投' ? 'status-pause' : '');
|
||||||
|
const tbody = document.querySelector('#campaignTable tbody');
|
||||||
|
tbody.innerHTML = data.map(c => `
|
||||||
|
<tr>
|
||||||
|
<td class="num-cell" style="font-weight:600;color:#4338ca;">${c.campid}</td>
|
||||||
|
<td style="font-weight:500">${c.product}</td>
|
||||||
|
<td class="num-cell" style="font-size:11px">${c.pkg}</td>
|
||||||
|
<td><span class="pkg-tag">${c.geo}</span></td>
|
||||||
|
<td>${c.channel}</td>
|
||||||
|
<td><span class="status-badge ${modeColor(c.mode)}" style="padding:2px 8px;font-size:10px;">${c.mode}</span></td>
|
||||||
|
</tr>
|
||||||
|
`).join('');
|
||||||
|
}
|
||||||
|
|
||||||
function populateFilters() {
|
function populateFilters() {
|
||||||
const pkgs = [...new Set(rawData.map(d => d.pkg))];
|
const pkgs = [...new Set(rawData.map(d => d.pkg))];
|
||||||
const sel = document.getElementById('pkgFilter');
|
const sel = document.getElementById('pkgFilter');
|
||||||
|
|||||||
Reference in New Issue
Block a user