import { Plus, Trash2, Edit2, AlertTriangle, Bell, Settings2, Power, PowerOff } from "lucide-react"; import React, { useEffect, useState, useCallback } from "react"; import { Button } from "../ui/button"; import { Input } from "../ui/input"; import { Badge } from "../ui/badge"; import { Switch } from "../ui/switch"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "../ui/select"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from "../ui/dialog"; import { Label } from "../ui/label"; import { inspectionAlertRuleApi, inspectionCatalogApi, type AlertRule, type AlertLevel, type Operator, type DeviceCatalog, } from "../../infrastructure/inspection/inspectionApi"; import { toast } from "../ui/toast"; const LEVEL_OPTIONS: { value: AlertLevel; label: string; color: string }[] = [ { value: "critical", label: "严重", color: "text-red-500 bg-red-500/10 border-red-500/30" }, { value: "warning", label: "警告", color: "text-orange-500 bg-orange-500/10 border-orange-500/30" }, { value: "info", label: "提示", color: "text-blue-500 bg-blue-500/10 border-blue-500/30" }, ]; const OPERATOR_OPTIONS: { value: Operator; label: string }[] = [ { value: ">", label: "大于 ( > )" }, { value: "<", label: "小于 ( < )" }, { value: ">=", label: "大于等于 ( >= )" }, { value: "<=", label: "小于等于 ( <= )" }, { value: "==", label: "等于 ( == )" }, { value: "!=", label: "不等于 ( != )" }, ]; const COMMON_METRICS = [ { value: "cpu_usage", label: "CPU 使用率 (%)", group: "通用" }, { value: "memory_usage", label: "内存使用率 (%)", group: "通用" }, { value: "disk_usage", label: "磁盘使用率 (%)", group: "通用" }, { value: "load_1m", label: "系统负载 (1分钟)", group: "通用" }, { value: "online", label: "设备在线状态", group: "通用" }, { value: "temperature", label: "设备温度 (°C)", group: "网络设备" }, { value: "power_failure_count", label: "电源故障数", group: "网络设备" }, { value: "fan_failure_count", label: "风扇故障数", group: "网络设备" }, { value: "port_down_count", label: "端口 Down 数", group: "网络设备" }, { value: "port_total_count", label: "端口总数", group: "网络设备" }, ]; const SCOPE_OPTIONS = [ { value: "all", label: "全部设备" }, { value: "tier", label: "按设备分级" }, { value: "catalog", label: "按设备类型" }, { value: "device", label: "指定设备" }, ]; export function AlertRulesPage() { const [rules, setRules] = useState([]); const [catalogs, setCatalogs] = useState([]); const [loading, setLoading] = useState(true); const [dialogOpen, setDialogOpen] = useState(false); const [editingRule, setEditingRule] = useState(null); // 筛选条件 const [filterLevel, setFilterLevel] = useState<"all" | AlertLevel>("all"); const [filterScope, setFilterScope] = useState<"all" | "preset" | "custom">("all"); const [searchText, setSearchText] = useState(""); // 表单状态 const [form, setForm] = useState({ name: "", metric: "cpu_usage", operator: ">" as Operator, threshold: "80", level: "warning" as AlertLevel, duration: 1, scope_type: "all" as "all" | "tier" | "catalog" | "device", scope_value: "" as string, enabled: true, }); const loadRules = useCallback(async () => { setLoading(true); try { const [list, catList] = await Promise.all([ inspectionAlertRuleApi.list(), inspectionCatalogApi.list(), ]); setRules(list); setCatalogs(catList); } catch (e: any) { console.error("[AlertRules] 加载失败:", e); } finally { setLoading(false); } }, []); useEffect(() => { loadRules(); }, [loadRules]); const handleCreate = () => { setEditingRule(null); setForm({ name: "", metric: "cpu_usage", operator: ">", threshold: "80", level: "warning", duration: 1, scope_type: "all", scope_value: "", enabled: true, }); setDialogOpen(true); }; const handleEdit = (rule: AlertRule) => { setEditingRule(rule); setForm({ name: rule.name, metric: rule.metric, operator: rule.operator, threshold: rule.threshold, level: rule.level, duration: rule.duration, scope_type: rule.scope_type as any, scope_value: Array.isArray(rule.scope_value) ? rule.scope_value.join(", ") : rule.scope_value || "", enabled: rule.enabled, }); setDialogOpen(true); }; const handleSave = async () => { if (!form.name.trim()) { toast.error("请输入规则名称"); return; } if (!form.threshold.trim()) { toast.error("请输入阈值"); return; } try { const data: Partial = { name: form.name, metric: form.metric, operator: form.operator, threshold: form.threshold, level: form.level, duration: form.duration, scope_type: form.scope_type, scope_value: form.scope_type === "all" ? null : form.scope_type === "device" ? form.scope_value.split(",").map((s) => s.trim()).filter(Boolean) : form.scope_value || null, enabled: form.enabled, }; if (editingRule) { await inspectionAlertRuleApi.update(editingRule.id, data); toast.success("规则已更新"); } else { await inspectionAlertRuleApi.create(data); toast.success("规则已创建"); } setDialogOpen(false); loadRules(); } catch (e: any) { toast.error("保存失败: " + e.message); } }; const handleToggle = async (ruleId: string, enabled: boolean) => { try { await inspectionAlertRuleApi.toggle(ruleId, enabled); toast.success(enabled ? "已启用" : "已停用"); loadRules(); } catch (e: any) { toast.error("操作失败"); } }; const handleDelete = async (ruleId: string) => { if (!confirm("确定要删除这条规则吗?")) return; try { await inspectionAlertRuleApi.remove(ruleId); toast.success("已删除"); loadRules(); } catch (e: any) { toast.error("删除失败"); } }; const getLevelBadge = (level: AlertLevel) => { const opt = LEVEL_OPTIONS.find((l) => l.value === level); return ( {opt?.label} ); }; const getScopeLabel = (rule: AlertRule) => { switch (rule.scope_type) { case "all": return "全部设备"; case "tier": const tierLabels: Record = { core: "核心级", aggregation: "重要级", access: "一般", }; return `分级: ${tierLabels[String(rule.scope_value)] || rule.scope_value}`; case "catalog": const cat = catalogs.find((c) => c.id === rule.scope_value); return `类型: ${cat?.name || rule.scope_value}`; case "device": return `指定设备 (${Array.isArray(rule.scope_value) ? rule.scope_value.length : 0})`; default: return rule.scope_type; } }; // 筛选后的数据 const filteredRules = (rules ?? []).filter((r) => { if (filterLevel !== "all" && r.level !== filterLevel) return false; if (filterScope === "preset" && !r.preset) return false; if (filterScope === "custom" && r.preset) return false; if (searchText) { const s = searchText.toLowerCase(); if (!r.name.toLowerCase().includes(s) && !r.metric.toLowerCase().includes(s)) { return false; } } return true; }); return (
{/* 顶部工具栏 */}

告警规则配置

定义设备巡检的告警触发条件(共 {(rules?.length ?? 0)} 条)

{/* 筛选栏 */}
级别:
{[ { value: "all", label: "全部" }, { value: "critical", label: "严重" }, { value: "warning", label: "警告" }, { value: "info", label: "提示" }, ].map((opt) => ( ))}
分类:
{[ { value: "all", label: "全部" }, { value: "preset", label: "预置" }, { value: "custom", label: "自定义" }, ].map((opt) => ( ))}
setSearchText(e.target.value)} className="h-8 text-xs" />
{/* 规则列表 */}
{loading ? (
加载中...
) : filteredRules.length === 0 ? (

暂无符合条件的告警规则

点击右上角新增规则开始配置

) : (
{filteredRules.map((rule) => (
{/* 启用开关 */}
handleToggle(rule.id, v)} /> {rule.enabled ? "启用" : "停用"}
{/* 规则信息 */}
{rule.name} {getLevelBadge(rule.level)} {rule.preset && ( 预置 )}
{COMMON_METRICS.find((m) => m.value === rule.metric)?.label || rule.metric} {rule.operator} {rule.threshold} | {getScopeLabel(rule)} {rule.duration > 1 && ( <> | 持续 {rule.duration} 次 )}
{/* 操作按钮 */}
{!rule.preset && ( )}
))}
)}
{/* 编辑弹窗 */} {editingRule ? "编辑告警规则" : "新增告警规则"}
{/* 规则名称 */}
setForm({ ...form, name: e.target.value })} />
{/* 指标 + 操作符 + 阈值 */}
setForm({ ...form, threshold: e.target.value })} />
{/* 告警级别 */}
{LEVEL_OPTIONS.map((opt) => ( ))}
{/* 适用范围 */}
{form.scope_type !== "all" && ( )}
{form.scope_type === "device" && ( setForm({ ...form, scope_value: e.target.value })} className="mt-1" /> )}
{/* 持续次数 */}
setForm({ ...form, duration: parseInt(e.target.value, 10) || 1 }) } className="w-24" /> 连续触发 N 次后才产生告警,避免瞬时波动误报
); } export default AlertRulesPage;