/* ===================================================================== aether-medical / Ansicht: Intensivstation Diese Ansicht ist ein Monitor für Dokumentation, nicht für Patienten. Kein Wert hier wird gemessen: der Zustand steht da, weil ein Arzt ihn eingetragen hat, und die Geräteliste ist eine Liste von Namen. Ein Aufenthalt endet erst, wenn jemand ihn beendet. ===================================================================== */ "use strict"; (() => { const { sicher, zeit, minuten, aufruf, meldung, fenster, bestaetigen } = App; const z = { ordner: "laufend", // laufend | beendet offen: null, // geöffneter Aufenthalt daten: null, }; // Marker-Art je Zustand — nur Farbe, keine Wertung const zustandArt = { kritisch: "kritisch", stabil: "info", besserung: "gut" }; /* ---- Kleine Helfer ---------------------------------------------------- */ /** Farbe eines Zustands aus der Konfiguration */ function zustandFarbe(kennung) { const liste = (z.daten && z.daten.zustaende) || []; const treffer = liste.find((s) => s.id === kennung); return treffer ? treffer.farbe : "#8697a4"; } /** Zerlegt die Geräteliste in einzelne Namen */ function geraeteTeile(text) { return String(text || "").split(",").map((t) => t.trim()).filter(Boolean); } /* ---- Gerüst ------------------------------------------------------------ */ function reiterleiste(d) { const eintraege = [ { id: "laufend", text: "In Betreuung", zahl: d.zaehler.laufend }, { id: "beendet", text: "Beendet", zahl: d.zaehler.beendetHeute }, ]; return `
${eintraege.map((e) => ` `).join("")}
`; } function kennzahlen(d) { const zk = d.zaehler; return `
In Betreuung
${zk.laufend}
laufende Aufenthalte
Als kritisch eingetragen
${zk.kritisch}
von Hand eingestuft
Ohne zuständigen Arzt
${zk.ohneArzt}
niemand eingetragen
Ohne frischen Eintrag
${zk.langeStill}
seit über ${d.stilleNach} Minuten
`; } /* ---- Übersicht ---------------------------------------------------------- */ function uebersicht(behaelter) { const d = z.daten; behaelter.innerHTML = `

Intensivstation

Das System misst nichts und schlägt keinen Alarm. Was hier steht, hat jemand eingetragen — der Zustand ändert sich nie von selbst.

${d.rechte.betreuen ? `` : ""}
${kennzahlen(d)} ${reiterleiste(d)}
${z.ordner === "laufend" ? "Patienten in Intensivbetreuung" : "Beendete Aufenthalte"} ${z.ordner === "laufend" ? "Oben steht, was als am schwersten eingetragen wurde" : d.liste.length + " Einträge"}
${d.liste.length ? d.liste.map(zeile).join("") : `
${z.ordner === "laufend" ? "Zurzeit wird niemand intensiv betreut." : "Noch keine beendeten Aufenthalte."}
`}
`; verdrahteUebersicht(behaelter); } function zeile(a) { const laufend = !a.beendet_am; return `
${sicher(a.name)} geb. ${sicher(a.geburt)}
${a.zimmerKennung ? "Zimmer " + sicher(a.zimmerKennung) : "ohne festen Platz"} ${a.geraete ? " · " + sicher(String(a.geraete).slice(0, 60)) : ""} ${laufend ? " · zuletzt dokumentiert vor " + sicher(minuten(a.stillSeit)) : ""}
${a.warnhinweis ? `⚠` : ""} ${a.allergien ? `A` : ""} ${a.blutgruppe ? `${sicher(a.blutgruppe)}` : ""} ${a.langeStill ? `Verlauf offen` : ""} ${laufend && !a.verantwortlichName ? `kein Arzt` : a.verantwortlichName ? `${sicher(a.verantwortlichName)}` : ""} ${sicher(a.zustandName)} ${laufend ? "seit " + sicher(minuten(a.liegtSeit)) : zeit(a.beendet_am)}
`; } function verdrahteUebersicht(behaelter) { behaelter.querySelectorAll("[data-reiter]").forEach((el) => { el.addEventListener("click", () => { z.ordner = el.dataset.reiter; rendern(behaelter); }); }); behaelter.querySelectorAll("[data-oeffne]").forEach((el) => { el.addEventListener("click", () => oeffne(behaelter, +el.dataset.oeffne)); }); const aufnehmen = behaelter.querySelector("[data-aufnehmen]"); if (aufnehmen) aufnehmen.addEventListener("click", () => aufnahmeFenster(behaelter)); } /* ---- Einzelansicht -------------------------------------------------------- */ function einzelAnsicht(behaelter, d) { const a = d.aufenthalt, s = d.stamm; const geraete = geraeteTeile(a.geraete); behaelter.innerHTML = `

${sicher(a.name)}

geb. ${sicher(a.geburt)} · ${sicher(a.zustandName)} ${a.zimmerKennung ? " · Zimmer " + sicher(a.zimmerKennung) : ""} ${a.stationName ? " · " + sicher(a.stationName) : ""}

${a.laufend ? "" : `
✔
Intensivbetreuung beendet — ${zeit(a.beendetAm)} von ${sicher(a.beendetVon || "unbekannt")}. Der Aufenthalt ist nur noch zum Nachlesen da.
`} ${s.hinweis ? `
⚠
Warnhinweis — ${sicher(s.hinweis)}
` : ""} ${s.allergien ? `
💊
Allergien — ${sicher(s.allergien)}
` : ""} ${a.laufend && !a.verantwortlichName ? `
🧑‍⚕️
Kein zuständiger Arzt eingetragen. Das System wählt keinen aus — jemand muss die Verantwortung übernehmen.
` : ""}
${s.lichtbild ? `Lichtbild` : `Kein Lichtbild`}
Zustand ${sicher(a.zustandName)}
In Betreuung seit ${sicher(minuten(a.liegtSeit))}
Zuständig ${sicher(a.verantwortlichName || "niemand eingetragen")}
Platz ${sicher(a.zimmerKennung || "kein fester Platz")}
Blutgruppe ${sicher(s.blutgruppe || "nicht bestimmt")}
Dauermedikation ${sicher(s.dauermedikation || "keine erfasst")}
${a.aufnahme ? `` : ""} ${a.laufend && d.rechte.betreuen ? ` ` : ""}
Aufenthalt
Aufgenommen${zeit(a.aufgenommenAm)}
Aufgenommen von${sicher(a.aufgenommenVon)}
${a.aufnahmeGrund ? `
Grund der Aufnahme${sicher(a.aufnahmeGrund)}
` : ""} ${a.beendetAm ? `
Beendet${zeit(a.beendetAm)}
Beendet von${sicher(a.beendetVon)}
` : ""}
Angeschlossene Geräte nur notiert, nicht gesteuert
${geraete.length ? `
${geraete.map((g) => `${sicher(g)}`).join("")}
` : `
Nichts eingetragen.
`}
Grund der Intensivbetreuung
${sicher(a.notiz || "Nichts eingetragen.")}
Verlauf ${d.verlauf.length} Einträge
${a.laufend && d.rechte.betreuen ? `
Der Wortlaut bleibt genau so stehen.
` : ""} ${d.verlauf.length ? `
${d.verlauf.map((v) => `
✎
${sicher(v.autor)} ${zeit(v.am)}
${sicher(v.text)}
`).join("")}
` : `
Noch nichts dokumentiert.
`}
`; verdrahteEinzel(behaelter, d); } function verdrahteEinzel(behaelter, d) { const a = d.aufenthalt; behaelter.querySelector("[data-zurueck]").addEventListener("click", () => { z.offen = null; rendern(behaelter); }); behaelter.querySelector("[data-akte]").addEventListener("click", () => { if (!App.zustand.module.some((m) => m.id === "mdt")) { return meldung("Das MDT steht dir nicht zur Verfügung.", "fehler"); } App.oeffneModul("mdt", { patient: a.patient }); }); const vorgang = behaelter.querySelector("[data-vorgang]"); if (vorgang) { vorgang.addEventListener("click", () => { if (!App.zustand.module.some((m) => m.id === "patienten")) { return meldung("Die Patientenverwaltung steht dir nicht zur Verfügung.", "fehler"); } App.oeffneModul("patienten", { aufnahme: a.aufnahme }); }); } const zustand = behaelter.querySelector("[data-zustand]"); if (zustand) zustand.addEventListener("click", () => zustandFenster(behaelter, d)); const geraete = behaelter.querySelector("[data-geraete]"); if (geraete) geraete.addEventListener("click", () => geraeteFenster(behaelter, d)); const zustaendig = behaelter.querySelector("[data-zustaendig]"); if (zustaendig) zustaendig.addEventListener("click", () => zustaendigFenster(behaelter, d)); const beenden = behaelter.querySelector("[data-beenden]"); if (beenden) beenden.addEventListener("click", () => beendenFenster(behaelter, d)); const speichern = behaelter.querySelector("[data-verlaufspeichern]"); if (speichern) { speichern.addEventListener("click", async () => { const feld = behaelter.querySelector("[data-neuerverlauf]"); const text = feld.value.trim(); if (text.length < 3) return meldung("Bitte einen Text eingeben.", "fehler"); try { await aufruf("intensiv", "verlauf", { id: a.id, text }); meldung("Eintrag geschrieben.", "gut"); oeffne(behaelter, a.id); } catch (f) { meldung(f.message, "fehler"); } }); } } /* ---- Intensivaufnahme ------------------------------------------------------ */ async function aufnahmeFenster(behaelter) { let k; try { k = await aufruf("intensiv", "kandidaten", {}); } catch (f) { return meldung(f.message, "fehler"); } let gewaehlt = null; // Patient/Aufnahme let gewaehltesZimmer = null; // Zimmer der Betreuung bestaetigen({ titel: "Patient auf die Intensivstation aufnehmen", inhalt: `
${k.patienten.length ? k.patienten.map((p) => `
${sicher(p.name)} geb. ${sicher(p.geburt)}
${sicher(String(p.grund || "").slice(0, 70))}
${p.warnhinweis ? `⚠` : ""} ${p.allergien ? `A` : ""} ${p.zimmerKennung ? `${sicher(p.zimmerKennung)}` : ""}
`).join("") : `
Kein aufgenommener Patient verfügbar.
`}
Auf die Intensivstation kommt nur, wer bereits aufgenommen ist. Die Reihenfolge ist die eingetragene Dringlichkeit.
Deine Einschätzung. Das System leitet sie aus nichts ab.
${k.zimmer.length ? k.zimmer.map((zi) => ` `).join("") : `
Kein Intensivplatz angelegt.
`}
Hier wird nur festgehalten, wo betreut wird. Das Bett selbst belegt die Stationsverwaltung.
Ohne Häkchen bleibt der Aufenthalt ohne zuständigen Arzt — das wird allen im Dienst gemeldet.
`, bestaetigenText: "Aufnehmen", bestaetigt: async (el, zu) => { if (!gewaehlt) return meldung("Bitte zuerst einen Patienten wählen.", "fehler"); const notiz = el.querySelector("[name=notiz]").value.trim(); if (notiz.length < 5) return meldung("Bitte den Grund angeben.", "fehler"); try { const antwort = await aufruf("intensiv", "aufnehmen", { aufnahme: gewaehlt, zimmer: gewaehltesZimmer, zustand: el.querySelector("[name=zustand]").value, geraete: el.querySelector("[name=geraete]").value.trim(), notiz, selbst: el.querySelector("[name=selbst]").checked, }); zu(); meldung("Intensivaufenthalt eröffnet.", "gut"); z.ordner = "laufend"; oeffne(behaelter, antwort.id); } catch (f) { meldung(f.message, "fehler"); } }, nachOeffnen: (hg) => { hg.querySelectorAll("[data-patient]").forEach((el) => { el.addEventListener("click", () => { gewaehlt = +el.dataset.patient; hg.querySelectorAll("[data-patient]") .forEach((zeile) => zeile.classList.remove("gewaehlt")); el.classList.add("gewaehlt"); }); }); hg.querySelectorAll("[data-zimmer]").forEach((el) => { el.addEventListener("click", () => { // Ein zweiter Klick nimmt die Wahl wieder zurück const schonGewaehlt = gewaehltesZimmer === +el.dataset.zimmer; hg.querySelectorAll("[data-zimmer]").forEach((k) => k.classList.remove("gewaehlt")); gewaehltesZimmer = schonGewaehlt ? null : +el.dataset.zimmer; if (!schonGewaehlt) el.classList.add("gewaehlt"); }); }); }, }); } /* ---- Zustand eintragen ------------------------------------------------------- */ function zustandFenster(behaelter, d) { const a = d.aufenthalt; bestaetigen({ titel: "Zustand eintragen", inhalt: `

Aktuell eingetragen: ${sicher(a.zustandName)} — von ${sicher(a.verantwortlichName || "niemandem")} verantwortet.

Dieser Text wandert unverändert in den Verlauf.
`, bestaetigenText: "Eintragen", bestaetigt: async (el, zu) => { const grund = el.querySelector("[name=grund]").value.trim(); if (grund.length < 3) return meldung("Bitte eine Begründung angeben.", "fehler"); try { await aufruf("intensiv", "zustand", { id: a.id, zustand: el.querySelector("[name=zustand]").value, grund, }); zu(); meldung("Zustand eingetragen.", "gut"); oeffne(behaelter, a.id); } catch (f) { meldung(f.message, "fehler"); } }, }); } /* ---- Geräte ------------------------------------------------------------------- */ function geraeteFenster(behaelter, d) { const a = d.aufenthalt; const vorschlaege = d.geraeteliste || []; const vorhanden = geraeteTeile(a.geraete); // Alles, was nicht in der Vorschlagsliste steht, bleibt als Freitext erhalten const eigene = vorhanden.filter((g) => !vorschlaege.includes(g)); bestaetigen({ titel: "Angeschlossene Geräte", inhalt: `
ℹ
Das System steuert kein Gerät, liest keinen Wert aus und schlägt keinen Alarm. Es hält fest, was jemand angeschlossen hat.
${vorschlaege.map((g) => ` `).join("")}
`, bestaetigenText: "Speichern", bestaetigt: async (el, zu) => { const gewaehlt = Array.from(el.querySelectorAll(".its-geraet-knopf.gewaehlt")) .map((k) => k.dataset.geraet); const eigeneTexte = geraeteTeile(el.querySelector("[name=eigene]").value); try { await aufruf("intensiv", "geraete", { id: a.id, geraete: gewaehlt.concat(eigeneTexte).join(", "), }); zu(); meldung("Geräte eingetragen.", "gut"); oeffne(behaelter, a.id); } catch (f) { meldung(f.message, "fehler"); } }, nachOeffnen: (hg) => { hg.querySelectorAll("[data-geraet]").forEach((el) => { el.addEventListener("click", () => el.classList.toggle("gewaehlt")); }); }, }); } /* ---- Zuständigkeit -------------------------------------------------------------- */ async function zustaendigFenster(behaelter, d) { const a = d.aufenthalt; let b; try { b = await aufruf("intensiv", "betreuer", {}); } catch (f) { return meldung(f.message, "fehler"); } let gewaehlt = a.verantwortlich || null; let niederlegen = false; bestaetigen({ titel: "Zuständigkeit", inhalt: `

Zuständig ist zurzeit: ${sicher(a.verantwortlichName || "niemand")}

${b.liste.length ? b.liste.map((p) => `
${sicher(p.name)} ${p.selbst ? `du` : ""}
${sicher(p.rolleName)} · ${sicher(p.personalnummer || "")}
${sicher(p.funktion || "")}
`).join("") : `
Niemand mit diesem Recht ist im Dienst.
`}
Das System verteilt keine Zuständigkeit — sie wird übernommen oder übertragen.
`, bestaetigenText: "Übernehmen", bestaetigt: async (el, zu) => { const grund = el.querySelector("[name=grund]").value.trim(); if (niederlegen && !grund) { return meldung("Bitte angeben, warum niemand mehr zuständig ist.", "fehler"); } if (!niederlegen && !gewaehlt) { return meldung("Bitte eine Person wählen.", "fehler"); } try { await aufruf("intensiv", "verantwortlich", { id: a.id, charakter: niederlegen ? null : gewaehlt, grund, }); zu(); meldung(niederlegen ? "Zuständigkeit niedergelegt." : "Zuständigkeit eingetragen.", "gut"); oeffne(behaelter, a.id); } catch (f) { meldung(f.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=niederlegen]"); haken.addEventListener("change", () => { niederlegen = haken.checked; // Die Personenliste wird unbrauchbar, sobald niedergelegt wird hg.querySelector("[data-betreuer]").style.opacity = niederlegen ? ".45" : ""; }); }, }); } /* ---- Betreuung beenden ------------------------------------------------------------ */ function beendenFenster(behaelter, d) { const a = d.aufenthalt; bestaetigen({ titel: "Intensivbetreuung beenden", gefahr: true, inhalt: `

${sicher(a.name)} wird ab sofort nicht mehr intensiv betreut.

ℹ
Das ist keine Entlassung. Der Patient bleibt aufgenommen, sein Bett bleibt belegt und keine Behandlung wird dadurch abgeschlossen.
${a.zustand === "kritisch" ? `
⚠
Der Zustand steht weiterhin auf kritisch. Das Beenden ist trotzdem möglich — es wird so festgehalten.
` : ""}
Dieser Text schließt den Verlauf ab.
`, bestaetigenText: "Betreuung beenden", bestaetigt: async (el, zu) => { const grund = el.querySelector("[name=grund]").value.trim(); if (grund.length < 5) return meldung("Bitte eine Begründung angeben.", "fehler"); try { await aufruf("intensiv", "beenden", { id: a.id, grund }); zu(); meldung("Intensivbetreuung beendet.", "gut"); z.offen = null; z.ordner = "beendet"; rendern(behaelter); } catch (f) { meldung(f.message, "fehler"); } }, }); } /* ---- Laden ----------------------------------------------------------------------- */ async function oeffne(behaelter, intensivId) { try { const d = await aufruf("intensiv", "oeffnen", { id: intensivId }); z.offen = intensivId; einzelAnsicht(behaelter, d); } catch (f) { meldung(f.message, "fehler"); } } async function rendern(behaelter) { try { z.daten = await aufruf("intensiv", "uebersicht", { ordner: z.ordner }); // Sprungziel aus einem Hinweis, z. B. „als kritisch eingetragen" const ziel = App.zustand.modulZiel; if (ziel && ziel.intensiv) { App.zustand.modulZiel = null; return oeffne(behaelter, ziel.intensiv); } if (z.offen) await oeffne(behaelter, z.offen); else uebersicht(behaelter); } catch (f) { behaelter.innerHTML = `

Intensivstation

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

`; } } App.registriereAnsicht("intensiv", { rendern, aktualisieren() { // Eine offene Einzelansicht oder ein offenes Fenster nicht stören if (App.zustand.aktivesModul === "intensiv" && !z.offen && !document.querySelector(".fenster-hg")) { rendern(App.$("inhalt")); } }, }); })();