Lehrer-View-Uebersicht: Vorschau einheitliches Leistungs-% (Sterne raus)

- Vorschau-Karte: %+Balken-Standardanzeige, 5-stufige Farbskala,
  Triage-Felder (Foerdern/Begleiten/Laeuft gut) aus %xFleiss mit
  Grenzen = Farbgrenzen (50/65), damit Farbe<->Feld immer stimmen.
- Neue Spalte 'Leistung' je Sim: Vorschlags-Formel auf die Testdaten
  gerechnet (PERF), als pctBar + Triage-Chip. Busfahrt/Flug/Sonnensystem
  Naeherung (Rohwerte fehlen in Testdaten).
- Bewertungs-Block je Sim um 'Vorschlag %' (PROPOSED_PCT) erweitert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-25 02:25:35 +02:00
parent bf579310ed
commit c79ef691ad
+87
View File
@@ -100,6 +100,7 @@
<div class="rec"><b>Vorschlag (ein System):</b> Jede App liefert genau <b>eine Funktion → Leistungs-% (0100)</b> als Wahrheit (grün→rot-Balken). Sterne werden daraus mit <b>denselben globalen Schwellen für alle</b> abgeleitet (z. B. ≥90→5★ · ≥75→4 · ≥55→3 · ≥35→2 · sonst 1). Dann bedeuten Sterne überall dasselbe und % ↔ Sterne sind konsistent.</div>
</div>
<div id="preview"></div>
<div class="toc" id="toc"></div>
<div id="content"></div>
<p class="foot">Alle Werte sind Beispieldaten zur Ansicht. Render-Logik gespiegelt aus <code>teacher.html · renderLive()</code>. Grün/Grau ist Atlas' Vorschlag — bitte prüfen &amp; korrigieren.</p>
@@ -516,6 +517,66 @@ var SCORING = {
},
};
/* ============================================================
3c) VORSCHLAG — einheitliches Leistungs-% (0100) je Sim,
5-stufige Farbskala, %+Balken-Komponente, Triage (%×Fleiß).
============================================================ */
var PROPOSED_PCT = {
farmer:'gewichteter 0100-Score (wie heute intern berechnet) — künftig auch LIVE senden.',
klima:'vorhandener 0100-Score (Temp+Flut+Budget+Bev.) übernehmen.',
fluss:'vorhandener Score Ø(Biodiv,Wirtschaft,Schutz) 5×Verluste übernehmen.',
energiemanager:'ausgeglichene Blöcke / (Tage×8) ×100 15 je Blackout.',
'eu-werkstatt':'saubere Erstversuche / Schritte ×100 5 je Mülleimer.',
weltkueche:'richtige / (richtige+falsche) ×100 (= 100 Fehlerquote).',
busfahrt:'Topo-Punkte / (Aufträge×3) ×100.',
fluggesellschaft:'Topo-Punkte / (Flüge×3) ×100.',
heli:'kontinuierlich aus PlanPct + Start + Landung (0100), nicht gerundete Sterne.',
kofferdetektiv:'vorhandener score100 (0100) übernehmen.',
sonnensystem:'Erstversuch-Quote ×100.',
tourismustal:'Ziele/gesamt ×100, gewichtet mit Zufriedenheit/Natur.',
tourismusregion:'vorhandener gewichteter 0100-Score übernehmen.',
logistik:'Kontostand→% (0 €→0, Zielbudget→100) — UND ans Backend senden.',
};
// 5-stufige Farbskala (= _tagTraffic).
function pctColor(v){ v=Math.max(0,Math.min(100,v||0)); return v>=80?'#1f7a3d':v>=65?'#7cb342':v>=50?'#f9c33b':v>=35?'#ef8b2c':'#d8453a'; }
// Standard-Anzeige überall: Prozent in Ampelfarbe + dünner Balken darunter.
function pctBar(pct){
if (pct==null) return '<span style="color:#9a9a9a">—</span>';
var c=pctColor(pct);
return '<div style="min-width:72px">'
+ '<div style="font-weight:800;color:'+c+';font-size:.86rem;font-variant-numeric:tabular-nums">'+pct+' %</div>'
+ '<div style="margin-top:2px;height:6px;border-radius:99px;background:rgba(0,0,0,.07);overflow:hidden"><div style="height:100%;width:'+pct+'%;background:'+c+'"></div></div>'
+ '</div>';
}
// Triage aus Leistungs-% × Aktivität — Grenzen = Farbgrenzen, damit Feld ↔ Farbe stimmen.
function triage(pct, active){
if (pct==null || !active) return {lab:'inaktiv', col:'#8a8a8a', bg:'#efeee8'};
if (pct<50) return {lab:'Fördern', col:'#b04a3e', bg:'#f7e2dc'};
if (pct<65) return {lab:'Begleiten', col:'#9a6a12', bg:'#f7edd6'};
return {lab:'Läuft gut', col:'#3a6b3e', bg:'#dceadd'};
}
function triageChip(pct, active){ var t=triage(pct,active); return '<span style="display:inline-block;font-size:.62rem;font-weight:700;color:'+t.col+';background:'+t.bg+';padding:1px 7px;border-radius:10px">'+t.lab+'</span>'; }
// Vorschlags-Leistungs-% auf die Testdaten gerechnet (Vorschau).
function _cl(v,a,b){ return Math.max(a,Math.min(b,v)); }
var PERF = {
klima:function(s){ var sp=(s.level>=3)?7000:6000; return Math.round(_cl(35-(s.temp-15.5)*20,0,35)+Math.max(0,25*(1-(s.floodedPct||0)/50))+_cl((s.budget||0)/10,0,20)+_cl((s.population||0)/sp*20,0,20)); },
fluss:function(s){ return _cl(Math.round((s.biodiv+s.economy+s.flood)/3)-(s.settlementsLost||0)*5,0,100); },
kofferdetektiv:function(s){ return s.score!=null?s.score:null; },
tourismusregion:function(s){ return Math.round(0.6*((s.avgStars||0)/5*100)+0.4*(s.env||0)); },
tourismustal:function(s){ if(!s.goalsTotal) return null; return Math.round(0.5*(s.goalsDone/s.goalsTotal*100)+0.3*(s.satisfaction||0)+0.2*(s.nature||0)); },
heli:function(s){ if(s.totalStars!=null) return Math.round(s.totalStars/5*100); if(s.planTotal) return Math.round((s.planCorrect||0)/s.planTotal*100); return null; },
farmer:function(s){ var money=_cl(50+(s.cash||0)/300,0,100),co2=_cl(100-(s.co2_kg||0)/80,0,100),dis=_cl(100-(s.diseases||0)*20,0,100),crop=_cl((s.crops_used||0)/10*100,0,100),country=_cl((s.countries||0)/6*100,0,100); return Math.round(0.25*money+0.20*(s.hit_rate||0)+0.15*co2+0.10*dis+0.10*crop+0.10*country+0.10*70); },
energiemanager:function(s){ var d=(s.day||1)*(s.blockTotal||8); return _cl(Math.round((s.setBlocksBalanced||0)/d*100)-15*(s.blackouts||0),0,100); },
'eu-werkstatt':function(s){ if(!s.stepsTotal) return null; return _cl(Math.round((s.firstTryHits||0)/s.stepsTotal*100)-5*(s.muelleimerCount||0),0,100); },
weltkueche:function(s){ var t=(s.correctClicks||0)+(s.wrongClicks||0); return t?Math.round((s.correctClicks||0)/t*100):null; },
busfahrt:function(s){ return s.orderIndex?Math.round((s.quizFirstTry||0)/s.orderIndex*100):null; },
fluggesellschaft:function(s){ return s.orderIndex?Math.round((s.quizFirstTry||0)/s.orderIndex*100):null; },
sonnensystem:function(s){ return s.taskTotal?Math.round((s.completed||0)/s.taskTotal*100):null; },
logistik:function(s){ return s.balance==null?null:_cl(Math.round(s.balance/16000*100),0,100); },
};
/* ============================================================
4) Testdaten je Sim (3 Schüler:innen: stark · schwach · mittel)
============================================================ */
@@ -616,6 +677,7 @@ function renderScoring(id){
var h = '<div class="scorebox"><h4>🎯 So entsteht die Bewertung</h4>';
h += '<div class="srow"><span class="lab">Sterne</span><span>'+sc.stars+'</span></div>';
h += '<div class="srow"><span class="lab">Prozent</span><span>'+sc.pct+'</span></div>';
if (PROPOSED_PCT[id]) h += '<div class="srow" style="background:#eef7f0;border-radius:6px;padding:.25rem .4rem;margin-top:.35rem"><span class="lab" style="color:#3a6b3e">Vorschlag %</span><span style="color:#2f5e39">'+PROPOSED_PCT[id]+'</span></div>';
(sc.flags||[]).forEach(function(f){ h += '<div class="flag">⚠ '+f+'</div>'; });
h += '</div>';
return h;
@@ -640,6 +702,7 @@ function renderSim(meta){
h += '<div class="tbl-scroll"><table class="live"><thead><tr>';
h += '<th style="text-align:left">Schüler*in<span class="key">displayName</span></th>';
h += '<th style="text-align:left;color:#8a8a8a">Seit<span class="key">missionStartedAt / started_at</span></th>';
h += '<th style="text-align:left;background:#e7f4ea;border-bottom-color:#bcd9c2">🎯 Leistung<span class="key">leistung_pct (Vorschlag)</span><span class="tag g">EIN Wert</span></th>';
fields.forEach(function(f){
var align=f.align||'right';
var isG=!!greenSet[f.k];
@@ -670,6 +733,8 @@ function renderSim(meta){
h += '<tr style="background:'+restBg+';'+(paused?'color:#9a9a9a;':'')+'box-shadow:'+accent+'">';
h += '<td style="white-space:nowrap"><span style="display:inline-flex;align-items:center;gap:.4rem">'+(help?'<span title="stockt · braucht evtl. Hilfe">🆘</span>':(paused?'<span title="pausiert">⏸</span>':''))+avatarHtml+'<strong>'+esc(ls.displayName)+'</strong></span></td>';
h += '<td style="white-space:nowrap;line-height:1.15"><div style="font-size:.78rem;color:#3a3a3a;font-weight:600">'+missionStr+'</div><div style="font-size:.62rem;color:#8a8a8a">'+simStr+' ges.</div></td>';
var perfPct = (PERF[meta.id]) ? PERF[meta.id](s) : null;
h += '<td style="background:#f2faf4;vertical-align:top">'+pctBar(perfPct)+'<div style="margin-top:3px">'+triageChip(perfPct, perfPct!=null)+'</div></td>';
fields.forEach(function(f){
var align=f.align||'right';
var isG=!!greenSet[f.k];
@@ -713,8 +778,30 @@ function renderSim(meta){
return h;
}
// Vorschau-Karte: neues Bewertungssystem (Skala · %+Balken · Triage)
function renderPreviewCard(){
var samples=[92,71,55,40,22];
var h='<div class="gbox" style="border-left-color:#5a8a5e">';
h+='<h2>🎯 Neues Bewertungssystem — Vorschau zum Abnehmen</h2>';
h+='<p><b>Standard überall:</b> ein Leistungs-% (0100) in der Ampelfarbe + dünner Balken darunter — Sterne fallen weg. Beispiele:</p>';
h+='<div style="display:flex;gap:1.4rem;flex-wrap:wrap;margin:.4rem 0 .9rem">'+samples.map(function(v){return pctBar(v);}).join('')+'</div>';
h+='<p><b>5-stufige Farbskala</b> (= bestehende Tag-Skala):</p>';
h+='<div style="display:flex;gap:.5rem;flex-wrap:wrap;margin:.3rem 0 .9rem;font-size:.72rem">'
+[['≥ 80','sehr gut',92],['6579','gut',71],['5064','solide',55],['3549','wackelig',40],['< 35','kritisch',22]]
.map(function(b){var c=pctColor(b[2]);return '<span style="display:inline-flex;align-items:center;gap:.35rem;background:#fff;border:1px solid rgba(0,0,0,.08);border-radius:20px;padding:.2rem .6rem"><span style="width:14px;height:14px;border-radius:4px;background:'+c+'"></span><b>'+b[0]+' %</b> · '+b[1]+'</span>';}).join('')+'</div>';
h+='<p><b>Triage-Felder aus %×Fleiß</b> — die Grenzen sind die Farbgrenzen, damit Balkenfarbe und Feld immer übereinstimmen:</p>';
h+='<div style="display:flex;gap:1.2rem;flex-wrap:wrap;margin:.3rem 0 .6rem">'
+[22,55,80].map(function(v){return '<div style="text-align:center">'+pctBar(v)+'<div style="margin-top:3px">'+triageChip(v,true)+'</div></div>';}).join('')
+'<div style="text-align:center">'+pctBar(null)+'<div style="margin-top:3px">'+triageChip(null,false)+'</div></div>'+'</div>';
h+='<div class="rec"><b>&lt; 50 % → Fördern</b> · <b>5064 % → Begleiten</b> · <b>≥ 65 % → Läuft gut</b> — jeweils nur, wenn aktiv gearbeitet wurde; sonst „inaktiv".</div>';
h+='<p style="font-size:.72rem;color:#8a8a8a;margin-top:.6rem">Unten hat jede Tabelle die neue Spalte <b>🎯 Leistung</b> — die Vorschlags-Formel je Sim, auf die Testdaten gerechnet. Bei Busfahrt · Fluggesellschaft · Sonnensystem ist der Wert eine Näherung (Topo-/Erstversuch-Rohwerte fehlen in den Testdaten).</p>';
h+='</div>';
return h;
}
// TOC + Inhalt aufbauen
var toc = SIM_META.map(function(m){ return '<a href="#sim-'+m.id+'">'+m.icon+' '+esc(m.title)+'</a>'; }).join('');
document.getElementById('preview').innerHTML = renderPreviewCard();
document.getElementById('toc').innerHTML = toc;
document.getElementById('content').innerHTML = SIM_META.map(renderSim).join('');
</script>