This commit is contained in:
2025-11-28 21:20:40 +08:00
commit f940b95b67
73 changed files with 15721 additions and 0 deletions

View File

@@ -0,0 +1,232 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>健康检查配置 - 管理后台</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/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">健康检查配置</h1>
<div class="actions">
<a href="/admin/config" class="ui-btn ui-btn-secondary">返回配置</a>
<button class="ui-btn ui-btn-primary" onclick="showAddModal()">+ 添加配置</button>
</div>
</div>
<div class="ui-card">
<div class="table-container">
<table id="healthTable">
<thead>
<tr>
<th>ID</th>
<th>平台</th>
<th>测试链接</th>
<th>检查间隔</th>
<th>告警邮箱</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="7" style="text-align: center; color: var(--text-muted);">加载中...</td>
</tr>
</tbody>
</table>
</div>
</div>
</main>
<!-- Health Check Modal -->
<div id="healthModal" class="ui-modal">
<div class="ui-modal-overlay" onclick="closeModal()"></div>
<div class="ui-modal-content">
<h3 id="modalTitle">添加健康检查配置</h3>
<form id="healthForm">
<input type="hidden" id="configId">
<div class="form-group">
<label>平台类型 *</label>
<select id="platform" class="ui-input" required>
<option value="douyin">抖音 (douyin)</option>
<option value="tiktok">TikTok (tiktok)</option>
<option value="bilibili">哔哩哔哩 (bilibili)</option>
</select>
</div>
<div class="form-group">
<label>测试视频链接 *</label>
<input type="url" id="testUrl" class="ui-input" required placeholder="https://...">
<small class="text-muted text-sm">用于健康检查的测试视频链接</small>
</div>
<div class="form-group">
<label>检查间隔(秒)*</label>
<input type="number" id="checkInterval" class="ui-input" value="300" min="60" max="3600" required>
<small class="text-muted text-sm">建议300秒5分钟</small>
</div>
<div class="form-group">
<label>告警邮箱</label>
<input type="email" id="alertEmail" class="ui-input" placeholder="admin@example.com">
<small class="text-muted text-sm">接口异常时发送告警邮件</small>
</div>
<div class="form-group">
<label>是否启用</label>
<select id="isEnabled" 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>
<script src="/static/js/ui-components.js"></script>
<script>
async function loadHealthChecks() {
try {
const response = await fetch('/admin/api/health-checks');
const result = await response.json();
if (result.success) {
const tbody = document.querySelector('#healthTable tbody');
if (result.data.length === 0) {
tbody.innerHTML = '<tr><td colspan="7" style="text-align: center; padding: 2rem; color: var(--text-muted);">暂无配置</td></tr>';
return;
}
tbody.innerHTML = result.data.map(c => `
<tr>
<td>${c.id}</td>
<td><span class="badge badge-neutral">${c.platform}</span></td>
<td style="max-width: 300px; overflow: hidden; text-overflow: ellipsis;" class="text-sm text-muted" title="${c.test_url}">${c.test_url}</td>
<td>${c.check_interval}秒</td>
<td class="text-sm">${c.alert_email || '-'}</td>
<td><span class="badge ${c.is_enabled ? 'badge-success' : 'badge-neutral'}">${c.is_enabled ? '启用' : '禁用'}</span></td>
<td>
<div class="flex gap-2">
<button class="ui-btn ui-btn-secondary ui-btn-sm" onclick='editConfig(${JSON.stringify(c)})'>编辑</button>
<button class="ui-btn ui-btn-danger ui-btn-sm" onclick="deleteConfig(${c.id})">删除</button>
</div>
</td>
</tr>
`).join('');
}
} catch (error) {
UI.notify('加载失败: ' + error.message, 'error');
}
}
function showAddModal() {
document.getElementById('modalTitle').textContent = '添加健康检查配置';
document.getElementById('healthForm').reset();
document.getElementById('configId').value = '';
document.getElementById('checkInterval').value = '300';
document.getElementById('healthModal').classList.add('show');
}
function editConfig(config) {
document.getElementById('modalTitle').textContent = '编辑健康检查配置';
document.getElementById('configId').value = config.id;
document.getElementById('platform').value = config.platform;
document.getElementById('testUrl').value = config.test_url;
document.getElementById('checkInterval').value = config.check_interval;
document.getElementById('alertEmail').value = config.alert_email || '';
document.getElementById('isEnabled').value = config.is_enabled;
document.getElementById('healthModal').classList.add('show');
}
function closeModal() {
document.getElementById('healthModal').classList.remove('show');
}
async function deleteConfig(id) {
UI.confirm('确认删除', '确定要删除此配置吗?', async () => {
try {
const response = await fetch(`/admin/api/health-checks/${id}`, { method: 'DELETE' });
const result = await response.json();
if (result.success) {
UI.notify('删除成功', 'success');
loadHealthChecks();
} else {
UI.notify('删除失败: ' + result.message, 'error');
}
} catch (error) {
UI.notify('删除失败: ' + error.message, 'error');
}
});
}
document.getElementById('healthForm').addEventListener('submit', async (e) => {
e.preventDefault();
const configId = document.getElementById('configId').value;
const data = {
platform: document.getElementById('platform').value,
test_url: document.getElementById('testUrl').value,
check_interval: parseInt(document.getElementById('checkInterval').value),
alert_email: document.getElementById('alertEmail').value || null,
is_enabled: document.getElementById('isEnabled').value === 'true'
};
try {
const url = configId ? `/admin/api/health-checks/${configId}` : '/admin/api/health-checks';
const method = configId ? '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(configId ? '更新成功' : '创建成功', 'success');
closeModal();
loadHealthChecks();
} 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');
}
}
loadHealthChecks();
</script>
</body>
</html>