337 lines
15 KiB
HTML
337 lines
15 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>SMTP配置 - 管理后台</title>
|
||
<link rel="stylesheet" href="/static/css/ui-components.css?v=3">
|
||
<link rel="stylesheet" href="/static/css/admin.css">
|
||
</head>
|
||
|
||
<body class="admin-layout">
|
||
<header class="admin-header">
|
||
<div class="header-container">
|
||
<a href="/admin/dashboard" class="brand">
|
||
<span style="font-size: 1.5rem;">⚡</span> JieXi Admin
|
||
</a>
|
||
<nav class="nav-links">
|
||
<a href="/admin/dashboard" class="nav-item">仪表板</a>
|
||
<a href="/admin/users" class="nav-item">用户管理</a>
|
||
<a href="/admin/apis" class="nav-item">接口管理</a>
|
||
<a href="/admin/redeem-codes" class="nav-item">兑换码</a>
|
||
<a href="/admin/config" class="nav-item active">系统配置</a>
|
||
<a href="/admin/logs" class="nav-item">日志审计</a>
|
||
</nav>
|
||
<div class="user-actions">
|
||
<a href="/admin/profile" class="ui-btn ui-btn-secondary ui-btn-sm">账号设置</a>
|
||
<button class="ui-btn ui-btn-secondary ui-btn-sm" onclick="logout()">退出登录</button>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="main-container">
|
||
<div class="page-header">
|
||
<h1 class="page-title">SMTP配置</h1>
|
||
<div class="actions">
|
||
<a href="/admin/config" class="ui-btn ui-btn-secondary">返回配置</a>
|
||
<button class="ui-btn ui-btn-primary" onclick="showAddModal()">+ 添加SMTP</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="ui-card">
|
||
<div class="table-container">
|
||
<table id="smtpTable">
|
||
<thead>
|
||
<tr>
|
||
<th>ID</th>
|
||
<th>名称</th>
|
||
<th>服务器</th>
|
||
<th>端口</th>
|
||
<th>用户名</th>
|
||
<th>发件邮箱</th>
|
||
<th>权重</th>
|
||
<th>状态</th>
|
||
<th>统计</th>
|
||
<th>操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td colspan="10" style="text-align: center; color: var(--text-muted);">加载中...</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
|
||
<!-- SMTP Modal -->
|
||
<div id="smtpModal" class="ui-modal">
|
||
<div class="ui-modal-overlay" onclick="closeModal()"></div>
|
||
<div class="ui-modal-content">
|
||
<h3 id="modalTitle">添加SMTP配置</h3>
|
||
<form id="smtpForm">
|
||
<input type="hidden" id="smtpId">
|
||
<div class="form-group">
|
||
<label>配置名称 *</label>
|
||
<input type="text" id="smtpName" class="ui-input" required placeholder="例如:阿里云邮件">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>SMTP服务器 *</label>
|
||
<input type="text" id="smtpHost" class="ui-input" required placeholder="smtp.example.com">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>端口 *</label>
|
||
<input type="number" id="smtpPort" class="ui-input" required value="587" min="1" max="65535">
|
||
<small class="text-muted text-sm">常用端口:25 (不加密), 587 (TLS), 465 (SSL)</small>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>用户名 *</label>
|
||
<input type="text" id="smtpUsername" class="ui-input" required>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>密码 *</label>
|
||
<input type="password" id="smtpPassword" class="ui-input" required placeholder="SMTP授权码/密码">
|
||
<small class="text-muted text-sm" id="smtpPasswordHint">创建时必填,编辑时留空表示不修改</small>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>发件邮箱 *</label>
|
||
<input type="email" id="smtpFromEmail" class="ui-input" required placeholder="noreply@example.com">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>发件人名称</label>
|
||
<input type="text" id="smtpFromName" class="ui-input" placeholder="短视频解析平台">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>使用TLS</label>
|
||
<select id="smtpUseTls" class="ui-input">
|
||
<option value="true">是</option>
|
||
<option value="false">否</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>权重</label>
|
||
<input type="number" id="smtpWeight" class="ui-input" value="1" min="0" max="100">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>是否启用</label>
|
||
<select id="smtpEnabled" class="ui-input">
|
||
<option value="true">启用</option>
|
||
<option value="false">禁用</option>
|
||
</select>
|
||
</div>
|
||
<div class="ui-modal-actions">
|
||
<button type="button" class="ui-btn ui-btn-secondary" onclick="closeModal()">取消</button>
|
||
<button type="submit" class="ui-btn ui-btn-primary">保存</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Test Modal -->
|
||
<div id="testModal" class="ui-modal">
|
||
<div class="ui-modal-overlay" onclick="closeTestModal()"></div>
|
||
<div class="ui-modal-content">
|
||
<h3>测试SMTP配置</h3>
|
||
<form id="testForm">
|
||
<div class="form-group">
|
||
<label>测试邮箱地址</label>
|
||
<input type="email" id="testEmail" class="ui-input" required placeholder="test@example.com">
|
||
</div>
|
||
<div class="ui-modal-actions">
|
||
<button type="button" class="ui-btn ui-btn-secondary" onclick="closeTestModal()">取消</button>
|
||
<button type="submit" class="ui-btn ui-btn-success">发送测试邮件</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="/static/js/ui-components.js"></script>
|
||
<script>
|
||
async function loadSmtp() {
|
||
try {
|
||
const response = await fetch('/admin/api/smtp');
|
||
const result = await response.json();
|
||
|
||
if (result.success) {
|
||
const tbody = document.querySelector('#smtpTable tbody');
|
||
if (result.data.length === 0) {
|
||
tbody.innerHTML = '<tr><td colspan="10" style="text-align: center; padding: 2rem; color: var(--text-muted);">暂无SMTP配置</td></tr>';
|
||
return;
|
||
}
|
||
tbody.innerHTML = result.data.map(s => `
|
||
<tr>
|
||
<td>${s.id}</td>
|
||
<td><span class="font-medium">${s.name}</span> ${s.is_default ? '<span class="badge badge-info">默认</span>' : ''}</td>
|
||
<td class="text-sm">${s.host}</td>
|
||
<td>${s.port}</td>
|
||
<td class="text-sm text-muted">${s.username}</td>
|
||
<td class="text-sm">${s.from_email}</td>
|
||
<td>${s.weight}</td>
|
||
<td><span class="badge ${s.is_enabled ? 'badge-success' : 'badge-neutral'}">${s.is_enabled ? '启用' : '禁用'}</span></td>
|
||
<td class="text-sm">${s.send_count} / <span class="text-error">${s.fail_count}失败</span></td>
|
||
<td>
|
||
<div class="flex gap-2">
|
||
<button class="ui-btn ui-btn-secondary ui-btn-sm" onclick='editSmtp(${JSON.stringify(s)})'>编辑</button>
|
||
<button class="ui-btn ui-btn-secondary ui-btn-sm" onclick="testSmtp()">测试</button>
|
||
<button class="ui-btn ui-btn-danger ui-btn-sm" onclick="deleteSmtp(${s.id})">删除</button>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
`).join('');
|
||
}
|
||
} catch (error) {
|
||
UI.notify('加载失败: ' + error.message, 'error');
|
||
}
|
||
}
|
||
|
||
function showAddModal() {
|
||
const passwordInput = document.getElementById('smtpPassword');
|
||
const passwordHint = document.getElementById('smtpPasswordHint');
|
||
document.getElementById('modalTitle').textContent = '添加SMTP配置';
|
||
document.getElementById('smtpForm').reset();
|
||
document.getElementById('smtpId').value = '';
|
||
document.getElementById('smtpPort').value = '587';
|
||
document.getElementById('smtpWeight').value = '1';
|
||
passwordInput.value = '';
|
||
passwordInput.required = true;
|
||
passwordHint.textContent = '创建时必填,编辑时留空表示不修改';
|
||
document.getElementById('smtpModal').classList.add('show');
|
||
}
|
||
|
||
function editSmtp(smtp) {
|
||
const passwordInput = document.getElementById('smtpPassword');
|
||
const passwordHint = document.getElementById('smtpPasswordHint');
|
||
document.getElementById('modalTitle').textContent = '编辑SMTP配置';
|
||
document.getElementById('smtpId').value = smtp.id;
|
||
document.getElementById('smtpName').value = smtp.name;
|
||
document.getElementById('smtpHost').value = smtp.host;
|
||
document.getElementById('smtpPort').value = smtp.port;
|
||
document.getElementById('smtpUsername').value = smtp.username;
|
||
passwordInput.value = '';
|
||
passwordInput.required = false;
|
||
passwordHint.textContent = '留空表示保留原密码/授权码';
|
||
document.getElementById('smtpFromEmail').value = smtp.from_email;
|
||
document.getElementById('smtpFromName').value = smtp.from_name || '';
|
||
document.getElementById('smtpUseTls').value = smtp.use_tls;
|
||
document.getElementById('smtpWeight').value = smtp.weight;
|
||
document.getElementById('smtpEnabled').value = smtp.is_enabled;
|
||
document.getElementById('smtpModal').classList.add('show');
|
||
}
|
||
|
||
function closeModal() {
|
||
document.getElementById('smtpModal').classList.remove('show');
|
||
}
|
||
|
||
function testSmtp() {
|
||
document.getElementById('testModal').classList.add('show');
|
||
}
|
||
|
||
function closeTestModal() {
|
||
document.getElementById('testModal').classList.remove('show');
|
||
}
|
||
|
||
async function deleteSmtp(id) {
|
||
UI.confirm('确认删除', '确定要删除此SMTP配置吗?', async () => {
|
||
try {
|
||
const response = await fetch(`/admin/api/smtp/${id}`, { method: 'DELETE' });
|
||
const result = await response.json();
|
||
|
||
if (result.success) {
|
||
UI.notify('删除成功', 'success');
|
||
loadSmtp();
|
||
} else {
|
||
UI.notify('删除失败: ' + result.message, 'error');
|
||
}
|
||
} catch (error) {
|
||
UI.notify('删除失败: ' + error.message, 'error');
|
||
}
|
||
});
|
||
}
|
||
|
||
document.getElementById('smtpForm').addEventListener('submit', async (e) => {
|
||
e.preventDefault();
|
||
const smtpId = document.getElementById('smtpId').value;
|
||
const passwordInput = document.getElementById('smtpPassword');
|
||
const password = passwordInput.value.trim();
|
||
const data = {
|
||
name: document.getElementById('smtpName').value.trim(),
|
||
host: document.getElementById('smtpHost').value.trim(),
|
||
port: parseInt(document.getElementById('smtpPort').value, 10),
|
||
username: document.getElementById('smtpUsername').value.trim(),
|
||
from_email: document.getElementById('smtpFromEmail').value.trim(),
|
||
from_name: document.getElementById('smtpFromName').value.trim(),
|
||
use_tls: document.getElementById('smtpUseTls').value === 'true',
|
||
weight: parseInt(document.getElementById('smtpWeight').value, 10),
|
||
is_enabled: document.getElementById('smtpEnabled').value === 'true'
|
||
};
|
||
|
||
if (password) {
|
||
data.password = password;
|
||
} else if (!smtpId) {
|
||
UI.notify('请输入SMTP密码/授权码', 'error');
|
||
passwordInput.focus();
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const url = smtpId ? `/admin/api/smtp/${smtpId}` : '/admin/api/smtp';
|
||
const method = smtpId ? 'PUT' : 'POST';
|
||
const response = await fetch(url, {
|
||
method: method,
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(data)
|
||
});
|
||
const result = await response.json();
|
||
|
||
if (result.success) {
|
||
UI.notify(smtpId ? '更新成功' : '创建成功', 'success');
|
||
closeModal();
|
||
loadSmtp();
|
||
} else {
|
||
UI.notify('操作失败: ' + result.message, 'error');
|
||
}
|
||
} catch (error) {
|
||
UI.notify('操作失败: ' + error.message, 'error');
|
||
}
|
||
});
|
||
|
||
document.getElementById('testForm').addEventListener('submit', async (e) => {
|
||
e.preventDefault();
|
||
const email = document.getElementById('testEmail').value;
|
||
|
||
try {
|
||
const response = await fetch('/admin/api/smtp/test', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ email })
|
||
});
|
||
const result = await response.json();
|
||
|
||
if (result.success) {
|
||
UI.notify('测试邮件已发送,请检查收件箱', 'success');
|
||
closeTestModal();
|
||
} else {
|
||
UI.notify('发送失败: ' + result.message, 'error');
|
||
}
|
||
} catch (error) {
|
||
UI.notify('发送失败: ' + error.message, 'error');
|
||
}
|
||
});
|
||
|
||
async function logout() {
|
||
try {
|
||
await fetch('/admin/logout', { method: 'POST' });
|
||
window.location.href = '/admin/login';
|
||
} catch (error) {
|
||
UI.notify('退出失败', 'error');
|
||
}
|
||
}
|
||
|
||
loadSmtp();
|
||
</script>
|
||
</body>
|
||
|
||
</html>
|