Files
JieXi/templates/admin_smtp.html
2025-11-30 19:49:25 +08:00

337 lines
15 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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>