63 lines
1.9 KiB
TypeScript
63 lines
1.9 KiB
TypeScript
|
|
import { memo } from 'react';
|
||
|
|
import {
|
||
|
|
BarChart,
|
||
|
|
Bar,
|
||
|
|
XAxis,
|
||
|
|
YAxis,
|
||
|
|
CartesianGrid,
|
||
|
|
Tooltip,
|
||
|
|
ResponsiveContainer,
|
||
|
|
} from 'recharts';
|
||
|
|
import { CLINICAL_COLORS, TOOLTIP_STYLE } from './chartColors';
|
||
|
|
|
||
|
|
interface CostByDiseaseChartProps {
|
||
|
|
data: { diagnosis: string; mean_cost: number; n: number }[];
|
||
|
|
}
|
||
|
|
|
||
|
|
function truncate(s: string, max: number): string {
|
||
|
|
return s.length > max ? s.slice(0, max) + '…' : s;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 各病种平均费用横向柱状图。 */
|
||
|
|
export const CostByDiseaseChart = memo(function CostByDiseaseChart({
|
||
|
|
data,
|
||
|
|
}: CostByDiseaseChartProps) {
|
||
|
|
if (!data || data.length === 0) {
|
||
|
|
return <div className="text-center py-8 text-text-muted text-sm">暂无数据</div>;
|
||
|
|
}
|
||
|
|
|
||
|
|
const chartData = [...data]
|
||
|
|
.sort((a, b) => a.mean_cost - b.mean_cost)
|
||
|
|
.map((d) => ({ ...d, displayName: truncate(d.diagnosis, 8) }));
|
||
|
|
|
||
|
|
return (
|
||
|
|
<ResponsiveContainer width="100%" height={Math.max(240, chartData.length * 34)}>
|
||
|
|
<BarChart
|
||
|
|
data={chartData}
|
||
|
|
layout="vertical"
|
||
|
|
margin={{ top: 5, right: 20, left: 12, bottom: 5 }}
|
||
|
|
>
|
||
|
|
<CartesianGrid strokeDasharray="3 3" stroke={CLINICAL_COLORS.grid} horizontal={false} />
|
||
|
|
<XAxis
|
||
|
|
type="number"
|
||
|
|
tick={{ fontSize: 10, fill: CLINICAL_COLORS.axis }}
|
||
|
|
tickFormatter={(v: number) => `¥${(v / 1000).toFixed(0)}k`}
|
||
|
|
/>
|
||
|
|
<YAxis
|
||
|
|
type="category"
|
||
|
|
dataKey="displayName"
|
||
|
|
tick={{ fontSize: 10, fill: CLINICAL_COLORS.axisLabel }}
|
||
|
|
width={72}
|
||
|
|
axisLine={false}
|
||
|
|
tickLine={false}
|
||
|
|
/>
|
||
|
|
<Tooltip
|
||
|
|
contentStyle={TOOLTIP_STYLE}
|
||
|
|
formatter={(v: number) => [`¥${Math.round(v).toLocaleString()}`, '人均费用']}
|
||
|
|
/>
|
||
|
|
<Bar dataKey="mean_cost" fill={CLINICAL_COLORS.cost} barSize={16} radius={[0, 3, 3, 0]} />
|
||
|
|
</BarChart>
|
||
|
|
</ResponsiveContainer>
|
||
|
|
);
|
||
|
|
});
|