{accessDenied && (
监控权限
{accessDenied}
如需使用监控功能,请联系管理员在用户页面授予监控权限。
)}
{/* ====== GRID/LIST VIEW ====== */}
{!accessDenied && !detailNodeId && (
<>
{wsConnected
? "实时已连接"
: wsConnecting
? "实时连接中"
: "实时未连接"}
节点在线 {onlineNodes.length}/{nodes.length}
监控 成功 {monitorSummary.ok} / 失败 {monitorSummary.fail}
{monitorSummary.stale > 0 && (
陈旧 {monitorSummary.stale}
)}
{viewMode === "grid" ? (
{nodes.map((node) => {
const metric = realtimeNodeMetrics[node.id] || null;
return (
{
setDetailNodeId(node.id);
setSelectedNodeId(node.id);
}}
/>
);
})}
) : (
状态
名称
速率
流量
开机时长
连接数
CPU
RAM
存储
操作
{nodes.map((node) => {
const metric = realtimeNodeMetrics[node.id] || null;
const isOnline = node.connectionStatus === "online";
return (
{node.name}
{isOnline && metric
? formatBytesPerSecond(metric.netOutSpeed)
: "-"}
{isOnline && metric
? formatBytesPerSecond(metric.netInSpeed)
: "-"}
{isOnline && metric
? formatBytes(metric.netOutBytes)
: "-"}
{isOnline && metric
? formatBytes(metric.netInBytes)
: "-"}
{isOnline && metric
? formatUptime(metric.uptime)
: "-"}
TCP {isOnline && metric ? metric.tcpConns : "-"}
UDP {isOnline && metric ? metric.udpConns : "-"}
{isOnline && metric ? (
) : (
)}
{isOnline && metric
? `${metric.cpuUsage.toFixed(1)}%`
: "-"}
{isOnline && metric ? (
) : (
)}
{isOnline && metric
? `${metric.memoryUsage.toFixed(1)}%`
: "-"}
{isOnline && metric ? (
) : (
)}
{isOnline && metric
? `${metric.diskUsage.toFixed(1)}%`
: "-"}
);
})}
)}
>
)}
{/* ====== DETAIL VIEW ====== */}
{!accessDenied && detailNodeId && (
<>
{/* Header */}
{detailNode?.name || `节点 #${detailNodeId}`}
{detailNode?.connectionStatus === "online" ? "在线" : "离线"}
{wsConnected
? "实时已连接"
: wsConnecting
? "实时连接中"
: "实时未连接"}
{/* Realtime KPI cards */}
{detailRealtimeMetric && (
{[
{
label: "CPU",
value: `${detailRealtimeMetric.cpuUsage.toFixed(1)}%`,
color: getColorByUsage(detailRealtimeMetric.cpuUsage),
},
{
label: "内存",
value: `${detailRealtimeMetric.memoryUsage.toFixed(1)}%`,
color: getColorByUsage(detailRealtimeMetric.memoryUsage),
},
{
label: "磁盘",
value: `${detailRealtimeMetric.diskUsage.toFixed(1)}%`,
color: getColorByUsage(detailRealtimeMetric.diskUsage),
},
{
label: "↓ 下行速度",
value: formatBytesPerSecond(detailRealtimeMetric.netInSpeed),
color: "success" as const,
},
{
label: "↑ 上行速度",
value: formatBytesPerSecond(detailRealtimeMetric.netOutSpeed),
color: "primary" as const,
},
{
label: "运行时间",
value: formatUptime(detailRealtimeMetric.uptime),
color: "default" as const,
},
].map((item) => (
{item.label}
{item.value}
))}
)}
{/* Node metrics chart */}
{/* Service monitors chart – same style as node metrics */}
{(() => {
// Resolve which monitor is active
const resolvedActiveMonitor =
detailServiceMonitors.find(
(m) => m.id === activeServiceMonitorId,
) ||
detailServiceMonitors[0] ||
null;
const resolvedActiveMonitorId = resolvedActiveMonitor?.id ?? null;
const activeLatestResult =
resolvedActiveMonitorId != null
? getLatestResult(resolvedActiveMonitorId)
: null;
const activeStale = resolvedActiveMonitor
? isResultStale(resolvedActiveMonitor, activeLatestResult)
: false;
const activeResults =
resolvedActiveMonitorId != null
? monitorResults[resolvedActiveMonitorId] || []
: [];
const activeLatencyData = [...activeResults].map((r) => ({
time: formatTimestamp(r.timestamp, serviceMonitorRangeMs),
latency: r.success === 1 ? r.latencyMs : null,
success: r.success,
}));
return (
服务监控图表
{resolvedActiveMonitorId != null && (
)}
{monitorsLoading ? (
) : detailServiceMonitors.length > 0 ? (
<>
{/* Monitor switcher buttons – like metric type tabs */}
{detailServiceMonitors.map((monitor) => {
const lr = getLatestResult(monitor.id);
const statusColor =
monitor.enabled !== 1
? "default"
: !lr
? "default"
: lr.success === 1
? "success"
: "danger";
const isActive =
monitor.id === resolvedActiveMonitorId;
return (
);
})}
{/* Active monitor info bar */}
{resolvedActiveMonitor && (
{resolvedActiveMonitor.type.toUpperCase()}
{resolvedActiveMonitor.target}
每秒测试,30秒上报
{activeLatestResult &&
Number.isFinite(activeLatestResult.latencyMs) ? (
{activeLatestResult.latencyMs.toFixed(0)}ms
) : null}
{activeStale ? (
陈旧
) : null}
{resolvedActiveMonitor.enabled !== 1 ? (
已禁用
) : null}
}
onPress={() =>
resolvedActiveMonitorId != null &&
handleRunMonitor(resolvedActiveMonitorId)
}
>
立即检查
}
onPress={() =>
resolvedActiveMonitorId != null &&
openResultsModal(resolvedActiveMonitorId)
}
>
查看记录
}
onPress={() =>
resolvedActiveMonitor &&
handleOpenEditModal(resolvedActiveMonitor)
}
>
编辑
}
onPress={() =>
resolvedActiveMonitorId != null &&
handleDeleteMonitor(resolvedActiveMonitorId)
}
>
删除
)}
{/* Chart area – same h-64 as node metrics */}
{activeLatencyData.length > 0 ? (
`${Math.round(v)}ms`
}
/>
[
`${Number(value).toFixed(0)}ms`,
"延迟",
]}
labelStyle={{ color: "#fff" }}
/>
) : (
暂无检查记录
)}
>
) : (
暂无服务监控,点击"添加监控"创建
)}
);
})()}
>
)}
{
setResultsModalOpen(false);
setResultsMonitorId(null);
}}
>
监控记录
{resultsMonitor?.name ? ` - ${resultsMonitor.name}` : ""}
{resultsMonitor?.nodeId && resultsMonitor.nodeId > 0 ? (
节点:{" "}
{nodeMap.get(resultsMonitor.nodeId)?.name ||
resultsMonitor.nodeId}
) : (
面板执行
)}
{modalResults.length > 0 ? (
最新检查:{" "}
{formatDateTime(modalResults[0].timestamp)}
) : null}
{resultsMonitorId != null ? (
) : null}
{resultsLoading ? (
) : modalResults.length > 0 ? (
时间
结果
延迟
错误
{modalResults.map((r) => (
{formatDateTime(r.timestamp)}
{r.success === 1 ? (
成功
) : (
失败
)}
{Number.isFinite(r.latencyMs)
? `${r.latencyMs.toFixed(0)}ms`
: "-"}
{r.errorMessage || "-"}
))}
) : (
暂无监控记录
)}
setEditModalOpen(false)}>
{editingMonitor ? "编辑监控" : "添加监控"}
setMonitorForm((f) => ({ ...f, name: e.target.value }))
}
/>
setMonitorForm((f) => ({ ...f, target: e.target.value }))
}
/>
setMonitorForm((f) => ({
...f,
intervalSec:
Number(e.target.value) ||
resolvedServiceMonitorLimits.defaultIntervalSec,
}))
}
/>
resolvedServiceMonitorLimits.maxTimeoutSec
? `需在 ${resolvedServiceMonitorLimits.minTimeoutSec}-${resolvedServiceMonitorLimits.maxTimeoutSec}s 范围内`
: undefined
}
isInvalid={
monitorForm.timeoutSec <
resolvedServiceMonitorLimits.minTimeoutSec ||
monitorForm.timeoutSec >
resolvedServiceMonitorLimits.maxTimeoutSec
}
label="超时时间(秒)"
type="number"
value={String(monitorForm.timeoutSec)}
onChange={(e) =>
setMonitorForm((f) => ({
...f,
timeoutSec:
Number(e.target.value) ||
resolvedServiceMonitorLimits.defaultTimeoutSec,
}))
}
/>
setMonitorForm((f) => ({ ...f, enabled: v }))
}
/>
启用
);
}