Live/Vergleich an Klassenaufgabe gekoppelt

- aktive Klassenaufgabe wird automatisch als Vergleichs-Modul vorgewaehlt
  (Chip mit 📋 markiert, immer vorne)
- Aufgaben-Banner: begonnen X/N (aus matrix) · gerade aktiv A · Oe Fortschritt
- zeigt Aufgabe auch wenn noch niemand aktiv ist (mit Hinweis)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 01:27:36 +02:00
parent 5f6abeeb42
commit 97144495a1
+62 -14
View File
@@ -1464,10 +1464,21 @@ function _compareGroupLabel(g) {
async function renderLiveCompare() {
var host = document.getElementById('tab-live');
if (!host) return;
var sessions = await api('live?class_id=' + currentClassId);
var res = await Promise.all([
api('live?class_id=' + currentClassId),
api('assignments?class_id=' + currentClassId),
api('results?class_id=' + currentClassId + '&view=matrix'),
]);
var sessions = res[0], assignments = res[1], matrix = res[2];
if (sessions.error) { host.innerHTML = _liveToggleHtml() + '<p style="color:#c07a6b">'+esc(sessions.error)+'</p>'; return; }
if (!Array.isArray(assignments)) assignments = [];
if (!matrix || matrix.error) matrix = { students:[], modules:[], cells:{} };
// Sim-Filter-Chips: alle aktiven Sims zählen, gruppiert
// Aktive Klassenaufgabe (erste aktive) → Fokus-Modul für den Vergleich
var activeAssign = assignments.filter(function(a){ return a.active; })[0] || null;
var assignGroup = activeAssign ? _compareSimGroup(activeAssign.module_id) : null;
// Online-Sessions nach Sim gruppieren
var byGroup = {};
(sessions || []).forEach(function(ls){
var g = _compareSimGroup(ls.module_id);
@@ -1477,38 +1488,75 @@ async function renderLiveCompare() {
});
var groups = Object.keys(byGroup).sort(function(a,b){ return byGroup[b].count - byGroup[a].count; });
if (!groups.length) {
// Chips = Online-Gruppen, Aufgabe immer vorne (auch wenn noch niemand aktiv)
var chipGroups = groups.slice();
if (assignGroup) chipGroups = [assignGroup].concat(chipGroups.filter(function(g){ return g !== assignGroup; }));
if (!chipGroups.length) {
host.innerHTML = _liveToggleHtml()
+ '<div class="card"><div class="card-h">Vergleich</div>'
+ '<p style="font-size:.78rem;color:#8a8a8a">Gerade niemand online — sobald Schüler*innen eine Simulation öffnen, kannst du hier vergleichen.</p>'
+ '<p style="font-size:.78rem;color:#8a8a8a">Gerade niemand online und keine aktive Klassenaufgabe — sobald Schüler*innen eine Simulation öffnen (oder du eine Aufgabe freigibst), kannst du hier vergleichen.</p>'
+ '</div>';
return;
}
// Aktive Sim wählen — User-Wahl, sonst die mit den meisten Schüler*innen
var sim = _liveCompareSim && byGroup[_liveCompareSim] ? _liveCompareSim : groups[0];
// Sim wählen: explizite User-Wahl > aktive Aufgabe > meiste Online
var sim;
if (_liveCompareSim && chipGroups.indexOf(_liveCompareSim) >= 0) sim = _liveCompareSim;
else if (assignGroup) sim = assignGroup;
else sim = groups[0];
_liveCompareSim = sim;
// Header mit Toggle + Sim-Filter-Chips
var html = _liveToggleHtml();
// Aufgaben-Banner, wenn eine Klassenaufgabe aktiv ist
if (activeAssign) {
var modId = activeAssign.module_id;
var N = (matrix.students || []).length;
var begun = 0;
(matrix.students || []).forEach(function(s){
var c = (matrix.cells && matrix.cells[s.id]) ? matrix.cells[s.id][modId] : null;
if (c && c.plays > 0) begun++;
});
var onlineNow = byGroup[assignGroup] ? byGroup[assignGroup].sessions : [];
var progVals = onlineNow.map(function(ls){ return _liveProgressPct(ls.module_id, ls.state); }).filter(function(v){ return v != null; });
var avgProg = progVals.length ? Math.round(progVals.reduce(function(a,b){return a+b;},0)/progVals.length) : null;
var due = activeAssign.ends_at ? ' · bis ' + new Date(activeAssign.ends_at).toLocaleDateString('de-AT',{day:'2-digit',month:'2-digit',hour:'2-digit',minute:'2-digit'}) : '';
html += '<div style="background:#f0f5f1;border:1px solid #cfe0d4;border-left:4px solid #3a6a3e;border-radius:10px;padding:.6rem .9rem;margin-bottom:.7rem">'
+ '<div style="font-size:.82rem;font-weight:800;color:#2a5a2e">📋 Aufgabe: '+esc(_compareGroupLabel(assignGroup))+'<span style="font-weight:500;color:#6a8a6e;font-size:.7rem"> · Level '+esc(activeAssign.level)+due+'</span></div>'
+ '<div style="display:flex;gap:1.2rem;flex-wrap:wrap;margin-top:.35rem;font-size:.74rem;color:#3a3a3a">'
+ '<span>begonnen <b>'+begun+'</b> / '+N+'</span>'
+ '<span>gerade aktiv <b>'+onlineNow.length+'</b></span>'
+ '<span>Ø Fortschritt <b>'+(avgProg!=null?avgProg+' %':'')+'</b></span>'
+ '</div></div>';
}
// Sim-Filter-Chips
html += '<div style="display:flex;gap:.4rem;flex-wrap:wrap;margin-bottom:.6rem;padding:.3rem 0">';
groups.forEach(function(g){
chipGroups.forEach(function(g){
var active = g === sim;
var isAssign = (g === assignGroup);
var bg = active ? '#1f4b37' : '#fff';
var col = active ? '#fff' : '#3d5165';
var border = active ? '#1f4b37' : 'rgba(0,0,0,.12)';
var border = active ? '#1f4b37' : (isAssign ? '#3a6a3e' : 'rgba(0,0,0,.12)');
var cnt = byGroup[g] ? byGroup[g].count : 0;
html += '<button onclick="setCompareSim(\''+g+'\')" style="padding:.35rem .7rem;border:1.5px solid '+border+';background:'+bg+';color:'+col+';border-radius:18px;font-size:.74rem;font-weight:700;cursor:pointer;display:inline-flex;align-items:center;gap:.4rem">'
+ (isAssign ? '<span title="aktive Klassenaufgabe">📋</span>' : '')
+ '<span>'+esc(_compareGroupLabel(g))+'</span>'
+ '<span style="background:'+(active?'rgba(255,255,255,.25)':'rgba(0,0,0,.07)')+';padding:0 .4rem;border-radius:8px;font-size:.66rem;font-weight:800">'+byGroup[g].count+'</span>'
+ '<span style="background:'+(active?'rgba(255,255,255,.25)':'rgba(0,0,0,.07)')+';padding:0 .4rem;border-radius:8px;font-size:.66rem;font-weight:800">'+cnt+'</span>'
+ '</button>';
});
html += '</div>';
// Sim-spezifisch rendern
if (sim === 'klima') {
html += _renderKlimaCompareBody(byGroup.klima.sessions);
// Körper
var simSessions = byGroup[sim] ? byGroup[sim].sessions : [];
if (!simSessions.length) {
html += '<div class="card"><div class="card-h">'+esc(_compareGroupLabel(sim))+' · Vergleich</div>'
+ '<p style="font-size:.78rem;color:#8a8a8a">Noch niemand arbeitet gerade an dieser Simulation. Sobald Kinder starten, erscheinen sie hier im Vergleich.</p></div>';
} else if (sim === 'klima') {
html += _renderKlimaCompareBody(simSessions);
} else {
html += _renderGenericCompareBody(byGroup[sim].sessions, sim);
html += _renderGenericCompareBody(simSessions, sim);
}
host.innerHTML = html;
}