/* ===================================================================== aether-medical / Ansicht: Labor Zwei Blöcke, streng getrennt: das ERGEBNIS trägt das Labor ein, den BEFUND ein Mediziner. Dazwischen liegt die Bewertung — und die nimmt das System niemandem ab. Kein Wert wird markiert, verglichen oder als auffällig dargestellt. ===================================================================== */ "use strict"; (() => { const { sicher, zeit, minuten, aufruf, meldung, fenster, bestaetigen } = App; const z = { ordner: "offen", // offen | befund | meine | archiv art: "", suche: "", daten: null, offen: null, }; const statusArt = { offen: "warn", in_arbeit: "info", fertig: "gut", verworfen: "neutral", }; const statusName = { offen: "offen", in_arbeit: "in Arbeit", fertig: "Ergebnis liegt vor", verworfen: "verworfen", }; /* ---- Übersicht ---------------------------------------------------------- */ function uebersicht(behaelter) { const d = z.daten; behaelter.innerHTML = `

Labor

Das Labor speichert Ergebnisse. Ob ein Wert etwas bedeutet, entscheidet ein Mediziner — nicht das System.

${d.rechte.beauftragen ? `` : ""}
Offen
${d.zaehler.offen}
wartet auf das Labor
Davon dringend
${d.zaehler.dringend}
vorrangig bearbeiten
Ohne Bewertung
${d.zaehler.befund}
Ergebnis da, Befund fehlt
Eigene Aufträge
${d.zaehler.meine}
von dir gestellt
Aufträge ${d.liste.length} Einträge
${d.liste.length ? d.liste.map(zeile).join("") : `
Kein Auftrag gefunden.
`}
`; verdrahteUebersicht(behaelter); } function zeile(l) { return `
${l.dringend ? `` : ``} ${sicher(l.kennung)}
${sicher(l.patientName)} ${sicher(l.artName)}
${sicher(String(l.fragestellung || "").slice(0, 90))}
${l.dringend ? `dringend` : ""} ${l.hatErgebnis && !l.hatBefund ? `Befund fehlt` : ""} ${l.hatBefund ? `befundet` : ""} ${l.eigene ? `dein Auftrag` : ""} ${sicher(statusName[l.status] || l.status)} ${l.status === "offen" || l.status === "in_arbeit" ? "seit " + minuten(l.offenSeit) : zeit(l.auftrag_am)}
`; } function verdrahteUebersicht(behaelter) { behaelter.querySelectorAll("[data-reiter]").forEach((el) => { el.addEventListener("click", () => { z.ordner = el.dataset.reiter; rendern(behaelter); }); }); behaelter.querySelector("[data-art]").addEventListener("change", (e) => { z.art = e.target.value; rendern(behaelter); }); const suchfeld = behaelter.querySelector("[data-suche]"); let warten = null; suchfeld.addEventListener("input", () => { clearTimeout(warten); warten = setTimeout(() => { z.suche = suchfeld.value.trim(); rendern(behaelter); }, 280); }); behaelter.querySelectorAll("[data-oeffne]").forEach((el) => { el.addEventListener("click", () => oeffne(behaelter, +el.dataset.oeffne)); }); const neu = behaelter.querySelector("[data-neu]"); if (neu) neu.addEventListener("click", () => auftragFenster(behaelter)); } /* ---- Einzelansicht -------------------------------------------------------- */ function einzelAnsicht(behaelter, d) { const a = d.auftrag, s = d.stamm; const offen = a.status === "offen"; const inArbeit = a.status === "in_arbeit"; const verworfen = a.status === "verworfen"; behaelter.innerHTML = `

${sicher(a.kennung)} · ${sicher(a.artName)}

${sicher(a.patientName)} · geb. ${sicher(a.geburt)} ${a.dringend ? " · dringend" : ""}

${s.hinweis ? `
⚠
Warnhinweis — ${sicher(s.hinweis)}
` : ""}
Status${sicher(statusName[a.status] || a.status)}
Beauftragt${zeit(a.auftragAm)}
Von${sicher(a.auftragVon)}
${a.bearbeitetVon ? `
Im Labor${sicher(a.bearbeitetVon)}
Angenommen${zeit(a.bearbeitetAm)}
` : ""}
Blutgruppe (Stammdaten) ${sicher(s.blutgruppe || "nicht bestimmt")}
${offen && d.rechte.bearbeiten ? `` : ""} ${(offen || inArbeit) && d.rechte.bearbeiten ? `` : ""}
${sicher(a.fragestellung || "—")}
Ergebnis — gemessene Werte ${d.rechte.bearbeiten && !verworfen ? `` : ""}
${a.ergebnis ? sicher(a.ergebnis).replace(/\n/g, "
") : "Das Labor hat noch nichts eingetragen."}
Reine Messwerte. Das System vergleicht sie mit nichts und markiert nichts als auffällig.
Befund — ärztliche Bewertung ${d.rechte.befunden && a.ergebnis && !verworfen ? `` : ""}
${a.befund ? sicher(a.befund).replace(/\n/g, "
") : a.ergebnis ? "Das Ergebnis ist noch nicht bewertet." : "Erst wenn ein Ergebnis vorliegt, lässt sich befunden."}
${a.befundVon ? `Bewertet von ${sicher(a.befundVon)} am ${zeit(a.befundAm)}.` : "Die Bewertung stammt immer von einem Mediziner."}
${a.ergebnis && !verworfen && d.rechte.stammdaten ? `
Blutgruppe in die Stammdaten übernehmen

Falls in diesem Auftrag eine Blutgruppe bestimmt wurde: sie wandert nicht von selbst in die Patientenakte. Du trägst sie ausdrücklich ein und stehst dafür gerade.

` : ""}
Frühere Aufträge dieses Patienten zum Vergleich — nicht verrechnet
${d.frueher.length ? d.frueher.map((f) => `
${sicher(f.kennung)}
${sicher(f.art)}
${zeit(f.auftrag_am)}
${sicher(statusName[f.status] || f.status)}
`).join("") : `
Keine früheren Aufträge.
`}
`; verdrahteEinzel(behaelter, d); } function verdrahteEinzel(behaelter, d) { const a = d.auftrag; 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 }); }); behaelter.querySelectorAll("[data-frueher]").forEach((el) => { el.addEventListener("click", () => oeffne(behaelter, +el.dataset.frueher)); }); const annehmen = behaelter.querySelector("[data-annehmen]"); if (annehmen) annehmen.addEventListener("click", async () => { try { await aufruf("labor", "annehmen", { id: a.id }); meldung("Auftrag in Arbeit genommen.", "gut"); oeffne(behaelter, a.id); } catch (f) { meldung(f.message, "fehler"); } }); const ergebnis = behaelter.querySelector("[data-ergebnis]"); if (ergebnis) ergebnis.addEventListener("click", () => ergebnisFenster(behaelter, d)); const befund = behaelter.querySelector("[data-befund]"); if (befund) befund.addEventListener("click", () => befundFenster(behaelter, d)); const verwerfen = behaelter.querySelector("[data-verwerfen]"); if (verwerfen) verwerfen.addEventListener("click", () => { bestaetigen({ titel: "Probe verwerfen", gefahr: true, inhalt: `

${sicher(a.kennung)} wird als verworfen abgelegt. Der Auftraggeber wird informiert; ein neuer Auftrag muss von Hand gestellt werden.

`, bestaetigenText: "Verwerfen", 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("labor", "verwerfen", { id: a.id, grund }); zu(); meldung("Auftrag verworfen.", "gut"); oeffne(behaelter, a.id); } catch (f) { meldung(f.message, "fehler"); } }, }); }); const blutgruppe = behaelter.querySelector("[data-blutgruppe]"); if (blutgruppe) blutgruppe.addEventListener("click", () => blutgruppeFenster(behaelter, d)); } /* ---- Ergebnis und Befund --------------------------------------------------- */ function ergebnisFenster(behaelter, d) { const a = d.auftrag; fenster({ titel: "Ergebnis eintragen · " + a.kennung, inhalt: `

${sicher(a.patientName)} · ${sicher(a.artName)}
Fragestellung: ${sicher(a.fragestellung || "—")}

Nur Messwerte, keine Bewertung. Die Einordnung nimmt anschließend ein Mediziner im Befund vor.
${d.vorlage && !a.ergebnis ? `` : ""}`, knoepfe: [ { text: "Abbrechen", art: "leise", klick: (_, zu) => zu() }, { text: "Ergebnis speichern", klick: async (el, zu) => { try { await aufruf("labor", "ergebnis", { id: a.id, ergebnis: el.querySelector("[name=ergebnis]").value.trim(), }); zu(); meldung("Ergebnis gespeichert. Der Auftraggeber wurde informiert.", "gut"); oeffne(behaelter, a.id); } catch (f) { meldung(f.message, "fehler"); } } }, ], nachOeffnen: (hg) => { const vorlage = hg.querySelector("[data-vorlage]"); if (vorlage) vorlage.addEventListener("click", () => { const feld = hg.querySelector("[name=ergebnis]"); feld.value = d.vorlage; feld.focus(); }); }, }); } function befundFenster(behaelter, d) { const a = d.auftrag; bestaetigen({ titel: "Befund eintragen · " + a.kennung, inhalt: `
${sicher(a.ergebnis).replace(/\n/g, "
")}
Der Befund erscheint in der Patientenakte und im Behandlungsbogen. Er trägt deinen Namen.
`, bestaetigenText: "Befund speichern", bestaetigt: async (el, zu) => { try { await aufruf("labor", "befund", { id: a.id, befund: el.querySelector("[name=befund]").value.trim(), }); zu(); meldung("Befund gespeichert.", "gut"); oeffne(behaelter, a.id); } catch (f) { meldung(f.message, "fehler"); } }, }); } /* ---- Blutgruppe übernehmen -------------------------------------------------- */ function blutgruppeFenster(behaelter, d) { const a = d.auftrag; bestaetigen({ titel: "Blutgruppe in die Stammdaten übernehmen", inhalt: `
${sicher(a.ergebnis).replace(/\n/g, "
")}
Das System liest die Blutgruppe nicht aus dem Ergebnistext aus. Du wählst sie, und damit steht dein Name darunter.
${d.stamm.blutgruppe ? `
⚠
In den Stammdaten steht bereits ${sicher(d.stamm.blutgruppe)}. Ein Überschreiben wird protokolliert.
` : ""}`, bestaetigenText: "Übernehmen", bestaetigt: async (el, zu) => { const gewaehlt = el.querySelector("[name=blutgruppe]").value; if (!gewaehlt) return meldung("Bitte eine Blutgruppe wählen.", "fehler"); try { const antwort = await aufruf("labor", "blutgruppeUebernehmen", { id: a.id, blutgruppe: gewaehlt, }); zu(); meldung("Blutgruppe " + antwort.blutgruppe + " eingetragen.", "gut"); oeffne(behaelter, a.id); } catch (f) { meldung(f.message, "fehler"); } }, }); } /* ---- Auftrag stellen --------------------------------------------------------- */ function auftragFenster(behaelter) { const d = z.daten; let gewaehlt = null; bestaetigen({ titel: "Laborauftrag stellen", inhalt: `
Mindestens zwei Zeichen eingeben.
Je genauer die Frage, desto brauchbarer das Ergebnis. Das Labor misst — bewerten musst du selbst.
Dringende Aufträge stehen im Labor oben und erzeugen einen Hinweis mit hoher Priorität. Bearbeitet werden sie trotzdem von einem Menschen.
`, bestaetigenText: "Auftrag stellen", bestaetigt: async (el, zu) => { if (!gewaehlt) return meldung("Bitte zuerst einen Patienten wählen.", "fehler"); try { const antwort = await aufruf("labor", "beauftragen", { patient: gewaehlt.id, art: el.querySelector("[name=art]").value, fragestellung: el.querySelector("[name=fragestellung]").value.trim(), dringend: el.querySelector("[name=dringend]").checked, }); zu(); meldung("Auftrag " + antwort.kennung + " gestellt.", "gut"); z.ordner = "meine"; rendern(behaelter); } catch (f) { meldung(f.message, "fehler"); } }, nachOeffnen: (hg) => { const suchfeld = hg.querySelector("[name=suche]"); const liste = hg.querySelector("[data-treffer]"); const formular = hg.querySelector("[data-formular]"); let warten = null; suchfeld.addEventListener("input", () => { clearTimeout(warten); warten = setTimeout(async () => { const begriff = suchfeld.value.trim(); if (begriff.length < 2) { liste.innerHTML = `
Mindestens zwei Zeichen eingeben.
`; return; } try { const antwort = await aufruf("labor", "patientSuche", { begriff }); const treffer = antwort.treffer || []; liste.innerHTML = treffer.length ? treffer.map((t) => `
${sicher(t.firstname)} ${sicher(t.lastname)}
geb. ${sicher(t.dob)} ${t.blutgruppe ? " · " + sicher(t.blutgruppe) : " · Blutgruppe nicht bestimmt"}
${t.hinweis ? `⚠` : ""}
`).join("") : `
Keine Person gefunden.
`; liste.querySelectorAll("[data-person]").forEach((el) => { el.addEventListener("click", () => { gewaehlt = treffer.find((t) => t.id === +el.dataset.person); liste.querySelectorAll("[data-person]") .forEach((zeile) => zeile.classList.remove("gewaehlt")); el.classList.add("gewaehlt"); formular.style.display = ""; }); }); } catch (f) { meldung(f.message, "fehler"); } }, 260); }); }, }); } /* ---- Laden -------------------------------------------------------------------- */ async function oeffne(behaelter, laborId) { try { const d = await aufruf("labor", "oeffnen", { id: laborId }); z.offen = laborId; einzelAnsicht(behaelter, d); } catch (f) { meldung(f.message, "fehler"); } } async function rendern(behaelter) { try { z.daten = await aufruf("labor", "uebersicht", { ordner: z.ordner, art: z.art, begriff: z.suche, }); // Sprungziel aus einem Hinweis, z. B. „Laborergebnis verfügbar" const ziel = App.zustand.modulZiel; if (ziel && ziel.labor) { App.zustand.modulZiel = null; return oeffne(behaelter, ziel.labor); } if (z.offen) await oeffne(behaelter, z.offen); else uebersicht(behaelter); } catch (f) { behaelter.innerHTML = `

Labor

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

`; } } App.registriereAnsicht("labor", { rendern, aktualisieren() { if (!z.offen && App.zustand.aktivesModul === "labor") rendern(App.$("inhalt")); }, }); App.registriereSuche(async (begriff) => { try { const d = await aufruf("labor", "uebersicht", { ordner: "archiv", begriff }); return (d.liste || []).slice(0, 5).map((l) => ({ bereich: "Labor", titel: l.kennung + " · " + l.patientName, unter: l.artName + " · " + (statusName[l.status] || l.status), })); } catch (e) { return []; } }); })();