Spaces:
Paused
Paused
| {% extends "base.html" %} | |
| {% block title %}用户控制台 | SCU 选课控制台{% endblock %} | |
| {% block content %} | |
| <section class="dashboard-shell" data-log-stream-url="{{ url_for('stream_user_logs', last_id=recent_logs[-1].id if recent_logs else 0) }}" data-status-url="{{ url_for('user_status') }}"> | |
| <header class="topbar reveal-up"> | |
| <div> | |
| <span class="eyebrow">User Console</span> | |
| <h1>{{ current_user.display_name or current_user.student_id }} 的选课面板</h1> | |
| <p>登录账号:{{ current_user.student_id }},你的课程目标与运行日志会实时同步到这里。</p> | |
| </div> | |
| <form method="post" action="{{ url_for('logout') }}"> | |
| <button type="submit" class="btn btn-ghost">退出登录</button> | |
| </form> | |
| </header> | |
| <section class="metric-grid reveal-up delay-1"> | |
| <article class="metric-card"> | |
| <span>当前任务</span> | |
| <strong id="task-status-text">{{ task_labels.get(task.status, '未启动') if task else '未启动' }}</strong> | |
| <small>最近更新时间:{{ task.updated_at if task else '暂无' }}</small> | |
| </article> | |
| <article class="metric-card"> | |
| <span>待选课程</span> | |
| <strong id="course-count">{{ courses|length }}</strong> | |
| <small>管理员可看到全部课程内容</small> | |
| </article> | |
| <article class="metric-card"> | |
| <span>最近任务编号</span> | |
| <strong>{{ task.id if task else '--' }}</strong> | |
| <small>{{ task.last_error if task and task.last_error else '当前没有错误提示' }}</small> | |
| </article> | |
| </section> | |
| <section class="content-grid dashboard-grid"> | |
| <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('update_profile') }}" class="form-grid"> | |
| <label class="field"> | |
| <span>显示名称</span> | |
| <input type="text" name="display_name" value="{{ current_user.display_name }}" placeholder="可选昵称"> | |
| </label> | |
| <label class="field"> | |
| <span>教务密码</span> | |
| <input type="password" name="password" value="" placeholder="重新输入当前有效密码" required> | |
| </label> | |
| <button type="submit" class="btn btn-primary">保存账号信息</button> | |
| </form> | |
| </article> | |
| <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('add_course') }}" class="form-grid form-grid-compact"> | |
| <label class="field"> | |
| <span>选课类型</span> | |
| <select name="category"> | |
| <option value="free">自由选课</option> | |
| <option value="plan">方案选课</option> | |
| </select> | |
| </label> | |
| <label class="field"> | |
| <span>课程号</span> | |
| <input type="text" name="course_id" inputmode="numeric" placeholder="课程号" required> | |
| </label> | |
| <label class="field"> | |
| <span>课序号</span> | |
| <input type="text" name="course_index" inputmode="numeric" placeholder="例如 01" maxlength="2" required> | |
| </label> | |
| <button type="submit" class="btn btn-secondary">加入抢课队列</button> | |
| </form> | |
| </article> | |
| <article class="card reveal-up delay-3 span-2"> | |
| <div class="card-head split"> | |
| <div> | |
| <span class="kicker">执行控制</span> | |
| <h2>启动与停止任务</h2> | |
| <p>后台会按照管理员设置的并行数进行排队和执行。</p> | |
| </div> | |
| <div class="button-row"> | |
| <form method="post" action="{{ url_for('start_task') }}"> | |
| <button type="submit" class="btn btn-primary">启动任务</button> | |
| </form> | |
| <form method="post" action="{{ url_for('stop_task') }}"> | |
| <button type="submit" class="btn btn-ghost danger">停止任务</button> | |
| </form> | |
| </div> | |
| </div> | |
| <div class="status-strip"> | |
| <span class="status-pill status-{{ task.status if task else 'idle' }}" id="task-status-pill">{{ task_labels.get(task.status, '未启动') if task else '未启动' }}</span> | |
| <span>创建时间:{{ task.created_at if task else '暂无任务' }}</span> | |
| <span>触发者:{{ task.requested_by if task else '暂无' }}</span> | |
| </div> | |
| <div class="course-table-wrap"> | |
| <table class="data-table"> | |
| <thead> | |
| <tr> | |
| <th>类型</th> | |
| <th>课程号</th> | |
| <th>课序号</th> | |
| <th>操作</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| {% if courses %} | |
| {% for course in courses %} | |
| <tr> | |
| <td>{{ category_labels.get(course.category, course.category) }}</td> | |
| <td>{{ course.course_id }}</td> | |
| <td>{{ course.course_index }}</td> | |
| <td> | |
| <form method="post" action="{{ url_for('delete_course', course_target_id=course.id) }}"> | |
| <button type="submit" class="inline-action">移除</button> | |
| </form> | |
| </td> | |
| </tr> | |
| {% endfor %} | |
| {% else %} | |
| <tr> | |
| <td colspan="4" class="empty-cell">还没有课程目标,先添加课程号和课序号吧。</td> | |
| </tr> | |
| {% endif %} | |
| </tbody> | |
| </table> | |
| </div> | |
| </article> | |
| <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="live-dot">LIVE</span> | |
| </div> | |
| <div class="log-console" id="log-console"> | |
| {% if recent_logs %} | |
| {% for log in recent_logs %} | |
| <div class="log-line level-{{ log.level|lower }}"> | |
| <span class="log-meta">{{ log.created_at }} · {{ log.scope }} · {{ log.level }}</span> | |
| <span>{{ log.message }}</span> | |
| </div> | |
| {% endfor %} | |
| {% else %} | |
| <div class="log-line level-info muted">暂无日志,启动任务后这里会自动刷新。</div> | |
| {% endif %} | |
| </div> | |
| </article> | |
| </section> | |
| </section> | |
| {% endblock %} | |