feat: 支持单套试卷同一提交人多次刷卷并展示
- DataService::build 新增 aggregateByStudent 按学号聚合: dedupe=true 仅保留最新一份;false 则每学号一行(代表成绩取最高分) 附 attempts(次数) 与 attempts_list(每次提交明细),修正提交人数被多次提交inflate的问题 - api.php dashboard 透传 attempts/attempts_list;statOf 增加 attempts 求和;export 增加刷题次数列 - dashboard.php 成员榜加"刷N次"徽标,点击下钻弹窗看每次提交(时间/成绩/时长/暂存);hero 显示总提交次数 - 主统计页成绩明细同样加"刷N次"徽标与下钻弹窗 - stats 新增 attempts_total
This commit is contained in:
+28
-3
@@ -447,10 +447,13 @@
|
||||
const sig = r.sid + '|' + r.score + '|' + r.submit_at;
|
||||
const changed = state.prevMap[r.sid] && state.prevMap[r.sid] !== sig;
|
||||
const isNew = r.sid && state.newSids.has(r.sid);
|
||||
const clsName = (changed ? 'diff ' : '') + (isNew ? 'new' : '');
|
||||
return '<tr class="' + clsName.trim() + '">' +
|
||||
const canDrill = (r.attempts || 1) > 1;
|
||||
const clsName = (changed ? 'diff ' : '') + (isNew ? 'new ' : '') + (canDrill ? 'clickable' : '');
|
||||
const att = canDrill ? ' <span class="tag tag-att" title="查看 ' + r.attempts + ' 次提交明细">刷' + r.attempts + '次</span>' : '';
|
||||
const onclk = canDrill ? ' onclick="openAttemptsModal(' + JSON.stringify(r.sid) + ')"' : '';
|
||||
return '<tr class="' + clsName.trim() + '"' + onclk + '>' +
|
||||
'<td class="sid">' + esc(r.sid) + '</td>' +
|
||||
'<td class="name">' + esc(r.name) + '</td>' +
|
||||
'<td class="name">' + esc(r.name) + att + '</td>' +
|
||||
'<td>' + esc(r.cls || '') + '</td>' +
|
||||
'<td>' + esc(r.grp || '') + '</td>' +
|
||||
'<td class="score num ' + scoreClass(r.score) + '">' + (r.score == null ? '-' : r.score) + '</td>' +
|
||||
@@ -499,6 +502,28 @@
|
||||
'</td><td class="num">' + esc(u.submit_at) + '</td></tr>').join('');
|
||||
}
|
||||
|
||||
/* 多次刷题下钻弹窗(主统计页成绩明细) */
|
||||
function openAttemptsModal(sid) {
|
||||
const r = (state.rows || []).find(x => String(x.sid) === String(sid));
|
||||
if (!r || (r.attempts || 1) <= 1) return;
|
||||
const list = r.attempts_list || [];
|
||||
const rows = list.map(a => {
|
||||
const sc = a.score == null ? '<span class="muted">未判分</span>' : esc(a.score);
|
||||
const tmp = a.temp_save ? ' <span class="tag tag-gray">暂存</span>' : '';
|
||||
return '<tr><td class="num">' + esc(a.submit_at) + '</td><td class="num">' + sc + tmp +
|
||||
'</td><td class="num">' + esc(a.duration_txt || '-') + '</td></tr>';
|
||||
}).join('');
|
||||
$('#attTitle').textContent = (r.name || '') + ' · 共 ' + r.attempts + ' 次提交';
|
||||
$('#attBody').innerHTML = list.length
|
||||
? '<table class="grid compact"><thead><tr><th>提交时间</th><th>成绩</th><th>考试时长</th></tr></thead><tbody>' + rows + '</tbody></table>'
|
||||
: '<div class="empty">无提交明细</div>';
|
||||
$('#attemptsModal').classList.add('open');
|
||||
}
|
||||
function closeAttemptsModal() {
|
||||
const m = $('#attemptsModal');
|
||||
if (m) m.classList.remove('open');
|
||||
}
|
||||
|
||||
/* ---------------- 自动刷新 ---------------- */
|
||||
function schedule() {
|
||||
if (state.timer) clearInterval(state.timer);
|
||||
|
||||
Reference in New Issue
Block a user