chore(design): stats-overhaul 设计 WIP — CONTRACT + ui_kits 统计页规格

stats-overhaul 的设计稿(CONTRACT.md + mobile/tablet/desktop ui_kits)。

注:这批 ui_kits 描述的是统计页「上聚合·下分设备」原方案;统计页后续已
重设计为「月/周/日 周期卡 + 设备下拉 + 两周折线」(见 client/lib/screens/
stats_page.dart)。设计稿与新页布局有出入,待更新到新布局(单列 TODO 跟踪)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-28 18:13:49 +08:00
parent bf84492eef
commit b98ad9dce4
6 changed files with 85 additions and 3 deletions
+2
View File
@@ -144,6 +144,8 @@ const STRINGS = {
durMonth: { zh: '本月时长', en: 'Time' },
weekTraffic: { zh: '本周流量 (GB)', en: 'This week (GB)' },
days7: { zh: ['一','二','三','四','五','六','日'], en: ['M','T','W','T','F','S','S'] },
byDevice: { zh: '设备明细', en: 'By device' },
noDeviceUsage:{ zh: '暂无设备用量', en: 'No device usage yet' },
proMember: { zh: 'PRO 会员', en: 'PRO member' },
expires: { zh: '有效期至', en: 'Expires' },
usage: { zh: '本月用量', en: 'Used this month' },
+26
View File
@@ -298,6 +298,12 @@ function SettingsScreen({ t, lang, setLang, dark, setDark, free, setFree, onRede
function StatsScreen({ t, lang }) {
const vals = [2.1, 3.4, 1.8, 4.6, 5.2, 6.1, 3.0]; const max = 6.1; const labels = t('days7');
const card = { background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--radius-lg)', boxShadow: 'var(--shadow-sm)' };
// 分设备用量(下分设备):名称 + 占比迷你条 + 流量/时长,流量降序。
const devs = [
{ name: 'iPhone 15', icon: 'smartphone', gb: '11.3', h: '5.2', frac: 1.0 },
{ name: 'MacBook Pro', icon: 'laptop', gb: '6.0', h: '3.1', frac: 0.53 },
{ name: 'Pixel 8', icon: 'smartphone', gb: '1.6', h: '1.1', frac: 0.14 },
];
return (
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
<TopBar t={t} lang={lang} />
@@ -323,6 +329,26 @@ function StatsScreen({ t, lang }) {
))}
</div>
</div>
<div style={{ fontSize: 13, fontWeight: 600, color: 'var(--fg1)', margin: '20px 0 12px 2px' }}>{t('byDevice')}</div>
<div style={{ ...card, overflow: 'hidden' }}>
{devs.map((d, i) => (
<div key={d.name} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '14px 16px', borderBottom: i < devs.length - 1 ? '1px solid var(--border)' : 'none' }}>
<div style={{ width: 38, height: 38, borderRadius: 'var(--radius-md)', background: 'var(--accent-subtle)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
<Icon name={d.icon} size={19} color="var(--accent)" stroke={2.2} />
</div>
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{ fontSize: 14.5, fontWeight: 600, color: 'var(--fg1)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{d.name}</div>
<div style={{ marginTop: 8, height: 4, borderRadius: 999, background: 'var(--border)', overflow: 'hidden' }}>
<div style={{ width: `${d.frac * 100}%`, height: '100%', background: 'var(--accent)', opacity: 0.85, borderRadius: 999 }} />
</div>
</div>
<div style={{ textAlign: 'right', flexShrink: 0 }}>
<div style={{ fontFamily: 'var(--font-mono)', fontSize: 14.5, fontWeight: 500, color: 'var(--fg1)' }}>{d.gb}<span style={{ fontSize: 11, color: 'var(--fg3)' }}> GB</span></div>
<div style={{ fontSize: 11, color: 'var(--fg3)', marginTop: 2 }}>{d.h} h</div>
</div>
</div>
))}
</div>
</div>
</div>
);