diff --git a/index.html b/index.html
index 70b8a25..e1b0dc5 100644
--- a/index.html
+++ b/index.html
@@ -513,6 +513,13 @@
search.addEventListener('input', () => { mtgState.page = 1; applyMtgFilters(); });
country.addEventListener('change', () => { mtgState.page = 1; applyMtgFilters(); });
match.addEventListener('change', () => { mtgState.page = 1; applyMtgFilters(); });
+ ['search', 'countryFilter', 'platformFilter', 'statusFilter'].forEach(id => {
+ const control = document.getElementById(id);
+ control.addEventListener(id === 'search' ? 'input' : 'change', () => {
+ mtgState.page = 1;
+ applyMtgFilters();
+ });
+ });
exportButton.addEventListener('click', exportMtgCsv);
applyMtgFilters();
}
@@ -521,15 +528,37 @@
const query = document.getElementById('mtgSearch').value.trim().toLocaleLowerCase();
const country = document.getElementById('mtgCountry').value;
const match = document.getElementById('mtgMatch').value;
+ const mainSearch = document.getElementById('search').value.trim().toLocaleLowerCase();
+ const mainCountry = document.getElementById('countryFilter').value;
+ const mainPlatform = document.getElementById('platformFilter').value;
+ const mainStatusControl = document.getElementById('statusFilter');
+ const mainStatus = mainStatusControl.value;
+ const coverageByKey = new Map(
+ state.data.records.map(row => [`${row.pkg.toLocaleLowerCase()}|${row.country}`, row])
+ );
+
mtgState.filtered = state.data.mtg1013.records.filter(row => {
const status = mtgMatchStatus(row).key;
+ const coverage = coverageByKey.get(`${row.pkg.toLocaleLowerCase()}|${row.country}`);
+ const coverageStatus = coverage ? statusOf(coverage).key : 'unmatched';
const matched = match === 'all'
|| status === match
|| (match === 'matched' && row.order_match);
+ const mainSearchable = `${row.adpingid} ${row.pkg} ${coverage ? coverage.product : ''} ${coverage ? coverage.adpingids.join(' ') : ''}`.toLocaleLowerCase();
return (!query || `${row.adpingid} ${row.pkg}`.toLocaleLowerCase().includes(query))
&& (country === 'all' || row.country === country)
- && matched;
+ && matched
+ && (!mainSearch || mainSearchable.includes(mainSearch))
+ && (mainCountry === 'all' || row.country === mainCountry)
+ && (mainPlatform === 'all' || Boolean(coverage && coverage.platforms.includes(mainPlatform)))
+ && (mainStatus === 'all' || coverageStatus === mainStatus);
});
+
+ const linked = [mainStatusControl.options[mainStatusControl.selectedIndex].text];
+ if (mainCountry !== 'all') linked.push(`国家 ${mainCountry}`);
+ if (mainPlatform !== 'all') linked.push(`平台 ${mainPlatform}`);
+ if (mainSearch) linked.push(`搜索 ${mainSearch}`);
+ mtgState.linkedLabel = linked.join(' · ');
renderMtgResults();
}
@@ -539,10 +568,27 @@
mtgState.page = Math.min(mtgState.page, totalPages);
const start = (mtgState.page - 1) * PAGE_SIZE;
const rows = mtgState.filtered.slice(start, start + PAGE_SIZE);
+ const clicks = mtgState.filtered.reduce((sum, row) => sum + row.valid_clicks, 0);
+ const installs = mtgState.filtered.reduce((sum, row) => sum + row.installs, 0);
+ const revenue = mtgState.filtered.reduce((sum, row) => sum + row.revenue, 0);
+ const cost = mtgState.filtered.reduce((sum, row) => sum + row.cost, 0);
+ const matchedRows = mtgState.filtered.filter(row => row.order_match).length;
+ const unmatchedRows = mtgState.filtered.length - matchedRows;
+ const cards = panel.querySelectorAll('.kpi');
+ const setCard = (index, value, sub) => {
+ cards[index].querySelector('.value').textContent = value;
+ cards[index].querySelector('.sub').textContent = sub;
+ };
+ setCard(0, nf.format(clicks), `${nf.format(mtgState.filtered.length)} 条筛选明细`);
+ setCard(1, nf.format(installs), `安装率 ${clicks ? percent(installs / clicks) : '-'}`);
+ setCard(2, money(revenue), `利润 ${money(revenue - cost)}`);
+ setCard(3, money(cost), `${nf.format(matchedRows)} 条已关联订单`);
+ setCard(4, cost ? percent(revenue / cost) : '-', `${nf.format(unmatchedRows)} 条未关联订单`);
+
const meta = panel.querySelector('.result-meta');
meta.textContent = '';
meta.append(
- el('span', '', `筛选结果 ${nf.format(mtgState.filtered.length)} 条`),
+ el('span', '', `筛选结果 ${nf.format(mtgState.filtered.length)} 条 · 联动:${mtgState.linkedLabel}`),
el('span', '', `第 ${mtgState.page} / ${totalPages} 页`)
);