5 changed files with 607 additions and 0 deletions
			
			
		- 
					454src/pages/system/message/index.tsx
 - 
					26src/pages/system/message/style.ts
 - 
					17src/service/message/message.ts
 - 
					85src/store/system/message.ts
 - 
					25src/types/system/message.ts
 
@ -0,0 +1,454 @@ | 
				
			|||
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<string[]>(['name']); | 
				
			|||
  const [titleTemplateField, setTitleTemplateField] = useState<string[]>([]); | 
				
			|||
 | 
				
			|||
  const [allTemplateField, setAllTemplateField] = useState<string[]>([]); | 
				
			|||
 | 
				
			|||
  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) => ( | 
				
			|||
                              <Tag key={index} color="blue" style={{marginRight: 8}}> | 
				
			|||
                                {variable} | 
				
			|||
                              </Tag> | 
				
			|||
                      )) | 
				
			|||
                    } | 
				
			|||
                  </> | 
				
			|||
          ); | 
				
			|||
        } | 
				
			|||
      }, | 
				
			|||
      { | 
				
			|||
        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) => [ | 
				
			|||
          <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>, | 
				
			|||
          <Divider type={'vertical'}/>, | 
				
			|||
          <Action key="send" | 
				
			|||
                  as={'a'} | 
				
			|||
                  onClick={() => { | 
				
			|||
                    form.setFieldsValue(record) | 
				
			|||
                    setOpen(true) | 
				
			|||
                  }}>{t('actions.sendMsg', '发送消息')}</Action>, | 
				
			|||
        ] | 
				
			|||
      } | 
				
			|||
    ] 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': allTemplateField}) | 
				
			|||
                    }} | 
				
			|||
                    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 | 
				
			|||
@ -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), | 
				
			|||
    } | 
				
			|||
}) | 
				
			|||
@ -0,0 +1,17 @@ | 
				
			|||
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<any, IMsgTemplate>('/mdw-msg/template'), | 
				
			|||
  list: async (params: any) => { | 
				
			|||
    return await request.get<IPageResult<IMsgTemplate>>(`mdw-msg/template/list`, { ...params }) | 
				
			|||
  }, | 
				
			|||
 | 
				
			|||
  fieldList: async (params: any) => { | 
				
			|||
    return await request.get<IApiResult<IMsgFieldRes>>(`mdw-msg/template/fieldList`, { ...params }) | 
				
			|||
  }, | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default mdwMessage | 
				
			|||
@ -0,0 +1,85 @@ | 
				
			|||
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<number>(0) | 
				
			|||
 | 
				
			|||
export const templateAtom = atom<IMsgTemplate>(undefined as unknown as IMsgTemplate) | 
				
			|||
 | 
				
			|||
export const templateSearchAtom = atom<SearchParams>({ | 
				
			|||
  key: '', | 
				
			|||
  pageSize: 10, | 
				
			|||
  page: 1, | 
				
			|||
} as SearchParams) | 
				
			|||
 | 
				
			|||
export const templatePageAtom = atom<IPage>({ | 
				
			|||
  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<IApiResult, IMsgTemplate>((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 | 
				
			|||
    } | 
				
			|||
  } | 
				
			|||
}) | 
				
			|||
@ -0,0 +1,25 @@ | 
				
			|||
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 | 
				
			|||
} | 
				
			|||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue