Rezept hinzugefügt auswahl der MEdikamente
This commit is contained in:
parent
798ba92b8a
commit
d41b0d22d1
@ -1,13 +1,23 @@
|
||||
const db = require("../db");
|
||||
const { createUser, getAllUsers} = require("../services/admin.service");
|
||||
const { createUser, getAllUsers } = require("../services/admin.service");
|
||||
const bcrypt = require("bcrypt");
|
||||
|
||||
async function listUsers(req, res) {
|
||||
const { q } = req.query;
|
||||
|
||||
try {
|
||||
const users = await getAllUsers(db);
|
||||
let users;
|
||||
|
||||
if (q) {
|
||||
users = await getAllUsers(db, q);
|
||||
} else {
|
||||
users = await getAllUsers(db);
|
||||
}
|
||||
|
||||
res.render("admin_users", {
|
||||
users,
|
||||
currentUser: req.session.user
|
||||
currentUser: req.session.user,
|
||||
query: { q },
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
@ -18,7 +28,7 @@ async function listUsers(req, res) {
|
||||
function showCreateUser(req, res) {
|
||||
res.render("admin_create_user", {
|
||||
error: null,
|
||||
user: req.session.user
|
||||
user: req.session.user,
|
||||
});
|
||||
}
|
||||
|
||||
@ -30,20 +40,20 @@ async function postCreateUser(req, res) {
|
||||
password,
|
||||
role,
|
||||
fachrichtung,
|
||||
arztnummer
|
||||
arztnummer,
|
||||
} = req.body;
|
||||
|
||||
first_name = first_name?.trim();
|
||||
last_name = last_name?.trim();
|
||||
username = username?.trim();
|
||||
first_name = first_name?.trim();
|
||||
last_name = last_name?.trim();
|
||||
username = username?.trim();
|
||||
fachrichtung = fachrichtung?.trim();
|
||||
arztnummer = arztnummer?.trim();
|
||||
arztnummer = arztnummer?.trim();
|
||||
|
||||
// 🔴 Grundvalidierung
|
||||
if (!first_name || !last_name || !username || !password || !role) {
|
||||
return res.render("admin_create_user", {
|
||||
error: "Alle Pflichtfelder müssen ausgefüllt sein",
|
||||
user: req.session.user
|
||||
user: req.session.user,
|
||||
});
|
||||
}
|
||||
|
||||
@ -52,7 +62,7 @@ async function postCreateUser(req, res) {
|
||||
if (!fachrichtung || !arztnummer) {
|
||||
return res.render("admin_create_user", {
|
||||
error: "Für Ärzte sind Fachrichtung und Arztnummer Pflicht",
|
||||
user: req.session.user
|
||||
user: req.session.user,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@ -75,20 +85,18 @@ async function postCreateUser(req, res) {
|
||||
|
||||
req.session.flash = {
|
||||
type: "success",
|
||||
message: "Benutzer erfolgreich angelegt"
|
||||
message: "Benutzer erfolgreich angelegt",
|
||||
};
|
||||
|
||||
res.redirect("/admin/users");
|
||||
|
||||
} catch (error) {
|
||||
res.render("admin_create_user", {
|
||||
error,
|
||||
user: req.session.user
|
||||
user: req.session.user,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function changeUserRole(req, res) {
|
||||
const userId = req.params.id;
|
||||
const { role } = req.body;
|
||||
@ -98,19 +106,21 @@ async function changeUserRole(req, res) {
|
||||
return res.redirect("/admin/users");
|
||||
}
|
||||
|
||||
db.query(
|
||||
"UPDATE users SET role = ? WHERE id = ?",
|
||||
[role, userId],
|
||||
err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
req.session.flash = { type: "danger", message: "Fehler beim Ändern der Rolle" };
|
||||
} else {
|
||||
req.session.flash = { type: "success", message: "Rolle erfolgreich geändert" };
|
||||
}
|
||||
res.redirect("/admin/users");
|
||||
db.query("UPDATE users SET role = ? WHERE id = ?", [role, userId], (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
req.session.flash = {
|
||||
type: "danger",
|
||||
message: "Fehler beim Ändern der Rolle",
|
||||
};
|
||||
} else {
|
||||
req.session.flash = {
|
||||
type: "success",
|
||||
message: "Rolle erfolgreich geändert",
|
||||
};
|
||||
}
|
||||
);
|
||||
res.redirect("/admin/users");
|
||||
});
|
||||
}
|
||||
|
||||
async function resetUserPassword(req, res) {
|
||||
@ -127,23 +137,70 @@ async function resetUserPassword(req, res) {
|
||||
db.query(
|
||||
"UPDATE users SET password = ? WHERE id = ?",
|
||||
[hash, userId],
|
||||
err => {
|
||||
(err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
req.session.flash = { type: "danger", message: "Fehler beim Zurücksetzen" };
|
||||
req.session.flash = {
|
||||
type: "danger",
|
||||
message: "Fehler beim Zurücksetzen",
|
||||
};
|
||||
} else {
|
||||
req.session.flash = { type: "success", message: "Passwort zurückgesetzt" };
|
||||
req.session.flash = {
|
||||
type: "success",
|
||||
message: "Passwort zurückgesetzt",
|
||||
};
|
||||
}
|
||||
res.redirect("/admin/users");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function activateUser(req, res) {
|
||||
const userId = req.params.id;
|
||||
|
||||
db.query("UPDATE users SET active = 1 WHERE id = ?", [userId], (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
req.session.flash = {
|
||||
type: "danger",
|
||||
message: "Benutzer konnte nicht aktiviert werden",
|
||||
};
|
||||
} else {
|
||||
req.session.flash = {
|
||||
type: "success",
|
||||
message: "Benutzer wurde aktiviert",
|
||||
};
|
||||
}
|
||||
res.redirect("/admin/users");
|
||||
});
|
||||
}
|
||||
|
||||
function deactivateUser(req, res) {
|
||||
const userId = req.params.id;
|
||||
|
||||
db.query("UPDATE users SET active = 0 WHERE id = ?", [userId], (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
req.session.flash = {
|
||||
type: "danger",
|
||||
message: "Benutzer konnte nicht deaktiviert werden",
|
||||
};
|
||||
} else {
|
||||
req.session.flash = {
|
||||
type: "success",
|
||||
message: "Benutzer wurde deaktiviert",
|
||||
};
|
||||
}
|
||||
res.redirect("/admin/users");
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
listUsers,
|
||||
showCreateUser,
|
||||
postCreateUser,
|
||||
changeUserRole,
|
||||
resetUserPassword
|
||||
resetUserPassword,
|
||||
activateUser,
|
||||
deactivateUser,
|
||||
};
|
||||
|
||||
@ -10,7 +10,7 @@ function createPatient(req, res) {
|
||||
db.query(
|
||||
"INSERT INTO patients (firstname, lastname, birthdate, active) VALUES (?, ?, ?, 1)",
|
||||
[firstname, lastname, birthdate],
|
||||
err => {
|
||||
(err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return res.send("Datenbankfehler");
|
||||
@ -26,15 +26,28 @@ function listPatients(req, res) {
|
||||
let sql = "SELECT * FROM patients WHERE 1=1";
|
||||
const params = [];
|
||||
|
||||
if (firstname) { sql += " AND firstname LIKE ?"; params.push(`%${firstname}%`); }
|
||||
if (lastname) { sql += " AND lastname LIKE ?"; params.push(`%${lastname}%`); }
|
||||
if (birthdate) { sql += " AND birthdate = ?"; params.push(birthdate); }
|
||||
if (firstname) {
|
||||
sql += " AND firstname LIKE ?";
|
||||
params.push(`%${firstname}%`);
|
||||
}
|
||||
if (lastname) {
|
||||
sql += " AND lastname LIKE ?";
|
||||
params.push(`%${lastname}%`);
|
||||
}
|
||||
if (birthdate) {
|
||||
sql += " AND birthdate = ?";
|
||||
params.push(birthdate);
|
||||
}
|
||||
|
||||
sql += " ORDER BY lastname, firstname";
|
||||
|
||||
db.query(sql, params, (err, patients) => {
|
||||
if (err) return res.send("Datenbankfehler");
|
||||
res.render("patients", { patients, query: req.query, user: req.session.user});
|
||||
res.render("patients", {
|
||||
patients,
|
||||
query: req.query,
|
||||
user: req.session.user,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -43,12 +56,13 @@ function showEditPatient(req, res) {
|
||||
"SELECT * FROM patients WHERE id = ?",
|
||||
[req.params.id],
|
||||
(err, results) => {
|
||||
if (err || results.length === 0) return res.send("Patient nicht gefunden");
|
||||
if (err || results.length === 0)
|
||||
return res.send("Patient nicht gefunden");
|
||||
res.render("patient_edit", {
|
||||
patient: results[0],
|
||||
error: null,
|
||||
user: req.session.user,
|
||||
returnTo: req.query.returnTo || null
|
||||
returnTo: req.query.returnTo || null,
|
||||
});
|
||||
}
|
||||
);
|
||||
@ -71,13 +85,13 @@ function updatePatient(req, res) {
|
||||
postal_code,
|
||||
city,
|
||||
country,
|
||||
notes
|
||||
notes,
|
||||
} = req.body;
|
||||
|
||||
if (!firstname || !lastname || !birthdate) {
|
||||
req.session.flash = {
|
||||
type: "warning",
|
||||
message: "Vorname, Nachname und Geburtsdatum sind Pflichtfelder"
|
||||
message: "Vorname, Nachname und Geburtsdatum sind Pflichtfelder",
|
||||
};
|
||||
return res.redirect("back");
|
||||
}
|
||||
@ -112,9 +126,9 @@ function updatePatient(req, res) {
|
||||
city || null,
|
||||
country || null,
|
||||
notes || null,
|
||||
id
|
||||
id,
|
||||
],
|
||||
err => {
|
||||
(err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return res.send("Fehler beim Speichern");
|
||||
@ -174,14 +188,15 @@ function showPatientMedications(req, res) {
|
||||
if (err) return res.send("Medikamente konnten nicht geladen werden");
|
||||
|
||||
db.query(currentSql, [patientId], (err, currentMeds) => {
|
||||
if (err) return res.send("Aktuelle Medikation konnte nicht geladen werden");
|
||||
if (err)
|
||||
return res.send("Aktuelle Medikation konnte nicht geladen werden");
|
||||
|
||||
res.render("patient_medications", {
|
||||
patient: patients[0],
|
||||
meds,
|
||||
currentMeds,
|
||||
user: req.session.user,
|
||||
returnTo
|
||||
returnTo,
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -199,7 +214,7 @@ function moveToWaitingRoom(req, res) {
|
||||
WHERE id = ?
|
||||
`,
|
||||
[id],
|
||||
err => {
|
||||
(err) => {
|
||||
if (err) return res.send("Fehler beim Verschieben ins Wartezimmer");
|
||||
res.redirect("/patients");
|
||||
}
|
||||
@ -214,7 +229,7 @@ function showWaitingRoom(req, res) {
|
||||
|
||||
res.render("waiting_room", {
|
||||
patients,
|
||||
user: req.session.user
|
||||
user: req.session.user,
|
||||
});
|
||||
}
|
||||
);
|
||||
@ -236,15 +251,17 @@ function showPatientOverview(req, res) {
|
||||
ORDER BY created_at DESC
|
||||
`;
|
||||
|
||||
// 🔤 Services dynamisch nach Sprache laden
|
||||
const servicesSql = (nameField) => `
|
||||
const medicationVariantsSql = `
|
||||
SELECT
|
||||
id,
|
||||
${nameField} AS name,
|
||||
price
|
||||
FROM services
|
||||
WHERE active = 1
|
||||
ORDER BY ${nameField}
|
||||
mv.id AS variant_id,
|
||||
m.name AS medication_name,
|
||||
mf.name AS form_name,
|
||||
mv.dosage,
|
||||
mv.package
|
||||
FROM medication_variants mv
|
||||
JOIN medications m ON mv.medication_id = m.id
|
||||
JOIN medication_forms mf ON mv.form_id = mf.id
|
||||
ORDER BY m.name, mf.name, mv.dosage
|
||||
`;
|
||||
|
||||
db.query(patientSql, [patientId], (err, patients) => {
|
||||
@ -254,12 +271,22 @@ function showPatientOverview(req, res) {
|
||||
|
||||
const patient = patients[0];
|
||||
|
||||
// 🇪🇸 / 🇩🇪 Sprache bestimmen
|
||||
// 🇪🇸 / 🇩🇪 Sprache für Leistungen
|
||||
const serviceNameField =
|
||||
patient.country === "ES"
|
||||
? "COALESCE(NULLIF(name_es, ''), name_de)"
|
||||
: "name_de";
|
||||
|
||||
const servicesSql = `
|
||||
SELECT
|
||||
id,
|
||||
${serviceNameField} AS name,
|
||||
price
|
||||
FROM services
|
||||
WHERE active = 1
|
||||
ORDER BY ${serviceNameField}
|
||||
`;
|
||||
|
||||
const todayServicesSql = `
|
||||
SELECT
|
||||
ps.id,
|
||||
@ -279,18 +306,23 @@ function showPatientOverview(req, res) {
|
||||
db.query(notesSql, [patientId], (err, notes) => {
|
||||
if (err) return res.send("Fehler Notizen");
|
||||
|
||||
db.query(servicesSql(serviceNameField), (err, services) => {
|
||||
db.query(servicesSql, (err, services) => {
|
||||
if (err) return res.send("Fehler Leistungen");
|
||||
|
||||
db.query(todayServicesSql, [patientId], (err, todayServices) => {
|
||||
if (err) return res.send("Fehler heutige Leistungen");
|
||||
|
||||
res.render("patient_overview", {
|
||||
patient,
|
||||
notes,
|
||||
services,
|
||||
todayServices,
|
||||
user: req.session.user
|
||||
db.query(medicationVariantsSql, (err, medicationVariants) => {
|
||||
if (err) return res.send("Fehler Medikamente");
|
||||
|
||||
res.render("patient_overview", {
|
||||
patient,
|
||||
notes,
|
||||
services,
|
||||
todayServices,
|
||||
medicationVariants,
|
||||
user: req.session.user,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -298,6 +330,47 @@ function showPatientOverview(req, res) {
|
||||
});
|
||||
}
|
||||
|
||||
function assignMedicationToPatient(req, res) {
|
||||
const patientId = req.params.id;
|
||||
const { medication_variant_id, dosage_instruction, start_date, end_date } =
|
||||
req.body;
|
||||
|
||||
if (!medication_variant_id) {
|
||||
req.session.flash = {
|
||||
type: "warning",
|
||||
message: "Bitte ein Medikament auswählen",
|
||||
};
|
||||
return res.redirect(`/patients/${patientId}/overview`);
|
||||
}
|
||||
|
||||
db.query(
|
||||
`
|
||||
INSERT INTO patient_medications
|
||||
(patient_id, medication_variant_id, dosage_instruction, start_date, end_date)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
`,
|
||||
[
|
||||
patientId,
|
||||
medication_variant_id,
|
||||
dosage_instruction || null,
|
||||
start_date || new Date(),
|
||||
end_date || null,
|
||||
],
|
||||
(err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return res.send("Fehler beim Verordnen");
|
||||
}
|
||||
|
||||
req.session.flash = {
|
||||
type: "success",
|
||||
message: "Medikament erfolgreich verordnet",
|
||||
};
|
||||
|
||||
res.redirect(`/patients/${patientId}/overview`);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function addPatientNote(req, res) {
|
||||
const patientId = req.params.id;
|
||||
@ -310,7 +383,7 @@ function addPatientNote(req, res) {
|
||||
db.query(
|
||||
"INSERT INTO patient_notes (patient_id, note) VALUES (?, ?)",
|
||||
[patientId, note],
|
||||
err => {
|
||||
(err) => {
|
||||
if (err) return res.send("Fehler beim Speichern der Notiz");
|
||||
res.redirect(`/patients/${patientId}/overview`);
|
||||
}
|
||||
@ -323,7 +396,7 @@ function callFromWaitingRoom(req, res) {
|
||||
db.query(
|
||||
"UPDATE patients SET waiting_room = 0 WHERE id = ?",
|
||||
[patientId],
|
||||
err => {
|
||||
(err) => {
|
||||
if (err) return res.send("Fehler beim Entfernen aus dem Wartezimmer");
|
||||
res.redirect(`/patients/${patientId}/overview`);
|
||||
}
|
||||
@ -336,7 +409,7 @@ function dischargePatient(req, res) {
|
||||
db.query(
|
||||
"UPDATE patients SET discharged = 1 WHERE id = ?",
|
||||
[patientId],
|
||||
err => {
|
||||
(err) => {
|
||||
if (err) return res.send("Fehler beim Entlassen des Patienten");
|
||||
res.redirect("/waiting-room");
|
||||
}
|
||||
@ -375,7 +448,7 @@ function showMedicationPlan(req, res) {
|
||||
|
||||
res.render("patient_plan", {
|
||||
patient: patients[0],
|
||||
meds
|
||||
meds,
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -392,19 +465,19 @@ function movePatientToWaitingRoom(req, res) {
|
||||
WHERE id = ?
|
||||
`,
|
||||
[patientId],
|
||||
err => {
|
||||
(err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
req.session.flash = {
|
||||
type: "danger",
|
||||
message: "Fehler beim Zurücksetzen ins Wartezimmer"
|
||||
message: "Fehler beim Zurücksetzen ins Wartezimmer",
|
||||
};
|
||||
return res.redirect(`/patients/${patientId}/overview`);
|
||||
}
|
||||
|
||||
req.session.flash = {
|
||||
type: "success",
|
||||
message: "Patient wurde ins Wartezimmer gesetzt"
|
||||
message: "Patient wurde ins Wartezimmer gesetzt",
|
||||
};
|
||||
|
||||
res.redirect("/waiting-room");
|
||||
@ -415,55 +488,107 @@ function movePatientToWaitingRoom(req, res) {
|
||||
function deactivatePatient(req, res) {
|
||||
const id = req.params.id;
|
||||
|
||||
db.query(
|
||||
"UPDATE patients SET active = 0 WHERE id = ?",
|
||||
[id],
|
||||
err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
req.session.flash = {
|
||||
type: "danger",
|
||||
message: "Patient konnte nicht gesperrt werden"
|
||||
};
|
||||
return res.redirect("/patients");
|
||||
}
|
||||
|
||||
db.query("UPDATE patients SET active = 0 WHERE id = ?", [id], (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
req.session.flash = {
|
||||
type: "success",
|
||||
message: "Patient wurde gesperrt"
|
||||
type: "danger",
|
||||
message: "Patient konnte nicht gesperrt werden",
|
||||
};
|
||||
|
||||
res.redirect("/patients");
|
||||
return res.redirect("/patients");
|
||||
}
|
||||
);
|
||||
|
||||
req.session.flash = {
|
||||
type: "success",
|
||||
message: "Patient wurde gesperrt",
|
||||
};
|
||||
|
||||
res.redirect("/patients");
|
||||
});
|
||||
}
|
||||
|
||||
function activatePatient(req, res) {
|
||||
const id = req.params.id;
|
||||
|
||||
db.query(
|
||||
"UPDATE patients SET active = 1 WHERE id = ?",
|
||||
[id],
|
||||
err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
req.session.flash = {
|
||||
type: "danger",
|
||||
message: "Patient konnte nicht entsperrt werden"
|
||||
};
|
||||
return res.redirect("/patients");
|
||||
}
|
||||
|
||||
db.query("UPDATE patients SET active = 1 WHERE id = ?", [id], (err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
req.session.flash = {
|
||||
type: "success",
|
||||
message: "Patient wurde entsperrt"
|
||||
type: "danger",
|
||||
message: "Patient konnte nicht entsperrt werden",
|
||||
};
|
||||
|
||||
res.redirect("/patients");
|
||||
return res.redirect("/patients");
|
||||
}
|
||||
);
|
||||
|
||||
req.session.flash = {
|
||||
type: "success",
|
||||
message: "Patient wurde entsperrt",
|
||||
};
|
||||
|
||||
res.redirect("/patients");
|
||||
});
|
||||
}
|
||||
|
||||
async function showPatientOverviewDashborad(req, res) {
|
||||
const patientId = req.params.id;
|
||||
|
||||
try {
|
||||
// 👤 Patient
|
||||
const [[patient]] = await db
|
||||
.promise()
|
||||
.query("SELECT * FROM patients WHERE id = ?", [patientId]);
|
||||
|
||||
if (!patient) {
|
||||
return res.redirect("/patients");
|
||||
}
|
||||
|
||||
// 💊 AKTUELLE MEDIKAMENTE (end_date IS NULL)
|
||||
const [medications] = await db.promise().query(
|
||||
`
|
||||
SELECT
|
||||
m.name AS medication_name,
|
||||
mv.dosage AS variant_dosage,
|
||||
pm.dosage_instruction,
|
||||
pm.start_date
|
||||
FROM patient_medications pm
|
||||
JOIN medication_variants mv
|
||||
ON pm.medication_variant_id = mv.id
|
||||
JOIN medications m
|
||||
ON mv.medication_id = m.id
|
||||
WHERE pm.patient_id = ?
|
||||
AND pm.end_date IS NULL
|
||||
ORDER BY pm.start_date DESC
|
||||
`,
|
||||
[patientId]
|
||||
);
|
||||
|
||||
// 🧾 RECHNUNGEN
|
||||
const [invoices] = await db.promise().query(
|
||||
`
|
||||
SELECT
|
||||
id,
|
||||
invoice_date,
|
||||
total_amount,
|
||||
file_path,
|
||||
status
|
||||
FROM invoices
|
||||
WHERE patient_id = ?
|
||||
ORDER BY invoice_date DESC
|
||||
`,
|
||||
[patientId]
|
||||
);
|
||||
|
||||
res.render("patient_overview_dashboard", {
|
||||
patient,
|
||||
medications,
|
||||
invoices,
|
||||
user: req.session.user,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.send("Datenbankfehler");
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
listPatients,
|
||||
@ -481,5 +606,7 @@ module.exports = {
|
||||
showMedicationPlan,
|
||||
movePatientToWaitingRoom,
|
||||
deactivatePatient,
|
||||
activatePatient
|
||||
activatePatient,
|
||||
showPatientOverviewDashborad,
|
||||
assignMedicationToPatient,
|
||||
};
|
||||
|
||||
BIN
public/invoices/2026/invoice-2026-0037.pdf
Normal file
BIN
public/invoices/2026/invoice-2026-0037.pdf
Normal file
Binary file not shown.
BIN
public/invoices/2026/invoice-2026-0038.pdf
Normal file
BIN
public/invoices/2026/invoice-2026-0038.pdf
Normal file
Binary file not shown.
@ -6,7 +6,9 @@ const {
|
||||
showCreateUser,
|
||||
postCreateUser,
|
||||
changeUserRole,
|
||||
resetUserPassword
|
||||
resetUserPassword,
|
||||
activateUser,
|
||||
deactivateUser,
|
||||
} = require("../controllers/admin.controller");
|
||||
|
||||
const { requireAdmin } = require("../middleware/auth.middleware");
|
||||
@ -17,6 +19,7 @@ router.post("/create-user", requireAdmin, postCreateUser);
|
||||
|
||||
router.post("/users/change-role/:id", requireAdmin, changeUserRole);
|
||||
router.post("/users/reset-password/:id", requireAdmin, resetUserPassword);
|
||||
router.post("/users/activate/:id", requireAdmin, activateUser);
|
||||
router.post("/users/deactivate/:id", requireAdmin, deactivateUser);
|
||||
|
||||
module.exports = router;
|
||||
|
||||
|
||||
@ -1,10 +1,7 @@
|
||||
const express = require("express");
|
||||
const router = express.Router();
|
||||
|
||||
const {
|
||||
requireLogin,
|
||||
requireAdmin
|
||||
} = require("../middleware/auth.middleware");
|
||||
const { requireLogin, requireAdmin } = require("../middleware/auth.middleware");
|
||||
|
||||
const {
|
||||
listPatients,
|
||||
@ -20,7 +17,9 @@ const {
|
||||
dischargePatient,
|
||||
showMedicationPlan,
|
||||
deactivatePatient,
|
||||
activatePatient
|
||||
activatePatient,
|
||||
showPatientOverviewDashborad,
|
||||
assignMedicationToPatient,
|
||||
} = require("../controllers/patient.controller");
|
||||
|
||||
router.get("/", requireLogin, listPatients);
|
||||
@ -35,8 +34,9 @@ router.post("/:id/notes", requireLogin, addPatientNote);
|
||||
router.post("/waiting-room/call/:id", requireAdmin, callFromWaitingRoom);
|
||||
router.post("/:id/discharge", requireLogin, dischargePatient);
|
||||
router.get("/:id/plan", requireLogin, showMedicationPlan);
|
||||
router.post("/deactivate/:id", requireLogin, deactivatePatient);
|
||||
router.post("/activate/:id", requireLogin, activatePatient);
|
||||
router.post("/deactivate/:id", requireLogin, deactivatePatient);
|
||||
router.post("/activate/:id", requireLogin, activatePatient);
|
||||
router.get("/:id", requireLogin, showPatientOverviewDashborad);
|
||||
router.post("/:id/medications/assign", requireLogin, assignMedicationToPatient);
|
||||
|
||||
module.exports = router;
|
||||
|
||||
|
||||
@ -17,16 +17,8 @@ async function createUser(
|
||||
`INSERT INTO users
|
||||
(first_name, last_name, username, password, role, fachrichtung, arztnummer, active)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, 1)`,
|
||||
[
|
||||
first_name,
|
||||
last_name,
|
||||
username,
|
||||
hash,
|
||||
role,
|
||||
fachrichtung,
|
||||
arztnummer
|
||||
],
|
||||
err => {
|
||||
[first_name, last_name, username, hash, role, fachrichtung, arztnummer],
|
||||
(err) => {
|
||||
if (err) {
|
||||
if (err.code === "ER_DUP_ENTRY") {
|
||||
return reject("Benutzername existiert bereits");
|
||||
@ -39,28 +31,33 @@ async function createUser(
|
||||
});
|
||||
}
|
||||
|
||||
function getAllUsers(db) {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.query(
|
||||
`SELECT
|
||||
id,
|
||||
first_name,
|
||||
last_name,
|
||||
username,
|
||||
role,
|
||||
active,
|
||||
lock_until
|
||||
FROM users
|
||||
ORDER BY last_name, first_name`,
|
||||
(err, users) => {
|
||||
if (err) return reject(err);
|
||||
resolve(users);
|
||||
}
|
||||
);
|
||||
});
|
||||
async function getAllUsers(db, search = null) {
|
||||
let sql = `
|
||||
SELECT *
|
||||
FROM users
|
||||
WHERE 1=1
|
||||
`;
|
||||
const params = [];
|
||||
|
||||
if (search) {
|
||||
sql += `
|
||||
AND (
|
||||
first_name LIKE ?
|
||||
OR last_name LIKE ?
|
||||
OR username LIKE ?
|
||||
)
|
||||
`;
|
||||
const q = `%${search}%`;
|
||||
params.push(q, q, q);
|
||||
}
|
||||
|
||||
sql += " ORDER BY last_name, first_name";
|
||||
|
||||
const [rows] = await db.promise().query(sql, params);
|
||||
return rows;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createUser,
|
||||
getAllUsers
|
||||
getAllUsers,
|
||||
};
|
||||
|
||||
@ -44,6 +44,30 @@
|
||||
+ Neuen Benutzer anlegen
|
||||
</a>
|
||||
</div>
|
||||
<div class="row mb-3 align-items-end">
|
||||
<div class="col-md-6">
|
||||
<form method="GET" action="/admin/users" class="d-flex gap-2">
|
||||
<input
|
||||
type="text"
|
||||
name="q"
|
||||
class="form-control"
|
||||
placeholder="🔍 Benutzer suchen (Name oder Username)"
|
||||
value="<%= query?.q || '' %>">
|
||||
|
||||
<button class="btn btn-outline-primary">
|
||||
Suchen
|
||||
</button>
|
||||
|
||||
<% if (query?.q) { %>
|
||||
<a href="/admin/users" class="btn btn-outline-secondary">
|
||||
Reset
|
||||
</a>
|
||||
<% } %>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<table class="table table-bordered table-hover align-middle">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
|
||||
@ -38,60 +38,6 @@ function formatDate(d) {
|
||||
<% if (user && user.role === 'arzt') { %>
|
||||
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-body">
|
||||
|
||||
<h5 class="mb-3">➕ Medikament hinzufügen</h5>
|
||||
|
||||
<form method="POST"
|
||||
action="/patients/<%= patient.id %>/medications?returnTo=<%= returnTo || '' %>">
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Medikament</label>
|
||||
<select name="medication_variant_id"
|
||||
class="form-select"
|
||||
required>
|
||||
<option value="">Bitte wählen</option>
|
||||
<% meds.forEach(m => { %>
|
||||
<option value="<%= m.id %>">
|
||||
<%= m.medication %> –
|
||||
<%= m.form %> –
|
||||
<%= m.dosage %> –
|
||||
<%= m.package %>
|
||||
</option>
|
||||
<% }) %>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Dosieranweisung</label>
|
||||
<input type="text"
|
||||
name="dosage_instruction"
|
||||
class="form-control"
|
||||
placeholder="z. B. 1–0–1 nach dem Essen">
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col">
|
||||
<label class="form-label">Startdatum</label>
|
||||
<input type="date"
|
||||
name="start_date"
|
||||
class="form-control">
|
||||
</div>
|
||||
<div class="col">
|
||||
<label class="form-label">Enddatum</label>
|
||||
<input type="date"
|
||||
name="end_date"
|
||||
class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-primary">
|
||||
💾 Medikament hinzufügen
|
||||
</button>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% } else { %>
|
||||
|
||||
|
||||
@ -1,282 +1,274 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Patientenübersicht – <%= patient.firstname %> <%= patient.lastname %></title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>
|
||||
Patientenübersicht – <%= patient.firstname %> <%= patient.lastname %>
|
||||
</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="stylesheet" href="/css/bootstrap.min.css" />
|
||||
<script src="/js/service-search.js"></script>
|
||||
</head>
|
||||
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<body class="bg-light">
|
||||
<!-- NAVBAR -->
|
||||
<nav class="navbar navbar-dark bg-dark position-relative px-3">
|
||||
<div
|
||||
class="position-absolute top-50 start-50 translate-middle d-flex align-items-center gap-2 text-white"
|
||||
>
|
||||
<span style="font-size: 1.4rem">👨⚕️</span>
|
||||
<span class="fw-semibold fs-5">
|
||||
Patient – <%= patient.firstname %> <%= patient.lastname %>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<nav class="navbar navbar-dark bg-dark px-3">
|
||||
<span class="navbar-brand">
|
||||
👨⚕️ Patient – <%= patient.firstname %> <%= patient.lastname %>
|
||||
</span>
|
||||
<a href="/waiting-room" class="btn btn-outline-light btn-sm">
|
||||
🪑 Zurück
|
||||
</a>
|
||||
<form method="POST"
|
||||
action="/patients/<%= patient.id %>/waiting-room"
|
||||
class="d-inline"
|
||||
onsubmit="return confirm('Patient ins Wartezimmer zurücksetzen?')">
|
||||
<button class="btn btn-warning">
|
||||
🪑 Ins Wartezimmer
|
||||
</button>
|
||||
</form>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-4">
|
||||
<%- include("partials/flash") %>
|
||||
|
||||
<!-- =========================
|
||||
PATIENTENDATEN
|
||||
========================== -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-body">
|
||||
<h4>Patientendaten</h4>
|
||||
|
||||
<table class="table table-sm">
|
||||
<tr>
|
||||
<th>Vorname</th>
|
||||
<td><%= patient.firstname %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Nachname</th>
|
||||
<td><%= patient.lastname %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Geburtsdatum</th>
|
||||
<td>
|
||||
<%= patient.birthdate
|
||||
? new Date(patient.birthdate).toLocaleDateString("de-DE")
|
||||
: "-" %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Geschlecht</th>
|
||||
<td>
|
||||
<% if (patient.gender === 'm') { %>Männlich
|
||||
<% } else if (patient.gender === 'w') { %>Weiblich
|
||||
<% } else if (patient.gender === 'd') { %>Divers
|
||||
<% } else { %>–<% } %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>E-Mail</th>
|
||||
<td><%= patient.email || "-" %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Telefon</th>
|
||||
<td><%= patient.phone || "-" %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Adresse</th>
|
||||
<td>
|
||||
<%= patient.street || "" %> <%= patient.house_number || "" %><br>
|
||||
<%= patient.postal_code || "" %> <%= patient.city || "" %><br>
|
||||
<%= patient.country || "" %>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- =========================
|
||||
AKTIONEN
|
||||
========================== -->
|
||||
<div class="d-flex flex-wrap gap-2 align-items-center mb-4">
|
||||
|
||||
<a href="/patients/<%= patient.id %>/medications?returnTo=overview"
|
||||
class="btn btn-primary">
|
||||
💊 Medikation
|
||||
</a>
|
||||
|
||||
<a href="/patients/<%= patient.id %>/plan"
|
||||
class="btn btn-outline-secondary">
|
||||
📄 Medikationsplan
|
||||
</a>
|
||||
|
||||
<a href="/patients/edit/<%= patient.id %>?returnTo=overview"
|
||||
class="btn btn-outline-info">
|
||||
✏️ Patient bearbeiten
|
||||
</a>
|
||||
|
||||
<form method="POST"
|
||||
action="/patients/<%= patient.id %>/discharge"
|
||||
class="d-inline"
|
||||
onsubmit="return confirm('Patient wirklich entlassen?')">
|
||||
<button class="btn btn-danger">
|
||||
🟥 Entlassen
|
||||
</button>
|
||||
<div class="ms-auto">
|
||||
<form
|
||||
method="POST"
|
||||
action="/patients/<%= patient.id %>/waiting-room"
|
||||
onsubmit="return confirm('Patient ins Wartezimmer zurücksetzen?')"
|
||||
>
|
||||
<button class="btn btn-warning btn-sm">🪑 Ins Wartezimmer</button>
|
||||
</form>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
<div class="container mt-4">
|
||||
<%- include("partials/flash") %>
|
||||
|
||||
<!-- =========================
|
||||
UNTERER BEREICH
|
||||
========================== -->
|
||||
<div class="row">
|
||||
<!-- PATIENTENDATEN -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-body">
|
||||
<h4>Patientendaten</h4>
|
||||
<table class="table table-sm">
|
||||
<tr>
|
||||
<th>Vorname</th>
|
||||
<td><%= patient.firstname %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Nachname</th>
|
||||
<td><%= patient.lastname %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Geburtsdatum</th>
|
||||
<td>
|
||||
<%= patient.birthdate ? new
|
||||
Date(patient.birthdate).toLocaleDateString("de-DE") : "-" %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>E-Mail</th>
|
||||
<td><%= patient.email || "-" %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Telefon</th>
|
||||
<td><%= patient.phone || "-" %></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- =========================
|
||||
LINKS: NOTIZEN
|
||||
========================== -->
|
||||
<div class="col-md-7">
|
||||
<!-- AKTIONEN -->
|
||||
<div class="d-flex gap-2 mb-4">
|
||||
<a
|
||||
href="/patients/<%= patient.id %>/medications?returnTo=overview"
|
||||
class="btn btn-primary"
|
||||
>
|
||||
💊 Medikation verwalten
|
||||
</a>
|
||||
|
||||
<div class="card shadow">
|
||||
<div class="card-body">
|
||||
<a
|
||||
href="/patients/edit/<%= patient.id %>?returnTo=overview"
|
||||
class="btn btn-outline-info"
|
||||
>
|
||||
✏️ Patient bearbeiten
|
||||
</a>
|
||||
|
||||
<h5>Notizen</h5>
|
||||
<form
|
||||
method="POST"
|
||||
action="/patients/<%= patient.id %>/discharge"
|
||||
class="d-inline"
|
||||
onsubmit="return confirm('Patient wirklich entlassen?')"
|
||||
>
|
||||
<button class="btn btn-danger">🟥 Entlassen</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<form method="POST"
|
||||
action="/patients/<%= patient.id %>/notes"
|
||||
class="mb-3">
|
||||
<!-- UNTERER BEREICH -->
|
||||
<div
|
||||
class="row g-3"
|
||||
style="
|
||||
height: calc(100vh - 520px);
|
||||
min-height: 320px;
|
||||
padding-bottom: 3rem;
|
||||
overflow: hidden;
|
||||
"
|
||||
>
|
||||
<!-- 📝 NOTIZEN -->
|
||||
<div class="col-lg-5 col-md-12 h-100">
|
||||
<div class="card shadow h-100">
|
||||
<div class="card-body d-flex flex-column h-100">
|
||||
<h5>📝 Notizen</h5>
|
||||
|
||||
<textarea class="form-control mb-2"
|
||||
name="note"
|
||||
rows="3"
|
||||
placeholder="Neue Notiz hinzufügen..."></textarea>
|
||||
<form
|
||||
method="POST"
|
||||
action="/patients/<%= patient.id %>/notes"
|
||||
style="flex-shrink: 0"
|
||||
>
|
||||
<textarea
|
||||
class="form-control mb-2"
|
||||
name="note"
|
||||
rows="3"
|
||||
style="resize: none"
|
||||
placeholder="Neue Notiz hinzufügen…"
|
||||
></textarea>
|
||||
<button class="btn btn-sm btn-primary">
|
||||
➕ Notiz speichern
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<button class="btn btn-sm btn-primary">
|
||||
➕ Notiz speichern
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
<% if (!notes || notes.length === 0) { %>
|
||||
<p class="text-muted">Keine Notizen vorhanden</p>
|
||||
<% } else { %>
|
||||
<% notes.forEach(n => { %>
|
||||
<div class="mb-3 p-2 border rounded bg-light">
|
||||
<div class="small text-muted mb-1">
|
||||
<%= new Date(n.created_at).toLocaleString("de-DE") %>
|
||||
</div>
|
||||
<div><%= n.note %></div>
|
||||
</div>
|
||||
<% }) %>
|
||||
<% } %>
|
||||
<hr class="my-2" style="flex-shrink: 0" />
|
||||
|
||||
<div
|
||||
style="
|
||||
flex: 1 1 auto;
|
||||
overflow-y: auto;
|
||||
min-height: 0;
|
||||
padding-bottom: 2rem;
|
||||
"
|
||||
>
|
||||
<% if (!notes || notes.length === 0) { %>
|
||||
<p class="text-muted">Keine Notizen vorhanden</p>
|
||||
<% } else { %> <% notes.forEach(n => { %>
|
||||
<div class="mb-3 p-2 border rounded bg-light">
|
||||
<div class="small text-muted">
|
||||
<%= new Date(n.created_at).toLocaleString("de-DE") %>
|
||||
</div>
|
||||
<div><%= n.note %></div>
|
||||
</div>
|
||||
<% }) %> <% } %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- =========================
|
||||
RECHTS: HEUTIGE LEISTUNGEN
|
||||
========================== -->
|
||||
<div class="col-md-5">
|
||||
<!-- 💊 MEDIKAMENT -->
|
||||
<div class="col-lg-3 col-md-6 h-100">
|
||||
<div class="card shadow h-100">
|
||||
<div class="card-body">
|
||||
<h5>💊 Rezept erstellen</h5>
|
||||
|
||||
<div class="card shadow">
|
||||
<div class="card-body">
|
||||
<form
|
||||
method="POST"
|
||||
action="/patients/<%= patient.id %>/medications/assign"
|
||||
>
|
||||
<select
|
||||
name="medication_variant_id"
|
||||
class="form-select mb-2"
|
||||
required
|
||||
>
|
||||
<option value="">Bitte auswählen…</option>
|
||||
<% medicationVariants.forEach(mv => { %>
|
||||
<option value="<%= mv.variant_id %>">
|
||||
<%= mv.medication_name %> – <%= mv.form_name %> – <%=
|
||||
mv.dosage %>
|
||||
</option>
|
||||
<% }) %>
|
||||
</select>
|
||||
|
||||
<h5>Heutige Leistungen</h5>
|
||||
<input
|
||||
type="text"
|
||||
name="dosage_instruction"
|
||||
class="form-control mb-2"
|
||||
placeholder="z. B. 1–0–1"
|
||||
/>
|
||||
|
||||
<!-- Leistung hinzufügen -->
|
||||
<form method="POST"
|
||||
action="/patients/<%= patient.id %>/services"
|
||||
class="mb-3">
|
||||
<input
|
||||
type="date"
|
||||
name="start_date"
|
||||
class="form-control mb-2"
|
||||
value="<%= new Date().toISOString().split('T')[0] %>"
|
||||
/>
|
||||
|
||||
<div class="mb-2">
|
||||
<label class="form-label">Leistung suchen</label>
|
||||
<input type="text"
|
||||
id="serviceSearch"
|
||||
class="form-control mb-2"
|
||||
placeholder="Leistung suchen…">
|
||||
</div>
|
||||
<input type="date" name="end_date" class="form-control mb-3" />
|
||||
|
||||
<div class="mb-2">
|
||||
<label class="form-label">Leistung</label>
|
||||
<select name="service_id"
|
||||
id="serviceSelect"
|
||||
class="form-select"
|
||||
size="8"
|
||||
required>
|
||||
<% services.forEach(s => { %>
|
||||
<option value="<%= s.id %>">
|
||||
<%= s.name %> –
|
||||
<%= Number(s.price || 0).toFixed(2) %> €
|
||||
</option>
|
||||
<% }) %>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<label class="form-label">Menge</label>
|
||||
<input type="number"
|
||||
name="quantity"
|
||||
class="form-control"
|
||||
value="1"
|
||||
min="1"
|
||||
required>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-sm btn-success">
|
||||
➕ Leistung hinzufügen
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
<!-- Heutige Leistungen anzeigen-->
|
||||
<% if (!todayServices || todayServices.length === 0) { %>
|
||||
<p class="text-muted">
|
||||
Noch keine Leistungen für heute erfasst.
|
||||
</p>
|
||||
<% } else { %>
|
||||
|
||||
<% todayServices.forEach(ls => { %>
|
||||
<div class="border rounded p-2 mb-2 bg-light">
|
||||
|
||||
<strong><%= ls.name %></strong><br>
|
||||
|
||||
Menge: <%= ls.quantity %><br>
|
||||
Preis: <%= Number(ls.price).toFixed(2) %> €<br>
|
||||
<small class="text-muted">
|
||||
Arzt: <%= ls.doctor || "—" %>
|
||||
</small>
|
||||
|
||||
|
||||
<div class="mt-2 d-flex gap-2">
|
||||
|
||||
<!-- Preis ändern -->
|
||||
<form method="POST"
|
||||
action="/patient-services/update/<%= ls.id %>">
|
||||
<input type="number"
|
||||
step="0.01"
|
||||
name="price"
|
||||
value="<%= ls.price %>"
|
||||
class="form-control form-control-sm mb-1"
|
||||
required>
|
||||
<button class="btn btn-sm btn-outline-warning">
|
||||
💰 Preis ändern
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<!-- Löschen -->
|
||||
<form method="POST"
|
||||
action="/patient-services/delete/<%= ls.id %>"
|
||||
onsubmit="return confirm('Leistung wirklich löschen?')">
|
||||
<button class="btn btn-sm btn-danger">
|
||||
🗑️ Löschen
|
||||
</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<% }) %>
|
||||
|
||||
<% } %>
|
||||
|
||||
</div>
|
||||
<button class="btn btn-sm btn-success w-100">
|
||||
➕ Verordnen
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 🧾 HEUTIGE LEISTUNGEN -->
|
||||
<div class="col-lg-4 col-md-6 h-100">
|
||||
<div class="card shadow h-100">
|
||||
<div class="card-body d-flex flex-column h-100">
|
||||
<h5>🧾 Heutige Leistungen</h5>
|
||||
|
||||
<form
|
||||
method="POST"
|
||||
action="/patients/<%= patient.id %>/services"
|
||||
style="flex-shrink: 0"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
id="serviceSearch"
|
||||
class="form-control mb-2"
|
||||
placeholder="Leistung suchen…"
|
||||
/>
|
||||
|
||||
<select
|
||||
name="service_id"
|
||||
id="serviceSelect"
|
||||
class="form-select mb-2"
|
||||
size="5"
|
||||
required
|
||||
>
|
||||
<% services.forEach(s => { %>
|
||||
<option value="<%= s.id %>">
|
||||
<%= s.name %> – <%= Number(s.price || 0).toFixed(2) %> €
|
||||
</option>
|
||||
<% }) %>
|
||||
</select>
|
||||
|
||||
<input
|
||||
type="number"
|
||||
name="quantity"
|
||||
class="form-control mb-2"
|
||||
value="1"
|
||||
min="1"
|
||||
/>
|
||||
|
||||
<button class="btn btn-sm btn-success w-100">
|
||||
➕ Leistung hinzufügen
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<hr class="my-2" style="flex-shrink: 0" />
|
||||
|
||||
<div
|
||||
style="
|
||||
flex: 1 1 auto;
|
||||
overflow-y: auto;
|
||||
min-height: 0;
|
||||
padding-bottom: 2rem;
|
||||
"
|
||||
>
|
||||
<% if (!todayServices || todayServices.length === 0) { %>
|
||||
<p class="text-muted">Noch keine Leistungen für heute.</p>
|
||||
<% } else { %> <% todayServices.forEach(ls => { %>
|
||||
<div class="border rounded p-2 mb-2 bg-light">
|
||||
<strong><%= ls.name %></strong><br />
|
||||
Menge: <%= ls.quantity %><br />
|
||||
Preis: <%= Number(ls.price).toFixed(2) %> €
|
||||
</div>
|
||||
<% }) %> <% } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
163
views/patient_overview_dashboard.ejs
Normal file
163
views/patient_overview_dashboard.ejs
Normal file
@ -0,0 +1,163 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Patientenübersicht</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="stylesheet" href="/css/bootstrap.min.css" />
|
||||
</head>
|
||||
|
||||
<body class="bg-light">
|
||||
<!-- NAVBAR -->
|
||||
<nav class="navbar navbar-dark bg-dark position-relative px-3">
|
||||
<div
|
||||
class="position-absolute top-50 start-50 translate-middle d-flex align-items-center gap-2 text-white"
|
||||
>
|
||||
<span style="font-size: 1.4rem">👥</span>
|
||||
<span class="fw-semibold fs-5">Patientenübersicht</span>
|
||||
</div>
|
||||
|
||||
<div class="ms-auto">
|
||||
<a href="/dashboard" class="btn btn-outline-primary btn-sm">
|
||||
⬅️ Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-4">
|
||||
<!-- PATIENT INFO -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-body">
|
||||
<h4>👤 <%= patient.firstname %> <%= patient.lastname %></h4>
|
||||
|
||||
<p class="text-muted mb-3">
|
||||
Geboren am <%= new
|
||||
Date(patient.birthdate).toLocaleDateString("de-DE") %>
|
||||
</p>
|
||||
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<strong>E-Mail:</strong> <%= patient.email || "-" %>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<strong>Telefon:</strong> <%= patient.phone || "-" %>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<strong>Adresse:</strong>
|
||||
<%= patient.street || "" %> <%= patient.house_number || "" %>, <%=
|
||||
patient.postal_code || "" %> <%= patient.city || "" %>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- =========================
|
||||
MEDIKAMENTE & RECHNUNGEN
|
||||
========================== -->
|
||||
<div
|
||||
class="row g-3"
|
||||
style="
|
||||
height: calc(100vh - 420px);
|
||||
min-height: 300px;
|
||||
padding-bottom: 3rem;
|
||||
overflow: hidden;
|
||||
"
|
||||
>
|
||||
<!-- 💊 MEDIKAMENTE -->
|
||||
<div class="col-lg-6 h-100">
|
||||
<div class="card shadow h-100">
|
||||
<div class="card-body d-flex flex-column h-100">
|
||||
<h5>💊 Aktuelle Medikamente</h5>
|
||||
|
||||
<div
|
||||
style="
|
||||
flex: 1 1 auto;
|
||||
overflow-y: auto;
|
||||
min-height: 0;
|
||||
padding-bottom: 1.5rem;
|
||||
"
|
||||
>
|
||||
<% if (medications.length === 0) { %>
|
||||
<p class="text-muted">Keine aktiven Medikamente</p>
|
||||
<% } else { %>
|
||||
<table class="table table-sm table-bordered mt-2">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Medikament</th>
|
||||
<th>Variante</th>
|
||||
<th>Anweisung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% medications.forEach(m => { %>
|
||||
<tr>
|
||||
<td><%= m.medication_name %></td>
|
||||
<td><%= m.variant_dosage %></td>
|
||||
<td><%= m.dosage_instruction || "-" %></td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 🧾 RECHNUNGEN -->
|
||||
<div class="col-lg-6 h-100">
|
||||
<div class="card shadow h-100">
|
||||
<div class="card-body d-flex flex-column h-100">
|
||||
<h5>🧾 Rechnungen</h5>
|
||||
|
||||
<div
|
||||
style="
|
||||
flex: 1 1 auto;
|
||||
overflow-y: auto;
|
||||
min-height: 0;
|
||||
padding-bottom: 1.5rem;
|
||||
"
|
||||
>
|
||||
<% if (invoices.length === 0) { %>
|
||||
<p class="text-muted">Keine Rechnungen vorhanden</p>
|
||||
<% } else { %>
|
||||
<table class="table table-sm table-bordered mt-2">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Datum</th>
|
||||
<th>Betrag</th>
|
||||
<th>PDF</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% invoices.forEach(i => { %>
|
||||
<tr>
|
||||
<td>
|
||||
<%= new Date(i.invoice_date).toLocaleDateString("de-DE")
|
||||
%>
|
||||
</td>
|
||||
<td><%= Number(i.total_amount).toFixed(2) %> €</td>
|
||||
<td>
|
||||
<% if (i.file_path) { %>
|
||||
<a
|
||||
href="<%= i.file_path %>"
|
||||
target="_blank"
|
||||
class="btn btn-sm btn-outline-primary"
|
||||
>
|
||||
📄 Öffnen
|
||||
</a>
|
||||
<% } else { %> - <% } %>
|
||||
</td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,74 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Medikationsplan – <%= patient.firstname %> <%= patient.lastname %></title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
|
||||
<nav class="navbar navbar-dark bg-dark px-3">
|
||||
<span class="navbar-brand">
|
||||
📄 Medikationsplan – <%= patient.firstname %> <%= patient.lastname %>
|
||||
</span>
|
||||
<a href="/patients/<%= patient.id %>/overview"
|
||||
class="btn btn-outline-light btn-sm">
|
||||
Zurück
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-4">
|
||||
<%- include("partials/flash") %>
|
||||
<div class="card shadow">
|
||||
<div class="card-body">
|
||||
|
||||
<table class="table table-bordered table-sm">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Medikament</th>
|
||||
<th>Form</th>
|
||||
<th>Dosierung</th>
|
||||
<th>Packung</th>
|
||||
<th>Anweisung</th>
|
||||
<th>Zeitraum</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<% if (meds.length === 0) { %>
|
||||
<tr>
|
||||
<td colspan="6" class="text-center text-muted">
|
||||
Keine aktuelle Medikation
|
||||
</td>
|
||||
</tr>
|
||||
<% } %>
|
||||
|
||||
<% meds.forEach(m => { %>
|
||||
<tr>
|
||||
<td><%= m.medication %></td>
|
||||
<td><%= m.form %></td>
|
||||
<td><%= m.dosage %></td>
|
||||
<td><%= m.package %></td>
|
||||
<td><%= m.dosage_instruction || "-" %></td>
|
||||
<td>
|
||||
<%= m.start_date
|
||||
? new Date(m.start_date).toLocaleDateString("de-DE")
|
||||
: "-" %>
|
||||
–
|
||||
<%= m.end_date
|
||||
? new Date(m.end_date).toLocaleDateString("de-DE")
|
||||
: "laufend" %>
|
||||
</td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -1,257 +1,270 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Patientenübersicht</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="stylesheet" href="/css/bootstrap.min.css" />
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<nav class="navbar navbar-dark bg-dark position-relative px-3">
|
||||
<!-- 🟢 ZENTRIERTER TITEL -->
|
||||
<div
|
||||
class="position-absolute top-50 start-50 translate-middle d-flex align-items-center gap-2 text-white"
|
||||
>
|
||||
<span style="font-size: 1.4rem">👥</span>
|
||||
<span class="fw-semibold fs-5">Patientenübersicht</span>
|
||||
</div>
|
||||
|
||||
<!-- 🟢 ZENTRIERTER TITEL -->
|
||||
<div class="position-absolute top-50 start-50 translate-middle
|
||||
d-flex align-items-center gap-2 text-white">
|
||||
<span style="font-size: 1.4rem;">👥</span>
|
||||
<span class="fw-semibold fs-5">Patientenübersicht</span>
|
||||
</div>
|
||||
|
||||
<!-- 🔵 RECHTS: DASHBOARD -->
|
||||
<div class="ms-auto">
|
||||
<a href="/dashboard" class="btn btn-outline-primary btn-sm">
|
||||
⬅️ Dashboard
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- 🔵 RECHTS: DASHBOARD -->
|
||||
<div class="ms-auto">
|
||||
<a href="/dashboard" class="btn btn-outline-primary btn-sm">
|
||||
⬅️ Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container-fluid mt-4">
|
||||
<%- include("partials/flash") %>
|
||||
<div class="container-fluid mt-4">
|
||||
<%- include("partials/flash") %>
|
||||
|
||||
<!-- Aktionen oben -->
|
||||
<div class="d-flex gap-2 mb-3">
|
||||
<a href="/patients/create" class="btn btn-success">
|
||||
+ Neuer Patient
|
||||
</a>
|
||||
</div>
|
||||
<!-- Aktionen oben -->
|
||||
<div class="d-flex gap-2 mb-3">
|
||||
<a href="/patients/create" class="btn btn-success"> + Neuer Patient </a>
|
||||
</div>
|
||||
|
||||
<div class="card shadow">
|
||||
<div class="card shadow">
|
||||
<div class="card-body">
|
||||
|
||||
<!-- Suchformular -->
|
||||
<form method="GET" action="/patients" class="row g-2 mb-4">
|
||||
|
||||
<div class="col-md-3">
|
||||
<input type="text"
|
||||
name="firstname"
|
||||
class="form-control"
|
||||
placeholder="Vorname"
|
||||
value="<%= query?.firstname || '' %>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<input type="text"
|
||||
name="lastname"
|
||||
class="form-control"
|
||||
placeholder="Nachname"
|
||||
value="<%= query?.lastname || '' %>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<input type="date"
|
||||
name="birthdate"
|
||||
class="form-control"
|
||||
value="<%= query?.birthdate || '' %>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-3 d-flex gap-2">
|
||||
<button class="btn btn-primary w-100">
|
||||
Suchen
|
||||
</button>
|
||||
<a href="/patients" class="btn btn-secondary w-100">
|
||||
Zurücksetzen
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<!-- Tabelle -->
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered table-hover align-middle table-sm">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>N.I.E. / DNI</th>
|
||||
<th>Geschlecht</th>
|
||||
<th>Geburtstag</th>
|
||||
<th>E-Mail</th>
|
||||
<th>Telefon</th>
|
||||
<th>Adresse</th>
|
||||
<th>Land</th>
|
||||
<th>Status</th>
|
||||
<th>Notizen</th>
|
||||
<th>Erstellt</th>
|
||||
<th>Geändert</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<% if (patients.length === 0) { %>
|
||||
<tr>
|
||||
<td colspan="13" class="text-center text-muted">
|
||||
Keine Patienten gefunden
|
||||
</td>
|
||||
</tr>
|
||||
<% } %>
|
||||
|
||||
<% patients.forEach(p => { %>
|
||||
<tr>
|
||||
<td><%= p.id %></td>
|
||||
|
||||
<td><strong><%= p.firstname %> <%= p.lastname %></strong></td>
|
||||
<td><%= p.dni || "-" %></td>
|
||||
|
||||
<td>
|
||||
<% if (p.gender === 'm') { %>m
|
||||
<% } else if (p.gender === 'w') { %>w
|
||||
<% } else if (p.gender === 'd') { %>d
|
||||
<% } else { %>-<% } %>
|
||||
</td>
|
||||
|
||||
<td><%= new Date(p.birthdate).toLocaleDateString("de-DE") %></td>
|
||||
|
||||
<td><%= p.email || "-" %></td>
|
||||
<td><%= p.phone || "-" %></td>
|
||||
|
||||
<td>
|
||||
<%= p.street || "" %> <%= p.house_number || "" %><br>
|
||||
<%= p.postal_code || "" %> <%= p.city || "" %>
|
||||
</td>
|
||||
|
||||
<td><%= p.country || "-" %></td>
|
||||
|
||||
<td>
|
||||
<% if (p.active) { %>
|
||||
<span class="badge bg-success">Aktiv</span>
|
||||
<% } else { %>
|
||||
<span class="badge bg-secondary">Inaktiv</span>
|
||||
<% } %>
|
||||
</td>
|
||||
|
||||
<td style="max-width: 200px;">
|
||||
<%= p.notes ? p.notes.substring(0, 80) : "-" %>
|
||||
</td>
|
||||
|
||||
<td><%= new Date(p.created_at).toLocaleString("de-DE") %></td>
|
||||
<td><%= new Date(p.updated_at).toLocaleString("de-DE") %></td>
|
||||
|
||||
<!-- AKTIONEN -->
|
||||
<td class="text-nowrap">
|
||||
|
||||
<div class="dropdown">
|
||||
|
||||
<button class="btn btn-sm btn-outline-secondary"
|
||||
data-bs-toggle="dropdown">
|
||||
Auswahl ▾
|
||||
</button>
|
||||
|
||||
<ul class="dropdown-menu dropdown-menu-end position-fixed">
|
||||
|
||||
<!-- ✏️ BEARBEITEN -->
|
||||
<li>
|
||||
<a class="dropdown-item"
|
||||
href="/patients/edit/<%= p.id %>">
|
||||
✏️ Bearbeiten
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
|
||||
<!-- 🪑 WARTEZIMMER -->
|
||||
<% if (p.waiting_room) { %>
|
||||
<li>
|
||||
<span class="dropdown-item text-muted">
|
||||
🪑 Wartet bereits
|
||||
</span>
|
||||
</li>
|
||||
<% } else { %>
|
||||
<li>
|
||||
<form method="POST"
|
||||
action="/patients/waiting-room/<%= p.id %>">
|
||||
<button class="dropdown-item">
|
||||
🪑 Ins Wartezimmer
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
<% } %>
|
||||
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
|
||||
<!-- 💊 MEDIKAMENTE -->
|
||||
<li>
|
||||
<a class="dropdown-item"
|
||||
href="/patients/<%= p.id %>/medications">
|
||||
💊 Medikamente
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
|
||||
<!-- 🔒 STATUS -->
|
||||
<li>
|
||||
<% if (p.active) { %>
|
||||
<form method="POST"
|
||||
action="/patients/deactivate/<%= p.id %>">
|
||||
<button class="dropdown-item text-warning">
|
||||
🔒 Sperren
|
||||
</button>
|
||||
</form>
|
||||
<% } else { %>
|
||||
<form method="POST"
|
||||
action="/patients/activate/<%= p.id %>">
|
||||
<button class="dropdown-item text-success">
|
||||
🔓 Entsperren
|
||||
</button>
|
||||
</form>
|
||||
<% } %>
|
||||
</li>
|
||||
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
|
||||
<!-- 📎 DATEI-UPLOAD -->
|
||||
<li class="px-3 py-2">
|
||||
<form method="POST"
|
||||
action="/patients/<%= p.id %>/files"
|
||||
enctype="multipart/form-data">
|
||||
<input type="file"
|
||||
name="file"
|
||||
class="form-control form-control-sm mb-2"
|
||||
required>
|
||||
<button class="btn btn-sm btn-secondary w-100">
|
||||
📎 Hochladen
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- Suchformular -->
|
||||
<form method="GET" action="/patients" class="row g-2 mb-4">
|
||||
<div class="col-md-3">
|
||||
<input
|
||||
type="text"
|
||||
name="firstname"
|
||||
class="form-control"
|
||||
placeholder="Vorname"
|
||||
value="<%= query?.firstname || '' %>"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<input
|
||||
type="text"
|
||||
name="lastname"
|
||||
class="form-control"
|
||||
placeholder="Nachname"
|
||||
value="<%= query?.lastname || '' %>"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script src="/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
<div class="col-md-3">
|
||||
<input
|
||||
type="date"
|
||||
name="birthdate"
|
||||
class="form-control"
|
||||
value="<%= query?.birthdate || '' %>"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3 d-flex gap-2">
|
||||
<button class="btn btn-primary w-100">Suchen</button>
|
||||
<a href="/patients" class="btn btn-secondary w-100">
|
||||
Zurücksetzen
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Tabelle -->
|
||||
<div class="table-responsive">
|
||||
<table
|
||||
class="table table-bordered table-hover align-middle table-sm"
|
||||
>
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>N.I.E. / DNI</th>
|
||||
<th>Geschlecht</th>
|
||||
<th>Geburtstag</th>
|
||||
<th>E-Mail</th>
|
||||
<th>Telefon</th>
|
||||
<th>Adresse</th>
|
||||
<th>Land</th>
|
||||
<th>Status</th>
|
||||
<th>Notizen</th>
|
||||
<th>Erstellt</th>
|
||||
<th>Geändert</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% if (patients.length === 0) { %>
|
||||
<tr>
|
||||
<td colspan="13" class="text-center text-muted">
|
||||
Keine Patienten gefunden
|
||||
</td>
|
||||
</tr>
|
||||
<% } %> <% patients.forEach(p => { %>
|
||||
<tr>
|
||||
<td><%= p.id %></td>
|
||||
|
||||
<td><strong><%= p.firstname %> <%= p.lastname %></strong></td>
|
||||
<td><%= p.dni || "-" %></td>
|
||||
|
||||
<td>
|
||||
<% if (p.gender === 'm') { %>m <% } else if (p.gender ===
|
||||
'w') { %>w <% } else if (p.gender === 'd') { %>d <% } else {
|
||||
%>-<% } %>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<%= new Date(p.birthdate).toLocaleDateString("de-DE") %>
|
||||
</td>
|
||||
|
||||
<td><%= p.email || "-" %></td>
|
||||
<td><%= p.phone || "-" %></td>
|
||||
|
||||
<td>
|
||||
<%= p.street || "" %> <%= p.house_number || "" %><br />
|
||||
<%= p.postal_code || "" %> <%= p.city || "" %>
|
||||
</td>
|
||||
|
||||
<td><%= p.country || "-" %></td>
|
||||
|
||||
<td>
|
||||
<% if (p.active) { %>
|
||||
<span class="badge bg-success">Aktiv</span>
|
||||
<% } else { %>
|
||||
<span class="badge bg-secondary">Inaktiv</span>
|
||||
<% } %>
|
||||
</td>
|
||||
|
||||
<td style="max-width: 200px">
|
||||
<%= p.notes ? p.notes.substring(0, 80) : "-" %>
|
||||
</td>
|
||||
|
||||
<td><%= new Date(p.created_at).toLocaleString("de-DE") %></td>
|
||||
<td><%= new Date(p.updated_at).toLocaleString("de-DE") %></td>
|
||||
|
||||
<!-- AKTIONEN -->
|
||||
<td class="text-nowrap">
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn btn-sm btn-outline-secondary"
|
||||
data-bs-toggle="dropdown"
|
||||
>
|
||||
Auswahl ▾
|
||||
</button>
|
||||
|
||||
<ul
|
||||
class="dropdown-menu dropdown-menu-end position-fixed"
|
||||
>
|
||||
<!-- ✏️ BEARBEITEN -->
|
||||
<li>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="/patients/edit/<%= p.id %>"
|
||||
>
|
||||
✏️ Bearbeiten
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li><hr class="dropdown-divider" /></li>
|
||||
|
||||
<!-- 🪑 WARTEZIMMER -->
|
||||
<% if (p.waiting_room) { %>
|
||||
<li>
|
||||
<span class="dropdown-item text-muted">
|
||||
🪑 Wartet bereits
|
||||
</span>
|
||||
</li>
|
||||
<% } else { %>
|
||||
<li>
|
||||
<form
|
||||
method="POST"
|
||||
action="/patients/waiting-room/<%= p.id %>"
|
||||
>
|
||||
<button class="dropdown-item">
|
||||
🪑 Ins Wartezimmer
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
<% } %>
|
||||
|
||||
<li><hr class="dropdown-divider" /></li>
|
||||
|
||||
<!-- 💊 MEDIKAMENTE -->
|
||||
<li>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="/patients/<%= p.id %>/medications"
|
||||
>
|
||||
💊 Medikamente
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li><hr class="dropdown-divider" /></li>
|
||||
|
||||
<!-- 🔒 STATUS -->
|
||||
<li>
|
||||
<% if (p.active) { %>
|
||||
<form
|
||||
method="POST"
|
||||
action="/patients/deactivate/<%= p.id %>"
|
||||
>
|
||||
<button class="dropdown-item text-warning">
|
||||
🔒 Sperren
|
||||
</button>
|
||||
</form>
|
||||
<% } else { %>
|
||||
<form
|
||||
method="POST"
|
||||
action="/patients/activate/<%= p.id %>"
|
||||
>
|
||||
<button class="dropdown-item text-success">
|
||||
🔓 Entsperren
|
||||
</button>
|
||||
</form>
|
||||
<% } %>
|
||||
</li>
|
||||
|
||||
<!-- 📋 ÜBERSICHT -->
|
||||
<li>
|
||||
<a class="dropdown-item" href="/patients/<%= p.id %>">
|
||||
📋 Übersicht
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li><hr class="dropdown-divider" /></li>
|
||||
|
||||
<!-- 📎 DATEI-UPLOAD -->
|
||||
<li class="px-3 py-2">
|
||||
<form
|
||||
method="POST"
|
||||
action="/patients/<%= p.id %>/files"
|
||||
enctype="multipart/form-data"
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
name="file"
|
||||
class="form-control form-control-sm mb-2"
|
||||
required
|
||||
/>
|
||||
<button class="btn btn-sm btn-secondary w-100">
|
||||
📎 Hochladen
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user