import {useTranslation} from '@/i18n.ts' import {Badge, Button, Divider, Form, Input, Select, Space, Table, TableColumnsType, 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"; import {coverType, IMsgTemplate} from "@/types/message/template.ts"; import dayjs from "dayjs"; const i18nPrefix = 'msgMy.list' const MdwMessage = () => { const {styles} = 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 [currentTemplate, setCurrentTemplate] = useState() const [searchKey, setSearchKey] = useState(search?.title) const [templateType, setTemplateType] = useState('') 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) } else { form.resetFields() setTemplateType('') setCurrentTemplate(undefined) } } const handleInputChange = (index, e) => { form.getFieldValue("fieldList")[index].field_value = e.target.value } const drawerColumns = useMemo(() => { return [ { title: 'ID', dataIndex: 'id', hideInTable: true, hideInSearch: true, formItemProps: {hidden: true} }, { title: t(`${i18nPrefix}.columns.template`, '选择模板'), valueType: 'select', fieldProps: { allowClear: true, }, renderFormItem: () => { return }, }, { title: t(`${i18nPrefix}.columns.type`, '通道类型'), dataIndex: 'type', valueType: 'select', fieldProps: { options: [ {label: '短信', value: 'SMS'}, {label: '邮件', value: 'EMAIL'}, {label: 'Telegram', value: 'TG'} ], allowClear: false, disabled: true, }, formItemProps: { rules: [ { required: true, } ] } }, { title: t(`${i18nPrefix}.columns.token`, 'Telegram BOT API Token'), dataIndex: 'token', valueType: 'text', fieldProps: { placeholder: "请输入 @BotFather 获取到的BOT的API Token" }, formItemProps: { hidden: templateType != 'TG', rules: [ { required: templateType == 'TG', } ] }, }, { title: t(`${i18nPrefix}.columns.email_from`, '发件人邮箱'), dataIndex: 'email_from', valueType: 'text', fieldProps: { maxLength: 100, showCount: true, }, formItemProps: { hidden: templateType != 'EMAIL', rules: [ { required: templateType == 'EMAIL', message: t('message.required', '模板内容必填') } ] }, }, { title: t(`${i18nPrefix}.columns.title`, '标题'), dataIndex: 'title', valueType: 'text', fieldProps: { maxLength: 100, showCount: true, disabled: true, }, formItemProps: { hidden: templateType != 'EMAIL', rules: [ { required: templateType == 'EMAIL', message: t('message.required', '模板内容必填') } ] }, }, { title: t(`${i18nPrefix}.columns.content`, '正文'), dataIndex: 'content', valueType: 'textarea', fieldProps: { maxLength: 1000, showCount: true, rows: 15, disabled: true, }, formItemProps: { rules: [ { required: true, message: t('message.required', '内容必填') } ] } }, { title: t(`${i18nPrefix}.columns.fieldList`, '填充变量'), dataIndex: 'fieldList', formItemProps: { hidden: currentTemplate === undefined, }, renderFormItem: (_, config) => { return ( <> { config.value?.map((variable, index) => (
handleInputChange(index, e)} />
)) } ); }, }, { title: t(`${i18nPrefix}.columns.dest`, '收件人(多个收件人用英文逗号隔开;如果类型是Telegram,请填写User ID或Chat ID)'), dataIndex: 'dest', valueType: 'textarea', fieldProps: { maxLength: 1000, showCount: true, rows: 5, placeholder: 'aaa@qq.com,bbb@gmail.com,-1001953214222,-1001953214333', }, formItemProps: { rules: [ { required: true, message: t('message.required', '内容必填') } ] } }, ] as ProColumns[] }, [search, templateType, templateList]) const columns = useMemo(() => { return [ { title: 'ID', dataIndex: 'id', hideInTable: true, hideInSearch: true, formItemProps: {hidden: true} }, { title: t(`${i18nPrefix}.columns.type`, '类型'), dataIndex: 'type', render: (_, record) => { return
{coverType(record.type)}
} }, { title: t(`${i18nPrefix}.columns.title`, '标题'), dataIndex: 'title', }, { title: t(`${i18nPrefix}.columns.content`, '正文'), dataIndex: 'content', }, { title: t(`${i18nPrefix}.columns.send_at`, '预计发送时间'), dataIndex: 'send_at', render: (_, record) => { return
{record.send_at == 0 ? "立即" : dayjs(record.send_at).format('YYYY-MM-DD HH:mm:ss')}
} }, ] as ProColumns[] }, [search, currentTemplate]) const expandedRowRender = (record, index) => { const expandedColumns: TableColumnsType = [ { title: "收件人", dataIndex: 'dest', }, { title: t(`${i18nPrefix}.columns.status`, '状态'), dataIndex: 'status', render: (_text, record) => { return } }, { title: t(`${i18nPrefix}.columns.send_at`, '发送时间'), dataIndex: 'send_at', render: (_, record) => { return
{record.send_at == 0 ? 0 : dayjs(record.send_at * 1000).format('YYYY-MM-DD HH:mm:ss')}
} }, ]; return ; } 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, } }) }, }} expandable={{ expandedRowRender, }} /> { setOpen(open) }} loading={isSubmitting} onValuesChange={() => { }} onFinish={async (values) => { saveOrUpdate({...values, "code": currentTemplate?.code}) }} 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