Refine Amazon ZA daily tracker

This commit is contained in:
zouyun
2026-08-24 16:51:55 +08:00
parent 7ba8ff6936
commit 838b7a844b
3 changed files with 161 additions and 94 deletions
+116 -73
View File
@@ -2,18 +2,18 @@
"meta": {
"package": "com.amazon.mShop.android.shopping",
"geo": "ZA",
"generated_at": "2026-08-24T08:27:15+00:00",
"generated_at": "2026-08-24T08:51:01+00:00",
"date_start": "2026-08-01",
"date_end": "2026-08-31",
"data_cutoff": "2026-08-23",
"currency": "USD",
"install_definition": "af_app_opened repostback",
"install_definition": "delivery repostback (attributed installs); af_app_opened excluded",
"event_definition": "event1/event2 repostback",
"rate_definition": "(event1 + event2) / Install",
"payable_definition": "(event1 + event2) × $3"
},
"totals": {
"install": 39149,
"install": 37796,
"event1": 6208,
"event2": 485,
"e1e2": 6693,
@@ -21,7 +21,7 @@
"midas_spend_zar": 321115.9,
"payable_spend": 20079,
"payable_spend_zar": 331303.5,
"e1e2_rate": 17.1
"e1e2_rate": 17.71
},
"budget": {
"monthly_budget_zar": 511500.0,
@@ -43,17 +43,18 @@
"required_daily_budget_zar": 22524.56,
"required_daily_events": 455,
"projected_month_spend_zar": 446539.5,
"projected_month_variance_zar": 64960.5
"projected_month_variance_zar": 64960.5,
"mtd_expected_ffr": 77.42
},
"daily": [
{
"date": "2026-08-01",
"is_actual": true,
"install": 1520,
"install": 1440,
"event1": 281,
"event2": 23,
"e1e2": 304,
"e1e2_rate": 20.0,
"e1e2_rate": 21.11,
"midas_spend": 920.34,
"midas_spend_zar": 15185.61,
"payable_spend": 912,
@@ -61,16 +62,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 91.2,
"ecpi_usd": 0.6055
"ecpi_usd": 0.6391
},
{
"date": "2026-08-02",
"is_actual": true,
"install": 1733,
"install": 1621,
"event1": 94,
"event2": 26,
"e1e2": 120,
"e1e2_rate": 6.92,
"e1e2_rate": 7.4,
"midas_spend": 1036.81,
"midas_spend_zar": 17107.36,
"payable_spend": 360,
@@ -78,16 +79,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 36.0,
"ecpi_usd": 0.5983
"ecpi_usd": 0.6396
},
{
"date": "2026-08-03",
"is_actual": true,
"install": 1781,
"install": 1652,
"event1": 432,
"event2": 26,
"e1e2": 458,
"e1e2_rate": 25.72,
"e1e2_rate": 27.72,
"midas_spend": 963.34,
"midas_spend_zar": 15895.11,
"payable_spend": 1374,
@@ -95,16 +96,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 137.4,
"ecpi_usd": 0.5409
"ecpi_usd": 0.5831
},
{
"date": "2026-08-04",
"is_actual": true,
"install": 1661,
"install": 1625,
"event1": 170,
"event2": 36,
"e1e2": 206,
"e1e2_rate": 12.4,
"e1e2_rate": 12.68,
"midas_spend": 686.46,
"midas_spend_zar": 11326.59,
"payable_spend": 618,
@@ -112,16 +113,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 61.8,
"ecpi_usd": 0.4133
"ecpi_usd": 0.4224
},
{
"date": "2026-08-05",
"is_actual": true,
"install": 1622,
"install": 1545,
"event1": 141,
"event2": 36,
"e1e2": 177,
"e1e2_rate": 10.91,
"e1e2_rate": 11.46,
"midas_spend": 651.98,
"midas_spend_zar": 10757.67,
"payable_spend": 531,
@@ -129,12 +130,12 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 53.1,
"ecpi_usd": 0.402
"ecpi_usd": 0.422
},
{
"date": "2026-08-06",
"is_actual": true,
"install": 1397,
"install": 1420,
"event1": 0,
"event2": 0,
"e1e2": 0,
@@ -146,16 +147,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 0.0,
"ecpi_usd": 0.4275
"ecpi_usd": 0.4206
},
{
"date": "2026-08-07",
"is_actual": true,
"install": 1870,
"install": 1517,
"event1": 516,
"event2": 36,
"e1e2": 552,
"e1e2_rate": 29.52,
"e1e2_rate": 36.39,
"midas_spend": 637.97,
"midas_spend_zar": 10526.51,
"payable_spend": 1656,
@@ -163,16 +164,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 165.6,
"ecpi_usd": 0.3412
"ecpi_usd": 0.4205
},
{
"date": "2026-08-08",
"is_actual": true,
"install": 1506,
"install": 1435,
"event1": 196,
"event2": 27,
"e1e2": 223,
"e1e2_rate": 14.81,
"e1e2_rate": 15.54,
"midas_spend": 603.36,
"midas_spend_zar": 9955.44,
"payable_spend": 669,
@@ -180,16 +181,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 66.9,
"ecpi_usd": 0.4006
"ecpi_usd": 0.4205
},
{
"date": "2026-08-09",
"is_actual": true,
"install": 1633,
"install": 1569,
"event1": 325,
"event2": 6,
"e1e2": 331,
"e1e2_rate": 20.27,
"e1e2_rate": 21.1,
"midas_spend": 659.2,
"midas_spend_zar": 10876.8,
"payable_spend": 993,
@@ -197,16 +198,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 99.3,
"ecpi_usd": 0.4037
"ecpi_usd": 0.4201
},
{
"date": "2026-08-10",
"is_actual": true,
"install": 1661,
"install": 1634,
"event1": 242,
"event2": 20,
"e1e2": 262,
"e1e2_rate": 15.77,
"e1e2_rate": 16.03,
"midas_spend": 727.32,
"midas_spend_zar": 12000.78,
"payable_spend": 786,
@@ -214,16 +215,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 78.6,
"ecpi_usd": 0.4379
"ecpi_usd": 0.4451
},
{
"date": "2026-08-11",
"is_actual": true,
"install": 1668,
"install": 1617,
"event1": 227,
"event2": 16,
"e1e2": 243,
"e1e2_rate": 14.57,
"e1e2_rate": 15.03,
"midas_spend": 871.5,
"midas_spend_zar": 14379.75,
"payable_spend": 729,
@@ -231,16 +232,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 72.9,
"ecpi_usd": 0.5225
"ecpi_usd": 0.539
},
{
"date": "2026-08-12",
"is_actual": true,
"install": 1650,
"install": 1635,
"event1": 266,
"event2": 22,
"e1e2": 288,
"e1e2_rate": 17.45,
"e1e2_rate": 17.61,
"midas_spend": 881.7,
"midas_spend_zar": 14548.05,
"payable_spend": 864,
@@ -248,16 +249,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 86.4,
"ecpi_usd": 0.5344
"ecpi_usd": 0.5393
},
{
"date": "2026-08-13",
"is_actual": true,
"install": 1543,
"install": 1535,
"event1": 41,
"event2": 5,
"e1e2": 46,
"e1e2_rate": 2.98,
"e1e2_rate": 3.0,
"midas_spend": 827.89,
"midas_spend_zar": 13660.18,
"payable_spend": 138,
@@ -265,16 +266,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 13.8,
"ecpi_usd": 0.5365
"ecpi_usd": 0.5393
},
{
"date": "2026-08-14",
"is_actual": true,
"install": 1677,
"install": 1660,
"event1": 176,
"event2": 23,
"e1e2": 199,
"e1e2_rate": 11.87,
"e1e2_rate": 11.99,
"midas_spend": 895.51,
"midas_spend_zar": 14775.91,
"payable_spend": 597,
@@ -282,16 +283,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 59.7,
"ecpi_usd": 0.534
"ecpi_usd": 0.5395
},
{
"date": "2026-08-15",
"is_actual": true,
"install": 1839,
"install": 1822,
"event1": 373,
"event2": 15,
"e1e2": 388,
"e1e2_rate": 21.1,
"e1e2_rate": 21.3,
"midas_spend": 983.11,
"midas_spend_zar": 16221.32,
"payable_spend": 1164,
@@ -299,16 +300,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 116.4,
"ecpi_usd": 0.5346
"ecpi_usd": 0.5396
},
{
"date": "2026-08-16",
"is_actual": true,
"install": 1809,
"install": 1800,
"event1": 273,
"event2": 72,
"e1e2": 345,
"e1e2_rate": 19.07,
"e1e2_rate": 19.17,
"midas_spend": 971.76,
"midas_spend_zar": 16034.04,
"payable_spend": 1035,
@@ -316,16 +317,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 103.5,
"ecpi_usd": 0.5372
"ecpi_usd": 0.5399
},
{
"date": "2026-08-17",
"is_actual": true,
"install": 1675,
"install": 1683,
"event1": 266,
"event2": 8,
"e1e2": 274,
"e1e2_rate": 16.36,
"e1e2_rate": 16.28,
"midas_spend": 908.82,
"midas_spend_zar": 14995.53,
"payable_spend": 822,
@@ -333,16 +334,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 82.2,
"ecpi_usd": 0.5426
"ecpi_usd": 0.54
},
{
"date": "2026-08-18",
"is_actual": true,
"install": 1988,
"install": 1840,
"event1": 370,
"event2": 40,
"e1e2": 410,
"e1e2_rate": 20.62,
"e1e2_rate": 22.28,
"midas_spend": 993.6,
"midas_spend_zar": 16394.4,
"payable_spend": 1230,
@@ -350,16 +351,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 123.0,
"ecpi_usd": 0.4998
"ecpi_usd": 0.54
},
{
"date": "2026-08-19",
"is_actual": true,
"install": 1543,
"install": 1517,
"event1": 438,
"event2": 13,
"e1e2": 451,
"e1e2_rate": 29.23,
"e1e2_rate": 29.73,
"midas_spend": 812.35,
"midas_spend_zar": 13403.77,
"payable_spend": 1353,
@@ -367,16 +368,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 135.3,
"ecpi_usd": 0.5265
"ecpi_usd": 0.5355
},
{
"date": "2026-08-20",
"is_actual": true,
"install": 1737,
"install": 1720,
"event1": 352,
"event2": 8,
"e1e2": 360,
"e1e2_rate": 20.73,
"e1e2_rate": 20.93,
"midas_spend": 911.15,
"midas_spend_zar": 15033.98,
"payable_spend": 1080,
@@ -384,16 +385,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 108.0,
"ecpi_usd": 0.5246
"ecpi_usd": 0.5297
},
{
"date": "2026-08-21",
"is_actual": true,
"install": 1877,
"install": 1867,
"event1": 265,
"event2": 4,
"e1e2": 269,
"e1e2_rate": 14.33,
"e1e2_rate": 14.41,
"midas_spend": 989.64,
"midas_spend_zar": 16329.06,
"payable_spend": 807,
@@ -401,16 +402,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 80.7,
"ecpi_usd": 0.5272
"ecpi_usd": 0.5301
},
{
"date": "2026-08-22",
"is_actual": true,
"install": 1883,
"install": 1779,
"event1": 435,
"event2": 13,
"e1e2": 448,
"e1e2_rate": 23.79,
"e1e2_rate": 25.18,
"midas_spend": 942.89,
"midas_spend_zar": 15557.68,
"payable_spend": 1344,
@@ -418,16 +419,16 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 134.4,
"ecpi_usd": 0.5007
"ecpi_usd": 0.53
},
{
"date": "2026-08-23",
"is_actual": true,
"install": 1876,
"install": 1863,
"event1": 329,
"event2": 10,
"e1e2": 339,
"e1e2_rate": 18.07,
"e1e2_rate": 18.2,
"midas_spend": 987.64,
"midas_spend_zar": 16296.06,
"payable_spend": 1017,
@@ -435,7 +436,7 @@
"daily_budget_zar": 16500.0,
"daily_cap": 333,
"ffr_rate": 101.7,
"ecpi_usd": 0.5265
"ecpi_usd": 0.5301
},
{
"date": "2026-08-24",
@@ -573,5 +574,47 @@
"ffr_rate": 0.0,
"ecpi_usd": null
}
],
"weekly": [
{
"label": "Aug 01–Aug 02",
"install": 3061,
"event1": 375,
"event2": 49,
"e1e2": 424,
"payable_spend": 1272.0,
"midas_spend": 1957.15,
"e1e2_rate": 13.85
},
{
"label": "Aug 03–Aug 09",
"install": 10763,
"event1": 1780,
"event2": 167,
"e1e2": 1947,
"payable_spend": 5841.0,
"midas_spend": 4799.54,
"e1e2_rate": 18.09
},
{
"label": "Aug 10–Aug 16",
"install": 11703,
"event1": 1598,
"event2": 173,
"e1e2": 1771,
"payable_spend": 5313.0,
"midas_spend": 6158.79,
"e1e2_rate": 15.13
},
{
"label": "Aug 17–Aug 23",
"install": 12269,
"event1": 2455,
"event2": 96,
"e1e2": 2551,
"payable_spend": 7653.0,
"midas_spend": 6546.09,
"e1e2_rate": 20.79
}
]
}
+16 -16
View File
@@ -4,42 +4,42 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="color-scheme" content="light dark">
<title>Amazon ZA 每日交付报告</title>
<title>Amazon - ZA daily tracker</title>
<style>
:root{--bg:#f4f7fb;--panel:#fff;--ink:#162033;--muted:#667085;--line:#dce3ec;--blue:#2f6fed;--gold:#d79b24;--orange:#e56d35;--soft:#eaf1ff;--shadow:0 8px 28px rgba(23,43,77,.08)}
*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--ink);font:14px/1.55 Inter,ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif}main{max-width:1180px;margin:auto;padding:42px 24px 64px}.eyebrow{color:var(--blue);font-weight:700;letter-spacing:.08em;text-transform:uppercase}.hero h1{font-size:clamp(28px,4vw,46px);line-height:1.1;margin:8px 0 12px}.hero p{color:var(--muted);font-size:16px;margin:0;max-width:800px}.status{display:inline-flex;align-items:center;gap:8px;margin-top:18px;padding:7px 11px;border:1px solid var(--line);border-radius:999px;background:var(--panel);color:var(--muted)}.dot{width:8px;height:8px;border-radius:50%;background:var(--blue)}section{margin-top:30px}h2{font-size:22px;margin:0 0 12px}.summary{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}.card,.panel{background:var(--panel);border:1px solid var(--line);border-radius:16px;box-shadow:var(--shadow)}.card{padding:18px}.card .label{color:var(--muted);font-weight:600}.card .value{font-size:28px;font-weight:750;margin-top:6px;font-variant-numeric:tabular-nums}.card .note{color:var(--muted);font-size:12px;margin-top:3px}.panel{padding:22px;margin-top:14px}.takeaway{border-left:4px solid var(--blue);padding-left:14px;color:var(--muted)}.takeaway strong{color:var(--ink)}.charts{display:grid;grid-template-columns:1fr 1fr;gap:14px}.chart{min-height:300px;overflow-x:auto}.chart-head{margin-bottom:16px}.chart-title{font-weight:750;font-size:16px}.chart-sub{color:var(--muted);font-size:12px}.bars{height:220px;display:flex;align-items:end;gap:14px;padding:20px 10px 28px;border-bottom:1px solid var(--line);position:relative}.bar-group{flex:1;height:100%;display:flex;align-items:end;justify-content:center;gap:6px;position:relative}.bar{min-width:8px;max-width:34px;width:33%;border-radius:6px 6px 0 0;position:relative}.bar span{position:absolute;top:-21px;left:50%;transform:translateX(-50%);font-size:11px;font-weight:700;white-space:nowrap}.bar-label{position:absolute;bottom:-25px;left:50%;transform:translateX(-50%);color:var(--muted);font-size:11px}.legend{display:flex;gap:14px;margin-top:13px;color:var(--muted);font-size:12px}.swatch{width:9px;height:9px;border-radius:2px;display:inline-block;margin-right:5px}.rate-bars .bar{width:52%;background:var(--orange)}.progress{height:14px;background:var(--soft);border-radius:999px;overflow:hidden;margin:18px 0 8px}.progress-fill{height:100%;background:var(--blue);border-radius:inherit}.progress-labels{display:flex;justify-content:space-between;color:var(--muted);font-size:12px}table{width:100%;border-collapse:collapse;font-variant-numeric:tabular-nums}th,td{padding:11px 9px;border-bottom:1px solid var(--line);text-align:right;white-space:nowrap}th:first-child,td:first-child{text-align:left}th{color:var(--muted);font-size:12px}tbody tr:hover{background:var(--soft)}tr.future{color:var(--muted);opacity:.65}.footer-note{color:var(--muted);font-size:12px;margin-top:18px}.error{padding:18px;border:1px solid #f0b7b7;background:#fff2f2;color:#912b2b;border-radius:12px}.login-shell{min-height:100vh;display:grid;place-items:center;padding:24px}.login-card{width:min(430px,100%);background:var(--panel);border:1px solid var(--line);border-radius:22px;padding:30px;box-shadow:var(--shadow)}.login-card h1{font-size:28px;margin:8px 0}.login-card p{color:var(--muted);margin:0 0 22px}.field{display:block;margin-top:14px;font-weight:700}.field input{display:block;width:100%;margin-top:7px;border:1px solid var(--line);border-radius:11px;padding:12px 13px;background:var(--bg);color:var(--ink);font:inherit;outline:none}.field input:focus{border-color:var(--blue);box-shadow:0 0 0 3px rgba(47,111,237,.14)}button{width:100%;margin-top:20px;border:0;border-radius:11px;padding:13px;background:var(--blue);color:white;font:inherit;font-weight:750;cursor:pointer}button:disabled{opacity:.65;cursor:wait}.login-error{min-height:22px;color:#c13a3a;font-size:13px;margin-top:10px}.access-note{font-size:12px!important;margin-top:18px!important}#report[hidden],#login[hidden]{display:none!important}@media(max-width:850px){.summary{grid-template-columns:1fr 1fr}.charts{grid-template-columns:1fr}}@media(max-width:520px){main{padding:26px 14px}.summary{grid-template-columns:1fr}.panel{padding:16px;overflow:auto}.card .value{font-size:24px}.login-card{padding:24px}}
.table-wrap{overflow-x:auto;padding:0}.table-wrap table{min-width:950px}.table-wrap th{position:sticky;top:0;background:var(--soft);z-index:1;text-transform:uppercase;letter-spacing:.03em}.table-wrap th,.table-wrap td{padding:12px 14px}.table-wrap tbody tr:nth-child(even):not(.future){background:rgba(47,111,237,.035)}.table-wrap tbody tr:hover{background:var(--soft)}.rate-spike{background:rgba(229,109,53,.16);color:#b94f20;font-weight:800;border-radius:7px}.trend-svg{display:block;width:100%;height:260px;min-width:760px}.trend-grid{stroke:var(--line);stroke-width:1}.trend-axis{fill:var(--muted);font-size:10px}.trend-line{fill:none;stroke-width:3;stroke-linejoin:round;stroke-linecap:round}.trend-point{stroke:var(--panel);stroke-width:2}
@media(prefers-color-scheme:dark){:root{--bg:#0c1220;--panel:#121a2a;--ink:#eef3fb;--muted:#9ba9bd;--line:#28354a;--soft:#182743;--shadow:none}}
</style>
</head>
<body><div id="login" class="login-shell"><form id="loginForm" class="login-card" autocomplete="on"><div class="eyebrow">Restricted Report</div><h1>登录查看报告</h1><p>请输入获授权的邮箱与密码。</p><label class="field">邮箱<input id="email" type="email" autocomplete="username" required></label><label class="field">密码<input id="password" type="password" autocomplete="current-password" required></label><button id="loginButton" type="submit">登录</button><div id="loginError" class="login-error" role="alert" aria-live="polite"></div><p class="access-note">仅授权名单内的邮箱可以访问。</p></form></div><main id="report" hidden>
<header class="hero"><div class="eyebrow">Daily Delivery · ZA</div><h1>Amazon ZA 每日交付报告</h1><p>包名:com.amazon.mShop.android.shopping。聚焦 repostback 交付、E1+E2 转化与 Midas / Payable spend。</p><div class="status"><span class="dot"></span><span id="range">正在载入数据…</span></div></header>
<section><h2>Executive Summary</h2><div id="summaryText" class="panel takeaway">载入中…</div></section>
<header class="hero"><div class="eyebrow">Daily Delivery · ZA</div><h1>Amazon - ZA daily tracker</h1><p>包名:com.amazon.mShop.android.shopping。聚焦 repostback 交付、E1+E2 转化与 Midas / Payable spend。</p><div class="status"><span class="dot"></span><span id="range">正在载入数据…</span></div></header>
<section><h2>核心指标</h2><div class="summary" id="cards"></div></section>
<section><h2>8 月预算消耗</h2><div id="budgetText" class="takeaway"></div><div class="summary" id="budgetCards" style="margin-top:14px"></div><div class="panel"><div class="chart-title">月度预算使用进度</div><div class="chart-sub">预算按 E1+E2 × 49.50 ZAR 扣减</div><div class="progress"><div id="budgetProgress" class="progress-fill"></div></div><div class="progress-labels"><span id="budgetUsed"></span><span id="budgetTotal"></span></div></div></section>
<section><h2>每日交付与转化</h2><div class="takeaway"><strong>如何阅读:</strong>柱状图展示本月截至数据日的逐日 repostback 交付;结合 E1+E2% 判断每日转化效率,整月完整日期则保留在下方明细表。</div><div class="charts"><div class="panel chart"><div class="chart-head"><div class="chart-title">每日 Install、Event1 与 Event2</div><div class="chart-sub">均取 repostback;按 ZA 日期汇总</div></div><div id="deliveryChart" class="bars"></div><div class="legend"><span><i class="swatch" style="background:var(--blue)"></i>Install</span><span><i class="swatch" style="background:var(--gold)"></i>Event1</span><span><i class="swatch" style="background:var(--orange)"></i>Event2</span></div></div><div class="panel chart"><div class="chart-head"><div class="chart-title">每日 E1+E2%</div><div class="chart-sub">(Event1 + Event2) ÷ Install</div></div><div id="rateChart" class="bars rate-bars"></div></div></div></section>
<section><h2>消耗对比</h2><div id="spendText" class="takeaway"></div><div class="panel chart"><div class="chart-head"><div class="chart-title">Midas spend 与 Payable spend</div><div class="chart-sub">USD;Payable spend = (E1 + E2) × $3</div></div><div id="spendChart" class="bars"></div><div class="legend"><span><i class="swatch" style="background:var(--blue)"></i>Midas spend</span><span><i class="swatch" style="background:var(--gold)"></i>Payable spend</span></div></div></section>
<section><h2>8 月每日明细</h2><div class="panel" style="overflow-x:auto"><table><thead><tr><th>日期</th><th>Install</th><th>Event1</th><th>Event2</th><th>Total</th><th>Event rate</th><th>Payable (ZAR)</th><th>日预算</th><th>FFR</th><th>Midas (USD)</th><th>eCPI</th></tr></thead><tbody id="rows"></tbody></table><div class="footer-note">口径:Install、Event1、Event2 均取 repostback;Total = E1+E2;FFR = Total ÷ Daily cap。灰色日期为数据截止日之后的剩余月份。</div></div></section>
<section><h2>每日交付与转化</h2><div class="takeaway"><strong>如何阅读:</strong>Install 仅取交付 repostback,不包含 app open;消耗趋势对比每日 Midas 与 Payable spend,转化趋势用于定位 Event rate 波动。</div><div class="panel chart"><div class="chart-head"><div class="chart-title">本月每日消耗趋势</div><div class="chart-sub">USD;Midas spend 与 Payable spend</div></div><div id="spendTrend"></div><div class="legend"><span><i class="swatch" style="background:var(--blue)"></i>Midas spend</span><span><i class="swatch" style="background:var(--gold)"></i>Payable spend</span></div></div><div class="charts"><div class="panel chart"><div class="chart-head"><div class="chart-title">每日 Install</div><div class="chart-sub">仅取 delivery repostback,排除 af_app_opened</div></div><div id="installChart" class="bars"></div></div><div class="panel chart"><div class="chart-head"><div class="chart-title">E1+E2% 趋势</div><div class="chart-sub">(Event1 + Event2) ÷ Install</div></div><div id="rateTrend"></div></div></div></section>
<section><h2>8 月每日明细</h2><div class="panel table-wrap"><table><thead><tr><th>日期</th><th>Install</th><th>Event1</th><th>Event2</th><th>Total</th><th>Event rate</th><th>Payable (ZAR)</th><th>日预算</th><th>FFR</th><th>Midas (USD)</th></tr></thead><tbody id="rows"></tbody></table><div class="footer-note">口径:Install 仅取交付 repostback;Total = E1+E2;FFR = Total ÷ Daily cap。Event rate 较前一日波动 ≥5 个百分点时突出显示;灰色日期为数据截止日之后。</div></div></section>
<section><h2>自然周汇总</h2><div class="panel table-wrap"><table><thead><tr><th>自然周(周一至周日)</th><th>Install</th><th>Event1+2</th><th>Event1+2%</th><th>Payable spend</th><th>Midas spend</th></tr></thead><tbody id="weeklyRows"></tbody></table><div class="footer-note">金额为 USD;首周和末周按 8 月自然月边界截取,当前周统计至数据截止日。</div></div></section>
<section><h2>建议关注</h2><div class="panel"><ul><li>优先关注 FFR 明显低于 100% 的日期,判断是流量不足、事件率下降还是日 cap 执行问题。</li><li>剩余预算需要的日均消耗已高于当前日预算;如目标是完整消耗月预算,需要确认是否提高每日 cap。</li><li>对比 Payable spend 与 Midas spend 的日级差额,排查差额扩大日期的事件质量和计费口径。</li></ul></div></section>
</main><script>
const fmt=n=>new Intl.NumberFormat('en-US').format(n), money=n=>'$'+new Intl.NumberFormat('en-US',{minimumFractionDigits:2,maximumFractionDigits:2}).format(n), pct=n=>n==null?'—':n.toFixed(2)+'%';
const label=d=>d.slice(5).replace('-','/');
function bars(el,data,series,max){const showValues=data.length<=12;el.style.minWidth=Math.max(0,data.length*48)+'px';el.innerHTML=data.map(d=>`<div class="bar-group">${series.map(s=>`<div class="bar" style="height:${Math.max(2,d[s.key]/max*100)}%;background:${s.color}">${showValues?`<span>${s.format(d[s.key])}</span>`:''}</div>`).join('')}<div class="bar-label">${label(d.date)}</div></div>`).join('')}
function lineChart(el,data,series,format){const w=Math.max(760,data.length*42),h=260,p={l:48,r:18,t:18,b:34},vals=data.flatMap(d=>series.map(s=>Number(d[s.key])||0)),max=Math.max(...vals,1),min=0,x=i=>p.l+i*(w-p.l-p.r)/Math.max(data.length-1,1),y=v=>h-p.b-(v-min)*(h-p.t-p.b)/(max-min||1),ticks=[0,.25,.5,.75,1];el.innerHTML=`<svg class="trend-svg" viewBox="0 0 ${w} ${h}" role="img">${ticks.map(t=>`<line class="trend-grid" x1="${p.l}" x2="${w-p.r}" y1="${y(max*t)}" y2="${y(max*t)}"/><text class="trend-axis" x="${p.l-7}" y="${y(max*t)+3}" text-anchor="end">${format(max*t)}</text>`).join('')}${data.map((d,i)=>`<text class="trend-axis" x="${x(i)}" y="${h-10}" text-anchor="middle">${label(d.date)}</text>`).join('')}${series.map(s=>`<polyline class="trend-line" stroke="${s.color}" points="${data.map((d,i)=>`${x(i)},${y(d[s.key]||0)}`).join(' ')}"/>${data.map((d,i)=>`<circle class="trend-point" fill="${s.color}" cx="${x(i)}" cy="${y(d[s.key]||0)}" r="3"><title>${d.date} · ${s.name}: ${format(d[s.key]||0)}</title></circle>`).join('')}`).join('')}</svg>`}
const ACCESS={emails:['a91dc567bcdb6d054cf121d7e4016454ee3d316e3b452b851ae4d3087bc99bb2'],salt:'amazon-za-delivery-2026-08',password:'2344c6c9cf72430cafbf48e014d7f721a53484f766f1455f0c12232515ec61e9'};
async function sha256(value){const bytes=new TextEncoder().encode(value);const digest=await crypto.subtle.digest('SHA-256',bytes);return [...new Uint8Array(digest)].map(x=>x.toString(16).padStart(2,'0')).join('')}
function showReport(){document.getElementById('login').hidden=true;document.getElementById('report').hidden=false;loadReport()}
async function loadReport(){fetch('data.json',{cache:'no-store'}).then(r=>{if(!r.ok)throw Error('data.json '+r.status);return r.json()}).then(data=>{
const t=data.totals,b=data.budget,all=data.daily,d=all.filter(x=>x.is_actual),latest=d[d.length-1],first=d[0];document.getElementById('range').textContent=`2026-08-01 至 2026-08-31 · 数据截至 ${data.meta.data_cutoff}`;
const delta=first&&latest?latest.e1e2_rate-first.e1e2_rate:0;document.getElementById('summaryText').innerHTML=`<strong>截至 ${data.meta.data_cutoff},累计 ${fmt(t.install)} Install,产生 ${fmt(t.e1e2)} 个 E1+E2,整体转化率 ${pct(t.e1e2_rate)}。</strong> 已消耗月预算 ${pct(b.used_rate)},当前消耗进度相当于同期预算的 ${pct(b.pacing_rate)}。按当前日均速度推算,月底预计${b.projected_month_variance_zar>=0?'结余':'超支'} ZAR ${fmt(Math.abs(b.projected_month_variance_zar))}。`;
const cards=[['Install',fmt(t.install),'af_app_opened repostback'],['E1 + E2',fmt(t.e1e2),`${fmt(t.event1)} E1 · ${fmt(t.event2)} E2`],['E1+E2%',pct(t.e1e2_rate),'累计 E1+E2 ÷ 累计 Install'],['Payable spend',money(t.payable_spend),`Midas spend ${money(t.midas_spend)}`]];document.getElementById('cards').innerHTML=cards.map(x=>`<div class="card"><div class="label">${x[0]}</div><div class="value">${x[1]}</div><div class="note">${x[2]}</div></div>`).join('');
const budgetCards=[['月度预算','R '+fmt(b.monthly_budget_zar),money(b.monthly_budget_usd)],['已用预算','R '+fmt(b.used_budget_zar),pct(b.used_rate)+' of month'],['剩余预算','R '+fmt(b.remaining_budget_zar),money(b.remaining_budget_usd)],['剩余日均需求','R '+fmt(b.required_daily_budget_zar),`${fmt(b.required_daily_events)} E1+E2 / day`]];document.getElementById('budgetCards').innerHTML=budgetCards.map(x=>`<div class="card"><div class="label">${x[0]}</div><div class="value">${x[1]}</div><div class="note">${x[2]}</div></div>`).join('');
const t=data.totals,b=data.budget,all=data.daily,d=all.filter(x=>x.is_actual);document.getElementById('range').textContent=`2026-08-01 至 2026-08-31 · 数据截至 ${data.meta.data_cutoff}`;
const cards=[['Install',fmt(t.install),'仅 delivery repostback;排除 app open'],['E1 + E2',fmt(t.e1e2),`${fmt(t.event1)} E1 · ${fmt(t.event2)} E2`],['E1+E2%',pct(t.e1e2_rate),'累计 E1+E2 ÷ 累计 Install'],['Payable spend',money(t.payable_spend),`Midas spend ${money(t.midas_spend)}`]];document.getElementById('cards').innerHTML=cards.map(x=>`<div class="card"><div class="label">${x[0]}</div><div class="value">${x[1]}</div><div class="note">${x[2]}</div></div>`).join('');
const budgetCards=[['月度预算','R '+fmt(b.monthly_budget_zar),money(b.monthly_budget_usd)],['已用预算','R '+fmt(b.used_budget_zar),`${pct(b.used_rate)} used · MTD expected FFR ${pct(b.mtd_expected_ffr)}`],['剩余预算','R '+fmt(b.remaining_budget_zar),money(b.remaining_budget_usd)],['剩余日均需求','R '+fmt(b.required_daily_budget_zar),`${fmt(b.required_daily_events)} E1+E2 / day`]];document.getElementById('budgetCards').innerHTML=budgetCards.map(x=>`<div class="card"><div class="label">${x[0]}</div><div class="value">${x[1]}</div><div class="note">${x[2]}</div></div>`).join('');
document.getElementById('budgetText').innerHTML=`<strong>预算消耗低于截至当前日期的均匀进度。</strong> 已用 R ${fmt(b.used_budget_zar)},同期预算应为 R ${fmt(b.expected_budget_to_date_zar)};剩余 ${b.remaining_days} 天需要日均 R ${fmt(b.required_daily_budget_zar)},高于当前日预算 R ${fmt(b.daily_budget_zar)}。`;
document.getElementById('budgetProgress').style.width=Math.min(b.used_rate,100)+'%';document.getElementById('budgetUsed').textContent=`已用 ${pct(b.used_rate)} · R ${fmt(b.used_budget_zar)}`;document.getElementById('budgetTotal').textContent=`总预算 R ${fmt(b.monthly_budget_zar)}`;
bars(document.getElementById('deliveryChart'),d,[{key:'install',color:'var(--blue)',format:fmt},{key:'event1',color:'var(--gold)',format:fmt},{key:'event2',color:'var(--orange)',format:fmt}],Math.max(...d.flatMap(x=>[x.install,x.event1,x.event2]),1));
bars(document.getElementById('rateChart'),d,[{key:'e1e2_rate',color:'var(--orange)',format:pct}],Math.max(...d.map(x=>x.e1e2_rate||0),1));
bars(document.getElementById('spendChart'),d,[{key:'midas_spend',color:'var(--blue)',format:money},{key:'payable_spend',color:'var(--gold)',format:money}],Math.max(...d.flatMap(x=>[x.midas_spend,x.payable_spend]),1));
const gap=t.payable_spend-t.midas_spend;document.getElementById('spendText').innerHTML=`<strong>累计 Payable spend ${gap>=0?'高于':'低于'} Midas spend ${money(Math.abs(gap))}。</strong> 该差额来自约定的事件计费公式与平台实际消耗之间的口径差异,不应直接解读为利润。`;
document.getElementById('rows').innerHTML=all.map(x=>`<tr class="${x.is_actual?'':'future'}"><td>${x.date}</td><td>${fmt(x.install)}</td><td>${fmt(x.event1)}</td><td>${fmt(x.event2)}</td><td>${fmt(x.e1e2)}</td><td>${pct(x.e1e2_rate)}</td><td>R ${fmt(x.payable_spend_zar)}</td><td>R ${fmt(x.daily_budget_zar)}</td><td>${pct(x.ffr_rate)}</td><td>${money(x.midas_spend)}</td><td>${x.ecpi_usd==null?'—':money(x.ecpi_usd)}</td></tr>`).join('');
}).catch(e=>{document.getElementById('summaryText').className='error';document.getElementById('summaryText').textContent='数据载入失败:'+e.message})}
lineChart(document.getElementById('spendTrend'),d,[{key:'midas_spend',name:'Midas spend',color:'var(--blue)'},{key:'payable_spend',name:'Payable spend',color:'var(--gold)'}],v=>'$'+Math.round(v));
bars(document.getElementById('installChart'),d,[{key:'install',color:'var(--blue)',format:fmt}],Math.max(...d.map(x=>x.install),1));
lineChart(document.getElementById('rateTrend'),d,[{key:'e1e2_rate',name:'E1+E2%',color:'var(--orange)'}],v=>v.toFixed(0)+'%');
document.getElementById('rows').innerHTML=all.map((x,i)=>{const prev=i?all[i-1]:null,spike=x.is_actual&&prev&&prev.is_actual&&Math.abs((x.e1e2_rate||0)-(prev.e1e2_rate||0))>=5;return `<tr class="${x.is_actual?'':'future'}"><td>${x.date}</td><td>${fmt(x.install)}</td><td>${fmt(x.event1)}</td><td>${fmt(x.event2)}</td><td>${fmt(x.e1e2)}</td><td class="${spike?'rate-spike':''}">${pct(x.e1e2_rate)}</td><td>R ${fmt(x.payable_spend_zar)}</td><td>R ${fmt(x.daily_budget_zar)}</td><td>${pct(x.ffr_rate)}</td><td>${money(x.midas_spend)}</td></tr>`}).join('');
document.getElementById('weeklyRows').innerHTML=data.weekly.map(w=>`<tr><td>${w.label}</td><td>${fmt(w.install)}</td><td>${fmt(w.e1e2)}</td><td>${pct(w.e1e2_rate)}</td><td>${money(w.payable_spend)}</td><td>${money(w.midas_spend)}</td></tr>`).join('');
}).catch(e=>{document.getElementById('range').textContent='数据载入失败:'+e.message})}
document.getElementById('loginForm').addEventListener('submit',async e=>{e.preventDefault();const button=document.getElementById('loginButton'),error=document.getElementById('loginError');button.disabled=true;error.textContent='';try{const email=document.getElementById('email').value.trim().toLowerCase(),password=document.getElementById('password').value;const [emailHash,passwordHash]=await Promise.all([sha256(email),sha256(ACCESS.salt+':'+password)]);if(ACCESS.emails.includes(emailHash)&&passwordHash===ACCESS.password){sessionStorage.setItem('amazonZaAccess','granted');showReport()}else{error.textContent='邮箱或密码不正确。'}}catch(_){error.textContent='当前浏览器无法完成验证,请更换现代浏览器。'}finally{button.disabled=false}});
if(sessionStorage.getItem('amazonZaAccess')==='granted')showReport();
</script></body></html>
+29 -5
View File
@@ -23,12 +23,14 @@ unit_price_zar = 49.5
fx_zar_per_usd = 16.5
spend = defaultdict(float)
repostback_installs = defaultdict(int)
with (root / "source-delivery.csv").open(encoding="utf-8-sig", newline="") as f:
for row in csv.DictReader(f):
if row.get("广告包") == package and row.get("国家") == geo:
day = row.get("日期", "")
if len(day) == 8 and day.isdigit():
spend[day] += float(row.get("平台消耗") or 0)
repostback_installs[day] += int(float(row.get("归因安装") or 0))
events = defaultdict(lambda: defaultdict(int))
with (root / "source-events.csv").open(encoding="utf-8-sig", newline="") as f:
@@ -38,7 +40,7 @@ with (root / "source-events.csv").open(encoding="utf-8-sig", newline="") as f:
if len(row) < 7 or row[2] != package or row[3] != geo:
continue
name, day = row[0], row[1]
if name not in {"af_app_opened", "event1", "event2"}:
if name not in {"event1", "event2"}:
continue
# The source export leaves its last three headers blank. The second
# numeric column after midas_campaign_id is the repostback count.
@@ -46,8 +48,7 @@ with (root / "source-events.csv").open(encoding="utf-8-sig", newline="") as f:
repostback = int(float(row[6] or 0))
except (ValueError, TypeError):
repostback = 0
key = "install" if name == "af_app_opened" else name
events[day][key] += repostback
events[day][name] += repostback
source_days = sorted(set(spend) | set(events))
data_cutoff = source_days[-1] if source_days else None
@@ -58,7 +59,7 @@ while cursor <= launch_end:
cursor += timedelta(days=1)
daily = []
for day in days:
install = events[day]["install"]
install = repostback_installs[day]
event1 = events[day]["event1"]
event2 = events[day]["event2"]
conversions = event1 + event2
@@ -123,8 +124,30 @@ budget = {
"required_daily_events": round(remaining_budget_zar / remaining_days / unit_price_zar) if remaining_days else 0,
"projected_month_spend_zar": round(projected_month_spend, 2),
"projected_month_variance_zar": round(monthly_budget_zar - projected_month_spend, 2),
"mtd_expected_ffr": round(min(datetime.now().day, 31) / 31 * 100, 2),
}
weeks = []
for row in actual_daily:
row_date = datetime.strptime(row["date"], "%Y-%m-%d").date()
week_start = row_date - timedelta(days=row_date.weekday())
week_end = week_start + timedelta(days=6)
label_start = max(week_start, launch_start)
label_end = min(week_end, launch_end)
key = week_start.isoformat()
if not weeks or weeks[-1]["key"] != key:
weeks.append({"key": key, "label": f"{label_start.strftime('%b %d')}–{label_end.strftime('%b %d')}", "install": 0, "event1": 0, "event2": 0, "e1e2": 0, "payable_spend": 0.0, "midas_spend": 0.0})
week = weeks[-1]
for metric in ("install", "event1", "event2", "e1e2"):
week[metric] += row[metric]
week["payable_spend"] += row["payable_spend"]
week["midas_spend"] += row["midas_spend"]
for week in weeks:
week["e1e2_rate"] = round(week["e1e2"] / week["install"] * 100, 2) if week["install"] else None
week["payable_spend"] = round(week["payable_spend"], 2)
week["midas_spend"] = round(week["midas_spend"], 2)
week.pop("key", None)
payload = {
"meta": {
"package": package,
@@ -134,7 +157,7 @@ payload = {
"date_end": daily[-1]["date"] if daily else None,
"data_cutoff": f"{data_cutoff[:4]}-{data_cutoff[4:6]}-{data_cutoff[6:]}" if data_cutoff else None,
"currency": "USD",
"install_definition": "af_app_opened repostback",
"install_definition": "delivery repostback (attributed installs); af_app_opened excluded",
"event_definition": "event1/event2 repostback",
"rate_definition": "(event1 + event2) / Install",
"payable_definition": "(event1 + event2) × $3",
@@ -142,6 +165,7 @@ payload = {
"totals": totals,
"budget": budget,
"daily": daily,
"weekly": weeks,
}
tmp = root / "data.json.tmp"