Tag-Ansicht: student_results einbeziehen + Datum/Zoom-Verhalten

- live.php summary: fertige Laeufe aus student_results ergaenzt (dedupliziert gegen assessment/
  live) -> JEDER heutige Durchgang erscheint als Balken, egal ueber welchen Submit-Pfad.
- teacher.html: Ergebnisse-Tab/Menuewechsel setzt Datum auf HEUTE + Regler auf Auto zurueck;
  Datumswahl/Heute setzt Regler auf Auto; Auto-Zoom jetzt +/-1 h um die Aktivitaet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-24 09:33:32 +02:00
parent 868cdda276
commit b77f4ed912
2 changed files with 76 additions and 5 deletions
+65
View File
@@ -388,6 +388,71 @@ if ($method === 'GET') {
unset($st);
}
// === student_results (V2) ergaenzen: fertige Laeufe des Tages, die NICHT schon
// als assessment/live-Session vorliegen (manche Sims schreiben nur student_results).
// So taucht JEDER Durchgang im Tag-Balken auf, unabhaengig vom Submit-Pfad. ===
$srRows = $db->fetchAll(
"SELECT sr.student_id, sr.module_id, sr.score, sr.duration_sec, sr.detail_json,
UNIX_TIMESTAMP(sr.completed_at) AS done_ts,
s.display_name, s.username, s.emoji_avatar, s.avatar_slug
FROM student_results sr
JOIN students s ON s.id = sr.student_id
WHERE sr.class_id = ?
AND sr.completed_at >= ? AND sr.completed_at < ?
ORDER BY sr.completed_at ASC",
[$classId, $date . ' 00:00:00', $date . ' 23:59:59.999']
);
foreach ($srRows as $sr) {
$sid = (int)$sr['student_id'];
$simId = $sr['module_id'];
$endMs = ((int)$sr['done_ts']) * 1000;
$durSec = max(0, (int)$sr['duration_sec']);
$startMs = $endMs - $durSec * 1000;
// Dedup: schon eine Session (assessment/live) fuer diese Sim mit ~gleicher Endzeit?
$dup = false;
if (isset($byStudent[$sid])) {
foreach ($byStudent[$sid]['sessions'] as $ex) {
if ($ex['simId'] === $simId && abs((int)($ex['endMs'] ?? 0) - $endMs) < 150000) { $dup = true; break; }
}
}
if ($dup) continue;
$lk = $extractLessonKey(['results' => $sr['detail_json'], 'process_log' => null]);
$mi = $moduleMap[$simId] ?? null;
if (!isset($byStudent[$sid])) {
$byStudent[$sid] = [
'studentId' => $sid,
'displayName' => $sr['display_name'] ?: $sr['username'],
'avatarSlug' => $sr['avatar_slug'],
'emoji' => $sr['emoji_avatar'],
'totalSec' => 0,
'sessions' => [],
];
}
$score = is_numeric($sr['score']) ? max(0, min(100, (int)round($sr['score']))) : null;
$success = ($score === null) ? ($durSec < 60 ? 'aborted' : 'good')
: ($score >= 65 ? 'good' : ($score >= 40 ? 'mid' : 'bad'));
$byStudent[$sid]['sessions'][] = [
'simId' => $simId,
'simTitle' => $mi['title'] ?? $simId,
'simIcon' => $mi['icon'] ?? '📚',
'lessonKind' => $lk['kind'],
'lessonLabel' => $lk['label'],
'startMs' => $startMs,
'endMs' => $endMs,
'durationSec' => $durSec,
'stars' => null,
'score' => $score,
'completed' => true,
'success' => $success,
'rowCount' => max(1, (int)round($durSec/4)),
];
$byStudent[$sid]['totalSec'] += $durSec;
}
foreach ($byStudent as &$stSR) {
usort($stSR['sessions'], function($a,$b){ return $a['startMs'] <=> $b['startMs']; });
}
unset($stSR);
// Stille Schüler*innen (keine Sessions an dem Tag) als leere Zeilen ergänzen
$allStudents = $db->fetchAll(
'SELECT id, display_name, username, emoji_avatar, avatar_slug FROM students WHERE class_id = ? AND deleted_at IS NULL ORDER BY COALESCE(display_name, username)',