115 lines
4.6 KiB
TypeScript
115 lines
4.6 KiB
TypeScript
import type { ReactNode } from 'react';
|
|
import { CalendarDays, Fuel, Sparkles, TrendingUp, Wallet } from 'lucide-react';
|
|
import type { HydrogenKpi } from '../../types';
|
|
import { formatKg as fmtKg, formatYuan as fmtYuan } from '../model';
|
|
|
|
interface KpiCardProps {
|
|
icon: ReactNode;
|
|
label: string;
|
|
hero: { value: string; unit: string };
|
|
rows: { label: string; value: string; valueClass?: string }[];
|
|
accentClass: string;
|
|
iconBg: string;
|
|
}
|
|
|
|
function KpiCard({ icon, label, hero, rows, accentClass, iconBg }: KpiCardProps) {
|
|
return (
|
|
<div className="bg-white rounded-2xl border border-slate-100 shadow-sm p-3 md:p-4 flex flex-col gap-2">
|
|
<div className="flex items-center gap-2">
|
|
<div className={`w-7 h-7 rounded-xl flex items-center justify-center ${iconBg}`}>
|
|
{icon}
|
|
</div>
|
|
<span className="text-[11px] font-bold text-slate-500">{label}</span>
|
|
</div>
|
|
<div className="flex items-baseline gap-1">
|
|
<span className={`text-xl md:text-2xl font-black tabular-nums leading-none ${accentClass}`}>{hero.value}</span>
|
|
<span className="text-[11px] text-slate-400 font-bold">{hero.unit}</span>
|
|
</div>
|
|
<div className="space-y-0.5 pt-1 border-t border-slate-50">
|
|
{rows.map((r, i) => (
|
|
<div key={i} className="flex items-center justify-between text-[11px] font-bold">
|
|
<span className="text-slate-400">{r.label}</span>
|
|
<span className={`tabular-nums ${r.valueClass ?? 'text-slate-700'}`}>{r.value}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function KpiSection({ kpi: k }: { kpi: HydrogenKpi }) {
|
|
const yearKgFmt = fmtKg(k.yearKg);
|
|
const yearFeeFmt = fmtYuan(k.yearFee);
|
|
const yearProfitFmt = fmtYuan(k.yearProfit);
|
|
const ourYearKgFmt = fmtKg(k.ourYearKg);
|
|
const customerYearKgFmt = fmtKg(k.customerYearKg);
|
|
const monthKgFmt = fmtKg(k.monthKg);
|
|
const monthFeeFmt = fmtYuan(k.monthFee);
|
|
const todayKgFmt = fmtKg(k.todayKg);
|
|
const todayFeeFmt = fmtYuan(k.todayFee);
|
|
const customerYearFee = Math.max(0, k.yearFee - k.ourYearFee);
|
|
const customerYearFeeFmt = fmtYuan(customerYearFee);
|
|
const yearRevenueFmt = fmtYuan(k.yearRevenue);
|
|
const profitColor = k.yearProfit >= 0 ? 'text-emerald-600' : 'text-red-600';
|
|
|
|
return (
|
|
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-5 gap-2 md:gap-3">
|
|
<KpiCard
|
|
icon={<Fuel size={14} className="text-cyan-600" strokeWidth={2.4} />}
|
|
iconBg="bg-cyan-50"
|
|
accentClass="text-slate-800"
|
|
label="累计加氢量"
|
|
hero={yearKgFmt}
|
|
rows={[
|
|
{ label: '我司', value: `${ourYearKgFmt.value} ${ourYearKgFmt.unit}` },
|
|
{ label: '客户', value: `${customerYearKgFmt.value} ${customerYearKgFmt.unit}` },
|
|
]}
|
|
/>
|
|
<KpiCard
|
|
icon={<Wallet size={14} className="text-blue-600" strokeWidth={2.4} />}
|
|
iconBg="bg-blue-50"
|
|
accentClass="text-slate-800"
|
|
label="累计加氢费"
|
|
hero={{ value: `¥${yearFeeFmt.value}`, unit: yearFeeFmt.unit }}
|
|
rows={[
|
|
{ label: '我司承担', value: `¥${fmtYuan(k.ourYearFee).value} ${fmtYuan(k.ourYearFee).unit}` },
|
|
{ label: '客户承担', value: `¥${customerYearFeeFmt.value} ${customerYearFeeFmt.unit}` },
|
|
]}
|
|
/>
|
|
<KpiCard
|
|
icon={<TrendingUp size={14} className="text-emerald-600" strokeWidth={2.4} />}
|
|
iconBg="bg-emerald-50"
|
|
accentClass={profitColor}
|
|
label="时享加氢获利"
|
|
hero={{ value: `¥${yearProfitFmt.value}`, unit: yearProfitFmt.unit }}
|
|
rows={[
|
|
{ label: '收入', value: `¥${yearRevenueFmt.value} ${yearRevenueFmt.unit}` },
|
|
{ label: '成本', value: `¥${yearFeeFmt.value} ${yearFeeFmt.unit}` },
|
|
]}
|
|
/>
|
|
<KpiCard
|
|
icon={<CalendarDays size={14} className="text-amber-600" strokeWidth={2.4} />}
|
|
iconBg="bg-amber-50"
|
|
accentClass="text-amber-600"
|
|
label="本月加氢"
|
|
hero={monthKgFmt}
|
|
rows={[
|
|
{ label: '加氢费', value: `¥${monthFeeFmt.value} ${monthFeeFmt.unit}` },
|
|
{ label: '占年比', value: `${k.yearKg > 0 ? (k.monthKg / k.yearKg * 100).toFixed(1) : '0.0'}%` },
|
|
]}
|
|
/>
|
|
<KpiCard
|
|
icon={<Sparkles size={14} className="text-violet-600" strokeWidth={2.4} />}
|
|
iconBg="bg-violet-50"
|
|
accentClass="text-violet-600"
|
|
label="本日加氢"
|
|
hero={todayKgFmt}
|
|
rows={[
|
|
{ label: '加氢费', value: `¥${todayFeeFmt.value} ${todayFeeFmt.unit}` },
|
|
{ label: '占月比', value: `${k.monthKg > 0 ? (k.todayKg / k.monthKg * 100).toFixed(1) : '0.0'}%` },
|
|
]}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|