Files
aiops/frontend/src/components/monitor/alertShared.tsx
T

97 lines
3.8 KiB
TypeScript

import { Mail, Phone, MessageSquare, Bell } from 'lucide-react';
// 将 notify_channels (可能是数组/JSON字符串/逗号分隔) 解析为数组
export function parseChannels(notifyChannels: any): string[] {
if (!notifyChannels) return [];
if (Array.isArray(notifyChannels)) return notifyChannels;
if (typeof notifyChannels === 'string') {
try {
const parsed = JSON.parse(notifyChannels);
if (Array.isArray(parsed)) return parsed;
} catch {
// 非JSON,尝试逗号分隔
}
return notifyChannels.split(',').map((s) => s.trim()).filter(Boolean);
}
return [];
}
// 已知的渠道类型(用于旧数据兼容 — 旧规则存储类型字符串而非渠道 ID)
export const KNOWN_CHANNEL_TYPES = ['email', 'sms', 'dingtalk', 'wechat', 'webhook'];
// 根据渠道类型获取图标组件名(用字符串映射,组件内用 getChannelIcon 返回实际组件)
export const CHANNEL_TYPE_LABELS: Record<string, string> = {
dingtalk: '钉钉',
wechat: '企业微信',
email: '邮件',
sms: '短信',
webhook: 'Webhook',
};
// 解析单个 notify_channels 引用值 — 返回 {id?, type, name, isLegacy}
// 新格式存渠道 ID (string),旧格式存类型字符串 (email/dingtalk 等)
export function resolveChannelRef(value: string, channels: any[]): { type: string; name: string; isLegacy: boolean } | null {
if (!value) return null;
// 尝试按 ID 匹配已配置渠道
const ch = channels.find((c) => String(c.id) === String(value));
if (ch) return { type: ch.type || 'unknown', name: ch.name || ch.type || '未命名', isLegacy: false };
// 兼容旧格式:值本身是类型字符串
if (KNOWN_CHANNEL_TYPES.includes(value)) {
return { type: value, name: CHANNEL_TYPE_LABELS[value] || value, isLegacy: true };
}
return null;
}
// 渠道类型选项(供下拉选择)
export const CHANNEL_TYPES: { key: string; label: string; placeholder: string }[] = [
{ key: 'dingtalk', label: '钉钉', placeholder: '{\n "webhook": "https://oapi.dingtalk.com/robot/send?access_token=***",\n "secret": "SECxxx"\n}' },
{ key: 'wechat', label: '企业微信', placeholder: '{\n "webhook": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=***"\n}' },
{ key: 'email', label: '邮件', placeholder: '{\n "to": "ops@ezops.io",\n "subject": "告警通知"\n}' },
{ key: 'sms', label: '短信', placeholder: '{\n "phones": "13800138000",\n "sign": "AIOps"\n}' },
{ key: 'webhook', label: 'Webhook', placeholder: '{\n "url": "https://example.com/alert"\n}' },
];
export function getChannelTypeLabel(type: string) {
return CHANNEL_TYPES.find((t) => t.key === type)?.label || type;
}
// 根据渠道类型返回对应图标组件
export function getChannelIcon(type: string) {
switch (type) {
case 'email':
return Mail;
case 'sms':
return Phone;
case 'dingtalk':
case 'wechat':
return MessageSquare;
default:
return Bell;
}
}
// 渲染规则的通知渠道引用列表(兼容新格式=渠道ID 和 旧格式=类型字符串)
export function renderRuleChannels(rule: any, notifyChannels: any[]) {
const refs = parseChannels(rule.notify_channels);
if (refs.length === 0) return <span className="text-xs text-slate-600">--</span>;
return (
<div className="flex flex-wrap gap-1">
{refs.map((ref) => {
const resolved = resolveChannelRef(ref, notifyChannels);
if (!resolved) return null;
const Icon = getChannelIcon(resolved.type);
return (
<span
key={ref}
title={`${resolved.name} (${getChannelTypeLabel(resolved.type)})`}
className="inline-flex items-center gap-1 text-xs px-1.5 py-0.5 rounded bg-slate-800 text-slate-300"
>
<Icon className="h-3 w-3 text-slate-400" />
{resolved.name}
</span>
);
})}
</div>
);
}