'use client'; import * as React from 'react'; import { useCallback, useEffect, useRef, useState } from 'react'; import { toast } from 'sonner'; import { Activity, Cpu, Database, HardDrive, Layers, RefreshCw, } from 'lucide-react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Switch } from '@/components/ui/switch'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Badge } from '@/components/ui/badge'; import { Progress } from '@/components/ui/progress'; import { Skeleton } from '@/components/ui/skeleton'; import type { SystemStatus } from '@/lib/services/admin'; import services from '@/lib/services'; /** * 格式化数字,每3位加逗号 */ const formatNumber = (num: number | string) => { if (num === undefined || num === null) return '0'; return num.toString().replace(/\B(?=(\d{3})+(?!\B))/g, ','); }; /** * 运行时系统状态展示与管理组件 */ export function SystemStatusManager() { const [status, setStatus] = useState(null); const [loading, setLoading] = useState(true); const [wavelet, setWavelet] = useState(false); const [autoRefresh, setAutoRefresh] = useState(true); const [intervalTime, setIntervalTime] = useState('5000'); // 默认5秒 const intervalRef = useRef(null); const prevStatusRef = useRef(null); const [changedFields, setChangedFields] = useState>( {}, ); // 获取状态数据 const fetchStatus = useCallback(async (isSilent = false) => { if (!isSilent) setWavelet(true); try { const data = await services.adminStatus.getSystemStatus(); // 检测变化的字段用于微动画效果 if (prevStatusRef.current) { const changes: Record = {}; Object.keys(data).forEach((key) => { const k = key as keyof SystemStatus; if (prevStatusRef.current && prevStatusRef.current[k] !== data[k]) { changes[k] = true; } }); setChangedFields(changes); // 1秒后清除变化状态 setTimeout(() => { setChangedFields({}); }, 1000); } setStatus(data); prevStatusRef.current = data; } catch (err) { toast.error('获取系统状态失败', { description: err instanceof Error ? err.message : '请求时发生未知错误', }); } finally { setLoading(false); setWavelet(false); } }, []); // 轮询逻辑 useEffect(() => { // 首次加载 fetchStatus(); }, [fetchStatus]); useEffect(() => { if (intervalRef.current) { clearInterval(intervalRef.current); } if (autoRefresh) { const time = parseInt(intervalTime, 10); intervalRef.current = setInterval(() => { fetchStatus(true); }, time); } return () => { if (intervalRef.current) { clearInterval(intervalRef.current); } }; }, [autoRefresh, intervalTime, fetchStatus]); // 计算内存分配百分比 (Alloc / Sys) const getMemoryUsagePercent = () => { if (!status) return 0; const parseSizeToBytes = (sizeStr: string): number => { const parts = sizeStr.split(' '); if (parts.length < 2) return 0; const value = parseFloat(parts[0]); const unit = parts[1].toLowerCase(); if (unit.startsWith('gib')) return value * 1024 * 1024 * 1024; if (unit.startsWith('mib')) return value * 1024 * 1024; if (unit.startsWith('kib')) return value * 1024; return value; }; const alloc = parseSizeToBytes(status.alloc); const sys = parseSizeToBytes(status.sys); if (sys === 0) return 0; return Math.min(Math.round((alloc / sys) * 100), 100); }; // 闪烁动画类 const getPulseClass = (field: string) => { return changedFields[field] ? 'animate-pulse text-primary font-bold transition-all duration-300 scale-105 inline-block' : 'transition-all duration-300'; }; const RenderMetricRow = ({ label, value, field, }: { label: string; value: string | number; field?: string; }) => (
{label} {typeof value === 'number' ? formatNumber(value) : value}
); if (loading) { return (
); } return (
{/* 顶部控制栏 */}

系统状态

{autoRefresh && ( )}
{status && ( <> {/* 主网格排版 */}
{/* 1. 服务概览 */}
服务概览 服务的基础生命指标
{/* 2. 内存统计 */}
内存统计 主内存消耗概览
{/* 物理内存水位比例 */}
当前使用率 (Alloc / Sys) {getMemoryUsagePercent()}%
{/* 3. 堆/栈详情 */}
堆/栈详情 运行时堆栈内存空间细节
{/* 4. 底层组件与结构体 */}
底层及结构体内存 运行时底层管理结构体开销
{/* 5. 垃圾回收与分配计数 */}
垃圾回收与分配计数 GC 历史数据与分配频次
)}
); }