From 0a6fa2172f05505ad8bb1547febee60a03d741a1 Mon Sep 17 00:00:00 2001 From: Thomas Date: Tue, 25 Aug 2026 02:37:33 +0200 Subject: [PATCH] Einheitliche Leistungs-Skala (%) + Farbcodes ueberall vereinheitlicht MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Schwellen NEU (Thomas): >=90 Dunkelgruen / >=80 Hellgruen / >=60 Gelb / >=50 Orange / <50 Rot. Sterne entfallen. - teacher.html: _pctColor (kanonisch) — _tagTraffic + _liveBar + _liveBarColor delegieren jetzt alle daran (EINE Skala; 'niedrig-ist-gut' invertiert). Neu: _leistungPct(simId,state) = das eine 0-100-% je Sim (eigener Score oder abgeleitet), _pctBar (kompakt, schmal). Neue Spalte 'Leistung' in 'Aktuell'. _liveMood aus _leistungPct (>=80 gut / >=50 mittel / <50) — deckungsgleich mit Triage Foerdern/Begleiten/Laeuft gut (50/80). - admin-styleguide.html: neue Sektion 'Leistungs-Skala' (5 Stufen, %+Balken, Triage, CSS-Variablen). - admin-lehrer-view.html: Schwellen/Triage/Preview auf neue Werte, Balken kompakt, Sterne-Hinweis raus. Co-Authored-By: Claude Opus 4.8 --- App/admin-lehrer-view.html | 22 ++++++----- App/admin-styleguide.html | 45 ++++++++++++++++++++++ App/teacher.html | 76 +++++++++++++++++++++++++++++++------- 3 files changed, 119 insertions(+), 24 deletions(-) diff --git a/App/admin-lehrer-view.html b/App/admin-lehrer-view.html index 32ea8da..c29b93e 100644 --- a/App/admin-lehrer-view.html +++ b/App/admin-lehrer-view.html @@ -97,7 +97,7 @@

Der Zeilen-Prozentwert in „Ergebnisse/Aktuell" entsteht in live.php · extractScore: liefert die Sim einen eigenen 0–100-Score, wird der genommen; sonst aus den Sternen: % = Sterne / 5 × 100.

Die Sterne berechnet jede App am Ende selbst — aus unterschiedlichen Kennzahlen und Schwellen (je Sim unten dokumentiert). Deshalb bedeuten 4★ heute nicht überall dasselbe.

Uneinheitlichkeiten: Busfahrt · Fluggesellschaft · Kofferdetektiv liefern nur 0–3 Sterne statt 0–5. Busfahrt/Fluggesellschaft senden als score rohe Punkte (nicht 0–100 → Zeilen-% verzerrt). Weltküche wertet pro Gericht statt pro Durchgang. Logistik überträgt weder Sterne noch Score. Ein echter 0–100-Live-Score existiert nur bei Klima, Fluss, Heli, Kofferdetektiv, Tourismusregion (abgeleitet Tourismustal).

-
Vorschlag (ein System): Jede App liefert genau eine Funktion → Leistungs-% (0–100) als Wahrheit (grün→rot-Balken). Sterne werden daraus mit denselben globalen Schwellen für alle abgeleitet (z. B. ≥90→5★ · ≥75→4 · ≥55→3 · ≥35→2 · sonst 1). Dann bedeuten Sterne überall dasselbe und % ↔ Sterne sind konsistent.
+
Beschlossen: Sterne entfallen. Jede App liefert genau eine Funktion → Leistungs-% (0–100) als Wahrheit, überall gezeigt als Prozent + Balken in der 5-stufigen Farbskala. Auch Fördern/Begleiten/Läuft gut leiten sich aus diesem % ab.
@@ -539,21 +539,23 @@ var PROPOSED_PCT = { }; // 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. +// ≥90 Dunkelgrün · ≥80 Hellgrün · ≥60 Gelb · ≥50 Orange · <50 Rot +function pctColor(v){ v=Math.max(0,Math.min(100,v||0)); return v>=90?'#1f7a3d':v>=80?'#7cb342':v>=60?'#f9c33b':v>=50?'#ef8b2c':'#d8453a'; } +// Standard-Anzeige überall: Prozent in Ampelfarbe + schmaler Balken darunter (kompakt). function pctBar(pct){ if (pct==null) return ''; var c=pctColor(pct); - return '
' - + '
'+pct+' %
' - + '
' + return '
' + + '
'+pct+' %
' + + '
' + '
'; } // Triage aus Leistungs-% × Aktivität — Grenzen = Farbgrenzen, damit Feld ↔ Farbe stimmen. +// <50 (Rot) → Fördern · 50–79 (Orange+Gelb) → Begleiten · ≥80 (Grün) → Läuft gut. 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'}; + if (pct<80) 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 ''+t.lab+''; } @@ -780,20 +782,20 @@ function renderSim(meta){ // Vorschau-Karte: neues Bewertungssystem (Skala · %+Balken · Triage) function renderPreviewCard(){ - var samples=[92,71,55,40,22]; + var samples=[95,84,68,54,30]; var h='
'; h+='

🎯 Neues Bewertungssystem — Vorschau zum Abnehmen

'; h+='

Standard überall: ein Leistungs-% (0–100) in der Ampelfarbe + dünner Balken darunter — Sterne fallen weg. Beispiele:

'; h+='
'+samples.map(function(v){return pctBar(v);}).join('')+'
'; h+='

5-stufige Farbskala (= bestehende Tag-Skala):

'; h+='
' - +[['≥ 80','sehr gut',92],['65–79','gut',71],['50–64','solide',55],['35–49','wackelig',40],['< 35','kritisch',22]] + +[['≥ 90','sehr gut',95],['80–89','gut',84],['60–79','solide',68],['50–59','wackelig',54],['< 50','kritisch',30]] .map(function(b){var c=pctColor(b[2]);return ''+b[0]+' % · '+b[1]+'';}).join('')+'
'; h+='

Triage-Felder aus %×Fleiß — die Grenzen sind die Farbgrenzen, damit Balkenfarbe und Feld immer übereinstimmen:

'; h+='
' +[22,55,80].map(function(v){return '
'+pctBar(v)+'
'+triageChip(v,true)+'
';}).join('') +'
'+pctBar(null)+'
'+triageChip(null,false)+'
'+'
'; - h+='
< 50 % → Fördern · 50–64 % → Begleiten · ≥ 65 % → Läuft gut — jeweils nur, wenn aktiv gearbeitet wurde; sonst „inaktiv".
'; + h+='
< 50 % → Fördern · 50–79 % → Begleiten · ≥ 80 % → Läuft gut — jeweils nur, wenn aktiv gearbeitet wurde; sonst „inaktiv".
'; h+='

Unten hat jede Tabelle die neue Spalte 🎯 Leistung — 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).

'; h+='
'; return h; diff --git a/App/admin-styleguide.html b/App/admin-styleguide.html index 56c6e03..980b115 100644 --- a/App/admin-styleguide.html +++ b/App/admin-styleguide.html @@ -64,6 +64,7 @@ 🎨 Bildstil 🌿 Bild-Farbpalette 🧩 UI-Farbtokens + 📊 Leistungs-Skala 📐 Layout & Spacing 🔤 Typografie 🖼️ Bildformate @@ -195,6 +196,50 @@
+ +
+
Leistungs-Skala — 5 Stufen (Standard für ALLE Sims)
+

EINE Skala für Schülerleistung überall im Programm: Prozentwert (0–100) + dünner Balken in der Ampelfarbe. Sterne entfallen. Die Grenzen 50 / 65 sind zugleich die Triage-Grenzen, damit Balkenfarbe und Feld (Fördern/Begleiten/Läuft gut) immer übereinstimmen. Quelle in Code: pctColor() = _tagTraffic().

+
+
≥ 90 % · sehr gut#1f7a3d
+
80–89 % · gut#7cb342
+
60–79 % · solide#f9c33b
+
50–59 % · wackelig#ef8b2c
+
< 50 % · kritisch#d8453a
+
+ +

Standard-Anzeige: Prozent + Balken

+
+
95 %
+
84 %
+
68 %
+
54 %
+
30 %
+
+ +

Triage-Felder (aus % × Fleiß)

+

< 50 % → Fördern · 50–79 % → Begleiten · ≥ 80 % → Läuft gut — jeweils nur, wenn aktiv gearbeitet wurde, sonst „inaktiv".

+
+ Fördern + Begleiten + Läuft gut + inaktiv +
+ +

CSS-Variablen

+
--ggs-perf-5: #1f7a3d;  /* ≥ 90 %  sehr gut  */
+--ggs-perf-4: #7cb342;  /* 80–89 % gut       */
+--ggs-perf-3: #f9c33b;  /* 60–79 % solide    */
+--ggs-perf-2: #ef8b2c;  /* 50–59 % wackelig  */
+--ggs-perf-1: #d8453a;  /* < 50 %  kritisch  */
+/* Triage */
+--ggs-triage-foerdern:  #b04a3e;
+--ggs-triage-begleiten: #9a6a12;
+--ggs-triage-gut:       #3a6b3e;
+--ggs-triage-inaktiv:   #8a8a8a;
+

Vorschau der Zuordnung je Sim: Lehrer-View Parameter-Überblick.

+
+
Layout & Spacing
diff --git a/App/teacher.html b/App/teacher.html index 5a5ce88..872a1af 100644 --- a/App/teacher.html +++ b/App/teacher.html @@ -624,14 +624,7 @@ function _liveBar(val, min, max, goodWhen, dec) { if (val == null || isNaN(val)) return ''; var span = (max - min) || 1; var pct = Math.max(0, Math.min(100, ((val - min) / span) * 100)); - var c; - if (goodWhen === 'low') { - c = pct <= 33 ? '#5a8a5e' : pct <= 66 ? '#c9913a' : '#c07a6b'; - } else if (goodWhen === 'mid') { - c = '#7a7a7a'; - } else { - c = pct >= 60 ? '#5a8a5e' : pct >= 30 ? '#c9913a' : '#c07a6b'; - } + var c = _liveBarColor(pct, goodWhen); var disp = (dec != null) ? Number(val).toFixed(dec) : Math.round(val); return '' + '' @@ -645,9 +638,9 @@ function _liveBar(val, min, max, goodWhen, dec) { // Farbwahl nach „gut wenn" (aus _liveBar extrahiert) — für die Mini-Balken. function _liveBarColor(pct, goodWhen) { pct = Math.max(0, Math.min(100, pct||0)); - if (goodWhen === 'low') return pct <= 33 ? '#5a8a5e' : pct <= 66 ? '#c9913a' : '#c07a6b'; if (goodWhen === 'mid') return '#9a9a9a'; - return pct >= 60 ? '#5a8a5e' : pct >= 30 ? '#c9913a' : '#c07a6b'; + // EINE Skala (_pctColor). „Niedrig ist gut" invertiert, damit Grün weiter „gut" heißt. + return _pctColor(goodWhen === 'low' ? 100 - pct : pct); } // Mini-Balken UNTER der Zahl (Cockpit „Aktuell"). pct 0 – 100. function _liveMiniBar(pct, color) { @@ -656,6 +649,58 @@ function _liveMiniBar(pct, color) { + '
'; } +// ===== EINHEITLICHE LEISTUNGS-SKALA (Styleguide „Leistungs-Skala", 5 Stufen) ===== +// EINE Farbfunktion für Schülerleistung überall. Grenzen 50/65 = Triage-Grenzen. +function _pctColor(v) { + v = Math.max(0, Math.min(100, v || 0)); + // ≥90 Dunkelgrün · ≥80 Hellgrün · ≥60 Gelb · ≥50 Orange · <50 Rot + return v >= 90 ? '#1f7a3d' : v >= 80 ? '#7cb342' : v >= 60 ? '#f9c33b' : v >= 50 ? '#ef8b2c' : '#d8453a'; +} +// Standard-Anzeige: Prozent in Ampelfarbe + dünner Balken darunter. +function _pctBar(pct) { + if (pct == null || isNaN(pct)) return ''; + pct = Math.max(0, Math.min(100, Math.round(pct))); + var c = _pctColor(pct); + // Kompakt: schmaler Balken (max ~34px), damit die Spalte wenig Platz braucht. + return '
' + + '
'+pct+' %
' + + '
' + + '
'; +} +// Das EINE Leistungs-% (0–100) je Sim aus dem Live-State. Sims mit eigenem +// 0–100-Score nutzen ihn direkt; sonst aus den vorhandenen Kennzahlen abgeleitet. +function _leistungPct(simId, s) { + if (!s || typeof s !== 'object') return null; + var cl = function(v,a,b){ return Math.max(a, Math.min(b, v)); }; + // Sims mit echtem 0–100-Live-Score (klima, fluss, kofferdetektiv, heli) direkt: + if (typeof s.score === 'number' && simId !== 'weltkueche' && simId !== 'busfahrt' && simId !== 'fluggesellschaft') + return cl(Math.round(s.score), 0, 100); + switch (simId) { + case 'klima': case 'klima-3d': { + var sp = (s.level >= 3) ? 7000 : 6000; + return Math.round(cl(35-((s.temp||16)-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)); + } + case 'fluss': return (s.biodiv!=null) ? cl(Math.round((s.biodiv+s.economy+s.flood)/3) - (s.settlementsLost||0)*5, 0, 100) : null; + case 'heli': return (s.totalStars!=null) ? Math.round(s.totalStars/5*100) : (s.planTotal ? Math.round((s.planCorrect||0)/s.planTotal*100) : null); + case 'farmer': { + if (s.hit_rate==null && s.cash==null) return null; + 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); + } + case 'energiemanager': { var d=(s.day||1)*(s.blockTotal||8); return cl(Math.round((s.setBlocksBalanced||0)/d*100) - 15*(s.blackouts||0), 0, 100); } + case 'eu-werkstatt': return s.stepsTotal ? cl(Math.round((s.firstTryHits||0)/s.stepsTotal*100) - 5*(s.muelleimerCount||0), 0, 100) : null; + case 'weltkueche': { var t=(s.correctClicks||0)+(s.wrongClicks||0); return t ? Math.round((s.correctClicks||0)/t*100) : null; } + case 'busfahrt': case 'fluggesellschaft': + return s.topoMax ? cl(Math.round((s.topoPoints||0)/s.topoMax*100),0,100) + : (s.totalOrders ? Math.round((s.wonOrders||0)/s.totalOrders*100) : null); + case 'sonnensystem': return (s.progressPct!=null) ? cl(Math.round(s.progressPct),0,100) : (s.taskTotal ? Math.round((s.completed||0)/s.taskTotal*100) : null); + case 'tourismustal': return s.goalsTotal ? Math.round(0.5*((s.goalsDone||0)/s.goalsTotal*100) + 0.3*(s.satisfaction||0) + 0.2*(s.nature||0)) : null; + case 'tourismusregion': return (s.avgStars!=null) ? Math.round(0.6*(s.avgStars/5*100) + 0.4*(s.env||0)) : null; + case 'logistik': return (s.balance!=null) ? cl(Math.round(s.balance/16000*100),0,100) : null; + } + return (typeof s.score === 'number') ? cl(Math.round(s.score),0,100) : null; +} + var LIVE_PRIMARY_FIELDS = { farmer: [ {k:'year', label:'Jahr', bar:{kind:'abs',max:10,good:'mid'}, fmt:function(v){ return (v||0) + ' / 10'; }}, @@ -1314,6 +1359,10 @@ function _liveProgressPct(simId, s) { } function _liveMood(simId, s) { if (!s) return null; + // Einheitliche Skala: Leistungs-% steuert die Stimmung (≥80 gut · ≥50 mittel · <50 schlecht), + // deckungsgleich mit Farbe + Triage (Läuft gut / Begleiten / Fördern). + var _p = _leistungPct(simId, s); + if (_p != null) return _p >= 80 ? 'good' : _p >= 50 ? 'mid' : 'bad'; if (s.health) return ({good:'good',ok:'good',warning:'mid',bad:'bad',critical:'bad'})[s.health] || 'mid'; if (_liveNeedsHelp(simId, s)) return 'bad'; switch (simId) { @@ -1548,6 +1597,7 @@ async function renderLive() { html += ''; html += 'Schüler*in'; html += 'Seit'; + html += '🎯 Leistung'; fields.forEach(function(f) { var align = f.align || 'right'; html += ''+esc(f.label)+(f.unit?' '+f.unit+'':'')+''; @@ -1596,6 +1646,7 @@ async function renderLive() { html += ''; html += ''+(help?'🆘':(paused?'':''))+avatarHtml+''+esc(ls.displayName)+''; html += '
'+missionStr+'
'+simStr+' ges.
'; + html += ''+_pctBar(_leistungPct(ls.module_id, s))+''; fields.forEach(function(f) { var align = f.align || 'right'; var cell = _liveFmt(s[f.k], f.unit, f, ls); @@ -1705,10 +1756,7 @@ function _liveSuccessColor(success) { })[success] || '#7a8a9c'; } // Ampelfarbe für den Tages-Erfolg (0–100): grün → hellgrün → gelb → orange → rot. -function _tagTraffic(v) { - v = Math.max(0, Math.min(100, v || 0)); - return v >= 80 ? '#1f7a3d' : v >= 65 ? '#7cb342' : v >= 50 ? '#f9c33b' : v >= 35 ? '#ef8b2c' : '#d8453a'; -} +function _tagTraffic(v) { return _pctColor(v); } // EINE Skala (siehe _pctColor) function _liveSuccessIcon(stars, success) { if (success === 'aborted') return '✗'; if (success === 'running') return '⏳';