| {% extends "base.html" %} |
| {% block title %}DRM | 后台管理{% endblock %} |
| {% block head %} |
| <link rel="stylesheet" href="{{ url_for('static', filename='v020.css') }}"> |
| {% endblock %} |
| {% block body %} |
| <main class="admin-layout admin-layout-v2" data-admin-page="{{ admin_page }}"> |
| <section class="admin-hero card-surface"> |
| <div> |
| <p class="section-kicker">后台管理</p> |
| {% if admin_page == "schedule" %} |
| <h1>时间表设置</h1> |
| <p class="admin-copy">通过拖拽上课块和课间块,重新安排整套节次时间。保存后首页与周课表会自动同步。</p> |
| {% elif admin_page == "lists" %} |
| <h1>清单管理</h1> |
| <p class="admin-copy">统一维护首页的 todolist 分类,删除或新建会即时反映到主页与拖拽池。</p> |
| {% else %} |
| <h1>课程管理</h1> |
| <p class="admin-copy">左侧新增或编辑课程,右侧用竖直列表快速检查全周课程配置。</p> |
| {% endif %} |
| </div> |
|
|
| <div class="action-group"> |
| <a class="ghost-link" href="{{ url_for('index') }}">返回主页</a> |
| </div> |
|
|
| <nav class="admin-page-nav" aria-label="后台分页"> |
| <a class="admin-page-tab {% if admin_page == 'schedule' %}is-active{% endif %}" href="{{ url_for('admin_schedule') }}">时间表设置</a> |
| <a class="admin-page-tab {% if admin_page == 'lists' %}is-active{% endif %}" href="{{ url_for('admin_lists') }}">清单管理</a> |
| <a class="admin-page-tab {% if admin_page == 'courses' %}is-active{% endif %}" href="{{ url_for('admin_courses') }}">课程管理</a> |
| </nav> |
| </section> |
|
|
| {% if admin_page == "schedule" %} |
| <section class="admin-section"> |
| <div class="admin-grid admin-grid-tight admin-schedule-grid"> |
| <article class="admin-card schedule-form-card"> |
| <div class="admin-card-head"> |
| <div> |
| <p class="column-label">Basic Settings</p> |
| <h2>基础参数</h2> |
| </div> |
| </div> |
|
|
| <form id="scheduleSettingsForm" class="modal-form compact"> |
| <label> |
| <span>学期开始日期</span> |
| <input id="semesterStartInput" name="semester_start" type="date" value="{{ schedule_settings.semester_start }}"> |
| </label> |
| <label> |
| <span>课表显示开始</span> |
| <input id="dayStartInput" name="day_start" type="time" value="{{ schedule_settings.day_start }}"> |
| </label> |
| <label> |
| <span>课表显示结束</span> |
| <input id="dayEndInput" name="day_end" type="time" value="{{ schedule_settings.day_end }}"> |
| </label> |
| <label> |
| <span>默认任务时长(分钟)</span> |
| <input id="defaultDurationInput" name="default_task_duration_minutes" type="number" min="30" max="240" step="15" value="{{ schedule_settings.default_task_duration_minutes }}"> |
| </label> |
| <div class="form-actions"> |
| <button class="secondary-button" id="resetTimelineButton" type="button">恢复默认节次</button> |
| <button class="primary-button" type="submit">保存时间表设置</button> |
| </div> |
| </form> |
| </article> |
|
|
| <article class="admin-card schedule-editor-card"> |
| <div class="admin-card-head"> |
| <div> |
| <p class="column-label">Timeline Editor</p> |
| <h2>拖拽块到时间轴上重新排布节次</h2> |
| </div> |
| <span class="task-count" id="scheduleSegmentCount">0 段</span> |
| </div> |
|
|
| <div class="schedule-palette" id="schedulePalette"> |
| <div class="schedule-palette-card class" draggable="true" data-palette-kind="class"> |
| <strong>上课块</strong> |
| <span>拖到时间轴末尾追加一节课</span> |
| </div> |
| <div class="schedule-palette-card break" draggable="true" data-palette-kind="break"> |
| <strong>课间块</strong> |
| <span>拖到时间轴末尾追加一段休息</span> |
| </div> |
| </div> |
|
|
| <p class="admin-card-copy">规则:时间段不能重叠,上课后必须是课间,课间后必须是上课。支持拖入新块、删除节次、调整时长。</p> |
|
|
| <div class="schedule-editor-shell"> |
| <div class="schedule-editor-axis" id="scheduleEditorAxis"></div> |
| <div class="schedule-editor-track" id="scheduleEditorTrack"> |
| <div class="schedule-editor-dropzone" id="scheduleEditorDropzone">将上课块或课间块拖到这里,追加到时间表末尾</div> |
| </div> |
| </div> |
| </article> |
| </div> |
| </section> |
| {% elif admin_page == "lists" %} |
| <section class="admin-section"> |
| <div class="admin-grid admin-grid-tight admin-lists-grid"> |
| <article class="admin-card create-card list-create-card"> |
| <div class="create-icon">+</div> |
| <h2>新建一个清单</h2> |
| <p class="admin-card-copy">清单会直接同步到首页与第二页的拖拽池。</p> |
| <form id="createCategoryForm" class="modal-form compact"> |
| <label> |
| <span>分类名称</span> |
| <input id="newCategoryName" name="name" type="text" maxlength="20" placeholder="例如:项目推进"> |
| </label> |
| <button class="primary-button" type="submit">立即创建</button> |
| </form> |
| </article> |
|
|
| <section class="admin-stack list-management-stack" id="adminGrid"> |
| {% for category in categories %} |
| <article class="admin-card admin-row-card list-row-card" data-category-id="{{ category.id }}"> |
| <div class="admin-row-main"> |
| <div> |
| <p class="column-label">Category</p> |
| <h2>{{ category.name }}</h2> |
| <p class="admin-card-copy">删除分类会同时移除其下全部任务,请谨慎操作。</p> |
| </div> |
| <div class="admin-row-side"> |
| <span class="task-count">{{ category.tasks|length }} 项任务</span> |
| <button class="danger-button" type="button" data-delete-category="{{ category.id }}">删除此清单</button> |
| </div> |
| </div> |
| </article> |
| {% endfor %} |
| </section> |
| </div> |
| </section> |
| {% else %} |
| <section class="admin-section"> |
| <div class="admin-grid admin-grid-tight course-management-grid"> |
| <article class="admin-card course-editor-card"> |
| <div class="admin-card-head"> |
| <div> |
| <p class="column-label">Course Editor</p> |
| <h2 id="courseEditorHeading">新增课程</h2> |
| </div> |
| </div> |
| <p class="admin-card-copy">课程时间按“第几节到第几节”输入,系统会根据当前时间表自动换算为具体时间。</p> |
|
|
| <form class="modal-form compact" id="courseForm"> |
| <input id="courseIdInput" name="course_id" type="hidden"> |
| <label> |
| <span>课程名称</span> |
| <input id="courseTitleInput" name="title" type="text" maxlength="40" placeholder="例如:高等数学"> |
| </label> |
| <label> |
| <span>上课地点</span> |
| <input id="courseLocationInput" name="location" type="text" maxlength="40" placeholder="例如:教学楼 A302"> |
| </label> |
| <label> |
| <span>星期几</span> |
| <select id="courseWeekdayInput" name="day_of_week"> |
| <option value="1">星期一</option> |
| <option value="2">星期二</option> |
| <option value="3">星期三</option> |
| <option value="4">星期四</option> |
| <option value="5">星期五</option> |
| <option value="6">星期六</option> |
| <option value="7">星期日</option> |
| </select> |
| </label> |
| <div class="split-fields"> |
| <label> |
| <span>开始节次</span> |
| <select id="courseStartPeriodInput" name="start_period"></select> |
| </label> |
| <label> |
| <span>结束节次</span> |
| <select id="courseEndPeriodInput" name="end_period"></select> |
| </label> |
| </div> |
| <div class="split-fields"> |
| <label> |
| <span>开始周数</span> |
| <input id="courseStartWeekInput" name="start_week" type="number" min="1" max="30" value="1"> |
| </label> |
| <label> |
| <span>结束周数</span> |
| <input id="courseEndWeekInput" name="end_week" type="number" min="1" max="30" value="16"> |
| </label> |
| </div> |
| <label> |
| <span>单双周</span> |
| <select id="courseWeekPatternInput" name="week_pattern"> |
| <option value="all">每周</option> |
| <option value="odd">单周</option> |
| <option value="even">双周</option> |
| </select> |
| </label> |
| <div class="form-actions"> |
| <button class="secondary-button" id="resetCourseEditorButton" type="button">清空表单</button> |
| <button class="primary-button" type="submit">保存课程</button> |
| </div> |
| </form> |
| </article> |
|
|
| <section class="admin-stack course-list" id="courseGrid"> |
| {% if courses %} |
| {% for course in courses %} |
| <article class="admin-card admin-row-card course-card" data-course-id="{{ course.id }}"> |
| <div class="admin-card-head course-row-head"> |
| <div> |
| <p class="column-label">Course</p> |
| <h2>{{ course.title }}</h2> |
| </div> |
| <div class="course-row-actions"> |
| <span class="task-count">周{{ ["一","二","三","四","五","六","日"][course.day_of_week - 1] }}</span> |
| <button class="secondary-button" type="button" data-edit-course="{{ course.id }}">编辑课程</button> |
| <button class="danger-button" type="button" data-delete-course="{{ course.id }}">删除课程</button> |
| </div> |
| </div> |
| <p class="admin-card-copy">{{ course.start_time }} - {{ course.end_time }} · 第 {{ course.start_week }}-{{ course.end_week }} 周 · {% if course.week_pattern == "odd" %}单周{% elif course.week_pattern == "even" %}双周{% else %}每周{% endif %}</p> |
| <p class="admin-card-copy">{{ course.location if course.location else "未填写地点" }}</p> |
| </article> |
| {% endfor %} |
| {% else %} |
| <article class="admin-card empty-admin-card"> |
| <h2>还没有固定课程</h2> |
| <p class="admin-card-copy">在左侧填写课程信息并保存后,周课表会自动按周显示。</p> |
| </article> |
| {% endif %} |
| </section> |
| </div> |
| </section> |
| {% endif %} |
|
|
| <div class="toast-stack" id="toastStack"></div> |
| </main> |
| {% endblock %} |
| {% block scripts %} |
| <script> |
| window.__ADMIN_BOOTSTRAP__ = { |
| adminPage: {{ admin_page|tojson }}, |
| courses: {{ courses|tojson }}, |
| categories: {{ categories|tojson }}, |
| scheduleSettings: {{ schedule_settings|tojson }}, |
| defaultTimeSlots: {{ default_time_slots|tojson }}, |
| }; |
| </script> |
| <script src="{{ url_for('static', filename='admin-v020.js') }}"></script> |
| {% endblock %} |
|
|