From 87cc601a2129889be1b386778f6f4ebb5ee9c39d Mon Sep 17 00:00:00 2001 From: cs Date: Tue, 10 Sep 2024 21:53:42 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/global.d.ts | 8 + src/pages/message/my/index.tsx | 345 ++++++++++++++++++++++++++ src/pages/message/my/style.ts | 26 ++ src/pages/message/template/index.tsx | 446 ++++++++++++++++++++++++++++++++++ src/pages/message/template/style.ts | 26 ++ src/pages/system/message/index.tsx | 454 ----------------------------------- src/pages/system/message/style.ts | 26 -- src/service/message/message.ts | 17 -- src/service/message/my.ts | 13 + src/service/message/template.ts | 17 ++ src/store/message/my.ts | 71 ++++++ src/store/message/template.ts | 84 +++++++ src/store/system/message.ts | 85 ------- src/types/message/my.ts | 11 + src/types/message/template.ts | 9 + src/types/system/message.ts | 25 -- 16 files changed, 1056 insertions(+), 607 deletions(-) create mode 100644 src/pages/message/my/index.tsx create mode 100644 src/pages/message/my/style.ts create mode 100644 src/pages/message/template/index.tsx create mode 100644 src/pages/message/template/style.ts delete mode 100644 src/pages/system/message/index.tsx delete mode 100644 src/pages/system/message/style.ts delete mode 100644 src/service/message/message.ts create mode 100644 src/service/message/my.ts create mode 100644 src/service/message/template.ts create mode 100644 src/store/message/my.ts create mode 100644 src/store/message/template.ts delete mode 100644 src/store/system/message.ts create mode 100644 src/types/message/my.ts create mode 100644 src/types/message/template.ts delete mode 100644 src/types/system/message.ts diff --git a/src/global.d.ts b/src/global.d.ts index 44baa73..dedf0fe 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -33,6 +33,14 @@ export type IPageResult = IPage & { total: number } +export type IListAllResult = { + list: T[] +} + +export type IBoolResult = { + success: boolean +} + export type IApiResult = { code: number; data: T; diff --git a/src/pages/message/my/index.tsx b/src/pages/message/my/index.tsx new file mode 100644 index 0000000..503eeeb --- /dev/null +++ b/src/pages/message/my/index.tsx @@ -0,0 +1,345 @@ +import {useTranslation} from '@/i18n.ts' +import {Badge, Button, Divider, Form, Input, Space, Tooltip} from 'antd' +import {useAtom, useAtomValue} from 'jotai' +import React, {useEffect, useMemo, useState} from 'react' +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 {msgListAtom, msgSearchAtom, saveMsgAtom} from "@/store/message/my.ts"; +import {templateAllListAtom} from "@/store/message/template.ts"; + +const i18nPrefix = 'msgMy.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(saveMsgAtom) + const [search, setSearch] = useAtom(msgSearchAtom) + const {data, isFetching, isLoading, refetch} = useAtomValue(msgListAtom) + const {data: templateList} = useAtomValue(templateAllListAtom) + + const [open, setOpen] = useState(false) + const [openFilter, setFilterOpen] = useState(false) + const [searchKey, setSearchKey] = useState(search?.title) + + const drawerColumns = useMemo(() => { + return [ + { + title: 'ID', + dataIndex: 'id', + hideInTable: true, + hideInSearch: true, + formItemProps: {hidden: true} + }, + { + title: t(`${i18nPrefix}.columns.type`, '选择模板'), + dataIndex: 'type', + valueType: 'select', + fieldProps: { + options: [ + {label: '短信', value: 'SMS'}, + {label: '邮件', value: 'EMAIL'}, + {label: 'Telegram', value: 'TG'} + ], + allowClear: false, + }, + formItemProps: { + rules: [ + { + required: true, + } + ] + } + }, + { + title: t(`${i18nPrefix}.columns.title`, '标题'), + dataIndex: 'title', + valueType: 'text', + fieldProps: { + maxLength: 100, + showCount: true, + }, + }, + { + title: t(`${i18nPrefix}.columns.content`, '模板内容'), + dataIndex: 'content', + valueType: 'textarea', + fieldProps: { + defaultValue: "你好,我叫${.name}", + maxLength: 1000, + showCount: true, + rows: 15, + }, + formItemProps: { + rules: [ + { + required: true, + message: t('message.required', '模板内容必填') + } + ] + } + }, + { + title: t(`${i18nPrefix}.columns.field`, '识别到的变量'), + dataIndex: 'field', + renderFormItem: () => { + return ( + <> + { + templateList?.map((variable, index) => ( +
+ +
+ ))} + + ); + } + }, + { + title: t(`${i18nPrefix}.columns.dest`, '收件人(多个收件人用英文逗号隔开,如果类型是TG,则填token)'), + dataIndex: 'dest', + valueType: 'textarea', + fieldProps: { + maxLength: 1000, + showCount: true, + rows: 15, + placeholder: 'aaa@qq.com,bbb@gmail.com', + }, + }, + ] as ProColumns[] + }, [search]) + + 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.title`, '模板标题'), + dataIndex: 'title', + }, + { + title: t(`${i18nPrefix}.columns.content`, '模板内容'), + dataIndex: 'content', + }, + // { + // title: t(`${i18nPrefix}.columns.option`, '操作'), + // key: 'option', + // valueType: 'option', + // fixed: 'right', + // render: (_, record) => [ + // { + // deleteAppPackage(record.id) + // }} + // title={t('message.deleteConfirm')}> + // + // {t('actions.delete', '删除')} + // + // , + // ] + // } + ] as ProColumns[] + }, [search]) + + useEffect(() => { + + setSearchKey(search?.title) + filterForm.setFieldsValue(search) + + }, [search]) + + useEffect(() => { + if (isSuccess) { + setOpen(false) + } + }, [isSuccess]) + + return ( + + { + setSearch(prev => ({ + ...prev, + title: value + })) + }, + allowClear: true, + onChange: (e) => { + setSearchKey(e.target?.value) + }, + value: searchKey, + placeholder: t(`${i18nPrefix}.placeholder`, '输入模板名称') + }, + actions: [ + + + + ] + }} + scroll={{ + x: columns.length * 200, + y: 'calc(100vh - 290px)' + }} + search={false} + 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, + } + }) + }, + }} + /> + { + setOpen(open) + }} + loading={isSubmitting} + onValuesChange={() => { + + }} + onFinish={async (values) => { + saveOrUpdate(values) + }} + columns={drawerColumns as ProFormColumnsType[]}/> + { + 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 ( +
+ + + + +
+ ) + }, + + }} + 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[]}/> +
+ ) +} + +export default MdwMessage \ No newline at end of file diff --git a/src/pages/message/my/style.ts b/src/pages/message/my/style.ts new file mode 100644 index 0000000..8774450 --- /dev/null +++ b/src/pages/message/my/style.ts @@ -0,0 +1,26 @@ +import { createStyles } from '@/theme' + +export const useStyle = createStyles(({ token, css, cx, prefixCls }, props: any) => { + const prefix = `${prefixCls}-${token?.proPrefix}-appPackage-list-page` + + const container = css` + .ant-table-cell{ + .ant-tag{ + padding-inline: 3px; + margin-inline-end: 3px; + } + } + .ant-table-empty { + .ant-table-body{ + height: calc(100vh - 350px) + } + } + .ant-pro-table-highlight{ + + } + ` + + return { + container: cx(prefix, props?.className, container), + } +}) \ No newline at end of file diff --git a/src/pages/message/template/index.tsx b/src/pages/message/template/index.tsx new file mode 100644 index 0000000..8a8077c --- /dev/null +++ b/src/pages/message/template/index.tsx @@ -0,0 +1,446 @@ +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"; + +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([]); + + 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 = (title: string, content: string) => { + // 使用正则表达式匹配 ${var} 格式的变量 + const regex = /\${\.([a-zA-Z0-9_]+)}/g; + const matches = [...(title + content).matchAll(regex)]; + + // 提取变量名 + const variables = Array.from(new Set(matches.map(match => match[1]))); + setTemplateField(variables); + }; + + const handleContentChange = (e) => { + const value = e.target.value; + setTemplateContent(value) + handleChange(templateTitle, value) + }; + + const titheHandleContentChange = (e) => { + const value = e.target.value; + setTemplateTitle(value) + handleChange(value, templateContent) + }; + + const typeHandlerChange = (value) => { + console.log(value) + 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) => ( + + {variable} + + )) + } + + ); + } + }, + { + title: t(`${i18nPrefix}.columns.dest`, '收件人(多个收件人用英文逗号隔开,如果类型是TG,则填token)'), + dataIndex: 'dest', + valueType: 'textarea', + fieldProps: { + maxLength: 1000, + showCount: true, + rows: 15, + placeholder: 'aaa@qq.com,bbb@gmail.com', + }, + }, + ] 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
{record.type}
+ } + }, + { + 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) => [ + { + form.setFieldsValue(record) + setOpen(true) + }}>{t('actions.edit')}, + , + { + deleteAppPackage(record.id) + }} + title={t('message.deleteConfirm')}> + + {t('actions.delete', '删除')} + + , + ] + } + ] as ProColumns[] + }, [isDeleting, currentTemplate, search]) + + useEffect(() => { + + setSearchKey(search?.title) + filterForm.setFieldsValue(search) + + }, [search]) + + useEffect(() => { + if (isSuccess) { + setOpen(false) + } + }, [isSuccess]) + + return ( + + { + setSearch(prev => ({ + ...prev, + title: value + })) + }, + allowClear: true, + onChange: (e) => { + setSearchKey(e.target?.value) + }, + value: searchKey, + placeholder: t(`${i18nPrefix}.placeholder`, '输入模板名称') + }, + actions: [ + + + + ] + }} + 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, + } + }) + }, + }} + /> + { + setOpen(open) + }} + loading={isSubmitting} + onValuesChange={() => { + + }} + onFinish={async (values) => { + saveOrUpdate({...values, 'fields': templateField.join()}) + }} + columns={drawerColumns as ProFormColumnsType[]}/> + { + 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 ( +
+ + + + +
+ ) + }, + + }} + 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[]}/> +
+ ) +} + +export default MdwMessage \ No newline at end of file diff --git a/src/pages/message/template/style.ts b/src/pages/message/template/style.ts new file mode 100644 index 0000000..8774450 --- /dev/null +++ b/src/pages/message/template/style.ts @@ -0,0 +1,26 @@ +import { createStyles } from '@/theme' + +export const useStyle = createStyles(({ token, css, cx, prefixCls }, props: any) => { + const prefix = `${prefixCls}-${token?.proPrefix}-appPackage-list-page` + + const container = css` + .ant-table-cell{ + .ant-tag{ + padding-inline: 3px; + margin-inline-end: 3px; + } + } + .ant-table-empty { + .ant-table-body{ + height: calc(100vh - 350px) + } + } + .ant-pro-table-highlight{ + + } + ` + + return { + container: cx(prefix, props?.className, container), + } +}) \ No newline at end of file diff --git a/src/pages/system/message/index.tsx b/src/pages/system/message/index.tsx deleted file mode 100644 index 327c0e2..0000000 --- a/src/pages/system/message/index.tsx +++ /dev/null @@ -1,454 +0,0 @@ -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' -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/system/message.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(['name']); - const [titleTemplateField, setTitleTemplateField] = useState([]); - - const [allTemplateField, setAllTemplateField] = useState([]); - - useEffect(() => { - const combinedFields = [...templateField, ...titleTemplateField]; - const uniqueFields = Array.from(new Set(combinedFields)); - setAllTemplateField(uniqueFields); - }, [templateField, titleTemplateField]); - - const [templateType, setTemplateType] = useState('') - useEffect(() => { - setTemplateType(currentTemplate?.type) - }, [open]); - - const handleContentChange = (e) => { - const value = e.target.value; - - // 使用正则表达式匹配 ${var} 格式的变量 - const regex = /\${\.([a-zA-Z0-9_]+)}/g; - const matches = [...value.matchAll(regex)]; - - // 提取变量名 - const variables = Array.from(new Set(matches.map(match => match[1]))); - - // 更新变量状态 - setTemplateField(variables); - }; - - const titheHandleContentChange = (e) => { - const value = e.target.value; - - // 使用正则表达式匹配 ${var} 格式的变量 - const regex = /\${\.([a-zA-Z0-9_]+)}/g; - const matches = [...value.matchAll(regex)]; - - // 提取变量名 - const variables = Array.from(new Set(matches.map(match => match[1]))); - - // 更新变量状态 - setTitleTemplateField(variables); - - }; - - const typeHandlerChange = (value) => { - console.log(value) - 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.field`, '识别到的变量'), - dataIndex: 'field', - renderFormItem: () => { - return ( - <> - { - allTemplateField.map((variable, index) => ( - - {variable} - - )) - } - - ); - } - }, - { - title: t(`${i18nPrefix}.columns.dest`, '收件人(多个收件人用英文逗号隔开,如果类型是TG,则填token)'), - dataIndex: 'dest', - valueType: 'textarea', - fieldProps: { - maxLength: 1000, - showCount: true, - rows: 15, - placeholder: 'aaa@qq.com,bbb@gmail.com', - }, - }, - ] as ProColumns[] - }, [isDeleting, currentTemplate, search, allTemplateField, 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.title`, '模板标题'), - dataIndex: 'title', - }, - { - title: t(`${i18nPrefix}.columns.content`, '模板内容'), - dataIndex: 'content', - }, - { - title: t(`${i18nPrefix}.columns.option`, '操作'), - key: 'option', - valueType: 'option', - fixed: 'right', - render: (_, record) => [ - { - form.setFieldsValue(record) - setOpen(true) - }}>{t('actions.edit')}, - , - { - deleteAppPackage(record.id) - }} - title={t('message.deleteConfirm')}> - - {t('actions.delete', '删除')} - - , - , - { - form.setFieldsValue(record) - setOpen(true) - }}>{t('actions.sendMsg', '发送消息')}, - ] - } - ] as ProColumns[] - }, [isDeleting, currentTemplate, search]) - - useEffect(() => { - - setSearchKey(search?.title) - filterForm.setFieldsValue(search) - - }, [search]) - - useEffect(() => { - if (isSuccess) { - setOpen(false) - } - }, [isSuccess]) - - return ( - - { - setSearch(prev => ({ - ...prev, - title: value - })) - }, - allowClear: true, - onChange: (e) => { - setSearchKey(e.target?.value) - }, - value: searchKey, - placeholder: t(`${i18nPrefix}.placeholder`, '输入模板名称') - }, - actions: [ - - - - ] - }} - 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, - } - }) - }, - }} - /> - { - setOpen(open) - }} - loading={isSubmitting} - onValuesChange={() => { - - }} - onFinish={async (values) => { - saveOrUpdate({...values, 'fields': allTemplateField}) - }} - columns={drawerColumns as ProFormColumnsType[]}/> - { - 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 ( -
- - - - -
- ) - }, - - }} - 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[]}/> -
- ) -} - -export default MdwMessage \ No newline at end of file diff --git a/src/pages/system/message/style.ts b/src/pages/system/message/style.ts deleted file mode 100644 index 8774450..0000000 --- a/src/pages/system/message/style.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { createStyles } from '@/theme' - -export const useStyle = createStyles(({ token, css, cx, prefixCls }, props: any) => { - const prefix = `${prefixCls}-${token?.proPrefix}-appPackage-list-page` - - const container = css` - .ant-table-cell{ - .ant-tag{ - padding-inline: 3px; - margin-inline-end: 3px; - } - } - .ant-table-empty { - .ant-table-body{ - height: calc(100vh - 350px) - } - } - .ant-pro-table-highlight{ - - } - ` - - return { - container: cx(prefix, props?.className, container), - } -}) \ No newline at end of file diff --git a/src/service/message/message.ts b/src/service/message/message.ts deleted file mode 100644 index 0e9a05c..0000000 --- a/src/service/message/message.ts +++ /dev/null @@ -1,17 +0,0 @@ -import request from '@/request.ts' -import { IApiResult, IPageResult } from '@/global' -import { IMsgFieldRes, IMsgTemplate } from '@/types/system/message.ts' -import { createCURD } from '@/service/base.ts' - -const mdwMessage = { - ...createCURD('/mdw-msg/template'), - list: async (params: any) => { - return await request.get>(`mdw-msg/template/list`, { ...params }) - }, - - fieldList: async (params: any) => { - return await request.get>(`mdw-msg/template/fieldList`, { ...params }) - }, -} - -export default mdwMessage \ No newline at end of file diff --git a/src/service/message/my.ts b/src/service/message/my.ts new file mode 100644 index 0000000..70962bf --- /dev/null +++ b/src/service/message/my.ts @@ -0,0 +1,13 @@ +import request from '@/request.ts' +import { IPageResult } from '@/global' +import { createCURD } from '@/service/base.ts' +import { IMsgMy } from '@/types/message/my.ts' + +const messageMy = { + ...createCURD('/mdw-msg/msg'), + list: async (params: any) => { + return await request.get>(`mdw-msg/msg/list`, { ...params }) + }, +} + +export default messageMy \ No newline at end of file diff --git a/src/service/message/template.ts b/src/service/message/template.ts new file mode 100644 index 0000000..3c5132b --- /dev/null +++ b/src/service/message/template.ts @@ -0,0 +1,17 @@ +import request from '@/request.ts' +import { IListAllResult, IPageResult } from '@/global' +import { IMsgTemplate } from '@/types/message/template.ts' +import { createCURD } from '@/service/base.ts' + +const messageTemplate = { + ...createCURD('/mdw-msg/template'), + list: async (params: any) => { + return await request.get>(`mdw-msg/template/list`, { ...params }) + }, + + listAll: async () => { + return await request.get>(`mdw-msg/template/listAll`) + }, +} + +export default messageTemplate \ No newline at end of file diff --git a/src/store/message/my.ts b/src/store/message/my.ts new file mode 100644 index 0000000..80e6073 --- /dev/null +++ b/src/store/message/my.ts @@ -0,0 +1,71 @@ +import { atom } from 'jotai/index' +import { IApiResult, IPage } from '@/global' +import { atomWithMutation, atomWithQuery, queryClientAtom } from 'jotai-tanstack-query' +import messageTemplate from '@/service/message/template.ts' +import { message } from 'antd' +import { t } from 'i18next' +import { IMsgMy } from '@/types/message/my.ts' + +type SearchParams = IPage & { + key?: string + + [key: string]: any +} + +export const msgIdsAtom = atom(0) + +export const msgSearchAtom = atom({ + key: '', + pageSize: 10, + page: 1, +} as SearchParams) + +export const msgPageAtom = atom({ + pageSize: 10, + page: 1, +}) + +export const msgListAtom = atomWithQuery((get) => { + return { + queryKey: [ 'msgList', get(msgSearchAtom) ], + queryFn: async ({ queryKey: [ , params ] }) => { + const list = await messageTemplate.list(params as SearchParams) + return list.data + } + } +}) + +export const deleteMsgAtom = atomWithMutation((get) => { + return { + mutationKey: [ 'deleteMsg' ], + mutationFn: async (ids: number) => { + return await messageTemplate.delete(ids ?? get(msgIdsAtom) as number) + }, + onSuccess: (res) => { + message.success('message.deleteSuccess') + //更新列表 + get(queryClientAtom).invalidateQueries({ queryKey: [ 'templateList', get(msgSearchAtom) ] }) + return res + } + } +}) + +export const saveMsgAtom = atomWithMutation((get) => { + + return { + mutationKey: [ 'saveMsg' ], + mutationFn: async (data) => { + if (data.id === 0) { + return await messageTemplate.add(data) + } + return await messageTemplate.update(data) + }, + onSuccess: (res) => { + message.success(t('message.saveSuccess', '保存成功')) + + get(queryClientAtom).invalidateQueries({ queryKey: [ 'templateList', get(msgSearchAtom) ] }) + + return res + } + } +}) diff --git a/src/store/message/template.ts b/src/store/message/template.ts new file mode 100644 index 0000000..043b122 --- /dev/null +++ b/src/store/message/template.ts @@ -0,0 +1,84 @@ +import { atom } from 'jotai/index' +import { IApiResult, IPage } from '@/global' +import { atomWithMutation, atomWithQuery, queryClientAtom } from 'jotai-tanstack-query' +import { IMsgTemplate } from '@/types/message/template.ts' +import messageTemplate from '@/service/message/template.ts' +import { message } from 'antd' +import { t } from 'i18next' + +type SearchParams = IPage & { + key?: string + + [key: string]: any +} + +export const templateIdsAtom = atom(0) + +export const templateAtom = atom(undefined as unknown as IMsgTemplate) + +export const templateSearchAtom = atom({ + key: '', + pageSize: 10, + page: 1, +} as SearchParams) + +export const templatePageAtom = atom({ + pageSize: 10, + page: 1, +}) + +export const templateListAtom = atomWithQuery((get) => { + return { + queryKey: [ 'templateList', get(templateSearchAtom) ], + queryFn: async ({ queryKey: [ , params ] }) => { + const list = await messageTemplate.list(params as SearchParams) + return list.data + } + } +}) + +export const templateAllListAtom = atomWithQuery(() => { + return { + queryKey: [ 'templateAllList'], + queryFn: async ({ queryKey: [ , ] }) => { + const list = await messageTemplate.listAll() + return list.data.list + } + } +}) + +export const deleteTemplateAtom = atomWithMutation((get) => { + return { + mutationKey: [ 'deleteTemplate' ], + mutationFn: async (ids: number) => { + return await messageTemplate.delete(ids ?? get(templateIdsAtom) as number) + }, + onSuccess: (res) => { + message.success('message.deleteSuccess') + //更新列表 + get(queryClientAtom).invalidateQueries({ queryKey: [ 'templateList', get(templateSearchAtom) ] }) + return res + } + } +}) + +export const saveOrUpdateTemplateAtom = atomWithMutation((get) => { + + return { + mutationKey: [ 'updateTemplate' ], + mutationFn: async (data) => { + if (data.id === 0) { + return await messageTemplate.add(data) + } + return await messageTemplate.update(data) + }, + onSuccess: (res) => { + const isAdd = !!res.data?.id + message.success(t(isAdd ? 'message.saveSuccess' : 'message.editSuccess', '保存成功')) + + get(queryClientAtom).invalidateQueries({ queryKey: [ 'templateList', get(templateSearchAtom) ] }) + + return res + } + } +}) diff --git a/src/store/system/message.ts b/src/store/system/message.ts deleted file mode 100644 index 7d95344..0000000 --- a/src/store/system/message.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { atom } from 'jotai/index' -import { IApiResult, IPage } from '@/global' -import { atomWithMutation, atomWithQuery, queryClientAtom } from 'jotai-tanstack-query' -import { IMsgTemplate } from '@/types/system/message.ts' -import mdwMessage from '@/service/message/message.ts' -import { message } from 'antd' -import { t } from 'i18next' - -type SearchParams = IPage & { - key?: string - - [key: string]: any -} - -export const templateAIdsAtom = atom(0) - -export const templateAtom = atom(undefined as unknown as IMsgTemplate) - -export const templateSearchAtom = atom({ - key: '', - pageSize: 10, - page: 1, -} as SearchParams) - -export const templatePageAtom = atom({ - pageSize: 10, - page: 1, -}) - -export const templateListAtom = atomWithQuery((get) => { - return { - queryKey: [ 'templateList', get(templateSearchAtom) ], - queryFn: async ({ queryKey: [ , params ] }) => { - const list = await mdwMessage.list(params as SearchParams) - return list.data - } - } -}) - -export const templateFieldAtom = atomWithQuery(() => { - return { - queryKey: [ 'templateField' ], - queryFn: async ({ queryKey: [ , params ] }) => { - const list = await mdwMessage.fieldList(params) - return list.data - } - } -}) - -export const deleteTemplateAtom = atomWithMutation((get) => { - return { - mutationKey: [ 'deleteTemplate' ], - mutationFn: async (ids: number) => { - return await mdwMessage.delete(ids ?? get(templateAIdsAtom) as number) - }, - onSuccess: (res) => { - message.success('message.deleteSuccess') - //更新列表 - get(queryClientAtom).invalidateQueries({ queryKey: [ 'templateList', get(templateSearchAtom) ] }) - return res - } - } -}) - -export const saveOrUpdateTemplateAtom = atomWithMutation((get) => { - - return { - mutationKey: [ 'updateTemplate' ], - mutationFn: async (data) => { - //data.status = data.status ? '1' : '0' - if (data.id === 0) { - return await mdwMessage.add(data) - } - return await mdwMessage.update(data) - }, - onSuccess: (res) => { - const isAdd = !!res.data?.id - message.success(t(isAdd ? 'message.saveSuccess' : 'message.editSuccess', '保存成功')) - - get(queryClientAtom).invalidateQueries({ queryKey: [ 'templateList', get(templateSearchAtom) ] }) - - return res - } - } -}) diff --git a/src/types/message/my.ts b/src/types/message/my.ts new file mode 100644 index 0000000..7e4c193 --- /dev/null +++ b/src/types/message/my.ts @@ -0,0 +1,11 @@ +export interface IMsgMy { + id: number + template_id: number + title: string + send_content: string + dest: string + type: string + status: number + error_message: string + send_at: number +} \ No newline at end of file diff --git a/src/types/message/template.ts b/src/types/message/template.ts new file mode 100644 index 0000000..25cf08c --- /dev/null +++ b/src/types/message/template.ts @@ -0,0 +1,9 @@ +export interface IMsgTemplate { + id: number + name: string + content: string + title: string + dest: string + type: string + fields: string +} diff --git a/src/types/system/message.ts b/src/types/system/message.ts deleted file mode 100644 index a94ac4f..0000000 --- a/src/types/system/message.ts +++ /dev/null @@ -1,25 +0,0 @@ -export interface IMsgTemplate { - id: number - name: string - content: string - title: string - dest: string - type: string -} - -export interface IMsgFieldRes { - list: IMsgField[] -} - - -export interface IMsgField { - template_id: string - field_key: string - field_value: string -} - -export interface IMdwMsgReq { - id: string - name: string - content: string -} From 7d8c5e6e146589062dbbea997c85af75c8cdc828 Mon Sep 17 00:00:00 2001 From: cs Date: Tue, 10 Sep 2024 21:57:35 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=A8=A1=E6=9D=BFbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/message/template/index.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/message/template/index.tsx b/src/pages/message/template/index.tsx index 8a8077c..5b7c214 100644 --- a/src/pages/message/template/index.tsx +++ b/src/pages/message/template/index.tsx @@ -47,7 +47,7 @@ const MdwMessage = () => { if (form.getFieldValue('id') === 0) { setTemplateField(['name']); } else { - setTemplateField(currentTemplate.fields.split(",")); + setTemplateField(currentTemplate?.fields.split(",")); } }, [open]); @@ -74,7 +74,6 @@ const MdwMessage = () => { }; const typeHandlerChange = (value) => { - console.log(value) setTemplateType(value) } From 4dafc2062c1c81b8e3ea5fb43826936179efcde5 Mon Sep 17 00:00:00 2001 From: cs Date: Wed, 11 Sep 2024 01:07:43 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E6=88=91=E7=9A=84=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/message/my/index.tsx | 181 ++++++++++++++++++++++++++++++----- src/pages/message/template/index.tsx | 10 +- src/store/message/my.ts | 15 ++- 3 files changed, 168 insertions(+), 38 deletions(-) diff --git a/src/pages/message/my/index.tsx b/src/pages/message/my/index.tsx index 503eeeb..63971f4 100644 --- a/src/pages/message/my/index.tsx +++ b/src/pages/message/my/index.tsx @@ -1,5 +1,5 @@ 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 React, {useEffect, useMemo, useState} from 'react' 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 {msgListAtom, msgSearchAtom, saveMsgAtom} from "@/store/message/my.ts"; import {templateAllListAtom} from "@/store/message/template.ts"; +import {IMsgTemplate} from "@/types/message/template.ts"; const i18nPrefix = 'msgMy.list' @@ -26,8 +27,77 @@ const MdwMessage = () => { const [open, setOpen] = useState(false) const [openFilter, setFilterOpen] = useState(false) + const [currentTemplate, setCurrentTemplate] = useState() 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(() => { return [ { @@ -38,7 +108,25 @@ const MdwMessage = () => { formItemProps: {hidden: true} }, { - title: t(`${i18nPrefix}.columns.type`, '选择模板'), + title: t(`${i18nPrefix}.columns.template`, '选择模板'), + valueType: 'select', + fieldProps: { + allowClear: true, + }, + renderFormItem: () => { + return + } + }, + { + title: t(`${i18nPrefix}.columns.type`, '消息类型'), dataIndex: 'type', valueType: 'select', fieldProps: { @@ -48,6 +136,7 @@ const MdwMessage = () => { {label: 'Telegram', value: 'TG'} ], allowClear: false, + onChange: typeHandlerChange }, formItemProps: { rules: [ @@ -64,46 +153,60 @@ const MdwMessage = () => { 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`, '模板内容'), + 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', '模板内容必填') + 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 ( <> { - templateList?.map((variable, index) => ( + config.value?.map((variable, index) => (
handleInputChange(index, e)} />
- ))} + )) + } ); - } + }, }, { title: t(`${i18nPrefix}.columns.dest`, '收件人(多个收件人用英文逗号隔开,如果类型是TG,则填token)'), @@ -112,12 +215,20 @@ const MdwMessage = () => { fieldProps: { maxLength: 1000, showCount: true, - rows: 15, + rows: 5, placeholder: 'aaa@qq.com,bbb@gmail.com', }, + formItemProps: { + rules: [ + { + required: true, + message: t('message.required', '内容必填') + } + ] + } }, ] as ProColumns[] - }, [search]) + }, [search, templateType, templateList]) const columns = useMemo(() => { return [ @@ -129,17 +240,37 @@ const MdwMessage = () => { formItemProps: {hidden: true} }, { - title: t(`${i18nPrefix}.columns.name`, '模板名称'), - dataIndex: 'name', + title: t(`${i18nPrefix}.columns.type`, '类型'), + dataIndex: 'type', + render: (_, record) => { + return
{record.type}
+ } }, { - title: t(`${i18nPrefix}.columns.title`, '模板标题'), + title: t(`${i18nPrefix}.columns.title`, '标题'), dataIndex: 'title', }, { - title: t(`${i18nPrefix}.columns.content`, '模板内容'), + title: t(`${i18nPrefix}.columns.content`, '正文'), dataIndex: 'content', }, + { + title: t(`${i18nPrefix}.columns.dest`, '收件人'), + dataIndex: 'dest', + }, + { + title: t(`${i18nPrefix}.columns.status`, '状态'), + dataIndex: 'status', + render: (_text, record) => { + return + } + }, + { + title: t(`${i18nPrefix}.columns.send_at`, '发送时间'), + dataIndex: 'send_at', + }, // { // title: t(`${i18nPrefix}.columns.option`, '操作'), // key: 'option', @@ -160,7 +291,7 @@ const MdwMessage = () => { // ] // } ] as ProColumns[] - }, [search]) + }, [search, currentTemplate]) useEffect(() => { @@ -179,7 +310,7 @@ const MdwMessage = () => { { }) setOpen(true) }} - type={'primary'}>{t(`${i18nPrefix}.add`, '添加模板')} + type={'primary'}>{t(`${i18nPrefix}.add`, '发送消息')} ] }} scroll={{ @@ -261,7 +392,7 @@ const MdwMessage = () => { form={form} layout={'vertical'} scrollToFirstError={true} - title={t(`${i18nPrefix}.title_${form.getFieldValue('id') !== 0 ? 'edit' : 'add'}`, form.getFieldValue('id') !== 0 ? '模板编辑' : '模板添加')} + title={t(`${i18nPrefix}.title_add}`, '发送消息')} layoutType={'DrawerForm'} open={open} drawerProps={{ @@ -275,7 +406,7 @@ const MdwMessage = () => { }} onFinish={async (values) => { - saveOrUpdate(values) + saveOrUpdate({...values, "template_id": currentTemplate?.id}) }} columns={drawerColumns as ProFormColumnsType[]}/> { } }, [open]); - const handleChange = (title: string, content: string) => { + const handleChange = () => { // 使用正则表达式匹配 ${var} 格式的变量 const regex = /\${\.([a-zA-Z0-9_]+)}/g; - const matches = [...(title + content).matchAll(regex)]; + 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) - handleChange(templateTitle, value) }; const titheHandleContentChange = (e) => { const value = e.target.value; setTemplateTitle(value) - handleChange(value, templateContent) }; const typeHandlerChange = (value) => { diff --git a/src/store/message/my.ts b/src/store/message/my.ts index 80e6073..4a62ded 100644 --- a/src/store/message/my.ts +++ b/src/store/message/my.ts @@ -1,10 +1,10 @@ import { atom } from 'jotai/index' import { IApiResult, IPage } from '@/global' import { atomWithMutation, atomWithQuery, queryClientAtom } from 'jotai-tanstack-query' -import messageTemplate from '@/service/message/template.ts' import { message } from 'antd' import { t } from 'i18next' import { IMsgMy } from '@/types/message/my.ts' +import messageMy from '@/service/message/my.ts' type SearchParams = IPage & { key?: string @@ -29,7 +29,7 @@ export const msgListAtom = atomWithQuery((get) => { return { queryKey: [ 'msgList', get(msgSearchAtom) ], queryFn: async ({ queryKey: [ , params ] }) => { - const list = await messageTemplate.list(params as SearchParams) + const list = await messageMy.list(params as SearchParams) return list.data } } @@ -39,12 +39,12 @@ export const deleteMsgAtom = atomWithMutation((get) => { return { mutationKey: [ 'deleteMsg' ], mutationFn: async (ids: number) => { - return await messageTemplate.delete(ids ?? get(msgIdsAtom) as number) + return await messageMy.delete(ids ?? get(msgIdsAtom) as number) }, onSuccess: (res) => { message.success('message.deleteSuccess') //更新列表 - get(queryClientAtom).invalidateQueries({ queryKey: [ 'templateList', get(msgSearchAtom) ] }) + get(queryClientAtom).invalidateQueries({ queryKey: [ 'msgList', get(msgSearchAtom) ] }) return res } } @@ -55,15 +55,12 @@ export const saveMsgAtom = atomWithMutation((get) => { return { mutationKey: [ 'saveMsg' ], mutationFn: async (data) => { - if (data.id === 0) { - return await messageTemplate.add(data) - } - return await messageTemplate.update(data) + return await messageMy.add(data) }, onSuccess: (res) => { message.success(t('message.saveSuccess', '保存成功')) - get(queryClientAtom).invalidateQueries({ queryKey: [ 'templateList', get(msgSearchAtom) ] }) + get(queryClientAtom).invalidateQueries({ queryKey: [ 'msgList', get(msgSearchAtom) ] }) return res } From 1c88019b1da4715e1d648fc5223a9725ba8c8a31 Mon Sep 17 00:00:00 2001 From: cs Date: Wed, 11 Sep 2024 01:09:12 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E6=B6=88=E6=81=AF=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vite.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/vite.config.ts b/vite.config.ts index 017c4d6..a47aad4 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -8,6 +8,7 @@ import jotaiReactRefresh from "jotai/babel/plugin-react-refresh"; //import { TanStackRouterVite } from '@tanstack/router-vite-plugin' export const downLoadUrl = "http://127.0.0.1:8000"; const proxyMap = { + '/api/v1/mdw-msg': 'http://127.0.0.1:8848', "/api/v1/package": "http://154.88.7.8:45321", "/api/v1/movie": "http://47.113.117.106:10000", //'/api/v1/certold': 'http://192.168.31.41:8000', From 9084a05f09aaff046b22119f1e6e8b8e3e9473dd Mon Sep 17 00:00:00 2001 From: cs Date: Wed, 11 Sep 2024 02:33:36 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E6=B6=88=E6=81=AF=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/message/my/index.tsx | 4 ++-- src/pages/message/template/index.tsx | 3 ++- src/types/message/template.ts | 16 ++++++++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/pages/message/my/index.tsx b/src/pages/message/my/index.tsx index 63971f4..f1f4080 100644 --- a/src/pages/message/my/index.tsx +++ b/src/pages/message/my/index.tsx @@ -10,7 +10,7 @@ import {getValueCount, unSetColumnRules} from '@/utils' import {Table as ProTable} from '@/components/table' import {msgListAtom, msgSearchAtom, saveMsgAtom} from "@/store/message/my.ts"; import {templateAllListAtom} from "@/store/message/template.ts"; -import {IMsgTemplate} from "@/types/message/template.ts"; +import {coverType, IMsgTemplate} from "@/types/message/template.ts"; const i18nPrefix = 'msgMy.list' @@ -243,7 +243,7 @@ const MdwMessage = () => { title: t(`${i18nPrefix}.columns.type`, '类型'), dataIndex: 'type', render: (_, record) => { - return
{record.type}
+ return
{coverType(record.type)}
} }, { diff --git a/src/pages/message/template/index.tsx b/src/pages/message/template/index.tsx index dcc1ccc..c481efc 100644 --- a/src/pages/message/template/index.tsx +++ b/src/pages/message/template/index.tsx @@ -16,6 +16,7 @@ import { templateListAtom, templateSearchAtom } from "@/store/message/template.ts"; +import {coverType} from "@/types/message/template.ts"; const i18nPrefix = 'mdwMessage.list' @@ -214,7 +215,7 @@ const MdwMessage = () => { title: t(`${i18nPrefix}.columns.type`, '模板类型'), dataIndex: 'type', render: (_, record) => { - return
{record.type}
+ return
{coverType(record.type)}
} }, { diff --git a/src/types/message/template.ts b/src/types/message/template.ts index 25cf08c..7ff2eec 100644 --- a/src/types/message/template.ts +++ b/src/types/message/template.ts @@ -7,3 +7,19 @@ export interface IMsgTemplate { type: string fields: string } + +export const coverType = (type: string) => { + let typeText = '' + switch (type) { + case 'SMS': + typeText = '短信' + break + case 'EMAIL': + typeText = '邮件' + break + case 'TG': + typeText = 'Telegram' + break + } + return typeText +}