// Zabbix 数据源监控面板 — 镜像 Grafana Dashboard 5456 + 5363 // Logan.Li import React, { useState, useEffect } from 'react'; import { Server, Wifi, WifiOff, Loader2, AlertTriangle, Activity, Cpu, HardDrive, Network, Clock, RefreshCw, Plug, Settings, ArrowUpDown, ArrowUp, ArrowDown, X, CheckCircle2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Badge } from '@/components/ui/badge'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Label } from '@/components/ui/label'; import { toast } from 'sonner'; import { http } from '@/services/http'; interface ZabbixHost { hostid: string; hostname: string; name: string; ip: string; available: string; // 0=未知 1=可用 2=不可用 cpu_usage: number; memory_usage: number; disk_usage: number; load5: number; net_in_bps: number; net_out_bps: number; problem_count: number; uptime_days: number; cpu_count: number; total_memory_gb: number; } interface ZabbixData { version: string; hosts: ZabbixHost[]; total: number; } type SortField = 'hostname' | 'cpu_usage' | 'memory_usage' | 'disk_usage' | 'load5' | 'net_in_bps' | 'net_out_bps' | 'problem_count' | 'uptime_days' | 'ip'; const LS_KEY = 'aiops_zabbix_ds'; function getSavedDS(): { url: string; username: string; password: string } | null { try { const raw = localStorage.getItem(LS_KEY); if (raw) return JSON.parse(raw); } catch {} return null; } function saveDS(ds: { url: string; username: string; password: string }) { localStorage.setItem(LS_KEY, JSON.stringify(ds)); } export const ZabbixDashboard: React.FC = () => { const [connected, setConnected] = useState(false); const [loading, setLoading] = useState(false); const [hosts, setHosts] = useState([]); const [version, setVersion] = useState(''); const [error, setError] = useState(''); const [url, setUrl] = useState(''); const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const [showForm, setShowForm] = useState(false); const [sortField, setSortField] = useState('cpu_usage'); const [sortDir, setSortDir] = useState<'asc' | 'desc'>('desc'); // 尝试用保存的凭据自动连接 useEffect(() => { const saved = getSavedDS(); if (saved) { setUrl(saved.url); setUsername(saved.username); setPassword(saved.password); doConnect(saved.url, saved.username, saved.password); } }, []); const doConnect = async (u: string, un: string, pw: string) => { setLoading(true); setError(''); try { const data: ZabbixData = await http.post('/zabbix/connect', { url: u, username: un, password: pw }); setHosts(data.hosts || []); setVersion(data.version || ''); setConnected(true); saveDS({ url: u, username: un, password: pw }); toast.success(`Zabbix ${data.version} 连接成功,${data.total} 台主机`); } catch (e: any) { setConnected(false); setError(e.message || '连接失败'); } finally { setLoading(false); } }; const handleConnect = () => { if (!url || !username || !password) { toast.error('请填写完整连接信息'); return; } doConnect(url, username, password); }; const handleDisconnect = () => { setConnected(false); setHosts([]); setError(''); localStorage.removeItem(LS_KEY); toast.info('已断开 Zabbix 连接'); }; const refreshData = () => { if (url && username && password) doConnect(url, username, password); }; const toggleSort = (field: SortField) => { if (sortField === field) setSortDir(d => d === 'asc' ? 'desc' : 'asc'); else { setSortField(field); setSortDir('desc'); } }; const sortedHosts = [...hosts].sort((a, b) => { const va = (a as any)[sortField] ?? ''; const vb = (b as any)[sortField] ?? ''; if (typeof va === 'number' && typeof vb === 'number') { return sortDir === 'asc' ? va - vb : vb - va; } return sortDir === 'asc' ? String(va).localeCompare(String(vb)) : String(vb).localeCompare(String(va)); }); const SortIcon = ({ field }: { field: SortField }) => { if (sortField !== field) return ; return sortDir === 'asc' ? : ; }; const usageBar = (val: number, label: string) => { const pct = Math.min(val, 100); const isWarn = val >= 80; return (
{label}
); }; const fmtBps = (bps: number): string => { if (!bps || bps === 0) return '—'; if (bps > 1e9) return `${(bps / 1e9).toFixed(1)} GB/s`; if (bps > 1e6) return `${(bps / 1e6).toFixed(1)} MB/s`; if (bps > 1e3) return `${(bps / 1e3).toFixed(1)} KB/s`; return `${bps.toFixed(1)} B/s`; }; const getAvailBadge = (avail: string) => { return avail === '1' ? 可用 : 不可用; }; const getPriorityColor = (count: number) => { if (count === 0) return ''; if (count <= 2) return 'text-amber-400'; return 'text-red-400'; }; return (
Zabbix 主机监控 {version && v{version}} {connected && ( <> {hosts.length} 台主机
)}
{loading ? (

正在连接 Zabbix...

) : !connected ? (
{error && (
{error}
)} {!showForm ? (

接入 Zabbix 数据源以显示主机监控

支持 Zabbix 5.0 / 6.0 / 7.0

) : (
Zabbix 连接配置
setUrl(e.target.value)} />
setUsername(e.target.value)} />
setPassword(e.target.value)} />
)}
) : hosts.length === 0 ? (

未找到被监控的 Zabbix 主机

) : (
{[ { field: 'hostname' as SortField, label: '主机名', w: '' }, { field: 'ip' as SortField, label: 'IP', w: '' }, { field: 'cpu_usage' as SortField, label: 'CPU', w: 'min-w-[90px]' }, { field: 'memory_usage' as SortField, label: '内存', w: 'min-w-[90px]' }, { field: 'disk_usage' as SortField, label: '磁盘', w: 'min-w-[90px]' }, { field: 'load5' as SortField, label: 'Load5', w: '' }, { field: 'net_in_bps' as SortField, label: '流入', w: '' }, { field: 'net_out_bps' as SortField, label: '流出', w: '' }, { field: 'problem_count' as SortField, label: '问题', w: '' }, { field: 'uptime_days' as SortField, label: '运行', w: '' }, ].map(({ field, label, w }) => ( ))} {sortedHosts.map((host, i) => ( ))}
toggleSort(field)}>
{label}
{getAvailBadge(host.available)} {host.name || host.hostname}
{host.ip || '—'} {usageBar(Number(host.cpu_usage || 0), `${Number(host.cpu_usage || 0).toFixed(1)}%`)} {usageBar(Number(host.memory_usage || 0), `${Number(host.memory_usage || 0).toFixed(1)}%`)} {usageBar(Number(host.disk_usage || 0), `${Number(host.disk_usage || 0).toFixed(1)}%`)} {host.load5 > 0 ? host.load5.toFixed(1) : '—'} {fmtBps(host.net_in_bps)} {fmtBps(host.net_out_bps)} {host.problem_count > 0 ? {host.problem_count} : 0} {host.uptime_days > 0 ? `${host.uptime_days}d` : '—'}
)}
); }; export default ZabbixDashboard;