feat: 看板支持A/B组对比下钻 + 全屏 + 删除返回按钮 + 全系统组别(A/B)支持
This commit is contained in:
@@ -148,29 +148,56 @@ try {
|
||||
$rowsByCls[$k][] = $r;
|
||||
}
|
||||
|
||||
// 通用统计器:给定学生集合 + 答卷集合,算一组指标
|
||||
$statOf = static function (array $stu, array $rs, int $fs): array {
|
||||
$total = count($stu);
|
||||
$submitted = count($rs);
|
||||
$scores = array_values(array_filter(array_map(static fn($r) => $r['score'] ?? null, $rs), static fn($v) => $v !== null));
|
||||
$avg = $scores !== [] ? round(array_sum($scores) / count($scores), 2) : null;
|
||||
$pass = count(array_filter($rs, static fn($r) => ($r['score'] ?? null) !== null && ($r['score'] >= 0.6 * $fs)));
|
||||
$passRate = $submitted > 0 ? round($pass / $submitted * 100, 1) : 0;
|
||||
$durs = array_values(array_filter(array_map(static fn($r) => $r['duration'] ?? null, $rs), static fn($v) => $v !== null));
|
||||
$avgDur = $durs !== [] ? (int)round(array_sum($durs) / count($durs)) : null;
|
||||
return [
|
||||
'total' => $total,
|
||||
'submitted' => $submitted,
|
||||
'absent' => max(0, $total - $submitted),
|
||||
'rate' => $total > 0 ? round($submitted / $total * 100, 1) : 0,
|
||||
'avg' => $avg,
|
||||
'pass_rate' => $passRate,
|
||||
'max' => $scores !== [] ? max($scores) : null,
|
||||
'min' => $scores !== [] ? min($scores) : null,
|
||||
'avg_duration' => $avgDur,
|
||||
];
|
||||
};
|
||||
|
||||
$classes = [];
|
||||
foreach ($byCls as $k => $stu) {
|
||||
$rs = $rowsByCls[$k] ?? [];
|
||||
$total = count($stu);
|
||||
$submitted = count($rs);
|
||||
$scores = array_values(array_filter(array_map(static fn($r) => $r['score'] ?? null, $rs), static fn($v) => $v !== null));
|
||||
$avg = $scores !== [] ? round(array_sum($scores) / count($scores), 2) : null;
|
||||
$pass = count(array_filter($rs, static fn($r) => ($r['score'] ?? null) !== null && ($r['score'] >= 0.6 * $fs)));
|
||||
$passRate = $submitted > 0 ? round($pass / $submitted * 100, 1) : 0;
|
||||
$durs = array_values(array_filter(array_map(static fn($r) => $r['duration'] ?? null, $rs), static fn($v) => $v !== null));
|
||||
$avgDur = $durs !== [] ? (int)round(array_sum($durs) / count($durs)) : null;
|
||||
$classes[] = [
|
||||
'class' => $k,
|
||||
'total' => $total,
|
||||
'submitted' => $submitted,
|
||||
'absent' => max(0, $total - $submitted),
|
||||
'rate' => $total > 0 ? round($submitted / $total * 100, 1) : 0,
|
||||
'avg' => $avg,
|
||||
'pass_rate' => $passRate,
|
||||
'max' => $scores !== [] ? max($scores) : null,
|
||||
'min' => $scores !== [] ? min($scores) : null,
|
||||
'avg_duration' => $avgDur,
|
||||
];
|
||||
$rs = $rowsByCls[$k] ?? [];
|
||||
$row = $statOf($stu, $rs, $fs);
|
||||
$row['class'] = $k;
|
||||
|
||||
// 班级内按组别(A/B 等)再聚合,用于看板下钻对比
|
||||
$stuByGrp = [];
|
||||
foreach ($stu as $s) {
|
||||
$g = trim((string)($s['grp'] ?? '')) ?: '(未分组)';
|
||||
$stuByGrp[$g][] = $s;
|
||||
}
|
||||
$rowsByGrp = [];
|
||||
foreach ($rs as $r) {
|
||||
$g = trim((string)($r['grp'] ?? '')) ?: '(未分组)';
|
||||
$rowsByGrp[$g][] = $r;
|
||||
}
|
||||
$groups = [];
|
||||
foreach ($stuByGrp as $g => $gstu) {
|
||||
$gs = $statOf($gstu, $rowsByGrp[$g] ?? [], $fs);
|
||||
$gs['group'] = $g;
|
||||
$groups[] = $gs;
|
||||
}
|
||||
usort($groups, static fn(array $a, array $b): int => strcmp((string)$a['group'], (string)$b['group']));
|
||||
$row['groups'] = $groups;
|
||||
|
||||
$classes[] = $row;
|
||||
}
|
||||
usort($classes, static function (array $a, array $b): int {
|
||||
$an = is_numeric($a['class']) ? (int)$a['class'] : $a['class'];
|
||||
@@ -233,6 +260,7 @@ try {
|
||||
'sid' => (string)($s['sid'] ?? ''),
|
||||
'name' => (string)($s['name'] ?? ''),
|
||||
'cls' => trim((string)($s['cls'] ?? '')),
|
||||
'grp' => trim((string)($s['grp'] ?? '')),
|
||||
];
|
||||
}
|
||||
Roster::save($students);
|
||||
@@ -263,17 +291,18 @@ try {
|
||||
$out = fopen('php://output', 'w');
|
||||
|
||||
if ($action === 'export_absent') {
|
||||
fputcsv($out, ['学号', '姓名', '班级']);
|
||||
fputcsv($out, ['学号', '姓名', '班级', '组别']);
|
||||
foreach ($result['absent'] as $r) {
|
||||
fputcsv($out, [$r['sid'], $r['name'], $r['cls'] ?? '']);
|
||||
fputcsv($out, [$r['sid'], $r['name'], $r['cls'] ?? '', $r['grp'] ?? '']);
|
||||
}
|
||||
} else {
|
||||
fputcsv($out, ['学号', '姓名', '班级', '成绩', '提交时间', '考试时长', '考试时长(秒)']);
|
||||
fputcsv($out, ['学号', '姓名', '班级', '组别', '成绩', '提交时间', '考试时长', '考试时长(秒)']);
|
||||
foreach ($result['rows'] as $r) {
|
||||
fputcsv($out, [
|
||||
$r['sid'],
|
||||
$r['name'],
|
||||
$r['cls'] ?? '',
|
||||
$r['grp'] ?? '',
|
||||
$r['score'] === null ? '' : $r['score'],
|
||||
$r['submit_at'],
|
||||
$r['duration_txt'],
|
||||
|
||||
Reference in New Issue
Block a user