feat: add TaurusX CPM CPC and CPI
This commit is contained in:
+24
-8
@@ -142,6 +142,11 @@
|
||||
function money(value) {
|
||||
return `$${Number(value || 0).toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
||||
}
|
||||
function unitCost(value) {
|
||||
return value === null || value === undefined
|
||||
? '-'
|
||||
: `$${Number(value).toLocaleString('en-US', { minimumFractionDigits: 4, maximumFractionDigits: 4 })}`;
|
||||
}
|
||||
function formatTime(value) {
|
||||
const date = new Date(value);
|
||||
return Number.isNaN(date.getTime()) ? value : date.toLocaleString('zh-CN', { hour12: false });
|
||||
@@ -170,7 +175,10 @@
|
||||
kpi('Impressions', nf.format(meta.impressions), `${nf.format(meta.campaigns)} 个 Campaign`),
|
||||
kpi('Clicks', nf.format(meta.clicks), `${nf.format(meta.pkg_country_count)} 个 Pkg_国家`),
|
||||
kpi('Conversions', nf.format(meta.conversions), `${nf.format(meta.countries)} 个国家`),
|
||||
kpi('Cost', money(meta.cost), `${nf.format(meta.rows)} 条投放明细`)
|
||||
kpi('Cost', money(meta.cost), `${nf.format(meta.rows)} 条投放明细`),
|
||||
kpi('CPM', unitCost(meta.cpm), 'Cost / Impressions × 1000'),
|
||||
kpi('CPC', unitCost(meta.cpc), 'Cost / Clicks'),
|
||||
kpi('CPI', unitCost(meta.cpi), 'Cost / Conversions')
|
||||
);
|
||||
|
||||
const panel = el('section', 'panel workspace');
|
||||
@@ -192,14 +200,15 @@
|
||||
[
|
||||
['date-desc','日期:新到旧'], ['cost-desc','Cost:高到低'],
|
||||
['impressions-desc','Impressions:高到低'], ['clicks-desc','Clicks:高到低'],
|
||||
['conversions-desc','Conversions:高到低'], ['pkg-asc','Pkg:A-Z']
|
||||
['conversions-desc','Conversions:高到低'], ['cpm-desc','CPM:高到低'],
|
||||
['cpc-desc','CPC:高到低'], ['cpi-desc','CPI:高到低'], ['pkg-asc','Pkg:A-Z']
|
||||
].forEach(([value, label]) => sort.append(new Option(`排序 · ${label}`, value)));
|
||||
const exportButton = el('button', 'button', '导出 TaurusX 数据');
|
||||
exportButton.type = 'button'; exportButton.id = 'exportButton';
|
||||
filters.append(search, reportDate, country, sort, exportButton);
|
||||
header.append(heading, filters);
|
||||
panel.append(header, el('div', 'result-meta'), el('div', 'table-wrap'), el('div', 'pagination'));
|
||||
app.append(summary, panel, el('footer', '', 'TaurusX 投放数据 · Impressions、Clicks、Conversions、Cost'));
|
||||
app.append(summary, panel, el('footer', '', 'TaurusX 投放数据 · Impressions、Clicks、Conversions、Cost、CPM、CPC、CPI'));
|
||||
|
||||
search.addEventListener('input', resetAndFilter);
|
||||
[reportDate, country, sort].forEach(control => control.addEventListener('change', resetAndFilter));
|
||||
@@ -255,6 +264,9 @@
|
||||
setCard(1, nf.format(clicks), `CTR ${impressions ? percent(clicks / impressions) : '-'}`);
|
||||
setCard(2, nf.format(conversions), `CVR ${clicks ? percent(conversions / clicks) : '-'}`);
|
||||
setCard(3, money(cost), `${nf.format(new Set(state.filtered.map(row => row.country)).size)} 个国家`);
|
||||
setCard(4, unitCost(impressions ? cost / impressions * 1000 : null), 'Cost / Impressions × 1000');
|
||||
setCard(5, unitCost(clicks ? cost / clicks : null), 'Cost / Clicks');
|
||||
setCard(6, unitCost(conversions ? cost / conversions : null), 'Cost / Conversions');
|
||||
|
||||
const meta = document.querySelector('.result-meta');
|
||||
meta.textContent = '';
|
||||
@@ -268,12 +280,12 @@
|
||||
wrap.textContent = '';
|
||||
const table = el('table');
|
||||
const thead = el('thead'); const header = el('tr');
|
||||
['日期', 'Campaign ID', 'Campaign', 'Pkg', '国家', 'Impressions', 'Clicks', 'Conversions', 'Cost']
|
||||
['日期', 'Campaign ID', 'Campaign', 'Pkg', '国家', 'Impressions', 'Clicks', 'Conversions', 'Cost', 'CPM', 'CPC', 'CPI']
|
||||
.forEach(label => header.append(el('th', '', label)));
|
||||
thead.append(header); table.append(thead);
|
||||
const tbody = el('tbody');
|
||||
if (!rows.length) {
|
||||
const cell = el('td', 'empty', '没有符合当前条件的 TaurusX 记录'); cell.colSpan = 9;
|
||||
const cell = el('td', 'empty', '没有符合当前条件的 TaurusX 记录'); cell.colSpan = 12;
|
||||
const row = el('tr'); row.append(cell); tbody.append(row);
|
||||
}
|
||||
rows.forEach(record => {
|
||||
@@ -288,7 +300,10 @@
|
||||
el('td', '', nf.format(record.impressions || 0)),
|
||||
el('td', '', nf.format(record.clicks || 0)),
|
||||
el('td', '', nf.format(record.conversions || 0)),
|
||||
el('td', '', money(record.cost))
|
||||
el('td', '', money(record.cost)),
|
||||
el('td', '', unitCost(record.cpm)),
|
||||
el('td', '', unitCost(record.cpc)),
|
||||
el('td', '', unitCost(record.cpi))
|
||||
);
|
||||
tbody.append(row);
|
||||
});
|
||||
@@ -306,10 +321,11 @@
|
||||
}
|
||||
|
||||
function exportCsv() {
|
||||
const headers = ['日期', 'Campaign ID', 'Campaign', 'Pkg', '国家', 'Impressions', 'Clicks', 'Conversions', 'Cost'];
|
||||
const headers = ['日期', 'Campaign ID', 'Campaign', 'Pkg', '国家', 'Impressions', 'Clicks', 'Conversions', 'Cost', 'CPM', 'CPC', 'CPI'];
|
||||
const rows = [headers, ...state.filtered.map(record => [
|
||||
record.date, record.campaign_id, record.campaign_name, record.pkg, record.country,
|
||||
record.impressions, record.clicks, record.conversions, record.cost
|
||||
record.impressions, record.clicks, record.conversions, record.cost,
|
||||
record.cpm ?? '', record.cpc ?? '', record.cpi ?? ''
|
||||
])];
|
||||
const csv = '\ufeff' + rows.map(row => row.map(value => `"${String(value ?? '').replaceAll('"', '""')}"`).join(',')).join('\n');
|
||||
const url = URL.createObjectURL(new Blob([csv], { type: 'text/csv;charset=utf-8' }));
|
||||
|
||||
Reference in New Issue
Block a user