first commit

This commit is contained in:
2026-02-27 10:37:11 +08:00
commit 74f19aad0b
86 changed files with 18642 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
<!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 %}{% endblock %}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
.sidebar { min-height: calc(100vh - 56px); }
.nav-link.active { background-color: #0d6efd; color: #fff !important; border-radius: 6px; }
</style>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="{{ url_for('dashboard') }}">🛡️ 管理后台</a>
</div>
</nav>
<div class="container-fluid">
<div class="row">
<nav class="col-md-2 bg-light sidebar py-3">
<div class="nav flex-column nav-pills">
<a class="nav-link text-dark mb-1" href="{{ url_for('dashboard') }}">📊 仪表盘</a>
<a class="nav-link text-dark mb-1" href="{{ url_for('competitions') }}">🏆 杯赛管理</a>
<a class="nav-link text-dark mb-1" href="{{ url_for('competition_apps') }}">📋 杯赛申请</a>
<a class="nav-link text-dark mb-1" href="{{ url_for('teacher_apps') }}">👨‍🏫 教师申请</a>
<a class="nav-link text-dark mb-1" href="{{ url_for('exams') }}">📝 考试管理</a>
<a class="nav-link text-dark mb-1" href="{{ url_for('users') }}">👥 用户管理</a>
<a class="nav-link text-dark mb-1" href="{{ url_for('posts') }}">💬 帖子管理</a>
<a class="nav-link text-dark mb-1" href="{{ url_for('notifications') }}">📢 公告管理</a>
</div>
</nav>
<main class="col-md-10 py-4">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ 'danger' if category == 'error' else 'success' }} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endfor %}
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</main>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

View File

@@ -0,0 +1,50 @@
{% extends "base.html" %}
{% block title %}杯赛申请{% endblock %}
{% block content %}
<h1>杯赛申请</h1>
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>比赛名称</th>
<th>申请人</th>
<th>描述</th>
<th>状态</th>
<th>申请时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for app in apps %}
<tr>
<td>{{ app.id }}</td>
<td>{{ app.name }}</td>
<td>{{ app.applicant_name }}</td>
<td>{{ app.description }}</td>
<td>
{% if app.status == 'pending' %}
<span class="badge bg-warning">待处理</span>
{% elif app.status == 'approved' %}
<span class="badge bg-success">已批准</span>
{% else %}
<span class="badge bg-danger">已驳回</span>
{% endif %}
</td>
<td>{{ app.created_at }}</td>
<td>
{% if app.status == 'pending' %}
<form action="{{ url_for('approve_competition_app', id=app.id) }}" method="post" style="display:inline;">
<button type="submit" class="btn btn-success btn-sm">批准</button>
</form>
<form action="{{ url_for('reject_competition_app', id=app.id) }}" method="post" style="display:inline;">
<button type="submit" class="btn btn-danger btn-sm">驳回</button>
</form>
{% else %}
<span class="text-muted">已处理</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@@ -0,0 +1,43 @@
{% extends "base.html" %}
{% block title %}杯赛管理{% endblock %}
{% block content %}
<h1>杯赛管理</h1>
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>名称</th>
<th>描述</th>
<th>状态</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for comp in competitions %}
<tr>
<td>{{ comp.id }}</td>
<td>{{ comp.name }}</td>
<td>{{ comp.description }}</td>
<td>
{% if comp.status == 'active' %}
<span class="badge bg-success">进行中</span>
{% else %}
<span class="badge bg-secondary">已停止</span>
{% endif %}
</td>
<td>{{ comp.created_at }}</td>
<td>
{% if comp.status == 'active' %}
<form action="{{ url_for('stop_competition', id=comp.id) }}" method="post" style="display:inline;">
<button type="submit" class="btn btn-warning btn-sm" onclick="return confirm('确定停止该比赛吗?')">停止</button>
</form>
{% else %}
<span class="text-muted">无操作</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@@ -0,0 +1,61 @@
{% extends "base.html" %}
{% block title %}仪表盘{% endblock %}
{% block content %}
<h2 class="mb-4">仪表盘</h2>
<div class="row g-4">
<div class="col-md-4">
<div class="card border-primary h-100">
<div class="card-body text-center">
<h1 class="display-4 text-primary">{{ stats.users }}</h1>
<p class="text-muted mb-2">注册用户</p>
<a href="{{ url_for('users') }}" class="btn btn-outline-primary btn-sm">管理用户</a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card border-success h-100">
<div class="card-body text-center">
<h1 class="display-4 text-success">{{ stats.contests }}</h1>
<p class="text-muted mb-2">杯赛总数</p>
<a href="{{ url_for('competitions') }}" class="btn btn-outline-success btn-sm">管理杯赛</a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card border-info h-100">
<div class="card-body text-center">
<h1 class="display-4 text-info">{{ stats.exams }}</h1>
<p class="text-muted mb-2">考试总数</p>
<a href="{{ url_for('exams') }}" class="btn btn-outline-info btn-sm">管理考试</a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card border-warning h-100">
<div class="card-body text-center">
<h1 class="display-4 text-warning">{{ stats.pending_teacher }}</h1>
<p class="text-muted mb-2">待审教师申请</p>
<a href="{{ url_for('teacher_apps') }}" class="btn btn-outline-warning btn-sm">处理申请</a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card border-danger h-100">
<div class="card-body text-center">
<h1 class="display-4 text-danger">{{ stats.pending_contest }}</h1>
<p class="text-muted mb-2">待审杯赛申请</p>
<a href="{{ url_for('competition_apps') }}" class="btn btn-outline-danger btn-sm">处理申请</a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card border-secondary h-100">
<div class="card-body text-center">
<h1 class="display-4 text-secondary">{{ stats.posts }}</h1>
<p class="text-muted mb-2">论坛帖子</p>
<a href="{{ url_for('posts') }}" class="btn btn-outline-secondary btn-sm">管理帖子</a>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,45 @@
{% extends "base.html" %}
{% block title %}考试管理{% endblock %}
{% block content %}
<h1>考试管理</h1>
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>名称</th>
<th>科目</th>
<th>考试日期</th>
<th>状态</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for exam in exams %}
<tr>
<td>{{ exam.id }}</td>
<td>{{ exam.name }}</td>
<td>{{ exam.subject }}</td>
<td>{{ exam.exam_date }}</td>
<td>
{% if exam.status == 'active' %}
<span class="badge bg-success">进行中</span>
{% else %}
<span class="badge bg-secondary">已停止</span>
{% endif %}
</td>
<td>{{ exam.created_at }}</td>
<td>
{% if exam.status == 'active' %}
<form action="{{ url_for('stop_exam', id=exam.id) }}" method="post" style="display:inline;">
<button type="submit" class="btn btn-warning btn-sm" onclick="return confirm('确定停止该考试吗?')">停止</button>
</form>
{% else %}
<span class="text-muted">无操作</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@@ -0,0 +1,45 @@
{% extends "base.html" %}
{% block title %}帖子管理{% endblock %}
{% block content %}
<h1>帖子管理</h1>
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>标题</th>
<th>内容</th>
<th>作者</th>
<th>封禁状态</th>
<th>发布时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for post in posts %}
<tr>
<td>{{ post.id }}</td>
<td>{{ post.title }}</td>
<td>{{ post.content[:50] }}{% if post.content|length > 50 %}...{% endif %}</td>
<td>{{ post.username }}</td>
<td>
{% if post.banned == 0 %}
<span class="badge bg-success">正常</span>
{% else %}
<span class="badge bg-danger">已封禁</span>
{% endif %}
</td>
<td>{{ post.created_at }}</td>
<td>
<form action="{{ url_for('toggle_ban_post', id=post.id) }}" method="post" style="display:inline;">
{% if post.banned == 0 %}
<button type="submit" class="btn btn-warning btn-sm" onclick="return confirm('确定封禁该帖子?')">封禁</button>
{% else %}
<button type="submit" class="btn btn-success btn-sm" onclick="return confirm('确定解封该帖子?')">解封</button>
{% endif %}
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@@ -0,0 +1,48 @@
{% extends "base.html" %}
{% block title %}教师申请{% endblock %}
{% block content %}
<h1>教师申请</h1>
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>申请人</th>
<th>理由</th>
<th>状态</th>
<th>申请时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for app in apps %}
<tr>
<td>{{ app.id }}</td>
<td>{{ app.username }}</td>
<td>{{ app.reason }}</td>
<td>
{% if app.status == 'pending' %}
<span class="badge bg-warning">待处理</span>
{% elif app.status == 'approved' %}
<span class="badge bg-success">已批准</span>
{% else %}
<span class="badge bg-danger">已驳回</span>
{% endif %}
</td>
<td>{{ app.created_at }}</td>
<td>
{% if app.status == 'pending' %}
<form action="{{ url_for('approve_teacher_app', id=app.id) }}" method="post" style="display:inline;">
<button type="submit" class="btn btn-success btn-sm">批准</button>
</form>
<form action="{{ url_for('reject_teacher_app', id=app.id) }}" method="post" style="display:inline;">
<button type="submit" class="btn btn-danger btn-sm">驳回</button>
</form>
{% else %}
<span class="text-muted">已处理</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@@ -0,0 +1,45 @@
{% extends "base.html" %}
{% block title %}用户管理{% endblock %}
{% block content %}
<h1>用户管理</h1>
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>用户名</th>
<th>邮箱</th>
<th>角色</th>
<th>封禁状态</th>
<th>注册时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td>{{ user.id }}</td>
<td>{{ user.username }}</td>
<td>{{ user.email }}</td>
<td>{{ user.role }}</td>
<td>
{% if user.banned == 0 %}
<span class="badge bg-success">正常</span>
{% else %}
<span class="badge bg-danger">已封禁</span>
{% endif %}
</td>
<td>{{ user.created_at }}</td>
<td>
<form action="{{ url_for('toggle_ban_user', id=user.id) }}" method="post" style="display:inline;">
{% if user.banned == 0 %}
<button type="submit" class="btn btn-warning btn-sm" onclick="return confirm('确定封禁该用户?')">封禁</button>
{% else %}
<button type="submit" class="btn btn-success btn-sm" onclick="return confirm('确定解封该用户?')">解封</button>
{% endif %}
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}