feat: V1 - DAG编排/告警系统/Agent循环/知识库RAG/Webhook + 审核管理富上下文修复
This commit is contained in:
@@ -0,0 +1,107 @@
|
|||||||
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
|
import {
|
||||||
|
Card, Table, Button, Tag, Space, message, Badge, Empty, Typography,
|
||||||
|
} from 'antd';
|
||||||
|
import {
|
||||||
|
BellOutlined, CheckOutlined, ReloadOutlined,
|
||||||
|
} from '@ant-design/icons';
|
||||||
|
import { alertApi } from '@/api';
|
||||||
|
import type { Alert } from '@/types';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
|
const { Text } = Typography;
|
||||||
|
|
||||||
|
const severityConfig: Record<string, { label: string; color: string; badge: string }> = {
|
||||||
|
critical: { label: '严重', color: 'red', badge: 'error' },
|
||||||
|
warning: { label: '警告', color: 'orange', badge: 'warning' },
|
||||||
|
info: { label: '通知', color: 'blue', badge: 'processing' },
|
||||||
|
};
|
||||||
|
|
||||||
|
const alertTypeConfig: Record<string, string> = {
|
||||||
|
budget_warning: '预算警告',
|
||||||
|
budget_exceeded: '预算超限',
|
||||||
|
task_failed: '任务失败',
|
||||||
|
worker_offline: 'Worker离线',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Alerts() {
|
||||||
|
const [alerts, setAlerts] = useState<Alert[]>([]);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [filter, setFilter] = useState<string>('all'); // all, unread, read
|
||||||
|
|
||||||
|
const loadData = useCallback(() => {
|
||||||
|
setLoading(true);
|
||||||
|
const isRead = filter === 'unread' ? false : filter === 'read' ? true : undefined;
|
||||||
|
alertApi.list(isRead).then(setAlerts).catch(() => {}).finally(() => setLoading(false));
|
||||||
|
}, [filter]);
|
||||||
|
|
||||||
|
useEffect(() => { loadData(); }, [loadData]);
|
||||||
|
|
||||||
|
const handleMarkRead = async (id: number) => {
|
||||||
|
try {
|
||||||
|
await alertApi.markRead(id);
|
||||||
|
message.success('已标记为已读');
|
||||||
|
loadData();
|
||||||
|
} catch { message.error('操作失败'); }
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: '级别', dataIndex: 'severity', key: 'severity', width: 80,
|
||||||
|
render: (s: string) => {
|
||||||
|
const cfg = severityConfig[s] || { label: s, color: 'default', badge: 'default' };
|
||||||
|
return <Badge status={cfg.badge as any} text={cfg.label} />;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '类型', dataIndex: 'alert_type', key: 'alert_type', width: 120,
|
||||||
|
render: (t: string, r: Alert) => <Tag color={severityConfig[r.severity]?.color || 'default'}>{alertTypeConfig[t] || t}</Tag>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '消息', dataIndex: 'message', key: 'message',
|
||||||
|
render: (m: string) => <Text style={{ whiteSpace: 'pre-wrap' }}>{m}</Text>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '时间', dataIndex: 'created_at', key: 'created_at', width: 160,
|
||||||
|
render: (t: string) => <Text style={{ fontSize: 12 }}>{dayjs(t).format('MM-DD HH:mm:ss')}</Text>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态', dataIndex: 'is_read', key: 'is_read', width: 80,
|
||||||
|
render: (r: boolean) => r ? <Text type="secondary">已读</Text> : <Tag color="orange">未读</Tag>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作', key: 'action', width: 80,
|
||||||
|
render: (_: any, r: Alert) => r.is_read ? null : (
|
||||||
|
<Button size="small" icon={<CheckOutlined />} onClick={() => handleMarkRead(r.id)}>已读</Button>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const filterButtons = [
|
||||||
|
{ key: 'all', label: '全部' },
|
||||||
|
{ key: 'unread', label: '未读' },
|
||||||
|
{ key: 'read', label: '已读' },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Card
|
||||||
|
title={<Space><BellOutlined /> 告警中心</Space>}
|
||||||
|
extra={
|
||||||
|
<Space>
|
||||||
|
{filterButtons.map(f => (
|
||||||
|
<Button key={f.key} type={filter === f.key ? 'primary' : 'default'} onClick={() => setFilter(f.key)}>{f.label}</Button>
|
||||||
|
))}
|
||||||
|
<Button icon={<ReloadOutlined />} onClick={loadData} />
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{alerts.length === 0 && !loading ? (
|
||||||
|
<Empty description="暂无告警记录" />
|
||||||
|
) : (
|
||||||
|
<Table columns={columns} dataSource={alerts} rowKey="id" loading={loading} pagination={{ pageSize: 15 }} />
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user