Files
rainblogweb/frontend/src/admin/pages/EmailSettings.jsx
T

89 lines
3.8 KiB
React

import React, { useEffect, useState } from 'react';
import Paper from '@mui/material/Paper';
import Typography from '@mui/material/Typography';
import TextField from '@mui/material/TextField';
import Button from '@mui/material/Button';
import Box from '@mui/material/Box';
import { getSettings, saveSettings } from '../../api/settings.js';
import { testSmtp } from '../../api/email.js';
import { showSnack } from '../snack.jsx';
/** 邮件配置:SMTP + 发件人信息 + 测试发送(迁移自 v1 邮件卡片) */
export default function EmailSettings() {
const [form, setForm] = useState({
smtp_host: '', smtp_port: '587', smtp_user: '', smtp_pass: '',
smtp_from_email: '', smtp_from_name: 'RainWeb',
});
const [testEmail, setTestEmail] = useState('');
const [saving, setSaving] = useState(false);
const [testing, setTesting] = useState(false);
useEffect(() => {
getSettings()
.then((s) => setForm({
smtp_host: s.smtp_host || '',
smtp_port: s.smtp_port || '587',
smtp_user: s.smtp_user || '',
smtp_pass: s.smtp_pass || '',
smtp_from_email: s.smtp_from_email || '',
smtp_from_name: s.smtp_from_name || 'RainWeb',
}))
.catch((e) => showSnack(e.message, 'error'));
}, []);
const set = (k) => (e) => setForm((p) => ({ ...p, [k]: e.target.value }));
const save = async () => {
setSaving(true);
try {
await saveSettings({
smtp_host: form.smtp_host.trim(),
smtp_port: form.smtp_port,
smtp_user: form.smtp_user.trim(),
smtp_pass: form.smtp_pass,
smtp_from_email: form.smtp_from_email.trim(),
smtp_from_name: form.smtp_from_name.trim(),
});
showSnack('邮件配置已保存');
} catch (e) {
showSnack(e.message, 'error');
}
setSaving(false);
};
const test = async () => {
if (!testEmail.trim()) { showSnack('请输入测试邮箱地址', 'error'); return; }
setTesting(true);
try {
await testSmtp(testEmail.trim());
showSnack('测试邮件已发送至 ' + testEmail.trim());
} catch (e) {
showSnack(e.message, 'error');
}
setTesting(false);
};
return (
<Box sx={{ maxWidth: 640 }}>
<Typography variant="h5" sx={{ mb: 2 }}>邮件配置</Typography>
<Paper sx={{ p: 3, mb: 2 }}>
<Typography variant="subtitle1" sx={{ mb: 1 }}>SMTP 服务器</Typography>
<TextField fullWidth label="SMTP 主机" value={form.smtp_host} onChange={set('smtp_host')} margin="normal" placeholder="smtp.example.com" />
<TextField fullWidth label="端口" type="number" value={form.smtp_port} onChange={set('smtp_port')} margin="normal" placeholder="587" />
<TextField fullWidth label="用户名" value={form.smtp_user} onChange={set('smtp_user')} margin="normal" />
<TextField fullWidth label="密码" type="password" value={form.smtp_pass} onChange={set('smtp_pass')} margin="normal" />
</Paper>
<Paper sx={{ p: 3, mb: 2 }}>
<Typography variant="subtitle1" sx={{ mb: 1 }}>发件人信息</Typography>
<TextField fullWidth label="发件人邮箱" type="email" value={form.smtp_from_email} onChange={set('smtp_from_email')} margin="normal" placeholder="noreply@example.com" />
<TextField fullWidth label="发件人名称" value={form.smtp_from_name} onChange={set('smtp_from_name')} margin="normal" placeholder="RainWeb" />
</Paper>
<Box sx={{ display: 'flex', gap: 1, alignItems: 'flex-start', flexWrap: 'wrap' }}>
<Button variant="contained" onClick={save} disabled={saving}>保存邮件配置</Button>
<TextField size="small" label="测试接收邮箱" value={testEmail} onChange={(e) => setTestEmail(e.target.value)} placeholder="your@email.com" />
<Button variant="outlined" onClick={test} disabled={testing}>发送测试邮件</Button>
</Box>
</Box>
);
}