import { useCallback, useEffect, useState } from 'react'; import { Button, Form, Input, InputNumber, message, Modal, Result, Select, Space, Switch, Table, Tag } from 'antd'; import type { ColumnsType } from 'antd/es/table'; import { alertRuleApi, type AlertRule, type CreateAlertRuleReq, type UpdateAlertRuleReq, } from '../../api/health/alerts'; import { SEVERITY_COLOR, SEVERITY_OPTIONS, DEVICE_TYPE_OPTIONS, CONDITION_TYPE_OPTIONS } from '../../constants/health'; import { usePermission } from '../../hooks/usePermission'; export default function AlertRuleList() { const { hasPermission } = usePermission('health.alerts.list'); if (!hasPermission) return ; const [data, setData] = useState([]); const [total, setTotal] = useState(0); const [loading, setLoading] = useState(false); const [page, setPage] = useState(1); const [modalOpen, setModalOpen] = useState(false); const [editingRule, setEditingRule] = useState(null); const [form] = Form.useForm(); const fetchRules = useCallback(async () => { setLoading(true); try { const res = await alertRuleApi.list({ page, page_size: 20 }); setData(res.data); setTotal(res.total); } catch { message.error('加载规则列表失败'); } finally { setLoading(false); } }, [page]); useEffect(() => { fetchRules(); }, [fetchRules]); const openCreateModal = () => { setEditingRule(null); form.resetFields(); form.setFieldsValue({ severity: 'warning', cooldown_minutes: 60, }); setModalOpen(true); }; const openEditModal = (rule: AlertRule) => { setEditingRule(rule); form.setFieldsValue({ name: rule.name, description: rule.description, device_type: rule.device_type, condition_type: rule.condition_type, condition_params: JSON.stringify(rule.condition_params, null, 2), severity: rule.severity, cooldown_minutes: rule.cooldown_minutes, }); setModalOpen(true); }; const handleSubmit = async () => { try { const values = await form.validateFields(); const conditionParams = JSON.parse(values.condition_params); if (editingRule) { const req: UpdateAlertRuleReq = { name: values.name, description: values.description, condition_params: conditionParams, severity: values.severity, cooldown_minutes: values.cooldown_minutes, version: editingRule.version, }; await alertRuleApi.update(editingRule.id, req); message.success('规则已更新'); } else { const req: CreateAlertRuleReq = { name: values.name, description: values.description, device_type: values.device_type, condition_type: values.condition_type, condition_params: conditionParams, severity: values.severity, cooldown_minutes: values.cooldown_minutes, }; await alertRuleApi.create(req); message.success('规则已创建'); } setModalOpen(false); fetchRules(); } catch (e) { if (e instanceof SyntaxError) { message.error('条件参数 JSON 格式无效'); } } }; const handleToggle = async (rule: AlertRule, active: boolean) => { try { if (!active) { await alertRuleApi.deactivate(rule.id, rule.version); message.success('规则已禁用'); } fetchRules(); } catch { message.error('操作失败'); } }; const columns: ColumnsType = [ { title: '规则名称', dataIndex: 'name', width: 180 }, { title: '指标类型', dataIndex: 'device_type', width: 100, render: (v: string) => DEVICE_TYPE_OPTIONS.find((d) => d.value === v)?.label || v, }, { title: '条件类型', dataIndex: 'condition_type', width: 120, render: (v: string) => CONDITION_TYPE_OPTIONS.find((c) => c.value === v)?.label || v, }, { title: '严重程度', dataIndex: 'severity', width: 90, render: (v: string) => {v}, }, { title: '启用', dataIndex: 'is_active', width: 80, render: (v: boolean, record) => ( handleToggle(record, checked)} /> ), }, { title: '冷却(分)', dataIndex: 'cooldown_minutes', width: 90, }, { title: '操作', width: 80, render: (_, record) => ( ), }, ]; return (

告警规则

rowKey="id" columns={columns} dataSource={data} loading={loading} pagination={{ current: page, total, pageSize: 20, showTotal: (t) => `共 ${t} 条`, onChange: (p) => setPage(p), }} /> setModalOpen(false)} width={560} >