补 commit hooks/图表组件、路由与 i18n domains、logs metrics API; StatCard/TimeRangePicker/ingress-access-log 抽到共享路径,干净 checkout 可编过。
33 lines
1.6 KiB
TypeScript
33 lines
1.6 KiB
TypeScript
import { memo } from 'react'
|
|
import { CartesianGrid, Legend, Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts'
|
|
import { useTranslation } from 'react-i18next'
|
|
import { EmptyChart } from './EmptyChart'
|
|
|
|
interface TrendPoint { time: string; total: number; error: number; warn: number }
|
|
|
|
/** 日志量趋势折线图:总量 / 错误 / 告警 三条线 */
|
|
export const TrendChart = memo(function TrendChart({ trend }: { trend: TrendPoint[] }) {
|
|
const { t } = useTranslation('analysis')
|
|
const hasData = trend.some(point => point.total > 0 || point.error > 0 || point.warn > 0)
|
|
if (!hasData) return <EmptyChart message={t('trend.empty')} />
|
|
const series = [
|
|
{ key: 'total', name: t('trend.seriesTotal'), color: 'hsl(var(--info))' },
|
|
{ key: 'error', name: t('trend.seriesError'), color: 'hsl(var(--destructive))' },
|
|
{ key: 'warn', name: t('trend.seriesWarn'), color: 'hsl(var(--warning))' },
|
|
] as const
|
|
return <div className="h-72 w-full">
|
|
<ResponsiveContainer width="100%" height="100%">
|
|
<LineChart data={trend} margin={{ top: 12, right: 16, bottom: 4, left: 0 }}>
|
|
<CartesianGrid stroke="hsl(var(--border))" strokeDasharray="3 3" />
|
|
<XAxis dataKey="time" tick={{ fontSize: 11 }} minTickGap={30} />
|
|
<YAxis allowDecimals={false} tick={{ fontSize: 11 }} width={48} />
|
|
<Tooltip />
|
|
<Legend wrapperStyle={{ fontSize: 11 }} />
|
|
{series.map(item => (
|
|
<Line key={item.key} type="monotone" dataKey={item.key} name={item.name} stroke={item.color} strokeWidth={2} dot={false} />
|
|
))}
|
|
</LineChart>
|
|
</ResponsiveContainer>
|
|
</div>
|
|
})
|