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

151 lines
6.2 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>仪表板 - 管理后台</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 active">仪表板</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">系统配置</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="/" target="_blank" class="ui-btn ui-btn-primary ui-btn-sm">
访问前台
</a>
</div>
</div>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-label">今日解析总数</div>
<div class="stat-value" id="todayTotal">-</div>
</div>
<div class="stat-card">
<div class="stat-label">今日成功解析</div>
<div class="stat-value" id="todaySuccess" style="color: var(--success);">-</div>
</div>
<div class="stat-card">
<div class="stat-label">总注册用户</div>
<div class="stat-value" id="totalUsers">-</div>
</div>
<div class="stat-card">
<div class="stat-label">活跃接口节点</div>
<div class="stat-value" id="activeApis" style="color: var(--warning);">-</div>
</div>
</div>
<div class="ui-card">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-bold">实时解析动态</h3>
<a href="/admin/logs" class="text-sm text-muted" style="text-decoration: none;">查看全部 &rarr;</a>
</div>
<div class="table-container">
<table id="logsTable">
<thead>
<tr>
<th>时间</th>
<th>平台</th>
<th>状态</th>
<th>耗时</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="4" style="text-align: center; color: var(--text-muted);">加载中...</td>
</tr>
</tbody>
</table>
</div>
</div>
</main>
<script src="/static/js/ui-components.js"></script>
<script>
async function loadDashboard() {
try {
const response = await fetch('/admin/api/dashboard');
const result = await response.json();
if (result.success) {
const data = result.data;
document.getElementById('todayTotal').textContent = data.today.total.toLocaleString();
document.getElementById('todaySuccess').textContent = data.today.success.toLocaleString();
document.getElementById('totalUsers').textContent = data.total_users.toLocaleString();
document.getElementById('activeApis').textContent = data.active_apis;
}
} catch (error) {
UI.notify('加载数据失败: ' + error.message, 'error');
}
}
async function loadRecentLogs() {
try {
const response = await fetch('/admin/api/logs?page=1&per_page=10');
const result = await response.json();
if (result.success && result.data.length > 0) {
const tbody = document.querySelector('#logsTable tbody');
tbody.innerHTML = result.data.map(log => {
let badgeClass = 'badge-neutral';
if (log.status === 'success') badgeClass = 'badge-success';
else if (log.status === 'failed') badgeClass = 'badge-error';
return `
<tr>
<td>${new Date(log.created_at).toLocaleString('zh-CN')}</td>
<td><span class="font-medium">${log.platform}</span></td>
<td><span class="badge ${badgeClass}">${log.status}</span></td>
<td class="text-muted">${log.response_time ? (log.response_time / 1000).toFixed(2) + 's' : '-'}</td>
</tr>
`;
}).join('');
} else {
document.querySelector('#logsTable tbody').innerHTML =
'<tr><td colspan="4" style="text-align: center; padding: 2rem; color: var(--text-muted);">暂无记录</td></tr>';
}
} catch (error) {
UI.notify('加载日志失败', 'error');
}
}
async function logout() {
try {
await fetch('/admin/logout', { method: 'POST' });
window.location.href = '/admin/login';
} catch (error) {
UI.notify('退出失败', 'error');
}
}
loadDashboard();
loadRecentLogs();
</script>
</body>
</html>