Files
ln-bi/src/modules/mileage/daily-report/ReportCharts.tsx
T

123 lines
5.2 KiB
TypeScript

import {
Bar,
BarChart,
CartesianGrid,
Legend,
Line,
LineChart,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from 'recharts';
import { SurfaceCard } from '../../../components/ui/surface';
import type { DailyMileageReport } from '../api';
import { fmtDate, fmtKm } from './utils';
interface ReportChartsProps {
report: DailyMileageReport;
trendTargetId: number | null;
onTrendTargetChange: (targetId: number | null) => void;
}
export default function ReportCharts({
report,
trendTargetId,
onTrendTargetChange,
}: ReportChartsProps) {
const comparisonData = report.groups.map(group => ({
name: group.displayName,
运营里程: group.operatingMileage,
库存里程: group.inventoryMileage,
}));
const trendGroup = trendTargetId == null
? null
: report.groups.find(group => group.targetId === trendTargetId) || null;
const trendData = trendGroup?.trend || report.trend;
const trendName = trendGroup?.displayName || '总计';
const trendSubtitle = '选择总计或车型查看近 7 日每日里程,包含库存车辆里程';
const trendColor = trendGroup ? '#0f766e' : '#2563eb';
return (
<div className="grid gap-3 xl:grid-cols-[minmax(0,1.35fr)_minmax(360px,0.65fr)]">
<SurfaceCard
title="近 7 日里程趋势"
subtitle={trendSubtitle}
actions={(
<div className="flex max-w-full gap-1 overflow-x-auto rounded-lg bg-slate-100 p-1">
<button
type="button"
onClick={() => onTrendTargetChange(null)}
className={`h-7 shrink-0 rounded-md px-2.5 text-[10px] font-black transition-colors ${trendGroup == null ? 'bg-white text-blue-600 shadow-sm' : 'text-slate-500 hover:text-slate-700'}`}
>
总计
</button>
{report.groups.map(group => (
<button
key={group.targetId}
type="button"
onClick={() => onTrendTargetChange(group.targetId)}
className={`h-7 shrink-0 rounded-md px-2.5 text-[10px] font-black transition-colors ${trendTargetId === group.targetId ? 'bg-white text-emerald-700 shadow-sm' : 'text-slate-500 hover:text-slate-700'}`}
>
{group.displayName}
</button>
))}
</div>
)}
>
<div className="h-[270px] px-2 py-3">
<ResponsiveContainer
width="100%"
height="100%"
minWidth={0}
minHeight={0}
initialDimension={{ width: 640, height: 246 }}
>
<LineChart data={trendData} margin={{ top: 14, right: 18, left: -4, bottom: 0 }}>
<CartesianGrid vertical={false} stroke="#e2e8f0" strokeDasharray="3 3" />
<XAxis dataKey="date" axisLine={false} tickLine={false} tick={{ fontSize: 10, fill: '#94a3b8' }} tickFormatter={fmtDate} />
<YAxis axisLine={false} tickLine={false} width={58} tick={{ fontSize: 10, fill: '#94a3b8' }} tickFormatter={fmtKm} />
<Tooltip
labelFormatter={label => fmtDate(String(label))}
formatter={value => [`${fmtKm(Number(value))} km`, trendName]}
contentStyle={{ borderRadius: 8, border: '1px solid #e2e8f0', fontSize: 11 }}
/>
<Line type="monotone" dataKey="totalMileage" stroke={trendColor} strokeWidth={2.5} dot={{ r: 3, fill: trendColor }} activeDot={{ r: 5 }} />
</LineChart>
</ResponsiveContainer>
</div>
</SurfaceCard>
<SurfaceCard
title={(
<span className="flex flex-wrap items-center gap-2">
<span>车型里程构成</span>
<span className="rounded-md bg-blue-50 px-1.5 py-0.5 text-[10px] font-black text-blue-600 ring-1 ring-blue-100">统计日期 {fmtDate(report.reportDate)}</span>
</span>
)}
subtitle="运营与库存里程分开展示"
>
<div className="h-[270px] px-2 py-3">
<ResponsiveContainer
width="100%"
height="100%"
minWidth={0}
minHeight={0}
initialDimension={{ width: 480, height: 246 }}
>
<BarChart data={comparisonData} layout="vertical" margin={{ top: 6, right: 14, left: 8, bottom: 0 }}>
<CartesianGrid horizontal={false} stroke="#e2e8f0" strokeDasharray="3 3" />
<XAxis type="number" axisLine={false} tickLine={false} tick={{ fontSize: 10, fill: '#94a3b8' }} tickFormatter={fmtKm} />
<YAxis type="category" dataKey="name" width={92} axisLine={false} tickLine={false} tick={{ fontSize: 10, fill: '#64748b', fontWeight: 700 }} />
<Tooltip formatter={(value, name) => [`${fmtKm(Number(value))} km`, String(name)]} contentStyle={{ borderRadius: 8, border: '1px solid #e2e8f0', fontSize: 11 }} />
<Legend wrapperStyle={{ fontSize: 10, fontWeight: 700 }} />
<Bar dataKey="运营里程" stackId="mileage" fill="#10b981" radius={[3, 0, 0, 3]} />
<Bar dataKey="库存里程" stackId="mileage" fill="#f59e0b" radius={[0, 3, 3, 0]} />
</BarChart>
</ResponsiveContainer>
</div>
</SurfaceCard>
</div>
);
}