Files
aiops/frontend/src/components/monitor/alert-center/AlertChannelDialog.tsx
T
attacker 5333f6f04a feat(alert-center): 添加飞书Webhook通知渠道 + 告警引擎实时通知
- 后端: NotifyChannel 模型新增 feishu 类型, FeishuWebhookConfig
- 后端: TestNotifyChannel 真实发送飞书测试消息(文本格式)
- 后端: 告警引擎触发/恢复时自动发送飞书通知(sendFeishuAlert/sendFeishuRecovery)
- 后端: AlertEngine 新增 tcp_time_wait/tcp_close_wait/service_process 指标检测
- 后端: NetworkStatModel 新增 TCPCloseWait 字段
- 后端: QuickSetupRules 一键创建6条告警规则(CPU/内存/磁盘/TIME_WAIT/CLOSE_WAIT/进程)
- 后端: 注册 /alerts/quick-setup 路由
- 前端: AlertChannelDialog 新增飞书类型选项
- 前端: helpers 新增 getChannelIcon/getChannelTypeLabel 支持 feishu/dingtalk/wechat
2026-06-24 08:34:43 +00:00

123 lines
4.5 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.
// 通知渠道创建/编辑对话框 // Logan.Li
import React, { useState, useEffect } from 'react';
import {
Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter,
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
} from '@/components/ui/select';
import { toast } from 'sonner';
import { alertApi } from '@/services/api';
import type { NotificationChannel } from './alert-center-helpers';
const CHANNEL_TYPES = [
{ value: 'dingtalk', label: '钉钉', hint: '钉钉机器人: webhook URL + secret' },
{ value: 'wechat', label: '企业微信', hint: '企业微信: webhook URL' },
{ value: 'feishu', label: '飞书', hint: '飞书机器人: {"url":"https://open.feishu.cn/open-apis/bot/v2/hook/..."}' },
{ value: 'email', label: '邮件', hint: '邮件: {"to":"ops@ezops.io"}' },
{ value: 'sms', label: '短信', hint: '短信: {"phones":"13800138000"}' },
{ value: 'webhook', label: 'Webhook', hint: 'Webhook: {"url":"https://..."}' },
];
export function AlertChannelDialog({
open,
onOpenChange,
editingChannel,
onSaved,
}: {
open: boolean;
onOpenChange: (open: boolean) => void;
editingChannel: NotificationChannel | null;
onSaved: () => void;
}) {
const [form, setForm] = useState({ name: '', type: 'dingtalk', config: '' });
const [saving, setSaving] = useState(false);
// Logan.Li — 对话框打开时同步编辑数据
useEffect(() => {
if (open) {
if (editingChannel) {
setForm({ name: editingChannel.name, type: editingChannel.type, config: editingChannel.config || '' });
} else {
setForm({ name: '', type: 'dingtalk', config: '' });
}
}
}, [open, editingChannel]);
const handleSave = async () => {
if (!form.name.trim()) return;
setSaving(true);
try {
const payload = { name: form.name.trim(), type: form.type, config: form.config.trim() };
if (editingChannel) {
await alertApi.updateNotifyChannel(editingChannel.id, payload);
toast.success('渠道已更新');
} else {
await alertApi.createNotifyChannel(payload);
toast.success('渠道已添加');
}
onOpenChange(false);
onSaved();
} catch {
toast.error('保存失败');
} finally {
setSaving(false);
}
};
const currentHint = CHANNEL_TYPES.find(t => t.value === form.type)?.hint || '';
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent>
<DialogHeader>
<DialogTitle>{editingChannel ? '编辑通知渠道' : '添加通知渠道'}</DialogTitle>
<DialogDescription>配置告警通知渠道(钉钉/企业微信/邮件/短信/Webhook)</DialogDescription>
</DialogHeader>
<div className="space-y-4">
<div className="space-y-2">
<Label>渠道名称 *</Label>
<Input
value={form.name}
onChange={(e) => setForm({ ...form, name: e.target.value })}
placeholder="如:运维告警群"
/>
</div>
<div className="space-y-2">
<Label>渠道类型</Label>
<Select value={form.type} onValueChange={(v) => setForm({ ...form, type: v })}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
{CHANNEL_TYPES.map(t => (
<SelectItem key={t.value} value={t.value}>{t.label}</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label>配置(JSON)</Label>
<Input
value={form.config}
onChange={(e) => setForm({ ...form, config: e.target.value })}
placeholder='{"webhook":"https://...","secret":"..."}'
className="font-mono text-sm"
/>
<p className="text-xs text-muted-foreground">{currentHint}</p>
</div>
</div>
<DialogFooter>
<Button variant="outline" onClick={() => onOpenChange(false)}>取消</Button>
<Button onClick={handleSave} disabled={!form.name.trim() || saving}>
{saving ? '保存中...' : editingChannel ? '保存修改' : '添加渠道'}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}