// SNMP 设备可观测面板 — 多指标趋势图 // Logan.Li import { useCallback, useEffect, useState } from 'react'; import { Card, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Activity, LineChart, Loader2, RefreshCw } from 'lucide-react'; import { snmpApi } from '@/api'; import type { SnmpDevice, SnmpHistoryPoint, SnmpMetricSeries, SnmpTimeRange, } from './helpers'; import { SNMP_TIME_RANGE_HOURS, fmtMetricValue, isSnmpCounterMetric, metricColor, pickSeriesByCategory, } from './helpers'; import { SnmpMetricTrendChart } from './SnmpMetricTrendChart'; import { useTranslation } from 'react-i18next'; interface Props { device: SnmpDevice | null; templateName: string; } interface ChartBlock { series: SnmpMetricSeries; data: SnmpHistoryPoint[]; unit?: string; loading: boolean; } export function SnmpDeviceChartsPanel({ device, templateName }: Props) { const { t } = useTranslation(); const [timeRange, setTimeRange] = useState('24h'); const [series, setSeries] = useState([]); const [charts, setCharts] = useState([]); const [loading, setLoading] = useState(false); const loadCharts = useCallback(async () => { if (!device) return; setLoading(true); try { const seriesRes = await snmpApi.getDeviceMetricSeries(device.id) as { list?: SnmpMetricSeries[] }; const allSeries = seriesRes?.list || []; setSeries(allSeries); const picked = pickSeriesByCategory(allSeries); const hours = SNMP_TIME_RANGE_HOURS[timeRange]; const blocks = await Promise.all( picked.map(async (s) => { try { const histRes = await snmpApi.getDeviceMetricHistory(device.id, { metric_name: s.name, index: s.index || undefined, hours, }) as { list?: SnmpHistoryPoint[]; rate_unit?: string }; const unit = histRes?.rate_unit || (isSnmpCounterMetric(s.name) ? 'bps' : s.unit); return { series: s, data: histRes?.list || [], unit, loading: false, }; } catch { return { series: s, data: [], loading: false }; } }), ); setCharts(blocks); } catch { setSeries([]); setCharts([]); } finally { setLoading(false); } }, [device, timeRange]); useEffect(() => { loadCharts(); }, [loadCharts]); // 30s 静默刷新趋势 // Logan.Li useEffect(() => { if (!device) return; const timer = setInterval(loadCharts, 30_000); return () => clearInterval(timer); }, [device, loadCharts]); if (!device) { return ( 点击设备行查看 CPU / 内存 / 温度 / 风扇趋势图 ); } const latestCpu = series.find((s) => s.name.includes('cpu')); const latestMem = series.find((s) => s.name.includes('mem')); return (

可观测 · {device.name}

{templateName}
{[ { label: t('monitor.lbl.totalDevices'), value: latestCpu ? fmtMetricValue(latestCpu.latest_value, latestCpu.unit || '%') : '--' }, { label: t('monitor.lbl.totalDevices'), value: latestMem ? fmtMetricValue(latestMem.latest_value, latestMem.unit || '%') : '--' }, { label: t('monitor.lbl.totalDevices'), value: t('monitor.lbl.totalDevices') }, ].map((item) => (

{item.label}

{item.value}

))}
{loading ? (
加载趋势...
) : charts.length === 0 ? (
暂无可视化指标,请先完成至少一次采集
) : (
{charts.map((block) => (
{block.series.label} {block.data.length > 0 ? fmtMetricValue(block.data[block.data.length - 1].value, block.unit) : fmtMetricValue(block.series.latest_value, block.series.unit)}
))}
)}
); }