From bfc90b78deca9aebf7f7bacdd1daaaba1f982d67 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 20 Jul 2026 21:22:50 +0200 Subject: [PATCH] Modul-Uebersicht: relevante Kennzahlen pro App korrigiert + Quoten Alle $MODULE_HIGHLIGHTS gegen echte Daten (Klasse 102) verifiziert und auf die tatsaechlichen Feldnamen umgestellt (viele waren veraltet/leer, z.B. farmer, sonnensystem, energiemanager, busfahrt, logistik, heli, tourismus*). - kofferdetektiv NEU: Geloest-Quote, Erstversuch, Fehlversuche, Oe Hinweise - weltkueche/fluss NEU - fluggesellschaft NEU (aus Submit-Schema) - Berechnete Quoten via num/den -> Prozent (Erfolgsquote statt Rohzahl): kofferdetektiv, weltkueche, busfahrt, logistik, energiemanager, eu-werkstatt, sonnensystem, tourismustal, fluggesellschaft - heli: Planung/Start/Landung/Level; sim-metrics: Level + Oe Hinweise ergaenzt Co-Authored-By: Claude Opus 4.8 --- App/assets/js/sim-metrics.js | 4 +- App/php/api/results.php | 116 +++++++++++++++++++++-------------- 2 files changed, 73 insertions(+), 47 deletions(-) diff --git a/App/assets/js/sim-metrics.js b/App/assets/js/sim-metrics.js index e03bbbe..0592822 100644 --- a/App/assets/js/sim-metrics.js +++ b/App/assets/js/sim-metrics.js @@ -30,6 +30,7 @@ {k:'planPct',type:'pct',l:'Planung'}, {k:'startScore',type:'starsSmall',l:'Start'}, {k:'landingScore',type:'starsSmall',l:'Landung'}, + {k:'level',type:'num',l:'Level'}, {k:'missionTitle',type:'text',l:'Mission'}, {k:'failed',type:'boolInv',l:'geschafft'} ], @@ -84,7 +85,8 @@ kofferdetektiv: [ {k:'cases_solved',type:'ratio',t:'cases_total',l:'Fälle gelöst'}, {k:'correct_first_try',type:'num',l:'Erstversuch'}, - {k:'wrong_guesses',type:'num',l:'Fehlversuche',dir:'lo'} + {k:'wrong_guesses',type:'num',l:'Fehlversuche',dir:'lo'}, + {k:'hints_used_avg',type:'num',l:'Ø Hinweise',dir:'lo'} ], tourismustal: [ {k:'goalsDone',type:'ratio',t:'goalsTotal',l:'Ziele erreicht'}, diff --git a/App/php/api/results.php b/App/php/api/results.php index b423726..074a176 100644 --- a/App/php/api/results.php +++ b/App/php/api/results.php @@ -25,9 +25,11 @@ if ($_SERVER['REQUEST_METHOD'] !== 'GET') { $teacherId = Session::requireTeacher(); $db = Database::get(); -// Pro Modul die wichtigsten Felder aus assessments.results-JSON. -// agg = min|max ("besser ist niedriger" vs "besser ist höher") -// format = percent|integer (Anzeige-Hint), unit = optionale Einheit hinter dem Wert. +// Pro Modul die wichtigsten Kennzahlen aus assessments.results-JSON (verifiziert +// gegen echte Daten, Klasse 102). agg = min|max ("besser niedriger/höher"). +// Berechnete Quote: statt 'key' → 'num'+'den' (Wert = num/den·100, in %). +// unit = Einheit hinter dem Wert. HINWEIS: Feldnamen konsistent mit dem +// Client-Schema SIM_METRICS in App/assets/js/sim-metrics.js halten. $MODULE_HIGHLIGHTS = [ 'klima' => [ ['key'=>'final_co2', 'label'=>'CO₂', 'agg'=>'min', 'unit'=>'ppm'], @@ -35,60 +37,74 @@ $MODULE_HIGHLIGHTS = [ ['key'=>'final_budget', 'label'=>'Budget', 'agg'=>'max', 'unit'=>'Mio'], ['key'=>'final_flooded_pct', 'label'=>'Überflutet','agg'=>'min', 'unit'=>'%'], ], - 'klima-3d' => [ - ['key'=>'final_co2', 'label'=>'CO₂', 'agg'=>'min', 'unit'=>'ppm'], - ['key'=>'final_temperature', 'label'=>'ΔTemp', 'agg'=>'min', 'unit'=>'°C'], - ['key'=>'final_budget', 'label'=>'Budget', 'agg'=>'max', 'unit'=>'Mio'], - ['key'=>'final_flooded_pct', 'label'=>'Überflutet','agg'=>'min', 'unit'=>'%'], + 'kofferdetektiv' => [ + ['key'=>'solve_quote', 'num'=>'cases_solved', 'den'=>'cases_total', 'label'=>'Gelöst-Quote', 'agg'=>'max', 'unit'=>'%'], + ['key'=>'correct_first_try', 'label'=>'Erstversuch', 'agg'=>'max'], + ['key'=>'wrong_guesses', 'label'=>'Fehlversuche', 'agg'=>'min'], + ['key'=>'hints_used_avg', 'label'=>'Ø Hinweise', 'agg'=>'min'], + ], + 'weltkueche' => [ + ['key'=>'dish_quote', 'num'=>'completedDishes', 'den'=>'totalDishes', 'label'=>'Gerichte-Quote', 'agg'=>'max', 'unit'=>'%'], + ['key'=>'mistakesInDish', 'label'=>'Fehlklicks', 'agg'=>'min'], + ], + 'fluss' => [ + ['key'=>'biodiv', 'label'=>'Biodiversität', 'agg'=>'max', 'unit'=>'%'], + ['key'=>'economy', 'label'=>'Wirtschaft', 'agg'=>'max', 'unit'=>'%'], + ['key'=>'flood', 'label'=>'Hochwasser', 'agg'=>'min', 'unit'=>'%'], + ['key'=>'food', 'label'=>'Ernährung', 'agg'=>'max', 'unit'=>'%'], ], 'farmer' => [ - ['key'=>'results.money', 'label'=>'Geld', 'agg'=>'max', 'unit'=>'€'], - ['key'=>'results.success_rate', 'label'=>'Trefferquote','agg'=>'max','format'=>'percent'], - ['key'=>'results.year_reached', 'label'=>'Jahr', 'agg'=>'max'], - ['key'=>'results.co2_kg', 'label'=>'CO₂', 'agg'=>'min', 'unit'=>'kg'], - ['key'=>'results.crops_used', 'label'=>'Sorten', 'agg'=>'max'], - ], - 'eu-werkstatt' => [ - ['key'=>'firstTryHits', 'label'=>'Erste Wahl','agg'=>'max'], - ['key'=>'totalAttempts', 'label'=>'Versuche', 'agg'=>'min'], - ['key'=>'muelleimerCount','label'=>'Mülleimer', 'agg'=>'min'], - ], - 'sonnensystem' => [ - ['key'=>'firstTryHits', 'label'=>'Erste Wahl','agg'=>'max'], - ['key'=>'totalAttempts', 'label'=>'Versuche', 'agg'=>'min'], - ], - 'energiemanager' => [ - ['key'=>'blocksCorrect', 'label'=>'Blöcke ok', 'agg'=>'max'], - ['key'=>'deficit', 'label'=>'Defizit', 'agg'=>'min'], + ['key'=>'hit_rate', 'label'=>'Trefferquote', 'agg'=>'max', 'unit'=>'%'], + ['key'=>'year', 'label'=>'Jahr', 'agg'=>'max'], + ['key'=>'crops_used', 'label'=>'Sorten', 'agg'=>'max'], ], 'busfahrt' => [ - ['key'=>'cities_correct', 'label'=>'Treffer', 'agg'=>'max'], - ['key'=>'tries_avg', 'label'=>'Ø Versuche','agg'=>'min'], + ['key'=>'order_quote', 'num'=>'wonOrders', 'den'=>'totalOrders', 'label'=>'Aufträge', 'agg'=>'max', 'unit'=>'%'], + ['key'=>'quiz_quote', 'num'=>'quizFirstTry', 'den'=>'totalOrders', 'label'=>'Quiz 1. Versuch','agg'=>'max', 'unit'=>'%'], + ['key'=>'avgTapKm', 'label'=>'Ø Abweichung', 'agg'=>'min', 'unit'=>'km'], ], 'logistik' => [ - ['key'=>'contracts_done', 'label'=>'Aufträge', 'agg'=>'max'], - ['key'=>'co2_total', 'label'=>'CO₂', 'agg'=>'min', 'unit'=>'kg'], - ['key'=>'profit', 'label'=>'Gewinn', 'agg'=>'max', 'unit'=>'€'], + ['key'=>'deliver_quote', 'num'=>'ordersDelivered', 'den'=>'totalOrders', 'label'=>'Geliefert', 'agg'=>'max', 'unit'=>'%'], + ['key'=>'ordersLate', 'label'=>'Verspätet', 'agg'=>'min'], + ['key'=>'finalBalance', 'label'=>'Bilanz', 'agg'=>'max', 'unit'=>'€'], + ], + 'energiemanager' => [ + ['key'=>'block_quote', 'num'=>'blocksBalanced', 'den'=>'blocksTotal', 'label'=>'Blöcke ok', 'agg'=>'max', 'unit'=>'%'], + ['key'=>'day_quote', 'num'=>'daysPlayed', 'den'=>'daysTotal', 'label'=>'Tage geschafft','agg'=>'max', 'unit'=>'%'], + ['key'=>'totalGap', 'label'=>'Restdefizit', 'agg'=>'min'], + ], + 'eu-werkstatt' => [ + ['key'=>'firsttry_quote', 'num'=>'firstTryHits', 'den'=>'stepsTotal', 'label'=>'Erste Wahl', 'agg'=>'max', 'unit'=>'%'], + ['key'=>'totalAttempts', 'label'=>'Versuche', 'agg'=>'min'], + ['key'=>'muelleimerCount','label'=>'Verworfen', 'agg'=>'min'], + ], + 'sonnensystem' => [ + ['key'=>'task_quote', 'num'=>'completed', 'den'=>'total', 'label'=>'Gelöst-Quote', 'agg'=>'max', 'unit'=>'%'], + ['key'=>'completed', 'label'=>'Aufgaben', 'agg'=>'max'], ], 'heli' => [ - ['key'=>'routes_completed','label'=>'Routen', 'agg'=>'max'], - ['key'=>'avg_accuracy', 'label'=>'Genauigkeit','agg'=>'max','format'=>'percent'], - ], - 'tourismusregion' => [ - ['key'=>'results.score', 'label'=>'Score', 'agg'=>'max'], - ['key'=>'results.avgStars', 'label'=>'Ø Sterne', 'agg'=>'max'], - ['key'=>'results.revenue', 'label'=>'Wertschöpfung','agg'=>'max', 'unit'=>'€'], - ['key'=>'results.env', 'label'=>'Umwelt', 'agg'=>'max'], - ['key'=>'results.goalsDone','label'=>'Ziele', 'agg'=>'max'], + ['key'=>'planPct', 'label'=>'Planung', 'agg'=>'max', 'unit'=>'%'], + ['key'=>'startScore', 'label'=>'Start', 'agg'=>'max'], + ['key'=>'landingScore', 'label'=>'Landung', 'agg'=>'max'], + ['key'=>'level', 'label'=>'Level', 'agg'=>'max'], ], 'tourismustal' => [ - ['key'=>'results.money', 'label'=>'Konto', 'agg'=>'max', 'unit'=>'€'], - ['key'=>'results.maxGuests', 'label'=>'Gäste-Rekord','agg'=>'max'], - ['key'=>'results.maxSummerGuests', 'label'=>'Sommer-Rekord','agg'=>'max'], - ['key'=>'results.nature', 'label'=>'Naturwert', 'agg'=>'max', 'unit'=>'%'], - ['key'=>'results.goalsDone', 'label'=>'Ziele', 'agg'=>'max'], + ['key'=>'goal_quote', 'num'=>'goalsDone', 'den'=>'goalsTotal', 'label'=>'Ziele', 'agg'=>'max', 'unit'=>'%'], + ['key'=>'satisfaction', 'label'=>'Zufriedenheit', 'agg'=>'max', 'unit'=>'%'], + ['key'=>'nature', 'label'=>'Naturwert', 'agg'=>'max', 'unit'=>'%'], + ['key'=>'money', 'label'=>'Konto', 'agg'=>'max', 'unit'=>'€'], + ], + 'tourismusregion' => [ + ['key'=>'score', 'label'=>'Gesamtscore', 'agg'=>'max', 'unit'=>'%'], + ], + 'fluggesellschaft' => [ + ['key'=>'flight_order_quote', 'num'=>'wonOrders', 'den'=>'totalOrders', 'label'=>'Aufträge', 'agg'=>'max', 'unit'=>'%'], + ['key'=>'flight_quiz_quote', 'num'=>'quizFirstTry', 'den'=>'totalOrders', 'label'=>'Quiz 1. Versuch','agg'=>'max', 'unit'=>'%'], + ['key'=>'co2Kg', 'label'=>'CO₂', 'agg'=>'min', 'unit'=>'kg'], + ['key'=>'earnings', 'label'=>'Gewinn', 'agg'=>'max', 'unit'=>'€'], ], ]; +$MODULE_HIGHLIGHTS['klima-3d'] = $MODULE_HIGHLIGHTS['klima']; // Hilfsfunktion: holt einen Wert aus einem JSON-Pfad ("results.money" → $json['results']['money']). function _hl_get($json, $path) { @@ -650,7 +666,15 @@ if ($view === 'module') { if (!is_array($j)) continue; if (!isset($perStudent[$sid])) $perStudent[$sid] = []; foreach ($highlights as $h) { - $val = _hl_get($j, $h['key']); + if (isset($h['num'])) { + // Berechnete Quote: num/den in Prozent (0..100) + $nu = _hl_get($j, $h['num']); + $de = _hl_get($j, $h['den']); + $val = ($nu !== null && $de !== null && (float)$de != 0.0) + ? round((float)$nu / (float)$de * 100) : null; + } else { + $val = _hl_get($j, $h['key']); + } if ($val === null) continue; $val = is_numeric($val) ? (float)$val : $val; if (!isset($perStudent[$sid][$h['key']])) {