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("/medications", medicationRoutes);
|
||||||
app.use("/patients", patientMedicationRoutes);
|
app.use("/patients", patientMedicationRoutes);
|
||||||
|
|
||||||
|
|
||||||
// ===============================
|
// ===============================
|
||||||
// PATIENT INS WARTEZIMMER
|
// PATIENT INS WARTEZIMMER
|
||||||
// ===============================
|
// ===============================
|
||||||
|
|||||||
@ -22,13 +22,19 @@ async function createInvoicePdf(req, res) {
|
|||||||
const [rows] = await db.promise().query(`
|
const [rows] = await db.promise().query(`
|
||||||
SELECT
|
SELECT
|
||||||
ps.quantity,
|
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
|
FROM patient_services ps
|
||||||
JOIN services s ON ps.service_id = s.id
|
JOIN services s ON ps.service_id = s.id
|
||||||
WHERE ps.patient_id = ?
|
WHERE ps.patient_id = ?
|
||||||
AND ps.invoice_id IS NULL
|
AND ps.invoice_id IS NULL
|
||||||
`, [patientId]);
|
`, [patient.country, patientId]);
|
||||||
|
|
||||||
if (rows.length === 0) {
|
if (rows.length === 0) {
|
||||||
return res.send("Keine Leistungen vorhanden");
|
return res.send("Keine Leistungen vorhanden");
|
||||||
@ -36,7 +42,7 @@ async function createInvoicePdf(req, res) {
|
|||||||
|
|
||||||
const services = rows.map(s => ({
|
const services = rows.map(s => ({
|
||||||
quantity: Number(s.quantity),
|
quantity: Number(s.quantity),
|
||||||
name_de: s.name,
|
name: s.name,
|
||||||
price: Number(s.price),
|
price: Number(s.price),
|
||||||
total: Number(s.price) * Number(s.quantity)
|
total: Number(s.price) * Number(s.quantity)
|
||||||
}));
|
}));
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
const db = require("../db");
|
const db = require("../db");
|
||||||
|
|
||||||
function listMedications(req, res) {
|
// 📋 LISTE
|
||||||
|
function listMedications(req, res, next) {
|
||||||
const sql = `
|
const sql = `
|
||||||
SELECT
|
SELECT
|
||||||
|
v.id,
|
||||||
m.name AS medication,
|
m.name AS medication,
|
||||||
f.name AS form,
|
f.name AS form,
|
||||||
v.dosage,
|
v.dosage,
|
||||||
@ -14,9 +16,38 @@ function listMedications(req, res) {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
db.query(sql, (err, rows) => {
|
db.query(sql, (err, rows) => {
|
||||||
if (err) return res.send("Datenbankfehler");
|
if (err) return next(err);
|
||||||
res.render("medications", { rows });
|
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ function listServices(req, res) {
|
|||||||
let sql = `
|
let sql = `
|
||||||
SELECT id, ${serviceNameField} AS name, category, price, active
|
SELECT id, ${serviceNameField} AS name, category, price, active
|
||||||
FROM services
|
FROM services
|
||||||
WHERE 1=1
|
WHERE 1=1
|
||||||
`;
|
`;
|
||||||
const params = [];
|
const params = [];
|
||||||
|
|
||||||
@ -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) {
|
function showCreateService(req, res) {
|
||||||
res.render("service_create", {
|
res.render("service_create", {
|
||||||
@ -184,15 +228,26 @@ function listOpenServices(req, res, next) {
|
|||||||
p.id AS patient_id,
|
p.id AS patient_id,
|
||||||
p.firstname,
|
p.firstname,
|
||||||
p.lastname,
|
p.lastname,
|
||||||
|
p.country,
|
||||||
ps.id AS patient_service_id,
|
ps.id AS patient_service_id,
|
||||||
ps.quantity,
|
ps.quantity,
|
||||||
COALESCE(ps.price_override, s.price) AS price,
|
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
|
FROM patient_services ps
|
||||||
JOIN patients p ON ps.patient_id = p.id
|
JOIN patients p ON ps.patient_id = p.id
|
||||||
JOIN services s ON ps.service_id = s.id
|
JOIN services s ON ps.service_id = s.id
|
||||||
WHERE ps.invoice_id IS NULL
|
WHERE ps.invoice_id IS NULL
|
||||||
ORDER BY p.lastname, p.firstname
|
ORDER BY
|
||||||
|
p.lastname,
|
||||||
|
p.firstname,
|
||||||
|
name
|
||||||
`;
|
`;
|
||||||
|
|
||||||
db.query(sql, (err, rows) => {
|
db.query(sql, (err, rows) => {
|
||||||
@ -206,6 +261,7 @@ function listOpenServices(req, res, next) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function showServiceLogs(req, res) {
|
function showServiceLogs(req, res) {
|
||||||
db.query(
|
db.query(
|
||||||
`
|
`
|
||||||
@ -238,5 +294,6 @@ module.exports = {
|
|||||||
updateServicePrice,
|
updateServicePrice,
|
||||||
toggleService,
|
toggleService,
|
||||||
listOpenServices,
|
listOpenServices,
|
||||||
showServiceLogs
|
showServiceLogs,
|
||||||
|
listServicesAdmin
|
||||||
};
|
};
|
||||||
|
|||||||
17
package-lock.json
generated
17
package-lock.json
generated
@ -10,6 +10,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bcrypt": "^6.0.0",
|
"bcrypt": "^6.0.0",
|
||||||
"bootstrap": "^5.3.8",
|
"bootstrap": "^5.3.8",
|
||||||
|
"bootstrap-icons": "^1.13.1",
|
||||||
"docxtemplater": "^3.67.6",
|
"docxtemplater": "^3.67.6",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
"ejs": "^3.1.10",
|
"ejs": "^3.1.10",
|
||||||
@ -1951,6 +1952,22 @@
|
|||||||
"@popperjs/core": "^2.11.8"
|
"@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": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bcrypt": "^6.0.0",
|
"bcrypt": "^6.0.0",
|
||||||
"bootstrap": "^5.3.8",
|
"bootstrap": "^5.3.8",
|
||||||
|
"bootstrap-icons": "^1.13.1",
|
||||||
"docxtemplater": "^3.67.6",
|
"docxtemplater": "^3.67.6",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
"ejs": "^3.1.10",
|
"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 router = express.Router();
|
||||||
|
|
||||||
const { requireLogin } = require("../middleware/auth.middleware");
|
const { requireLogin } = require("../middleware/auth.middleware");
|
||||||
const { listMedications } = require("../controllers/medication.controller");
|
const {
|
||||||
|
listMedications,
|
||||||
|
updateMedication
|
||||||
|
} = require("../controllers/medication.controller");
|
||||||
|
|
||||||
router.get("/", requireLogin, listMedications);
|
router.get("/", requireLogin, listMedications);
|
||||||
|
|
||||||
|
// 🆕 UPDATE pro Zeile
|
||||||
|
router.post("/update/:id", requireLogin, updateMedication);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@ -9,9 +9,11 @@ const {
|
|||||||
updateServicePrice,
|
updateServicePrice,
|
||||||
toggleService,
|
toggleService,
|
||||||
listOpenServices,
|
listOpenServices,
|
||||||
showServiceLogs
|
showServiceLogs,
|
||||||
|
listServicesAdmin
|
||||||
} = require("../controllers/service.controller");
|
} = require("../controllers/service.controller");
|
||||||
|
|
||||||
|
router.get("/", requireLogin, listServicesAdmin);
|
||||||
router.get("/", requireAdmin, listServices);
|
router.get("/", requireAdmin, listServices);
|
||||||
router.get("/create", requireAdmin, showCreateService);
|
router.get("/create", requireAdmin, showCreateService);
|
||||||
router.post("/create", requireAdmin, createService);
|
router.post("/create", requireAdmin, createService);
|
||||||
|
|||||||
@ -7,11 +7,25 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<nav class="navbar navbar-dark bg-dark px-3">
|
<nav class="navbar navbar-dark bg-dark position-relative px-3">
|
||||||
<span class="navbar-brand">📜 Service-Änderungsprotokoll</span>
|
|
||||||
<a href="/dashboard" class="btn btn-outline-light btn-sm">Dashboard</a>
|
<!-- 🟢 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>
|
</nav>
|
||||||
|
|
||||||
|
|
||||||
<div class="container mt-4">
|
<div class="container mt-4">
|
||||||
|
|
||||||
<table class="table table-sm table-bordered">
|
<table class="table table-sm table-bordered">
|
||||||
|
|||||||
@ -6,18 +6,30 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<!-- Bootstrap 5 -->
|
<!-- Bootstrap 5 -->
|
||||||
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="/bootstrap-icons/bootstrap-icons.min.css">
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-light">
|
<body class="bg-light">
|
||||||
|
|
||||||
<!-- NAVBAR -->
|
<!-- NAVBAR -->
|
||||||
<nav class="navbar navbar-dark bg-dark px-3">
|
<nav class="navbar navbar-dark bg-dark position-relative px-3">
|
||||||
<span class="navbar-brand">User Verwaltung</span>
|
|
||||||
<div>
|
<!-- 🟢 ZENTRIERTER TITEL -->
|
||||||
<a href="/dashboard" class="btn btn-outline-light btn-sm me-2">Dashboard</a>
|
<div class="position-absolute top-50 start-50 translate-middle
|
||||||
<a href="/logout" class="btn btn-outline-danger btn-sm">Logout</a>
|
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>
|
</div>
|
||||||
|
|
||||||
|
<!-- 🔵 RECHTS: DASHBOARD -->
|
||||||
|
<div class="ms-auto">
|
||||||
|
<a href="/dashboard" class="btn btn-outline-primary btn-sm">
|
||||||
|
⬅️ Dashboard
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|
||||||
<!-- CONTENT -->
|
<!-- CONTENT -->
|
||||||
<div class="container mt-4">
|
<div class="container mt-4">
|
||||||
<%- include("partials/flash") %>
|
<%- include("partials/flash") %>
|
||||||
|
|||||||
@ -6,14 +6,30 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
||||||
<link rel="stylesheet" href="/css/style.css">
|
<link rel="stylesheet" href="/css/style.css">
|
||||||
|
<link rel="stylesheet" href="/bootstrap-icons/bootstrap-icons.min.css">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-light">
|
<body class="bg-light">
|
||||||
|
|
||||||
<nav class="navbar navbar-dark bg-dark px-3">
|
<nav class="navbar navbar-dark bg-dark position-relative px-3">
|
||||||
<span class="navbar-brand">Dashboard</span>
|
|
||||||
<a href="/logout" class="btn btn-outline-light btn-sm">Logout</a>
|
<!-- 🟢 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>
|
</nav>
|
||||||
|
|
||||||
|
|
||||||
<div class="container-fluid mt-4">
|
<div class="container-fluid mt-4">
|
||||||
|
|
||||||
<!-- Flash Messages -->
|
<!-- Flash Messages -->
|
||||||
|
|||||||
@ -7,9 +7,22 @@
|
|||||||
</head>
|
</head>
|
||||||
<body class="bg-light">
|
<body class="bg-light">
|
||||||
|
|
||||||
<nav class="navbar navbar-dark bg-dark px-3">
|
<nav class="navbar navbar-dark bg-dark position-relative px-3">
|
||||||
<span class="navbar-brand">Medikamentenübersicht</span>
|
|
||||||
<a href="/dashboard" class="btn btn-outline-light btn-sm">Dashboard</a>
|
<!-- 🟢 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>
|
</nav>
|
||||||
|
|
||||||
<div class="container mt-4">
|
<div class="container mt-4">
|
||||||
@ -27,16 +40,51 @@
|
|||||||
<th>Packung</th>
|
<th>Packung</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<% rows.forEach(r => { %>
|
<% rows.forEach(r => { %>
|
||||||
<tr>
|
<tr>
|
||||||
<td><%= r.medication %></td>
|
<form method="POST"
|
||||||
<td><%= r.form %></td>
|
action="/medications/update/<%= r.id %>">
|
||||||
<td><%= r.dosage %></td>
|
|
||||||
<td><%= r.package %></td>
|
<td>
|
||||||
</tr>
|
<input type="text"
|
||||||
<% }) %>
|
name="medication"
|
||||||
</tbody>
|
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>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,24 @@
|
|||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="container mt-4">
|
<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; %>
|
<% let currentPatient = null; %>
|
||||||
|
|
||||||
@ -39,7 +56,7 @@
|
|||||||
<div class="border rounded p-2 mb-2 d-flex align-items-center gap-2">
|
<div class="border rounded p-2 mb-2 d-flex align-items-center gap-2">
|
||||||
|
|
||||||
<strong class="flex-grow-1">
|
<strong class="flex-grow-1">
|
||||||
<%= r.name_de %>
|
<%= r.name %>
|
||||||
</strong>
|
</strong>
|
||||||
|
|
||||||
<form method="POST"
|
<form method="POST"
|
||||||
|
|||||||
@ -219,7 +219,7 @@
|
|||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<!-- Heutige Leistungen anzeigen alle-->
|
<!-- Heutige Leistungen anzeigen-->
|
||||||
<% if (!todayServices || todayServices.length === 0) { %>
|
<% if (!todayServices || todayServices.length === 0) { %>
|
||||||
<p class="text-muted">
|
<p class="text-muted">
|
||||||
Noch keine Leistungen für heute erfasst.
|
Noch keine Leistungen für heute erfasst.
|
||||||
|
|||||||
@ -8,10 +8,23 @@
|
|||||||
</head>
|
</head>
|
||||||
<body class="bg-light">
|
<body class="bg-light">
|
||||||
|
|
||||||
<nav class="navbar navbar-dark bg-dark px-3">
|
<nav class="navbar navbar-dark bg-dark position-relative px-3">
|
||||||
<span class="navbar-brand">Patientenübersicht</span>
|
|
||||||
<a href="/dashboard" class="btn btn-outline-light btn-sm">Dashboard</a>
|
<!-- 🟢 ZENTRIERTER TITEL -->
|
||||||
</nav>
|
<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">
|
<div class="container-fluid mt-4">
|
||||||
<%- include("partials/flash") %>
|
<%- include("partials/flash") %>
|
||||||
@ -136,77 +149,98 @@
|
|||||||
<td><%= new Date(p.updated_at).toLocaleString("de-DE") %></td>
|
<td><%= new Date(p.updated_at).toLocaleString("de-DE") %></td>
|
||||||
|
|
||||||
<!-- AKTIONEN -->
|
<!-- AKTIONEN -->
|
||||||
<td>
|
<td class="text-nowrap">
|
||||||
<!-- 🔘 OBERE AKTIONEN -->
|
|
||||||
<div class="d-flex flex-wrap gap-1 mb-2">
|
<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 -->
|
<!-- 🪑 WARTEZIMMER -->
|
||||||
<% if (p.waiting_room) { %>
|
<% if (p.waiting_room) { %>
|
||||||
<button class="btn btn-sm btn-secondary" disabled>
|
<li>
|
||||||
🪑 Wartet
|
<span class="dropdown-item text-muted">
|
||||||
</button>
|
🪑 Wartet bereits
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
|
<li>
|
||||||
<form method="POST"
|
<form method="POST"
|
||||||
action="/patients/waiting-room/<%= p.id %>"
|
action="/patients/waiting-room/<%= p.id %>">
|
||||||
class="d-inline">
|
<button class="dropdown-item">
|
||||||
<button class="btn btn-sm btn-outline-primary">
|
🪑 Ins Wartezimmer
|
||||||
🪑 Wartezimmer
|
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
</li>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<!-- ✏️ BEARBEITEN -->
|
<li><hr class="dropdown-divider"></li>
|
||||||
<a href="/patients/edit/<%= p.id %>"
|
|
||||||
class="btn btn-sm btn-info">
|
|
||||||
✏️ Bearbeiten
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<!-- 💊 MEDIKAMENTE -->
|
<!-- 💊 MEDIKAMENTE -->
|
||||||
<a href="/patients/<%= p.id %>/medications"
|
<li>
|
||||||
class="btn btn-sm btn-outline-primary">
|
<a class="dropdown-item"
|
||||||
|
href="/patients/<%= p.id %>/medications">
|
||||||
💊 Medikamente
|
💊 Medikamente
|
||||||
</a>
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
<!-- 🔒 AKTIV / INAKTIV -->
|
<li><hr class="dropdown-divider"></li>
|
||||||
<% if (p.active) { %>
|
|
||||||
|
<!-- 🔒 STATUS -->
|
||||||
|
<li>
|
||||||
|
<% if (p.active) { %>
|
||||||
<form method="POST"
|
<form method="POST"
|
||||||
action="/patients/deactivate/<%= p.id %>"
|
action="/patients/deactivate/<%= p.id %>">
|
||||||
class="d-inline">
|
<button class="dropdown-item text-warning">
|
||||||
<button class="btn btn-sm btn-warning">
|
🔒 Sperren
|
||||||
Sperren
|
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<form method="POST"
|
<form method="POST"
|
||||||
action="/patients/activate/<%= p.id %>"
|
action="/patients/activate/<%= p.id %>">
|
||||||
class="d-inline">
|
<button class="dropdown-item text-success">
|
||||||
<button class="btn btn-sm btn-danger">
|
🔓 Entsperren
|
||||||
Entsperren
|
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</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>
|
</div>
|
||||||
|
|
||||||
<!-- 📎 DATEI-UPLOAD (UNTEN) -->
|
</td>
|
||||||
<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>
|
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
<% }) %>
|
<% }) %>
|
||||||
|
|
||||||
@ -218,6 +252,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<script src="/js/bootstrap.bundle.min.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -4,105 +4,161 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Leistungen</title>
|
<title>Leistungen</title>
|
||||||
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
||||||
|
<script src="/js/services-lock.js"></script> ✔ erlaubt
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<nav class="navbar navbar-dark bg-dark px-3">
|
<!-- NAVBAR -->
|
||||||
<span class="navbar-brand">🧾 Leistungen</span>
|
<nav class="navbar navbar-dark bg-dark position-relative px-3">
|
||||||
<a href="/dashboard" class="btn btn-outline-light btn-sm">Dashboard</a>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="container mt-4">
|
<!-- ZENTRIERTER TITEL -->
|
||||||
|
<div class="position-absolute top-50 start-50 translate-middle
|
||||||
<h4>Leistungen</h4>
|
d-flex align-items-center gap-2 text-white">
|
||||||
|
<span style="font-size:1.3rem;">🧾</span>
|
||||||
<form method="GET" action="/services" class="row g-2 mb-3">
|
<span class="fw-semibold fs-5">Leistungen</span>
|
||||||
|
|
||||||
<div class="col-md-6">
|
|
||||||
<input type="text"
|
|
||||||
name="q"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="🔍 Suche nach Name oder Kategorie"
|
|
||||||
value="<%= query?.q || '' %>">
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-3 d-flex align-items-center">
|
<!-- DASHBOARD -->
|
||||||
<div class="form-check">
|
<div class="ms-auto">
|
||||||
<input class="form-check-input"
|
<a href="/dashboard" class="btn btn-outline-light btn-sm">
|
||||||
type="checkbox"
|
⬅️ Dashboard
|
||||||
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
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</nav>
|
||||||
|
|
||||||
<a href="/services/create" class="btn btn-success mb-3">
|
<!-- CONTENT -->
|
||||||
➕ Neue Leistung
|
<div class="container mt-4">
|
||||||
</a>
|
|
||||||
|
|
||||||
<table class="table table-bordered table-sm align-middle">
|
<h4>Leistungen</h4>
|
||||||
<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 => { %>
|
<!-- SUCHFORMULAR -->
|
||||||
<tr class="<%= s.active ? '' : 'table-secondary' %>">
|
<form method="GET" action="/services" class="row g-2 mb-3">
|
||||||
<td><%= s.name %></td>
|
|
||||||
|
|
||||||
<form method="POST" action="/services/<%= s.id %>/update-price">
|
<div class="col-md-6">
|
||||||
<td>
|
<input type="text"
|
||||||
<input name="price"
|
name="q"
|
||||||
value="<%= s.price %>"
|
class="form-control"
|
||||||
class="form-control form-control-sm">
|
placeholder="🔍 Suche nach Name oder Kategorie"
|
||||||
</td>
|
value="<%= query?.q || '' %>">
|
||||||
<td>
|
</div>
|
||||||
<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>
|
|
||||||
|
|
||||||
<form method="POST" action="/services/<%= s.id %>/toggle">
|
<div class="col-md-3 d-flex align-items-center">
|
||||||
<button class="btn btn-sm btn-outline-warning">
|
<div class="form-check">
|
||||||
🔄 Aktiv/Inaktiv
|
<input class="form-check-input"
|
||||||
</button>
|
type="checkbox"
|
||||||
</form>
|
name="onlyActive"
|
||||||
</td>
|
value="1"
|
||||||
</tr>
|
<%= query?.onlyActive === "1" ? "checked" : "" %>>
|
||||||
<% }) %>
|
<label class="form-check-label">
|
||||||
|
Nur aktive Leistungen
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</tbody>
|
<div class="col-md-3 d-flex gap-2">
|
||||||
</table>
|
<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>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -4,14 +4,29 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Wartezimmer</title>
|
<title>Wartezimmer</title>
|
||||||
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="/bootstrap-icons/bootstrap-icons.min.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<nav class="navbar navbar-dark bg-dark px-3">
|
<nav class="navbar navbar-dark bg-dark position-relative px-3">
|
||||||
<span class="navbar-brand">🪑 Wartezimmer</span>
|
|
||||||
<a href="/dashboard" class="btn btn-outline-light btn-sm">Dashboard</a>
|
<!-- 🟢 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>
|
</nav>
|
||||||
|
|
||||||
|
|
||||||
<div class="container mt-4">
|
<div class="container mt-4">
|
||||||
|
|
||||||
<!-- ✅ EINMAL Flash anzeigen -->
|
<!-- ✅ EINMAL Flash anzeigen -->
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user