feat: 报告改为数据驱动,每日 09:00 由服务器自动刷新 data.json

This commit is contained in:
2026-09-09 17:05:18 +08:00
parent e06e3f02e4
commit 03ddc19276
+114 -81
View File
@@ -8,7 +8,6 @@
:root{
--rose:#C4506A;
--rose-dark:#a63f57;
--rose-600:#b3445e;
--rose-100:#f9e8ec;
--rose-50:#fdf3f5;
--ink:#2D1B20;
@@ -33,28 +32,24 @@
}
.wrap{max-width:980px;margin:0 auto;padding:40px 24px 72px}
/* header */
header{padding:34px 32px 28px;background:linear-gradient(135deg,#2D1B20 0%,#4a2430 55%,#C4506A 130%);border-radius:18px;color:#fff;margin-bottom:22px}
header .eyebrow{font-size:12px;letter-spacing:2px;opacity:.75;text-transform:uppercase}
header h1{font-size:28px;font-weight:700;margin-top:8px;letter-spacing:.5px}
header p{margin-top:10px;font-size:14px;opacity:.85}
.meta{display:inline-block;margin-top:16px;font-size:12.5px;padding:5px 13px;border-radius:999px;background:rgba(255,255,255,.14);letter-spacing:.5px}
/* KPI */
.kpis{display:grid;grid-template-columns:repeat(5,1fr);gap:12px;margin-bottom:30px}
.kpi{background:var(--white);border:1px solid var(--line);border-radius:14px;padding:18px 16px;text-align:left}
.kpi .num{font-size:30px;font-weight:700;color:var(--rose);font-variant-numeric:tabular-nums;line-height:1.1}
.kpi .lbl{font-size:12.5px;color:var(--ink-50);margin-top:6px;letter-spacing:.3px}
.kpi.alt .num{color:var(--ink)}
/* sections */
section{margin-bottom:32px}
.sec-head{display:flex;align-items:baseline;gap:10px;margin-bottom:14px}
.sec-head h2{font-size:19px;font-weight:700}
.sec-head .count{font-size:13px;color:var(--ink-50)}
.card{background:var(--white);border:1px solid var(--line);border-radius:14px;overflow:hidden}
/* tables */
table{width:100%;border-collapse:collapse;font-size:13.5px}
thead th{font-size:11.5px;text-transform:uppercase;letter-spacing:.8px;color:var(--ink-50);font-weight:600;text-align:left;padding:12px 16px;background:#faf3f4;border-bottom:1px solid var(--line)}
tbody td{padding:11px 16px;border-bottom:1px solid var(--line);vertical-align:top}
@@ -71,26 +66,23 @@
.repo-list{color:var(--ink-70);font-size:12.5px}
.repo-list .r{display:inline-block;background:var(--rose-50);color:var(--rose-dark);border-radius:6px;padding:1px 7px;margin:2px 3px 2px 0;font-size:11.5px}
/* group blocks */
.group{margin-bottom:18px}
.group>.g-title{font-size:14px;font-weight:700;margin-bottom:8px;display:flex;align-items:center;gap:8px}
.g-title .dot{width:8px;height:8px;border-radius:50%;display:inline-block}
/* chips (未登录) */
.chips{display:flex;flex-wrap:wrap;gap:8px}
.chip{background:var(--white);border:1px solid var(--line);border-radius:999px;padding:6px 14px;font-size:13px;color:var(--ink-70)}
.chip b{color:var(--ink)}
.chip .tag{font-size:10.5px;color:var(--rose-dark);background:var(--rose-100);border-radius:4px;padding:1px 5px;margin-left:5px}
/* findings */
.finding{display:flex;gap:14px;padding:14px 16px;border-bottom:1px solid var(--line)}
.finding:last-child{border-bottom:none}
.finding .idx{flex:none;width:26px;height:26px;border-radius:8px;background:var(--rose-100);color:var(--rose-dark);font-weight:700;font-size:13px;display:flex;align-items:center;justify-content:center}
.finding .f-body{font-size:13.5px;color:var(--ink-70)}
.finding .f-body b{color:var(--ink)}
footer{margin-top:36px;text-align:center;font-size:12px;color:var(--ink-50)}
.table-scroll{overflow-x:auto}
.empty{text-align:center;padding:28px;color:var(--ink-50);font-size:13.5px}
@media (max-width:760px){
.wrap{padding:20px 14px 56px}
@@ -109,125 +101,166 @@
<div class="eyebrow">AgentStage · Ops Report</div>
<h1>使用情况统计</h1>
<p>账号开通、登录、报告上线一屏总览,方便跟进未激活的同学。</p>
<span class="meta">统计时间:2026-09-09</span>
<span class="meta" id="gen-meta">统计时间:加载中…</span>
</header>
<div class="kpis">
<div class="kpi"><div class="num">23</div><div class="lbl">账号总数</div></div>
<div class="kpi"><div class="num">12</div><div class="lbl">已登录</div></div>
<div class="kpi alt"><div class="num">11</div><div class="lbl">从未登录</div></div>
<div class="kpi"><div class="num">17</div><div class="lbl">已上线报告</div></div>
<div class="kpi alt"><div class="num">9</div><div class="lbl">建仓人数</div></div>
<div class="kpi"><div class="num" id="k-total">—</div><div class="lbl">账号总数</div></div>
<div class="kpi"><div class="num" id="k-in">—</div><div class="lbl">已登录</div></div>
<div class="kpi alt"><div class="num" id="k-never">—</div><div class="lbl">从未登录</div></div>
<div class="kpi"><div class="num" id="k-reports">—</div><div class="lbl">已上线报告</div></div>
<div class="kpi alt"><div class="num" id="k-owners">—</div><div class="lbl">建仓人数</div></div>
</div>
<section>
<div class="sec-head"><h2>人员使用情况</h2><span class="count">共 23 人</span></div>
<div class="sec-head"><h2>人员使用情况</h2><span class="count" id="c-users"></span></div>
<div class="group">
<div class="g-title"><span class="dot" style="background:#2e7d4f"></span>已跑通 · 登录 + 2FA + token + 已上线报告(7 人)</div>
<div class="g-title"><span class="dot" style="background:#2e7d4f"></span><span id="g-active">已跑通 · 已登录且有报告</span></div>
<div class="card table-scroll">
<table>
<thead><tr><th>账号</th><th>最后登录</th><th>报告</th><th>已上线</th></tr></thead>
<tbody>
<tr><td class="acct">zouyun</td><td class="num-mono">08-28</td><td class="num-mono">4</td><td><span class="repo-list"><span class="r">amazon-za-delivery</span><span class="r">manta-tracking</span><span class="r">manta-tracking-new</span><span class="r">zouyun-amazon-za-daily-report</span></span></td></tr>
<tr><td class="acct">wangwj1</td><td class="num-mono">08-26</td><td class="num-mono">3</td><td><span class="repo-list"><span class="r">king-daily-report</span><span class="r">ru-ozon-dailyreport</span><span class="r">top10-ffr</span></span></td></tr>
<tr><td class="acct">fangjie</td><td class="num-mono">08-24</td><td class="num-mono">2</td><td><span class="repo-list"><span class="r">mediabuy-wh</span><span class="r">manta-audience-manual</span></span></td></tr>
<tr><td class="acct">liuji</td><td class="num-mono">08-26</td><td class="num-mono">2</td><td><span class="repo-list"><span class="r">agency-report</span><span class="r">cn-am-report</span></span></td></tr>
<tr><td class="acct">caoxiaoqi</td><td class="num-mono">08-31</td><td class="num-mono">1</td><td><span class="repo-list"><span class="r">eg-nagwa-daily-report</span></span></td></tr>
<tr><td class="acct">wangyuan</td><td class="num-mono">08-24</td><td class="num-mono">1</td><td><span class="repo-list"><span class="r">moboos-ad-report</span></span></td></tr>
<tr><td class="acct">yinly_sh</td><td class="num-mono">08-25</td><td class="num-mono">1</td><td><span class="repo-list"><span class="r">traffic-weekly-report</span></span></td></tr>
</tbody>
<tbody id="tb-active"></tbody>
</table>
</div>
</div>
<div class="group">
<div class="g-title"><span class="dot" style="background:#b07a1e"></span>已登录 · 已配 token,但还没建报告(3 人)</div>
<div class="g-title"><span class="dot" style="background:#b07a1e"></span><span id="g-partial">已登录 · 还没建报告</span></div>
<div class="card table-scroll">
<table>
<thead><tr><th>账号</th><th>最后登录</th><th>2FA</th><th>备注</th></tr></thead>
<tbody>
<tr><td class="acct">liyx</td><td class="num-mono">08-24</td><td><span class="pill ok">已绑</span></td><td class="repo-list">已生成钥匙,待上线首个报告</td></tr>
<tr><td class="acct">jiameng</td><td class="num-mono">08-24</td><td><span class="pill ok">已绑</span></td><td class="repo-list">已生成钥匙,待上线首个报告</td></tr>
<tr><td class="acct">hanxiaoqing</td><td class="num-mono">08-25</td><td><span class="pill warn">未绑 2FA</span></td><td class="repo-list">有 token 但未绑 2FA,需补绑</td></tr>
</tbody>
<thead><tr><th>账号</th><th>最后登录</th><th>钥匙</th><th>备注</th></tr></thead>
<tbody id="tb-partial"></tbody>
</table>
</div>
</div>
<div class="group">
<div class="g-title"><span class="dot" style="background:#C4506A"></span>管理员 / pilot(2 人)</div>
<div class="g-title"><span class="dot" style="background:#C4506A"></span><span id="g-staff">管理员 / pilot</span></div>
<div class="card table-scroll">
<table>
<thead><tr><th>账号</th><th>角色</th><th>报告</th></tr></thead>
<tbody>
<tr><td class="acct">summer</td><td><span class="pill rose">管理员</span></td><td><span class="repo-list"><span class="r">brand</span></span></td></tr>
<tr><td class="acct">wangwj</td><td><span class="pill rose">pilot</span></td><td><span class="repo-list"><span class="r">demo</span><span class="r">instruction</span></span></td></tr>
</tbody>
<tbody id="tb-staff"></tbody>
</table>
</div>
</div>
<div class="group">
<div class="g-title"><span class="dot" style="background:#9a8f8f"></span>从未登录(11 人)</div>
<div class="g-title"><span class="dot" style="background:#9a8f8f"></span><span id="g-inactive">从未登录</span></div>
<div class="card" style="padding:16px">
<div class="chips">
<span class="chip"><b>zhangyujia</b></span>
<span class="chip"><b>lilin</b></span>
<span class="chip"><b>yangyanming</b></span>
<span class="chip"><b>cop.fengtong</b></span>
<span class="chip"><b>cop.wangyuting</b></span>
<span class="chip"><b>gengxx</b></span>
<span class="chip"><b>chenqiaoli</b></span>
<span class="chip">jiasiyuan <span class="sub">新</span></span>
<span class="chip">liuxiaoxiao <span class="sub">新</span></span>
<span class="chip">huanglu <span class="sub">新</span></span>
<span class="chip">hanguangming <span class="sub">新</span></span>
</div>
<p style="font-size:12px;color:var(--ink-50);margin-top:12px">其中 zhangyujia~chenqiaoli 为 8/22 批次(开通近三周未登录);jiasiyuan~hanguangming 为 9/9 今日新增。</p>
<div class="chips" id="chips-inactive"></div>
</div>
</div>
</section>
<section>
<div class="sec-head"><h2>报告清单</h2><span class="count">共 17 份</span></div>
<div class="sec-head"><h2>报告清单</h2><span class="count" id="c-reports"></span></div>
<div class="card table-scroll">
<table>
<thead><tr><th>报告</th><th>归属</th><th>自动刷新</th><th>最近刷新</th></tr></thead>
<tbody>
<tr><td class="acct">demo</td><td>wangwj</td><td><span class="pill ok">有</span></td><td class="num-mono">09-09 16:04</td></tr>
<tr><td class="acct">manta-tracking</td><td>zouyun</td><td><span class="pill ok">有</span></td><td class="num-mono">09-09 16:04</td></tr>
<tr><td class="acct">eg-nagwa-daily-report</td><td>caoxiaoqi</td><td><span class="pill ok">有</span></td><td class="num-mono">09-09 13:02</td></tr>
<tr><td class="acct">manta-tracking-new</td><td>zouyun</td><td><span class="pill ok">有</span></td><td class="num-mono">09-09 10:05</td></tr>
<tr><td class="acct">mediabuy-wh</td><td>fangjie</td><td><span class="pill ok">有</span></td><td class="num-mono">09-09 09:03</td></tr>
<tr><td class="acct">moboos-ad-report</td><td>wangyuan</td><td><span class="pill ok">有</span></td><td class="num-mono">09-09 03:05</td></tr>
<tr><td class="acct">agency-report</td><td>liuji</td><td><span class="pill ok">有</span></td><td class="num-mono">09-09 02:05</td></tr>
<tr><td class="acct">amazon-za-delivery</td><td>zouyun</td><td><span class="pill ok">有</span></td><td class="num-mono">09-08 23:02</td></tr>
<tr><td class="acct">cn-am-report</td><td>liuji</td><td><span class="pill ok">有</span></td><td class="num-mono">09-08 23:02</td></tr>
<tr><td class="acct">ru-ozon-dailyreport</td><td>wangwj1</td><td><span class="pill warn">已停更</span></td><td class="num-mono">08-26</td></tr>
<tr><td class="acct">brand</td><td>summer</td><td><span class="pill mut">静态</span></td><td class="num-mono">—</td></tr>
<tr><td class="acct">instruction</td><td>wangwj</td><td><span class="pill mut">静态</span></td><td class="num-mono">—</td></tr>
<tr><td class="acct">king-daily-report</td><td>wangwj1</td><td><span class="pill mut">静态</span></td><td class="num-mono">—</td></tr>
<tr><td class="acct">manta-audience-manual</td><td>fangjie</td><td><span class="pill mut">静态</span></td><td class="num-mono">—</td></tr>
<tr><td class="acct">top10-ffr</td><td>wangwj1</td><td><span class="pill mut">静态</span></td><td class="num-mono">—</td></tr>
<tr><td class="acct">traffic-weekly-report</td><td>yinly_sh</td><td><span class="pill mut">静态</span></td><td class="num-mono">—</td></tr>
<tr><td class="acct">zouyun-amazon-za-daily-report</td><td>zouyun</td><td><span class="pill mut">静态</span></td><td class="num-mono">—</td></tr>
</tbody>
<tbody id="tb-reports"></tbody>
</table>
</div>
</section>
<section>
<div class="sec-head"><h2>关键发现</h2></div>
<div class="card">
<div class="finding"><div class="idx">1</div><div class="f-body"><b>8/22 批次还有 7 人从未登录</b>:zhangyujia、lilin、yangyanming、cop.fengtong、cop.wangyuting、gengxx、chenqiaoli。开通近三周还没进来,建议跟进。</div></div>
<div class="finding"><div class="idx">2</div><div class="f-body"><b>hanxiaoqing 状态异常</b>:已登录、也生成了 token,但没绑 2FA(服务器是强制 2FA,正常登录一定会绑)。可能只用 API 生成的 token、没走完网页登录,建议提醒补绑。</div></div>
<div class="finding"><div class="idx">3</div><div class="f-body"><b>ru-ozon-dailyreport 已停更</b>:现已改成纯静态(无 update.sh),状态文件停在 08-26。若属有意改静态则正常,否则需 wangwj1 补回 update.sh。</div></div>
<div class="finding"><div class="idx">4</div><div class="f-body"><b>最活跃是 zouyun(4 份)、wangwj1(3 份)</b>,两人贡献了 17 份报告里的 7 份。</div></div>
</div>
<div class="card" id="findings"></div>
</section>
<footer>AgentStage · 使用情况统计 · 自动生成于 2026-09-09</footer>
<footer id="foot">AgentStage · 使用情况统计</footer>
</div>
<script>
function esc(s){
return String(s==null?'':s).replace(/[&<>"']/g, function(c){
return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c];
});
}
function repoChips(repos){
if(!repos || !repos.length) return '<span class="num-mono">—</span>';
return '<span class="repo-list">'+repos.map(function(r){return '<span class="r">'+esc(r)+'</span>';}).join('')+'</span>';
}
function statusPill(s){
if(s==='auto') return '<span class="pill ok">有</span>';
if(s==='stale') return '<span class="pill warn">已停更</span>';
return '<span class="pill mut">静态</span>';
}
fetch('data.json')
.then(function(r){ if(!r.ok) throw new Error('HTTP '+r.status); return r.json(); })
.then(function(d){
document.getElementById('gen-meta').textContent = '统计时间:' + d.generated_at;
document.getElementById('k-total').textContent = d.summary.total;
document.getElementById('k-in').textContent = d.summary.logged_in;
document.getElementById('k-never').textContent = d.summary.never;
document.getElementById('k-reports').textContent = d.summary.reports;
document.getElementById('k-owners').textContent = d.summary.owners;
document.getElementById('c-users').textContent = '共 ' + d.summary.total + ' 人';
document.getElementById('c-reports').textContent = '共 ' + d.summary.reports + ' 份';
var el;
// active
document.getElementById('g-active').textContent =
'已跑通 · 登录 + 2FA + token + 已上线报告(' + d.active.length + ' 人)';
el = document.getElementById('tb-active');
el.innerHTML = d.active.length ? d.active.map(function(u){
return '<tr><td class="acct">'+esc(u.login)+'</td>'+
'<td class="num-mono">'+esc(u.last_login||'—')+'</td>'+
'<td class="num-mono">'+u.count+'</td>'+
'<td>'+repoChips(u.repos)+'</td></tr>';
}).join('') : '<tr><td colspan="4" class="empty">暂无</td></tr>';
// partial
document.getElementById('g-partial').textContent =
'已登录 · 还没建报告(' + d.partial.length + ' 人)';
el = document.getElementById('tb-partial');
el.innerHTML = d.partial.length ? d.partial.map(function(u){
var k = u.tk > 0 ? '<span class="pill ok">已生成</span>' : '<span class="pill warn">未生成</span>';
var note = u.tk > 0 ? '已生成钥匙,待上线首个报告' : '还没生成钥匙(token),需到设置里生成';
return '<tr><td class="acct">'+esc(u.login)+'</td>'+
'<td class="num-mono">'+esc(u.last_login||'—')+'</td>'+
'<td>'+k+'</td><td class="repo-list">'+note+'</td></tr>';
}).join('') : '<tr><td colspan="4" class="empty">暂无</td></tr>';
// staff
document.getElementById('g-staff').textContent = '管理员 / pilot(' + d.staff.length + ' 人)';
el = document.getElementById('tb-staff');
el.innerHTML = d.staff.map(function(u){
return '<tr><td class="acct">'+esc(u.login)+'</td>'+
'<td><span class="pill rose">'+esc(u.role)+'</span></td>'+
'<td>'+repoChips(u.repos)+'</td></tr>';
}).join('');
// inactive
document.getElementById('g-inactive').textContent = '从未登录(' + d.inactive.length + ' 人)';
el = document.getElementById('chips-inactive');
el.innerHTML = d.inactive.length ? d.inactive.map(function(u){
var tag = u.is_new ? '<span class="tag">新</span>' : '';
return '<span class="chip"><b>'+esc(u.login)+'</b>'+tag+'</span>';
}).join('') : '<span class="empty">暂无</span>';
// reports
el = document.getElementById('tb-reports');
el.innerHTML = d.reports.length ? d.reports.map(function(r){
return '<tr><td class="acct">'+esc(r.name)+'</td>'+
'<td>'+esc(r.owner)+'</td>'+
'<td>'+statusPill(r.status)+'</td>'+
'<td class="num-mono">'+esc(r.last_refresh||'—')+'</td></tr>';
}).join('') : '<tr><td colspan="4" class="empty">暂无</td></tr>';
// findings
el = document.getElementById('findings');
el.innerHTML = d.findings.length ? d.findings.map(function(f,i){
return '<div class="finding"><div class="idx">'+(i+1)+'</div><div class="f-body">'+esc(f)+'</div></div>';
}).join('') : '<div class="empty">暂无</div>';
document.getElementById('foot').textContent = 'AgentStage · 使用情况统计 · 数据生成于 ' + d.generated_at;
})
.catch(function(e){
document.getElementById('gen-meta').textContent = '数据加载失败:' + e.message;
});
</script>
</body>
</html>