Gesamt: "Jetzt live"-Streifen oben (laufende Spiele, blinkend)

In Ergebnisse/Gesamt fehlten laufende Sessions (Fleiss baut nur auf fertigen
Laeufen). Neuer blinkender Live-Streifen ganz oben aus live_sessions: Name +
Sim-Symbol + Laufzeit, Klick = zuschauen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-22 14:55:32 +02:00
parent 71226581fa
commit ad8c6b7d7e
+28 -1
View File
@@ -3758,11 +3758,13 @@ async function loadResults() {
host.innerHTML = '<p style="font-size:.78rem;color:#8a8a8a;padding:1rem">Lade Ergebnisse…</p>';
// Drei parallele API-Calls: Fleiß (NEU oben) + Matrix + Activity (alt)
var [fleiss, matrix, activity] = await Promise.all([
var [fleiss, matrix, activity, live] = await Promise.all([
api('results?class_id=' + currentClassId + '&view=fleiss&range=' + _resultsState.fleissRange + '&module_id=' + encodeURIComponent(_resultsState.fleissModule)),
api('results?class_id=' + currentClassId + '&view=matrix'),
api('results?class_id=' + currentClassId + '&view=activity&range=' + _resultsState.range + '&groupBy=' + (_resultsState.groupBy || 'module')),
api('live?class_id=' + currentClassId),
]);
_resultsState.live = Array.isArray(live) ? live : [];
if (matrix.error) { host.innerHTML = '<p style="color:#c07a6b">'+esc(matrix.error)+'</p>'; return; }
if (activity.error) { host.innerHTML = '<p style="color:#c07a6b">'+esc(activity.error)+'</p>'; return; }
@@ -3777,16 +3779,41 @@ async function loadResults() {
function renderResults() {
var host = document.getElementById(_resultsHost) || document.getElementById('tab-results');
host.innerHTML = ''
+ '<div id="res-live"></div>'
+ '<div id="res-fleiss"></div>'
+ '<div id="res-matrix"></div>'
+ '<div id="res-activity"></div>'
+ '<div id="res-modules"></div>';
renderResultsLive();
renderFleiss();
renderMatrix();
renderActivity();
renderModuleCards();
}
// „Jetzt live"-Streifen ganz oben in Gesamt: laufende Spiele (aus live_sessions),
// als langsam blinkende Blöcke — sonst fehlen sie hier (Fleiß baut nur auf fertigen Läufen).
function renderResultsLive() {
var host = document.getElementById('res-live'); if (!host) return;
var live = (_resultsState.live || []).filter(function(ls){ return ls.last_seen_ms && (Date.now() - ls.last_seen_ms) < 90000; });
if (!live.length) { host.innerHTML = ''; return; }
var html = '<div class="card" style="border-color:#e0b3aa">'
+ '<div class="card-h" style="color:#b03a2a"><span style="display:inline-block;width:9px;height:9px;border-radius:50%;background:#c0392b;margin-right:.45rem;animation:_tagblink 1.4s ease-in-out infinite"></span>Jetzt live · '+live.length+'</div>'
+ '<div style="display:flex;flex-wrap:wrap;gap:.5rem">';
live.forEach(function(ls){
var el = ls.started_at_ms ? Math.max(0, Math.round((Date.now() - ls.started_at_ms)/60000)) : 0;
var av = (typeof ls.emoji === 'string' && ls.emoji.indexOf('avatar:') === 0)
? '<img src="assets/img/avatars/thumbs/avatar-'+ls.emoji.substring(7)+'.webp" alt="" style="width:1.4em;height:1.4em;border-radius:50%;object-fit:cover">'
: '<span style="font-size:1.05rem">'+(ls.emoji || '🧑‍🎓')+'</span>';
html += '<button onclick="openLiveSpectator('+ls.student_id+',\''+ls.module_id+'\')" title="Live zuschauen" '
+ 'style="animation:_tagblink 1.9s ease-in-out infinite;cursor:pointer;background:#fdeae4;border:1px solid #eabfb4;border-radius:10px;padding:.4rem .7rem;display:inline-flex;align-items:center;gap:.4rem;font-size:.76rem">'
+ av + '<b>'+esc(ls.displayName)+'</b>'
+ '<span style="color:#8a5a52">'+esc((ls.moduleIcon||'📚')+' '+(ls.moduleName||ls.module_id))+' · '+el+' min</span></button>';
});
html += '</div></div>';
host.innerHTML = html;
}
// ---------- Sektion 0 (NEU oben): Fleiß pro Schüler:in ----------
// Layout: Matrix mit Zeilen=Schüler:innen, Spalten=Zeitbuckets (MoSo
// bei Woche, 24 Stunden bei Tag etc.). Pro Zelle eine vertikale Säule;