| {% extends 'base.html' %} |
|
|
| {% block content %} |
| <section class="page-grid admin-page-grid users-admin-grid"> |
| <article class="glass-card form-panel"> |
| <div class="section-head"> |
| <div> |
| <p class="eyebrow">Create User</p> |
| <h3>手动录入用户</h3> |
| </div> |
| </div> |
| <form method="post" action="/admin/users" class="form-stack"> |
| <div class="form-grid cols-2"> |
| <label> |
| <span>学号</span> |
| <input type="text" name="student_id" required /> |
| </label> |
| <label> |
| <span>姓名</span> |
| <input type="text" name="full_name" required /> |
| </label> |
| <label> |
| <span>登录密码</span> |
| <input type="text" name="password" required /> |
| </label> |
| <label> |
| <span>所属小组</span> |
| <select name="group_id"> |
| <option value="">暂不分组</option> |
| {% for group in groups %} |
| <option value="{{ group.id }}">{{ group.name }}({{ group.members|length }}/{{ group.max_members }})</option> |
| {% endfor %} |
| </select> |
| </label> |
| </div> |
| <button class="btn btn-primary" type="submit">保存用户</button> |
| </form> |
| </article> |
|
|
| <article class="glass-card form-panel"> |
| <div class="section-head"> |
| <div> |
| <p class="eyebrow">Batch Import</p> |
| <h3>批量导入用户</h3> |
| </div> |
| </div> |
| <form method="post" action="/admin/users/import" class="form-stack"> |
| <label> |
| <span>每行一人,格式:姓名 学号</span> |
| <textarea name="import_text" rows="8" placeholder="张三 20230001 李四 20230002"></textarea> |
| </label> |
| <label> |
| <span>导入后分配到小组</span> |
| <select name="group_id"> |
| <option value="">暂不分组</option> |
| {% for group in groups %} |
| <option value="{{ group.id }}">{{ group.name }}({{ group.members|length }}/{{ group.max_members }})</option> |
| {% endfor %} |
| </select> |
| </label> |
| <p class="mini-note">默认密码为学号后六位,不足六位则使用完整学号。</p> |
| <button class="btn btn-secondary" type="submit">开始导入</button> |
| </form> |
| </article> |
| </section> |
|
|
| <section class="glass-card table-panel"> |
| <div class="section-head"> |
| <div> |
| <p class="eyebrow">Users</p> |
| <h3>用户列表与批量操作</h3> |
| </div> |
| </div> |
|
|
| <form id="bulk-users-form" method="post" action="/admin/users/bulk" class="bulk-toolbar"> |
| <label> |
| <span>批量操作</span> |
| <select name="bulk_action" required> |
| <option value="assign_group">批量分组</option> |
| <option value="delete">批量删除</option> |
| </select> |
| </label> |
| <label> |
| <span>目标小组</span> |
| <select name="group_id"> |
| <option value="">未分组</option> |
| {% for group in groups %} |
| <option value="{{ group.id }}">{{ group.name }}</option> |
| {% endfor %} |
| </select> |
| </label> |
| <button class="btn btn-primary" type="submit">执行批量操作</button> |
| </form> |
|
|
| <div class="table-shell"> |
| <table class="data-table"> |
| <thead> |
| <tr> |
| <th> |
| <input class="table-checkbox" type="checkbox" data-check-all /> |
| </th> |
| <th>学号</th> |
| <th>姓名</th> |
| <th>当前小组</th> |
| <th>调整小组</th> |
| </tr> |
| </thead> |
| <tbody> |
| {% for user_item in users %} |
| <tr> |
| <td> |
| <input class="table-checkbox" type="checkbox" name="user_ids" value="{{ user_item.id }}" data-user-check form="bulk-users-form" /> |
| </td> |
| <td>{{ user_item.student_id }}</td> |
| <td>{{ user_item.full_name }}</td> |
| <td>{{ user_item.group.name if user_item.group else '未分组' }}</td> |
| <td> |
| <form method="post" action="/admin/users/{{ user_item.id }}/group" class="inline-form table-inline-form"> |
| <select name="group_id"> |
| <option value="">未分组</option> |
| {% for group in groups %} |
| <option value="{{ group.id }}" {% if user_item.group_id == group.id %}selected{% endif %}>{{ group.name }}</option> |
| {% endfor %} |
| </select> |
| <button class="btn btn-secondary small-btn" type="submit">保存</button> |
| </form> |
| </td> |
| </tr> |
| {% else %} |
| <tr> |
| <td colspan="5">还没有用户,请先录入。</td> |
| </tr> |
| {% endfor %} |
| </tbody> |
| </table> |
| </div> |
| </section> |
|
|
| <script> |
| (() => { |
| const checkAll = document.querySelector('[data-check-all]'); |
| const checks = Array.from(document.querySelectorAll('[data-user-check]')); |
| if (!checkAll || checks.length === 0) return; |
| checkAll.addEventListener('change', () => { |
| checks.forEach((checkbox) => { |
| checkbox.checked = checkAll.checked; |
| }); |
| }); |
| })(); |
| </script> |
| {% endblock %}
|
|
|