Files
users/components/dialogs/api-monitor-dialog.tsx
v0 b17b488f8e refactor: restructure navigation and module layout
Reorganize navigation and module structure based on new requirements.

Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
2026-01-31 04:32:36 +00:00

169 lines
6.8 KiB
TypeScript

"use client"
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"
import { Card, CardContent } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Activity, Clock, Zap, AlertTriangle, CheckCircle } from "lucide-react"
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, AreaChart, Area } from "recharts"
interface APIMonitorDialogProps {
open: boolean
onOpenChange: (open: boolean) => void
api?: {
name: string
endpoint: string
}
}
const LATENCY_DATA = [
{ time: "00:00", p50: 28, p95: 45, p99: 68 },
{ time: "04:00", p50: 25, p95: 42, p99: 62 },
{ time: "08:00", p50: 32, p95: 55, p99: 85 },
{ time: "12:00", p50: 45, p95: 78, p99: 120 },
{ time: "16:00", p50: 42, p95: 72, p99: 110 },
{ time: "20:00", p50: 35, p95: 58, p99: 88 },
]
const QPS_DATA = [
{ time: "00:00", qps: 450 },
{ time: "04:00", qps: 280 },
{ time: "08:00", qps: 850 },
{ time: "12:00", qps: 1200 },
{ time: "16:00", qps: 1100 },
{ time: "20:00", qps: 780 },
]
const ERROR_DATA = [
{ time: "00:00", rate: 0.1 },
{ time: "04:00", rate: 0.05 },
{ time: "08:00", rate: 0.15 },
{ time: "12:00", rate: 0.3 },
{ time: "16:00", rate: 0.2 },
{ time: "20:00", rate: 0.12 },
]
export function APIMonitorDialog({ open, onOpenChange, api }: APIMonitorDialogProps) {
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-4xl max-h-[85vh] overflow-y-auto">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<Activity className="w-5 h-5" />
API监控 - {api?.name || "API服务"}
</DialogTitle>
<DialogDescription>{api?.endpoint}</DialogDescription>
</DialogHeader>
{/* 实时指标 */}
<div className="grid grid-cols-4 gap-4">
<Card className="bg-slate-50">
<CardContent className="p-4">
<div className="flex items-center justify-between">
<div>
<p className="text-xs text-slate-500">QPS</p>
<p className="text-2xl font-bold text-slate-800">1,156</p>
</div>
<Zap className="w-8 h-8 text-blue-500" />
</div>
<p className="text-xs text-emerald-600 mt-1">峰值: 1,200</p>
</CardContent>
</Card>
<Card className="bg-slate-50">
<CardContent className="p-4">
<div className="flex items-center justify-between">
<div>
<p className="text-xs text-slate-500">P99延迟</p>
<p className="text-2xl font-bold text-slate-800">95ms</p>
</div>
<Clock className="w-8 h-8 text-amber-500" />
</div>
<p className="text-xs text-slate-500 mt-1">P50: 32ms</p>
</CardContent>
</Card>
<Card className="bg-slate-50">
<CardContent className="p-4">
<div className="flex items-center justify-between">
<div>
<p className="text-xs text-slate-500"></p>
<p className="text-2xl font-bold text-emerald-600">99.85%</p>
</div>
<CheckCircle className="w-8 h-8 text-emerald-500" />
</div>
<p className="text-xs text-emerald-600 mt-1">SLA: 99.9%</p>
</CardContent>
</Card>
<Card className="bg-slate-50">
<CardContent className="p-4">
<div className="flex items-center justify-between">
<div>
<p className="text-xs text-slate-500"></p>
<p className="text-2xl font-bold text-red-600">156</p>
</div>
<AlertTriangle className="w-8 h-8 text-red-500" />
</div>
<p className="text-xs text-slate-500 mt-1"> -23%</p>
</CardContent>
</Card>
</div>
{/* QPS趋势 */}
<div className="space-y-2">
<h4 className="text-sm font-medium">QPS趋势</h4>
<div className="h-48 bg-slate-50 rounded-lg p-4">
<ResponsiveContainer width="100%" height="100%">
<AreaChart data={QPS_DATA}>
<CartesianGrid strokeDasharray="3 3" stroke="#e2e8f0" />
<XAxis dataKey="time" tick={{ fontSize: 12 }} stroke="#94a3b8" />
<YAxis tick={{ fontSize: 12 }} stroke="#94a3b8" />
<Tooltip />
<Area type="monotone" dataKey="qps" stroke="#3b82f6" fill="#93c5fd" fillOpacity={0.5} />
</AreaChart>
</ResponsiveContainer>
</div>
</div>
{/* 延迟分布 */}
<div className="space-y-2">
<h4 className="text-sm font-medium"> (ms)</h4>
<div className="h-48 bg-slate-50 rounded-lg p-4">
<ResponsiveContainer width="100%" height="100%">
<LineChart data={LATENCY_DATA}>
<CartesianGrid strokeDasharray="3 3" stroke="#e2e8f0" />
<XAxis dataKey="time" tick={{ fontSize: 12 }} stroke="#94a3b8" />
<YAxis tick={{ fontSize: 12 }} stroke="#94a3b8" />
<Tooltip />
<Line type="monotone" dataKey="p50" stroke="#22c55e" strokeWidth={2} name="P50" />
<Line type="monotone" dataKey="p95" stroke="#f59e0b" strokeWidth={2} name="P95" />
<Line type="monotone" dataKey="p99" stroke="#ef4444" strokeWidth={2} name="P99" />
</LineChart>
</ResponsiveContainer>
</div>
</div>
{/* 最近错误 */}
<div className="space-y-2">
<h4 className="text-sm font-medium"></h4>
<div className="space-y-2">
{[
{ time: "14:35:12", code: 429, message: "Rate limit exceeded", count: 23 },
{ time: "14:32:08", code: 500, message: "Internal server error", count: 5 },
{ time: "14:28:45", code: 404, message: "User not found", count: 12 },
].map((error, i) => (
<div key={i} className="flex items-center justify-between p-3 bg-slate-50 rounded-lg">
<div className="flex items-center gap-3">
<Badge className="bg-red-100 text-red-700">{error.code}</Badge>
<span className="text-sm text-slate-700">{error.message}</span>
</div>
<div className="flex items-center gap-4 text-sm text-slate-500">
<span>{error.count} </span>
<span>{error.time}</span>
</div>
</div>
))}
</div>
</div>
</DialogContent>
</Dialog>
)
}