import type { MonitorNodeApiItem } from "@/api/types"; import { useCallback, useEffect, useMemo, useState } from "react"; import toast from "react-hot-toast"; import { RefreshCw } from "lucide-react"; import { AnimatedPage } from "@/components/animated-page"; import { Button } from "@/shadcn-bridge/heroui/button"; import { Card, CardBody, CardHeader } from "@/shadcn-bridge/heroui/card"; import { getMonitorNodes } from "@/api"; import { MonitorView } from "@/pages/node/monitor-view"; type MonitorNode = { id: number; name: string; connectionStatus: "online" | "offline"; }; export default function MonitorPage() { const [nodes, setNodes] = useState([]); const [nodesLoading, setNodesLoading] = useState(false); const [nodesError, setNodesError] = useState(null); const loadNodes = useCallback(async () => { setNodesLoading(true); try { const response = await getMonitorNodes(); if (response.code === 0 && Array.isArray(response.data)) { setNodesError(null); setNodes(response.data); return; } if (response.code === 403) { setNodes([]); setNodesError(response.msg || "暂无监控权限,请联系管理员授权"); return; } toast.error(response.msg || "加载节点失败"); } catch { toast.error("加载节点失败"); } finally { setNodesLoading(false); } }, []); useEffect(() => { void loadNodes(); }, [loadNodes]); useEffect(() => { const timer = window.setInterval(() => { void loadNodes(); }, 30_000); return () => window.clearInterval(timer); }, [loadNodes]); const nodeMap = useMemo(() => { const list: MonitorNode[] = nodes .filter((n) => Number(n.id) > 0) .map((n) => ({ id: Number(n.id), name: String(n.name ?? ""), connectionStatus: n.status === 1 ? "online" : "offline", })); return new Map(list.map((n) => [n.id, n])); }, [nodes]); return (

监控

实时节点状态 + 历史指标图表 + 隧道流量 + 服务监控(TCP/ICMP)
{nodesError ? (

节点列表

{nodesError}
) : null}
); }