|
|
import {useTranslation} from '@/i18n.ts' import {Badge, Button, Divider, Form, Popconfirm, Space, Tag, Tooltip} from 'antd' import {useAtom, useAtomValue} from 'jotai' import React, {useEffect, useMemo, useState} from 'react' import Action from '@/components/action/Action.tsx' import {BetaSchemaForm, ProColumns, ProFormColumnsType,} from '@ant-design/pro-components' import ListPageLayout from '@/layout/ListPageLayout.tsx' import {useStyle} from './style.ts' import {FilterOutlined} from '@ant-design/icons' import {getValueCount, unSetColumnRules} from '@/utils' import {Table as ProTable} from '@/components/table' import { deleteTemplateAtom, saveOrUpdateTemplateAtom, templateAtom, templateListAtom, templateSearchAtom } from "@/store/message/template.ts"; import {coverType} from "@/types/message/template.ts";
const i18nPrefix = 'mdwMessage.list'
const MdwMessage = () => {
const {styles, cx} = useStyle() const {t} = useTranslation() const [form] = Form.useForm() const [filterForm] = Form.useForm() const {mutate: saveOrUpdate, isPending: isSubmitting, isSuccess} = useAtomValue(saveOrUpdateTemplateAtom) const [search, setSearch] = useAtom(templateSearchAtom) const [currentTemplate, setAppPackage] = useAtom(templateAtom) const {data, isFetching, isLoading, refetch} = useAtomValue(templateListAtom) const {mutate: deleteAppPackage, isPending: isDeleting} = useAtomValue(deleteTemplateAtom)
const [open, setOpen] = useState(false) const [openFilter, setFilterOpen] = useState(false) const [searchKey, setSearchKey] = useState(search?.title)
const [templateField, setTemplateField] = useState<string[]>([]);
const [templateTitle, setTemplateTitle] = useState(''); const [templateContent, setTemplateContent] = useState('');
const [templateType, setTemplateType] = useState('') useEffect(() => { setTemplateType(currentTemplate?.type)
if (form.getFieldValue('id') === 0) { setTemplateField(['name']); } else { setTemplateField(currentTemplate?.fields.split(",")); } }, [open]);
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]))); setTemplateField(variables); };
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 typeHandlerChange = (value) => { if (value !== 'EMAIL') { setTemplateTitle('') form.setFieldsValue({'title': undefined}) } setTemplateType(value) }
const drawerColumns = useMemo(() => { return [ { title: 'ID', dataIndex: 'id', hideInTable: true, hideInSearch: true, formItemProps: {hidden: true} }, { title: t(`${i18nPrefix}.columns.name`, '模板名称'), dataIndex: 'name', valueType: 'text', fieldProps: { maxLength: 50, showCount: true, }, formItemProps: { rules: [ { required: true, message: t('message.required', '模板名称必填') } ] } }, { title: t(`${i18nPrefix}.columns.type`, '模板类型'), dataIndex: 'type', valueType: 'select', fieldProps: { options: [ {label: '短信', value: 'SMS'}, {label: '邮件', value: 'EMAIL'}, {label: 'Telegram', value: 'TG'} ], allowClear: false, onChange: typeHandlerChange }, formItemProps: { rules: [ { required: true, } ] } }, { title: t(`${i18nPrefix}.columns.title`, '模板标题'), dataIndex: 'title', valueType: 'text', fieldProps: { maxLength: 100, showCount: true, onChange: titheHandleContentChange, // 监听输入事件
}, formItemProps: { tooltip: '支持邮件类型', hidden: templateType != 'EMAIL', rules: [ { required: templateType == 'EMAIL', message: t('message.required', '模板内容必填') } ] }, }, { title: t(`${i18nPrefix}.columns.content`, '模板内容'), dataIndex: 'content', valueType: 'textarea', fieldProps: { defaultValue: "你好,我叫${.name}", maxLength: 1000, showCount: true, rows: 15, onChange: handleContentChange, // 监听输入事件
}, formItemProps: { rules: [ { required: true, message: t('message.required', '模板内容必填') } ] } }, { title: t(`${i18nPrefix}.columns.fields`, '识别到的变量'), dataIndex: 'fields', renderFormItem: () => { return ( <> { templateField.map((variable, index) => ( <Tag key={index} color="blue" style={{marginRight: 8}}> {variable} </Tag> )) } </> ); } }, ] as ProColumns[] }, [isDeleting, currentTemplate, search, templateField, templateType])
const columns = useMemo(() => { return [ { title: 'ID', dataIndex: 'id', hideInTable: true, hideInSearch: true, formItemProps: {hidden: true} }, { title: t(`${i18nPrefix}.columns.name`, '模板名称'), dataIndex: 'name', }, { title: t(`${i18nPrefix}.columns.type`, '模板类型'), dataIndex: 'type', render: (_, record) => { return <div>{coverType(record.type)}</div> } }, { title: t(`${i18nPrefix}.columns.title`, '模板标题'), dataIndex: 'title', }, { title: t(`${i18nPrefix}.columns.content`, '模板内容'), dataIndex: 'content', }, { title: t(`${i18nPrefix}.columns.option`, '操作'), key: 'option', valueType: 'option', fixed: 'right', render: (_, record) => [ <Action key="edit" as={'a'} onClick={() => { form.setFieldsValue(record) setOpen(true) }}>{t('actions.edit')}</Action>, <Divider type={'vertical'}/>, <Popconfirm key={'del_confirm'} disabled={isDeleting} onConfirm={() => { deleteAppPackage(record.id) }} title={t('message.deleteConfirm')}> <a key="del"> {t('actions.delete', '删除')} </a> </Popconfirm>, ] } ] as ProColumns[] }, [isDeleting, currentTemplate, search])
useEffect(() => {
setSearchKey(search?.title) filterForm.setFieldsValue(search)
}, [search])
useEffect(() => { if (isSuccess) { setOpen(false) } }, [isSuccess])
return ( <ListPageLayout className={styles.container}> <ProTable rowKey="id" headerTitle={t(`${i18nPrefix}.title`, '消息模板管理')} toolbar={{ search: { loading: isFetching && !!search?.title, onSearch: (value: string) => { setSearch(prev => ({ ...prev, title: value })) }, allowClear: true, onChange: (e) => { setSearchKey(e.target?.value) }, value: searchKey, placeholder: t(`${i18nPrefix}.placeholder`, '输入模板名称') }, actions: [ <Tooltip key={'filter'} title={t(`${i18nPrefix}.filter.tooltip`, '高级查询')}> <Badge count={getValueCount(search)}> <Button onClick={() => { setFilterOpen(true) }} icon={<FilterOutlined/>} shape={'circle'} size={'small'}/> </Badge> </Tooltip>, <Divider type={'vertical'} key={'divider'}/>, <Button key={'add'} onClick={() => { form.resetFields() form.setFieldsValue({ id: 0, }) setOpen(true) }} type={'primary'}>{t(`${i18nPrefix}.add`, '添加模板')}</Button> ] }} scroll={{ x: columns.length * 200, y: 'calc(100vh - 290px)' }} search={false} onRow={(record) => { return { className: cx({ // 'ant-table-row-selected': currentAppPackage?.id === record.id
}), onClick: () => { setAppPackage(record) } } }} dateFormatter="string" loading={isLoading || isFetching} dataSource={data?.rows ?? []} columns={columns} options={{ reload: () => { refetch() }, }} pagination={{ total: data?.total, pageSize: search.pageSize, current: search.page, onShowSizeChange: (current: number, size: number) => { setSearch({ ...search, pageSize: size, page: current }) }, onChange: (current, pageSize) => { setSearch(prev => { return { ...prev, page: current, pageSize: pageSize, } }) }, }} /> <BetaSchemaForm grid={true} shouldUpdate={false} width={1000} form={form} layout={'vertical'} scrollToFirstError={true} title={t(`${i18nPrefix}.title_${form.getFieldValue('id') !== 0 ? 'edit' : 'add'}`, form.getFieldValue('id') !== 0 ? '模板编辑' : '模板添加')} layoutType={'DrawerForm'} open={open} drawerProps={{ maskClosable: false, }} onOpenChange={(open) => { setOpen(open) }} loading={isSubmitting} onValuesChange={() => {
}} onFinish={async (values) => { saveOrUpdate({...values, 'fields': templateField.join()}) }} columns={drawerColumns as ProFormColumnsType[]}/> <BetaSchemaForm title={t(`${i18nPrefix}.filter.title`, '模板高级查询')} grid={true} shouldUpdate={false} width={500} form={filterForm} open={openFilter} onOpenChange={open => { setFilterOpen(open) }} layout={'vertical'} scrollToFirstError={true} layoutType={'DrawerForm'} drawerProps={{ maskClosable: false, mask: false, }} submitter={{ searchConfig: { resetText: t(`${i18nPrefix}.filter.reset`, '清空'), submitText: t(`${i18nPrefix}.filter.submit`, '查询'), }, onReset: () => { filterForm.resetFields() }, render: (props,) => { return ( <div style={{textAlign: 'right'}}> <Space> <Button onClick={() => { props.reset()
}}>{props.searchConfig?.resetText}</Button> <Button type="primary" onClick={() => { props.submit() }} >{props.searchConfig?.submitText}</Button> </Space> </div> ) },
}} onValuesChange={() => {
}}
onFinish={async (values) => { //处理,变成数组
Object.keys(values).forEach(key => { if (typeof values[key] === 'string' && values[key].includes(',')) { values[key] = values[key].split(',') } })
setSearch(values)
}} columns={unSetColumnRules(columns.filter(item => !item.hideInSearch)) as ProFormColumnsType[]}/> </ListPageLayout> ) }
export default MdwMessage
|