This commit is contained in:
DengDai
2025-12-09 13:08:38 +08:00
commit 02ecea06f8
36 changed files with 5876 additions and 0 deletions

72
templates/base.html Normal file
View File

@@ -0,0 +1,72 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}PT站点管理系统{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap-icons.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
{% block extra_css %}{% endblock %}
</head>
<body>
<!-- 导航栏 -->
{% if show_nav %}
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="{{ url_for('tasks') }}">PT管理系统</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto">
<li class="nav-item">
<a class="nav-link" href="{{ url_for('tasks') }}">
<i class="bi bi-list-task"></i> 任务列表
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('statistics') }}">
<i class="bi bi-graph-up"></i> 统计报表
</a>
</li>
<li class="nav-item admin-only" style="display:none;">
<a class="nav-link" href="{{ url_for('create_task_page') }}">
<i class="bi bi-plus-circle"></i> 创建任务
</a>
</li>
<li class="nav-item" id="nav-users" style="display:none;">
<a class="nav-link" href="{{ url_for('users_page') }}">
<i class="bi bi-people"></i> 用户管理
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('profile_page') }}">
<i class="bi bi-person"></i> 个人资料
</a>
</li>
</ul>
<div class="d-flex align-items-center text-white">
<span class="me-3">欢迎,<span id="current-username"></span></span>
<button class="btn btn-outline-light btn-sm" onclick="logout()">退出</button>
</div>
</div>
</div>
</nav>
{% endif %}
<!-- 主内容 -->
<div class="{% if show_nav %}container-fluid mt-4{% endif %}">
{% block content %}{% endblock %}
</div>
<!-- Bootstrap JS -->
<script src="{{ url_for('static', filename='js/jquery.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/bootstrap.bundle.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/common.js') }}"></script>
{% block extra_js %}{% endblock %}
</body>
</html>

38
templates/login.html Normal file
View File

@@ -0,0 +1,38 @@
{% extends "base.html" %}
{% block title %}登录 - PT管理系统{% endblock %}
{% block content %}
<div class="container">
<div class="row justify-content-center mt-5">
<div class="col-md-4">
<div class="card shadow">
<div class="card-body">
<h3 class="card-title text-center mb-4">PT管理系统</h3>
<form id="login-form">
<div class="mb-3">
<label for="username" class="form-label">用户名</label>
<input type="text" class="form-control" id="username" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">密码</label>
<input type="password" class="form-control" id="password" required>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary">登录</button>
</div>
</form>
<div id="error-msg" class="alert alert-danger mt-3" style="display:none;"></div>
<div class="text-center mt-3">
<a href="/register">没有账号?立即注册</a>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script src="{{ url_for('static', filename='js/login.js') }}"></script>
{% endblock %}

64
templates/profile.html Normal file
View File

@@ -0,0 +1,64 @@
{% extends "base.html" %}
{% set show_nav = true %}
{% block title %}个人资料{% endblock %}
{% block content %}
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<h2 class="mb-4">个人资料</h2>
<div class="card mb-3">
<div class="card-header">
<h5>基本信息</h5>
</div>
<div class="card-body">
<form id="profile-form">
<div class="mb-3">
<label class="form-label">用户名</label>
<input type="text" class="form-control" id="username" disabled>
</div>
<div class="mb-3">
<label class="form-label">邮箱</label>
<input type="email" class="form-control" id="email">
</div>
<div class="mb-3">
<label class="form-label">站点UID</label>
<input type="text" class="form-control" id="uid">
</div>
<button type="submit" class="btn btn-primary">保存</button>
</form>
</div>
</div>
<div class="card">
<div class="card-header">
<h5>修改密码</h5>
</div>
<div class="card-body">
<form id="password-form">
<div class="mb-3">
<label class="form-label">旧密码</label>
<input type="password" class="form-control" id="old-password" required>
</div>
<div class="mb-3">
<label class="form-label">新密码</label>
<input type="password" class="form-control" id="new-password" required>
</div>
<div class="mb-3">
<label class="form-label">确认新密码</label>
<input type="password" class="form-control" id="confirm-password" required>
</div>
<button type="submit" class="btn btn-warning">修改密码</button>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script src="{{ url_for('static', filename='js/profile.js') }}"></script>
{% endblock %}

52
templates/register.html Normal file
View File

@@ -0,0 +1,52 @@
<!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="{{ url_for('static', filename='css/bootstrap.min.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap-icons.css') }}">
</head>
<body class="bg-light">
<div class="container">
<div class="row justify-content-center mt-5">
<div class="col-md-6">
<div class="card shadow">
<div class="card-body p-5">
<h3 class="text-center mb-4">用户注册</h3>
<form id="register-form">
<div class="mb-3">
<label class="form-label">用户名 *</label>
<input type="text" class="form-control" id="username" required>
</div>
<div class="mb-3">
<label class="form-label">邮箱 *</label>
<input type="email" class="form-control" id="email" required>
</div>
<div class="mb-3">
<label class="form-label">站点UID</label>
<input type="text" class="form-control" id="uid">
</div>
<div class="mb-3">
<label class="form-label">密码 *</label>
<input type="password" class="form-control" id="password" required>
</div>
<div class="mb-3">
<label class="form-label">确认密码 *</label>
<input type="password" class="form-control" id="confirm-password" required>
</div>
<button type="submit" class="btn btn-primary w-100">注册</button>
</form>
<div class="text-center mt-3">
<a href="/">已有账号?立即登录</a>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="{{ url_for('static', filename='js/jquery.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/bootstrap.bundle.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/register.js') }}"></script>
</body>
</html>

153
templates/statistics.html Normal file
View File

@@ -0,0 +1,153 @@
{% extends "base.html" %}
{% set show_nav = true %}
{% block title %}统计报表{% endblock %}
{% block extra_css %}
<script src="{{ url_for('static', filename='js/chart.umd.min.js') }}"></script>
{% endblock %}
{% block content %}
<div class="container-fluid">
<h2 class="mb-4">统计报表</h2>
<!-- 筛选器 -->
<div class="card mb-3">
<div class="card-body">
<div class="row g-3 align-items-end">
<div class="col-md-2">
<label class="form-label">快捷选择</label>
<select class="form-select" id="quick-select" onchange="applyQuickSelect()">
<option value="">自定义</option>
<option value="today">今天</option>
<option value="week">本周</option>
<option value="month">本月</option>
<option value="30days">最近30天</option>
</select>
</div>
<div class="col-md-2">
<label class="form-label">开始日期</label>
<input type="date" class="form-control" id="date-from">
</div>
<div class="col-md-2">
<label class="form-label">结束日期</label>
<input type="date" class="form-control" id="date-to">
</div>
<div class="col-md-3">
<button class="btn btn-primary me-2" onclick="loadStatistics()">
<i class="bi bi-search"></i> 查询
</button>
<button class="btn btn-success" onclick="exportData()">
<i class="bi bi-download"></i> 导出CSV
</button>
</div>
</div>
</div>
</div>
<!-- 概览卡片 -->
<div class="row mb-4">
<div class="col-md-3">
<div class="card text-white bg-primary">
<div class="card-body">
<h5 class="card-title">今日完成</h5>
<h2 id="today-count">-</h2>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-success">
<div class="card-body">
<h5 class="card-title">本月完成</h5>
<h2 id="month-count">-</h2>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-warning">
<div class="card-body">
<h5 class="card-title">待认领</h5>
<h2 id="pending-count">-</h2>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-white bg-info">
<div class="card-body">
<h5 class="card-title">进行中</h5>
<h2 id="claimed-count">-</h2>
</div>
</div>
</div>
</div>
<!-- 个人统计 -->
<div class="row mb-4">
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h5 id="stats-title">我的完成统计</h5>
</div>
<div class="card-body">
<div class="mb-3">
<strong>总完成数:</strong><span id="my-total">-</span>
</div>
<div class="mb-3">
<strong>待完成数:</strong><span id="my-pending">-</span>
</div>
<div style="height: 250px;">
<canvas id="myChart"></canvas>
</div>
</div>
</div>
</div>
<!-- 排行榜 -->
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h5>本月排行榜</h5>
</div>
<div class="card-body">
<div style="max-height: 400px; overflow-y: auto;">
<table class="table table-sm">
<thead>
<tr>
<th>排名</th>
<th>用户</th>
<th>完成数</th>
</tr>
</thead>
<tbody id="leaderboard">
<tr>
<td colspan="3" class="text-center">加载中...</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- 趋势图 -->
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h5 id="trend-title">完成趋势</h5>
</div>
<div class="card-body">
<div style="height: 300px;">
<canvas id="trendChart"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script src="{{ url_for('static', filename='js/statistics.js') }}"></script>
{% endblock %}

View File

@@ -0,0 +1,91 @@
{% extends "base.html" %}
{% set show_nav = true %}
{% block title %}创建任务{% endblock %}
{% block content %}
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<h4>创建新任务</h4>
</div>
<div class="card-body">
<form id="create-task-form">
<div class="mb-3">
<label for="series-name" class="form-label">剧集名称 <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="series-name" required
placeholder="例如:某某剧集 S01E01">
</div>
<div class="mb-3">
<label for="series-link" class="form-label">剧集链接(可选)</label>
<input type="url" class="form-control" id="series-link"
placeholder="https://...">
<small class="form-text text-muted">资源来源链接</small>
</div>
<div class="mb-3">
<label for="series-date" class="form-label">剧集更新日期 <span class="text-danger">*</span></label>
<input type="date" class="form-control" id="series-date" required>
</div>
<div class="mb-3">
<label for="priority" class="form-label">优先级</label>
<select class="form-select" id="priority">
<option value="中" selected></option>
<option value="高"></option>
<option value="低"></option>
</select>
</div>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<a href="/tasks" class="btn btn-secondary">取消</a>
<button type="submit" class="btn btn-primary">创建任务</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script>
$(document).ready(function() {
// 设置默认日期为今天
$('#series-date').val(new Date().toISOString().split('T')[0]);
$('#create-task-form').submit(function(e) {
e.preventDefault();
const data = {
series_name: $('#series-name').val(),
series_link: $('#series-link').val() || null,
series_date: $('#series-date').val(),
priority: $('#priority').val()
};
$.ajax({
url: '/api/groups/1/tasks',
method: 'POST',
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('access_token'),
'Content-Type': 'application/json'
},
data: JSON.stringify(data),
success: function(response) {
alert('任务创建成功!');
window.location.href = '/tasks';
},
error: function(xhr) {
const error = xhr.responseJSON?.error || '创建失败';
alert(error);
}
});
});
});
</script>
{% endblock %}

157
templates/task_list.html Normal file
View File

@@ -0,0 +1,157 @@
{% extends "base.html" %}
{% set show_nav = true %}
{% block title %}任务列表{% endblock %}
{% block content %}
<div class="container-fluid">
<div class="row mb-3">
<div class="col">
<h2>发布组任务列表</h2>
</div>
<div class="col text-end admin-only" style="display:none;">
<a href="/tasks/create" class="btn btn-primary">
<i class="bi bi-plus-circle"></i> 创建任务
</a>
</div>
</div>
<!-- 筛选器 -->
<div class="card mb-3">
<div class="card-body">
<div class="row g-3">
<div class="col-md-3">
<label class="form-label">状态</label>
<select id="filter-status" class="form-select">
<option value="">全部</option>
<option value="pending">待认领</option>
<option value="claimed">已认领</option>
<option value="completed">已完成</option>
</select>
</div>
<div class="col-md-3">
<label class="form-label">查看范围</label>
<select id="filter-scope" class="form-select">
<option value="all">全部任务</option>
<option value="my">我的任务</option>
</select>
</div>
<div class="col-md-3 d-flex align-items-end">
<button class="btn btn-primary" onclick="loadTasks()">
<i class="bi bi-search"></i> 查询
</button>
<button class="btn btn-secondary ms-2" onclick="resetFilters()">
<i class="bi bi-arrow-clockwise"></i> 重置
</button>
</div>
</div>
</div>
</div>
<!-- 任务表格 -->
<div class="card">
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>ID</th>
<th>剧集名称</th>
<th>更新日期</th>
<th>优先级</th>
<th>状态</th>
<th>认领人</th>
<th>种子ID</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="task-list">
<tr>
<td colspan="9" class="text-center">加载中...</td>
</tr>
</tbody>
</table>
</div>
<!-- 分页 -->
<nav>
<ul class="pagination justify-content-center" id="pagination">
</ul>
</nav>
</div>
</div>
</div>
<!-- 认领任务模态框 -->
<div class="modal fade" id="claimModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">认领任务</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="claim-form">
<input type="hidden" id="claim-task-id">
<div class="mb-3">
<label class="form-label">认领备注(可选)</label>
<textarea class="form-control" id="claim-note" rows="3"></textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary" onclick="submitClaim()">确认认领</button>
</div>
</div>
</div>
</div>
<!-- 完成任务模态框 -->
<div class="modal fade" id="completeModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">完成任务</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="complete-form">
<input type="hidden" id="complete-task-id">
<div class="mb-3">
<label class="form-label">种子ID <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="torrent-id" required placeholder="例如12345">
</div>
<div class="mb-3">
<label class="form-label">完成备注(可选)</label>
<textarea class="form-control" id="complete-note" rows="3"></textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-success" onclick="submitComplete()">确认完成</button>
</div>
</div>
</div>
</div>
<!-- 任务详情模态框 -->
<div class="modal fade" id="detailModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">任务详情</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body" id="task-detail">
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script src="{{ url_for('static', filename='js/task_list.js') }}"></script>
{% endblock %}

98
templates/users.html Normal file
View File

@@ -0,0 +1,98 @@
{% extends "base.html" %}
{% set show_nav = true %}
{% block title %}用户管理{% endblock %}
{% block content %}
<div class="container-fluid">
<h2 class="mb-4">用户管理</h2>
<ul class="nav nav-tabs mb-3">
<li class="nav-item">
<a class="nav-link active" data-status="" href="#">全部</a>
</li>
<li class="nav-item">
<a class="nav-link" data-status="pending" href="#">待审核</a>
</li>
<li class="nav-item">
<a class="nav-link" data-status="active" href="#">已激活</a>
</li>
<li class="nav-item">
<a class="nav-link" data-status="disabled" href="#">已禁用</a>
</li>
</ul>
<div class="card">
<div class="card-body">
<table class="table">
<thead>
<tr>
<th>用户名</th>
<th>邮箱</th>
<th>UID</th>
<th>角色</th>
<th>状态</th>
<th>标签</th>
<th>注册时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="users-table"></tbody>
</table>
</div>
</div>
</div>
<!-- 编辑用户模态框 -->
<div class="modal fade" id="editModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">编辑用户</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<input type="hidden" id="edit-user-id">
<div class="mb-3">
<label class="form-label">邮箱</label>
<input type="email" class="form-control" id="edit-email">
</div>
<div class="mb-3">
<label class="form-label">UID</label>
<input type="text" class="form-control" id="edit-uid">
</div>
<div class="mb-3">
<label class="form-label">角色</label>
<select class="form-select" id="edit-role">
<option value="user">普通用户</option>
<option value="admin">管理员</option>
</select>
</div>
<div class="mb-3">
<label class="form-label">状态</label>
<select class="form-select" id="edit-status">
<option value="active">已激活</option>
<option value="disabled">已禁用</option>
</select>
</div>
<div class="mb-3">
<label class="form-label">标签</label>
<input type="text" class="form-control" id="edit-tags" placeholder="多个标签用逗号分隔">
</div>
<div class="mb-3">
<label class="form-label">备注</label>
<textarea class="form-control" id="edit-note" rows="3"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary" onclick="saveUser()">保存</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script src="{{ url_for('static', filename='js/users.js') }}"></script>
{% endblock %}