Files
pdf-translate-web/templates/admin/stats.html
coder 7fede0212b feat: 后台添加大模型配置管理页面
- 新增 /admin/llm_config 页面
- 支持配置API地址、Key、模型名称、参数
- 支持测试连接和恢复默认配置
- 配置保存到数据库,翻译服务动态读取
- 所有后台页面侧边栏添加入口
2026-04-10 18:42:20 +08:00

161 lines
7.6 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">
<title>统计报表 - 后台管理</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
body { background-color: #f5f5f5; }
.sidebar { position: fixed; top: 0; left: 0; height: 100vh; width: 250px; background: #343a40; padding-top: 60px; }
.sidebar .nav-link { color: #adb5bd; padding: 12px 20px; }
.sidebar .nav-link:hover, .sidebar .nav-link.active { color: #fff; background: rgba(255,255,255,0.1); }
.main-content { margin-left: 250px; padding: 20px; }
</style>
</head>
<body>
<nav class="sidebar">
<div class="position-absolute top-0 w-100 p-3 border-bottom border-secondary">
<h5 class="text-white mb-0"><i class="bi bi-gear-fill"></i> 后台管理</h5>
</div>
<ul class="nav flex-column">
<li class="nav-item"><a class="nav-link" href="{{ url_for('admin.dashboard') }}"><i class="bi bi-speedometer2"></i> 数据概览</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('admin.users') }}"><i class="bi bi-people"></i> 用户管理</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('admin.translations') }}"><i class="bi bi-file-text"></i> 翻译记录</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('admin.cache_list') }}"><i class="bi bi-database"></i> 缓存管理</a></li>
<li class="nav-item"><a class="nav-link active" href="{{ url_for('admin.stats') }}"><i class="bi bi-bar-chart"></i> 统计报表</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('admin.logs') }}"><i class="bi bi-list-check"></i> 操作日志</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('admin.llm_config') }}"><i class="bi bi-cpu"></i> 大模型配置</a></li>
<li class="nav-item"><a class="nav-link" href="{{ url_for('admin.settings') }}"><i class="bi bi-sliders"></i> 系统配置</a></li>
</ul>
<div class="position-absolute bottom-0 w-100 p-3 border-top border-secondary">
<a href="/" class="btn btn-outline-light btn-sm w-100"><i class="bi bi-house"></i> 返回前台</a>
</div>
</nav>
<main class="main-content">
<div class="row mb-4">
<!-- 用户增长趋势 -->
<div class="col-md-6">
<div class="card">
<div class="card-header"><h6 class="mb-0"><i class="bi bi-people"></i> 用户增长趋势30天</h6></div>
<div class="card-body">
<canvas id="userChart" height="150"></canvas>
</div>
</div>
</div>
<!-- 翻译量趋势 -->
<div class="col-md-6">
<div class="card">
<div class="card-header"><h6 class="mb-0"><i class="bi bi-file-text"></i> 翻译量趋势30天</h6></div>
<div class="card-body">
<canvas id="transChart" height="150"></canvas>
</div>
</div>
</div>
</div>
<div class="row mb-4">
<!-- 用户类型分布 -->
<div class="col-md-4">
<div class="card">
<div class="card-header"><h6 class="mb-0"><i class="bi bi-pie-chart"></i> 用户类型分布</h6></div>
<div class="card-body">
<canvas id="userTypeChart" height="200"></canvas>
</div>
</div>
</div>
<!-- 翻译状态分布 -->
<div class="col-md-4">
<div class="card">
<div class="card-header"><h6 class="mb-0"><i class="bi bi-pie-chart"></i> 翻译状态分布</h6></div>
<div class="card-body">
<canvas id="statusChart" height="200"></canvas>
</div>
</div>
</div>
<!-- Top用户 -->
<div class="col-md-4">
<div class="card">
<div class="card-header"><h6 class="mb-0"><i class="bi bi-trophy"></i> 活跃用户Top10</h6></div>
<div class="card-body p-0">
<table class="table table-sm mb-0">
<thead class="table-light">
<tr><th>排名</th><th>用户</th><th>翻译数</th></tr>
</thead>
<tbody>
{% for name, count in top_users %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ name }}</td>
<td><span class="badge bg-primary">{{ count }}</span></td>
</tr>
{% else %}
<tr><td colspan="3" class="text-center text-muted">暂无数据</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</main>
<script>
// 用户增长趋势
new Chart(document.getElementById('userChart'), {
type: 'line',
data: {
labels: {{ user_growth | map(attribute='date') | list | tojson }},
datasets: [{
label: '新增用户',
data: {{ user_growth | map(attribute='count') | list | tojson }},
borderColor: '#0d6efd',
backgroundColor: 'rgba(13, 110, 253, 0.1)',
fill: true, tension: 0.3
}]
},
options: { responsive: true, plugins: { legend: { display: false } } }
});
// 翻译量趋势
new Chart(document.getElementById('transChart'), {
type: 'bar',
data: {
labels: {{ translation_growth | map(attribute='date') | list | tojson }},
datasets: [{
label: '翻译次数',
data: {{ translation_growth | map(attribute='count') | list | tojson }},
backgroundColor: 'rgba(25, 135, 84, 0.7)'
}]
},
options: { responsive: true, plugins: { legend: { display: false } } }
});
// 用户类型分布
new Chart(document.getElementById('userTypeChart'), {
type: 'doughnut',
data: {
labels: {{ user_distribution | map(attribute=0) | list | tojson }},
datasets: [{
data: {{ user_distribution | map(attribute=1) | list | tojson }},
backgroundColor: ['#6c757d', '#ffc107', '#fd7e14', '#0d6efd', '#198754']
}]
}
});
// 翻译状态分布
new Chart(document.getElementById('statusChart'), {
type: 'doughnut',
data: {
labels: {{ status_distribution | map(attribute=0) | list | tojson }},
datasets: [{
data: {{ status_distribution | map(attribute=1) | list | tojson }},
backgroundColor: ['#198754', '#ffc107', '#dc3545', '#6c757d']
}]
}
});
</script>
</body>
</html>