Aenderungen der Dashboard Icons
This commit is contained in:
parent
851250a734
commit
7ab67a839b
1
app.js
1
app.js
@ -77,6 +77,7 @@ app.use("/", patientFileRoutes);
|
||||
app.use("/medications", medicationRoutes);
|
||||
app.use("/patients", patientMedicationRoutes);
|
||||
|
||||
|
||||
// ===============================
|
||||
// PATIENT INS WARTEZIMMER
|
||||
// ===============================
|
||||
|
||||
@ -22,13 +22,19 @@ async function createInvoicePdf(req, res) {
|
||||
const [rows] = await db.promise().query(`
|
||||
SELECT
|
||||
ps.quantity,
|
||||
s.name,
|
||||
COALESCE(ps.price_override, s.price) AS price
|
||||
COALESCE(ps.price_override, s.price) AS price,
|
||||
|
||||
CASE
|
||||
WHEN UPPER(TRIM(?)) = 'ES'
|
||||
THEN COALESCE(NULLIF(s.name_es, ''), s.name_de)
|
||||
ELSE s.name_de
|
||||
END AS name
|
||||
|
||||
FROM patient_services ps
|
||||
JOIN services s ON ps.service_id = s.id
|
||||
WHERE ps.patient_id = ?
|
||||
AND ps.invoice_id IS NULL
|
||||
`, [patientId]);
|
||||
`, [patient.country, patientId]);
|
||||
|
||||
if (rows.length === 0) {
|
||||
return res.send("Keine Leistungen vorhanden");
|
||||
@ -36,7 +42,7 @@ async function createInvoicePdf(req, res) {
|
||||
|
||||
const services = rows.map(s => ({
|
||||
quantity: Number(s.quantity),
|
||||
name_de: s.name,
|
||||
name: s.name,
|
||||
price: Number(s.price),
|
||||
total: Number(s.price) * Number(s.quantity)
|
||||
}));
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
const db = require("../db");
|
||||
|
||||
function listMedications(req, res) {
|
||||
// 📋 LISTE
|
||||
function listMedications(req, res, next) {
|
||||
const sql = `
|
||||
SELECT
|
||||
v.id,
|
||||
m.name AS medication,
|
||||
f.name AS form,
|
||||
v.dosage,
|
||||
@ -14,9 +16,38 @@ function listMedications(req, res) {
|
||||
`;
|
||||
|
||||
db.query(sql, (err, rows) => {
|
||||
if (err) return res.send("Datenbankfehler");
|
||||
res.render("medications", { rows });
|
||||
if (err) return next(err);
|
||||
|
||||
res.render("medications", {
|
||||
rows,
|
||||
user: req.session.user
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { listMedications };
|
||||
// 💾 UPDATE
|
||||
function updateMedication(req, res, next) {
|
||||
const { medication, form, dosage, package: pkg } = req.body;
|
||||
const id = req.params.id;
|
||||
|
||||
const sql = `
|
||||
UPDATE medication_variants
|
||||
SET
|
||||
dosage = ?,
|
||||
package = ?
|
||||
WHERE id = ?
|
||||
`;
|
||||
|
||||
db.query(sql, [dosage, pkg, id], err => {
|
||||
if (err) return next(err);
|
||||
|
||||
req.session.flash = { type: "success", message: "Medikament gespeichert"};
|
||||
res.redirect("/medications");
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
listMedications,
|
||||
updateMedication
|
||||
};
|
||||
|
||||
|
||||
@ -60,6 +60,50 @@ function listServices(req, res) {
|
||||
}
|
||||
}
|
||||
|
||||
function listServicesAdmin(req, res) {
|
||||
const { q, onlyActive } = req.query;
|
||||
|
||||
let sql = `
|
||||
SELECT
|
||||
id,
|
||||
name_de,
|
||||
name_es,
|
||||
category,
|
||||
price,
|
||||
price_c70,
|
||||
active
|
||||
FROM services
|
||||
WHERE 1=1
|
||||
`;
|
||||
const params = [];
|
||||
|
||||
if (q) {
|
||||
sql += `
|
||||
AND (
|
||||
name_de LIKE ?
|
||||
OR name_es LIKE ?
|
||||
OR category LIKE ?
|
||||
)
|
||||
`;
|
||||
params.push(`%${q}%`, `%${q}%`, `%${q}%`);
|
||||
}
|
||||
|
||||
if (onlyActive === "1") {
|
||||
sql += " AND active = 1";
|
||||
}
|
||||
|
||||
sql += " ORDER BY name_de";
|
||||
|
||||
db.query(sql, params, (err, services) => {
|
||||
if (err) return res.send("Datenbankfehler");
|
||||
|
||||
res.render("services", {
|
||||
services,
|
||||
user: req.session.user,
|
||||
query: { q, onlyActive }
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function showCreateService(req, res) {
|
||||
res.render("service_create", {
|
||||
@ -184,15 +228,26 @@ function listOpenServices(req, res, next) {
|
||||
p.id AS patient_id,
|
||||
p.firstname,
|
||||
p.lastname,
|
||||
p.country,
|
||||
ps.id AS patient_service_id,
|
||||
ps.quantity,
|
||||
COALESCE(ps.price_override, s.price) AS price,
|
||||
s.name
|
||||
|
||||
-- 🌍 Sprachabhängiger Servicename
|
||||
CASE
|
||||
WHEN UPPER(TRIM(p.country)) = 'ES'
|
||||
THEN COALESCE(NULLIF(s.name_es, ''), s.name_de)
|
||||
ELSE s.name_de
|
||||
END AS name
|
||||
|
||||
FROM patient_services ps
|
||||
JOIN patients p ON ps.patient_id = p.id
|
||||
JOIN services s ON ps.service_id = s.id
|
||||
WHERE ps.invoice_id IS NULL
|
||||
ORDER BY p.lastname, p.firstname
|
||||
ORDER BY
|
||||
p.lastname,
|
||||
p.firstname,
|
||||
name
|
||||
`;
|
||||
|
||||
db.query(sql, (err, rows) => {
|
||||
@ -206,6 +261,7 @@ function listOpenServices(req, res, next) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
function showServiceLogs(req, res) {
|
||||
db.query(
|
||||
`
|
||||
@ -238,5 +294,6 @@ module.exports = {
|
||||
updateServicePrice,
|
||||
toggleService,
|
||||
listOpenServices,
|
||||
showServiceLogs
|
||||
showServiceLogs,
|
||||
listServicesAdmin
|
||||
};
|
||||
|
||||
17
package-lock.json
generated
17
package-lock.json
generated
@ -10,6 +10,7 @@
|
||||
"dependencies": {
|
||||
"bcrypt": "^6.0.0",
|
||||
"bootstrap": "^5.3.8",
|
||||
"bootstrap-icons": "^1.13.1",
|
||||
"docxtemplater": "^3.67.6",
|
||||
"dotenv": "^17.2.3",
|
||||
"ejs": "^3.1.10",
|
||||
@ -1951,6 +1952,22 @@
|
||||
"@popperjs/core": "^2.11.8"
|
||||
}
|
||||
},
|
||||
"node_modules/bootstrap-icons": {
|
||||
"version": "1.13.1",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.13.1.tgz",
|
||||
"integrity": "sha512-ijombt4v6bv5CLeXvRWKy7CuM3TRTuPEuGaGKvTV5cz65rQSY8RQ2JcHt6b90cBBAC7s8fsf2EkQDldzCoXUjw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/twbs"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/bootstrap"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
"dependencies": {
|
||||
"bcrypt": "^6.0.0",
|
||||
"bootstrap": "^5.3.8",
|
||||
"bootstrap-icons": "^1.13.1",
|
||||
"docxtemplater": "^3.67.6",
|
||||
"dotenv": "^17.2.3",
|
||||
"ejs": "^3.1.10",
|
||||
|
||||
2106
public/bootstrap-icons/bootstrap-icons.css
vendored
Normal file
2106
public/bootstrap-icons/bootstrap-icons.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5
public/bootstrap-icons/bootstrap-icons.min.css
vendored
Normal file
5
public/bootstrap-icons/bootstrap-icons.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
public/bootstrap-icons/fonts/bootstrap-icons.woff
Normal file
BIN
public/bootstrap-icons/fonts/bootstrap-icons.woff
Normal file
Binary file not shown.
BIN
public/bootstrap-icons/fonts/bootstrap-icons.woff2
Normal file
BIN
public/bootstrap-icons/fonts/bootstrap-icons.woff2
Normal file
Binary file not shown.
7
public/js/bootstrap.bundle.min.js
vendored
Normal file
7
public/js/bootstrap.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
28
public/js/services-lock.js
Normal file
28
public/js/services-lock.js
Normal file
@ -0,0 +1,28 @@
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
|
||||
document.querySelectorAll(".lock-btn").forEach(btn => {
|
||||
btn.addEventListener("click", () => {
|
||||
const row = btn.closest("tr");
|
||||
|
||||
// Alle Zeilen sperren
|
||||
document.querySelectorAll("tr").forEach(r => {
|
||||
r.querySelectorAll("input").forEach(i => i.disabled = true);
|
||||
const save = r.querySelector(".save-btn");
|
||||
if (save) save.disabled = true;
|
||||
});
|
||||
|
||||
// Aktuelle Zeile entsperren
|
||||
row.querySelectorAll("input").forEach(i => i.disabled = false);
|
||||
row.querySelector(".save-btn").disabled = false;
|
||||
|
||||
// Button ändern
|
||||
btn.textContent = "🔒";
|
||||
btn.title = "Bearbeitung gesperrt";
|
||||
|
||||
// Fokus
|
||||
const firstInput = row.querySelector("input");
|
||||
if (firstInput) firstInput.focus();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@ -2,8 +2,14 @@ const express = require("express");
|
||||
const router = express.Router();
|
||||
|
||||
const { requireLogin } = require("../middleware/auth.middleware");
|
||||
const { listMedications } = require("../controllers/medication.controller");
|
||||
const {
|
||||
listMedications,
|
||||
updateMedication
|
||||
} = require("../controllers/medication.controller");
|
||||
|
||||
router.get("/", requireLogin, listMedications);
|
||||
|
||||
// 🆕 UPDATE pro Zeile
|
||||
router.post("/update/:id", requireLogin, updateMedication);
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@ -9,9 +9,11 @@ const {
|
||||
updateServicePrice,
|
||||
toggleService,
|
||||
listOpenServices,
|
||||
showServiceLogs
|
||||
showServiceLogs,
|
||||
listServicesAdmin
|
||||
} = require("../controllers/service.controller");
|
||||
|
||||
router.get("/", requireLogin, listServicesAdmin);
|
||||
router.get("/", requireAdmin, listServices);
|
||||
router.get("/create", requireAdmin, showCreateService);
|
||||
router.post("/create", requireAdmin, createService);
|
||||
|
||||
@ -7,11 +7,25 @@
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<nav class="navbar navbar-dark bg-dark px-3">
|
||||
<span class="navbar-brand">📜 Service-Änderungsprotokoll</span>
|
||||
<a href="/dashboard" class="btn btn-outline-light btn-sm">Dashboard</a>
|
||||
<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">Service-Änderungsprotokoll</span>
|
||||
</div>
|
||||
|
||||
<!-- 🔵 RECHTS: DASHBOARD -->
|
||||
<div class="ms-auto">
|
||||
<a href="/dashboard" class="btn btn-outline-light btn-sm">
|
||||
⬅️ Dashboard
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
|
||||
|
||||
<div class="container mt-4">
|
||||
|
||||
<table class="table table-sm table-bordered">
|
||||
|
||||
@ -6,18 +6,30 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!-- Bootstrap 5 -->
|
||||
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/bootstrap-icons/bootstrap-icons.min.css">
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
|
||||
<!-- NAVBAR -->
|
||||
<nav class="navbar navbar-dark bg-dark px-3">
|
||||
<span class="navbar-brand">User Verwaltung</span>
|
||||
<div>
|
||||
<a href="/dashboard" class="btn btn-outline-light btn-sm me-2">Dashboard</a>
|
||||
<a href="/logout" class="btn btn-outline-danger btn-sm">Logout</a>
|
||||
<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">
|
||||
<i class="bi bi-shield-lock fs-4"></i>
|
||||
<span class="fw-semibold fs-5">User Verwaltung</span>
|
||||
</div>
|
||||
|
||||
<!-- 🔵 RECHTS: DASHBOARD -->
|
||||
<div class="ms-auto">
|
||||
<a href="/dashboard" class="btn btn-outline-primary btn-sm">
|
||||
⬅️ Dashboard
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
|
||||
|
||||
<!-- CONTENT -->
|
||||
<div class="container mt-4">
|
||||
<%- include("partials/flash") %>
|
||||
|
||||
@ -6,14 +6,30 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
<link rel="stylesheet" href="/bootstrap-icons/bootstrap-icons.min.css">
|
||||
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
|
||||
<nav class="navbar navbar-dark bg-dark px-3">
|
||||
<span class="navbar-brand">Dashboard</span>
|
||||
<a href="/logout" class="btn btn-outline-light btn-sm">Logout</a>
|
||||
<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">
|
||||
<i class="bi bi-speedometer2 fs-4"></i>
|
||||
<span class="fw-semibold fs-5">Dashboard</span>
|
||||
</div>
|
||||
|
||||
<!-- 🔴 RECHTS: LOGOUT -->
|
||||
<div class="ms-auto">
|
||||
<a href="/logout" class="btn btn-outline-light btn-sm">
|
||||
Logout
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
|
||||
|
||||
<div class="container-fluid mt-4">
|
||||
|
||||
<!-- Flash Messages -->
|
||||
|
||||
@ -7,9 +7,22 @@
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
|
||||
<nav class="navbar navbar-dark bg-dark px-3">
|
||||
<span class="navbar-brand">Medikamentenübersicht</span>
|
||||
<a href="/dashboard" class="btn btn-outline-light btn-sm">Dashboard</a>
|
||||
<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>
|
||||
|
||||
</nav>
|
||||
|
||||
<div class="container mt-4">
|
||||
@ -27,16 +40,51 @@
|
||||
<th>Packung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% rows.forEach(r => { %>
|
||||
<tr>
|
||||
<td><%= r.medication %></td>
|
||||
<td><%= r.form %></td>
|
||||
<td><%= r.dosage %></td>
|
||||
<td><%= r.package %></td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
</tbody>
|
||||
<tbody>
|
||||
<% rows.forEach(r => { %>
|
||||
<tr>
|
||||
<form method="POST"
|
||||
action="/medications/update/<%= r.id %>">
|
||||
|
||||
<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>
|
||||
|
||||
|
||||
@ -8,7 +8,24 @@
|
||||
<body>
|
||||
|
||||
<div class="container mt-4">
|
||||
<h3>🧾 Offene Leistungen</h3>
|
||||
<div class="position-relative mb-3">
|
||||
|
||||
<!-- 🟢 ZENTRIERTER TITEL -->
|
||||
<div class="position-absolute top-50 start-50 translate-middle
|
||||
d-flex align-items-center gap-2">
|
||||
<span style="font-size:1.4rem;">📄</span>
|
||||
<h3 class="mb-0">Offene Rechnungen</h3>
|
||||
</div>
|
||||
|
||||
<!-- 🔵 RECHTS: DASHBOARD -->
|
||||
<div class="text-end">
|
||||
<a href="/dashboard" class="btn btn-outline-primary btn-sm">
|
||||
⬅️ Dashboard
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<% let currentPatient = null; %>
|
||||
|
||||
@ -39,7 +56,7 @@
|
||||
<div class="border rounded p-2 mb-2 d-flex align-items-center gap-2">
|
||||
|
||||
<strong class="flex-grow-1">
|
||||
<%= r.name_de %>
|
||||
<%= r.name %>
|
||||
</strong>
|
||||
|
||||
<form method="POST"
|
||||
|
||||
@ -219,7 +219,7 @@
|
||||
|
||||
<hr>
|
||||
|
||||
<!-- Heutige Leistungen anzeigen alle-->
|
||||
<!-- Heutige Leistungen anzeigen-->
|
||||
<% if (!todayServices || todayServices.length === 0) { %>
|
||||
<p class="text-muted">
|
||||
Noch keine Leistungen für heute erfasst.
|
||||
|
||||
@ -8,10 +8,23 @@
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
|
||||
<nav class="navbar navbar-dark bg-dark px-3">
|
||||
<span class="navbar-brand">Patientenübersicht</span>
|
||||
<a href="/dashboard" class="btn btn-outline-light btn-sm">Dashboard</a>
|
||||
</nav>
|
||||
<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>
|
||||
|
||||
<!-- 🔵 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") %>
|
||||
@ -136,77 +149,98 @@
|
||||
<td><%= new Date(p.updated_at).toLocaleString("de-DE") %></td>
|
||||
|
||||
<!-- AKTIONEN -->
|
||||
<td>
|
||||
<!-- 🔘 OBERE AKTIONEN -->
|
||||
<div class="d-flex flex-wrap gap-1 mb-2">
|
||||
<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) { %>
|
||||
<button class="btn btn-sm btn-secondary" disabled>
|
||||
🪑 Wartet
|
||||
</button>
|
||||
<li>
|
||||
<span class="dropdown-item text-muted">
|
||||
🪑 Wartet bereits
|
||||
</span>
|
||||
</li>
|
||||
<% } else { %>
|
||||
<li>
|
||||
<form method="POST"
|
||||
action="/patients/waiting-room/<%= p.id %>"
|
||||
class="d-inline">
|
||||
<button class="btn btn-sm btn-outline-primary">
|
||||
🪑 Wartezimmer
|
||||
action="/patients/waiting-room/<%= p.id %>">
|
||||
<button class="dropdown-item">
|
||||
🪑 Ins Wartezimmer
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
<% } %>
|
||||
|
||||
<!-- ✏️ BEARBEITEN -->
|
||||
<a href="/patients/edit/<%= p.id %>"
|
||||
class="btn btn-sm btn-info">
|
||||
✏️ Bearbeiten
|
||||
</a>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
|
||||
<!-- 💊 MEDIKAMENTE -->
|
||||
<a href="/patients/<%= p.id %>/medications"
|
||||
class="btn btn-sm btn-outline-primary">
|
||||
<li>
|
||||
<a class="dropdown-item"
|
||||
href="/patients/<%= p.id %>/medications">
|
||||
💊 Medikamente
|
||||
</a>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!-- 🔒 AKTIV / INAKTIV -->
|
||||
<% if (p.active) { %>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
|
||||
<!-- 🔒 STATUS -->
|
||||
<li>
|
||||
<% if (p.active) { %>
|
||||
<form method="POST"
|
||||
action="/patients/deactivate/<%= p.id %>"
|
||||
class="d-inline">
|
||||
<button class="btn btn-sm btn-warning">
|
||||
Sperren
|
||||
action="/patients/deactivate/<%= p.id %>">
|
||||
<button class="dropdown-item text-warning">
|
||||
🔒 Sperren
|
||||
</button>
|
||||
</form>
|
||||
<% } else { %>
|
||||
<% } else { %>
|
||||
<form method="POST"
|
||||
action="/patients/activate/<%= p.id %>"
|
||||
class="d-inline">
|
||||
<button class="btn btn-sm btn-danger">
|
||||
Entsperren
|
||||
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>
|
||||
|
||||
<!-- 📎 DATEI-UPLOAD (UNTEN) -->
|
||||
<form method="POST"
|
||||
action="/patients/<%= p.id %>/files"
|
||||
enctype="multipart/form-data"
|
||||
class="d-flex gap-1">
|
||||
|
||||
<input type="file"
|
||||
name="file"
|
||||
required
|
||||
class="form-control form-control-sm"
|
||||
style="max-width:220px">
|
||||
|
||||
<button class="btn btn-sm btn-secondary">
|
||||
📎 Datei hochladen
|
||||
</button>
|
||||
</form>
|
||||
|
||||
</td>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
|
||||
@ -218,6 +252,6 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -4,105 +4,161 @@
|
||||
<meta charset="UTF-8">
|
||||
<title>Leistungen</title>
|
||||
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
||||
<script src="/js/services-lock.js"></script> ✔ erlaubt
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<nav class="navbar navbar-dark bg-dark px-3">
|
||||
<span class="navbar-brand">🧾 Leistungen</span>
|
||||
<a href="/dashboard" class="btn btn-outline-light btn-sm">Dashboard</a>
|
||||
</nav>
|
||||
<!-- NAVBAR -->
|
||||
<nav class="navbar navbar-dark bg-dark position-relative px-3">
|
||||
|
||||
<div class="container mt-4">
|
||||
|
||||
<h4>Leistungen</h4>
|
||||
|
||||
<form method="GET" action="/services" class="row g-2 mb-3">
|
||||
|
||||
<div class="col-md-6">
|
||||
<input type="text"
|
||||
name="q"
|
||||
class="form-control"
|
||||
placeholder="🔍 Suche nach Name oder Kategorie"
|
||||
value="<%= query?.q || '' %>">
|
||||
<!-- 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">Leistungen</span>
|
||||
</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 Leistungen
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3 d-flex gap-2">
|
||||
<button class="btn btn-primary w-100">
|
||||
Suchen
|
||||
</button>
|
||||
<a href="/services" class="btn btn-secondary w-100">
|
||||
Reset
|
||||
<!-- DASHBOARD -->
|
||||
<div class="ms-auto">
|
||||
<a href="/dashboard" class="btn btn-outline-light btn-sm">
|
||||
⬅️ Dashboard
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</nav>
|
||||
|
||||
<a href="/services/create" class="btn btn-success mb-3">
|
||||
➕ Neue Leistung
|
||||
</a>
|
||||
<!-- CONTENT -->
|
||||
<div class="container mt-4">
|
||||
|
||||
<table class="table table-bordered table-sm align-middle">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Bezeichnung (DE)</th>
|
||||
<th>Bezeichnung (ES)</th>
|
||||
<th>Preis</th>
|
||||
<th>Preis C70</th>
|
||||
<th>Status</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<h4>Leistungen</h4>
|
||||
|
||||
<% services.forEach(s => { %>
|
||||
<tr class="<%= s.active ? '' : 'table-secondary' %>">
|
||||
<td><%= s.name %></td>
|
||||
<!-- SUCHFORMULAR -->
|
||||
<form method="GET" action="/services" class="row g-2 mb-3">
|
||||
|
||||
<form method="POST" action="/services/<%= s.id %>/update-price">
|
||||
<td>
|
||||
<input name="price"
|
||||
value="<%= s.price %>"
|
||||
class="form-control form-control-sm">
|
||||
</td>
|
||||
<td>
|
||||
<input name="price_c70"
|
||||
value="<%= s.price_c70 %>"
|
||||
class="form-control form-control-sm">
|
||||
</td>
|
||||
<td>
|
||||
<%= s.active ? 'Aktiv' : 'Inaktiv' %>
|
||||
</td>
|
||||
<td class="d-flex gap-1">
|
||||
<button class="btn btn-sm btn-primary">
|
||||
💾 Speichern
|
||||
</button>
|
||||
</form>
|
||||
<div class="col-md-6">
|
||||
<input type="text"
|
||||
name="q"
|
||||
class="form-control"
|
||||
placeholder="🔍 Suche nach Name oder Kategorie"
|
||||
value="<%= query?.q || '' %>">
|
||||
</div>
|
||||
|
||||
<form method="POST" action="/services/<%= s.id %>/toggle">
|
||||
<button class="btn btn-sm btn-outline-warning">
|
||||
🔄 Aktiv/Inaktiv
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
<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 Leistungen
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="col-md-3 d-flex gap-2">
|
||||
<button class="btn btn-primary w-100">
|
||||
Suchen
|
||||
</button>
|
||||
<a href="/services" class="btn btn-secondary w-100">
|
||||
Reset
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<!-- NEUE LEISTUNG -->
|
||||
<a href="/services/create" class="btn btn-success mb-3">
|
||||
➕ Neue Leistung
|
||||
</a>
|
||||
|
||||
<!-- TABELLE -->
|
||||
<table class="table table-bordered table-sm align-middle">
|
||||
|
||||
<!-- FIXE SPALTENBREITEN -->
|
||||
<colgroup>
|
||||
<col style="width:35%">
|
||||
<col style="width:25%">
|
||||
<col style="width:10%">
|
||||
<col style="width:10%">
|
||||
<col style="width:8%">
|
||||
<col style="width:12%">
|
||||
</colgroup>
|
||||
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Bezeichnung (DE)</th>
|
||||
<th>Bezeichnung (ES)</th>
|
||||
<th>Preis</th>
|
||||
<th>Preis C70</th>
|
||||
<th>Status</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<% services.forEach(s => { %>
|
||||
<tr class="<%= s.active ? '' : 'table-secondary' %>">
|
||||
|
||||
<!-- DE -->
|
||||
<td><%= s.name_de %></td>
|
||||
|
||||
<!-- ES -->
|
||||
<td><%= s.name_es || "-" %></td>
|
||||
|
||||
<!-- FORM BEGINNT -->
|
||||
<form method="POST" action="/services/<%= s.id %>/update-price">
|
||||
|
||||
<!-- PREIS -->
|
||||
<td>
|
||||
<input name="price"
|
||||
value="<%= s.price %>"
|
||||
class="form-control form-control-sm text-end w-100"
|
||||
disabled>
|
||||
</td>
|
||||
|
||||
<!-- PREIS C70 -->
|
||||
<td>
|
||||
<input name="price_c70"
|
||||
value="<%= s.price_c70 %>"
|
||||
class="form-control form-control-sm text-end w-100"
|
||||
disabled>
|
||||
</td>
|
||||
|
||||
<!-- STATUS -->
|
||||
<td class="text-center">
|
||||
<%= s.active ? 'Aktiv' : 'Inaktiv' %>
|
||||
</td>
|
||||
|
||||
<!-- AKTIONEN -->
|
||||
<td class="d-flex justify-content-center gap-2">
|
||||
|
||||
<!-- SPEICHERN -->
|
||||
<button type="submit"
|
||||
class="btn btn-sm btn-primary save-btn"
|
||||
disabled>
|
||||
💾
|
||||
</button>
|
||||
|
||||
<!-- SPERREN / ENTSPERREN -->
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-outline-warning lock-btn"
|
||||
title="Bearbeiten freigeben">
|
||||
🔓
|
||||
</button>
|
||||
|
||||
</td>
|
||||
|
||||
</form>
|
||||
|
||||
</tr>
|
||||
<% }) %>
|
||||
</tbody>
|
||||
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -4,14 +4,29 @@
|
||||
<meta charset="UTF-8">
|
||||
<title>Wartezimmer</title>
|
||||
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/bootstrap-icons/bootstrap-icons.min.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<nav class="navbar navbar-dark bg-dark px-3">
|
||||
<span class="navbar-brand">🪑 Wartezimmer</span>
|
||||
<a href="/dashboard" class="btn btn-outline-light btn-sm">Dashboard</a>
|
||||
<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">Wartezimmer</span>
|
||||
</div>
|
||||
|
||||
<!-- 🔵 RECHTS: DASHBOARD -->
|
||||
<div class="ms-auto">
|
||||
<a href="/dashboard" class="btn btn-outline-primary btn-sm">
|
||||
⬅️ Dashboard
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
|
||||
|
||||
<div class="container mt-4">
|
||||
|
||||
<!-- ✅ EINMAL Flash anzeigen -->
|
||||
|
||||
Loading…
Reference in New Issue
Block a user