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:
@@ -45,7 +45,7 @@ try {
|
||||
$in = $_POST;
|
||||
}
|
||||
$old = cfg();
|
||||
$allowed = ['base_url', 'api_prefix', 'username', 'timeout', 'refresh_interval', 'page_size', 'name_keywords'];
|
||||
$allowed = ['base_url', 'api_prefix', 'username', 'timeout', 'refresh_interval', 'page_size', 'name_keywords', 'history_display', 'export_sort'];
|
||||
$new = $old;
|
||||
foreach ($allowed as $k) {
|
||||
if (array_key_exists($k, $in)) {
|
||||
@@ -68,6 +68,14 @@ try {
|
||||
if (array_key_exists('layout', $in)) {
|
||||
$new['layout'] = ($in['layout'] === 'side') ? 'side' : 'default';
|
||||
}
|
||||
// 历史成绩展示方式:click(点击成员弹窗,默认) / inline(明细内全部展开)
|
||||
if (array_key_exists('history_display', $in)) {
|
||||
$new['history_display'] = ($in['history_display'] === 'inline') ? 'inline' : 'click';
|
||||
}
|
||||
// 成绩导出排序:time(按提交时间降序,默认) / sid(按学号)
|
||||
if (array_key_exists('export_sort', $in)) {
|
||||
$new['export_sort'] = ($in['export_sort'] === 'sid') ? 'sid' : 'time';
|
||||
}
|
||||
// 各试卷独立满分(覆盖整个 full_scores 映射)
|
||||
if (array_key_exists('full_scores', $in) && is_array($in['full_scores'])) {
|
||||
$new['full_scores'] = $in['full_scores'];
|
||||
@@ -476,23 +484,41 @@ try {
|
||||
$out = fopen('php://output', 'w');
|
||||
|
||||
if ($action === 'export_absent') {
|
||||
// 与页面缺考名单一致:按学号升序(纯数字按数值,否则自然排序)
|
||||
usort($absent, static function ($x, $y): int {
|
||||
$a = trim((string)($x['sid'] ?? ''));
|
||||
$b = trim((string)($y['sid'] ?? ''));
|
||||
if (is_numeric($a) && is_numeric($b)) {
|
||||
return $a <=> $b;
|
||||
}
|
||||
return strnatcmp($a, $b);
|
||||
});
|
||||
fputcsv($out, ['学号', '姓名', '班级', '组别']);
|
||||
foreach ($absent as $r) {
|
||||
fputcsv($out, [$r['sid'] ?? '', $r['name'] ?? '', $r['cls'] ?? '', $r['grp'] ?? '']);
|
||||
}
|
||||
} else {
|
||||
fputcsv($out, ['学号', '姓名', '班级', '组别', '成绩', '提交时间', '考试时长', '考试时长(秒)', '刷题次数']);
|
||||
foreach ($rows as $r) {
|
||||
// 导出全部考试记录(同一学号考了 N 次就有 N 行),并保留"考试次数"
|
||||
$sortMode = (string)($_GET['sort'] ?? '');
|
||||
$sortMode = ($sortMode === 'sid') ? 'sid' : 'time';
|
||||
$all = DataService::expandAttempts($rows, true);
|
||||
|
||||
// time=按提交时间降序;sid=按学号(同学号内按提交时间降序)
|
||||
$all = DataService::sortForExport($all, $sortMode);
|
||||
|
||||
fputcsv($out, ['学号', '姓名', '班级', '组别', '成绩', '考试次数', '第几次', '提交时间', '考试时长', '考试时长(秒)']);
|
||||
foreach ($all as $r) {
|
||||
fputcsv($out, [
|
||||
$r['sid'] ?? '',
|
||||
$r['name'] ?? '',
|
||||
$r['cls'] ?? '',
|
||||
$r['grp'] ?? '',
|
||||
$r['score'] === null ? '' : $r['score'],
|
||||
(int)($r['attempts'] ?? 1),
|
||||
(int)($r['idx'] ?? 1),
|
||||
$r['submit_at'] ?? '',
|
||||
$r['duration_txt'] ?? '',
|
||||
$r['duration'] === null ? '' : $r['duration'],
|
||||
(int)($r['attempts'] ?? 1),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user