增加代码编辑器表单组件
This commit is contained in:
parent
54545a91ec
commit
1791eb13cb
@ -35,6 +35,7 @@ import {
|
|||||||
updateTemplate,
|
updateTemplate,
|
||||||
getTemplateById,
|
getTemplateById,
|
||||||
checkTemplateCodeUnique,
|
checkTemplateCodeUnique,
|
||||||
|
renderTemplate,
|
||||||
} from '../service';
|
} from '../service';
|
||||||
import { TemplateEditor, TemplateRender } from './';
|
import { TemplateEditor, TemplateRender } from './';
|
||||||
|
|
||||||
@ -57,6 +58,8 @@ const formSchema = z.object({
|
|||||||
channelType: z.nativeEnum(NotificationChannelType),
|
channelType: z.nativeEnum(NotificationChannelType),
|
||||||
contentTemplate: z.string().min(1, '请输入模板内容'),
|
contentTemplate: z.string().min(1, '请输入模板内容'),
|
||||||
templateConfig: z.object({
|
templateConfig: z.object({
|
||||||
|
// 用于后端多态反序列化,必须存在
|
||||||
|
channelType: z.nativeEnum(NotificationChannelType),
|
||||||
// 企业微信配置
|
// 企业微信配置
|
||||||
messageType: z.enum(['TEXT', 'MARKDOWN', 'FILE']).optional(),
|
messageType: z.enum(['TEXT', 'MARKDOWN', 'FILE']).optional(),
|
||||||
// 邮件配置
|
// 邮件配置
|
||||||
@ -78,6 +81,9 @@ export const NotificationTemplateDialog: React.FC<NotificationTemplateDialogProp
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
const [showPreview, setShowPreview] = useState(false);
|
const [showPreview, setShowPreview] = useState(false);
|
||||||
|
const [previewRendering, setPreviewRendering] = useState(false);
|
||||||
|
const [renderedContent, setRenderedContent] = useState<string>('');
|
||||||
|
const [currentEnabled, setCurrentEnabled] = useState<boolean>(true);
|
||||||
const [formData, setFormData] = useState<Record<string, any>>({});
|
const [formData, setFormData] = useState<Record<string, any>>({});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -102,6 +108,7 @@ export const NotificationTemplateDialog: React.FC<NotificationTemplateDialogProp
|
|||||||
const watchedChannelType = watch('channelType');
|
const watchedChannelType = watch('channelType');
|
||||||
const watchedCode = watch('code');
|
const watchedCode = watch('code');
|
||||||
const watchedTemplate = watch('contentTemplate');
|
const watchedTemplate = watch('contentTemplate');
|
||||||
|
const watchedTemplateConfig = watch('templateConfig');
|
||||||
|
|
||||||
// 验证编码唯一性
|
// 验证编码唯一性
|
||||||
const validateCodeUnique = async (code: string) => {
|
const validateCodeUnique = async (code: string) => {
|
||||||
@ -147,20 +154,33 @@ export const NotificationTemplateDialog: React.FC<NotificationTemplateDialogProp
|
|||||||
}
|
}
|
||||||
}, [open, editId]);
|
}, [open, editId]);
|
||||||
|
|
||||||
|
// 同步内层 templateConfig.channelType,确保后端多态识别
|
||||||
|
useEffect(() => {
|
||||||
|
if (watchedChannelType) {
|
||||||
|
setValue('templateConfig.channelType', watchedChannelType as any);
|
||||||
|
}
|
||||||
|
}, [watchedChannelType, setValue]);
|
||||||
|
|
||||||
const loadTemplateData = async () => {
|
const loadTemplateData = async () => {
|
||||||
if (!editId) return;
|
if (!editId) return;
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const data = await getTemplateById(editId);
|
const data = await getTemplateById(editId);
|
||||||
|
const cfg = data.templateConfig || TemplateConfigFormFactory.getDefaultConfig(data.channelType);
|
||||||
|
// 补齐内部的 channelType
|
||||||
|
if (!cfg.channelType) {
|
||||||
|
(cfg as any).channelType = data.channelType;
|
||||||
|
}
|
||||||
reset({
|
reset({
|
||||||
name: data.name,
|
name: data.name,
|
||||||
code: data.code,
|
code: data.code,
|
||||||
description: data.description || '',
|
description: data.description || '',
|
||||||
channelType: data.channelType,
|
channelType: data.channelType,
|
||||||
contentTemplate: data.contentTemplate,
|
contentTemplate: data.contentTemplate,
|
||||||
templateConfig: data.templateConfig || TemplateConfigFormFactory.getDefaultConfig(data.channelType),
|
templateConfig: cfg,
|
||||||
});
|
});
|
||||||
|
setCurrentEnabled(Boolean(data.enabled));
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
toast({
|
toast({
|
||||||
variant: 'destructive',
|
variant: 'destructive',
|
||||||
@ -173,18 +193,61 @@ export const NotificationTemplateDialog: React.FC<NotificationTemplateDialogProp
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 处理预览按钮点击
|
||||||
|
const handlePreviewClick = async () => {
|
||||||
|
if (!watchedTemplate || !watchedTemplate.trim()) {
|
||||||
|
toast({
|
||||||
|
variant: 'destructive',
|
||||||
|
title: '无法预览',
|
||||||
|
description: '请先输入模板内容',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPreviewRendering(true);
|
||||||
|
try {
|
||||||
|
// 先调用渲染 API
|
||||||
|
const content = await renderTemplate(
|
||||||
|
watchedTemplate,
|
||||||
|
formData || {}
|
||||||
|
);
|
||||||
|
|
||||||
|
// 渲染成功,保存结果并弹出预览窗口
|
||||||
|
setRenderedContent(content);
|
||||||
|
setShowPreview(true);
|
||||||
|
} catch (error: any) {
|
||||||
|
// 渲染失败,显示错误提示,不弹出窗口
|
||||||
|
toast({
|
||||||
|
variant: 'destructive',
|
||||||
|
title: '渲染失败',
|
||||||
|
description: error.response?.data?.message || error.message || '模板渲染出错,请检查模板语法',
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setPreviewRendering(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const onSubmit = async (values: FormValues) => {
|
const onSubmit = async (values: FormValues) => {
|
||||||
setSaving(true);
|
setSaving(true);
|
||||||
try {
|
try {
|
||||||
|
// 确保 templateConfig不为空
|
||||||
|
const templateConfig = values.templateConfig || TemplateConfigFormFactory.getDefaultConfig(values.channelType);
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
|
id: editId!,
|
||||||
name: values.name,
|
name: values.name,
|
||||||
code: values.code,
|
code: values.code,
|
||||||
description: values.description,
|
description: values.description,
|
||||||
channelType: values.channelType,
|
channelType: values.channelType,
|
||||||
contentTemplate: values.contentTemplate,
|
contentTemplate: values.contentTemplate,
|
||||||
templateConfig: values.templateConfig || TemplateConfigFormFactory.getDefaultConfig(values.channelType),
|
enabled: currentEnabled,
|
||||||
|
templateConfig: templateConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log('=== 提交模板数据 ===');
|
||||||
|
console.log('Payload:', JSON.stringify(payload, null, 2));
|
||||||
|
console.log('TemplateConfig:', templateConfig);
|
||||||
|
|
||||||
if (mode === 'edit' && editId) {
|
if (mode === 'edit' && editId) {
|
||||||
await updateTemplate(editId, payload);
|
await updateTemplate(editId, payload);
|
||||||
toast({ title: '更新成功' });
|
toast({ title: '更新成功' });
|
||||||
@ -196,6 +259,9 @@ export const NotificationTemplateDialog: React.FC<NotificationTemplateDialogProp
|
|||||||
onSuccess();
|
onSuccess();
|
||||||
onOpenChange(false);
|
onOpenChange(false);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
console.error('=== 提交失败 ===');
|
||||||
|
console.error('Error:', error);
|
||||||
|
console.error('Response:', error.response?.data);
|
||||||
toast({
|
toast({
|
||||||
variant: 'destructive',
|
variant: 'destructive',
|
||||||
title: mode === 'edit' ? '更新失败' : '创建失败',
|
title: mode === 'edit' ? '更新失败' : '创建失败',
|
||||||
@ -217,14 +283,14 @@ export const NotificationTemplateDialog: React.FC<NotificationTemplateDialogProp
|
|||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<DialogBody className="flex-1 overflow-hidden">
|
<DialogBody className="flex-1 overflow-y-auto">
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="flex items-center justify-center py-8">
|
<div className="flex items-center justify-center py-8">
|
||||||
<Loader2 className="h-6 w-6 animate-spin mr-2" />
|
<Loader2 className="h-6 w-6 animate-spin mr-2" />
|
||||||
加载中...
|
加载中...
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<form onSubmit={handleSubmit(onSubmit)} className="h-full flex flex-col space-y-4">
|
<form onSubmit={handleSubmit(onSubmit)} className="flex flex-col space-y-4">
|
||||||
{/* 基础信息 */}
|
{/* 基础信息 */}
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@ -317,7 +383,7 @@ export const NotificationTemplateDialog: React.FC<NotificationTemplateDialogProp
|
|||||||
register,
|
register,
|
||||||
errors,
|
errors,
|
||||||
setValue,
|
setValue,
|
||||||
configState: {},
|
configState: watchedTemplateConfig || {},
|
||||||
updateConfigState: () => {},
|
updateConfigState: () => {},
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
@ -326,7 +392,7 @@ export const NotificationTemplateDialog: React.FC<NotificationTemplateDialogProp
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 模板编辑器区域 */}
|
{/* 模板编辑器区域 */}
|
||||||
<div className="flex-1 flex flex-col min-h-0">
|
<div className="flex flex-col">
|
||||||
<div className="flex items-center justify-between mb-2">
|
<div className="flex items-center justify-between mb-2">
|
||||||
<Label>
|
<Label>
|
||||||
模板内容 <span className="text-destructive">*</span>
|
模板内容 <span className="text-destructive">*</span>
|
||||||
@ -337,16 +403,21 @@ export const NotificationTemplateDialog: React.FC<NotificationTemplateDialogProp
|
|||||||
type="button"
|
type="button"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => setShowPreview(!showPreview)}
|
onClick={handlePreviewClick}
|
||||||
|
disabled={previewRendering}
|
||||||
>
|
>
|
||||||
|
{previewRendering ? (
|
||||||
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||||
|
) : (
|
||||||
<Eye className="mr-2 h-4 w-4" />
|
<Eye className="mr-2 h-4 w-4" />
|
||||||
{showPreview ? '隐藏预览' : '显示预览'}
|
)}
|
||||||
|
{previewRendering ? '渲染中...' : '显示预览'}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-1 min-h-0">
|
<div className="h-[500px]">
|
||||||
<TemplateEditor
|
<TemplateEditor
|
||||||
value={watchedTemplate}
|
value={watchedTemplate}
|
||||||
onChange={(value) => setValue('contentTemplate', value)}
|
onChange={(value) => setValue('contentTemplate', value)}
|
||||||
@ -391,12 +462,10 @@ export const NotificationTemplateDialog: React.FC<NotificationTemplateDialogProp
|
|||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>模板预览</DialogTitle>
|
<DialogTitle>模板预览</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<DialogBody className="flex-1 overflow-hidden">
|
<DialogBody className="flex-1 overflow-auto">
|
||||||
<TemplateRender
|
<div className="whitespace-pre-wrap font-mono text-sm bg-muted/30 p-4 rounded border">
|
||||||
template={watchedTemplate}
|
{renderedContent}
|
||||||
channelType={watchedChannelType}
|
</div>
|
||||||
formData={formData}
|
|
||||||
/>
|
|
||||||
</DialogBody>
|
</DialogBody>
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button variant="outline" onClick={() => setShowPreview(false)}>
|
<Button variant="outline" onClick={() => setShowPreview(false)}>
|
||||||
|
|||||||
@ -203,15 +203,15 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
|
|||||||
return (
|
return (
|
||||||
<div className="flex gap-4 h-full w-full">
|
<div className="flex gap-4 h-full w-full">
|
||||||
{/* 编辑器区域 */}
|
{/* 编辑器区域 */}
|
||||||
<div className="flex-1 border rounded-lg flex flex-col min-h-[400px]">
|
<div className="flex-1 border rounded-lg flex flex-col overflow-hidden">
|
||||||
<div className="p-3 border-b bg-muted/50">
|
<div className="p-3 border-b bg-muted/50 flex-shrink-0">
|
||||||
<h3 className="font-medium">模板编辑器</h3>
|
<h3 className="font-medium">模板编辑器</h3>
|
||||||
<p className="text-xs text-muted-foreground mt-1">
|
<p className="text-xs text-muted-foreground mt-1">
|
||||||
支持 FreeMarker 语法,使用 ${'{'}变量名{'}'} 插入变量
|
支持 FreeMarker 语法,使用 ${'{'}变量名{'}'} 插入变量
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-1 min-h-[300px] overflow-hidden">
|
<div className="flex-1 overflow-hidden">
|
||||||
<Editor
|
<Editor
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
value={value}
|
value={value}
|
||||||
@ -266,8 +266,8 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
|
|||||||
|
|
||||||
{/* 变量面板 - 只在编辑模式显示 */}
|
{/* 变量面板 - 只在编辑模式显示 */}
|
||||||
{mode === 'edit' && (
|
{mode === 'edit' && (
|
||||||
<div className="w-80 border rounded-lg flex flex-col">
|
<div className="w-80 border rounded-lg flex flex-col overflow-hidden">
|
||||||
<div className="p-3 border-b bg-muted/50">
|
<div className="p-3 border-b bg-muted/50 flex-shrink-0">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-medium">可用变量</h3>
|
<h3 className="font-medium">可用变量</h3>
|
||||||
@ -287,7 +287,7 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-1 min-h-0">
|
<div className="flex-1 overflow-hidden">
|
||||||
{console.log('formSchema:', formSchema)}
|
{console.log('formSchema:', formSchema)}
|
||||||
{formSchema ? (
|
{formSchema ? (
|
||||||
<ScrollArea className="h-full">
|
<ScrollArea className="h-full">
|
||||||
@ -304,7 +304,7 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex-1 flex items-center justify-center p-8">
|
<div className="flex items-center justify-center h-full p-8">
|
||||||
<div className="text-center text-muted-foreground">
|
<div className="text-center text-muted-foreground">
|
||||||
<Settings className="h-12 w-12 mx-auto mb-3 opacity-30" />
|
<Settings className="h-12 w-12 mx-auto mb-3 opacity-30" />
|
||||||
<p className="text-sm mb-2">暂无变量表单</p>
|
<p className="text-sm mb-2">暂无变量表单</p>
|
||||||
|
|||||||
@ -10,14 +10,18 @@ export const EmailTemplateConfigForm: React.FC<TemplateConfigComponentProps> = (
|
|||||||
register,
|
register,
|
||||||
errors,
|
errors,
|
||||||
setValue,
|
setValue,
|
||||||
|
configState,
|
||||||
}) => {
|
}) => {
|
||||||
|
const currentContentType = configState?.contentType || 'TEXT';
|
||||||
|
const currentPriority = configState?.priority || 'NORMAL';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<Label htmlFor="contentType">内容类型</Label>
|
<Label htmlFor="contentType">内容类型</Label>
|
||||||
<Select
|
<Select
|
||||||
|
value={currentContentType}
|
||||||
onValueChange={(value) => setValue('templateConfig.contentType', value)}
|
onValueChange={(value) => setValue('templateConfig.contentType', value)}
|
||||||
defaultValue="TEXT"
|
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="选择内容类型" />
|
<SelectValue placeholder="选择内容类型" />
|
||||||
@ -37,8 +41,8 @@ export const EmailTemplateConfigForm: React.FC<TemplateConfigComponentProps> = (
|
|||||||
<div>
|
<div>
|
||||||
<Label htmlFor="priority">优先级</Label>
|
<Label htmlFor="priority">优先级</Label>
|
||||||
<Select
|
<Select
|
||||||
|
value={currentPriority}
|
||||||
onValueChange={(value) => setValue('templateConfig.priority', value)}
|
onValueChange={(value) => setValue('templateConfig.priority', value)}
|
||||||
defaultValue="NORMAL"
|
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="选择优先级" />
|
<SelectValue placeholder="选择优先级" />
|
||||||
|
|||||||
@ -34,10 +34,10 @@ export class TemplateConfigFormFactory {
|
|||||||
static getDefaultConfig(type: NotificationChannelType): any {
|
static getDefaultConfig(type: NotificationChannelType): any {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case NotificationChannelType.WEWORK:
|
case NotificationChannelType.WEWORK:
|
||||||
return { messageType: 'TEXT' };
|
return { channelType: NotificationChannelType.WEWORK, messageType: 'TEXT' };
|
||||||
|
|
||||||
case NotificationChannelType.EMAIL:
|
case NotificationChannelType.EMAIL:
|
||||||
return { contentType: 'TEXT', priority: 'NORMAL' };
|
return { channelType: NotificationChannelType.EMAIL, contentType: 'TEXT', priority: 'NORMAL' };
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
|
|||||||
@ -10,14 +10,17 @@ export const WeworkTemplateConfigForm: React.FC<TemplateConfigComponentProps> =
|
|||||||
register,
|
register,
|
||||||
errors,
|
errors,
|
||||||
setValue,
|
setValue,
|
||||||
|
configState,
|
||||||
}) => {
|
}) => {
|
||||||
|
const currentValue = configState?.messageType || 'TEXT';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<Label htmlFor="messageType">消息类型</Label>
|
<Label htmlFor="messageType">消息类型</Label>
|
||||||
<Select
|
<Select
|
||||||
|
value={currentValue}
|
||||||
onValueChange={(value) => setValue('templateConfig.messageType', value)}
|
onValueChange={(value) => setValue('templateConfig.messageType', value)}
|
||||||
defaultValue="TEXT"
|
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="选择消息类型" />
|
<SelectValue placeholder="选择消息类型" />
|
||||||
|
|||||||
@ -44,12 +44,19 @@ export const getTemplateById = async (id: number): Promise<NotificationTemplateD
|
|||||||
* 创建模板
|
* 创建模板
|
||||||
*/
|
*/
|
||||||
export const createTemplate = async (
|
export const createTemplate = async (
|
||||||
template: Pick<NotificationTemplateDTO, 'name' | 'code' | 'description' | 'channelType' | 'contentTemplate'>
|
template: Pick<NotificationTemplateDTO, 'name' | 'code' | 'description' | 'channelType' | 'contentTemplate' | 'templateConfig'>
|
||||||
): Promise<NotificationTemplateDTO> => {
|
): Promise<NotificationTemplateDTO> => {
|
||||||
return request.post(`${API_PREFIX}`, {
|
// 确保 channelType 在 templateConfig 之前
|
||||||
...template,
|
const payload = {
|
||||||
|
name: template.name,
|
||||||
|
code: template.code,
|
||||||
|
description: template.description,
|
||||||
|
channelType: template.channelType,
|
||||||
|
contentTemplate: template.contentTemplate,
|
||||||
|
templateConfig: template.templateConfig,
|
||||||
enabled: true, // 默认启用
|
enabled: true, // 默认启用
|
||||||
});
|
};
|
||||||
|
return request.post(`${API_PREFIX}`, payload);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,9 +64,20 @@ export const createTemplate = async (
|
|||||||
*/
|
*/
|
||||||
export const updateTemplate = async (
|
export const updateTemplate = async (
|
||||||
id: number,
|
id: number,
|
||||||
template: Pick<NotificationTemplateDTO, 'name' | 'code' | 'description' | 'channelType' | 'contentTemplate'>
|
template: Pick<NotificationTemplateDTO, 'id' | 'name' | 'code' | 'description' | 'channelType' | 'contentTemplate' | 'templateConfig' | 'enabled'>
|
||||||
): Promise<NotificationTemplateDTO> => {
|
): Promise<NotificationTemplateDTO> => {
|
||||||
return request.put(`${API_PREFIX}/${id}`, template);
|
// 确保字段顺序:channelType 必须在 templateConfig 之前
|
||||||
|
const payload = {
|
||||||
|
id: template.id ?? id,
|
||||||
|
name: template.name,
|
||||||
|
code: template.code,
|
||||||
|
description: template.description,
|
||||||
|
channelType: template.channelType,
|
||||||
|
contentTemplate: template.contentTemplate,
|
||||||
|
enabled: template.enabled,
|
||||||
|
templateConfig: template.templateConfig,
|
||||||
|
};
|
||||||
|
return request.put(`${API_PREFIX}/${id}`, payload);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -65,12 +65,16 @@ export interface BaseTemplateConfig {
|
|||||||
|
|
||||||
/** 企业微信模板配置 */
|
/** 企业微信模板配置 */
|
||||||
export interface WeworkTemplateConfig extends BaseTemplateConfig {
|
export interface WeworkTemplateConfig extends BaseTemplateConfig {
|
||||||
|
/** 渠道类型(与外层保持一致,用于后端多态反序列化) */
|
||||||
|
channelType: NotificationChannelType.WEWORK;
|
||||||
/** 消息类型 */
|
/** 消息类型 */
|
||||||
messageType: 'TEXT' | 'MARKDOWN' | 'FILE';
|
messageType: 'TEXT' | 'MARKDOWN' | 'FILE';
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 邮件模板配置 */
|
/** 邮件模板配置 */
|
||||||
export interface EmailTemplateConfig extends BaseTemplateConfig {
|
export interface EmailTemplateConfig extends BaseTemplateConfig {
|
||||||
|
/** 渠道类型(与外层保持一致,用于后端多态反序列化) */
|
||||||
|
channelType: NotificationChannelType.EMAIL;
|
||||||
/** 内容类型 */
|
/** 内容类型 */
|
||||||
contentType: 'TEXT' | 'HTML';
|
contentType: 'TEXT' | 'HTML';
|
||||||
/** 优先级 */
|
/** 优先级 */
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user