From ff2875b0ada8eaaf98cc65070427071f02921610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=BA=90?= Date: Wed, 14 Oct 2026 17:33:45 +0800 Subject: [PATCH] feat: link MTG data to coverage filters --- index.html | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) 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} 页`) );