Atlas: Phase A Integrations-Konzept + Cockpit + End-Screen
- Integrations-Konzept dokumentiert (App/docs/integration-konzept.md) - Module-IDs vereinheitlicht: sim-XX -> semantische IDs (klima/heli/fluss/logistik/...) - class_modules um current_level + quiz_enabled Spalten erweitert - modules.php liefert dynamisch aus module_info, inkl. forcedLevel, quizEnabled, play_url, dueDate; neuer Filter ?module_id=X fuer einzeln - schueler.html Cockpit: komplett API-first, teacher_started-Sektion als Auftrags-Block, neue IDs, Sprachregel 4a (Starten statt Spielen) - teacher.html: Hardcoded ALL_MODS entfernt, laedt dynamisch - Design-System: .ggs-endscreen-Komponente fuer einheitliche Modul-Abschluesse - index.html Landing-Links gefixt: App/modul-X -> modul-X, V1-HTMLs auf Front-Controller-Routen (fluss, heli-game, stadt) - 6 Inbox-Auftraege an Instanzen (Klima/Heli/Fluss/Logistik/Lehrplan/Glossar) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+33
-16
@@ -9,17 +9,15 @@
|
||||
$method = $_SERVER['REQUEST_METHOD'];
|
||||
$db = Database::get();
|
||||
|
||||
$ALL_MODULES = [
|
||||
['id' => 'sim-05', 'name' => 'Klimawächter 2D', 'desc' => 'Treibhauseffekt-Simulation', 'icon' => '🌡️'],
|
||||
['id' => 'sim-05-3d', 'name' => 'Klimawächter 3D', 'desc' => '3D-Klimasimulation', 'icon' => '🌊'],
|
||||
['id' => 'sim-07', 'name' => 'Erdbeben', 'desc' => 'Plattentektonik & Stadtplanung', 'icon' => '🌋'],
|
||||
['id' => 'sim-09', 'name' => 'Energiemix', 'desc' => 'Energiewende planen', 'icon' => '⚡'],
|
||||
['id' => 'sim-10', 'name' => 'Lieferketten', 'desc' => 'Globale Lieferketten', 'icon' => '👕'],
|
||||
['id' => 'sim-11', 'name' => 'Regenwald', 'desc' => 'Regenwald-Expedition', 'icon' => '🌴'],
|
||||
['id' => 'sim-12', 'name' => 'Flussmanagement', 'desc' => 'Fluss & Hochwasserschutz', 'icon' => '🏞️'],
|
||||
['id' => 'sim-13', 'name' => 'Stadt & Raumplanung', 'desc' => 'Stadtsimulation mit Kacheln', 'icon' => '🏗️'],
|
||||
['id' => 'sim-14', 'name' => 'Helikopter-Navigation', 'desc' => 'Rettungshubschrauber steuern', 'icon' => '🚁'],
|
||||
];
|
||||
// Modul-Katalog dynamisch aus module_info (Source of Truth)
|
||||
// Nur aktive + beta + geplante Module anzeigen (keine archivierten)
|
||||
$ALL_MODULES = $db->fetchAll(
|
||||
"SELECT module_id AS id, title AS name, short_desc AS `desc`, icon,
|
||||
status, play_url, sort_order
|
||||
FROM module_info
|
||||
WHERE status IN ('aktiv','beta','geplant')
|
||||
ORDER BY sort_order, title"
|
||||
);
|
||||
|
||||
if ($method === 'GET') {
|
||||
// Schüler*innen-Ansicht: welche Module sind für mich freigeschaltet?
|
||||
@@ -36,11 +34,12 @@ if ($method === 'GET') {
|
||||
}
|
||||
$classId = $session['class_id'];
|
||||
$classMap = [];
|
||||
$settings = $db->fetchAll('SELECT module_id, mode FROM class_modules WHERE class_id = ?', [$classId]);
|
||||
foreach ($settings as $s) $classMap[$s['module_id']] = $s['mode'];
|
||||
$settings = $db->fetchAll(
|
||||
'SELECT module_id, mode, current_level, quiz_enabled, due_date
|
||||
FROM class_modules WHERE class_id = ?', [$classId]);
|
||||
foreach ($settings as $s) $classMap[$s['module_id']] = $s;
|
||||
|
||||
// Individuelle Overrides für diesen Schüler
|
||||
// Finde student_id aus session
|
||||
$studentRow = $db->fetchOne(
|
||||
'SELECT s.id FROM students s JOIN student_sessions ss ON ss.class_id = s.class_id AND ss.display_name = s.display_name WHERE ss.id = ?',
|
||||
[$sessionId]
|
||||
@@ -51,10 +50,28 @@ if ($method === 'GET') {
|
||||
foreach ($rows as $r) $overrides[$r['module_id']] = $r['mode'];
|
||||
}
|
||||
|
||||
// Einzelner Modul-Filter
|
||||
$filterId = $_GET['module_id'] ?? null;
|
||||
|
||||
$result = [];
|
||||
foreach ($ALL_MODULES as $mod) {
|
||||
$mode = $overrides[$mod['id']] ?? $classMap[$mod['id']] ?? 'locked';
|
||||
$result[] = ['id' => $mod['id'], 'name' => $mod['name'], 'icon' => $mod['icon'], 'mode' => $mode];
|
||||
if ($filterId && $mod['id'] !== $filterId) continue;
|
||||
$cm = $classMap[$mod['id']] ?? null;
|
||||
$mode = $overrides[$mod['id']] ?? ($cm['mode'] ?? 'locked');
|
||||
$result[] = [
|
||||
'id' => $mod['id'],
|
||||
'name' => $mod['name'],
|
||||
'icon' => $mod['icon'],
|
||||
'play_url' => $mod['play_url'],
|
||||
'mode' => $mode,
|
||||
'forcedLevel' => ($mode === 'teacher_started' && $cm) ? (int)($cm['current_level'] ?? 1) : null,
|
||||
'quizEnabled' => (bool)($cm['quiz_enabled'] ?? 0),
|
||||
'dueDate' => $cm['due_date'] ?? null,
|
||||
];
|
||||
}
|
||||
// Wenn einzelnes Modul, liefere Objekt statt Array
|
||||
if ($filterId) {
|
||||
Response::ok($result[0] ?? ['id' => $filterId, 'mode' => 'locked', 'error' => 'not_found']);
|
||||
}
|
||||
Response::ok($result);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user