Gesamt/Fleiss: laufende Sessions als blinkende Saeule im aktuellen Bucket

Statt separatem Top-Streifen (rueckgebaut): results.php view=fleiss spielt
laufende live_sessions in den aktuellen Bucket (Stunde/Wochentag/Tag/Monat) ein,
markiert ihn `live`. renderFleiss laesst diese Saeule blinken (roter Rahmen).
So sieht man Bens laufendes Spiel direkt bei "Fleiss pro Schueler*in".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-22 15:02:19 +02:00
parent ad8c6b7d7e
commit 64a9a62157
2 changed files with 49 additions and 30 deletions
+43
View File
@@ -369,6 +369,16 @@ if ($view === 'fleiss') {
default: Response::error('range muss day|week|weeks|month|year sein');
}
// Aktueller Bucket-Index (für LAUFENDE, noch nicht abgegebene Sessions).
$nowBucketIdx = -1;
switch ($range) {
case 'day': $nowBucketIdx = (int)date('G'); break; // Stunde 023
case 'week': $nowBucketIdx = (int)date('N') - 1; break; // Mo=0 … So=6
case 'month': $nowBucketIdx = (int)date('j') - 1; break; // Tag 131
case 'year': $nowBucketIdx = (int)date('n') - 1; break; // Monat 112
case 'weeks': $nowBucketIdx = isset($bmap) ? ($bmap[(int)date('oW')] ?? -1) : -1; break;
}
// Optional Modul-Filter
$params = [$classId];
$modSql = '';
@@ -463,6 +473,39 @@ if ($view === 'fleiss') {
$moduleAgg[$sim]['totalSec'] += $sec;
}
// 5b) LAUFENDE Sessions (noch kein Assessment abgegeben) in den aktuellen
// Bucket einspielen — als „live" markiert, damit die Säule dort blinkt.
if ($nowBucketIdx >= 0) {
$liveRows = $db->fetchAll(
"SELECT ls.student_id, ls.module_id,
UNIX_TIMESTAMP(ls.started_at) AS started_ts,
UNIX_TIMESTAMP(ls.last_seen) AS last_seen_ts
FROM live_sessions ls
WHERE ls.class_id = ? AND ls.last_seen > NOW() - INTERVAL 90 SECOND",
[$classId]
);
foreach ($liveRows as $lr) {
$sid = (int)$lr['student_id'];
if (!isset($byStudent[$sid])) continue;
$sim = $lr['module_id'];
if ($moduleId !== 'ALL' && $moduleId !== '' && $sim !== $moduleId) continue;
$sec = max(0, (int)$lr['last_seen_ts'] - (int)$lr['started_ts']);
$b = &$byStudent[$sid]['buckets'][$nowBucketIdx];
$b['sum'] += $sec;
$byMod = (array)$b['byModule'];
$byMod[$sim] = ($byMod[$sim] ?? 0) + $sec;
$b['byModule'] = $byMod;
$b['live'] = true; // Client lässt diese Säule blinken
$b['liveModule'] = $sim;
unset($b);
$byStudent[$sid]['totalSec'] += $sec;
if (!isset($moduleAgg[$sim])) {
$info = $moduleMap[$sim] ?? null;
$moduleAgg[$sim] = ['id'=>$sim,'name'=>$info?$info['name']:$sim,'icon'=>$info?$info['icon']:'📘','color'=>$info?$info['color']:'#888','totalSec'=>0];
}
}
}
// 6) Global-Max-Bucket-Sec für klassenweite Säulen-Skalierung
foreach ($byStudent as $sid => &$st) {
foreach ($st['buckets'] as $b) {