cs
2 months ago
3 changed files with 168 additions and 38 deletions
-
181src/pages/message/my/index.tsx
-
10src/pages/message/template/index.tsx
-
15src/store/message/my.ts
@ -1,5 +1,5 @@ |
|||||
import {useTranslation} from '@/i18n.ts' |
import {useTranslation} from '@/i18n.ts' |
||||
import {Badge, Button, Divider, Form, Input, Space, Tooltip} from 'antd' |
|
||||
|
import {Badge, Button, Divider, Form, Input, Select, Space, Tooltip} from 'antd' |
||||
import {useAtom, useAtomValue} from 'jotai' |
import {useAtom, useAtomValue} from 'jotai' |
||||
import React, {useEffect, useMemo, useState} from 'react' |
import React, {useEffect, useMemo, useState} from 'react' |
||||
import {BetaSchemaForm, ProColumns, ProFormColumnsType,} from '@ant-design/pro-components' |
import {BetaSchemaForm, ProColumns, ProFormColumnsType,} from '@ant-design/pro-components' |
||||
@ -10,6 +10,7 @@ import {getValueCount, unSetColumnRules} from '@/utils' |
|||||
import {Table as ProTable} from '@/components/table' |
import {Table as ProTable} from '@/components/table' |
||||
import {msgListAtom, msgSearchAtom, saveMsgAtom} from "@/store/message/my.ts"; |
import {msgListAtom, msgSearchAtom, saveMsgAtom} from "@/store/message/my.ts"; |
||||
import {templateAllListAtom} from "@/store/message/template.ts"; |
import {templateAllListAtom} from "@/store/message/template.ts"; |
||||
|
import {IMsgTemplate} from "@/types/message/template.ts"; |
||||
|
|
||||
const i18nPrefix = 'msgMy.list' |
const i18nPrefix = 'msgMy.list' |
||||
|
|
||||
@ -26,8 +27,77 @@ const MdwMessage = () => { |
|||||
|
|
||||
const [open, setOpen] = useState(false) |
const [open, setOpen] = useState(false) |
||||
const [openFilter, setFilterOpen] = useState(false) |
const [openFilter, setFilterOpen] = useState(false) |
||||
|
const [currentTemplate, setCurrentTemplate] = useState<IMsgTemplate>() |
||||
const [searchKey, setSearchKey] = useState(search?.title) |
const [searchKey, setSearchKey] = useState(search?.title) |
||||
|
|
||||
|
const [templateType, setTemplateType] = useState('') |
||||
|
const typeHandlerChange = (value: string) => { |
||||
|
if (value !== 'EMAIL') { |
||||
|
setTemplateTitle('') |
||||
|
form.setFieldsValue({'title': undefined}) |
||||
|
} |
||||
|
setTemplateType(value) |
||||
|
} |
||||
|
|
||||
|
const templateChange = (index: number) => { |
||||
|
if (templateList && index !== undefined) { |
||||
|
// key转换
|
||||
|
const result = templateList[index].fields.split(',').map(item => { |
||||
|
return { |
||||
|
field_key: item, |
||||
|
field_value: '' |
||||
|
}; |
||||
|
}); |
||||
|
setCurrentTemplate(templateList[index]) |
||||
|
form.setFieldsValue({...templateList[index], 'fieldList': result}) |
||||
|
setTemplateType(templateList[index].type) |
||||
|
setTemplateTitle(templateList[index].title) |
||||
|
setTemplateContent(templateList[index].content) |
||||
|
} else { |
||||
|
form.resetFields() |
||||
|
setTemplateType('') |
||||
|
setCurrentTemplate(undefined) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const [templateTitle, setTemplateTitle] = useState(''); |
||||
|
const [templateContent, setTemplateContent] = useState(''); |
||||
|
|
||||
|
useEffect(() => { |
||||
|
handleChange() |
||||
|
}, [templateTitle, templateContent]); |
||||
|
|
||||
|
const handleContentChange = (e) => { |
||||
|
const value = e.target.value; |
||||
|
setTemplateContent(value) |
||||
|
}; |
||||
|
|
||||
|
const titheHandleContentChange = (e) => { |
||||
|
const value = e.target.value; |
||||
|
setTemplateTitle(value) |
||||
|
}; |
||||
|
|
||||
|
const handleChange = () => { |
||||
|
// 使用正则表达式匹配 ${var} 格式的变量
|
||||
|
const regex = /\${\.([a-zA-Z0-9_]+)}/g; |
||||
|
const matches = [...(templateTitle + templateContent).matchAll(regex)]; |
||||
|
|
||||
|
// 提取变量名
|
||||
|
const variables = Array.from(new Set(matches.map(match => match[1]))); |
||||
|
const result = variables.map(item => { |
||||
|
return { |
||||
|
field_key: item, |
||||
|
field_value: '' |
||||
|
}; |
||||
|
}); |
||||
|
form.setFieldsValue({'fieldList': result}) |
||||
|
}; |
||||
|
|
||||
|
const handleInputChange = (index, e) => { |
||||
|
form.getFieldValue("fieldList")[index].field_value = e.target.value |
||||
|
} |
||||
|
|
||||
|
|
||||
const drawerColumns = useMemo(() => { |
const drawerColumns = useMemo(() => { |
||||
return [ |
return [ |
||||
{ |
{ |
||||
@ -38,7 +108,25 @@ const MdwMessage = () => { |
|||||
formItemProps: {hidden: true} |
formItemProps: {hidden: true} |
||||
}, |
}, |
||||
{ |
{ |
||||
title: t(`${i18nPrefix}.columns.type`, '选择模板'), |
|
||||
|
title: t(`${i18nPrefix}.columns.template`, '选择模板'), |
||||
|
valueType: 'select', |
||||
|
fieldProps: { |
||||
|
allowClear: true, |
||||
|
}, |
||||
|
renderFormItem: () => { |
||||
|
return <Select onChange={templateChange}> |
||||
|
{ |
||||
|
templateList?.map((template, index) => ( |
||||
|
<Select.Option key={index} value={index}> |
||||
|
{template.name} |
||||
|
</Select.Option> |
||||
|
)) |
||||
|
} |
||||
|
</Select> |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
title: t(`${i18nPrefix}.columns.type`, '消息类型'), |
||||
dataIndex: 'type', |
dataIndex: 'type', |
||||
valueType: 'select', |
valueType: 'select', |
||||
fieldProps: { |
fieldProps: { |
||||
@ -48,6 +136,7 @@ const MdwMessage = () => { |
|||||
{label: 'Telegram', value: 'TG'} |
{label: 'Telegram', value: 'TG'} |
||||
], |
], |
||||
allowClear: false, |
allowClear: false, |
||||
|
onChange: typeHandlerChange |
||||
}, |
}, |
||||
formItemProps: { |
formItemProps: { |
||||
rules: [ |
rules: [ |
||||
@ -64,46 +153,60 @@ const MdwMessage = () => { |
|||||
fieldProps: { |
fieldProps: { |
||||
maxLength: 100, |
maxLength: 100, |
||||
showCount: true, |
showCount: true, |
||||
|
onChange: titheHandleContentChange, |
||||
|
}, |
||||
|
formItemProps: { |
||||
|
tooltip: '支持邮件类型', |
||||
|
hidden: templateType != 'EMAIL', |
||||
|
rules: [ |
||||
|
{ |
||||
|
required: templateType == 'EMAIL', |
||||
|
message: t('message.required', '模板内容必填') |
||||
|
} |
||||
|
] |
||||
}, |
}, |
||||
}, |
}, |
||||
{ |
{ |
||||
title: t(`${i18nPrefix}.columns.content`, '模板内容'), |
|
||||
|
title: t(`${i18nPrefix}.columns.content`, '正文'), |
||||
dataIndex: 'content', |
dataIndex: 'content', |
||||
valueType: 'textarea', |
valueType: 'textarea', |
||||
fieldProps: { |
fieldProps: { |
||||
defaultValue: "你好,我叫${.name}", |
|
||||
maxLength: 1000, |
maxLength: 1000, |
||||
showCount: true, |
showCount: true, |
||||
rows: 15, |
rows: 15, |
||||
|
onChange: handleContentChange, |
||||
}, |
}, |
||||
formItemProps: { |
formItemProps: { |
||||
rules: [ |
rules: [ |
||||
{ |
{ |
||||
required: true, |
required: true, |
||||
message: t('message.required', '模板内容必填') |
|
||||
|
message: t('message.required', '内容必填') |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
}, |
}, |
||||
{ |
{ |
||||
title: t(`${i18nPrefix}.columns.field`, '识别到的变量'), |
|
||||
dataIndex: 'field', |
|
||||
renderFormItem: () => { |
|
||||
|
title: t(`${i18nPrefix}.columns.fieldList`, '填充变量'), |
||||
|
dataIndex: 'fieldList', |
||||
|
formItemProps: { |
||||
|
hidden: currentTemplate === undefined, |
||||
|
}, |
||||
|
renderFormItem: (_, config) => { |
||||
return ( |
return ( |
||||
<> |
<> |
||||
{ |
{ |
||||
templateList?.map((variable, index) => ( |
|
||||
|
config.value?.map((variable, index) => ( |
||||
<div key={index} style={{marginBottom: 8}}> |
<div key={index} style={{marginBottom: 8}}> |
||||
<Input |
<Input |
||||
addonBefore={`${variable.name}:`} |
|
||||
defaultValue="" |
|
||||
placeholder={`请输入${variable}`} |
|
||||
|
addonBefore={variable.field_key} |
||||
|
onChange={(e) => handleInputChange(index, e)} |
||||
/> |
/> |
||||
</div> |
</div> |
||||
))} |
|
||||
|
)) |
||||
|
} |
||||
</> |
</> |
||||
); |
); |
||||
} |
|
||||
|
}, |
||||
}, |
}, |
||||
{ |
{ |
||||
title: t(`${i18nPrefix}.columns.dest`, '收件人(多个收件人用英文逗号隔开,如果类型是TG,则填token)'), |
title: t(`${i18nPrefix}.columns.dest`, '收件人(多个收件人用英文逗号隔开,如果类型是TG,则填token)'), |
||||
@ -112,12 +215,20 @@ const MdwMessage = () => { |
|||||
fieldProps: { |
fieldProps: { |
||||
maxLength: 1000, |
maxLength: 1000, |
||||
showCount: true, |
showCount: true, |
||||
rows: 15, |
|
||||
|
rows: 5, |
||||
placeholder: '[email protected],[email protected]', |
placeholder: '[email protected],[email protected]', |
||||
}, |
}, |
||||
|
formItemProps: { |
||||
|
rules: [ |
||||
|
{ |
||||
|
required: true, |
||||
|
message: t('message.required', '内容必填') |
||||
|
} |
||||
|
] |
||||
|
} |
||||
}, |
}, |
||||
] as ProColumns[] |
] as ProColumns[] |
||||
}, [search]) |
|
||||
|
}, [search, templateType, templateList]) |
||||
|
|
||||
const columns = useMemo(() => { |
const columns = useMemo(() => { |
||||
return [ |
return [ |
||||
@ -129,17 +240,37 @@ const MdwMessage = () => { |
|||||
formItemProps: {hidden: true} |
formItemProps: {hidden: true} |
||||
}, |
}, |
||||
{ |
{ |
||||
title: t(`${i18nPrefix}.columns.name`, '模板名称'), |
|
||||
dataIndex: 'name', |
|
||||
|
title: t(`${i18nPrefix}.columns.type`, '类型'), |
||||
|
dataIndex: 'type', |
||||
|
render: (_, record) => { |
||||
|
return <div>{record.type}</div> |
||||
|
} |
||||
}, |
}, |
||||
{ |
{ |
||||
title: t(`${i18nPrefix}.columns.title`, '模板标题'), |
|
||||
|
title: t(`${i18nPrefix}.columns.title`, '标题'), |
||||
dataIndex: 'title', |
dataIndex: 'title', |
||||
}, |
}, |
||||
{ |
{ |
||||
title: t(`${i18nPrefix}.columns.content`, '模板内容'), |
|
||||
|
title: t(`${i18nPrefix}.columns.content`, '正文'), |
||||
dataIndex: 'content', |
dataIndex: 'content', |
||||
}, |
}, |
||||
|
{ |
||||
|
title: t(`${i18nPrefix}.columns.dest`, '收件人'), |
||||
|
dataIndex: 'dest', |
||||
|
}, |
||||
|
{ |
||||
|
title: t(`${i18nPrefix}.columns.status`, '状态'), |
||||
|
dataIndex: 'status', |
||||
|
render: (_text, record) => { |
||||
|
return <Badge |
||||
|
status={['default', 'processing', 'success', 'error'][record.status] as any} |
||||
|
text={['未处理', '发送中', '发送成功', '发送失败'][record.status]}/> |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
title: t(`${i18nPrefix}.columns.send_at`, '发送时间'), |
||||
|
dataIndex: 'send_at', |
||||
|
}, |
||||
// {
|
// {
|
||||
// title: t(`${i18nPrefix}.columns.option`, '操作'),
|
// title: t(`${i18nPrefix}.columns.option`, '操作'),
|
||||
// key: 'option',
|
// key: 'option',
|
||||
@ -160,7 +291,7 @@ const MdwMessage = () => { |
|||||
// ]
|
// ]
|
||||
// }
|
// }
|
||||
] as ProColumns[] |
] as ProColumns[] |
||||
}, [search]) |
|
||||
|
}, [search, currentTemplate]) |
||||
|
|
||||
useEffect(() => { |
useEffect(() => { |
||||
|
|
||||
@ -179,7 +310,7 @@ const MdwMessage = () => { |
|||||
<ListPageLayout className={styles.container}> |
<ListPageLayout className={styles.container}> |
||||
<ProTable |
<ProTable |
||||
rowKey="id" |
rowKey="id" |
||||
headerTitle={t(`${i18nPrefix}.title`, '消息模板管理')} |
|
||||
|
headerTitle={t(`${i18nPrefix}.title`, '消息管理')} |
||||
toolbar={{ |
toolbar={{ |
||||
search: { |
search: { |
||||
loading: isFetching && !!search?.title, |
loading: isFetching && !!search?.title, |
||||
@ -215,7 +346,7 @@ const MdwMessage = () => { |
|||||
}) |
}) |
||||
setOpen(true) |
setOpen(true) |
||||
}} |
}} |
||||
type={'primary'}>{t(`${i18nPrefix}.add`, '添加模板')}</Button> |
|
||||
|
type={'primary'}>{t(`${i18nPrefix}.add`, '发送消息')}</Button> |
||||
] |
] |
||||
}} |
}} |
||||
scroll={{ |
scroll={{ |
||||
@ -261,7 +392,7 @@ const MdwMessage = () => { |
|||||
form={form} |
form={form} |
||||
layout={'vertical'} |
layout={'vertical'} |
||||
scrollToFirstError={true} |
scrollToFirstError={true} |
||||
title={t(`${i18nPrefix}.title_${form.getFieldValue('id') !== 0 ? 'edit' : 'add'}`, form.getFieldValue('id') !== 0 ? '模板编辑' : '模板添加')} |
|
||||
|
title={t(`${i18nPrefix}.title_add}`, '发送消息')} |
||||
layoutType={'DrawerForm'} |
layoutType={'DrawerForm'} |
||||
open={open} |
open={open} |
||||
drawerProps={{ |
drawerProps={{ |
||||
@ -275,7 +406,7 @@ const MdwMessage = () => { |
|||||
|
|
||||
}} |
}} |
||||
onFinish={async (values) => { |
onFinish={async (values) => { |
||||
saveOrUpdate(values) |
|
||||
|
saveOrUpdate({...values, "template_id": currentTemplate?.id}) |
||||
}} |
}} |
||||
columns={drawerColumns as ProFormColumnsType[]}/> |
columns={drawerColumns as ProFormColumnsType[]}/> |
||||
<BetaSchemaForm |
<BetaSchemaForm |
||||
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue