// 中间件概览图表 — 状态 + 命中率 + QPS/连接(支持放大)// Logan.Li import { useMemo, type ReactNode } from 'react'; import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, Cell, PieChart, Pie, } from 'recharts'; import { Card, CardContent } from '@/components/ui/card'; import { BarChart3, PieChart as PieChartIcon, Percent } from 'lucide-react'; import type { MwTarget } from './helpers'; import { fmtHitRate, fmtVal } from './helpers'; import { ChartExpandShell } from '../shared/ChartExpandShell'; import { MonitorChartTooltip, MONITOR_PIE_STROKE, MonitorPieTooltip } from '../shared/monitorChartTheme'; import { useTranslation } from 'react-i18next'; interface Props { targets: MwTarget[]; } function shortName(name: string) { return name.length > 10 ? `${name.slice(0, 10)}…` : name; } export function MwOverviewCharts({ targets }: Props) { const { t } = useTranslation(); const statusData = useMemo(() => { const online = targets.filter((tg) => tg.status === 'online').length; const offline = targets.length - online; return [ { name: t('agent.agentOnline'), value: online, fill: 'var(--dg-green)' }, { name: t('agent.agentOffline'), value: offline, fill: 'var(--dg-red)' }, ].filter((d) => d.value > 0); }, [targets, t]); const redisHitData = useMemo(() => targets .filter((tg) => tg.description === 'redis' && tg.latest_metrics?.redis_hit_rate > 0) .map((tg) => ({ name: shortName(tg.name), fullName: tg.name, value: (tg.latest_metrics.redis_hit_rate || 0) * 100, fill: (tg.latest_metrics.redis_hit_rate || 0) >= 0.9 ? 'var(--dg-green)' : 'var(--dg-yellow)', })) .sort((a, b) => a.value - b.value), [targets]); const redisQpsData = useMemo(() => targets .filter((tg) => tg.description === 'redis' && tg.latest_metrics?.redis_qps > 0) .map((tg) => ({ name: shortName(tg.name), fullName: tg.name, value: tg.latest_metrics.redis_qps, fill: 'var(--dg-blue)' })) .sort((a, b) => b.value - a.value), [targets]); const mysqlConnData = useMemo(() => targets .filter((tg) => tg.description === 'mysql' && tg.latest_metrics?.mysql_connections > 0) .map((tg) => ({ name: shortName(tg.name), fullName: tg.name, value: tg.latest_metrics.mysql_connections, fill: 'var(--dg-blue)' })) .sort((a, b) => b.value - a.value), [targets]); if (targets.length === 0) return null; return (
} empty={statusData.length === 0}> {(h) => ( {statusData.map((e) => )} } /> )} } empty={redisHitData.length === 0}> {(h) => ( `${v}%`} /> fmtHitRate(v / 100)} nameFormatter={() => t('monitor.lbl.hitRate')} />} /> {redisHitData.map((e) => )} )} } empty={redisQpsData.length === 0}> {(h) => ( fmtVal(v, 1)} nameFormatter={() => 'QPS'} />} /> {redisQpsData.map((e) => )} )} } empty={mysqlConnData.length === 0}> {(h) => ( fmtVal(v)} nameFormatter={() => t('monitor.lbl.connections')} />} /> {mysqlConnData.map((e) => )} )}
); } function OverviewChartCard({ title, icon, empty, children, }: { title: string; icon: ReactNode; empty?: boolean; children: (height: number) => ReactNode; }) { return ( {children} ); }