/* ===================================================================== aether-police / Ansicht: MDT Drei Reiter: Personen, Fahrzeuge, Akten. Die Ansicht zeigt und dokumentiert — sie bewertet nichts und löst keine Maßnahme aus. Jede Änderung verlangt eine Bestätigung. ===================================================================== */ "use strict"; (() => { const { sicher, zeit, aufruf, meldung, fenster, bestaetigen, $, anClient } = App; /* Zustand der Ansicht */ const z = { reiter: "personen", // personen | fahrzeuge | akten suche: "", treffer: [], offenePerson: null, // geladene Personenakte offenesFahrzeug: null, offeneAkte: null, akteFilter: { typ: "", status: "" }, stammdaten: null, // Aktenarten, Beteiligtenrollen }; /* ---- kleine Bausteine ------------------------------------------- */ const gefahrText = ["keine", "gering", "erhöht", "hoch"]; /** Marke für die Gefahrenstufe einer Person */ function gefahrMarke(stufe) { const s = Number(stufe) || 0; if (s === 0) return ""; const art = s >= 3 ? "kritisch" : s === 2 ? "warn" : "neutral"; return `Gefahr: ${gefahrText[s]}`; } function reiterLeiste() { const reiter = [ { id: "personen", name: "Personen", symbol: "👤" }, { id: "fahrzeuge", name: "Fahrzeuge", symbol: "🚗" }, { id: "akten", name: "Akten", symbol: "🗂" }, ]; return `
${reiter.map((r) => ``).join("")}
`; } /* ===================================================================== PERSONEN ===================================================================== */ function personenTrefferListe() { if (!z.treffer.length) { return `
${z.suche ? "Keine Treffer." : "Suchbegriff eingeben — Name, Geburtsdatum oder Telefonnummer."}
`; } return `
${z.treffer.map((p) => `
${sicher(p.firstname + " " + p.lastname)} ${p.fahndung > 0 ? 'Fahndung' : ""} ${gefahrMarke(p.gefahrenstufe)}
geb. ${sicher(String(p.dob || "").slice(0, 10))} ${p.telefon ? " · ☎ " + sicher(p.telefon) : ""} ${p.job ? " · " + sicher(p.job) : ""}
`).join("")}
`; } /** Zeichnet eine vollständige Personenakte */ function personenAkte(d) { const p = d.person; const lizenzName = { perso: "Personalausweis", fs: "Führerschein", ws: "Waffenschein", gk: "Gesundheitskarte", vk: "Visitenkarte", }; return `
${p.lichtbild ? `Lichtbild` : `Kein Lichtbild`}

${sicher(p.firstname + " " + p.lastname)}

Geboren${sicher(String(p.dob || "").slice(0, 10))} Geschlecht${sicher(p.gender || "—")} Herkunft${sicher(p.nationality || "—")} Beruf${sicher(p.job || "—")} Telefon${sicher(d.telefon || "—")} Fingerabdruck${sicher(p.fingerabdruck || "nicht erfasst")} DNA${sicher(p.dna || "nicht erfasst")}
${p.warnhinweis ? `
⚠ Warnhinweis: ${sicher(p.warnhinweis)} — Gefahrenstufe ${gefahrText[Number(p.gefahrenstufe) || 0]}
` : ""} ${d.fahndung ? `
🔍 Zur Fahndung ausgeschrieben: ${sicher(d.fahndung.grund)} (${sicher(d.fahndung.gefahr)})
` : ""} ${d.gewahrsam ? `
🔒 In Gewahrsam — ${sicher(d.gewahrsam.grund || "ohne Grundangabe")}; Frist ${Number(d.gewahrsam.rest) <= 0 ? "abgelaufen" : "noch " + d.gewahrsam.rest + " Minuten"}. Eine Entlassung entscheidet ein Beamter.
` : ""}
Dokumente & Lizenzen
${d.lizenzen.length ? `
${d.lizenzen.map((l) => `
${sicher(lizenzName[l.typ] || l.typ)}
${l.nummer ? sicher(l.nummer) : "—"} ${l.klassen ? " · Klassen " + sicher(l.klassen.join(", ")) : ""} ${l.gueltigBis ? " · gültig bis " + sicher(l.gueltigBis) : ""}
${l.entzogen ? "entzogen" : l.gueltig ? "gültig" : "abgelaufen"}
`).join("")}
` : `
Keine Dokumente hinterlegt.
`}
Bekannte Fahrzeuge
${d.fahrzeuge.length ? `
${d.fahrzeuge.map((f) => `
${sicher(f.name || f.model)} ${f.fahndung > 0 ? 'Fahndung' : ""}
${sicher(f.plate)} · ${sicher(f.state === "impound" ? "sichergestellt" : f.state === "out" ? "unterwegs" : "eingeparkt")}
`).join("")}
` : `
Keine Fahrzeuge zugeordnet.
`}
Vorgänge & Anzeigen ${d.anzeigen.length}
${d.anzeigen.length ? `
${d.anzeigen.map((a) => `
${sicher((a.delikte || []).map((x) => x.name).join(", ") || "Anzeige")}
${zeit(a.erstellt_am)} ${a.status === "bestaetigt" ? ` · ${a.haft_final} Min · ${App.euro(a.geld_final)}` : ""}
${sicher(a.status)}
`).join("")}
` : `
Keine Vorgänge erfasst.
`}
Verknüpfte Akten
${d.akten.length ? `
${d.akten.map((a) => `
${sicher(a.titel)}
${sicher(a.aktenzeichen)} · ${sicher(a.typ)} ${a.rolle ? " · " + sicher(a.rolle) : ""}
${sicher(a.status)}
`).join("")}
` : `
Keine Akten verknüpft.
`}
Bekannte Kontakte
${d.kontakte.length ? `
${d.kontakte.map((k) => `
${sicher(k.name)}
☎ ${sicher(k.number)}
${k.charakterId ? 'bekannt' : ""}
`).join("")}
` : `
Keine Kontakte bekannt.
`}
Notizen ${d.notizen.length}
${d.notizen.length ? `
${d.notizen.map((n) => `
${sicher(n.text)}
${sicher((n.firstname || "") + " " + (n.lastname || ""))} · ${zeit(n.am)}
`).join("")}
` : `
Keine Notizen.
`}
`; } /* ---- Aktionen an der Personenakte -------------------------------- */ function verdrahtePersonenakte(behaelter, charakterId) { // Notiz hinzufügen const notizKnopf = $("p-notiz"); if (notizKnopf) notizKnopf.addEventListener("click", () => { fenster({ titel: "Notiz hinzufügen", inhalt: `
Notizen sind für alle Beamten sichtbar und werden protokolliert.
`, knoepfe: [ { text: "Abbrechen", klick: (_, zu) => zu() }, { text: "Speichern", art: "", klick: async (el, zu) => { const text = el.querySelector("#nz-text").value.trim(); if (text.length < 3) { meldung("Bitte einen Text eingeben.", "fehler"); return; } try { await aufruf("mdt", "personNotiz", { charakterId, text }); zu(); meldung("Notiz gespeichert.", "gut"); oeffnePerson(behaelter, charakterId); } catch (f) { meldung(f.message, "fehler"); } }}, ], }); }); // Notiz entfernen behaelter.querySelectorAll("[data-notiz-weg]").forEach((b) => { b.addEventListener("click", async (e) => { e.stopPropagation(); try { await aufruf("mdt", "personNotizLoeschen", { id: +b.dataset.notizWeg }); oeffnePerson(behaelter, charakterId); } catch (f) { meldung(f.message, "fehler"); } }); }); // Warnhinweis setzen const warnKnopf = $("p-warn"); if (warnKnopf) warnKnopf.addEventListener("click", () => { const p = z.offenePerson.person; bestaetigen({ titel: "Warnhinweis festlegen", inhalt: `
`, bestaetigenText: "Warnhinweis setzen", bestaetigt: async (el, zu) => { try { await aufruf("mdt", "personWarnhinweis", { charakterId, hinweis: el.querySelector("#wh-text").value.trim(), stufe: +el.querySelector("#wh-stufe").value, grund: el.querySelector("#wh-grund").value.trim(), }); zu(); meldung("Warnhinweis aktualisiert.", "gut"); oeffnePerson(behaelter, charakterId); } catch (f) { meldung(f.message, "fehler"); } }, }); }); // Erkennungsdienstliche Daten const edKnopf = $("p-ed"); if (edKnopf) edKnopf.addEventListener("click", () => { const p = z.offenePerson.person; fenster({ titel: "Erkennungsdienstliche Daten", inhalt: `
Die Aufnahme selbst erfolgt im Rollenspiel — hier wird nur dokumentiert.
`, knoepfe: [ { text: "Abbrechen", klick: (_, zu) => zu() }, { text: "Speichern", klick: async (el, zu) => { try { await aufruf("mdt", "personStammdaten", { charakterId, fingerabdruck: el.querySelector("#ed-finger").value.trim(), dna: el.querySelector("#ed-dna").value.trim(), lichtbild: el.querySelector("#ed-bild").value.trim(), }); zu(); meldung("Daten gespeichert.", "gut"); oeffnePerson(behaelter, charakterId); } catch (f) { meldung(f.message, "fehler"); } }}, ], }); }); // Akte direkt zu dieser Person anlegen const akteKnopf = $("p-akte-neu"); if (akteKnopf) akteKnopf.addEventListener("click", () => akteAnlegenDialog(behaelter, { typ: "person", id: charakterId })); // Sprünge in andere Akten behaelter.querySelectorAll("[data-akte]").forEach((el) => el.addEventListener("click", () => { z.reiter = "akten"; oeffneAkte(behaelter, +el.dataset.akte); })); behaelter.querySelectorAll("[data-fahrzeug]").forEach((el) => el.addEventListener("click", () => { z.reiter = "fahrzeuge"; oeffneFahrzeug(behaelter, el.dataset.fahrzeug); })); behaelter.querySelectorAll("[data-person]").forEach((el) => el.addEventListener("click", () => oeffnePerson(behaelter, +el.dataset.person))); } async function oeffnePerson(behaelter, charakterId) { try { const daten = await aufruf("mdt", "personAkte", { charakterId }); z.offenePerson = daten; z.reiter = "personen"; zeichne(behaelter, personenAkte(daten), () => verdrahtePersonenakte(behaelter, charakterId), true); } catch (f) { meldung(f.message, "fehler"); } } /* ===================================================================== FAHRZEUGE ===================================================================== */ function fahrzeugTrefferListe() { if (!z.treffer.length) { return `
${z.suche ? "Keine Treffer." : "Kennzeichen, Modell oder Halter eingeben."}
`; } return `
${z.treffer.map((f) => `
${sicher(f.plate)}
${sicher(f.name || f.model)} ${f.fahndung > 0 ? 'Fahndung' : ""} ${f.state === "impound" ? 'sichergestellt' : ""}
Halter: ${sicher((f.firstname || "unbekannt") + " " + (f.lastname || ""))}
`).join("")}
`; } function fahrzeugAkte(d) { const f = d.fahrzeug; const zustandText = { in: "eingeparkt", out: "unterwegs", impound: "sichergestellt" }; return `
${sicher(f.plate)}

${sicher(f.name || f.model)}

Modell${sicher(f.model)} Klasse${sicher(f.klasse || "—")} Farbe${f.farbe ? ` ${sicher(f.farbe)}` : "—"} Status${sicher(zustandText[f.state] || f.state)} Standort${sicher(f.garage || "—")} Kilometerstand${sicher(f.mileage || 0)} km
${f.owner ? `` : ""}
${d.fahndung ? `
🔍 Fahrzeug zur Fahndung ausgeschrieben: ${sicher(d.fahndung.grund)}
` : ""}
Halter
${f.owner ? `
${sicher((f.firstname || "") + " " + (f.lastname || ""))}
geb. ${sicher(String(f.dob || "").slice(0, 10))}
` : `
Kein Halter eingetragen.
`}
Verknüpfte Akten
${d.akten.length ? `
${d.akten.map((a) => `
${sicher(a.titel)}
${sicher(a.aktenzeichen)} · ${sicher(a.typ)}
`).join("")}
` : `
Keine Akten verknüpft.
`}
Historie
${d.historie.length ? `
${d.historie.map((h) => `
${sicher(h.aktion)}
${sicher((h.firstname || "") + " " + (h.lastname || ""))} ${h.dienstnummer ? " · " + sicher(h.dienstnummer) : ""} · ${zeit(h.am)} ${h.grund ? " · " + sicher(h.grund) : ""}
`).join("")}
` : `
Keine dokumentierten Vorgänge.
`}
`; } async function oeffneFahrzeug(behaelter, kennzeichen) { try { const daten = await aufruf("mdt", "fahrzeugAkte", { kennzeichen }); z.offenesFahrzeug = daten; z.reiter = "fahrzeuge"; zeichne(behaelter, fahrzeugAkte(daten), () => { behaelter.querySelectorAll("[data-person]").forEach((el) => el.addEventListener("click", () => oeffnePerson(behaelter, +el.dataset.person))); behaelter.querySelectorAll("[data-akte]").forEach((el) => el.addEventListener("click", () => oeffneAkte(behaelter, +el.dataset.akte))); const neu = $("v-akte-neu"); if (neu) neu.addEventListener("click", () => akteAnlegenDialog(behaelter, { typ: "fahrzeug", id: daten.fahrzeug.plate })); }, true); } catch (f) { meldung(f.message, "fehler"); } } /* ===================================================================== AKTEN ===================================================================== */ function aktenListe(akten) { if (!akten.length) return `
Keine Akten gefunden.
`; const statusArt = { offen: "warn", pruefung: "info", geschlossen: "neutral" }; return `
${akten.map((a) => `
${sicher(a.typ)}
${sicher(a.titel)}
${sicher(a.aktenzeichen)} · ${sicher((a.firstname || "") + " " + (a.lastname || ""))} · ${zeit(a.erstellt_am)} ${a.version > 1 ? ` · Version ${a.version}` : ""}
${sicher(a.status)}
`).join("")}
`; } function akteAnsicht(d) { const a = d.akte; const statusArt = { offen: "warn", pruefung: "info", geschlossen: "neutral" }; return `

${sicher(a.titel)}

Aktenzeichen${sicher(a.aktenzeichen)} Art${sicher(a.typ)} Angelegt von${sicher((a.firstname || "") + " " + (a.lastname || ""))} Angelegt am${zeit(a.erstellt_am)} Version${sicher(a.version)}
${sicher(a.status)} ${d.darfBearbeiten ? `` : ""} ${d.darfBearbeiten ? `` : ""} ${d.darfSchliessen && a.status !== "geschlossen" ? `` : ""}
Sachverhalt
${a.inhalt ? sicher(a.inhalt).replace(/\n/g, "
") : "Kein Inhalt hinterlegt."}
Verknüpfungen ${d.verknuepfungen.length}
${d.verknuepfungen.length ? `
${d.verknuepfungen.map((v) => `
${sicher(v.typ)}
${sicher(v.bezeichnung || v.ziel_id)}
${v.rolle ? `
${sicher(v.rolle)}
` : ""}
${d.darfBearbeiten ? `` : ""}
`).join("")}
` : `
Nichts verknüpft.
`}
Änderungshistorie
${d.versionen.length ? `
${d.versionen.map((v) => `
v${sicher(v.version)}
${sicher(v.grund || "ohne Angabe")}
${sicher((v.firstname || "") + " " + (v.lastname || ""))} · ${zeit(v.geaendert_am)}
`).join("")}
` : `
Keine Änderungen.
`}
`; } async function oeffneAkte(behaelter, akteId) { try { const daten = await aufruf("mdt", "akteOeffnen", { id: akteId }); z.offeneAkte = daten; z.reiter = "akten"; zeichne(behaelter, akteAnsicht(daten), () => verdrahteAkte(behaelter, daten), true); } catch (f) { meldung(f.message, "fehler"); } } function verdrahteAkte(behaelter, d) { const a = d.akte; const bearbeiten = $("a-bearbeiten"); if (bearbeiten) bearbeiten.addEventListener("click", () => { fenster({ titel: "Akte bearbeiten", inhalt: `
Jede Änderung erzeugt eine neue Version. Die alte bleibt nachvollziehbar.
`, knoepfe: [ { text: "Abbrechen", klick: (_, zu) => zu() }, { text: "Speichern", klick: async (el, zu) => { try { await aufruf("mdt", "akteBearbeiten", { id: a.id, titel: el.querySelector("#ab-titel").value.trim(), inhalt: el.querySelector("#ab-inhalt").value, grund: el.querySelector("#ab-grund").value.trim(), }); zu(); meldung("Akte gespeichert.", "gut"); oeffneAkte(behaelter, a.id); } catch (f) { meldung(f.message, "fehler"); } }}, ], }); }); const verknuepfen = $("a-verknuepfen"); if (verknuepfen) verknuepfen.addEventListener("click", () => { const rollen = (z.stammdaten && z.stammdaten.rollen) || []; fenster({ titel: "Verknüpfung hinzufügen", inhalt: `
`, knoepfe: [ { text: "Abbrechen", klick: (_, zu) => zu() }, { text: "Verknüpfen", klick: async (el, zu) => { try { await aufruf("mdt", "akteVerknuepfen", { akteId: a.id, typ: el.querySelector("#vk-typ").value, zielId: el.querySelector("#vk-ziel").value.trim(), rolle: el.querySelector("#vk-rolle").value || null, }); zu(); meldung("Verknüpfung angelegt.", "gut"); oeffneAkte(behaelter, a.id); } catch (f) { meldung(f.message, "fehler"); } }}, ], }); }); behaelter.querySelectorAll("[data-vk-weg]").forEach((b) => b.addEventListener("click", async () => { try { await aufruf("mdt", "akteVerknuepfungLoesen", { id: +b.dataset.vkWeg }); oeffneAkte(behaelter, a.id); } catch (f) { meldung(f.message, "fehler"); } })); const schliessen = $("a-schliessen"); if (schliessen) schliessen.addEventListener("click", () => { bestaetigen({ titel: "Akte schließen", gefahr: true, inhalt: `

Die Akte ${sicher(a.aktenzeichen)} wird als abgeschlossen gekennzeichnet. Es wird festgehalten, dass du diese Entscheidung getroffen hast.

`, bestaetigenText: "Akte schließen", bestaetigt: async (el, zu) => { try { await aufruf("mdt", "akteStatus", { id: a.id, status: "geschlossen", grund: el.querySelector("#as-grund").value.trim(), }); zu(); meldung("Akte geschlossen.", "gut"); oeffneAkte(behaelter, a.id); } catch (f) { meldung(f.message, "fehler"); } }, }); }); behaelter.querySelectorAll("[data-person]").forEach((el) => el.addEventListener("click", () => oeffnePerson(behaelter, +el.dataset.person))); behaelter.querySelectorAll("[data-fahrzeug]").forEach((el) => el.addEventListener("click", () => oeffneFahrzeug(behaelter, el.dataset.fahrzeug))); } /** Dialog zum Anlegen einer Akte, optional gleich verknüpft */ function akteAnlegenDialog(behaelter, verknuepfung) { const arten = (z.stammdaten && z.stammdaten.aktenarten) || []; const rollen = (z.stammdaten && z.stammdaten.rollen) || []; fenster({ titel: "Akte anlegen", inhalt: `
${verknuepfung ? `
` : ""}`, knoepfe: [ { text: "Abbrechen", klick: (_, zu) => zu() }, { text: "Akte anlegen", klick: async (el, zu) => { try { const ergebnis = await aufruf("mdt", "akteErstellen", { typ: el.querySelector("#an-typ").value, titel: el.querySelector("#an-titel").value.trim(), inhalt: el.querySelector("#an-inhalt").value, verknuepfeTyp: verknuepfung && verknuepfung.typ, verknuepfeId: verknuepfung && verknuepfung.id, verknuepfeRolle: verknuepfung ? (el.querySelector("#an-rolle") || {}).value : null, }); zu(); meldung("Akte " + ergebnis.aktenzeichen + " angelegt.", "gut"); oeffneAkte(behaelter, ergebnis.id); } catch (f) { meldung(f.message, "fehler"); } }}, ], }); } /* ===================================================================== Gerüst ===================================================================== */ /** * Zeichnet den MDT-Rahmen mit Inhalt. * @param {boolean} detail Wenn true, wird ein Zurück-Knopf gezeigt. */ function zeichne(behaelter, inhalt, nachher, detail) { const suchfeld = { personen: "Name, Geburtsdatum oder Telefonnummer …", fahrzeuge: "Kennzeichen, Modell oder Halter …", akten: "Aktenzeichen oder Titel …", }[z.reiter]; behaelter.innerHTML = `

MDT

Personen, Fahrzeuge und Akten

${z.reiter === "akten" ? `` : ""}
${reiterLeiste()} ${detail ? `` : `
${z.reiter === "akten" ? ` ` : ""}
`}
${inhalt}
`; // Reiter wechseln behaelter.querySelectorAll("[data-reiter]").forEach((b) => b.addEventListener("click", () => { z.reiter = b.dataset.reiter; z.suche = ""; z.treffer = []; rendern(behaelter); })); const zurueck = $("mdt-zurueck"); if (zurueck) zurueck.addEventListener("click", () => rendern(behaelter)); const neueAkte = $("mdt-akte-neu"); if (neueAkte) neueAkte.addEventListener("click", () => akteAnlegenDialog(behaelter, null)); // Suche const suchfeldEl = $("mdt-suche"); if (suchfeldEl) { const suchen = () => { z.suche = suchfeldEl.value.trim(); ausfuehrenSuche(behaelter); }; suchfeldEl.addEventListener("keydown", (e) => { if (e.key === "Enter") suchen(); }); $("mdt-suchen").addEventListener("click", suchen); } ["mdt-filter-typ", "mdt-filter-status"].forEach((id) => { const el = $(id); if (el) el.addEventListener("change", () => { z.akteFilter.typ = ($("mdt-filter-typ") || {}).value || ""; z.akteFilter.status = ($("mdt-filter-status") || {}).value || ""; ausfuehrenSuche(behaelter); }); }); if (nachher) nachher(); } /** Führt die Suche des aktiven Reiters aus */ async function ausfuehrenSuche(behaelter) { try { if (z.reiter === "personen") { if (!z.suche) { z.treffer = []; zeichne(behaelter, personenTrefferListe(), () => verdrahteTreffer(behaelter)); return; } const d = await aufruf("mdt", "personSuchen", { begriff: z.suche }); z.treffer = d.treffer; zeichne(behaelter, personenTrefferListe(), () => verdrahteTreffer(behaelter)); } else if (z.reiter === "fahrzeuge") { if (!z.suche) { z.treffer = []; zeichne(behaelter, fahrzeugTrefferListe(), () => verdrahteTreffer(behaelter)); return; } const d = await aufruf("mdt", "fahrzeugSuchen", { begriff: z.suche }); z.treffer = d.treffer; zeichne(behaelter, fahrzeugTrefferListe(), () => verdrahteTreffer(behaelter)); } else { const d = await aufruf("mdt", "aktenListe", { begriff: z.suche, typ: z.akteFilter.typ, status: z.akteFilter.status, }); zeichne(behaelter, aktenListe(d.akten), () => verdrahteTreffer(behaelter)); } } catch (f) { meldung(f.message, "fehler"); } } function verdrahteTreffer(behaelter) { behaelter.querySelectorAll("[data-person]").forEach((el) => el.addEventListener("click", () => oeffnePerson(behaelter, +el.dataset.person))); behaelter.querySelectorAll("[data-fahrzeug]").forEach((el) => el.addEventListener("click", () => oeffneFahrzeug(behaelter, el.dataset.fahrzeug))); behaelter.querySelectorAll("[data-akte]").forEach((el) => el.addEventListener("click", () => oeffneAkte(behaelter, +el.dataset.akte))); } async function rendern(behaelter) { // Stammdaten einmalig holen (Aktenarten, Beteiligtenrollen) if (!z.stammdaten) { try { z.stammdaten = await aufruf("mdt", "stammdaten", {}); } catch (f) { z.stammdaten = {}; } } /* Sprungziel eines anderen Moduls auswerten, z. B. aus einer Fahndung. Es gilt nur einmal und wird danach verworfen. */ const ziel = App.zustand.modulZiel; if (ziel) { App.zustand.modulZiel = null; if (ziel.person) { await oeffnePerson(behaelter, +ziel.person); return; } if (ziel.fahrzeug) { await oeffneFahrzeug(behaelter, ziel.fahrzeug); return; } if (ziel.akte) { await oeffneAkte(behaelter, +ziel.akte); return; } } await ausfuehrenSuche(behaelter); } /* ---- Registrierung ----------------------------------------------- */ App.registriereAnsicht("mdt", { rendern }); /* Globale Suche bedienen */ App.registriereSuche(async (begriff) => { const treffer = []; try { const personen = await aufruf("mdt", "personSuchen", { begriff }); (personen.treffer || []).slice(0, 5).forEach((p) => treffer.push({ bereich: "Person", titel: p.firstname + " " + p.lastname, unter: "geb. " + String(p.dob || "").slice(0, 10), })); } catch (e) { /* Bereich überspringen */ } try { const fahrzeuge = await aufruf("mdt", "fahrzeugSuchen", { begriff }); (fahrzeuge.treffer || []).slice(0, 5).forEach((f) => treffer.push({ bereich: "Fahrzeug", titel: f.plate + " · " + (f.name || f.model), unter: "Halter: " + ((f.firstname || "unbekannt") + " " + (f.lastname || "")), })); } catch (e) { /* Bereich überspringen */ } try { const akten = await aufruf("mdt", "aktenListe", { begriff }); (akten.akten || []).slice(0, 5).forEach((a) => treffer.push({ bereich: "Akte", titel: a.titel, unter: a.aktenzeichen + " · " + a.typ, })); } catch (e) { /* Bereich überspringen */ } return treffer; }); })();