feat(energy): hydrogen overview KPI cards (4-card grid)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
kkfluous
2026-04-28 11:20:32 +08:00
parent 09b9862f1f
commit e6880cba17
3 changed files with 116 additions and 3 deletions

View File

@@ -0,0 +1,7 @@
export default function HydrogenDaily() {
return (
<div className="bg-white rounded-2xl border border-slate-100 shadow-sm p-6 text-center text-slate-400 text-sm">
Task 5
</div>
);
}

View File

@@ -0,0 +1,75 @@
import { Fuel, Wallet, Coins, CalendarClock } from 'lucide-react';
import { HYDROGEN_KPI } from './mock';
function fmtKg(kg: number) {
if (kg >= 1000) return `${(kg / 1000).toFixed(2)}T`;
return `${kg.toFixed(2)}Kg`;
}
function fmtYuanWan(yuan: number) {
return `¥${(yuan / 10_000).toFixed(2)}`;
}
function fmtYuan(yuan: number) {
return `¥${yuan.toLocaleString('zh-CN', { maximumFractionDigits: 2 })}`;
}
export default function HydrogenOverview() {
const k = HYDROGEN_KPI;
return (
<div className="flex flex-col gap-3">
<div className="bg-white rounded-xl border border-slate-100 px-3 py-1.5 text-[11px] text-slate-400">
2025-01-01 5
</div>
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
{/* 卡 1年加氢量 */}
<div className="bg-gradient-to-br from-cyan-50 to-blue-50 rounded-2xl border border-slate-100 shadow-sm p-4 flex flex-col gap-2">
<div className="flex items-center justify-between text-[11px] text-slate-500">
<span className="flex items-center gap-1 font-bold"><Fuel size={12} className="text-cyan-600" /></span>
</div>
<div className="text-2xl md:text-3xl font-bold text-slate-800 leading-tight">{fmtKg(k.yearKg)}</div>
<div className="text-[11px] text-slate-500 font-bold space-y-0.5">
<div> <span className="text-slate-700">{fmtKg(k.ourYearKg)}</span></div>
<div> <span className="text-slate-700">{fmtKg(k.customerYearKg)}</span></div>
</div>
</div>
{/* 卡 2年加氢费 */}
<div className="bg-gradient-to-br from-blue-50 to-violet-50 rounded-2xl border border-slate-100 shadow-sm p-4 flex flex-col gap-2">
<div className="flex items-center justify-between text-[11px] text-slate-500">
<span className="flex items-center gap-1 font-bold"><Wallet size={12} className="text-blue-600" /></span>
</div>
<div className="text-2xl md:text-3xl font-bold text-slate-800 leading-tight">{fmtYuanWan(k.yearFee)}</div>
<div className="text-[11px] text-slate-500 font-bold">
<div> <span className="text-slate-700">{fmtYuanWan(k.ourYearFee)}</span></div>
</div>
</div>
{/* 卡 3累计羚牛承担 */}
<div className="bg-gradient-to-br from-amber-50 to-orange-50 rounded-2xl border border-slate-100 shadow-sm p-4 flex flex-col gap-2">
<div className="flex items-center justify-between text-[11px] text-slate-500">
<span className="flex items-center gap-1 font-bold"><Coins size={12} className="text-amber-600" /></span>
</div>
<div className="text-2xl md:text-3xl font-bold text-slate-800 leading-tight">{fmtYuanWan(k.lingniuBornFee)}</div>
<div className="text-[11px] text-slate-500 font-bold space-y-0.5">
<div> <span className="text-slate-700">{fmtKg(k.lingniuBornKg)}</span></div>
</div>
</div>
{/* 卡 4本月 / 今日 */}
<div className="bg-white rounded-2xl border border-slate-100 shadow-sm p-4 flex flex-col gap-2">
<div className="flex items-center justify-between text-[11px] text-slate-500">
<span className="flex items-center gap-1 font-bold"><CalendarClock size={12} className="text-slate-500" /> / </span>
</div>
<div className="grid grid-cols-2 gap-2">
<div>
<div className="text-[10px] text-slate-400 font-bold"></div>
<div className="text-base md:text-lg font-bold text-slate-800">{fmtKg(k.monthKg)}</div>
<div className="text-[11px] text-slate-500 font-bold">{fmtYuanWan(k.monthFee)}</div>
</div>
<div>
<div className="text-[10px] text-slate-400 font-bold"></div>
<div className="text-base md:text-lg font-bold text-slate-800">{fmtKg(k.todayKg)}</div>
<div className="text-[11px] text-slate-500 font-bold">{fmtYuan(k.todayFee)}</div>
</div>
</div>
</div>
</div>
</div>
);
}

View File

@@ -1,7 +1,38 @@
import { useState } from 'react';
import { LayoutDashboard, CalendarDays } from 'lucide-react';
import { motion } from 'motion/react';
import HydrogenOverview from './HydrogenOverview';
import HydrogenDaily from './HydrogenDaily';
type SubTab = 'overview' | 'daily';
export default function HydrogenView() { export default function HydrogenView() {
const [sub, setSub] = useState<SubTab>('overview');
return ( return (
<div className="bg-white rounded-2xl border border-slate-100 shadow-sm p-6 text-center text-slate-400 text-sm"> <>
Task 3-5 <div className="bg-white px-4 py-2 rounded-2xl border border-slate-100 shadow-sm flex items-center gap-6 sticky top-[58px] z-20">
<button
onClick={() => setSub('overview')}
className={`flex items-center gap-2 py-1 transition-all relative ${sub === 'overview' ? 'text-blue-600' : 'text-slate-400'}`}
>
<LayoutDashboard size={14} />
<span className="text-[11px] font-bold"></span>
{sub === 'overview' && (
<motion.div layoutId="activeHydrogenSub" className="absolute -bottom-2 left-0 right-0 h-0.5 bg-blue-600 rounded-full" />
)}
</button>
<button
onClick={() => setSub('daily')}
className={`flex items-center gap-2 py-1 transition-all relative ${sub === 'daily' ? 'text-blue-600' : 'text-slate-400'}`}
>
<CalendarDays size={14} />
<span className="text-[11px] font-bold"></span>
{sub === 'daily' && (
<motion.div layoutId="activeHydrogenSub" className="absolute -bottom-2 left-0 right-0 h-0.5 bg-blue-600 rounded-full" />
)}
</button>
</div> </div>
{sub === 'overview' ? <HydrogenOverview /> : <HydrogenDaily />}
</>
); );
} }