"use client" import { useEffect, useState } from "react" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { useToast } from "@/components/ui/use-toast" import { useRouter } from "next/navigation" interface Metrics { uptime: string active_requests: number total_requests: number total_errors: number num_goroutine: number memory_usage: string avg_response_time: string requests_per_second: number status_code_stats: Record top_paths: Array<{ path: string request_count: number error_count: number avg_latency: string bytes_transferred: number }> recent_requests: Array<{ Time: string Path: string Status: number Latency: number BytesSent: number ClientIP: string }> } export default function DashboardPage() { const [metrics, setMetrics] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const { toast } = useToast() const router = useRouter() const fetchMetrics = async () => { try { const token = localStorage.getItem("token") if (!token) { router.push("/login") return } const response = await fetch("/admin/api/metrics", { headers: { 'Authorization': `Bearer ${token}` } }) if (response.status === 401) { localStorage.removeItem("token") router.push("/login") return } if (!response.ok) { throw new Error("加载监控数据失败") } const data = await response.json() setMetrics(data) setError(null) } catch (error) { const message = error instanceof Error ? error.message : "加载监控数据失败" setError(message) toast({ title: "错误", description: message, variant: "destructive", }) } finally { setLoading(false) } } useEffect(() => { // 立即获取一次数据 fetchMetrics() // 设置定时刷新 const interval = setInterval(fetchMetrics, 5000) return () => clearInterval(interval) }, []) if (loading) { return (
加载中...
正在获取监控数据
) } if (error || !metrics) { return (
{error || "暂无数据"}
请检查后端服务是否正常运行
) } return (
基础指标
运行时间
{metrics.uptime}
当前活跃请求
{metrics.active_requests}
总请求数
{metrics.total_requests}
错误数
{metrics.total_errors}
系统指标
Goroutine数量
{metrics.num_goroutine}
内存使用
{metrics.memory_usage}
平均响应时间
{metrics.avg_response_time}
每秒请求数
{metrics.requests_per_second.toFixed(2)}
状态码统计
{Object.entries(metrics.status_code_stats || {}) .sort((a, b) => a[0].localeCompare(b[0])) .map(([status, count]) => (
状态码 {status}
{count}
))}
热门路径 (Top 10)
{(metrics.top_paths || []).map((path, index) => ( ))}
路径 请求数 错误数 平均延迟 传输大小
{path.path} {path.request_count} {path.error_count} {path.avg_latency} {formatBytes(path.bytes_transferred)}
最近请求
{(metrics.recent_requests || []).map((req, index) => ( ))}
时间 路径 状态 延迟 大小 客户端IP
{formatDate(req.Time)} {req.Path} {req.Status} {formatLatency(req.Latency)} {formatBytes(req.BytesSent)} {req.ClientIP}
) } function formatBytes(bytes: number) { if (bytes === 0) return "0 B" const k = 1024 const sizes = ["B", "KB", "MB", "GB"] const i = Math.floor(Math.log(bytes) / Math.log(k)) return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i] } function formatDate(dateStr: string) { const date = new Date(dateStr) return date.toLocaleTimeString() } function formatLatency(nanoseconds: number) { if (nanoseconds < 1000) { return nanoseconds + " ns" } else if (nanoseconds < 1000000) { return (nanoseconds / 1000).toFixed(2) + " µs" } else if (nanoseconds < 1000000000) { return (nanoseconds / 1000000).toFixed(2) + " ms" } else { return (nanoseconds / 1000000000).toFixed(2) + " s" } } function getStatusColor(status: number) { if (status >= 500) return "bg-red-100 text-red-800" if (status >= 400) return "bg-yellow-100 text-yellow-800" if (status >= 300) return "bg-blue-100 text-blue-800" return "bg-green-100 text-green-800" }