Medikamente übersicht geändert.
This commit is contained in:
parent
8754c22dc4
commit
961c024252
100
app.js
100
app.js
@ -1,16 +1,13 @@
|
||||
const express = require("express");
|
||||
const session = require("express-session");
|
||||
const bcrypt = require("bcrypt");
|
||||
const db = require("./db");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { requireLogin, requireAdmin} = require("./middleware/auth.middleware");
|
||||
const adminRoutes = require("./routes/admin.routes");
|
||||
const dashboardRoutes = require("./routes/dashboard.routes");
|
||||
const helmet = require("helmet");
|
||||
const sessionStore = require("./config/session");
|
||||
require("dotenv").config();
|
||||
|
||||
const adminRoutes = require("./routes/admin.routes");
|
||||
const dashboardRoutes = require("./routes/dashboard.routes");
|
||||
const patientRoutes = require("./routes/patient.routes");
|
||||
const medicationRoutes = require("./routes/medication.routes");
|
||||
const medicationRoutes = require("./routes/medications.routes");
|
||||
const patientMedicationRoutes = require("./routes/patientMedication.routes");
|
||||
const waitingRoomRoutes = require("./routes/waitingRoom.routes");
|
||||
const serviceRoutes = require("./routes/service.routes");
|
||||
@ -18,10 +15,7 @@ const patientServiceRoutes = require("./routes/patientService.routes");
|
||||
const invoiceRoutes = require("./routes/invoice.routes");
|
||||
const patientFileRoutes = require("./routes/patientFile.routes");
|
||||
const companySettingsRoutes = require("./routes/companySettings.routes");
|
||||
|
||||
|
||||
|
||||
require("dotenv").config();
|
||||
const authRoutes = require("./routes/auth.routes");
|
||||
|
||||
const app = express();
|
||||
|
||||
@ -31,37 +25,31 @@ const app = express();
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
app.use(helmet());
|
||||
|
||||
app.use(session({
|
||||
name: "praxis.sid",
|
||||
secret: process.env.SESSION_SECRET,
|
||||
store: sessionStore,
|
||||
resave: false,
|
||||
saveUninitialized: false
|
||||
}));
|
||||
app.use(
|
||||
session({
|
||||
name: "praxis.sid",
|
||||
secret: process.env.SESSION_SECRET,
|
||||
store: sessionStore,
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
})
|
||||
);
|
||||
|
||||
const flashMiddleware = require("./middleware/flash.middleware");
|
||||
app.use(flashMiddleware);
|
||||
|
||||
app.use(express.static("public"));
|
||||
|
||||
app.use("/uploads", express.static("uploads"));
|
||||
app.set("view engine", "ejs");
|
||||
|
||||
app.use("/patients", require("./routes/patient.routes"));
|
||||
|
||||
app.use("/uploads", express.static("uploads"));
|
||||
|
||||
|
||||
/* ===============================
|
||||
COMPANYDATA
|
||||
COMPANY SETTINGS
|
||||
================================ */
|
||||
app.use(companySettingsRoutes);
|
||||
|
||||
|
||||
/* ===============================
|
||||
LOGIN
|
||||
AUTH / LOGIN
|
||||
================================ */
|
||||
const authRoutes = require("./routes/auth.routes");
|
||||
|
||||
app.use("/", authRoutes);
|
||||
|
||||
/* ===============================
|
||||
@ -70,7 +58,7 @@ app.use("/", authRoutes);
|
||||
app.use("/dashboard", dashboardRoutes);
|
||||
|
||||
/* ===============================
|
||||
Mitarbeiter
|
||||
ADMIN
|
||||
================================ */
|
||||
app.use("/admin", adminRoutes);
|
||||
|
||||
@ -78,41 +66,45 @@ app.use("/admin", adminRoutes);
|
||||
PATIENTEN
|
||||
================================ */
|
||||
app.use("/patients", patientRoutes);
|
||||
app.use("/patients", patientMedicationRoutes);
|
||||
app.use("/patients", patientServiceRoutes);
|
||||
|
||||
/* ===============================
|
||||
MEDIKAMENTE
|
||||
================================ */
|
||||
app.use("/medications", medicationRoutes);
|
||||
console.log("🧪 /medications Router mounted");
|
||||
|
||||
/* ===============================
|
||||
LEISTUNGEN
|
||||
================================ */
|
||||
app.use("/services", serviceRoutes);
|
||||
|
||||
/* ===============================
|
||||
DATEIEN
|
||||
================================ */
|
||||
app.use("/", patientFileRoutes);
|
||||
|
||||
/* ===============================
|
||||
MEDIKAMENTENÜBERSICHT
|
||||
WARTEZIMMER
|
||||
================================ */
|
||||
app.use("/medications", medicationRoutes);
|
||||
app.use("/patients", patientMedicationRoutes);
|
||||
|
||||
|
||||
// ===============================
|
||||
// PATIENT INS WARTEZIMMER
|
||||
// ===============================
|
||||
app.use("/", waitingRoomRoutes);
|
||||
|
||||
// ===============================
|
||||
// Leistungen
|
||||
// ===============================
|
||||
app.use("/services", serviceRoutes);
|
||||
app.use("/patients", patientServiceRoutes);
|
||||
|
||||
// ===============================
|
||||
// RECHNUNGEN
|
||||
// ===============================
|
||||
/* ===============================
|
||||
RECHNUNGEN
|
||||
================================ */
|
||||
app.use("/", invoiceRoutes);
|
||||
|
||||
/* ===============================
|
||||
LOGOUT
|
||||
================================ */
|
||||
app.get("/logout", (req, res) => {
|
||||
req.session.destroy(() => res.redirect("/"));
|
||||
req.session.destroy(() => res.redirect("/"));
|
||||
});
|
||||
|
||||
// ===============================
|
||||
// ERROR HANDLING (IMMER ZUM SCHLUSS)
|
||||
// ===============================
|
||||
/* ===============================
|
||||
ERROR HANDLING
|
||||
================================ */
|
||||
app.use((err, req, res, next) => {
|
||||
console.error(err);
|
||||
res.status(500).send("Interner Serverfehler");
|
||||
@ -121,8 +113,8 @@ app.use((err, req, res, next) => {
|
||||
/* ===============================
|
||||
SERVER
|
||||
================================ */
|
||||
const PORT = 51777; // garantiert frei
|
||||
const HOST = "127.0.0.1"; // kein HTTP.sys
|
||||
const PORT = 51777;
|
||||
const HOST = "127.0.0.1";
|
||||
|
||||
app.listen(PORT, HOST, () => {
|
||||
console.log(`Server läuft auf http://${HOST}:${PORT}`);
|
||||
|
||||
@ -2,25 +2,50 @@ const db = require("../db");
|
||||
|
||||
// 📋 LISTE
|
||||
function listMedications(req, res, next) {
|
||||
const sql = `
|
||||
const { q, onlyActive } = req.query;
|
||||
|
||||
let sql = `
|
||||
SELECT
|
||||
v.id,
|
||||
m.id AS medication_id,
|
||||
m.name AS medication,
|
||||
m.active,
|
||||
f.name AS form,
|
||||
v.dosage,
|
||||
v.package
|
||||
FROM medication_variants v
|
||||
JOIN medications m ON v.medication_id = m.id
|
||||
JOIN medication_forms f ON v.form_id = f.id
|
||||
ORDER BY m.name, v.dosage
|
||||
WHERE 1=1
|
||||
`;
|
||||
|
||||
db.query(sql, (err, rows) => {
|
||||
const params = [];
|
||||
|
||||
if (q) {
|
||||
sql += `
|
||||
AND (
|
||||
m.name LIKE ?
|
||||
OR f.name LIKE ?
|
||||
OR v.dosage LIKE ?
|
||||
OR v.package LIKE ?
|
||||
)
|
||||
`;
|
||||
params.push(`%${q}%`, `%${q}%`, `%${q}%`, `%${q}%`);
|
||||
}
|
||||
|
||||
if (onlyActive === "1") {
|
||||
sql += " AND m.active = 1";
|
||||
}
|
||||
|
||||
sql += " ORDER BY m.name, v.dosage";
|
||||
|
||||
db.query(sql, params, (err, rows) => {
|
||||
if (err) return next(err);
|
||||
|
||||
res.render("medications", {
|
||||
rows,
|
||||
user: req.session.user
|
||||
query: { q, onlyActive },
|
||||
user: req.session.user,
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -38,16 +63,75 @@ function updateMedication(req, res, next) {
|
||||
WHERE id = ?
|
||||
`;
|
||||
|
||||
db.query(sql, [dosage, pkg, id], err => {
|
||||
db.query(sql, [dosage, pkg, id], (err) => {
|
||||
if (err) return next(err);
|
||||
|
||||
req.session.flash = { type: "success", message: "Medikament gespeichert"};
|
||||
req.session.flash = { type: "success", message: "Medikament gespeichert" };
|
||||
res.redirect("/medications");
|
||||
});
|
||||
}
|
||||
|
||||
function toggleMedication(req, res, next) {
|
||||
const id = req.params.id;
|
||||
|
||||
db.query(
|
||||
"UPDATE medications SET active = NOT active WHERE id = ?",
|
||||
[id],
|
||||
(err) => {
|
||||
if (err) return next(err);
|
||||
res.redirect("/medications");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function showCreateMedication(req, res) {
|
||||
const sql = "SELECT id, name FROM medication_forms ORDER BY name";
|
||||
|
||||
db.query(sql, (err, forms) => {
|
||||
if (err) return res.send("DB Fehler");
|
||||
|
||||
res.render("medication_create", {
|
||||
forms,
|
||||
user: req.session.user,
|
||||
error: null,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function createMedication(req, res) {
|
||||
const { name, form_id, dosage, package: pkg } = req.body;
|
||||
|
||||
if (!name || !form_id || !dosage) {
|
||||
return res.send("Pflichtfelder fehlen");
|
||||
}
|
||||
|
||||
db.query(
|
||||
"INSERT INTO medications (name, active) VALUES (?, 1)",
|
||||
[name],
|
||||
(err, result) => {
|
||||
if (err) return res.send("Fehler Medikament");
|
||||
|
||||
const medicationId = result.insertId;
|
||||
|
||||
db.query(
|
||||
`INSERT INTO medication_variants
|
||||
(medication_id, form_id, dosage, package)
|
||||
VALUES (?, ?, ?, ?)`,
|
||||
[medicationId, form_id, dosage, pkg || null],
|
||||
(err) => {
|
||||
if (err) return res.send("Fehler Variante");
|
||||
|
||||
res.redirect("/medications");
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
listMedications,
|
||||
updateMedication
|
||||
updateMedication,
|
||||
toggleMedication,
|
||||
showCreateMedication,
|
||||
createMedication,
|
||||
};
|
||||
|
||||
|
||||
BIN
public/invoices/2026/invoice-2026-0040.pdf
Normal file
BIN
public/invoices/2026/invoice-2026-0040.pdf
Normal file
Binary file not shown.
@ -4,12 +4,26 @@ const router = express.Router();
|
||||
const { requireLogin } = require("../middleware/auth.middleware");
|
||||
const {
|
||||
listMedications,
|
||||
updateMedication
|
||||
updateMedication,
|
||||
toggleMedication,
|
||||
showCreateMedication,
|
||||
createMedication,
|
||||
} = require("../controllers/medication.controller");
|
||||
|
||||
console.log("✅ medication.routes geladen");
|
||||
|
||||
router.get("/", requireLogin, listMedications);
|
||||
|
||||
// 🆕 Formular anzeigen
|
||||
router.get("/create", requireLogin, showCreateMedication);
|
||||
|
||||
// 🆕 Speichern
|
||||
router.post("/create", requireLogin, createMedication);
|
||||
|
||||
// 🆕 UPDATE pro Zeile
|
||||
router.post("/update/:id", requireLogin, updateMedication);
|
||||
|
||||
// 🆕 Toggle
|
||||
router.post("/toggle/:id", requireLogin, toggleMedication);
|
||||
|
||||
module.exports = router;
|
||||
@ -2,17 +2,20 @@ const express = require("express");
|
||||
const router = express.Router();
|
||||
|
||||
const { requireLogin, requireAdmin } = require("../middleware/auth.middleware");
|
||||
const {
|
||||
const {
|
||||
addPatientService,
|
||||
deletePatientService,
|
||||
updatePatientServicePrice,
|
||||
updatePatientServiceQuantity
|
||||
updatePatientServiceQuantity,
|
||||
} = require("../controllers/patientService.controller");
|
||||
|
||||
router.post("/:id/services", requireLogin, addPatientService);
|
||||
router.post("/services/delete/:id", requireAdmin, deletePatientService);
|
||||
router.post("/services/update-price/:id", requireAdmin, updatePatientServicePrice);
|
||||
router.post("/patients/services/update-quantity/:id", updatePatientServiceQuantity);
|
||||
|
||||
router.post(
|
||||
"/services/update-price/:id",
|
||||
requireAdmin,
|
||||
updatePatientServicePrice
|
||||
);
|
||||
router.post("/services/update-quantity/:id", updatePatientServiceQuantity);
|
||||
|
||||
module.exports = router;
|
||||
|
||||
45
views/medication_create.ejs
Normal file
45
views/medication_create.ejs
Normal file
@ -0,0 +1,45 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Neues Medikament</title>
|
||||
<link rel="stylesheet" href="/css/bootstrap.min.css" />
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<div class="container mt-4">
|
||||
<h4>➕ Neues Medikament</h4>
|
||||
|
||||
<% if (error) { %>
|
||||
<div class="alert alert-danger"><%= error %></div>
|
||||
<% } %>
|
||||
|
||||
<form method="POST" action="/medications/create">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Medikament</label>
|
||||
<input name="name" class="form-control" required />
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Darreichungsform</label>
|
||||
<select name="form_id" class="form-control" required>
|
||||
<% forms.forEach(f => { %>
|
||||
<option value="<%= f.id %>"><%= f.name %></option>
|
||||
<% }) %>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Dosierung</label>
|
||||
<input name="dosage" class="form-control" required />
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Packung</label>
|
||||
<input name="package" class="form-control" />
|
||||
</div>
|
||||
|
||||
<button class="btn btn-success">Speichern</button>
|
||||
<a href="/medications" class="btn btn-secondary">Abbrechen</a>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,96 +1,164 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Medikamentenübersicht</title>
|
||||
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
||||
<meta charset="UTF-8" />
|
||||
<title>Medikamentenübersicht</title>
|
||||
<link rel="stylesheet" href="/css/bootstrap.min.css" />
|
||||
<script src="/js/services-lock.js"></script>
|
||||
|
||||
<style>
|
||||
input.form-control { box-shadow: none !important; }
|
||||
|
||||
input.form-control:disabled {
|
||||
background-color: #fff !important;
|
||||
color: #212529 !important;
|
||||
opacity: 1 !important;
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
input.form-control:disabled:focus {
|
||||
box-shadow: none !important;
|
||||
outline: none !important;
|
||||
}
|
||||
/* Inaktive Medikamente ROT */
|
||||
tr.table-secondary > td {
|
||||
background-color: #f8d7da !important;
|
||||
}
|
||||
</style>
|
||||
</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.3rem;">💊</span>
|
||||
<span class="fw-semibold fs-5">Medikamentenübersicht</span>
|
||||
</div>
|
||||
|
||||
<!-- 🔵 RECHTS: DASHBOARD -->
|
||||
<div class="ms-auto">
|
||||
<a href="/dashboard" class="btn btn-outline-light btn-sm">
|
||||
⬅️ Dashboard
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="position-absolute top-50 start-50 translate-middle d-flex align-items-center gap-2 text-white">
|
||||
<span style="font-size:1.3rem">💊</span>
|
||||
<span class="fw-semibold fs-5">Medikamentenübersicht</span>
|
||||
</div>
|
||||
<div class="ms-auto">
|
||||
<a href="/dashboard" class="btn btn-outline-light btn-sm">⬅️ Dashboard</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-4">
|
||||
<%- include("partials/flash") %>
|
||||
<div class="card shadow">
|
||||
<div class="card-body">
|
||||
<%- include("partials/flash") %>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered table-hover table-sm align-middle">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>Medikament</th>
|
||||
<th>Darreichungsform</th>
|
||||
<th>Dosierung</th>
|
||||
<th>Packung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% rows.forEach(r => { %>
|
||||
<tr>
|
||||
<form method="POST"
|
||||
action="/medications/update/<%= r.id %>">
|
||||
<div class="card shadow">
|
||||
<div class="card-body">
|
||||
|
||||
<td>
|
||||
<input type="text"
|
||||
name="medication"
|
||||
value="<%= r.medication %>"
|
||||
class="form-control form-control-sm"
|
||||
required>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<input type="text"
|
||||
name="form"
|
||||
value="<%= r.form %>"
|
||||
class="form-control form-control-sm">
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<input type="text"
|
||||
name="dosage"
|
||||
value="<%= r.dosage %>"
|
||||
class="form-control form-control-sm">
|
||||
</td>
|
||||
|
||||
<td class="d-flex gap-2">
|
||||
<input type="text"
|
||||
name="package"
|
||||
value="<%= r.package %>"
|
||||
class="form-control form-control-sm">
|
||||
|
||||
<button class="btn btn-sm btn-outline-success"
|
||||
type="submit">
|
||||
💾
|
||||
</button>
|
||||
</td>
|
||||
|
||||
</form>
|
||||
</tr>
|
||||
<% }) %>
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
<!-- 🔍 Suche -->
|
||||
<form method="GET" action="/medications" class="row g-2 mb-3">
|
||||
|
||||
<div class="col-md-6">
|
||||
<input type="text"
|
||||
name="q"
|
||||
class="form-control"
|
||||
placeholder="🔍 Suche nach Medikament, Form, Dosierung"
|
||||
value="<%= query?.q || '' %>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3 d-flex gap-2">
|
||||
<button class="btn btn-primary w-100">Suchen</button>
|
||||
<a href="/medications" class="btn btn-secondary w-100">Reset</a>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3 d-flex align-items-center">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input"
|
||||
type="checkbox"
|
||||
name="onlyActive"
|
||||
value="1"
|
||||
<%= query?.onlyActive === "1" ? "checked" : "" %>>
|
||||
<label class="form-check-label">
|
||||
Nur aktive Medikamente
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<!-- ➕ Neu -->
|
||||
<a href="/medications/create" class="btn btn-success mb-3">
|
||||
➕ Neues Medikament
|
||||
</a>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered table-hover table-sm align-middle">
|
||||
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>Medikament</th>
|
||||
<th>Darreichungsform</th>
|
||||
<th>Dosierung</th>
|
||||
<th>Packung</th>
|
||||
<th>Status</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<% rows.forEach(r => { %>
|
||||
|
||||
<tr class="<%= r.active ? '' : 'table-secondary' %>">
|
||||
|
||||
<!-- UPDATE-FORM -->
|
||||
<form method="POST" action="/medications/update/<%= r.id %>">
|
||||
|
||||
<td><%= r.medication %></td>
|
||||
<td><%= r.form %></td>
|
||||
|
||||
<td>
|
||||
<input type="text"
|
||||
name="dosage"
|
||||
value="<%= r.dosage %>"
|
||||
class="form-control form-control-sm"
|
||||
disabled>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<input type="text"
|
||||
name="package"
|
||||
value="<%= r.package %>"
|
||||
class="form-control form-control-sm"
|
||||
disabled>
|
||||
</td>
|
||||
|
||||
<td class="text-center">
|
||||
<%= r.active ? "Aktiv" : "Inaktiv" %>
|
||||
</td>
|
||||
|
||||
<td class="d-flex gap-2">
|
||||
|
||||
<button class="btn btn-sm btn-outline-success save-btn" disabled>
|
||||
💾
|
||||
</button>
|
||||
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-outline-warning lock-btn">
|
||||
🔓
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
<!-- TOGGLE-FORM (separat!) -->
|
||||
<form method="POST" action="/medications/toggle/<%= r.medication_id %>">
|
||||
<button class="btn btn-sm <%= r.active ? 'btn-outline-danger' : 'btn-outline-success' %>">
|
||||
<%= r.active ? "⛔" : "✅" %>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<% }) %>
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user