Files
aiops/frontend/src/pages/monitor/site-monitor/SiteProtocolPieChart.tsx
T
attacker ecec73989b feat(i18n): 剩余模块全量国际化 — 51% 覆盖率 (231 文件接入 t())
批量转换 163 个文件,3204 处中文替换为 t() 调用:
- Monitor: 日志中心/告警中心/数据源/大屏/站点拨测/SNMP/中间件 全部转换
- Kubernetes: ResourceVisualEditor/NamespaceResourcePage/拓扑/事件 全部转换
- Deploy: 流水线/发布/凭证/RBAC 全部转换
- Server/Cloud/Agent/Task/Layout/UI: 全部转换
- 翻译词典扩展至 6474 行 (22 namespaces, 5000+ keys)
- tsc 编译零错误
2026-07-03 01:51:57 +08:00

84 lines
3.1 KiB
TypeScript

// 拨测协议数量分布饼图 // Logan.Li
import { useMemo } from 'react';
import { PieChart, Pie, Cell, Tooltip, ResponsiveContainer } from 'recharts';
import { MONITOR_PIE_STROKE, MonitorPieTooltip } from '../shared/monitorChartTheme';
import { Card, CardContent } from '@/components/ui/card';
import { PieChart as PieChartIcon } from 'lucide-react';
import { PROBE_TYPE_OPTIONS, normalizeProbeType } from './helpers';
import type { SiteTask } from './helpers';
import { useTranslation } from 'react-i18next';
interface Props {
tasks: SiteTask[];
}
const PROTOCOL_COLORS: Record<string, string> = {
HTTP: 'var(--dg-blue)',
SSL: '#a855f7',
TCP: '#06b6d4',
DNS: 'var(--dg-green)',
PING: '#f59e0b',
};
export function SiteProtocolPieChart({ tasks }: Props) {
const { t } = useTranslation();
const protocolData = useMemo(() => {
const counts: Record<string, number> = {};
for (const t of PROBE_TYPE_OPTIONS) counts[t] = 0;
for (const t of tasks) {
const key = normalizeProbeType(t.type);
counts[key] = (counts[key] || 0) + 1;
}
return PROBE_TYPE_OPTIONS
.map((name) => ({ name, value: counts[name] || 0, fill: PROTOCOL_COLORS[name] || 'var(--dg-text-muted)' }))
.filter((d) => d.value > 0);
}, [tasks]);
if (tasks.length === 0) {
return (
<Card className="bg-[var(--dg-bg-secondary)] border-[var(--dg-border)]">
<CardContent className="p-6 text-center text-sm text-[var(--dg-text-muted)]">{t('monitor.siteprotocolpiechart.s0589e5')}</CardContent>
</Card>
);
}
return (
<Card className="bg-[var(--dg-bg-secondary)] border-[var(--dg-border)]">
<CardContent className="p-4">
<div className="flex items-center gap-2 mb-2">
<PieChartIcon className="h-4 w-4 text-[var(--dg-text-muted)]" />
<h3 className="text-sm font-medium text-[var(--dg-text-primary)]">{t('monitor.siteprotocolpiechart.s20721c')}</h3>
<span className="text-[10px] text-[var(--dg-text-muted)]">共 {tasks.length} 个任务</span>
</div>
<ResponsiveContainer width="100%" height={200}>
<PieChart>
<Pie
data={protocolData}
dataKey="value"
nameKey="name"
cx="50%"
cy="50%"
innerRadius={48}
outerRadius={76}
paddingAngle={2}
isAnimationActive={false}
>
{protocolData.map((entry) => (
<Cell key={entry.name} fill={entry.fill} stroke={MONITOR_PIE_STROKE} strokeWidth={2} />
))}
</Pie>
<Tooltip content={<MonitorPieTooltip />} />
</PieChart>
</ResponsiveContainer>
<div className="flex flex-wrap justify-center gap-x-4 gap-y-1 mt-1">
{protocolData.map((d) => (
<div key={d.name} className="flex items-center gap-1.5 text-xs text-[var(--dg-text-muted)]">
<span className="w-2 h-2 rounded-full shrink-0" style={{ backgroundColor: d.fill }} />
{d.name} {d.value}
</div>
))}
</div>
</CardContent>
</Card>
);
}