From 15ac35a7ad1794ec9cda2b5ed24c4344ea8d1d40 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 20 Jul 2026 13:17:22 +0200 Subject: [PATCH] =?UTF-8?q?Lehrer-=C3=9Cbersicht:=20Interventions-Block=20?= =?UTF-8?q?(Erfolg/Aktiv/Verlauf=20+=20Triage)=20live?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Neuer Block oben im Übersicht-Tab: 5 Stat-Karten (Erfolg-Klassenschnitt, Aktuell aktiv als Streifen, Verlauf-Klassenschnitt mit Skala, Schüler, Simulationen) + Interventions-Triage (Fördern/Fordern/Begleiten/Bestätigen/Beteiligen) mit Erfolg-Ampelbalken, blinkender Live-Aktiv-Ampel und Verlaufs-Sparkline pro Person. Ampelfarben nur für Leistung, Triage-Karten neutral. Alte 5 Stat-Cards raus, Top-Performer bleibt. Wochen-Cap gegen Zwischenspeicher-Log-Ausreißer. - results.php: neue fleiss-range 'weeks' (letzte 10 ISO-Wochen) - 2. Testklasse „3b Klasse" (3 Schüler); Klasse 99 → „4b Klasse" Co-Authored-By: Claude Opus 4.8 --- .../2026-07-20-klasse-3b-und-umbenennung.sql | 113 ++++++++++++ App/php/api/results.php | 15 +- App/teacher.html | 171 +++++++++++++++++- 3 files changed, 289 insertions(+), 10 deletions(-) create mode 100644 App/Don_t_Deploy/2026-07-20-klasse-3b-und-umbenennung.sql diff --git a/App/Don_t_Deploy/2026-07-20-klasse-3b-und-umbenennung.sql b/App/Don_t_Deploy/2026-07-20-klasse-3b-und-umbenennung.sql new file mode 100644 index 0000000..cde0768 --- /dev/null +++ b/App/Don_t_Deploy/2026-07-20-klasse-3b-und-umbenennung.sql @@ -0,0 +1,113 @@ +SET FOREIGN_KEY_CHECKS=0; +-- Klasse 99 umbenennen +UPDATE classes SET name='4b Klasse' WHERE id=99; +-- Cleanup 3b (idempotent) +DELETE FROM player_progress WHERE student_id IN (SELECT id FROM students WHERE username IN ('pia_3b','rosa_3b','sami_3b')); +DELETE FROM student_results WHERE student_id IN (SELECT id FROM students WHERE username IN ('pia_3b','rosa_3b','sami_3b')); +DELETE FROM assessments WHERE session_id IN (SELECT id FROM student_sessions WHERE created_at='2025-10-01 08:00:00' AND display_name IN ('Pia','Rosa','Sami')); +DELETE FROM student_sessions WHERE created_at='2025-10-01 08:00:00' AND display_name IN ('Pia','Rosa','Sami'); +DELETE FROM students WHERE username IN ('pia_3b','rosa_3b','sami_3b'); +DELETE FROM classes WHERE join_code='TEST3B'; +-- Klasse 3b anlegen +INSERT INTO classes (teacher_id, name, school_year, join_code, country) VALUES (99,'3b Klasse','2025/26','TEST3B','AT'); +INSERT INTO students (class_id, username, password, display_name, emoji_avatar, avatar_slug, is_anonymous, created_at) VALUES ((SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'pia_3b','!nologin-generated','Pia','🦉','eule-prof',0,'2025-09-20 08:00:00'); +INSERT INTO student_sessions (id, class_id, display_name, created_at, last_seen, country) VALUES ('d112ac1b-8fec-f2da-28ae-e97cd5acbec5',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'Pia','2025-10-01 08:00:00','2026-06-15 12:00:00','AT'); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('d112ac1b-8fec-f2da-28ae-e97cd5acbec5','fluss',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGFycyI6IDUsICJiaW9kaXYiOiAxMDAsICJlY29ub215IjogMTAwLCAiZmxvb2QiOiAwLCAiZm9vZCI6IDEwMH0=') USING utf8mb4),353000,'2026-03-13 09:41:03'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='pia_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'fluss',100,353,CONVERT(FROM_BASE64('eyJzdGFycyI6IDUsICJiaW9kaXYiOiAxMDAsICJlY29ub215IjogMTAwLCAiZmxvb2QiOiAwLCAiZm9vZCI6IDEwMH0=') USING utf8mb4),'2026-03-13 09:41:03'); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('d112ac1b-8fec-f2da-28ae-e97cd5acbec5','fluss',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGFycyI6IDQsICJiaW9kaXYiOiA3MSwgImVjb25vbXkiOiA3MSwgImZsb29kIjogMjksICJmb29kIjogNzF9') USING utf8mb4),400000,'2026-02-07 13:02:46'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='pia_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'fluss',71,400,CONVERT(FROM_BASE64('eyJzdGFycyI6IDQsICJiaW9kaXYiOiA3MSwgImVjb25vbXkiOiA3MSwgImZsb29kIjogMjksICJmb29kIjogNzF9') USING utf8mb4),'2026-02-07 13:02:46'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='pia_3b' LIMIT 1),'fluss',2,95,2,5); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('d112ac1b-8fec-f2da-28ae-e97cd5acbec5','tourismustal',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJnb2Fsc0RvbmUiOiA0LCAiZ29hbHNUb3RhbCI6IDYsICJzYXRpc2ZhY3Rpb24iOiA3MywgIm5hdHVyZSI6IDczLCAibW9uZXkiOiAxMDB9') USING utf8mb4),467000,'2025-11-15 14:14:17'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='pia_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'tourismustal',73,467,CONVERT(FROM_BASE64('eyJnb2Fsc0RvbmUiOiA0LCAiZ29hbHNUb3RhbCI6IDYsICJzYXRpc2ZhY3Rpb24iOiA3MywgIm5hdHVyZSI6IDczLCAibW9uZXkiOiAxMDB9') USING utf8mb4),'2025-11-15 14:14:17'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='pia_3b' LIMIT 1),'tourismustal',1,40,1,4); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('d112ac1b-8fec-f2da-28ae-e97cd5acbec5','kofferdetektiv',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJjYXNlc190b3RhbCI6IDYsICJjYXNlc19zb2x2ZWQiOiAzLCAiY29ycmVjdF9maXJzdF90cnkiOiAzLCAid3JvbmdfZ3Vlc3NlcyI6IDAsICJoaW50c191c2VkX2F2ZyI6IDUuMH0=') USING utf8mb4),192000,'2025-11-22 15:19:52'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='pia_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'kofferdetektiv',56,192,CONVERT(FROM_BASE64('eyJjYXNlc190b3RhbCI6IDYsICJjYXNlc19zb2x2ZWQiOiAzLCAiY29ycmVjdF9maXJzdF90cnkiOiAzLCAid3JvbmdfZ3Vlc3NlcyI6IDAsICJoaW50c191c2VkX2F2ZyI6IDUuMH0=') USING utf8mb4),'2025-11-22 15:19:52'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='pia_3b' LIMIT 1),'kofferdetektiv',1,30,1,3); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('d112ac1b-8fec-f2da-28ae-e97cd5acbec5','farmer',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGFycyI6IDMsICJoaXRfcmF0ZSI6IDY4LCAieWVhciI6IDEwLCAiY3JvcHNfdXNlZCI6IDR9') USING utf8mb4),240000,'2025-12-20 10:26:16'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='pia_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'farmer',68,240,CONVERT(FROM_BASE64('eyJzdGFycyI6IDMsICJoaXRfcmF0ZSI6IDY4LCAieWVhciI6IDEwLCAiY3JvcHNfdXNlZCI6IDR9') USING utf8mb4),'2025-12-20 10:26:16'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='pia_3b' LIMIT 1),'farmer',1,30,1,3); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('d112ac1b-8fec-f2da-28ae-e97cd5acbec5','weltkueche',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGFycyI6IDMsICJjb21wbGV0ZWREaXNoZXMiOiA1LCAidG90YWxEaXNoZXMiOiAxMCwgIm1pc3Rha2VzSW5EaXNoIjogN30=') USING utf8mb4),377000,'2025-12-07 14:02:09'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='pia_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'weltkueche',53,377,CONVERT(FROM_BASE64('eyJzdGFycyI6IDMsICJjb21wbGV0ZWREaXNoZXMiOiA1LCAidG90YWxEaXNoZXMiOiAxMCwgIm1pc3Rha2VzSW5EaXNoIjogN30=') USING utf8mb4),'2025-12-07 14:02:09'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='pia_3b' LIMIT 1),'weltkueche',1,30,1,3); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('d112ac1b-8fec-f2da-28ae-e97cd5acbec5','sonnensystem',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJjb21wbGV0ZWQiOiAxMSwgInRvdGFsIjogMjAsICJmaXJzdFRyeSI6IGZhbHNlfQ==') USING utf8mb4),290000,'2025-12-07 13:09:48'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='pia_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'sonnensystem',55,290,CONVERT(FROM_BASE64('eyJjb21wbGV0ZWQiOiAxMSwgInRvdGFsIjogMjAsICJmaXJzdFRyeSI6IGZhbHNlfQ==') USING utf8mb4),'2025-12-07 13:09:48'); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('d112ac1b-8fec-f2da-28ae-e97cd5acbec5','sonnensystem',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJjb21wbGV0ZWQiOiAxNiwgInRvdGFsIjogMjAsICJmaXJzdFRyeSI6IGZhbHNlfQ==') USING utf8mb4),509000,'2026-03-03 11:22:40'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='pia_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'sonnensystem',82,509,CONVERT(FROM_BASE64('eyJjb21wbGV0ZWQiOiAxNiwgInRvdGFsIjogMjAsICJmaXJzdFRyeSI6IGZhbHNlfQ==') USING utf8mb4),'2026-03-03 11:22:40'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='pia_3b' LIMIT 1),'sonnensystem',2,70,2,4); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('d112ac1b-8fec-f2da-28ae-e97cd5acbec5','heli',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGVybmVHZXNhbXQiOiA0LCAicGxhblBjdCI6IDkwLCAic3RhcnRTY29yZSI6IDQsICJsYW5kaW5nU2NvcmUiOiA0fQ==') USING utf8mb4),286000,'2026-02-02 08:38:06'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='pia_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'heli',90,286,CONVERT(FROM_BASE64('eyJzdGVybmVHZXNhbXQiOiA0LCAicGxhblBjdCI6IDkwLCAic3RhcnRTY29yZSI6IDQsICJsYW5kaW5nU2NvcmUiOiA0fQ==') USING utf8mb4),'2026-02-02 08:38:06'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='pia_3b' LIMIT 1),'heli',1,40,1,4); +INSERT INTO students (class_id, username, password, display_name, emoji_avatar, avatar_slug, is_anonymous, created_at) VALUES ((SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'rosa_3b','!nologin-generated','Rosa','🦊','fuchs-explorer',0,'2025-09-20 08:00:00'); +INSERT INTO student_sessions (id, class_id, display_name, created_at, last_seen, country) VALUES ('8b7a490f-e331-c6c5-3840-785bcd851ffe',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'Rosa','2025-10-01 08:00:00','2026-06-15 12:00:00','AT'); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('8b7a490f-e331-c6c5-3840-785bcd851ffe','farmer',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGFycyI6IDMsICJoaXRfcmF0ZSI6IDU4LCAieWVhciI6IDksICJjcm9wc191c2VkIjogM30=') USING utf8mb4),472000,'2026-05-13 08:45:16'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'farmer',58,472,CONVERT(FROM_BASE64('eyJzdGFycyI6IDMsICJoaXRfcmF0ZSI6IDU4LCAieWVhciI6IDksICJjcm9wc191c2VkIjogM30=') USING utf8mb4),'2026-05-13 08:45:16'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),'farmer',1,30,1,3); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('8b7a490f-e331-c6c5-3840-785bcd851ffe','kofferdetektiv',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJjYXNlc190b3RhbCI6IDYsICJjYXNlc19zb2x2ZWQiOiA0LCAiY29ycmVjdF9maXJzdF90cnkiOiA0LCAid3JvbmdfZ3Vlc3NlcyI6IDAsICJoaW50c191c2VkX2F2ZyI6IDMuOX0=') USING utf8mb4),210000,'2026-01-03 11:47:17'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'kofferdetektiv',68,210,CONVERT(FROM_BASE64('eyJjYXNlc190b3RhbCI6IDYsICJjYXNlc19zb2x2ZWQiOiA0LCAiY29ycmVjdF9maXJzdF90cnkiOiA0LCAid3JvbmdfZ3Vlc3NlcyI6IDAsICJoaW50c191c2VkX2F2ZyI6IDMuOX0=') USING utf8mb4),'2026-01-03 11:47:17'); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('8b7a490f-e331-c6c5-3840-785bcd851ffe','kofferdetektiv',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJjYXNlc190b3RhbCI6IDYsICJjYXNlc19zb2x2ZWQiOiAyLCAiY29ycmVjdF9maXJzdF90cnkiOiAyLCAid3JvbmdfZ3Vlc3NlcyI6IDAsICJoaW50c191c2VkX2F2ZyI6IDcuM30=') USING utf8mb4),216000,'2026-05-25 15:04:54'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'kofferdetektiv',30,216,CONVERT(FROM_BASE64('eyJjYXNlc190b3RhbCI6IDYsICJjYXNlc19zb2x2ZWQiOiAyLCAiY29ycmVjdF9maXJzdF90cnkiOiAyLCAid3JvbmdfZ3Vlc3NlcyI6IDAsICJoaW50c191c2VkX2F2ZyI6IDcuM30=') USING utf8mb4),'2026-05-25 15:04:54'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),'kofferdetektiv',2,50,2,3); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('8b7a490f-e331-c6c5-3840-785bcd851ffe','eu-werkstatt',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJlbmRUeXBlIjogImFib3J0ZWQiLCAic3RlcHNUb3RhbCI6IDEwLCAiZmlyc3RUcnlIaXRzIjogNSwgInRvdGFsQXR0ZW1wdHMiOiAxMiwgIm11ZWxsZWltZXJDb3VudCI6IDF9') USING utf8mb4),192000,'2026-03-28 10:06:01'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'eu-werkstatt',51,192,CONVERT(FROM_BASE64('eyJlbmRUeXBlIjogImFib3J0ZWQiLCAic3RlcHNUb3RhbCI6IDEwLCAiZmlyc3RUcnlIaXRzIjogNSwgInRvdGFsQXR0ZW1wdHMiOiAxMiwgIm11ZWxsZWltZXJDb3VudCI6IDF9') USING utf8mb4),'2026-03-28 10:06:01'); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('8b7a490f-e331-c6c5-3840-785bcd851ffe','eu-werkstatt',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJlbmRUeXBlIjogImFib3J0ZWQiLCAic3RlcHNUb3RhbCI6IDEwLCAiZmlyc3RUcnlIaXRzIjogNSwgInRvdGFsQXR0ZW1wdHMiOiAxMiwgIm11ZWxsZWltZXJDb3VudCI6IDF9') USING utf8mb4),124000,'2025-12-13 11:22:35'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'eu-werkstatt',54,124,CONVERT(FROM_BASE64('eyJlbmRUeXBlIjogImFib3J0ZWQiLCAic3RlcHNUb3RhbCI6IDEwLCAiZmlyc3RUcnlIaXRzIjogNSwgInRvdGFsQXR0ZW1wdHMiOiAxMiwgIm11ZWxsZWltZXJDb3VudCI6IDF9') USING utf8mb4),'2025-12-13 11:22:35'); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('8b7a490f-e331-c6c5-3840-785bcd851ffe','eu-werkstatt',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJlbmRUeXBlIjogImFib3J0ZWQiLCAic3RlcHNUb3RhbCI6IDEwLCAiZmlyc3RUcnlIaXRzIjogNCwgInRvdGFsQXR0ZW1wdHMiOiAxMiwgIm11ZWxsZWltZXJDb3VudCI6IDF9') USING utf8mb4),354000,'2025-12-28 08:11:15'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'eu-werkstatt',36,354,CONVERT(FROM_BASE64('eyJlbmRUeXBlIjogImFib3J0ZWQiLCAic3RlcHNUb3RhbCI6IDEwLCAiZmlyc3RUcnlIaXRzIjogNCwgInRvdGFsQXR0ZW1wdHMiOiAxMiwgIm11ZWxsZWltZXJDb3VudCI6IDF9') USING utf8mb4),'2025-12-28 08:11:15'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),'eu-werkstatt',2,80,3,3); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('8b7a490f-e331-c6c5-3840-785bcd851ffe','energiemanager',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGFycyI6IDMsICJibG9ja3NCYWxhbmNlZCI6IDYsICJibG9ja3NUb3RhbCI6IDEyLCAiZGF5c1BsYXllZCI6IDMsICJkYXlzVG90YWwiOiA2fQ==') USING utf8mb4),119000,'2026-05-24 08:08:07'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'energiemanager',51,119,CONVERT(FROM_BASE64('eyJzdGFycyI6IDMsICJibG9ja3NCYWxhbmNlZCI6IDYsICJibG9ja3NUb3RhbCI6IDEyLCAiZGF5c1BsYXllZCI6IDMsICJkYXlzVG90YWwiOiA2fQ==') USING utf8mb4),'2026-05-24 08:08:07'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),'energiemanager',1,30,1,3); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('8b7a490f-e331-c6c5-3840-785bcd851ffe','klima',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJmaW5hbF90ZW1wZXJhdHVyZSI6IDE2LjYxLCAiZmluYWxfZmxvb2RlZF9wY3QiOiAzNywgImZpbmFsX2J1ZGdldCI6IDIzMCwgImZpbmFsX2NvMiI6IDQzNiwgImZpbmFsX3BvcHVsYXRpb24iOiAyNTB9') USING utf8mb4),355000,'2026-04-19 12:54:37'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'klima',63,355,CONVERT(FROM_BASE64('eyJmaW5hbF90ZW1wZXJhdHVyZSI6IDE2LjYxLCAiZmluYWxfZmxvb2RlZF9wY3QiOiAzNywgImZpbmFsX2J1ZGdldCI6IDIzMCwgImZpbmFsX2NvMiI6IDQzNiwgImZpbmFsX3BvcHVsYXRpb24iOiAyNTB9') USING utf8mb4),'2026-04-19 12:54:37'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),'klima',1,30,1,3); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('8b7a490f-e331-c6c5-3840-785bcd851ffe','logistik',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGFycyI6IDMsICJvcmRlcnNEZWxpdmVyZWQiOiA1LCAidG90YWxPcmRlcnMiOiAxMCwgIm9yZGVyc0xhdGUiOiAwLCAiZmluYWxCYWxhbmNlIjogMjgwfQ==') USING utf8mb4),403000,'2026-05-12 11:30:33'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'logistik',54,403,CONVERT(FROM_BASE64('eyJzdGFycyI6IDMsICJvcmRlcnNEZWxpdmVyZWQiOiA1LCAidG90YWxPcmRlcnMiOiAxMCwgIm9yZGVyc0xhdGUiOiAwLCAiZmluYWxCYWxhbmNlIjogMjgwfQ==') USING utf8mb4),'2026-05-12 11:30:33'); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('8b7a490f-e331-c6c5-3840-785bcd851ffe','logistik',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGFycyI6IDIsICJvcmRlcnNEZWxpdmVyZWQiOiA0LCAidG90YWxPcmRlcnMiOiAxMCwgIm9yZGVyc0xhdGUiOiAwLCAiZmluYWxCYWxhbmNlIjogMTAwfQ==') USING utf8mb4),483000,'2026-02-15 13:37:26'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'logistik',45,483,CONVERT(FROM_BASE64('eyJzdGFycyI6IDIsICJvcmRlcnNEZWxpdmVyZWQiOiA0LCAidG90YWxPcmRlcnMiOiAxMCwgIm9yZGVyc0xhdGUiOiAwLCAiZmluYWxCYWxhbmNlIjogMTAwfQ==') USING utf8mb4),'2026-02-15 13:37:26'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),'logistik',2,50,2,3); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('8b7a490f-e331-c6c5-3840-785bcd851ffe','weltkueche',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGFycyI6IDMsICJjb21wbGV0ZWREaXNoZXMiOiA2LCAidG90YWxEaXNoZXMiOiAxMCwgIm1pc3Rha2VzSW5EaXNoIjogNn0=') USING utf8mb4),319000,'2026-06-04 14:53:49'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'weltkueche',59,319,CONVERT(FROM_BASE64('eyJzdGFycyI6IDMsICJjb21wbGV0ZWREaXNoZXMiOiA2LCAidG90YWxEaXNoZXMiOiAxMCwgIm1pc3Rha2VzSW5EaXNoIjogNn0=') USING utf8mb4),'2026-06-04 14:53:49'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),'weltkueche',1,30,1,3); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('8b7a490f-e331-c6c5-3840-785bcd851ffe','heli',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGVybmVHZXNhbXQiOiA0LCAicGxhblBjdCI6IDcxLCAic3RhcnRTY29yZSI6IDQsICJsYW5kaW5nU2NvcmUiOiA0fQ==') USING utf8mb4),430000,'2025-10-23 08:34:16'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'heli',71,430,CONVERT(FROM_BASE64('eyJzdGVybmVHZXNhbXQiOiA0LCAicGxhblBjdCI6IDcxLCAic3RhcnRTY29yZSI6IDQsICJsYW5kaW5nU2NvcmUiOiA0fQ==') USING utf8mb4),'2025-10-23 08:34:16'); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('8b7a490f-e331-c6c5-3840-785bcd851ffe','heli',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGVybmVHZXNhbXQiOiAzLCAicGxhblBjdCI6IDU0LCAic3RhcnRTY29yZSI6IDMsICJsYW5kaW5nU2NvcmUiOiAzfQ==') USING utf8mb4),179000,'2025-11-16 14:34:52'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'heli',54,179,CONVERT(FROM_BASE64('eyJzdGVybmVHZXNhbXQiOiAzLCAicGxhblBjdCI6IDU0LCAic3RhcnRTY29yZSI6IDMsICJsYW5kaW5nU2NvcmUiOiAzfQ==') USING utf8mb4),'2025-11-16 14:34:52'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),'heli',2,70,2,4); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('8b7a490f-e331-c6c5-3840-785bcd851ffe','fluss',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGFycyI6IDQsICJiaW9kaXYiOiA3MCwgImVjb25vbXkiOiA3MCwgImZsb29kIjogMzAsICJmb29kIjogNzB9') USING utf8mb4),302000,'2026-05-13 12:16:30'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'fluss',70,302,CONVERT(FROM_BASE64('eyJzdGFycyI6IDQsICJiaW9kaXYiOiA3MCwgImVjb25vbXkiOiA3MCwgImZsb29kIjogMzAsICJmb29kIjogNzB9') USING utf8mb4),'2026-05-13 12:16:30'); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('8b7a490f-e331-c6c5-3840-785bcd851ffe','fluss',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGFycyI6IDEsICJiaW9kaXYiOiAyNywgImVjb25vbXkiOiAyNywgImZsb29kIjogNzMsICJmb29kIjogMjd9') USING utf8mb4),499000,'2026-01-06 13:41:04'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'fluss',27,499,CONVERT(FROM_BASE64('eyJzdGFycyI6IDEsICJiaW9kaXYiOiAyNywgImVjb25vbXkiOiAyNywgImZsb29kIjogNzMsICJmb29kIjogMjd9') USING utf8mb4),'2026-01-06 13:41:04'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='rosa_3b' LIMIT 1),'fluss',2,50,2,4); +INSERT INTO students (class_id, username, password, display_name, emoji_avatar, avatar_slug, is_anonymous, created_at) VALUES ((SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'sami_3b','!nologin-generated','Sami','🐢','baer-foerster',0,'2025-09-20 08:00:00'); +INSERT INTO student_sessions (id, class_id, display_name, created_at, last_seen, country) VALUES ('facaddee-c2df-1213-5ee0-5624dcfb1482',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'Sami','2025-10-01 08:00:00','2026-06-15 12:00:00','AT'); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('facaddee-c2df-1213-5ee0-5624dcfb1482','energiemanager',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGFycyI6IDMsICJibG9ja3NCYWxhbmNlZCI6IDYsICJibG9ja3NUb3RhbCI6IDEyLCAiZGF5c1BsYXllZCI6IDMsICJkYXlzVG90YWwiOiA2fQ==') USING utf8mb4),131000,'2026-01-04 08:48:05'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='sami_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'energiemanager',52,131,CONVERT(FROM_BASE64('eyJzdGFycyI6IDMsICJibG9ja3NCYWxhbmNlZCI6IDYsICJibG9ja3NUb3RhbCI6IDEyLCAiZGF5c1BsYXllZCI6IDMsICJkYXlzVG90YWwiOiA2fQ==') USING utf8mb4),'2026-01-04 08:48:05'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='sami_3b' LIMIT 1),'energiemanager',1,30,1,3); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('facaddee-c2df-1213-5ee0-5624dcfb1482','heli',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGVybmVHZXNhbXQiOiAyLCAicGxhblBjdCI6IDQyLCAic3RhcnRTY29yZSI6IDIsICJsYW5kaW5nU2NvcmUiOiAyfQ==') USING utf8mb4),342000,'2026-03-24 14:45:15'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='sami_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'heli',42,342,CONVERT(FROM_BASE64('eyJzdGVybmVHZXNhbXQiOiAyLCAicGxhblBjdCI6IDQyLCAic3RhcnRTY29yZSI6IDIsICJsYW5kaW5nU2NvcmUiOiAyfQ==') USING utf8mb4),'2026-03-24 14:45:15'); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('facaddee-c2df-1213-5ee0-5624dcfb1482','heli',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGVybmVHZXNhbXQiOiAxLCAicGxhblBjdCI6IDE3LCAic3RhcnRTY29yZSI6IDEsICJsYW5kaW5nU2NvcmUiOiAxfQ==') USING utf8mb4),409000,'2026-01-12 08:25:46'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='sami_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'heli',17,409,CONVERT(FROM_BASE64('eyJzdGVybmVHZXNhbXQiOiAxLCAicGxhblBjdCI6IDE3LCAic3RhcnRTY29yZSI6IDEsICJsYW5kaW5nU2NvcmUiOiAxfQ==') USING utf8mb4),'2026-01-12 08:25:46'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='sami_3b' LIMIT 1),'heli',1,30,2,2); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('facaddee-c2df-1213-5ee0-5624dcfb1482','weltkueche',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGFycyI6IDMsICJjb21wbGV0ZWREaXNoZXMiOiA3LCAidG90YWxEaXNoZXMiOiAxMCwgIm1pc3Rha2VzSW5EaXNoIjogNX0=') USING utf8mb4),395000,'2025-11-14 14:46:57'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='sami_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'weltkueche',67,395,CONVERT(FROM_BASE64('eyJzdGFycyI6IDMsICJjb21wbGV0ZWREaXNoZXMiOiA3LCAidG90YWxEaXNoZXMiOiAxMCwgIm1pc3Rha2VzSW5EaXNoIjogNX0=') USING utf8mb4),'2025-11-14 14:46:57'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='sami_3b' LIMIT 1),'weltkueche',1,30,1,3); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('facaddee-c2df-1213-5ee0-5624dcfb1482','tourismusregion',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzY29yZSI6IDM3fQ==') USING utf8mb4),361000,'2026-05-28 14:22:21'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='sami_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'tourismusregion',37,361,CONVERT(FROM_BASE64('eyJzY29yZSI6IDM3fQ==') USING utf8mb4),'2026-05-28 14:22:21'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='sami_3b' LIMIT 1),'tourismusregion',1,20,1,2); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('facaddee-c2df-1213-5ee0-5624dcfb1482','kofferdetektiv',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJjYXNlc190b3RhbCI6IDYsICJjYXNlc19zb2x2ZWQiOiAzLCAiY29ycmVjdF9maXJzdF90cnkiOiAzLCAid3JvbmdfZ3Vlc3NlcyI6IDAsICJoaW50c191c2VkX2F2ZyI6IDUuOX0=') USING utf8mb4),413000,'2025-11-11 08:03:50'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='sami_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'kofferdetektiv',46,413,CONVERT(FROM_BASE64('eyJjYXNlc190b3RhbCI6IDYsICJjYXNlc19zb2x2ZWQiOiAzLCAiY29ycmVjdF9maXJzdF90cnkiOiAzLCAid3JvbmdfZ3Vlc3NlcyI6IDAsICJoaW50c191c2VkX2F2ZyI6IDUuOX0=') USING utf8mb4),'2025-11-11 08:03:50'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='sami_3b' LIMIT 1),'kofferdetektiv',1,20,1,2); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('facaddee-c2df-1213-5ee0-5624dcfb1482','tourismustal',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJnb2Fsc0RvbmUiOiAzLCAiZ29hbHNUb3RhbCI6IDYsICJzYXRpc2ZhY3Rpb24iOiA0NiwgIm5hdHVyZSI6IDQ2LCAibW9uZXkiOiAxMDB9') USING utf8mb4),194000,'2026-01-31 08:06:10'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='sami_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'tourismustal',46,194,CONVERT(FROM_BASE64('eyJnb2Fsc0RvbmUiOiAzLCAiZ29hbHNUb3RhbCI6IDYsICJzYXRpc2ZhY3Rpb24iOiA0NiwgIm5hdHVyZSI6IDQ2LCAibW9uZXkiOiAxMDB9') USING utf8mb4),'2026-01-31 08:06:10'); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('facaddee-c2df-1213-5ee0-5624dcfb1482','tourismustal',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJnb2Fsc0RvbmUiOiAyLCAiZ29hbHNUb3RhbCI6IDYsICJzYXRpc2ZhY3Rpb24iOiAzNSwgIm5hdHVyZSI6IDM1LCAibW9uZXkiOiAxMDB9') USING utf8mb4),406000,'2025-12-21 14:05:28'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='sami_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'tourismustal',35,406,CONVERT(FROM_BASE64('eyJnb2Fsc0RvbmUiOiAyLCAiZ29hbHNUb3RhbCI6IDYsICJzYXRpc2ZhY3Rpb24iOiAzNSwgIm5hdHVyZSI6IDM1LCAibW9uZXkiOiAxMDB9') USING utf8mb4),'2025-12-21 14:05:28'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='sami_3b' LIMIT 1),'tourismustal',1,40,2,2); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('facaddee-c2df-1213-5ee0-5624dcfb1482','logistik',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGFycyI6IDIsICJvcmRlcnNEZWxpdmVyZWQiOiA0LCAidG90YWxPcmRlcnMiOiAxMCwgIm9yZGVyc0xhdGUiOiAwLCAiZmluYWxCYWxhbmNlIjogLTI1fQ==') USING utf8mb4),167000,'2025-12-13 14:57:42'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='sami_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'logistik',39,167,CONVERT(FROM_BASE64('eyJzdGFycyI6IDIsICJvcmRlcnNEZWxpdmVyZWQiOiA0LCAidG90YWxPcmRlcnMiOiAxMCwgIm9yZGVyc0xhdGUiOiAwLCAiZmluYWxCYWxhbmNlIjogLTI1fQ==') USING utf8mb4),'2025-12-13 14:57:42'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='sami_3b' LIMIT 1),'logistik',1,20,1,2); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('facaddee-c2df-1213-5ee0-5624dcfb1482','farmer',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGFycyI6IDIsICJoaXRfcmF0ZSI6IDM5LCAieWVhciI6IDYsICJjcm9wc191c2VkIjogMn0=') USING utf8mb4),349000,'2026-04-24 14:11:37'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='sami_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'farmer',39,349,CONVERT(FROM_BASE64('eyJzdGFycyI6IDIsICJoaXRfcmF0ZSI6IDM5LCAieWVhciI6IDYsICJjcm9wc191c2VkIjogMn0=') USING utf8mb4),'2026-04-24 14:11:37'); +INSERT INTO assessments (session_id, sim_id, class_id, results, duration_ms, submitted_at) VALUES ('facaddee-c2df-1213-5ee0-5624dcfb1482','farmer',(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),CONVERT(FROM_BASE64('eyJzdGFycyI6IDIsICJoaXRfcmF0ZSI6IDMzLCAieWVhciI6IDUsICJjcm9wc191c2VkIjogMn0=') USING utf8mb4),159000,'2025-11-03 10:02:43'); +INSERT INTO student_results (student_id, class_id, module_id, score, duration_sec, detail_json, completed_at) VALUES ((SELECT id FROM students WHERE username='sami_3b' LIMIT 1),(SELECT id FROM classes WHERE join_code='TEST3B' LIMIT 1),'farmer',33,159,CONVERT(FROM_BASE64('eyJzdGFycyI6IDIsICJoaXRfcmF0ZSI6IDMzLCAieWVhciI6IDUsICJjcm9wc191c2VkIjogMn0=') USING utf8mb4),'2025-11-03 10:02:43'); +INSERT INTO player_progress (student_id, sim_id, level, xp, plays, best_stars) VALUES ((SELECT id FROM students WHERE username='sami_3b' LIMIT 1),'farmer',1,40,2,2); +SET FOREIGN_KEY_CHECKS=1; diff --git a/App/php/api/results.php b/App/php/api/results.php index 1ce3a97..b423726 100644 --- a/App/php/api/results.php +++ b/App/php/api/results.php @@ -271,7 +271,20 @@ if ($view === 'fleiss') { $idxMap = function($b) { return (int)$b - 1; }; $label = 'Letzte 12 Monate'; break; - default: Response::error('range muss day|week|month|year sein'); + case 'weeks': + // Letzte 10 ISO-Kalenderwochen — je Woche eine Säule (für den „Verlauf"). + $sinceSql = "a.submitted_at >= NOW() - INTERVAL 10 WEEK"; + $bucketFn = 'YEARWEEK(a.submitted_at, 3)'; + $buckets = []; $bmap = []; + for ($i = 9; $i >= 0; $i--) { + $yw = (int)date('oW', strtotime("-$i week")); + $buckets[] = 'KW' . date('W', strtotime("-$i week")); + $bmap[$yw] = 9 - $i; + } + $idxMap = function($b) use ($bmap) { return $bmap[(int)$b] ?? -1; }; + $label = 'Letzte 10 Wochen'; + break; + default: Response::error('range muss day|week|weeks|month|year sein'); } // Optional Modul-Filter diff --git a/App/teacher.html b/App/teacher.html index fc51621..b94030a 100644 --- a/App/teacher.html +++ b/App/teacher.html @@ -2073,6 +2073,161 @@ function startLiveStatusPoll() { _liveStatusTimer = setInterval(pollLiveStatus, 10000); } +// === INTERVENTIONS-ÜBERSICHT (neu, oben im Übersicht-Tab) === +var IV_CSS = '' ++ '.iv-wrap{--ivg:#3e9b63;--ivli:#7aa03a;--ivy:#dcae35;--ivo:#db8a33;--ivr:#cc4a37;' ++ '--ivns:#5b7fa6;--ivnm:#3f8f8f;--ivnw:#8f6f9c;--ivngd:#6a72b0;--ivni:#8c857c;' ++ '--ivtrack:rgba(41,52,46,.13);--ivline:rgba(0,0,0,.08);--ivsoft:#f5f3ec;--ivmut:#8a8a8a;font-size:14px}' ++ '.iv-wrap *{box-sizing:border-box}' ++ '.iv-h1{font-size:1.15rem;font-weight:800;margin:0 0 14px;color:#3d4a44}' ++ '.iv-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:12px;margin-bottom:20px}' ++ '.iv-stat{background:#fff;border:1px solid var(--ivline);border-radius:12px;padding:12px 14px;display:flex;flex-direction:column;gap:8px}' ++ '.iv-lab{font-size:.6rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--ivmut);display:flex;justify-content:space-between;gap:8px}' ++ '.iv-maxv{text-transform:none;letter-spacing:0}.iv-maxv b{color:#2f3a34}' ++ '.iv-gfx{height:32px;display:flex;align-items:center;gap:9px}' ++ '.iv-exp{font-size:.7rem;color:var(--ivmut)}' ++ '.iv-ebar2{flex:1;height:10px;border-radius:5px;background:var(--ivtrack);overflow:hidden}.iv-ebar2>i{display:block;height:100%;border-radius:5px;background:var(--ivli)}' ++ '.iv-bign{font-size:1.4rem;font-weight:800;letter-spacing:-.02em}' ++ '.iv-stripe{display:flex;width:100%;height:16px;border-radius:5px;overflow:hidden;border:1px solid var(--ivline)}.iv-stripe i{height:100%}' ++ '.iv-cav{display:flex;align-items:flex-end;gap:2px;height:32px;width:100%}.iv-cav i{flex:1;border-radius:2px;min-width:2px}' ++ '.iv-g{background:var(--ivg)!important}.iv-li{background:var(--ivli)!important}.iv-y{background:var(--ivy)!important}.iv-o{background:var(--ivo)!important}.iv-r{background:var(--ivr)!important}.iv-z{background:var(--ivtrack)!important}' ++ '.iv-sec{font-size:1rem;font-weight:700;margin:0 0 12px;color:#3d4a44}.iv-sec span{font-size:.78rem;font-weight:400;color:var(--ivmut);margin-left:8px}' ++ '.iv-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(330px,1fr));gap:14px;align-items:start;margin-bottom:8px}' ++ '.iv-card{background:#fff;border:1px solid var(--ivline);border-radius:12px;padding:12px 14px;border-top:3px solid var(--iva)}' ++ '.iv-chead{display:flex;align-items:center;gap:10px;margin-bottom:6px}' ++ '.iv-ic{width:32px;height:32px;flex:none;border-radius:8px;display:grid;place-items:center;background:color-mix(in srgb,var(--iva) 16%,transparent);color:var(--iva)}' ++ '.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-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}' ++ '.iv-akt{justify-self:center}.iv-dotA{display:block;width:13px;height:13px;border-radius:50%}' ++ '.iv-hot .iv-dotA{background:var(--ivg);animation:ivblink .55s ease-in-out infinite}.iv-on .iv-dotA{background:var(--ivg);animation:ivblink 1.2s ease-in-out infinite}.iv-mid .iv-dotA{background:var(--ivy);animation:ivblink 2.2s ease-in-out infinite}.iv-off .iv-dotA{background:var(--ivr);opacity:.5}' ++ '@keyframes ivblink{0%,100%{opacity:1}50%{opacity:.28}}' ++ '.iv-vl{display:inline-flex;align-items:flex-end;gap:2px;height:18px;justify-self:center}.iv-vl i{width:4px;border-radius:1.5px;min-height:2px}' ++ '.iv-chev{width:15px;height:15px;fill:none;stroke:var(--ivmut);stroke-width:2;stroke-linecap:round;stroke-linejoin:round;opacity:.45}.iv-prow:hover .iv-chev{opacity:1}' ++ '.iv-calm{background:#fff;border:1px solid var(--ivline);border-radius:12px;padding:11px 16px;display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:8px}.iv-calm .iv-dot{width:9px;height:9px;border-radius:50%;background:var(--ivg)}.iv-calm b{font-weight:750}.iv-calm .iv-names{font-size:.8rem;color:var(--ivmut)}' ++ '.iv-legend{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:12px 24px;background:#fff;border:1px solid var(--ivline);border-radius:12px;padding:14px 16px;margin-top:6px;font-size:.74rem;color:var(--ivmut)}.iv-legend b{color:#2f3a34}' ++ '.iv-lgdot{display:inline-block;width:11px;height:11px;border-radius:50%;vertical-align:middle;margin:0 4px}' ++ '@media (prefers-reduced-motion:reduce){.iv-dotA{animation:none!important}}'; + +function ivInjectCss(){ if(!document.getElementById('iv-css')){ var s=document.createElement('style'); s.id='iv-css'; s.textContent=IV_CSS; document.head.appendChild(s); } } +function ivAmp(v){ return v<38?'iv-r':v<50?'iv-o':v<62?'iv-y':v<75?'iv-li':'iv-g'; } +function ivErf(v){ + if (v==null||isNaN(v)) return ''; + v=Math.round(v); + return ''+v+''; +} +function ivAkt(status){ + var m={aktiv:['iv-on','arbeitet gerade'],idle:['iv-mid','Tab offen, keine Eingabe'],heute:['iv-off','heute schon fertig'],kalt:['iv-off','heute nichts'],nie:['iv-off','noch nie']}; + var x=m[status]||m.kalt; + return ''; +} +function ivSpark(secArr, maxSec){ + maxSec = maxSec||1; + var bars = secArr.map(function(sec){ + var frac = sec/maxSec; // 0..1 + var h = Math.max(2, Math.round(frac*18)); + 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 ''; + }).join(''); + return ''+bars+''; +} +var IV_ICON={ + support:'', + more:'', + work:'', + good:'', + idle:''}; +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']}; + +// 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'; + return null; // läuft rund +} + +function ivBuildOverview(cockpit, weeks, studentsCount, matrix){ + ivInjectCss(); + var cs = (cockpit && cockpit.students) || []; + var sc = (cockpit && cockpit.statusCounts) || {}; + // Verlauf-Map je Schüler. CAP gegen Ausreißer (z. B. Zwischenspeicher-Logs + // mit aufgeblähter duration): eine Woche zählt max. 3 h aktive Zeit. + var IV_WEEK_CAP=10800, wById={}, maxSec=1; + ((weeks&&weeks.students)||[]).forEach(function(w){ wById[w.studentId]=w; }); + // Plays je Schüler aus Matrix + var playsById={}; + ((matrix&&matrix.students)||[]).forEach(function(s){ playsById[s.id]=(matrix.totals[s.id]||{}).plays||0; }); + + 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 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++; } + weekTotals.push(secs); + var g=ivTriage(erf,plays,rising); + var row={name:s.displayName,erf:erf,status:s.status,secs:secs}; + if(g) groups[g].push(row); else calm.push(s.displayName); + }); + + var erfAvg = erfN? Math.round(erfSum/erfN):null; + var aktiv=(sc.aktiv||0), idle=(sc.idle||0), rest=Math.max(0,studentsCount-aktiv-idle); + var tot=Math.max(1,aktiv+idle+rest); + // Klassen-Verlauf = Summe je Woche + var classWeeks=[]; for(var i=0;i<10;i++){ var sum=0; weekTotals.forEach(function(a){sum+=(a[i]||0);}); classWeeks.push(sum); } + var classMax=Math.max.apply(null,classWeeks.concat([1])); + var maxLabel = classMax>=3600 ? (classMax/3600).toFixed(1)+' h' : Math.round(classMax/60)+' min'; + var simTotal=0; ((matrix&&matrix.students)||[]).forEach(function(s){ simTotal+=(matrix.totals[s.id]||{}).plays||0; }); + + var h='
'; + h+='
Klassenübersicht für didaktische Intervention
'; + // Stat-Karten + h+='
'; + h+='
Erfolg Klassenschnitt
'+(erfAvg!=null?erfAvg:'–')+'
0 – 100, Mittel über alle Module
'; + h+='
Aktuell aktiv
'+aktiv+' aktiv · '+idle+' teilweise · '+rest+' inaktiv
'; + h+='
Verlauf Klassenschnittmax '+maxLabel+'
'+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 '';}).join('')+'
aktive Zeit pro Woche · 10 Wochen
'; + h+='
Schüler:innen
'+studentsCount+'
'+aktiv+' gerade aktiv
'; + h+='
Simulationen
'+simTotal+'
Durchläufe insgesamt
'; + h+='
'; + // Triage + var need=groups.support.length+groups.more.length+groups.work.length+groups.good.length+groups.idle.length; + h+='
Braucht mein Zutun'+need+' von '+studentsCount+'
'; + ['support','more','work','good','idle'].forEach(function(key){ + var rows=groups[key]; if(!rows.length) return; + var m=IV_META[key]; + h+='
'+IV_ICON[key]+'

'+m[0]+'

'+m[1]+'

'+rows.length+'
'; + h+='
ErfolgAktivVerlauf
'; + rows.forEach(function(r){ + h+=''; + }); + h+='
'; + }); + h+='
'; + if(calm.length) h+='
Läuft rund — '+calm.length+''+calm.map(esc).join(' · ')+'
'; + // Legende + h+='
' + +'
Erfolg Wie gut die Simulation gemeistert wird, 0 – 100 (grün gut … rot schwach). Normiert zwischen Scheitern und „sehr gut".
' + +'
Aktuell aktiv Interaktionen der letzten Minuten, live: aktiv teilweise inaktiv
' + +'
Verlauf Aktive Zeit pro Woche, letzte 10 Wochen, gleiches Raster für alle. Farbe = Aktivität der Woche.
' + +'
'; + h+='
'; + return h; +} + // === ÜBERSICHT === // Lehrer-Übersicht: Stat-Bar + aktive Aufgaben + Top-Performer + Aktivitäts-Sparkline + Modul-Cards. // Drei parallele API-Calls (matrix + activity-week + assignments) — alle existing. @@ -2080,16 +2235,20 @@ async function loadOverview() { var host = document.getElementById('tab-overview'); host.innerHTML = '

Lade…

'; - var [matrix, activity, assignments, students] = await Promise.all([ + var [matrix, activity, assignments, students, cockpit, weeks] = await Promise.all([ api('results?class_id=' + currentClassId + '&view=matrix'), api('results?class_id=' + currentClassId + '&view=activity&range=week'), api('assignments?class_id=' + currentClassId), api('students?class_id=' + currentClassId), + api('live?class_id=' + currentClassId + '&cockpit=1'), + api('results?class_id=' + currentClassId + '&view=fleiss&range=weeks'), ]); if (matrix.error) { host.innerHTML = '

'+esc(matrix.error)+'

'; return; } if (activity.error) activity = {series:[], buckets:[]}; if (assignments.error) assignments = []; if (students.error) students = []; + if (!cockpit || cockpit.error) cockpit = {students:[], statusCounts:{}}; + if (!weeks || weeks.error) weeks = {students:[], globalMaxBucketSec:0}; // === Top 3 Performer aus Matrix-Cells ableiten === var topRuns = []; @@ -2121,14 +2280,8 @@ async function loadOverview() { var html = ''; - // === Sektion A: Stat-Bar === - html += '
'; - html += '
'+students.length+'
Schüler*innen
'; - html += '
'+activeStudents+'
Aktiv
'; - html += '
'+totalPlays+'
Durchgänge
'; - html += '
'+totalScore.toFixed(0)+'
Σ Score
'; - html += '
'+(currentClass?.join_code||'—')+'
Klassencode
'; - html += '
'; + // === NEU: Interventions-Übersicht (Erfolg · Aktiv · Verlauf + Triage) === + html += ivBuildOverview(cockpit, weeks, students.length, matrix); // === Sektion B: Aktive Klassen-Simulationen === var active = (assignments || []).filter(function(a){return a.active;});