| {% extends "admin_layout.html" %} |
| {% block admin_title %}后台总览{% endblock %} |
| {% block admin_page_content %} |
| <section class="metric-grid reveal-up delay-2"> |
| <article class="metric-card"> |
| <span>用户数</span> |
| <strong id="stat-users">{{ stats.users_count }}</strong> |
| <small>已录入的学生账号</small> |
| </article> |
| <article class="metric-card"> |
| <span>运行中任务</span> |
| <strong id="stat-running">{{ stats.running_count }}</strong> |
| <small>排队中:<span id="stat-pending">{{ stats.pending_count }}</span></small> |
| </article> |
| <article class="metric-card"> |
| <span>总课程目标</span> |
| <strong>{{ stats.courses_count }}</strong> |
| <small>管理员可见全部课程号与课序号</small> |
| </article> |
| <article class="metric-card"> |
| <span>有效定时任务</span> |
| <strong>{{ stats.active_schedule_count }}</strong> |
| <small>管理员配置的每日自动启动与停止</small> |
| </article> |
| <article class="metric-card"> |
| <span>注册码总数</span> |
| <strong>{{ stats.registration_code_count }}</strong> |
| <small>支持用户按注册码自助注册</small> |
| </article> |
| </section> |
|
|
| <section class="content-grid admin-grid"> |
| <article class="card reveal-up delay-2"> |
| <div class="card-head"> |
| <span class="kicker">分页面管理</span> |
| <h2>功能入口</h2> |
| <p>不同功能已经拆分到独立页面,避免全部堆在首页。</p> |
| </div> |
| <div class="button-row wrap-row"> |
| <a href="{{ url_for('admin_users') }}" class="btn btn-primary">进入用户管理</a> |
| <a href="{{ url_for('admin_schedules') }}" class="btn btn-secondary">进入定时任务</a> |
| <a href="{{ url_for('admin_registration_codes') }}" class="btn btn-secondary">进入注册码</a> |
| <a href="{{ url_for('admin_logs') }}" class="btn btn-ghost">查看运行日志</a> |
| </div> |
| </article> |
|
|
| <article class="card reveal-up delay-2"> |
| <div class="card-head"> |
| <span class="kicker">调度设置</span> |
| <h2>并行数</h2> |
| <p>默认并行数已调整为 4,建议根据 Hugging Face Space 的资源情况适当调节。</p> |
| </div> |
| <form method="post" action="{{ url_for('update_parallel_limit') }}" class="form-grid form-grid-compact"> |
| <label class="field"> |
| <span>当前并行数</span> |
| <input type="number" id="parallel-limit-input" name="parallel_limit" min="1" max="8" value="{{ parallel_limit }}" required> |
| </label> |
| <button type="submit" class="btn btn-primary">更新并行数</button> |
| </form> |
| </article> |
|
|
| {% if is_super_admin %} |
| <article class="card reveal-up delay-2"> |
| <div class="card-head"> |
| <span class="kicker">管理员管理</span> |
| <h2>新增管理员</h2> |
| <p>只有超级管理员可以继续创建普通管理员。</p> |
| </div> |
| <form method="post" action="{{ url_for('create_admin') }}" class="form-grid form-grid-compact"> |
| <label class="field"> |
| <span>管理员账号</span> |
| <input type="text" name="username" placeholder="输入管理员账号" required> |
| </label> |
| <label class="field"> |
| <span>管理员密码</span> |
| <input type="password" name="password" placeholder="输入管理员密码" required> |
| </label> |
| <button type="submit" class="btn btn-ghost">创建管理员</button> |
| </form> |
| <div class="chip-row"> |
| <span class="chip highlight">超级管理员:{{ admin_identity.username }}</span> |
| {% for admin in admins %} |
| <span class="chip">{{ admin.username }}</span> |
| {% endfor %} |
| </div> |
| </article> |
| {% endif %} |
|
|
| <article class="card reveal-up delay-3 span-2"> |
| <div class="card-head split"> |
| <div> |
| <span class="kicker">任务总览</span> |
| <h2>最近任务</h2> |
| <p>用于快速确认任务是否正在排队、执行、停止或失败。</p> |
| </div> |
| <span class="status-pill status-running">实时刷新</span> |
| </div> |
| <div class="course-table-wrap"> |
| <table class="data-table"> |
| <thead> |
| <tr> |
| <th>任务</th> |
| <th>学号</th> |
| <th>状态</th> |
| <th>尝试</th> |
| <th>错误</th> |
| <th>刷新间隔</th> |
| <th>触发者</th> |
| <th>更新时间</th> |
| </tr> |
| </thead> |
| <tbody> |
| {% if recent_tasks %} |
| {% for task in recent_tasks %} |
| <tr> |
| <td>#{{ task.id }}</td> |
| <td>{{ task.student_id }}</td> |
| <td><span class="status-pill status-{{ task.status }}">{{ task_labels.get(task.status, task.status) }}</span></td> |
| <td>{{ task.total_attempts }}</td> |
| <td>{{ task.total_errors }}</td> |
| <td>{{ task.refresh_interval_seconds or default_refresh_interval_seconds }} 秒</td> |
| <td>{{ task.requested_by_role }}:{{ task.requested_by }}</td> |
| <td>{{ task.updated_at }}</td> |
| </tr> |
| {% endfor %} |
| {% else %} |
| <tr> |
| <td colspan="8" class="empty-cell">还没有任务记录。</td> |
| </tr> |
| {% endif %} |
| </tbody> |
| </table> |
| </div> |
| </article> |
| </section> |
| {% endblock %}
|
|
|