153 lines
8.1 KiB
HTML
153 lines
8.1 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>EG Nagwa Daily Report - September 2026</title>
|
|
<meta name="description" content="Egypt · September 2026 · Install / Enroll Session / Revenue">
|
|
<meta property="og:title" content="EG Nagwa Daily Report - September 2026">
|
|
<meta property="og:description" content="Egypt · September 2026 · Install / Enroll Session / Revenue">
|
|
<meta property="og:type" content="website">
|
|
<meta name="twitter:card" content="summary">
|
|
<meta name="twitter:title" content="EG Nagwa Daily Report - September 2026">
|
|
<meta name="twitter:description" content="Egypt · September 2026 · Install / Enroll Session / Revenue">
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
|
|
<style>
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f0f2f5; color: #333; padding: 24px; }
|
|
.container { max-width: 1200px; margin: 0 auto; }
|
|
h1 { font-size: 22px; color: #1a1a2e; margin-bottom: 4px; }
|
|
.subtitle { color: #666; font-size: 13px; margin-bottom: 24px; }
|
|
.summary-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 14px; }
|
|
.summary-cards.primary { margin-bottom: 14px; }
|
|
.summary-cards.secondary { margin-bottom: 28px; }
|
|
.card { background: #fff; border-radius: 10px; padding: 16px; box-shadow: 0 1px 6px rgba(0,0,0,0.06); }
|
|
.card.key { background: linear-gradient(135deg, #fff 0%, #f5f7ff 100%); box-shadow: 0 2px 10px rgba(59,130,246,0.15); border: 1px solid #e5ecff; }
|
|
.card.key .value { font-size: 26px; }
|
|
.card .label { font-size: 11px; color: #888; text-transform: uppercase; letter-spacing: 0.5px; }
|
|
.card .value { font-size: 20px; font-weight: 700; margin-top: 4px; }
|
|
.card .value.blue { color: #3b82f6; }
|
|
.card .value.green { color: #10b981; }
|
|
.card .value.orange { color: #f59e0b; }
|
|
.card .value.purple { color: #8b5cf6; }
|
|
.charts { display: grid; grid-template-columns: 1fr; gap: 20px; margin-bottom: 28px; }
|
|
@media(min-width:900px) { .charts { grid-template-columns: 1fr 1fr; } }
|
|
.chart-box { background: #fff; border-radius: 10px; padding: 18px; box-shadow: 0 1px 6px rgba(0,0,0,0.06); }
|
|
.chart-box.full { grid-column: 1 / -1; }
|
|
.chart-box h3 { font-size: 14px; color: #555; margin-bottom: 10px; }
|
|
.table-wrap { background: #fff; border-radius: 10px; padding: 18px; box-shadow: 0 1px 6px rgba(0,0,0,0.06); overflow-x: auto; }
|
|
.table-wrap h3 { font-size: 14px; color: #555; margin-bottom: 10px; }
|
|
table { width: 100%; border-collapse: collapse; font-size: 12px; }
|
|
th, td { padding: 8px 10px; text-align: right; border-bottom: 1px solid #f0f0f0; }
|
|
th { background: #f8fafc; color: #666; font-weight: 600; position: sticky; top: 0; }
|
|
td:first-child, th:first-child { text-align: left; }
|
|
tr:hover td { background: #f5f9ff; }
|
|
.footer { text-align: center; color: #aaa; font-size: 11px; margin-top: 20px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1>EG Nagwa Daily Report</h1>
|
|
<p class="subtitle">Egypt · September 2026 · Install / Enroll Session / Revenue</p>
|
|
<div class="summary-cards primary" id="summaryPrimary"></div>
|
|
<div class="summary-cards secondary" id="summarySecondary"></div>
|
|
<div class="table-wrap">
|
|
<h3>Daily Detail</h3>
|
|
<table>
|
|
<thead><tr><th>Date</th><th>Install</th><th>Spend</th><th>Enroll Session</th><th>Enroll %</th></tr></thead>
|
|
<tbody id="tbody"></tbody>
|
|
</table>
|
|
</div>
|
|
<div class="charts">
|
|
<div class="chart-box full">
|
|
<h3>Daily Install vs Enroll Session</h3>
|
|
<canvas id="chartMain" height="70"></canvas>
|
|
</div>
|
|
<div class="chart-box">
|
|
<h3>Enroll Session Rate (%)</h3>
|
|
<canvas id="chartRate" height="90"></canvas>
|
|
</div>
|
|
<div class="chart-box">
|
|
<h3>Daily Spend ($)</h3>
|
|
<canvas id="chartSpend" height="90"></canvas>
|
|
</div>
|
|
</div>
|
|
<p class="footer" id="foot"></p>
|
|
</div>
|
|
<script>
|
|
fetch('data.json?t='+Date.now()).then(r=>r.json()).then(({meta, daily})=>{
|
|
const valid = daily.filter(d=>d.install>0);
|
|
const totalInstall = valid.reduce((s,d)=>s+d.install,0);
|
|
const totalSpend = valid.reduce((s,d)=>s+d.payable_spend,0);
|
|
const totalEnroll = valid.reduce((s,d)=>s+d.enroll_session,0);
|
|
const avgRate = totalInstall ? (totalEnroll/totalInstall*100).toFixed(1) : '0.0';
|
|
|
|
// 预算字段名会随月份变化(aug_budget / sep_budget ...),动态查找,避免写死导致渲染崩溃
|
|
const budgetKey = Object.keys(meta).find(k=>k.endsWith('_budget'));
|
|
const budget = budgetKey!=null ? meta[budgetKey] : null;
|
|
const fmt = v => (v==null ? '-' : Number(v).toLocaleString());
|
|
|
|
// 根据数据里的月份动态更新标题
|
|
if (valid.length){
|
|
const monthNames=['January','February','March','April','May','June','July','August','September','October','November','December'];
|
|
const [y,m] = valid[valid.length-1].date.split('-');
|
|
const title = `${monthNames[parseInt(m,10)-1]} ${y}`;
|
|
document.title = 'EG Nagwa Daily Report - ' + title;
|
|
const sub = document.querySelector('.subtitle');
|
|
if (sub) sub.innerHTML = 'Egypt · ' + title + ' · Install / Enroll Session / Revenue';
|
|
}
|
|
|
|
// 第一行:重点指标 —— Total Spend / Total Install + 预算相关
|
|
document.getElementById('summaryPrimary').innerHTML = `
|
|
<div class="card key"><div class="label">Total Spend</div><div class="value purple">$${totalSpend.toFixed(2)}</div></div>
|
|
<div class="card key"><div class="label">Total Install (MTD)</div><div class="value blue">${totalInstall.toLocaleString()}</div></div>
|
|
<div class="card"><div class="label">Budget</div><div class="value">$${fmt(budget)}</div></div>
|
|
<div class="card"><div class="label">Budget Left</div><div class="value green">$${fmt(meta.left)}</div></div>
|
|
<div class="card"><div class="label">Budget Used</div><div class="value orange">${meta.spend_pct||'-'}</div></div>
|
|
`;
|
|
|
|
// 第二行:事件率、推荐日安装、总注册会话
|
|
document.getElementById('summarySecondary').innerHTML = `
|
|
<div class="card"><div class="label">Total Enroll Session</div><div class="value green">${totalEnroll.toLocaleString()}</div></div>
|
|
<div class="card"><div class="label">Avg Enroll Rate</div><div class="value orange">${avgRate}%</div></div>
|
|
<div class="card"><div class="label">Rec. Daily Install</div><div class="value blue">${fmt(meta.rec_daily_install)}</div></div>
|
|
`;
|
|
|
|
const labels = valid.map(d=>d.date.slice(5));
|
|
const installs = valid.map(d=>d.install);
|
|
const enrolls = valid.map(d=>d.enroll_session);
|
|
const rates = valid.map(d=>d.enroll_session_pct);
|
|
const spends = valid.map(d=>d.payable_spend);
|
|
|
|
new Chart(document.getElementById('chartMain'),{
|
|
type:'line',
|
|
data:{labels, datasets:[
|
|
{label:'Install', data:installs, borderColor:'#3b82f6', backgroundColor:'rgba(59,130,246,0.07)', tension:0.3, fill:true, pointRadius:3},
|
|
{label:'Enroll Session', data:enrolls, borderColor:'#10b981', backgroundColor:'rgba(16,185,129,0.07)', tension:0.3, fill:true, pointRadius:3}
|
|
]},
|
|
options:{responsive:true, plugins:{legend:{position:'top'}}, scales:{y:{beginAtZero:false}}}
|
|
});
|
|
|
|
new Chart(document.getElementById('chartRate'),{
|
|
type:'bar',
|
|
data:{labels, datasets:[{label:'Enroll %', data:rates, backgroundColor:'rgba(245,158,11,0.55)', borderColor:'#f59e0b', borderWidth:1}]},
|
|
options:{responsive:true, plugins:{legend:{display:false}}, scales:{y:{ticks:{callback:v=>v+'%'}}}}
|
|
});
|
|
|
|
new Chart(document.getElementById('chartSpend'),{
|
|
type:'line',
|
|
data:{labels, datasets:[{label:'Spend', data:spends, borderColor:'#8b5cf6', backgroundColor:'rgba(139,92,246,0.08)', tension:0.3, fill:true, pointRadius:3}]},
|
|
options:{responsive:true, plugins:{legend:{display:false}}, scales:{y:{ticks:{callback:v=>'$'+v}}}}
|
|
});
|
|
|
|
const tbody = document.getElementById('tbody');
|
|
valid.slice().reverse().forEach(d=>{
|
|
tbody.innerHTML+=`<tr><td>${d.date}</td><td>${d.install}</td><td>$${d.payable_spend.toFixed(2)}</td><td>${d.enroll_session}</td><td>${d.enroll_session_pct.toFixed(2)}%</td></tr>`;
|
|
});
|
|
|
|
document.getElementById('foot').textContent='Last updated: '+new Date().toLocaleString();
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|