Files
users/app/system/alerts/page.tsx
v0 1219166526 refactor: overhaul system navigation based on 5 HTML docs
Reorganize modules, add AI Agent smart interaction, include prompt settings, enhance data output with subscriptions, and separate system monitoring.

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

347 lines
14 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client"
import { useState } from "react"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Switch } from "@/components/ui/switch"
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import {
Bell, Plus, Settings, CheckCircle2, AlertTriangle,
XCircle, Clock, Eye, Trash2, BellOff
} from "lucide-react"
const alerts = [
{
id: "1",
title: "磁盘使用率超过70%",
description: "服务器磁盘使用率达到72%,建议清理或扩容",
severity: "warning",
source: "系统监控",
time: "2024-01-15 14:30:00",
status: "active",
},
{
id: "2",
title: "AI推理服务延迟升高",
description: "AI推理服务平均延迟达到230ms超过预设阈值200ms",
severity: "warning",
source: "AI Agent",
time: "2024-01-15 13:45:00",
status: "active",
},
{
id: "3",
title: "数据同步任务失败",
description: "用户行为数据同步任务执行失败,已自动重试",
severity: "error",
source: "数据接入",
time: "2024-01-15 10:20:00",
status: "resolved",
},
]
const alertRules = [
{ id: "1", name: "CPU使用率告警", condition: "CPU > 80%", severity: "critical", enabled: true },
{ id: "2", name: "内存使用率告警", condition: "内存 > 85%", severity: "critical", enabled: true },
{ id: "3", name: "磁盘使用率告警", condition: "磁盘 > 70%", severity: "warning", enabled: true },
{ id: "4", name: "API延迟告警", condition: "延迟 > 500ms", severity: "warning", enabled: true },
{ id: "5", name: "任务失败告警", condition: "失败次数 > 3", severity: "error", enabled: false },
]
export default function AlertsPage() {
const [activeTab, setActiveTab] = useState("active")
const [showCreateDialog, setShowCreateDialog] = useState(false)
const getSeverityBadge = (severity: string) => {
switch (severity) {
case "critical":
return <Badge className="bg-red-100 text-red-700"></Badge>
case "error":
return <Badge className="bg-red-100 text-red-700"></Badge>
case "warning":
return <Badge className="bg-yellow-100 text-yellow-700"></Badge>
case "info":
return <Badge className="bg-blue-100 text-blue-700"></Badge>
default:
return <Badge variant="secondary"></Badge>
}
}
const getSeverityIcon = (severity: string) => {
switch (severity) {
case "critical":
case "error":
return <XCircle className="h-5 w-5 text-red-500" />
case "warning":
return <AlertTriangle className="h-5 w-5 text-yellow-500" />
default:
return <Bell className="h-5 w-5 text-blue-500" />
}
}
return (
<div className="space-y-6">
{/* 页面标题 */}
<div className="flex items-center justify-between">
<div>
<h1 className="text-2xl font-bold text-foreground"></h1>
<p className="text-muted-foreground"></p>
</div>
<Button onClick={() => setShowCreateDialog(true)}>
<Plus className="mr-2 h-4 w-4" />
</Button>
</div>
{/* 统计卡片 */}
<div className="grid gap-4 md:grid-cols-4">
<Card>
<CardContent className="pt-6">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-muted-foreground"></p>
<p className="text-2xl font-bold text-yellow-600">2</p>
</div>
<AlertTriangle className="h-8 w-8 text-yellow-500" />
</div>
</CardContent>
</Card>
<Card>
<CardContent className="pt-6">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-muted-foreground"></p>
<p className="text-2xl font-bold">5</p>
</div>
<Bell className="h-8 w-8 text-blue-500" />
</div>
</CardContent>
</Card>
<Card>
<CardContent className="pt-6">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-muted-foreground"></p>
<p className="text-2xl font-bold text-green-600">3</p>
</div>
<CheckCircle2 className="h-8 w-8 text-green-500" />
</div>
</CardContent>
</Card>
<Card>
<CardContent className="pt-6">
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-muted-foreground"></p>
<p className="text-2xl font-bold">5</p>
</div>
<Settings className="h-8 w-8 text-purple-500" />
</div>
</CardContent>
</Card>
</div>
{/* 主内容区 */}
<Tabs value={activeTab} onValueChange={setActiveTab}>
<TabsList>
<TabsTrigger value="active">
<Badge className="ml-2 bg-yellow-100 text-yellow-700">2</Badge>
</TabsTrigger>
<TabsTrigger value="history"></TabsTrigger>
<TabsTrigger value="rules"></TabsTrigger>
</TabsList>
<TabsContent value="active" className="space-y-4">
{alerts.filter(a => a.status === "active").map((alert) => (
<Card key={alert.id}>
<CardContent className="pt-6">
<div className="flex items-start justify-between">
<div className="flex items-start gap-4">
{getSeverityIcon(alert.severity)}
<div>
<div className="flex items-center gap-2 mb-1">
<h3 className="font-semibold">{alert.title}</h3>
{getSeverityBadge(alert.severity)}
</div>
<p className="text-sm text-muted-foreground mb-2">{alert.description}</p>
<div className="flex items-center gap-4 text-xs text-muted-foreground">
<span>: {alert.source}</span>
<span>: {alert.time}</span>
</div>
</div>
</div>
<div className="flex items-center gap-2">
<Button variant="outline" size="sm">
<Eye className="h-4 w-4 mr-1" />
</Button>
<Button size="sm">
<CheckCircle2 className="h-4 w-4 mr-1" />
</Button>
</div>
</div>
</CardContent>
</Card>
))}
</TabsContent>
<TabsContent value="history" className="space-y-4">
<Card>
<CardContent className="pt-6">
<Table>
<TableHeader>
<TableRow>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{alerts.map((alert) => (
<TableRow key={alert.id}>
<TableCell className="font-medium">{alert.title}</TableCell>
<TableCell>{getSeverityBadge(alert.severity)}</TableCell>
<TableCell>{alert.source}</TableCell>
<TableCell>{alert.time}</TableCell>
<TableCell>
{alert.status === "resolved" ? (
<Badge className="bg-green-100 text-green-700"></Badge>
) : (
<Badge className="bg-yellow-100 text-yellow-700"></Badge>
)}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
</TabsContent>
<TabsContent value="rules" className="space-y-4">
<Card>
<CardContent className="pt-6">
<Table>
<TableHeader>
<TableRow>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead className="text-right"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{alertRules.map((rule) => (
<TableRow key={rule.id}>
<TableCell className="font-medium">{rule.name}</TableCell>
<TableCell>
<code className="text-sm bg-muted px-2 py-1 rounded">{rule.condition}</code>
</TableCell>
<TableCell>{getSeverityBadge(rule.severity)}</TableCell>
<TableCell>
<Switch checked={rule.enabled} />
</TableCell>
<TableCell className="text-right">
<div className="flex items-center justify-end gap-1">
<Button variant="ghost" size="sm">
<Settings className="h-4 w-4" />
</Button>
<Button variant="ghost" size="sm" className="text-red-600">
<Trash2 className="h-4 w-4" />
</Button>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
</TabsContent>
</Tabs>
{/* 创建告警规则弹窗 */}
<Dialog open={showCreateDialog} onOpenChange={setShowCreateDialog}>
<DialogContent>
<DialogHeader>
<DialogTitle></DialogTitle>
<DialogDescription></DialogDescription>
</DialogHeader>
<div className="space-y-4">
<div className="space-y-2">
<Label></Label>
<Input placeholder="输入规则名称" />
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label></Label>
<Select>
<SelectTrigger>
<SelectValue placeholder="选择指标" />
</SelectTrigger>
<SelectContent>
<SelectItem value="cpu">CPU使用率</SelectItem>
<SelectItem value="memory">使</SelectItem>
<SelectItem value="disk">使</SelectItem>
<SelectItem value="latency">API延迟</SelectItem>
<SelectItem value="error_rate"></SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label></Label>
<Input placeholder="输入阈值" type="number" />
</div>
</div>
<div className="space-y-2">
<Label></Label>
<Select>
<SelectTrigger>
<SelectValue placeholder="选择严重程度" />
</SelectTrigger>
<SelectContent>
<SelectItem value="critical"></SelectItem>
<SelectItem value="warning"></SelectItem>
<SelectItem value="info"></SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label></Label>
<div className="grid grid-cols-3 gap-2">
<label className="flex items-center gap-2 p-3 border rounded-lg cursor-pointer hover:bg-muted">
<input type="checkbox" defaultChecked />
<span></span>
</label>
<label className="flex items-center gap-2 p-3 border rounded-lg cursor-pointer hover:bg-muted">
<input type="checkbox" />
<span></span>
</label>
<label className="flex items-center gap-2 p-3 border rounded-lg cursor-pointer hover:bg-muted">
<input type="checkbox" />
<span></span>
</label>
</div>
</div>
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setShowCreateDialog(false)}></Button>
<Button></Button>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
)
}