134 lines
4.8 KiB
TypeScript
134 lines
4.8 KiB
TypeScript
import {
|
|
Bar,
|
|
BarChart,
|
|
Cell,
|
|
LabelList,
|
|
Pie,
|
|
PieChart,
|
|
ResponsiveContainer,
|
|
Tooltip,
|
|
XAxis,
|
|
YAxis,
|
|
} from 'recharts';
|
|
import type { HydrogenRegionShare, HydrogenStationTop } from '../../types';
|
|
|
|
const REGION_COLORS = [
|
|
'#3b82f6', '#22d3ee', '#a855f7', '#f59e0b',
|
|
'#10b981', '#ef4444', '#6366f1', '#14b8a6',
|
|
'#94a3b8',
|
|
];
|
|
|
|
interface YAxisTickProps {
|
|
x?: number;
|
|
y?: number;
|
|
index?: number;
|
|
payload?: { value: string };
|
|
}
|
|
|
|
function RankYAxisTick({ x = 0, y = 0, index = 0, payload }: YAxisTickProps) {
|
|
return (
|
|
<g transform={`translate(${x},${y})`}>
|
|
<circle cx={-172} cy={0} r={9} fill="#3b82f6" />
|
|
<text x={-172} y={3} textAnchor="middle" fontSize={10} fontWeight={700} fill="#fff">
|
|
{index + 1}
|
|
</text>
|
|
<text x={-154} y={4} textAnchor="start" fontSize={11} fill="#475569">
|
|
{payload?.value}
|
|
</text>
|
|
</g>
|
|
);
|
|
}
|
|
|
|
interface DistributionChartsProps {
|
|
top5: HydrogenStationTop[];
|
|
regions: HydrogenRegionShare[];
|
|
yearKg: number;
|
|
}
|
|
|
|
export function DistributionCharts({ top5, regions, yearKg }: DistributionChartsProps) {
|
|
return (
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
|
<div className="bg-white rounded-2xl border border-slate-100 shadow-sm p-3 md:p-4">
|
|
<div className="flex items-center justify-between mb-3">
|
|
<span className="text-sm font-bold text-slate-700">加氢站加注量 Top5</span>
|
|
<span className="text-[11px] text-slate-400 font-bold">单位 Kg</span>
|
|
</div>
|
|
<ResponsiveContainer width="100%" height={260}>
|
|
<BarChart data={top5} layout="vertical" margin={{ top: 4, right: 80, bottom: 4, left: 12 }}>
|
|
<XAxis type="number" hide />
|
|
<YAxis
|
|
type="category"
|
|
dataKey="name"
|
|
width={188}
|
|
tick={<RankYAxisTick />}
|
|
tickLine={false}
|
|
axisLine={false}
|
|
/>
|
|
<Tooltip
|
|
formatter={(v) => `${Number(v ?? 0).toLocaleString('zh-CN')} Kg`}
|
|
contentStyle={{ borderRadius: 12, fontSize: 12 }}
|
|
/>
|
|
<Bar dataKey="kg" radius={[6, 6, 6, 6]}>
|
|
{top5.map((_, i) => (
|
|
<Cell key={i} fill="url(#topBarGrad)" />
|
|
))}
|
|
<LabelList
|
|
dataKey="kg"
|
|
position="right"
|
|
formatter={(v) => `${Number(v ?? 0).toLocaleString('zh-CN', { maximumFractionDigits: 0 })}`}
|
|
fill="#475569"
|
|
fontSize={11}
|
|
fontWeight={700}
|
|
/>
|
|
</Bar>
|
|
<defs>
|
|
<linearGradient id="topBarGrad" x1="0" x2="1" y1="0" y2="0">
|
|
<stop offset="0%" stopColor="#3b82f6" />
|
|
<stop offset="100%" stopColor="#22d3ee" />
|
|
</linearGradient>
|
|
</defs>
|
|
</BarChart>
|
|
</ResponsiveContainer>
|
|
</div>
|
|
|
|
<div className="bg-white rounded-2xl border border-slate-100 shadow-sm p-3 md:p-4 flex flex-col gap-2">
|
|
<span className="text-sm font-bold text-slate-700">各区域加氢占比</span>
|
|
<div className="flex items-center gap-2">
|
|
<div className="relative w-1/2 h-[200px]">
|
|
<ResponsiveContainer width="100%" height="100%">
|
|
<PieChart>
|
|
<Pie
|
|
data={regions}
|
|
dataKey="kg"
|
|
nameKey="region"
|
|
innerRadius={48}
|
|
outerRadius={80}
|
|
paddingAngle={1}
|
|
>
|
|
{regions.map((_, i) => (
|
|
<Cell key={i} fill={REGION_COLORS[i % REGION_COLORS.length]} />
|
|
))}
|
|
</Pie>
|
|
<Tooltip formatter={(v) => `${(Number(v ?? 0) / 1000).toFixed(2)}T`} contentStyle={{ borderRadius: 12, fontSize: 12 }} />
|
|
</PieChart>
|
|
</ResponsiveContainer>
|
|
<div className="absolute inset-0 flex flex-col items-center justify-center pointer-events-none">
|
|
<div className="text-[10px] text-slate-400 font-bold">年合计</div>
|
|
<div className="text-base font-bold text-slate-700 leading-tight">{(yearKg / 1000).toFixed(2)}T</div>
|
|
</div>
|
|
</div>
|
|
<div className="flex-1 grid grid-cols-1 md:grid-cols-2 gap-x-3 gap-y-1 text-[11px]">
|
|
{regions.map((r, i) => (
|
|
<div key={r.region} className="flex items-center gap-1.5">
|
|
<span className="w-2 h-2 rounded-full flex-shrink-0" style={{ background: REGION_COLORS[i % REGION_COLORS.length] }} />
|
|
<span className="text-slate-600 truncate">{r.region}</span>
|
|
<span className="text-slate-400 ml-auto font-bold flex-shrink-0">{(r.share * 100).toFixed(1)}%</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|