diff --git a/App/teacher.html b/App/teacher.html index c27f948..5665675 100644 --- a/App/teacher.html +++ b/App/teacher.html @@ -1362,6 +1362,57 @@ function _liveIsActive(ls) { return ls.last_seen_ms && (Date.now() - ls.last_seen_ms) <= _LIVE_PAUSE_SEC * 1000; } +// Uhrzeit HH:MM aus ms-Epoch. +function _hhmm(ms){ if(!ms) return '—'; var d=new Date(ms); return ('0'+d.getHours()).slice(-2)+':'+('0'+d.getMinutes()).slice(-2); } + +// „Heute nicht mehr aktiv" — Schüler:innen, die HEUTE gespielt haben, gerade aber +// offline sind: zuletzt aktiv (Uhrzeit) + letzte Aktivität + deren Leistung. +// Wiederverwendet in „Aktuell" und „Fortschritt". activeSet = {studentId:true} +// der gerade Online-Schüler:innen (die stehen oben in der aktiven Tabelle). +async function _renderInactiveToday(activeSet) { + var today = new Date().toISOString().slice(0,10); + var data; + try { data = await api('live?summary=1&class_id=' + currentClassId + '&date=' + encodeURIComponent(today)); } + catch(e){ return ''; } + if (!data || data.error || !Array.isArray(data.students)) return ''; + var rows = []; + data.students.forEach(function(s){ + if (activeSet && activeSet[s.studentId]) return; // gerade online → oben + var sess = (s.sessions||[]).filter(function(x){ return x.startMs; }); + if (!sess.length) return; // heute nichts gespielt + if (sess.some(function(x){ return x.isLive || x.success==='running'; })) return; // läuft noch → oben + sess.sort(function(a,b){ return (b.endMs||0)-(a.endMs||0); }); + rows.push({ s:s, last:sess[0] }); + }); + if (!rows.length) return ''; + rows.sort(function(a,b){ return (b.last.endMs||0)-(a.last.endMs||0); }); + var html = '
Heute nicht mehr aktiv · '+rows.length+'
'; + html += '

Heute schon gearbeitet, gerade aber offline — mit letzter Aktivität und deren Leistung.

'; + html += '
'; + html += '' + + '' + + '' + + '' + + ''; + rows.forEach(function(r){ + var s=r.s, last=r.last; + var av = (typeof s.emoji === 'string' && s.emoji.indexOf('avatar:')===0) + ? '' + : ''+(s.emoji||'🧑‍🎓')+''; + var score = (last.score!=null)?last.score:(last.stars!=null?Math.round(last.stars/5*100):null); + var perf = score!=null + ? ''+score+' %' + : (last.success==='aborted' ? 'abgebrochen' : ''); + html += '' + + '' + + '' + + '' + + ''; + }); + html += '
Schüler*inZuletzt aktivAktivitätLeistung
'+av+''+esc(s.displayName)+''+_hhmm(last.endMs)+' Uhr'+esc((last.simIcon||'📚')+' '+(last.simTitle||last.simId))+(last.lessonLabel?' · '+esc(last.lessonLabel):'')+''+perf+'
'; + return html; +} + async function renderLive() { var sessions = await api('live?class_id=' + currentClassId); if (sessions.error) { document.getElementById('tab-live').innerHTML = '

'+esc(sessions.error)+'

'; return; } @@ -1370,7 +1421,7 @@ async function renderLive() { html += '

Aktualisiert sich alle 4 Sekunden. Aktiv = Lebenszeichen ≤ 90 s · pausierte Sessions (⏸) bleiben sichtbar, bis der/die Lernende weitermacht. Klick auf eine Zeile öffnet die Detailansicht.

'; if (!sessions.length) { html += '

Gerade niemand online — sobald eine Schülerin oder ein Schüler eine Simulation startet, taucht sie hier auf.

'; - host.innerHTML = html + ''; + host.innerHTML = html + '' + (await _renderInactiveToday({})); return; } @@ -1385,9 +1436,11 @@ async function renderLive() { // Nach Modul gruppieren var byModule = {}; + var _activeSet = {}; sessions.forEach(function(ls) { if (!byModule[ls.module_id]) byModule[ls.module_id] = { meta: ls, rows: [] }; byModule[ls.module_id].rows.push(ls); + _activeSet[ls.student_id] = true; }); Object.keys(byModule).forEach(function(modId) { @@ -1507,6 +1560,8 @@ async function renderLive() { html += ''; + html += await _renderInactiveToday(_activeSet); + // Reflexionen (letzte Antworten der Klasse) — gecacht, damit der 4s-Refresh nicht flackert html += '
' + '
💭 Reflexionen — letzte Antworten der Klasse
' @@ -1769,13 +1824,16 @@ async function renderLiveCompare() { // Körper var simSessions = byGroup[sim] ? byGroup[sim].sessions : []; if (!simSessions.length) { - html += '
'+esc(_compareGroupLabel(sim))+' · Vergleich
' - + '

Noch niemand arbeitet gerade an dieser Simulation. Sobald Kinder starten, erscheinen sie hier im Vergleich.

'; + html += '
'+esc(_compareGroupLabel(sim))+' · Fortschritt
' + + '

Noch niemand arbeitet gerade an dieser Simulation. Sobald Kinder starten, erscheinen sie hier.

'; } else if (sim === 'klima') { html += _renderKlimaCompareBody(simSessions); } else { html += _renderGenericCompareBody(simSessions, sim); } + var _cActive = {}; + (Array.isArray(sessions) ? sessions : []).forEach(function(ls){ _cActive[ls.student_id] = true; }); + html += await _renderInactiveToday(_cActive); host.innerHTML = html; }