89 lines
3.8 KiB
TypeScript
89 lines
3.8 KiB
TypeScript
import { AlertTriangle, Building2, Gauge } from 'lucide-react';
|
|
import type { HydrogenMonthlyPoint } from '../../types';
|
|
import { formatKg as fmtKg } from '../model';
|
|
|
|
interface InsightCardsProps {
|
|
monthAvgKg: number;
|
|
bestMonth: HydrogenMonthlyPoint | null;
|
|
latestMonth: HydrogenMonthlyPoint | undefined;
|
|
monthMomentum: number | null;
|
|
top5Share: number;
|
|
profitYield: number;
|
|
stationAvgKg: number;
|
|
stationCount: number;
|
|
yearProfitValue: string;
|
|
yearProfitUnit: string;
|
|
yearRevenueValue: string;
|
|
yearRevenueUnit: string;
|
|
}
|
|
|
|
export function InsightCards({
|
|
monthAvgKg,
|
|
bestMonth,
|
|
latestMonth,
|
|
monthMomentum,
|
|
top5Share,
|
|
profitYield,
|
|
stationAvgKg,
|
|
stationCount,
|
|
yearProfitValue,
|
|
yearProfitUnit,
|
|
yearRevenueValue,
|
|
yearRevenueUnit,
|
|
}: InsightCardsProps) {
|
|
return (
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-2 md:gap-3">
|
|
<div className="rounded-2xl border border-slate-100 bg-white p-3 shadow-sm">
|
|
<div className="flex items-center justify-between gap-2">
|
|
<div>
|
|
<div className="text-[11px] font-black text-slate-400">月度动能</div>
|
|
<div className="mt-1 text-lg font-black text-slate-900">
|
|
{monthMomentum === null ? '暂无对比' : `${monthMomentum >= 0 ? '+' : ''}${monthMomentum.toFixed(1)}%`}
|
|
</div>
|
|
</div>
|
|
<span className="flex h-9 w-9 items-center justify-center rounded-xl bg-blue-50 text-blue-600 ring-1 ring-blue-100">
|
|
<Gauge size={18} />
|
|
</span>
|
|
</div>
|
|
<div className="mt-2 text-[11px] font-bold leading-relaxed text-slate-500">
|
|
{latestMonth ? `${latestMonth.month} 加氢 ${fmtKg(latestMonth.kg).value}${fmtKg(latestMonth.kg).unit}` : '暂无月度数据'}
|
|
{bestMonth ? ` · 峰值 ${bestMonth.month}` : ''}
|
|
{monthAvgKg > 0 ? ` · 月均 ${fmtKg(monthAvgKg).value}${fmtKg(monthAvgKg).unit}` : ''}
|
|
</div>
|
|
</div>
|
|
<div className="rounded-2xl border border-slate-100 bg-white p-3 shadow-sm">
|
|
<div className="flex items-center justify-between gap-2">
|
|
<div>
|
|
<div className="text-[11px] font-black text-slate-400">站点集中度</div>
|
|
<div className="mt-1 text-lg font-black text-slate-900">Top5 {top5Share.toFixed(1)}%</div>
|
|
</div>
|
|
<span className="flex h-9 w-9 items-center justify-center rounded-xl bg-cyan-50 text-cyan-600 ring-1 ring-cyan-100">
|
|
<Building2 size={18} />
|
|
</span>
|
|
</div>
|
|
<div className="mt-2 text-[11px] font-bold leading-relaxed text-slate-500">
|
|
共 {stationCount} 站 · 单站年均 {fmtKg(stationAvgKg).value}{fmtKg(stationAvgKg).unit}
|
|
{top5Share >= 70 ? ' · 头部站点依赖偏高' : ' · 分布相对健康'}
|
|
</div>
|
|
</div>
|
|
<div className="rounded-2xl border border-slate-100 bg-white p-3 shadow-sm">
|
|
<div className="flex items-center justify-between gap-2">
|
|
<div>
|
|
<div className="text-[11px] font-black text-slate-400">收支健康度</div>
|
|
<div className={`mt-1 text-lg font-black ${profitYield >= 0 ? 'text-emerald-600' : 'text-rose-600'}`}>
|
|
{profitYield.toFixed(1)}%
|
|
</div>
|
|
</div>
|
|
<span className={`flex h-9 w-9 items-center justify-center rounded-xl ring-1 ${profitYield >= 0 ? 'bg-emerald-50 text-emerald-600 ring-emerald-100' : 'bg-rose-50 text-rose-600 ring-rose-100'}`}>
|
|
<AlertTriangle size={18} />
|
|
</span>
|
|
</div>
|
|
<div className="mt-2 text-[11px] font-bold leading-relaxed text-slate-500">
|
|
时享获利 {yearProfitValue}{yearProfitUnit} · 客户收入 {yearRevenueValue}{yearRevenueUnit}
|
|
{profitYield < 0 ? ' · 需关注亏损站点与客户价格' : ' · 当前保持正向收益'}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|