feat: Tab栏和KPI卡片吸顶固定
滚动列表时: - Tab栏(实时监控/统计报表/每日汇报)sticky固定在顶部 - KPI统计卡片sticky固定在Tab栏下方,略缩小间距 - 背景色匹配页面避免透出内容 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,8 +11,8 @@ export default function MileageModule() {
|
|||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-[#F8F9FB] text-gray-800 font-sans p-3 md:p-6 relative overflow-x-hidden">
|
<div className="min-h-screen bg-[#F8F9FB] text-gray-800 font-sans p-3 md:p-6 relative overflow-x-hidden">
|
||||||
<div className="max-w-6xl mx-auto flex flex-col gap-3 pb-16 landscape:pb-0 landscape:h-full landscape:flex-1 landscape:overflow-hidden">
|
<div className="max-w-6xl mx-auto flex flex-col gap-3 pb-16 landscape:pb-0 landscape:h-full landscape:flex-1 landscape:overflow-hidden">
|
||||||
{/* Sub-navigation */}
|
{/* Sub-navigation — sticky */}
|
||||||
<div className="bg-white px-4 py-2 rounded-2xl border border-slate-100 shadow-sm flex items-center gap-6">
|
<div className="bg-white px-4 py-2 rounded-2xl border border-slate-100 shadow-sm flex items-center gap-6 sticky top-0 z-30">
|
||||||
<button
|
<button
|
||||||
onClick={() => setActiveSubTab('monitoring')}
|
onClick={() => setActiveSubTab('monitoring')}
|
||||||
className={`flex items-center gap-2 py-1 transition-all relative ${activeSubTab === 'monitoring' ? 'text-blue-600' : 'text-slate-400'}`}
|
className={`flex items-center gap-2 py-1 transition-all relative ${activeSubTab === 'monitoring' ? 'text-blue-600' : 'text-slate-400'}`}
|
||||||
|
|||||||
@@ -708,31 +708,35 @@ export default function MonitoringView() {
|
|||||||
);
|
);
|
||||||
})()}
|
})()}
|
||||||
|
|
||||||
{/* High Density KPI Grid */}
|
{/* High Density KPI Grid — sticky below tab bar */}
|
||||||
|
<div className="sticky top-[44px] z-20 bg-[#F8F9FB] py-1">
|
||||||
<div className="grid grid-cols-4 gap-2">
|
<div className="grid grid-cols-4 gap-2">
|
||||||
<div className="col-span-2 bg-slate-900 p-3 rounded-2xl text-white relative overflow-hidden">
|
<div className="col-span-2 bg-slate-900 p-2.5 rounded-xl text-white relative overflow-hidden">
|
||||||
<div className="text-[8px] font-bold text-slate-500 uppercase tracking-wider mb-1">
|
<div className="flex items-baseline justify-between">
|
||||||
{sortBy === 'today' ? '今日' : '累计'}总里程 (KM)
|
<div>
|
||||||
</div>
|
<div className="text-[7px] font-bold text-slate-500 uppercase tracking-wider">{sortBy === 'today' ? '今日' : '累计'}总里程</div>
|
||||||
<div className="text-2xl font-black tracking-tighter flex items-baseline gap-1">
|
<div className="text-lg font-black tracking-tighter leading-tight flex items-baseline gap-1">
|
||||||
{Math.round(sortBy === 'today' ? stats.totalToday : stats.totalAll).toLocaleString()}
|
{Math.round(sortBy === 'today' ? stats.totalToday : stats.totalAll).toLocaleString()}
|
||||||
|
<span className="text-[8px] text-slate-400">km</span>
|
||||||
{sortBy === 'today' && stats.yesterdayTotal > 0 && (() => {
|
{sortBy === 'today' && stats.yesterdayTotal > 0 && (() => {
|
||||||
const change = ((stats.totalToday - stats.yesterdayTotal) / stats.yesterdayTotal) * 100;
|
const change = ((stats.totalToday - stats.yesterdayTotal) / stats.yesterdayTotal) * 100;
|
||||||
const isUp = change >= 0;
|
const isUp = change >= 0;
|
||||||
return <span className={`text-[10px] font-bold ${isUp ? 'text-blue-400' : 'text-rose-400'}`}>{isUp ? '\u2191' : '\u2193'}{Math.abs(change).toFixed(1)}%</span>;
|
return <span className={`text-[9px] font-bold ${isUp ? 'text-blue-400' : 'text-rose-400'}`}>{isUp ? '\u2191' : '\u2193'}{Math.abs(change).toFixed(1)}%</span>;
|
||||||
})()}
|
})()}
|
||||||
</div>
|
</div>
|
||||||
<div className="absolute -right-4 -bottom-4 w-12 h-12 bg-blue-500/10 rounded-full blur-xl"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-white p-3 rounded-2xl border border-gray-100 shadow-sm">
|
|
||||||
<div className="text-[8px] font-bold text-slate-400 uppercase mb-1">平均单车</div>
|
|
||||||
<div className="text-sm font-black text-slate-800">{(stats.vehicleCount > 0 ? (sortBy === 'today' ? stats.totalToday : stats.totalAll) / stats.vehicleCount : 0).toFixed(0)}</div>
|
|
||||||
<div className="text-[7px] text-slate-400 mt-0.5">KM/台</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-white p-3 rounded-2xl border border-gray-100 shadow-sm">
|
</div>
|
||||||
<div className="text-[8px] font-bold text-slate-400 uppercase mb-1">监控台数</div>
|
<div className="bg-white p-2.5 rounded-xl border border-gray-100 shadow-sm">
|
||||||
<div className="text-sm font-black text-slate-800">{stats.vehicleCount}</div>
|
<div className="text-[7px] font-bold text-slate-400 uppercase">平均单车</div>
|
||||||
<div className="text-[7px] text-slate-400 mt-0.5">台</div>
|
<div className="text-sm font-black text-slate-800 leading-tight">{(stats.vehicleCount > 0 ? (sortBy === 'today' ? stats.totalToday : stats.totalAll) / stats.vehicleCount : 0).toFixed(0)}</div>
|
||||||
|
<div className="text-[7px] text-slate-400">km/台</div>
|
||||||
|
</div>
|
||||||
|
<div className="bg-white p-2.5 rounded-xl border border-gray-100 shadow-sm">
|
||||||
|
<div className="text-[7px] font-bold text-slate-400 uppercase">监控台数</div>
|
||||||
|
<div className="text-sm font-black text-slate-800 leading-tight">{stats.vehicleCount}</div>
|
||||||
|
<div className="text-[7px] text-slate-400">台</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user