diff --git a/index.html b/index.html
index a483ac8..a287182 100644
--- a/index.html
+++ b/index.html
@@ -7,11 +7,11 @@
Amazon ZA 每日交付报告
-
+
@@ -23,7 +23,10 @@
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){el.innerHTML=data.map(d=>`${series.map(s=>`
${s.format(d[s.key])}
`).join('')}
${label(d.date)}
`).join('')}
-fetch('data.json',{cache:'no-store'}).then(r=>{if(!r.ok)throw Error('data.json '+r.status);return r.json()}).then(data=>{
+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,d=data.daily,latest=d[d.length-1],first=d[0];document.getElementById('range').textContent=`${data.meta.date_start} 至 ${data.meta.date_end} · 每日快照`;
const delta=first&&latest?latest.e1e2_rate-first.e1e2_rate:0;document.getElementById('summaryText').innerHTML=`${d.length} 天累计 ${fmt(t.install)} Install,产生 ${fmt(t.e1e2)} 个 E1+E2,整体转化率 ${pct(t.e1e2_rate)}。 Midas spend 为 ${money(t.midas_spend)},按每个 E1/E2 事件 $3 计算的 Payable spend 为 ${money(t.payable_spend)}。窗口首尾 E1+E2% ${delta>=0?'上升':'下降'} ${Math.abs(delta).toFixed(2)} 个百分点;由于仅有 ${d.length} 天数据,应作为短期交付快照解读。`;
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=>``).join('');
@@ -32,5 +35,7 @@ fetch('data.json',{cache:'no-store'}).then(r=>{if(!r.ok)throw Error('data.json '
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=`累计 Payable spend ${gap>=0?'高于':'低于'} Midas spend ${money(Math.abs(gap))}。 该差额来自约定的事件计费公式与平台实际消耗之间的口径差异,不应直接解读为利润。`;
document.getElementById('rows').innerHTML=d.slice().reverse().map(x=>`| ${x.date} | ${fmt(x.install)} | ${fmt(x.event1)} | ${fmt(x.event2)} | ${pct(x.e1e2_rate)} | ${money(x.midas_spend)} | ${money(x.payable_spend)} |
`).join('');
-}).catch(e=>{document.getElementById('summaryText').className='error';document.getElementById('summaryText').textContent='数据载入失败:'+e.message});
+}).catch(e=>{document.getElementById('summaryText').className='error';document.getElementById('summaryText').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();