first commit

This commit is contained in:
liu
2026-07-13 15:23:29 +08:00
commit 50885a98c8
473 changed files with 33772 additions and 0 deletions
+514
View File
@@ -0,0 +1,514 @@
import React, {useEffect, useRef, useState} from 'react';
import {
Button,
Card,
Form,
Input,
message,
Row,
Col,
Typography,
Divider
} from 'antd';
import { SendOutlined } from '@ant-design/icons';
import { useTranslation } from 'react-i18next';
import { getMailConfig, saveMailConfig, sendTestMail } from '@/api/system/sysMail.ts';
import type {FormColumn} from "@/components/XinFormField/FieldRender";
import XinForm, {type XinFormRef} from "@/components/XinForm";
const { Text, Title } = Typography;
interface MailResponse {
other: {
mode: 'single' | 'failover' | 'roundrobin',
mailers: string[];
},
mail: {
default: string;
mailers: {
smtp: {
url: string;
host: string;
port: string;
username: string;
password: string;
},
log: {
channel: string;
}
},
from: {
address: string;
name: string;
}
},
services: {
postmark: {
token: string;
},
ses: {
key: string;
secret: string;
region: string;
token: string;
},
resend: {
key: string;
},
mailgun: {
domain: string;
secret: string;
endpoint: string;
}
}
}
const MailConfig: React.FC = () => {
const { t } = useTranslation();
const formRef = useRef<XinFormRef>(null);
const [form] = Form.useForm();
const [testForm] = Form.useForm();
const [testing, setTesting] = useState(false);
const driverOptions = [
{ label: t('system.mail.driver.smtp'), value: 'smtp' },
{ label: t('system.mail.driver.ses'), value: 'ses' },
{ label: t('system.mail.driver.mailgun'), value: 'mailgun' },
{ label: t('system.mail.driver.postmark'), value: 'postmark' },
{ label: t('system.mail.driver.resend'), value: 'resend' },
{ label: t('system.mail.driver.log'), value: 'log' },
{ label: t('system.mail.driver.array'), value: 'array' },
];
const columns: FormColumn<MailResponse>[] = [
{
dataIndex: ['other', 'mode'],
valueType: 'radio',
title: t('system.mail.mode'),
fieldProps: {
options: [
{ label: t('system.mail.mode.single'), value: 'single'},
{ label: t('system.mail.mode.failover'), value: 'failover'},
{ label: t('system.mail.mode.roundrobin'), value: 'roundrobin'},
]
},
required: true,
colProps: {span: 24}
},
{
dataIndex: ['mail', 'default'],
valueType: 'radioButton',
title: t('system.mail.driver'),
fieldProps: {
options: driverOptions
},
required: true,
colProps: {span: 24},
dependency: {
dependencies: ['other'],
visible: (values) => {
return values.other?.mode === 'single'
}
}
},
{
dataIndex: ['other', 'mailers'],
valueType: 'checkbox',
title: t('system.mail.driver'),
fieldProps: { options: driverOptions},
colProps: {span: 24},
dependency: {
dependencies: ['other'],
visible: (values) => {
return values.other?.mode !== 'single'
}
}
},
{
dataIndex: ['mail', 'from', 'address'],
valueType: 'text',
title: t('system.mail.from_address'),
fieldProps: {
placeholder: t('system.mail.from_address.placeholder'),
},
required: true,
colProps: {span: 12}
},
{
dataIndex: ['mail', 'from', 'name'],
valueType: 'text',
title: t('system.mail.from_name'),
fieldProps: {
placeholder: t('system.mail.from_name.placeholder'),
},
required: true,
colProps: {span: 12}
},
{
fieldRender: () => <Divider>{t('system.mail.smtp.title')}</Divider>,
dependency: {
dependencies: ['mail', 'other'],
visible: (values) => {
return values.mail?.default === 'smtp' || !!values.other?.mailers?.includes('smtp')
}
},
colProps: {span: 24},
noStyle: true
},
{
dataIndex: ['mail', 'mailers', 'smtp', 'host'],
valueType: 'text',
title: t('system.mail.host'),
fieldProps: {
placeholder: t('system.mail.host.placeholder'),
},
required: true,
colProps: {span: 16},
dependency: {
dependencies: ['mail', 'other'],
visible: (values) => {
return values.mail?.default === 'smtp' || !!values.other?.mailers?.includes('smtp')
}
}
},
{
dataIndex: ['mail', 'mailers', 'smtp', 'port'],
valueType: 'digit',
title: t('system.mail.port'),
fieldProps: {
placeholder: t('system.mail.port.placeholder'),
},
required: true,
colProps: {span: 8},
dependency: {
dependencies: ['mail', 'other'],
visible: (values) => {
return values.mail?.default === 'smtp' || !!values.other?.mailers?.includes('smtp')
}
}
},
{
dataIndex: ['mail', 'mailers', 'smtp', 'username'],
valueType: 'text',
title: t('system.mail.username'),
fieldProps: {
placeholder: t('system.mail.username.placeholder'),
},
required: true,
colProps: {span: 12},
dependency: {
dependencies: ['mail', 'other'],
visible: (values) => {
return values.mail?.default === 'smtp' || !!values.other?.mailers?.includes('smtp')
}
}
},
{
dataIndex: ['mail', 'mailers', 'smtp', 'password'],
valueType: 'password',
title: t('system.mail.password'),
fieldProps: {
placeholder: t('system.mail.password.placeholder'),
},
required: true,
colProps: {span: 12},
dependency: {
dependencies: ['mail', 'other'],
visible: (values) => {
return values.mail?.default === 'smtp' || !!values.other?.mailers?.includes('smtp')
}
}
},
{
fieldRender: () => <Divider>{t('system.mail.log.title')}</Divider>,
dependency: {
dependencies: ['mail', 'other'],
visible: (values) => {
return values.mail?.default === 'log' || !!values.other?.mailers?.includes('log')
}
},
colProps: {span: 24},
noStyle: true
},
{
dataIndex: ['mail', 'mailers', 'log', 'channel'],
valueType: 'text',
title: t('system.mail.log.channel'),
fieldProps: {
placeholder: t('system.mail.log.channel.placeholder'),
},
required: true,
colProps: {span: 24},
dependency: {
dependencies: ['mail', 'other'],
visible: (values) => {
return values.mail?.default === 'log' || !!values.other?.mailers?.includes('log')
}
}
},
{
fieldRender: () => <Divider>{t('system.mail.postmark.title')}</Divider>,
dependency: {
dependencies: ['mail', 'other'],
visible: (values) => {
return values.mail?.default === 'postmark' || !!values.other?.mailers?.includes('postmark')
}
},
colProps: {span: 24},
noStyle: true
},
{
dataIndex: ['services', 'postmark', 'token'],
valueType: 'text',
title: t('system.mail.postmark.token'),
fieldProps: {
placeholder: t('system.mail.postmark.token.placeholder'),
},
required: true,
colProps: {span: 24},
dependency: {
dependencies: ['mail', 'other'],
visible: (values) => {
return values.mail?.default === 'postmark' || !!values.other?.mailers?.includes('postmark')
}
}
},
{
fieldRender: () => <Divider>{t('system.mail.resend.title')}</Divider>,
dependency: {
dependencies: ['mail', 'other'],
visible: (values) => {
return values.mail?.default === 'resend' || !!values.other?.mailers?.includes('resend')
}
},
colProps: {span: 24},
noStyle: true
},
{
dataIndex: ['services', 'resend', 'key'],
valueType: 'text',
title: t('system.mail.resend.key'),
fieldProps: {
placeholder: t('system.mail.resend.key.placeholder'),
},
required: true,
colProps: {span: 24},
dependency: {
dependencies: ['mail', 'other'],
visible: (values) => {
return values.mail?.default === 'resend' || !!values.other?.mailers?.includes('resend')
}
}
},
{
fieldRender: () => <Divider>{t('system.mail.mailgun.title')}</Divider>,
dependency: {
dependencies: ['mail', 'other'],
visible: (values) => {
return values.mail?.default === 'mailgun' || !!values.other?.mailers?.includes('mailgun')
}
},
colProps: {span: 24},
noStyle: true
},
{
dataIndex: ['services', 'mailgun', 'domain'],
valueType: 'text',
title: t('system.mail.mailgun.domain'),
fieldProps: {
placeholder: t('system.mail.mailgun.domain.placeholder'),
},
required: true,
colProps: {span: 12},
dependency: {
dependencies: ['mail', 'other'],
visible: (values) => {
return values.mail?.default === 'mailgun' || !!values.other?.mailers?.includes('mailgun')
}
}
},
{
dataIndex: ['services', 'mailgun', 'secret'],
valueType: 'text',
title: t('system.mail.mailgun.secret'),
fieldProps: {
placeholder: t('system.mail.mailgun.secret.placeholder'),
},
required: true,
colProps: {span: 12},
dependency: {
dependencies: ['mail', 'other'],
visible: (values) => {
return values.mail?.default === 'mailgun' || !!values.other?.mailers?.includes('mailgun')
}
}
},
{
dataIndex: ['services', 'mailgun', 'endpoint'],
valueType: 'text',
title: t('system.mail.mailgun.endpoint'),
fieldProps: {
placeholder: t('system.mail.mailgun.endpoint.placeholder'),
},
required: true,
colProps: {span: 12},
dependency: {
dependencies: ['mail', 'other'],
visible: (values) => {
return values.mail?.default === 'mailgun' || !!values.other?.mailers?.includes('mailgun')
}
}
},
{
fieldRender: () => <Divider>{t('system.mail.ses.title')}</Divider>,
dependency: {
dependencies: ['mail', 'other'],
visible: (values) => {
return values.mail?.default === 'ses' || !!values.other?.mailers?.includes('ses')
}
},
colProps: {span: 24},
noStyle: true
},
{
dataIndex: ['services', 'ses', 'key'],
valueType: 'text',
title: t('system.mail.ses.key'),
fieldProps: {
placeholder: t('system.mail.ses.key.placeholder'),
},
required: true,
colProps: {span: 12},
dependency: {
dependencies: ['mail', 'other'],
visible: (values) => {
return values.mail?.default === 'ses' || !!values.other?.mailers?.includes('ses')
}
}
},
{
dataIndex: ['services', 'ses', 'secret'],
valueType: 'text',
title: t('system.mail.ses.secret'),
fieldProps: {
placeholder: t('system.mail.ses.secret.placeholder'),
},
required: true,
colProps: {span: 12},
dependency: {
dependencies: ['mail', 'other'],
visible: (values) => {
return values.mail?.default === 'ses' || !!values.other?.mailers?.includes('ses')
}
}
},
{
dataIndex: ['services', 'ses', 'region'],
valueType: 'text',
title: t('system.mail.ses.region'),
fieldProps: {
placeholder: t('system.mail.ses.region.placeholder'),
},
required: true,
colProps: {span: 12},
dependency: {
dependencies: ['mail', 'other'],
visible: (values) => {
return values.mail?.default === 'ses' || !!values.other?.mailers?.includes('ses')
}
}
},
{
dataIndex: ['services', 'ses', 'token'],
valueType: 'text',
title: t('system.mail.ses.token'),
fieldProps: {
placeholder: t('system.mail.ses.token.placeholder'),
},
required: true,
colProps: {span: 12},
dependency: {
dependencies: ['mail', 'other'],
visible: (values) => {
return values.mail?.default === 'ses' || !!values.other?.mailers?.includes('ses')
}
}
}
];
useEffect(() => {
loadConfig();
}, []);
const loadConfig = async () => {
const { data } = await getMailConfig();
if (data.success) {
form.setFieldsValue(data.data);
}
};
const onFinish = async (values: any) => {
await saveMailConfig(values);
message.success(t('system.mail.save.success'));
};
const onTestFinish = async (values: any) => {
try {
setTesting(true);
await sendTestMail(values.to);
message.success(t('system.mail.test.success'));
} finally {
setTesting(false);
}
};
return (
<>
<div className={'mb-5'}>
<Title level={3}>{t('system.mail.page.title')}</Title>
<Text type="secondary">{t('system.mail.page.description')}</Text>
</div>
<Row gutter={24}>
<Col span={16}>
<Card variant={'borderless'}>
<XinForm
columns={columns}
layout="vertical"
formRef={formRef}
form={form}
grid={true}
onFinish={onFinish}
rowProps={{
gutter: [10, 0]
}}
/>
</Card>
</Col>
<Col span={8}>
<Card title={t('system.mail.test.title')}>
<Form
form={testForm}
layout="vertical"
onFinish={onTestFinish}
>
<Form.Item
name="to"
label={t('system.mail.test.to')}
rules={[{ required: true, type: 'email' }]}
>
<Input placeholder={t('system.mail.test.to.placeholder')} />
</Form.Item>
<Button type="primary" htmlType="submit" block icon={<SendOutlined />} loading={testing}>
{t('system.mail.test.send')}
</Button>
</Form>
</Card>
</Col>
</Row>
</>
);
};
export default MailConfig;