Files
pdf-translate-web/templates/admin/dashboard.html
coder d338522692 feat: 添加浏览器标签图标 favicon
- 创建 SVG 格式 favicon(蓝色文档+翻译箭头+中文标记)
- 在所有前台页面添加 favicon:index, login, register, history, pricing, translation
- 在所有后台管理页面添加 favicon
2026-04-11 10:51:24 +08:00

300 lines
13 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>后台管理 - PDF翻译助手</title>
<link rel="icon" href="/static/img/favicon.svg" type="image/svg+xml">
<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">
<style>
body { background-color: #f5f5f5; }
.sidebar {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 250px;
background: #343a40;
padding-top: 60px;
z-index: 1000;
}
.sidebar .nav-link {
color: #adb5bd;
padding: 12px 20px;
border-left: 3px solid transparent;
}
.sidebar .nav-link:hover,
.sidebar .nav-link.active {
color: #fff;
background: rgba(255,255,255,0.1);
border-left-color: #0d6efd;
}
.sidebar .nav-link i { margin-right: 10px; }
.main-content {
margin-left: 250px;
padding: 20px;
}
.stat-card {
border-radius: 10px;
border: none;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.stat-card .icon {
width: 60px;
height: 60px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
}
.stat-card .icon.blue { background: rgba(13, 110, 253, 0.1); color: #0d6efd; }
.stat-card .icon.green { background: rgba(25, 135, 84, 0.1); color: #198754; }
.stat-card .icon.orange { background: rgba(253, 126, 20, 0.1); color: #fd7e14; }
.stat-card .icon.purple { background: rgba(111, 66, 193, 0.1); color: #6f42c1; }
</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 active" 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" 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-3">
<div class="card stat-card">
<div class="card-body d-flex align-items-center">
<div class="icon blue me-3"><i class="bi bi-people-fill"></i></div>
<div>
<div class="text-muted small">总用户数</div>
<div class="fs-4 fw-bold">{{ total_users }}</div>
<div class="text-success small">今日 +{{ new_users_today }}</div>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card stat-card">
<div class="card-body d-flex align-items-center">
<div class="icon green me-3"><i class="bi bi-file-earmark-text"></i></div>
<div>
<div class="text-muted small">总翻译次数</div>
<div class="fs-4 fw-bold">{{ total_translations }}</div>
<div class="text-success small">今日 +{{ today_translations }}</div>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card stat-card">
<div class="card-body d-flex align-items-center">
<div class="icon orange me-3"><i class="bi bi-crown"></i></div>
<div>
<div class="text-muted small">VIP用户</div>
<div class="fs-4 fw-bold">{{ vip_users }}</div>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card stat-card">
<div class="card-body d-flex align-items-center">
<div class="icon purple me-3"><i class="bi bi-database-fill"></i></div>
<div>
<div class="text-muted small">缓存数量</div>
<div class="fs-4 fw-bold">{{ total_cache }}</div>
<div class="text-info small">命中 {{ total_cache_hits }} 次</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<!-- 每日翻译趋势 -->
<div class="col-md-8 mb-4">
<div class="card">
<div class="card-header">
<h6 class="mb-0"><i class="bi bi-graph-up"></i> 每日翻译趋势最近7天</h6>
</div>
<div class="card-body">
<canvas id="trendChart" height="100"></canvas>
</div>
</div>
</div>
<!-- 快捷操作 -->
<div class="col-md-4 mb-4">
<div class="card">
<div class="card-header">
<h6 class="mb-0"><i class="bi bi-lightning"></i> 快捷操作</h6>
</div>
<div class="card-body">
<a href="{{ url_for('admin.users') }}" class="btn btn-outline-primary w-100 mb-2">
<i class="bi bi-person-plus"></i> 添加用户
</a>
<a href="{{ url_for('admin.cache_list') }}" class="btn btn-outline-warning w-100 mb-2">
<i class="bi bi-trash"></i> 清理缓存
</a>
<a href="{{ url_for('admin.settings') }}" class="btn btn-outline-secondary w-100">
<i class="bi bi-gear"></i> 系统配置
</a>
</div>
</div>
</div>
</div>
<div class="row">
<!-- 最近翻译 -->
<div class="col-md-6 mb-4">
<div class="card">
<div class="card-header d-flex justify-content-between">
<h6 class="mb-0"><i class="bi bi-clock-history"></i> 最近翻译</h6>
<a href="{{ url_for('admin.translations') }}" class="small">查看全部</a>
</div>
<div class="card-body p-0">
<table class="table table-hover mb-0">
<thead>
<tr>
<th>文件名</th>
<th>状态</th>
<th>时间</th>
</tr>
</thead>
<tbody>
{% for t in recent_translations %}
<tr>
<td>{{ t.original_filename[:30] }}{% if t.original_filename|length > 30 %}...{% endif %}</td>
<td>
<span class="badge bg-{% if t.status == 'completed' %}success{% elif t.status == 'processing' %}warning{% else %}danger{% endif %}">
{{ t.status }}
</span>
</td>
<td><small>{{ t.created_at.strftime('%H:%M') }}</small></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<!-- 最近用户 -->
<div class="col-md-6 mb-4">
<div class="card">
<div class="card-header d-flex justify-content-between">
<h6 class="mb-0"><i class="bi bi-person-lines-fill"></i> 最近注册</h6>
<a href="{{ url_for('admin.users') }}" class="small">查看全部</a>
</div>
<div class="card-body p-0">
<table class="table table-hover mb-0">
<thead>
<tr>
<th>用户名</th>
<th>类型</th>
<th>注册时间</th>
</tr>
</thead>
<tbody>
{% for u in recent_users %}
<tr>
<td>{{ u.username }}</td>
<td>
<span class="badge bg-{% if u.user_type == 'free' %}secondary{% elif 'vip' in u.user_type %}warning{% else %}primary{% endif %}">
{{ u.user_type }}
</span>
</td>
<td><small>{{ u.created_at.strftime('%m-%d %H:%M') }}</small></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
// 绘制趋势图
const ctx = document.getElementById('trendChart').getContext('2d');
const data = {{ daily_stats | tojson }};
new Chart(ctx, {
type: 'line',
data: {
labels: data.map(d => d.date),
datasets: [{
label: '翻译次数',
data: data.map(d => d.count),
borderColor: '#0d6efd',
backgroundColor: 'rgba(13, 110, 253, 0.1)',
fill: true,
tension: 0.3
}]
},
options: {
responsive: true,
plugins: { legend: { display: false } },
scales: { y: { beginAtZero: true } }
}
});
</script>
</body>
</html>