Übersicht: Empfehlung nur aus AKTUELLER Leistung (Recency)
Denkfehler behoben — eine Empfehlung reagiert auf das Zuletzt-Gesehene, nicht auf einen Allzeit-Rückblick. live.php cockpit liefert jetzt recentErfolg (Ø letzte 3 Läufe), earlyErfolg (frühere Läufe), daysSince, recentPlays. Triage rechnet darauf: >14 Tage weg → Nachfassen; recent schwach → Fördern; recent+viel → Begleiten; recent stark, kaum gefordert → Fordern; recent > früher → Bestätigen. Neue Spalte „Zuletzt", Legende erklärt: Erfolg = letzte Läufe, Verlauf = nur Historie. 4b-Daten mit kontrollierter Recency neu (jede Gruppe besetzt). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+39
-24
@@ -2111,9 +2111,10 @@ var IV_CSS = ''
|
||||
+ '.iv-ic svg{width:19px;height:19px;stroke:currentColor;stroke-width:1.9;fill:none;stroke-linecap:round;stroke-linejoin:round}'
|
||||
+ '.iv-ct{flex:1}.iv-ct h4{margin:0;font-size:.9rem;font-weight:750;color:var(--iva)}.iv-ct p{margin:0;font-size:.72rem;color:var(--ivmut)}'
|
||||
+ '.iv-cn{font-size:1.05rem;font-weight:750;color:var(--iva)}'
|
||||
+ '.iv-cols{display:grid;grid-template-columns:78px 1fr 30px 58px 14px;gap:9px;padding:0 8px 3px;font-size:.54rem;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--ivmut);border-bottom:1px solid var(--ivline)}'
|
||||
+ '.iv-cols span:nth-child(2){justify-self:end}.iv-cols span:nth-child(3),.iv-cols span:nth-child(4){justify-self:center}'
|
||||
+ '.iv-prow{display:grid;grid-template-columns:78px 1fr 30px 58px 14px;gap:9px;align-items:center;width:100%;text-align:left;cursor:pointer;background:none;border:0;border-radius:8px;padding:7px 8px;font:inherit;color:inherit}'
|
||||
+ '.iv-cols{display:grid;grid-template-columns:72px 1fr 28px 50px 46px 14px;gap:9px;padding:0 8px 3px;font-size:.52rem;font-weight:700;text-transform:uppercase;letter-spacing:.03em;color:var(--ivmut);border-bottom:1px solid var(--ivline)}'
|
||||
+ '.iv-cols span:nth-child(2){justify-self:end}.iv-cols span:nth-child(3),.iv-cols span:nth-child(4){justify-self:center}.iv-cols span:nth-child(5){justify-self:end}'
|
||||
+ '.iv-prow{display:grid;grid-template-columns:72px 1fr 28px 50px 46px 14px;gap:9px;align-items:center;width:100%;text-align:left;cursor:pointer;background:none;border:0;border-radius:8px;padding:7px 8px;font:inherit;color:inherit}'
|
||||
+ '.iv-last{justify-self:end;font-size:.7rem;color:var(--ivmut);white-space:nowrap}.iv-last-old{color:var(--ivr);font-weight:700}'
|
||||
+ '.iv-prow:hover{background:var(--ivsoft)}'
|
||||
+ '.iv-nm{font-size:.86rem;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}'
|
||||
+ '.iv-erf{display:flex;align-items:center;gap:7px;justify-self:end}.iv-ebar{width:70px;height:9px;border-radius:5px;background:var(--ivtrack);overflow:hidden}.iv-ebar>i{display:block;height:100%;border-radius:5px}.iv-erf b{font-size:.78rem;font-weight:700;width:1.7em}'
|
||||
@@ -2161,18 +2162,27 @@ var IV_ICON={
|
||||
work:'<circle cx="12" cy="12" r="9"/><path d="m15 9-3.6 1.4L10 14l3.6-1.4L15 9Z"/>',
|
||||
good:'<path d="m4 15 5-5 4 4 7-8"/><path d="M17 6h3v3"/>',
|
||||
idle:'<circle cx="12" cy="12" r="9" stroke-dasharray="3 3"/><path d="M12 8v4l2 2"/>'};
|
||||
var IV_META={support:['Fördern','strengen sich an, kommen nicht weiter','--ivns'],more:['Fordern','lösen sicher, kaum ausgelastet','--ivnm'],
|
||||
work:['Begleiten','viel Aktivität, wenig Ertrag','--ivnw'],good:['Bestätigen','noch nicht am Ziel, aber im Aufwind','--ivngd'],idle:['Beteiligen','kaum Daten – zuerst ins Arbeiten holen','--ivni']};
|
||||
var IV_META={support:['Fördern','zuletzt schwächere Läufe','--ivns'],more:['Fordern','zuletzt sicher, kaum gefordert','--ivnm'],
|
||||
work:['Begleiten','zuletzt viel gearbeitet, wenig Ertrag','--ivnw'],good:['Bestätigen','zuletzt besser geworden','--ivngd'],idle:['Nachfassen','länger nicht mehr dran (oder noch nie)','--ivni']};
|
||||
|
||||
// Triage-Zuordnung aus Erfolg (benchmarkPct) × Beteiligung (plays) + Verlaufs-Trend.
|
||||
function ivTriage(erfolg, plays, rising){
|
||||
if (plays < 2 || erfolg==null) return 'idle';
|
||||
if (erfolg < 48 && plays >= 9) return 'work';
|
||||
if (erfolg < 48) return 'support';
|
||||
if (erfolg >= 65 && plays < 6) return 'more';
|
||||
if (erfolg < 65 && rising) return 'good';
|
||||
// Triage NUR aus der AKTUELLEN Leistung (Empfehlung = Reaktion auf das Zuletzt-
|
||||
// Gesehene, kein Allzeit-Rückblick): recentErfolg = Ø letzte 3 Läufe, daysSince =
|
||||
// Tage seit letztem Lauf, recentPlays = Läufe der letzten 14 Tage, rising =
|
||||
// zuletzt besser als der bisherige Schnitt.
|
||||
function ivTriage(recErf, daysSince, recentPlays, rising){
|
||||
if (daysSince == null || daysSince > 14) return 'idle'; // länger nicht dran / nie
|
||||
if (recErf == null) return 'idle';
|
||||
if (recErf < 48 && recentPlays >= 5) return 'work'; // zuletzt viel, wenig Ertrag
|
||||
if (recErf < 48) return 'support'; // zuletzt schwach
|
||||
if (recErf >= 65 && recentPlays <= 2) return 'more'; // zuletzt sicher, kaum gefordert
|
||||
if (rising) return 'good'; // zuletzt besser geworden
|
||||
return null; // läuft rund
|
||||
}
|
||||
function ivZuletzt(days){
|
||||
if (days == null) return '<span class="iv-last iv-last-old">nie</span>';
|
||||
var t = days<=0 ? 'heute' : (days==1 ? 'gestern' : 'vor '+days+' T');
|
||||
return '<span class="iv-last'+(days>14?' iv-last-old':'')+'">'+t+'</span>';
|
||||
}
|
||||
|
||||
function ivBuildOverview(cockpit, weeks, studentsCount, matrix){
|
||||
ivInjectCss();
|
||||
@@ -2188,17 +2198,19 @@ function ivBuildOverview(cockpit, weeks, studentsCount, matrix){
|
||||
|
||||
var groups={support:[],more:[],work:[],good:[],idle:[]}, calm=[], erfSum=0,erfN=0, weekTotals=[];
|
||||
cs.forEach(function(s){
|
||||
var sid=s.studentId||s.id, erf=(s.benchmarkPct!=null)?s.benchmarkPct:null, plays=playsById[sid]||0;
|
||||
var sid=s.studentId||s.id;
|
||||
var recErf=(s.recentErfolg!=null)?s.recentErfolg:null; // Ø letzte 3 Läufe
|
||||
var allErf=(s.benchmarkPct!=null)?s.benchmarkPct:null; // Allzeit (nur für „rising")
|
||||
var days=(s.daysSince!=null)?s.daysSince:null;
|
||||
var rplays=s.recentPlays||0;
|
||||
var w=wById[sid], secs=w?w.buckets.map(function(b){return Math.min(IV_WEEK_CAP, b.sum||0);}):[];
|
||||
while(secs.length<10) secs.unshift(0);
|
||||
secs.forEach(function(v){ if(v>maxSec) maxSec=v; });
|
||||
// Trend: Mittel letzte 3 vs erste 3
|
||||
var last3=secs.slice(-3).reduce(function(a,b){return a+b;},0), first3=secs.slice(0,3).reduce(function(a,b){return a+b;},0);
|
||||
var rising = last3>first3*1.2 && last3>0;
|
||||
if(erf!=null){ erfSum+=erf; erfN++; }
|
||||
var rising=(recErf!=null && s.earlyErfolg!=null && recErf > s.earlyErfolg+10); // letzte 3 besser als frühere
|
||||
if(recErf!=null){ erfSum+=recErf; erfN++; }
|
||||
weekTotals.push(secs);
|
||||
var g=ivTriage(erf,plays,rising);
|
||||
var row={name:s.displayName,erf:erf,status:s.status,secs:secs};
|
||||
var g=ivTriage(recErf, days, rplays, rising);
|
||||
var row={name:s.displayName, erf:recErf, status:s.status, secs:secs, days:days};
|
||||
if(g) groups[g].push(row); else calm.push(s.displayName);
|
||||
});
|
||||
|
||||
@@ -2215,7 +2227,7 @@ function ivBuildOverview(cockpit, weeks, studentsCount, matrix){
|
||||
h+='<div class="iv-h1">Klassenübersicht</div>';
|
||||
// Stat-Karten
|
||||
h+='<div class="iv-stats">';
|
||||
h+='<div class="iv-stat"><span class="iv-lab">Erfolg Klassenschnitt</span><div class="iv-gfx"><span class="iv-ebar2 '+(erfAvg!=null?ivAmp(erfAvg):'')+'"><i style="width:'+(erfAvg||0)+'%"></i></span><span class="iv-bign num" style="font-size:1.05rem">'+(erfAvg!=null?erfAvg:'–')+'</span></div><span class="iv-exp">0 – 100, Mittel über alle Module</span></div>';
|
||||
h+='<div class="iv-stat"><span class="iv-lab">Erfolg Klassenschnitt</span><div class="iv-gfx"><span class="iv-ebar2 '+(erfAvg!=null?ivAmp(erfAvg):'')+'"><i style="width:'+(erfAvg||0)+'%"></i></span><span class="iv-bign num" style="font-size:1.05rem">'+(erfAvg!=null?erfAvg:'–')+'</span></div><span class="iv-exp">0 – 100, aus den letzten Läufen</span></div>';
|
||||
h+='<div class="iv-stat"><span class="iv-lab">Aktuell aktiv</span><div class="iv-gfx"><span class="iv-stripe"><i class="iv-g" style="width:'+(aktiv/tot*100)+'%"></i><i class="iv-y" style="width:'+(idle/tot*100)+'%"></i><i class="iv-r" style="width:'+(rest/tot*100)+'%"></i></span></div><span class="iv-exp">'+aktiv+' aktiv · '+idle+' teilweise · '+rest+' inaktiv</span></div>';
|
||||
h+='<div class="iv-stat"><span class="iv-lab">Verlauf Klassenschnitt<span class="iv-maxv">max <b class="num">'+maxLabel+'</b></span></span><div class="iv-gfx"><span class="iv-cav">'+classWeeks.map(function(sec){var frac=sec/classMax;var cls=sec<=0?'iv-z':(frac<.2?'iv-r':frac<.4?'iv-o':frac<.62?'iv-y':frac<.82?'iv-li':'iv-g');return '<i class="'+cls+'" style="height:'+Math.max(2,Math.round(frac*30))+'px"></i>';}).join('')+'</span></div><span class="iv-exp">aktive Zeit pro Woche · 10 Wochen</span></div>';
|
||||
h+='<div class="iv-stat"><span class="iv-lab">Schüler:innen</span><div class="iv-gfx"><span class="iv-bign num">'+studentsCount+'</span></div><span class="iv-exp">'+aktiv+' gerade aktiv</span></div>';
|
||||
@@ -2228,9 +2240,9 @@ function ivBuildOverview(cockpit, weeks, studentsCount, matrix){
|
||||
var rows=groups[key]; if(!rows.length) return;
|
||||
var m=IV_META[key];
|
||||
h+='<div class="iv-card" style="--iva:var('+m[2]+')"><div class="iv-chead"><span class="iv-ic"><svg viewBox="0 0 24 24">'+IV_ICON[key]+'</svg></span><div class="iv-ct"><h4>'+m[0]+'</h4><p>'+m[1]+'</p></div><span class="iv-cn num">'+rows.length+'</span></div>';
|
||||
h+='<div class="iv-cols"><span></span><span title="Wie gut die Sim gemeistert wird, 0–100">Erfolg</span><span title="arbeitet gerade? blinkt live">Aktiv</span><span title="aktive Zeit pro Woche">Verlauf</span><span></span></div>';
|
||||
h+='<div class="iv-cols"><span></span><span title="Ø der letzten 3 Läufe, 0–100">Erfolg</span><span title="arbeitet gerade? blinkt live">Aktiv</span><span title="aktive Zeit pro Woche">Verlauf</span><span title="Tage seit dem letzten Lauf">Zuletzt</span><span></span></div>';
|
||||
rows.forEach(function(r){
|
||||
h+='<button class="iv-prow" onclick="switchTab(\'results\')"><span class="iv-nm">'+esc(r.name)+'</span><span style="display:contents">'+ivErf(r.erf)+ivAkt(r.status)+ivSpark(r.secs,maxSec,IV_WEEK_CAP)+'</span><svg class="iv-chev" viewBox="0 0 24 24"><path d="m9 6 6 6-6 6"/></svg></button>';
|
||||
h+='<button class="iv-prow" onclick="switchTab(\'results\')"><span class="iv-nm">'+esc(r.name)+'</span><span style="display:contents">'+ivErf(r.erf)+ivAkt(r.status)+ivSpark(r.secs,maxSec,IV_WEEK_CAP)+'</span>'+ivZuletzt(r.days)+'<svg class="iv-chev" viewBox="0 0 24 24"><path d="m9 6 6 6-6 6"/></svg></button>';
|
||||
});
|
||||
h+='</div>';
|
||||
});
|
||||
@@ -2238,13 +2250,16 @@ function ivBuildOverview(cockpit, weeks, studentsCount, matrix){
|
||||
if(calm.length) h+='<div class="iv-calm"><span class="iv-dot"></span><span><b>Läuft rund — '+calm.length+'</b></span><span class="iv-names">'+calm.map(esc).join(' · ')+'</span></div>';
|
||||
// Legende
|
||||
h+='<div class="iv-legend">'
|
||||
+'<div><b>Erfolg</b> Wie gut die Simulation gemeistert wird, 0 – 100. Normiert: 0 = gescheitert, 100 = „sehr gut" (90 % des Bestwerts). Beispiel: <b style="color:#2f3a34">56</b> = solide über dem Durchschnitt.'
|
||||
+'<div style="grid-column:1/-1;font-size:.72rem;color:#8a8a8a;margin-bottom:-.2rem">Die <b>Empfehlung</b> beruht nur auf der <b>aktuellen</b> Leistung: dem Erfolg der letzten Läufe und den Tagen seit dem letzten Mal. Der Verlauf daneben ist nur Historie.</div>'
|
||||
+'<div><b>Erfolg</b> Ø der <b>letzten 3 Läufe</b> (aktueller Stand), 0 – 100: 0 = gescheitert, 100 = „sehr gut". Alte Durchläufe zählen für die Empfehlung nicht mehr mit.'
|
||||
+'<div class="iv-lgrow"><span class="iv-lgbar"></span><span>rot → grün</span></div></div>'
|
||||
+'<div><b>Zuletzt</b> Tage seit dem letzten Lauf. Wer <b>länger als 14 Tage</b> nicht mehr dran war (oder noch nie), landet bei „Nachfassen" — unabhängig von früheren Werten.'
|
||||
+'<div class="iv-lgrow"><span class="iv-last">heute</span><span style="color:#cbc6b8">·</span><span class="iv-last iv-last-old">vor 20 T</span></div></div>'
|
||||
+'<div><b>Aktuell aktiv</b> Interaktionen der letzten Minuten, live. Blinkt bei jeder Eingabe.'
|
||||
+'<div class="iv-lgrow"><span class="iv-lgdot" style="background:var(--ivg)"></span>aktiv'
|
||||
+'<span class="iv-lgdot" style="background:var(--ivy)"></span>teilweise'
|
||||
+'<span class="iv-lgdot" style="background:var(--ivr)"></span>inaktiv (10 Min nichts)</div></div>'
|
||||
+'<div><b>Verlauf</b> Aktive Zeit pro Woche, letzte 10 Wochen, gleiches Raster für alle. Farbe = Aktivität der Woche; rote Kappe = bei 3 h gedeckelt.'
|
||||
+'<div><b>Verlauf</b> Aktive Zeit pro Woche, letzte 10 Wochen — nur <b>Historie</b>, nicht Grundlage der Empfehlung. Rote Kappe = bei 3 h gedeckelt.'
|
||||
+'<div class="iv-lgrow"><span class="iv-lgv"><i class="iv-r" style="height:4px"></i><i class="iv-o" style="height:6px"></i><i class="iv-y" style="height:9px"></i><i class="iv-li" style="height:11px"></i><i class="iv-g" style="height:14px"></i></span><span>wenig → viel</span></div></div>'
|
||||
+'</div>';
|
||||
h+='</div>';
|
||||
|
||||
Reference in New Issue
Block a user