diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index f1483a3..66d5a4b 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -33,7 +33,7 @@ export default function Dashboard() { const { data: serverData } = useQuery({ queryKey: ['servers', 'metrics'], queryFn: getServerMetrics, - refetchInterval: 10_000, + refetchInterval: 15_000, }) const userTrendOption = useMemo(() => ({ @@ -68,15 +68,18 @@ export default function Dashboard() { {serverData?.servers?.map(s => ( -
- {s.name}{s.network.ip} - +
+
+ {s.name} + {s.network.privateIp} / {s.network.publicIp} +
+ - CPU {s.cpu.usagePercent}% + CPU {s.cpu.usagePercent}% ({s.cpu.cores}c) 80 ? '#ff4d4f' : '#1677ff'} showInfo={false} /> - 内存 {s.memory.percent}% + RAM {s.memory.percent}% 80 ? '#ff4d4f' : '#52c41a'} showInfo={false} /> diff --git a/src/pages/Servers.tsx b/src/pages/Servers.tsx index 3b61870..d6a1f5c 100644 --- a/src/pages/Servers.tsx +++ b/src/pages/Servers.tsx @@ -1,68 +1,110 @@ -import { useQuery } from '@tanstack/react-query' -import { Card, Row, Col, Progress, Table, Tag, Typography, theme, Space } from 'antd' -import { CloudServerOutlined, DashboardOutlined } from '@ant-design/icons' -import { getServerMetrics, type ServerInfo } from '@/services/server-api' +import { useState } from 'react' +import { useQuery, useQueryClient } from '@tanstack/react-query' +import { Card, Row, Col, Progress, Table, Tag, Typography, Button, Space, Tooltip, message } from 'antd' +import { CloudServerOutlined, ReloadOutlined, CopyOutlined, GlobalOutlined } from '@ant-design/icons' +import { getServerMetrics, type ServerInfo, type ProcessInfo } from '@/services/server-api' const { Text, Title } = Typography function ServerCard({ server }: { server: ServerInfo }) { - theme.useToken() - const cpuColor = server.cpu.usagePercent > 80 ? 'red' : server.cpu.usagePercent > 50 ? 'orange' : 'green' - const memColor = server.memory.percent > 80 ? 'red' : server.memory.percent > 50 ? 'orange' : 'green' + const cpuColor = server.cpu.usagePercent > 80 ? '#ff4d4f' : server.cpu.usagePercent > 50 ? '#faad14' : '#52c41a' + const memColor = server.memory.percent > 80 ? '#ff4d4f' : server.memory.percent > 50 ? '#faad14' : '#52c41a' return ( - {server.name}{server.role}} - extra={{server.network.ip}} - style={{ height: '100%' }}> - - - CPU ({server.cpu.cores}核) - - {server.cpu.model?.slice(0, 40)} - - - 内存 - - {server.memory.used}/{server.memory.total} - - - 磁盘 - 80 ? 'red' : 'blue'} size="small" /> - {server.disk.used}/{server.disk.total} - - - 运行时间 -
{server.uptime}
+ {server.name}{server.role}} + style={{ height: '100%' }} + > + {/* Network info */} + + + + { navigator.clipboard.writeText(server.network.publicIp); message.success('已复制') }}> + 🌐 {server.network.publicIp} + + { navigator.clipboard.writeText(server.network.privateIp); message.success('已复制') }}> + 🔒 {server.network.privateIp} + + {server.network.domains.map(d => ( + { navigator.clipboard.writeText(d); message.success('已复制') }}> + {d} + + ))} + + + {/* Metrics */} + + + CPU ({server.cpu.cores}核) + `${p}%`} /> + {server.cpu.model?.slice(0, 30)} + + + 内存 + `${p}%`} /> + {server.memory.used}/{server.memory.total} + + + 磁盘 + {server.disks.map(d => ( +
+ + {d.mount} + 80 ? '#ff4d4f' : '#1677ff'} style={{ flex: 1, margin: 0 }} /> + {d.used}/{d.total} + +
+ ))} + + + 运行时间 +
{server.uptime}
+ +
+ + {/* Processes */} ( + {name} + )}, + { title: 'CPU', dataIndex: 'cpu', width: 55 }, + { title: 'MEM', dataIndex: 'mem', width: 55 }, ]} - locale={{ emptyText: '暂无进程数据' }} + locale={{ emptyText: '暂无进程' }} /> ) } export default function ServersPage() { + const qc = useQueryClient() + const [refreshing, setRefreshing] = useState(false) + const { data } = useQuery({ queryKey: ['servers', 'metrics'], queryFn: getServerMetrics, - refetchInterval: 10_000, + refetchInterval: 15_000, }) + const handleRefresh = async () => { + setRefreshing(true) + await qc.invalidateQueries({ queryKey: ['servers', 'metrics'] }) + setTimeout(() => setRefreshing(false), 1000) + } + return (
- <DashboardOutlined /> 服务器运维 +
+ <CloudServerOutlined /> 服务器运维 + +
{(data?.servers || []).map(s => (
diff --git a/src/services/server-api.ts b/src/services/server-api.ts index 7cae6a9..4acafc9 100644 --- a/src/services/server-api.ts +++ b/src/services/server-api.ts @@ -1,15 +1,15 @@ import { api } from './http-client' +export interface DiskInfo { mount: string; total: string; used: string; free: string; percent: number } +export interface ProcessInfo { pid: number; cpu: string; mem: string; name: string; command: string } export interface ServerInfo { - name: string - role: string - hostname: string - cpu: { model: string; cores: number; usagePercent: number; loadAvg: number[] } - memory: { total: string; used: string; free: string; percent: number } - disk: { total: string; used: string; free: string; percent: number } - uptime: string - network: { ip: string } - processes: { pid: number; cpu: string; mem: string; command: string }[] + name: string; role: string; hostname: string; + cpu: { model: string; cores: number; usagePercent: number }; + memory: { total: string; used: string; free: string; percent: number }; + disks: DiskInfo[]; + uptime: string; + processes: ProcessInfo[]; + network: { publicIp: string; privateIp: string; domains: string[] }; } export function getServerMetrics(): Promise<{ servers: ServerInfo[] }> {