151 lines
6.2 KiB
HTML
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;">查看全部 →</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> |