-- ===================================================================== -- aether-police / Modul: Dashboard -- -- Zeigt eine Lageübersicht. Alle Zahlen werden bei jedem Aufruf frisch -- aus der Datenbank bzw. dem Dienstsystem geholt — nichts ist fest -- programmiert. Das Dashboard bewertet nichts, es zeigt nur an. -- ===================================================================== Kern.RegistriereModul({ id = 'dashboard', name = 'Übersicht', icon = '▤', reihenfolge = 1, beschreibung = 'Lageübersicht der Dienststelle', }) --- Sammelt alle Kennzahlen für die Übersicht Kern.RegistriereAktion('dashboard', 'laden', nil, function(quelle, beamter) local charakterId = beamter.charakterId -- --- Beamte im Dienst --- local dienstliste = Dienst.BaueListe() local nachStatus = {} for _, eintrag in ipairs(dienstliste) do nachStatus[eintrag.status] = (nachStatus[eintrag.status] or 0) + 1 end -- --- Offene Einsätze --- local einsaetze = MySQL.query.await([[ SELECT id, nummer, titel, kategorie, prioritaet, ort, status, erstellt_am, pos_x, pos_y, pos_z FROM police_einsatz WHERE status <> 'abgeschlossen' ORDER BY prioritaet ASC, id DESC LIMIT 20 ]]) or {} -- --- Offene Anzeigen (Entwürfe warten auf Bestätigung) --- local anzeigenOffen = MySQL.scalar.await( "SELECT COUNT(*) FROM police_anzeige WHERE status = 'entwurf'") or 0 -- --- Aktive Fahndungen --- local fahndungen = MySQL.query.await([[ SELECT id, typ, bezeichnung, grund, gefahr, prioritaet FROM police_fahndung WHERE aktiv = 1 ORDER BY prioritaet ASC, id DESC LIMIT 10 ]]) or {} -- --- Gefangene und auslaufende Haftzeiten --- local gewahrsam = MySQL.query.await([[ SELECT g.id, g.character, g.grund, g.faellig_am, g.zelle, TIMESTAMPDIFF(MINUTE, NOW(), g.faellig_am) AS rest, c.firstname, c.lastname FROM police_gewahrsam g JOIN aether_characters c ON c.id = g.character WHERE g.entlassen_am IS NULL ORDER BY g.faellig_am ASC ]]) or {} local abgelaufen = 0 for _, eintrag in ipairs(gewahrsam) do if (tonumber(eintrag.rest) or 0) <= 0 then abgelaufen = abgelaufen + 1 end end -- --- Offene Berichte des eigenen Beamten --- local eigeneBerichte = MySQL.query.await([[ SELECT id, nummer, titel, status, erstellt_am FROM police_bericht WHERE erstellt_von = ? AND status = 'entwurf' ORDER BY id DESC LIMIT 10 ]], { charakterId }) or {} -- --- Akten, die auf Freigabe warten --- local akteFreigabe = MySQL.scalar.await( "SELECT COUNT(*) FROM police_akte WHERE status = 'pruefung'") or 0 -- --- Dienstfahrzeuge im Einsatz --- local fahrzeuge = MySQL.query.await([[ SELECT id, kennzeichen, bezeichnung, status, wartung, tank, zugewiesen_an FROM police_fahrzeug ORDER BY kennzeichen ASC ]]) or {} local fahrzeugeImEinsatz = 0 local wartungFaellig = 0 for _, fahrzeug in ipairs(fahrzeuge) do if fahrzeug.status ~= 'verfuegbar' then fahrzeugeImEinsatz = fahrzeugeImEinsatz + 1 end if fahrzeug.wartung ~= 'ok' then wartungFaellig = wartungFaellig + 1 end end -- --- Neueste Mitteilungen --- local mitteilungen = MySQL.query.await([[ SELECT n.id, n.betreff, n.text, n.gesendet, c.firstname, c.lastname FROM police_nachricht n LEFT JOIN aether_characters c ON c.id = n.absender WHERE n.empf_typ = 'rundmeldung' OR (n.empf_typ = 'person' AND n.empfaenger = ?) OR (n.empf_typ = 'abteilung' AND n.empfaenger = ?) ORDER BY n.id DESC LIMIT 5 ]], { tostring(charakterId), beamter.abteilung }) or {} -- --- Warnungen zusammenstellen (reine Hinweise) --- local warnungen = {} if abgelaufen > 0 then warnungen[#warnungen + 1] = { prioritaet = 'hoch', text = ('%d Haftzeit%s abgelaufen — Entlassung muss manuell entschieden werden.') :format(abgelaufen, abgelaufen == 1 and '' or 'en'), zielTyp = 'gewahrsam', } end if anzeigenOffen > 0 then warnungen[#warnungen + 1] = { prioritaet = 'normal', text = ('%d Anzeige%s im Entwurf — wartet auf Bestätigung.') :format(anzeigenOffen, anzeigenOffen == 1 and '' or 'n'), zielTyp = 'anzeigen', } end if akteFreigabe > 0 then warnungen[#warnungen + 1] = { prioritaet = 'normal', text = ('%d Akte%s wartet auf Freigabe.') :format(akteFreigabe, akteFreigabe == 1 and '' or 'n'), zielTyp = 'akten', } end if wartungFaellig > 0 then warnungen[#warnungen + 1] = { prioritaet = 'niedrig', text = ('%d Dienstfahrzeug%s benötigt Wartung.') :format(wartungFaellig, wartungFaellig == 1 and '' or 'e'), zielTyp = 'fahrzeuge', } end return { kennzahlen = { imDienst = #dienstliste, verfuegbar = nachStatus.verfuegbar or 0, imEinsatz = nachStatus.einsatz or 0, pause = nachStatus.pause or 0, einsaetzeOffen = #einsaetze, anzeigenOffen = anzeigenOffen, fahndungen = #fahndungen, gefangene = #gewahrsam, haftAbgelaufen = abgelaufen, berichteOffen = #eigeneBerichte, akteFreigabe = akteFreigabe, fahrzeugeGesamt = #fahrzeuge, fahrzeugeEinsatz= fahrzeugeImEinsatz, }, beamte = dienstliste, einsaetze = einsaetze, fahndungen = fahndungen, gewahrsam = gewahrsam, berichte = eigeneBerichte, fahrzeuge = fahrzeuge, mitteilungen = mitteilungen, warnungen = warnungen, hinweise = Hinweise.Lade(charakterId, 15), } end) --- Markiert einen Hinweis als gelesen Kern.RegistriereAktion('dashboard', 'hinweisGelesen', nil, function(quelle, beamter, daten) if type(daten.id) ~= 'number' then return nil, 'Ungültige Kennung.' end Hinweise.MarkiereGelesen(beamter.charakterId, daten.id) return { ok = true } end)