/* ===================================================================== aether-medical / Ansicht: Fuhrpark Zwei Sorten von Angaben, streng getrennt dargestellt: GEMELDET (Tank, Zustand, Position) kommt aus dem Spiel und trägt immer sein Alter mit sich. EINGETRAGEN (Status, Wartung, Zuweisung) stammt von Menschen. Kein gemeldeter Wert ändert einen eingetragenen. ===================================================================== */ "use strict"; (() => { const { sicher, zeit, minuten, aufruf, meldung, fenster, bestaetigen, anClient } = App; const z = { ordner: "dienst", // dienst | werkstatt | ausser art: "", // Filter auf eine Fahrzeugart daten: null, }; // Marker-Art je Einsatzstatus const statusArt = { verfuegbar: "gut", im_einsatz: "warn", werkstatt: "info", ausser_dienst: "neutral", }; /* ---- Kleine Helfer ---------------------------------------------------- */ /** Anzeigename aus einer Konfigurationsliste */ function nameAus(liste, kennung) { const treffer = (liste || []).find((e) => e.id === kennung); return treffer ? treffer.name : kennung; } /** Farbe eines Balkens nach seinem Wert */ function balkenFarbe(wert, grenze) { if (wert === null || wert === undefined) return "var(--text-leise)"; if (wert <= grenze / 2) return "var(--kritisch)"; if (wert <= grenze) return "var(--warn)"; return "var(--gut)"; } /** * Ein Balken für einen gemeldeten Wert. * Ist die Meldung alt, wird der Balken blass — der Wert sagt dann * nichts über den jetzigen Zustand. */ function balken(titel, wert, grenze, veraltet) { const hat = wert !== null && wert !== undefined; return `
${sicher(titel)} ${hat ? wert + " %" : "nie gemeldet"}
`; } /* ---- Gerüst ------------------------------------------------------------ */ function reiterleiste(d) { const eintraege = [ { id: "dienst", text: "Im Dienst", zahl: d.zaehler.verfuegbar + d.zaehler.imEinsatz }, { id: "werkstatt", text: "Wartung", zahl: d.zaehler.werkstatt }, { id: "ausser", text: "Außer Dienst", zahl: d.zaehler.ausserDienst }, ]; return `
${eintraege.map((e) => ` `).join("")}
`; } function kennzahlen(d) { const zk = d.zaehler; return `
Verfügbar
${zk.verfuegbar}
so eingetragen
Im Einsatz
${zk.imEinsatz}
${zk.zugewiesen} Fahrzeuge zugewiesen
Wartung offen
${zk.werkstatt}
Werkstatt oder fällig
Außer Dienst
${zk.ausserDienst}
fahren nicht
`; } /* ---- Übersicht ---------------------------------------------------------- */ function uebersicht(behaelter) { const d = z.daten; behaelter.innerHTML = `

Fuhrpark

Tank, Zustand und Position werden gemeldet, während jemand fährt. Status, Wartung und Zuweisung trägt ein Mensch ein — das eine ändert das andere nie.

${d.rechte.pflegen ? `` : ""}
${kennzahlen(d)} ${reiterleiste(d)}
Eine Meldung älter als ${d.grenzen.meldung} Minuten wird blass dargestellt.
${d.liste.length ? `
${d.liste.map((f) => karte(f, d)).join("")}
` : `
Kein Fahrzeug in diesem Ordner.
`} `; verdrahteUebersicht(behaelter); } function karte(f, d) { return `
${sicher(f.bezeichnung)}
${sicher(f.kennzeichen)}
${sicher(f.statusName)}
${sicher(f.artName)} ${f.wartung !== "ok" ? `${sicher(f.wartungName)}` : ""} ${f.zugewiesenAn ? `${sicher(f.zugewiesenAn)}` : ""}
${balken("Tank", f.tank, d.grenzen.tank, f.meldungVeraltet)} ${balken("Zustand", f.zustand, d.grenzen.zustand, f.meldungVeraltet)}
${f.gemeldet_am ? `gemeldet vor ${sicher(minuten(f.meldungAlter))}${ f.letzterFahrer ? " · " + sicher(f.letzterFahrer) : ""}` : "noch nie gemeldet"} ${f.notiz ? ` · ${sicher(f.notiz)}` : ""}
`; } function verdrahteUebersicht(behaelter) { behaelter.querySelectorAll("[data-reiter]").forEach((el) => { el.addEventListener("click", () => { z.ordner = el.dataset.reiter; rendern(behaelter); }); }); behaelter.querySelector("[data-artfilter]").addEventListener("change", (e) => { z.art = e.target.value; rendern(behaelter); }); behaelter.querySelectorAll("[data-oeffne]").forEach((el) => { el.addEventListener("click", () => fahrzeugFenster(behaelter, +el.dataset.oeffne)); }); const neu = behaelter.querySelector("[data-neu]"); if (neu) neu.addEventListener("click", () => bearbeitenFenster(behaelter, null)); } /* ---- Einzelnes Fahrzeug ---------------------------------------------------- */ async function fahrzeugFenster(behaelter, fahrzeugId) { let d; try { d = await aufruf("fahrzeug", "oeffnen", { id: fahrzeugId }); } catch (f) { return meldung(f.message, "fehler"); } const f = d.fahrzeug; const ausstattung = String(f.ausstattung || "") .split(",").map((t) => t.trim()).filter(Boolean); const dialog = fenster({ titel: `${f.bezeichnung} · ${f.kennzeichen}`, inhalt: ` ${f.wartung !== "ok" ? `
🔧
${sicher(f.wartungName)}${f.notiz ? " — " + sicher(f.notiz) : ""}. Eingetragen von Hand; ob das Fahrzeug fährt, steht im Einsatzstatus.
` : ""} ${f.meldungVeraltet ? `
🕓
Die letzte Meldung ist ${sicher(minuten(f.meldungAlter))} alt. Tank und Zustand sagen nichts über den jetzigen Stand.
` : ""}
Einsatzstatus${sicher(f.statusName)}
Wartung${sicher(f.wartungName)}
Art${sicher(f.artName)}
Modell${sicher(f.modell)}
Station${sicher(f.station || "—")}
Zugewiesen an ${sicher(f.zugewiesenAn || "niemand")}
Gemeldet ${f.gemeldetAm ? "vor " + sicher(minuten(f.meldungAlter)) + " von " + sicher(f.letzterFahrer || "unbekannt") : "noch nie"}
${balken("Tank", f.tank, 20, f.meldungVeraltet)} ${balken("Zustand", f.zustand, 60, f.meldungVeraltet)}
${f.position ? `` : `
Keine Position gemeldet.
`}
Ausstattung notiert, nicht geprüft
${ausstattung.length ? `
${ausstattung.map((a) => `${sicher(a)}`).join("")}
` : `
Nichts eingetragen.
`}
${d.rechte.zuweisen ? ` ` : ""} ${d.rechte.wartung ? `` : ""} ${d.rechte.pflegen ? `` : ""} ${d.rechte.pflegen && f.status === "ausser_dienst" ? `` : ""}
Eingetragene Vorgänge aus dem Protokoll, unveränderlich
${d.spur.length ? d.spur.map((s) => `
${sicher(s.aktion)}
${sicher(s.autor)} ${s.grund ? " · " + sicher(s.grund) : ""}
${zeit(s.am)}
`).join("") : `
Noch kein Eintrag.
`}
`, nachOeffnen: (hg) => { const wegpunkt = hg.querySelector("[data-wegpunkt]"); if (wegpunkt) { wegpunkt.addEventListener("click", () => { anClient("wegpunkt", { x: f.position.x, y: f.position.y }); meldung("Wegpunkt zur letzten gemeldeten Position gesetzt."); }); } const knopf = (name, funktion) => { const el = hg.querySelector(`[data-${name}]`); if (el) el.addEventListener("click", () => { dialog.schliessen(); funktion(); }); }; knopf("status", () => statusFenster(behaelter, f, d)); knopf("zuweisen", () => zuweisenFenster(behaelter, f)); knopf("wartung", () => wartungFenster(behaelter, f, d)); knopf("bearbeiten", () => bearbeitenFenster(behaelter, f)); knopf("entfernen", () => entfernenFenster(behaelter, f)); }, }); } /* ---- Einsatzstatus ----------------------------------------------------------- */ function statusFenster(behaelter, f, d) { bestaetigen({ titel: "Einsatzstatus setzen", inhalt: `

Aktuell eingetragen: ${sicher(f.statusName)}

Werkstatt und Außer Dienst darf nur eintragen, wer die Wartung führt — und beides braucht einen Grund.
${f.zugewiesenAn ? `
🧍
Das Fahrzeug ist ${sicher(f.zugewiesenAn)} zugewiesen. Bei Werkstatt oder Außer Dienst wird das gemeldet — die Zuweisung selbst bleibt bestehen.
` : ""}`, bestaetigenText: "Status setzen", bestaetigt: async (el, zu) => { try { await aufruf("fahrzeug", "status", { id: f.id, status: el.querySelector("[name=status]").value, grund: el.querySelector("[name=grund]").value.trim(), }); zu(); meldung("Status gesetzt.", "gut"); rendern(behaelter); } catch (fehler) { meldung(fehler.message, "fehler"); } }, }); } /* ---- Zuweisung ------------------------------------------------------------------ */ async function zuweisenFenster(behaelter, f) { let k; try { k = await aufruf("fahrzeug", "kollegen", {}); } catch (fehler) { return meldung(fehler.message, "fehler"); } let gewaehlt = f.zugewiesen || null; let aufheben = false; bestaetigen({ titel: `${f.bezeichnung} zuweisen`, inhalt: `

Zugewiesen ist zurzeit: ${sicher(f.zugewiesenAn || "niemand")}

ℹ
Eine Zuweisung ist ein Eintrag im Fahrzeugbuch. Sie spawnt kein Fahrzeug, schließt keines auf und gibt keinen Schlüssel aus.
${k.liste.length ? k.liste.map((p) => `
${sicher(p.name)} ${p.selbst ? `du` : ""}
${sicher(p.rolleName)} · ${sicher(p.personalnummer || "")}
${sicher(p.funktion || "")}
`).join("") : `
Niemand im Dienst.
`}
`, bestaetigenText: "Eintragen", bestaetigt: async (el, zu) => { const grund = el.querySelector("[name=grund]").value.trim(); if (aufheben && !grund) { return meldung("Bitte angeben, warum die Zuweisung entfällt.", "fehler"); } if (!aufheben && !gewaehlt) { return meldung("Bitte eine Person wählen.", "fehler"); } try { await aufruf("fahrzeug", "zuweisen", { id: f.id, charakter: aufheben ? null : gewaehlt, grund, }); zu(); meldung(aufheben ? "Zuweisung aufgehoben." : "Fahrzeug zugewiesen.", "gut"); rendern(behaelter); } catch (fehler) { meldung(fehler.message, "fehler"); } }, nachOeffnen: (hg) => { hg.querySelectorAll("[data-person]").forEach((el) => { el.addEventListener("click", () => { gewaehlt = +el.dataset.person; hg.querySelectorAll("[data-person]") .forEach((zeile) => zeile.classList.remove("gewaehlt")); el.classList.add("gewaehlt"); }); }); const haken = hg.querySelector("[name=aufheben]"); haken.addEventListener("change", () => { aufheben = haken.checked; hg.querySelector("[data-kollegen]").style.opacity = aufheben ? ".45" : ""; }); }, }); } /* ---- Wartung ---------------------------------------------------------------------- */ function wartungFenster(behaelter, f, d) { bestaetigen({ titel: "Wartungsstatus", inhalt: `

Aktuell eingetragen: ${sicher(f.wartungName)}

ℹ
Ein gemeldeter Schaden setzt diesen Status nicht. Was das Spiel meldet, ist eine Beobachtung — ob gewartet wird, beurteilst du.
Ein leeres Feld löscht die Notiz.
`, bestaetigenText: "Eintragen", bestaetigt: async (el, zu) => { try { await aufruf("fahrzeug", "wartung", { id: f.id, wartung: el.querySelector("[name=wartung]").value, notiz: el.querySelector("[name=notiz]").value.trim(), }); zu(); meldung("Wartungsstatus eingetragen.", "gut"); rendern(behaelter); } catch (fehler) { meldung(fehler.message, "fehler"); } }, }); } /* ---- Fahrzeug anlegen und bearbeiten ------------------------------------------------ */ function bearbeitenFenster(behaelter, f) { const d = z.daten; const neu = !f; const vorhanden = String((f && f.ausstattung) || "") .split(",").map((t) => t.trim()).filter(Boolean); const eigene = vorhanden.filter((a) => !d.ausstattung.includes(a)); bestaetigen({ titel: neu ? "Fahrzeug aufnehmen" : `${f.bezeichnung} bearbeiten`, inhalt: `
Über das Kennzeichen findet die Telemetrie das Fahrzeug wieder — es muss genau dem im Spiel entsprechen.
${d.ausstattung.map((a) => ` `).join("")}
`, bestaetigenText: neu ? "Aufnehmen" : "Speichern", bestaetigt: async (el, zu) => { const gewaehlt = Array.from(el.querySelectorAll(".fz-teil-knopf.gewaehlt")) .map((k) => k.dataset.teil); const weitere = el.querySelector("[name=eigene]").value .split(",").map((t) => t.trim()).filter(Boolean); try { await aufruf("fahrzeug", "speichern", { id: neu ? null : f.id, kennzeichen: el.querySelector("[name=kennzeichen]").value.trim(), bezeichnung: el.querySelector("[name=bezeichnung]").value.trim(), modell: el.querySelector("[name=modell]").value.trim(), art: el.querySelector("[name=art]").value, station: el.querySelector("[name=station]").value, ausstattung: gewaehlt.concat(weitere).join(", "), }); zu(); meldung(neu ? "Fahrzeug aufgenommen." : "Fahrzeug gespeichert.", "gut"); rendern(behaelter); } catch (fehler) { meldung(fehler.message, "fehler"); } }, nachOeffnen: (hg) => { hg.querySelectorAll("[data-teil]").forEach((el) => { el.addEventListener("click", () => el.classList.toggle("gewaehlt")); }); }, }); } function entfernenFenster(behaelter, f) { bestaetigen({ titel: `${f.bezeichnung} aus dem Fuhrpark nehmen`, gefahr: true, inhalt: `

Das Fahrzeug verschwindet aus dem Fuhrpark. Die Protokolleinträge dazu bleiben erhalten.

`, bestaetigenText: "Entfernen", bestaetigt: async (el, zu) => { const grund = el.querySelector("[name=grund]").value.trim(); if (!grund) return meldung("Bitte einen Grund angeben.", "fehler"); try { await aufruf("fahrzeug", "entfernen", { id: f.id, grund }); zu(); meldung("Fahrzeug entfernt.", "gut"); rendern(behaelter); } catch (fehler) { meldung(fehler.message, "fehler"); } }, }); } /* ---- Laden ---------------------------------------------------------------------- */ async function rendern(behaelter) { try { z.daten = await aufruf("fahrzeug", "uebersicht", { ordner: z.ordner, art: z.art }); uebersicht(behaelter); // Sprungziel aus einem Hinweis, z. B. „Tankstand gemeldet" const ziel = App.zustand.modulZiel; if (ziel && ziel.fahrzeug) { App.zustand.modulZiel = null; return fahrzeugFenster(behaelter, ziel.fahrzeug); } } catch (f) { behaelter.innerHTML = `

Fuhrpark

Konnte nicht geladen werden: ${sicher(f.message)}

`; } } App.registriereAnsicht("fahrzeug", { rendern, aktualisieren() { // Kein offenes Fenster überschreiben if (App.zustand.aktivesModul === "fahrzeug" && !document.querySelector(".fenster-hg")) { rendern(App.$("inhalt")); } }, }); })();