feat: 成绩明细考试次数/历史成绩/导出排序/高亮常亮

- 成绩明细成绩列后新增「考试次数」列(可排序)
- 点击任意成员弹窗查看历史成绩(修复内联 onclick 找不到 IIFE 内函数、多次刷题下钻完全失效的 bug;仅 1 次也能点开)
- 历史成绩展示方式可切换:默认点击成员弹窗;可选「成绩明细内全部展开」(每次考试一行,标注第几次/最佳)
- 新数据绿色底纹常亮(不再黄闪一下):变更检测纳入 attempts/最近提交时间(重考低分也能发现);高亮跨刷新累积,新增「清除高亮」按钮,切换项目/姓名题时清零
- 导出成绩可选排序:按提交时间(默认)或按学号(同学号内按提交时间降序);导出全部考试记录并始终带「考试次数/第几次」列
- 优化排序:空值恒排末尾、主键相同时按学号次级排序;提交时间列显示「最近一次提交」
- 后端:DataService 补 last_submit_ts/last_submit_at/attempts_list 的 idx 与 is_best;新增 expandAttempts 与 sortForExport;修复 expandAttempts 降序比较器写反
- 设置新增 history_display/export_sort 两项配置(局部保存不触发重连、非法值归一化);缺考导出按学号排序
- 设置里补充「只保留最新一份」与考试次数的关系说明
This commit is contained in:
2026-09-10 10:10:02 +08:00
parent 9ee2aec2f0
commit 14c7fa7177
6 changed files with 467 additions and 59 deletions
+34 -3
View File
@@ -80,6 +80,12 @@ $rosterCount = Roster::count();
<input type="text" id="kw" placeholder="输入学号或姓名筛选">
</div>
<div class="field btns">
<label style="display:flex;align-items:center;gap:6px;font-size:12px;color:var(--text-2)">导出排序
<select id="exportSortSel" style="height:30px;border-radius:8px;border:1px solid var(--border);padding:0 6px;background:#fff">
<option value="time">按提交时间</option>
<option value="sid">按学号</option>
</select>
</label>
<button class="btn" id="btnExport">导出成绩</button>
<button class="btn" id="btnExportAbsent">导出缺考</button>
</div>
@@ -102,7 +108,10 @@ $rosterCount = Roster::count();
<section class="panel" id="tablePanel">
<div class="panel-head">
<h2>成绩明细 <small id="tableHint"></small></h2>
<div class="updated">最后更新:<span id="lastUpdate">—</span><i id="liveDot" class="dot"></i></div>
<div class="updated">
<button class="btn sm" id="btnClearHl" hidden title="清除新数据的绿色高亮标记">清除高亮 <b id="hlBadge">0</b></button>
最后更新:<span id="lastUpdate">—</span><i id="liveDot" class="dot"></i>
</div>
</div>
<div class="table-scroll">
<table class="grid" id="dataTable">
@@ -113,11 +122,12 @@ $rosterCount = Roster::count();
<th class="sortable" data-k="cls">班级</th>
<th class="sortable" data-k="grp">组别</th>
<th class="sortable" data-k="score">成绩</th>
<th class="sortable" data-k="submit_ts">提交时间</th>
<th class="sortable" data-k="attempts" title="该生提交过的次数,点击表头可排序">考试次数</th>
<th class="sortable" data-k="submit_ts" title="最近一次提交时间">提交时间</th>
<th class="sortable" data-k="duration">考试时长</th>
</tr>
</thead>
<tbody id="tbody"><tr><td colspan="7" class="empty">请选择问卷 / 考试</td></tr></tbody>
<tbody id="tbody"><tr><td colspan="8" class="empty">请选择问卷 / 考试</td></tr></tbody>
</table>
</div>
</section>
@@ -175,6 +185,22 @@ $rosterCount = Roster::count();
<input type="number" id="cfgFull" min="1" max="1000">
<p class="hint" id="cfgFullHint">未选中试卷时的默认值</p>
</div>
<div class="fi">
<label>历史成绩展示方式</label>
<select id="cfgHistoryDisplay">
<option value="click">点击成员弹窗查看(默认)</option>
<option value="inline">成绩明细内全部展开</option>
</select>
<p class="hint">「全部展开」时每次考试单独一行,直接显示在成绩明细中</p>
</div>
<div class="fi">
<label>成绩导出排序</label>
<select id="cfgExportSort">
<option value="time">按提交时间(默认)</option>
<option value="sid">按学号(同学号按提交时间)</option>
</select>
<p class="hint">导出包含每次考试记录,始终带「考试次数」列</p>
</div>
<div class="fi full">
<label>姓名题关键词</label>
<input type="text" id="cfgKeywords">
@@ -192,6 +218,11 @@ $rosterCount = Roster::count();
<label><input type="checkbox" id="cfgTemp"> 包含"暂存"未提交的答卷</label>
<label><input type="checkbox" id="cfgSsl"> 校验 HTTPS 证书</label>
</div>
<p class="hint" style="margin-top:-4px">
<b>「只保留最新一份」务必注意</b>:勾选后每人只算最后一次提交,
「考试次数」恒为 1、历史成绩只有一条。<b>想看考试次数与多次考试记录,请取消勾选</b>
(取消后每人一行,成绩取最高分,历史里可看到每一次)。
</p>
<div class="fi full" style="margin-top:6px">
<div style="display:flex;align-items:center;gap:8px">