feat: 登录态持久化 + 禁用按钮灰色 + 登录提示精简 + 全局美化 + 独立数据看板页

This commit is contained in:
2026-09-08 16:30:19 +08:00
parent d934cd27ac
commit e111151504
5 changed files with 370 additions and 26 deletions
+70
View File
@@ -119,6 +119,76 @@ try {
];
ny_ok($result);
// ---------------- 数据看板(按班级聚合,面向班主任/学生整体情况) ----------------
case 'dashboard':
$projectId = (string)($_GET['projectId'] ?? '');
if ($projectId === '') {
ny_fail('请先选择问卷/考试');
}
$nameQid = (string)($_GET['nameQid'] ?? '');
$c = cfg();
$result = DataService::build($c, $projectId, $nameQid);
$fsMap = is_array($c['full_scores'] ?? null) ? $c['full_scores'] : [];
$fs = isset($fsMap[$projectId]) ? (int)$fsMap[$projectId] : (int)($c['full_score'] ?? 100);
if ($fs < 1) {
$fs = 100;
}
$students = $result['roster'] ?: [];
$rows = $result['rows'] ?: [];
$byCls = [];
foreach ($students as $s) {
$k = trim((string)($s['cls'] ?? '')) ?: '(未分班)';
$byCls[$k][] = $s;
}
$rowsByCls = [];
foreach ($rows as $r) {
$k = trim((string)($r['cls'] ?? '')) ?: '(未分班)';
$rowsByCls[$k][] = $r;
}
$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,
];
}
usort($classes, static function (array $a, array $b): int {
$an = is_numeric($a['class']) ? (int)$a['class'] : $a['class'];
$bn = is_numeric($b['class']) ? (int)$b['class'] : $b['class'];
if (is_int($an) && is_int($bn)) {
return $an <=> $bn;
}
return strcmp((string)$a['class'], (string)$b['class']);
});
ny_ok([
'project' => $result['project'],
'full_score' => $fs,
'overall' => $result['stats'],
'classes' => $classes,
'updated_at' => $result['updated_at'],
]);
// ---------------- 名单 ----------------
case 'roster':
ny_ok(['students' => Roster::all(), 'meta' => Roster::meta()]);