diff --git a/frontend/src/components/monitor/dashboard/HostMonitorDashboard.tsx b/frontend/src/components/monitor/dashboard/HostMonitorDashboard.tsx
index c46879c..0ca1078 100644
--- a/frontend/src/components/monitor/dashboard/HostMonitorDashboard.tsx
+++ b/frontend/src/components/monitor/dashboard/HostMonitorDashboard.tsx
@@ -1,10 +1,11 @@
-// 主机监控大屏 — 列表视图 + 可排序 + 操作栏 // Logan.Li
+// 主机监控大屏 — Grafana 风格:统计卡片 + 资源条状图 + 可排序列表 // Logan.Li
+// 参照: Grafana node-dashboard.json (表格+时序) / k8s-dashboard.json (bargauge+阈值)
import { useState, useEffect, useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import {
Server, Cpu, HardDrive, Activity, Monitor, Bell,
ArrowUpDown, ArrowUp, ArrowDown, RefreshCw, Search,
- ChevronLeft, ChevronRight
+ ChevronLeft, ChevronRight, Zap, AlertTriangle, Wifi, WifiOff
} from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
@@ -133,37 +134,151 @@ export default function HostMonitorDashboard() {
return (
- {/* 统计卡片 */}
-
+ {/* 统计卡片 — Grafana Quick Facts 风格 (参照 JVM Dashboard) */}
+
-
-
+
+
-
{stats.online}
-
Agent 在线
+
{stats.total}
+
主机总数
-
-
+
+
-
{stats.offline}
-
Agent 离线
+
{stats.online}
+
Agent 在线
-
-
+
+
-
{stats.total}
-
主机总数
+
{stats.offline}
+
离线
+ {(() => {
+ const onlines = hosts.filter((h: any) => h.agent_status === 'online');
+ const avgCpu = onlines.length > 0 ? onlines.reduce((s: number, h: any) => s + (h.cpu_usage || 0), 0) / onlines.length : 0;
+ const avgMem = onlines.length > 0 ? onlines.reduce((s: number, h: any) => s + (h.memory_usage || 0), 0) / onlines.length : 0;
+ const cpuColor = avgCpu > 85 ? 'text-red-400' : avgCpu > 60 ? 'text-amber-400' : 'text-emerald-400';
+ const memColor = avgMem > 85 ? 'text-red-400' : avgMem > 60 ? 'text-amber-400' : 'text-emerald-400';
+ return (<>
+
+
+
+
+
{avgCpu.toFixed(1)}%
+
平均 CPU
+
+
+
+
+
+
+
+
{avgMem.toFixed(1)}%
+
平均内存
+
+
+
+ >);
+ })()}
+ {/* 资源条状图 — Grafana Bargauge 风格 (参照 K8s Node CPU/Memory Ratio) */}
+ {hosts.filter((h: any) => h.agent_status === 'online').length > 0 && (
+
+ {/* CPU 排行 */}
+
+
+
+
+ CPU 使用率 Top 5
+ 阈值: 60% / 85%
+
+
+
+ {[...hosts]
+ .filter((h: any) => h.agent_status === 'online')
+ .sort((a: any, b: any) => (b.cpu_usage || 0) - (a.cpu_usage || 0))
+ .slice(0, 5)
+ .map((h: any) => {
+ const val = h.cpu_usage || 0;
+ return (
+
+
{h.hostname}
+
+
= 85
+ ? 'linear-gradient(90deg, #ef4444, #f87171)'
+ : val >= 60
+ ? 'linear-gradient(90deg, #f59e0b, #fbbf24)'
+ : 'linear-gradient(90deg, #10b981, #34d399)'
+ }}
+ />
+
+
= 85 ? 'text-red-400' : val >= 60 ? 'text-amber-400' : 'text-emerald-400'
+ }`}>{val.toFixed(1)}%
+
+ );
+ })}
+
+
+
+ {/* 内存排行 */}
+
+
+
+
+ 内存使用率 Top 5
+ 阈值: 60% / 85%
+
+
+
+ {[...hosts]
+ .filter((h: any) => h.agent_status === 'online')
+ .sort((a: any, b: any) => (b.memory_usage || 0) - (a.memory_usage || 0))
+ .slice(0, 5)
+ .map((h: any) => {
+ const val = h.memory_usage || 0;
+ return (
+
+
{h.hostname}
+
+
= 85
+ ? 'linear-gradient(90deg, #ef4444, #f87171)'
+ : val >= 60
+ ? 'linear-gradient(90deg, #f59e0b, #fbbf24)'
+ : 'linear-gradient(90deg, #10b981, #34d399)'
+ }}
+ />
+
+
= 85 ? 'text-red-400' : val >= 60 ? 'text-amber-400' : 'text-emerald-400'
+ }`}>{val.toFixed(1)}%
+
+ );
+ })}
+
+
+
+ )}
+
{/* 表格卡片 */}