Klassenaufgabe: Modal mit Frist-Schnellwahl + Live-Bestaetigung; Start/Tempo auf aktiver Card

- Modal "Aufgabe erteilen": Frist-Buttons (Heute/Morgen/+1 Woche/Kein Limit),
  Default +1 Woche, Tempo-Checkbox "Vorbereiten", Live-Zusammenfassung als
  Bestaetigung, Button "Auftrag erteilen"
- Aktive Klassen-Aufgabe-Card: Sim-Bild + Status (Vorbereitet/Laeuft) +
  Steuerung "Start freigeben" / "Pause" / "Beenden" direkt auf der Card
  (Tempo-Start nicht mehr in der individuellen Freigabe)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 11:58:04 +02:00
parent 3a2e65ebd9
commit bbef4856d0
+74 -26
View File
@@ -373,26 +373,33 @@ schueler01,Max M.,,,,,</pre>
</div>
</div>
<!-- Modal: Klassen-Simulation starten -->
<!-- Modal: Klassen-Aufgabe erteilen -->
<div class="modal hidden" id="modal-startsim">
<div class="modal-card">
<h3>🚀 Klassen-Simulation starten</h3>
<p style="font-size:.7rem;color:#8a8a8a;margin-bottom:.5rem">Wählen Sie ein Modul und Level. Die Aufgabe erscheint bei allen Schüler*innen an oberster Stelle.</p>
<h3>🚀 Klassen-Aufgabe erteilen</h3>
<p style="font-size:.7rem;color:#8a8a8a;margin-bottom:.5rem">Modul und Stufe wählen, Frist setzen. Die Aufgabe erscheint bei allen Schüler*innen ganz oben.</p>
<label>Modul</label>
<select id="ss-module" style="width:100%;padding:.4rem .6rem;border:1.5px solid rgba(0,0,0,.1);border-radius:6px;font-size:.78rem;font-family:inherit"></select>
<label>Level</label>
<select id="ss-level" style="width:100%;padding:.4rem .6rem;border:1.5px solid rgba(0,0,0,.1);border-radius:6px;font-size:.78rem;font-family:inherit">
<option value="1">Level 1 — Einsteiger</option>
<option value="2">Level 2 — Fortgeschritten</option>
<option value="3">Level 3 — Profi</option>
<select id="ss-module" onchange="ssUpdateSummary()" style="width:100%;padding:.4rem .6rem;border:1.5px solid rgba(0,0,0,.1);border-radius:6px;font-size:.78rem;font-family:inherit"></select>
<label>Stufe</label>
<select id="ss-level" onchange="ssUpdateSummary()" style="width:100%;padding:.4rem .6rem;border:1.5px solid rgba(0,0,0,.1);border-radius:6px;font-size:.78rem;font-family:inherit">
<option value="1">Stufe 1 — Einsteiger</option>
<option value="2">Stufe 2 — Fortgeschritten</option>
<option value="3">Stufe 3 — Profi</option>
</select>
<label>Endet am (optional, leer = ohne Zeitlimit)</label>
<input type="datetime-local" id="ss-ends">
<label style="display:flex;align-items:center;gap:.4rem;margin-top:.5rem;cursor:pointer">
<input type="checkbox" id="ss-paused"> <span style="font-size:.74rem">⏸ Tempo-Sperre — Schüler*in startet pausiert, bis Lehrperson freigibt</span>
<label>Fällig bis</label>
<div style="display:flex;gap:.3rem;flex-wrap:wrap;margin-bottom:.35rem">
<button type="button" class="btn btn-outline" style="font-size:.66rem;padding:.25rem .55rem" onclick="ssSetDue('heute')">Heute 13:00</button>
<button type="button" class="btn btn-outline" style="font-size:.66rem;padding:.25rem .55rem" onclick="ssSetDue('morgen')">Morgen</button>
<button type="button" class="btn btn-outline" style="font-size:.66rem;padding:.25rem .55rem" onclick="ssSetDue('woche')">+1 Woche</button>
<button type="button" class="btn btn-outline" style="font-size:.66rem;padding:.25rem .55rem" onclick="ssSetDue('')">Kein Limit</button>
</div>
<input type="datetime-local" id="ss-ends" onchange="ssUpdateSummary()">
<label style="display:flex;align-items:flex-start;gap:.4rem;margin-top:.6rem;cursor:pointer">
<input type="checkbox" id="ss-paused" onchange="ssUpdateSummary()" style="margin-top:.15rem"> <span style="font-size:.74rem">⏸ Vorbereiten — die Klasse startet erst, wenn du auf der Aufgaben-Card „▶ Start freigeben" drückst (gemeinsamer Start)</span>
</label>
<div style="display:flex;gap:.4rem;margin-top:.8rem">
<button class="btn" onclick="startSimulation()">🚀 Starten</button>
<div id="ss-summary" style="margin-top:.7rem;padding:.5rem .7rem;background:#f5f3eb;border:1px solid rgba(0,0,0,.06);border-radius:8px;font-size:.72rem;color:#3a3a3a"></div>
<div style="display:flex;gap:.4rem;margin-top:.7rem">
<button class="btn" onclick="startSimulation()">✓ Auftrag erteilen</button>
<button class="btn btn-outline" onclick="hideModal('modal-startsim')">Abbrechen</button>
</div>
</div>
@@ -2878,23 +2885,41 @@ async function loadModuleMatrix() {
// Aktive Aufgaben anzeigen
var html = '';
if (activeAssign.length > 0) {
html += '<div class="card" style="border-color:#e8833a;border-width:2px"><div class="card-h" style="color:#e8833a">Aktive Klassen-Simulation</div>';
html += '<div class="card" style="border-color:#e8833a;border-width:2px"><div class="card-h" style="color:#e8833a">📋 Aktive Klassen-Aufgabe</div>';
var anyPrepared = false;
activeAssign.forEach(function(a) {
var mod = mods.find(function(m){return m.id===a.module_id;});
var name = mod ? mod.icon + ' ' + mod.name : a.module_id;
var end = a.ends_at ? ' · bis ' + new Date(a.ends_at).toLocaleDateString('de-AT',{day:'2-digit',month:'2-digit',hour:'2-digit',minute:'2-digit'}) : ' · ohne Zeitlimit';
html += '<div style="display:flex;align-items:center;gap:.6rem;padding:.3rem 0">';
html += '<span style="font-size:1.2rem">' + (mod?.icon||'📋') + '</span>';
html += '<div style="flex:1"><strong style="font-size:.78rem">' + esc(mod?.name||a.module_id) + '</strong>';
html += '<span style="font-size:.65rem;color:#8a8a8a"> · Level ' + a.level + end + '</span></div>';
html += '<button class="btn" style="background:#c07a6b;font-size:.6rem;padding:.2rem .5rem" onclick="stopAssignment('+a.id+')">Beenden</button>';
html += '</div>';
var paused = mod ? !!mod.paused : false;
if (paused) anyPrepared = true;
var img = (mod && mod.card_image) ? 'assets/img/'+mod.card_image : null;
var thumb = img
? '<img src="'+img+'" alt="" style="width:50px;height:50px;border-radius:9px;object-fit:cover;flex:none">'
: '<span style="font-size:1.6rem;width:50px;text-align:center">'+(mod?mod.icon:'📋')+'</span>';
var end = a.ends_at ? 'fällig ' + new Date(a.ends_at).toLocaleDateString('de-AT',{weekday:'short',day:'2-digit',month:'2-digit',hour:'2-digit',minute:'2-digit'}) : 'ohne Zeitlimit';
var stateBadge = paused
? '<span style="background:#fdf1e6;color:#c25e1e;border:1px solid #e8c3a0;padding:.08rem .5rem;border-radius:99px;font-size:.62rem;font-weight:700">⏸ Vorbereitet</span>'
: '<span style="background:#e5f2e7;color:#2a7a3a;border:1px solid #b9dcc0;padding:.08rem .5rem;border-radius:99px;font-size:.62rem;font-weight:700">▶ Läuft</span>';
html += '<div style="display:flex;align-items:center;gap:.7rem;padding:.5rem 0;border-bottom:1px solid rgba(0,0,0,.05)">';
html += thumb;
html += '<div style="flex:1;min-width:0"><div style="font-size:.86rem;font-weight:800;color:#3a3a3a">'+esc(mod?mod.name:a.module_id)+' <span style="font-weight:500;color:#8a8a8a;font-size:.72rem">· Stufe '+a.level+'</span></div>';
html += '<div style="font-size:.66rem;color:#8a8a8a;margin-top:.2rem">'+stateBadge+' <span style="margin-left:.35rem">'+end+'</span></div></div>';
html += '<div style="display:flex;gap:.4rem;align-items:center;flex:none">';
if (paused) {
html += '<button class="btn" style="background:#3a6a3e;font-size:.74rem;padding:.42rem .85rem;font-weight:700" onclick="toggleAssignmentPause(\''+a.module_id+'\',true)" title="Die Klasse darf jetzt loslegen">▶ Start freigeben</button>';
} else {
html += '<button class="btn" style="background:#c9913a;font-size:.66rem;padding:.35rem .6rem" onclick="toggleAssignmentPause(\''+a.module_id+'\',false)" title="Pausieren — die Klasse wartet">⏸ Pause</button>';
}
html += '<button class="btn" style="background:#c07a6b;font-size:.66rem;padding:.35rem .6rem" onclick="stopAssignment('+a.id+')">■ Beenden</button>';
html += '</div></div>';
});
if (anyPrepared) {
html += '<p style="font-size:.66rem;color:#8a8a8a;margin-top:.55rem;line-height:1.45"><b>Vorbereitet:</b> Die Klasse sieht den Auftrag bereits, kann aber erst loslegen, wenn du <b>„▶ Start freigeben"</b> drückst — so starten alle gemeinsam.</p>';
}
html += '</div>';
}
// Start-Button
html += '<div style="margin-bottom:.6rem"><button class="btn" onclick="showStartSim()" style="font-size:.75rem">🚀 Klassen-Simulation starten</button></div>';
html += '<div style="margin-bottom:.6rem"><button class="btn" onclick="showStartSim()" style="font-size:.75rem">🚀 Klassen-Aufgabe erteilen</button></div>';
// Vorbereitung: spielbare vs. geplante Module trennen (vor Matrix nutzen)
var modsActive = mods.filter(function(m){ return m.status !== 'geplant' && m.status !== 'archiv'; });
@@ -3021,11 +3046,34 @@ async function showStartSim(preselectedModuleId) {
sel.innerHTML = '';
ALL_MODS.forEach(function(m) { var o=document.createElement('option'); o.value=m.id; o.textContent=(m.icon||'')+' '+m.name; sel.appendChild(o); });
if (preselectedModuleId) sel.value = preselectedModuleId;
document.getElementById('ss-ends').value = '';
document.getElementById('ss-paused').checked = false;
document.getElementById('ss-level').value = '1';
ssSetDue('woche'); // Default-Frist: +1 Woche (Hausübung); setzt Feld + Bestätigung
showModal('modal-startsim');
}
function _ssPad(n){ return String(n).padStart(2,'0'); }
function _ssDtLocal(d){ return d.getFullYear()+'-'+_ssPad(d.getMonth()+1)+'-'+_ssPad(d.getDate())+'T'+_ssPad(d.getHours())+':'+_ssPad(d.getMinutes()); }
function ssSetDue(kind){
var el = document.getElementById('ss-ends');
if (kind === '') { el.value = ''; ssUpdateSummary(); return; }
var d = new Date();
if (kind === 'morgen') d.setDate(d.getDate()+1);
else if (kind === 'woche') d.setDate(d.getDate()+7);
d.setHours(13, 0, 0, 0);
el.value = _ssDtLocal(d);
ssUpdateSummary();
}
function ssUpdateSummary(){
var el = document.getElementById('ss-summary'); if (!el) return;
var modSel = document.getElementById('ss-module');
var modTxt = (modSel && modSel.options[modSel.selectedIndex]) ? modSel.options[modSel.selectedIndex].text : '—';
var lvl = document.getElementById('ss-level').value;
var ends = document.getElementById('ss-ends').value;
var paused = document.getElementById('ss-paused').checked;
var endTxt = ends ? new Date(ends).toLocaleDateString('de-AT',{weekday:'short',day:'2-digit',month:'2-digit',hour:'2-digit',minute:'2-digit'}) : 'ohne Zeitlimit';
var startTxt = paused ? '⏸ startet auf dein Signal' : '▶ startet sofort';
el.innerHTML = '<b>'+esc(modTxt)+'</b> · Stufe '+lvl+' · fällig <b>'+esc(endTxt)+'</b> · '+startTxt;
}
async function startSimulation() {
var moduleId = document.getElementById('ss-module').value;
var level = parseInt(document.getElementById('ss-level').value);