Änderung der pausen regelung
This commit is contained in:
@@ -26,6 +26,13 @@ function initDatabase() {
|
|||||||
// Fehler ignorieren wenn Spalte bereits existiert
|
// Fehler ignorieren wenn Spalte bereits existiert
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Migration: default_break_minutes (Standard-Pausenzeit pro Mitarbeiter)
|
||||||
|
db.run(`ALTER TABLE users ADD COLUMN default_break_minutes INTEGER DEFAULT 30`, (err) => {
|
||||||
|
if (err && !err.message.includes('duplicate column')) {
|
||||||
|
console.warn('Warnung beim Hinzufügen der Spalte default_break_minutes:', err.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Stundenerfassung-Tabelle
|
// Stundenerfassung-Tabelle
|
||||||
db.run(`CREATE TABLE IF NOT EXISTS timesheet_entries (
|
db.run(`CREATE TABLE IF NOT EXISTS timesheet_entries (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
|||||||
@@ -1100,6 +1100,11 @@ table input[type="text"] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Pausenfeld: rot nur wenn unter gesetzlicher Mindestpause (Tooltip im HTML) */
|
||||||
|
input.break-below-legal {
|
||||||
|
color: #dc3545;
|
||||||
|
}
|
||||||
|
|
||||||
/* App Footer */
|
/* App Footer */
|
||||||
.app-footer {
|
.app-footer {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultBreakInput = document.getElementById('defaultBreakMinutes');
|
||||||
|
const defaultBreakVal = defaultBreakInput && defaultBreakInput.value !== '' ? parseInt(defaultBreakInput.value, 10) : 30;
|
||||||
|
const default_break_minutes = (!isNaN(defaultBreakVal) && defaultBreakVal >= 0) ? defaultBreakVal : 30;
|
||||||
|
|
||||||
const formData = {
|
const formData = {
|
||||||
username: document.getElementById('username').value,
|
username: document.getElementById('username').value,
|
||||||
password: document.getElementById('password').value,
|
password: document.getElementById('password').value,
|
||||||
@@ -26,7 +30,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
personalnummer: document.getElementById('personalnummer').value,
|
personalnummer: document.getElementById('personalnummer').value,
|
||||||
wochenstunden: document.getElementById('wochenstunden').value,
|
wochenstunden: document.getElementById('wochenstunden').value,
|
||||||
arbeitstage: document.getElementById('arbeitstage').value,
|
arbeitstage: document.getElementById('arbeitstage').value,
|
||||||
urlaubstage: document.getElementById('urlaubstage').value
|
urlaubstage: document.getElementById('urlaubstage').value,
|
||||||
|
default_break_minutes: default_break_minutes
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -318,6 +323,9 @@ async function saveUser(userId) {
|
|||||||
const wochenstunden = row.querySelector('input[data-field="wochenstunden"]').value;
|
const wochenstunden = row.querySelector('input[data-field="wochenstunden"]').value;
|
||||||
const arbeitstage = row.querySelector('input[data-field="arbeitstage"]').value;
|
const arbeitstage = row.querySelector('input[data-field="arbeitstage"]').value;
|
||||||
const urlaubstage = row.querySelector('input[data-field="urlaubstage"]').value;
|
const urlaubstage = row.querySelector('input[data-field="urlaubstage"]').value;
|
||||||
|
const defaultBreakInput = row.querySelector('input[data-field="default_break_minutes"]');
|
||||||
|
const default_break_minutes = defaultBreakInput && defaultBreakInput.value !== '' ? parseInt(defaultBreakInput.value, 10) : 30;
|
||||||
|
const normalizedDefaultBreak = (!isNaN(default_break_minutes) && default_break_minutes >= 0) ? default_break_minutes : 30;
|
||||||
|
|
||||||
// Rollen aus Checkboxen sammeln
|
// Rollen aus Checkboxen sammeln
|
||||||
const roleCheckboxes = row.querySelectorAll('.role-checkbox:checked');
|
const roleCheckboxes = row.querySelectorAll('.role-checkbox:checked');
|
||||||
@@ -340,6 +348,7 @@ async function saveUser(userId) {
|
|||||||
wochenstunden: wochenstunden || null,
|
wochenstunden: wochenstunden || null,
|
||||||
arbeitstage: arbeitstage || 5,
|
arbeitstage: arbeitstage || 5,
|
||||||
urlaubstage: urlaubstage || null,
|
urlaubstage: urlaubstage || null,
|
||||||
|
default_break_minutes: normalizedDefaultBreak,
|
||||||
roles: roles
|
roles: roles
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@@ -351,6 +360,8 @@ async function saveUser(userId) {
|
|||||||
row.querySelector('span[data-field="personalnummer"]').textContent = personalnummer || '-';
|
row.querySelector('span[data-field="personalnummer"]').textContent = personalnummer || '-';
|
||||||
row.querySelector('span[data-field="wochenstunden"]').textContent = wochenstunden || '-';
|
row.querySelector('span[data-field="wochenstunden"]').textContent = wochenstunden || '-';
|
||||||
row.querySelector('span[data-field="urlaubstage"]').textContent = urlaubstage || '-';
|
row.querySelector('span[data-field="urlaubstage"]').textContent = urlaubstage || '-';
|
||||||
|
const defaultBreakDisplay = row.querySelector('span[data-field="default_break_minutes"]');
|
||||||
|
if (defaultBreakDisplay) defaultBreakDisplay.textContent = normalizedDefaultBreak;
|
||||||
|
|
||||||
// Rollen-Display aktualisieren
|
// Rollen-Display aktualisieren
|
||||||
const rolesDisplay = row.querySelector('div[data-field="roles"]');
|
const rolesDisplay = row.querySelector('div[data-field="roles"]');
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ let currentHolidayDates = new Set(); // Feiertage der aktuellen Woche (YYYY-MM-D
|
|||||||
let userWochenstunden = 0; // Wochenstunden des Users
|
let userWochenstunden = 0; // Wochenstunden des Users
|
||||||
let userArbeitstage = 5; // Arbeitstage pro Woche des Users (Standard: 5)
|
let userArbeitstage = 5; // Arbeitstage pro Woche des Users (Standard: 5)
|
||||||
let weekendPercentages = { saturday: 100, sunday: 100 }; // Wochenend-Prozentsätze (100% = normal)
|
let weekendPercentages = { saturday: 100, sunday: 100 }; // Wochenend-Prozentsätze (100% = normal)
|
||||||
|
let defaultBreakMinutes = 30; // Standard-Pausenzeit des Mitarbeiters (Vorbelegung)
|
||||||
let latestSubmittedTimesheetId = null; // ID der neuesten eingereichten Version
|
let latestSubmittedTimesheetId = null; // ID der neuesten eingereichten Version
|
||||||
|
|
||||||
// Wochenend-Prozentsätze laden
|
// Wochenend-Prozentsätze laden
|
||||||
@@ -376,16 +377,18 @@ function getFullDayHours() {
|
|||||||
// Woche laden
|
// Woche laden
|
||||||
async function loadWeek() {
|
async function loadWeek() {
|
||||||
try {
|
try {
|
||||||
// User-Daten laden (Wochenstunden, Arbeitstage)
|
// User-Daten laden (Wochenstunden, Arbeitstage, Standard-Pausenzeit)
|
||||||
try {
|
try {
|
||||||
const userResponse = await fetch('/api/user/data');
|
const userResponse = await fetch('/api/user/data');
|
||||||
const userData = await userResponse.json();
|
const userData = await userResponse.json();
|
||||||
userWochenstunden = userData.wochenstunden || 0;
|
userWochenstunden = userData.wochenstunden || 0;
|
||||||
userArbeitstage = userData.arbeitstage || 5;
|
userArbeitstage = userData.arbeitstage || 5;
|
||||||
|
defaultBreakMinutes = userData.default_break_minutes ?? 30;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('Konnte User-Daten nicht laden:', error);
|
console.warn('Konnte User-Daten nicht laden:', error);
|
||||||
userWochenstunden = 0;
|
userWochenstunden = 0;
|
||||||
userArbeitstage = 5;
|
userArbeitstage = 5;
|
||||||
|
defaultBreakMinutes = 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
const parts = currentWeekStart.split('-');
|
const parts = currentWeekStart.split('-');
|
||||||
@@ -472,7 +475,7 @@ function renderWeek() {
|
|||||||
|
|
||||||
const startTime = entry.start_time || '';
|
const startTime = entry.start_time || '';
|
||||||
const endTime = entry.end_time || '';
|
const endTime = entry.end_time || '';
|
||||||
const breakMinutes = entry.break_minutes || 0;
|
const breakMinutes = (entry.break_minutes != null && entry.break_minutes !== '') ? entry.break_minutes : defaultBreakMinutes;
|
||||||
const hours = entry.total_hours || 0;
|
const hours = entry.total_hours || 0;
|
||||||
const overtimeTaken = entry.overtime_taken_hours || '';
|
const overtimeTaken = entry.overtime_taken_hours || '';
|
||||||
const vacationType = entry.vacation_type || '';
|
const vacationType = entry.vacation_type || '';
|
||||||
@@ -568,24 +571,29 @@ function renderWeek() {
|
|||||||
hoursDisplay = hours.toFixed(2) + ' h';
|
hoursDisplay = hours.toFixed(2) + ' h';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const requiredBreak = (startTime && endTime) ? calculateRequiredBreakMinutes(startTime, endTime) : null;
|
||||||
|
const isBreakBelowLegal = requiredBreak !== null && breakMinutes < requiredBreak;
|
||||||
|
const breakClass = isBreakBelowLegal ? 'break-below-legal' : '';
|
||||||
|
const breakTitle = isBreakBelowLegal ? ' title="Die Pausenzeit liegt unterhalb der gesetzlichen Vorgabe."' : '';
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>${getWeekday(dateStr)}</strong></td>
|
<td><strong>${getWeekday(dateStr)}</strong></td>
|
||||||
<td>${formatDateDE(dateStr)}${isFullDayVacation ? ' <span style="color: #28a745;">(Urlaub - ganzer Tag)</span>' : ''}${isSick ? ' <span style="color: #e74c3c;">(Krank)</span>' : ''}${holidayLabel}</td>
|
<td>${formatDateDE(dateStr)}${isFullDayVacation ? ' <span style="color: #28a745;">(Urlaub - ganzer Tag)</span>' : ''}${isSick ? ' <span style="color: #e74c3c;">(Krank)</span>' : ''}${holidayLabel}</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="time" value="${startTime}"
|
<input type="time" id="start_time_${dateStr}" name="start_time_${dateStr}" value="${startTime}"
|
||||||
data-date="${dateStr}" data-field="start_time"
|
data-date="${dateStr}" data-field="start_time"
|
||||||
step="60"
|
step="60"
|
||||||
${timeFieldsDisabled} ${disabled} oninput="saveEntry(this)" onchange="saveEntry(this)" onblur="saveEntry(this); checkWeekComplete();">
|
${timeFieldsDisabled} ${disabled} oninput="saveEntry(this)" onchange="saveEntry(this)" onblur="saveEntry(this); checkWeekComplete();">
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="time" value="${endTime}"
|
<input type="time" id="end_time_${dateStr}" name="end_time_${dateStr}" value="${endTime}"
|
||||||
data-date="${dateStr}" data-field="end_time"
|
data-date="${dateStr}" data-field="end_time"
|
||||||
step="60"
|
step="60"
|
||||||
${timeFieldsDisabled} ${disabled} oninput="saveEntry(this)" onchange="saveEntry(this)" onblur="saveEntry(this); checkWeekComplete();">
|
${timeFieldsDisabled} ${disabled} oninput="saveEntry(this)" onchange="saveEntry(this)" onblur="saveEntry(this); checkWeekComplete();">
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="number" value="${breakMinutes}" min="0" step="15"
|
<input type="number" id="break_minutes_${dateStr}" name="break_minutes_${dateStr}" value="${breakMinutes}" min="0" step="15" class="${breakClass}"${breakTitle}
|
||||||
data-date="${dateStr}" data-field="break_minutes"
|
data-date="${dateStr}" data-field="break_minutes"
|
||||||
${timeFieldsDisabled} ${disabled} oninput="saveEntry(this)" onchange="saveEntry(this)">
|
${timeFieldsDisabled} ${disabled} oninput="saveEntry(this)" onchange="saveEntry(this)">
|
||||||
</td>
|
</td>
|
||||||
@@ -1087,6 +1095,26 @@ function calculateRequiredBreakMinutes(startTime, endTime) {
|
|||||||
return 0; // Weniger als 6 Stunden: keine gesetzliche Pause erforderlich
|
return 0; // Weniger als 6 Stunden: keine gesetzliche Pause erforderlich
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Aktualisiert die visuelle Kennzeichnung (nur rot + Tooltip wenn unter gesetzlicher Mindestpause)
|
||||||
|
function updateBreakCompliance(dateStr) {
|
||||||
|
const startInput = document.querySelector(`input[data-date="${dateStr}"][data-field="start_time"]`);
|
||||||
|
const endInput = document.querySelector(`input[data-date="${dateStr}"][data-field="end_time"]`);
|
||||||
|
const breakInput = document.querySelector(`input[data-date="${dateStr}"][data-field="break_minutes"]`);
|
||||||
|
if (!breakInput) return;
|
||||||
|
breakInput.classList.remove('break-below-legal');
|
||||||
|
breakInput.removeAttribute('title');
|
||||||
|
const startTime = startInput && startInput.value ? startInput.value.trim() : '';
|
||||||
|
const endTime = endInput && endInput.value ? endInput.value.trim() : '';
|
||||||
|
if (!startTime || !endTime) return;
|
||||||
|
const required = calculateRequiredBreakMinutes(startTime, endTime);
|
||||||
|
if (required === null) return;
|
||||||
|
const breakVal = breakInput.value ? (parseInt(breakInput.value, 10) || 0) : 0;
|
||||||
|
if (breakVal < required) {
|
||||||
|
breakInput.classList.add('break-below-legal');
|
||||||
|
breakInput.setAttribute('title', 'Die Pausenzeit liegt unterhalb der gesetzlichen Vorgabe.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Eintrag speichern
|
// Eintrag speichern
|
||||||
async function saveEntry(input) {
|
async function saveEntry(input) {
|
||||||
const date = input.dataset.date;
|
const date = input.dataset.date;
|
||||||
@@ -1133,19 +1161,6 @@ async function saveEntry(input) {
|
|||||||
const end_time = actualEndTime;
|
const end_time = actualEndTime;
|
||||||
let break_minutes = breakInput && breakInput.value ? (parseInt(breakInput.value) || 0) : (parseInt(currentEntries[date].break_minutes) || 0);
|
let break_minutes = breakInput && breakInput.value ? (parseInt(breakInput.value) || 0) : (parseInt(currentEntries[date].break_minutes) || 0);
|
||||||
|
|
||||||
// Automatische Vorbelegung der Pausenzeiten basierend auf gesetzlichen Vorgaben
|
|
||||||
// Wird ausgelöst, wenn start_time oder end_time geändert werden
|
|
||||||
if ((input.dataset.field === 'start_time' || input.dataset.field === 'end_time') && start_time && end_time) {
|
|
||||||
const requiredBreakMinutes = calculateRequiredBreakMinutes(start_time, end_time);
|
|
||||||
if (requiredBreakMinutes !== null && requiredBreakMinutes > break_minutes) {
|
|
||||||
// Setze den höheren Wert (gesetzliche Mindestpause)
|
|
||||||
break_minutes = requiredBreakMinutes;
|
|
||||||
// Aktualisiere das Input-Feld im DOM
|
|
||||||
if (breakInput) {
|
|
||||||
breakInput.value = break_minutes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const notes = notesInput ? (notesInput.value || '') : (currentEntries[date].notes || '');
|
const notes = notesInput ? (notesInput.value || '') : (currentEntries[date].notes || '');
|
||||||
const vacation_type = vacationSelect && vacationSelect.value ? vacationSelect.value : (currentEntries[date].vacation_type || null);
|
const vacation_type = vacationSelect && vacationSelect.value ? vacationSelect.value : (currentEntries[date].vacation_type || null);
|
||||||
const overtime_taken_hours = overtimeInput && overtimeInput.value ? overtimeInput.value : (currentEntries[date].overtime_taken_hours || null);
|
const overtime_taken_hours = overtimeInput && overtimeInput.value ? overtimeInput.value : (currentEntries[date].overtime_taken_hours || null);
|
||||||
@@ -1490,6 +1505,10 @@ async function saveEntry(input) {
|
|||||||
// Submit-Button Status prüfen (nach jedem Speichern)
|
// Submit-Button Status prüfen (nach jedem Speichern)
|
||||||
checkWeekComplete();
|
checkWeekComplete();
|
||||||
|
|
||||||
|
if (field === 'start_time' || field === 'end_time' || field === 'break_minutes') {
|
||||||
|
updateBreakCompliance(date);
|
||||||
|
}
|
||||||
|
|
||||||
// Visuelles Feedback
|
// Visuelles Feedback
|
||||||
input.style.backgroundColor = '#d4edda';
|
input.style.backgroundColor = '#d4edda';
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const { requireAdmin } = require('../middleware/auth');
|
|||||||
function registerAdminRoutes(app) {
|
function registerAdminRoutes(app) {
|
||||||
// Admin-Bereich
|
// Admin-Bereich
|
||||||
app.get('/admin', requireAdmin, (req, res) => {
|
app.get('/admin', requireAdmin, (req, res) => {
|
||||||
db.all('SELECT id, username, firstname, lastname, role, personalnummer, wochenstunden, urlaubstage, arbeitstage, created_at FROM users ORDER BY created_at DESC',
|
db.all('SELECT id, username, firstname, lastname, role, personalnummer, wochenstunden, urlaubstage, arbeitstage, default_break_minutes, created_at FROM users ORDER BY created_at DESC',
|
||||||
(err, users) => {
|
(err, users) => {
|
||||||
// LDAP-Konfiguration, Sync-Log und Optionen abrufen
|
// LDAP-Konfiguration, Sync-Log und Optionen abrufen
|
||||||
db.get('SELECT * FROM ldap_config WHERE id = 1', (err, ldapConfig) => {
|
db.get('SELECT * FROM ldap_config WHERE id = 1', (err, ldapConfig) => {
|
||||||
@@ -48,7 +48,7 @@ function registerAdminRoutes(app) {
|
|||||||
|
|
||||||
// Benutzer erstellen
|
// Benutzer erstellen
|
||||||
app.post('/admin/users', requireAdmin, (req, res) => {
|
app.post('/admin/users', requireAdmin, (req, res) => {
|
||||||
const { username, password, firstname, lastname, roles, personalnummer, wochenstunden, urlaubstage, arbeitstage } = req.body;
|
const { username, password, firstname, lastname, roles, personalnummer, wochenstunden, urlaubstage, arbeitstage, default_break_minutes } = req.body;
|
||||||
const hashedPassword = bcrypt.hashSync(password, 10);
|
const hashedPassword = bcrypt.hashSync(password, 10);
|
||||||
|
|
||||||
// Normalisiere die optionalen Felder
|
// Normalisiere die optionalen Felder
|
||||||
@@ -56,6 +56,8 @@ function registerAdminRoutes(app) {
|
|||||||
const normalizedWochenstunden = wochenstunden && wochenstunden !== '' ? parseFloat(wochenstunden) : null;
|
const normalizedWochenstunden = wochenstunden && wochenstunden !== '' ? parseFloat(wochenstunden) : null;
|
||||||
const normalizedUrlaubstage = urlaubstage && urlaubstage !== '' ? parseFloat(urlaubstage) : null;
|
const normalizedUrlaubstage = urlaubstage && urlaubstage !== '' ? parseFloat(urlaubstage) : null;
|
||||||
const normalizedArbeitstage = arbeitstage && arbeitstage !== '' ? parseInt(arbeitstage) : 5;
|
const normalizedArbeitstage = arbeitstage && arbeitstage !== '' ? parseInt(arbeitstage) : 5;
|
||||||
|
const parsedBreak = default_break_minutes !== undefined && default_break_minutes !== '' ? parseInt(default_break_minutes, 10) : 30;
|
||||||
|
const normalizedDefaultBreak = (!isNaN(parsedBreak) && parsedBreak >= 0) ? parsedBreak : 30;
|
||||||
|
|
||||||
// Rollen verarbeiten: Erwarte Array, konvertiere zu JSON-String
|
// Rollen verarbeiten: Erwarte Array, konvertiere zu JSON-String
|
||||||
let rolesArray = [];
|
let rolesArray = [];
|
||||||
@@ -73,8 +75,8 @@ function registerAdminRoutes(app) {
|
|||||||
|
|
||||||
const rolesJson = JSON.stringify(rolesArray);
|
const rolesJson = JSON.stringify(rolesArray);
|
||||||
|
|
||||||
db.run('INSERT INTO users (username, password, firstname, lastname, role, personalnummer, wochenstunden, urlaubstage, arbeitstage) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
db.run('INSERT INTO users (username, password, firstname, lastname, role, personalnummer, wochenstunden, urlaubstage, arbeitstage, default_break_minutes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||||
[username, hashedPassword, firstname, lastname, rolesJson, normalizedPersonalnummer, normalizedWochenstunden, normalizedUrlaubstage, normalizedArbeitstage],
|
[username, hashedPassword, firstname, lastname, rolesJson, normalizedPersonalnummer, normalizedWochenstunden, normalizedUrlaubstage, normalizedArbeitstage, normalizedDefaultBreak],
|
||||||
(err) => {
|
(err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return res.status(400).json({ error: 'Benutzername existiert bereits' });
|
return res.status(400).json({ error: 'Benutzername existiert bereits' });
|
||||||
@@ -100,10 +102,13 @@ function registerAdminRoutes(app) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Benutzer aktualisieren (Personalnummer, Wochenstunden, Urlaubstage, Rollen)
|
// Benutzer aktualisieren (Personalnummer, Wochenstunden, Urlaubstage, Rollen, Standard-Pause)
|
||||||
app.put('/admin/users/:id', requireAdmin, (req, res) => {
|
app.put('/admin/users/:id', requireAdmin, (req, res) => {
|
||||||
const userId = req.params.id;
|
const userId = req.params.id;
|
||||||
const { personalnummer, wochenstunden, urlaubstage, arbeitstage, roles } = req.body;
|
const { personalnummer, wochenstunden, urlaubstage, arbeitstage, roles, default_break_minutes } = req.body;
|
||||||
|
|
||||||
|
const parsedBreak = default_break_minutes !== undefined && default_break_minutes !== '' ? parseInt(default_break_minutes, 10) : 30;
|
||||||
|
const normalizedDefaultBreak = (!isNaN(parsedBreak) && parsedBreak >= 0) ? parsedBreak : 30;
|
||||||
|
|
||||||
// Rollen verarbeiten falls vorhanden
|
// Rollen verarbeiten falls vorhanden
|
||||||
let rolesJson = null;
|
let rolesJson = null;
|
||||||
@@ -122,12 +127,13 @@ function registerAdminRoutes(app) {
|
|||||||
// SQL-Query dynamisch zusammenstellen
|
// SQL-Query dynamisch zusammenstellen
|
||||||
if (rolesJson !== null) {
|
if (rolesJson !== null) {
|
||||||
// Aktualisiere auch Rollen
|
// Aktualisiere auch Rollen
|
||||||
db.run('UPDATE users SET personalnummer = ?, wochenstunden = ?, urlaubstage = ?, arbeitstage = ?, role = ? WHERE id = ?',
|
db.run('UPDATE users SET personalnummer = ?, wochenstunden = ?, urlaubstage = ?, arbeitstage = ?, default_break_minutes = ?, role = ? WHERE id = ?',
|
||||||
[
|
[
|
||||||
personalnummer || null,
|
personalnummer || null,
|
||||||
wochenstunden ? parseFloat(wochenstunden) : null,
|
wochenstunden ? parseFloat(wochenstunden) : null,
|
||||||
urlaubstage ? parseFloat(urlaubstage) : null,
|
urlaubstage ? parseFloat(urlaubstage) : null,
|
||||||
arbeitstage ? parseInt(arbeitstage) : 5,
|
arbeitstage ? parseInt(arbeitstage) : 5,
|
||||||
|
normalizedDefaultBreak,
|
||||||
rolesJson,
|
rolesJson,
|
||||||
userId
|
userId
|
||||||
],
|
],
|
||||||
@@ -139,12 +145,13 @@ function registerAdminRoutes(app) {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Nur andere Felder aktualisieren
|
// Nur andere Felder aktualisieren
|
||||||
db.run('UPDATE users SET personalnummer = ?, wochenstunden = ?, urlaubstage = ?, arbeitstage = ? WHERE id = ?',
|
db.run('UPDATE users SET personalnummer = ?, wochenstunden = ?, urlaubstage = ?, arbeitstage = ?, default_break_minutes = ? WHERE id = ?',
|
||||||
[
|
[
|
||||||
personalnummer || null,
|
personalnummer || null,
|
||||||
wochenstunden ? parseFloat(wochenstunden) : null,
|
wochenstunden ? parseFloat(wochenstunden) : null,
|
||||||
urlaubstage ? parseFloat(urlaubstage) : null,
|
urlaubstage ? parseFloat(urlaubstage) : null,
|
||||||
arbeitstage ? parseInt(arbeitstage) : 5,
|
arbeitstage ? parseInt(arbeitstage) : 5,
|
||||||
|
normalizedDefaultBreak,
|
||||||
userId
|
userId
|
||||||
],
|
],
|
||||||
(err) => {
|
(err) => {
|
||||||
|
|||||||
@@ -57,14 +57,15 @@ function registerUserRoutes(app) {
|
|||||||
app.get('/api/user/data', requireAuth, (req, res) => {
|
app.get('/api/user/data', requireAuth, (req, res) => {
|
||||||
const userId = req.session.userId;
|
const userId = req.session.userId;
|
||||||
|
|
||||||
db.get('SELECT wochenstunden, arbeitstage FROM users WHERE id = ?', [userId], (err, user) => {
|
db.get('SELECT wochenstunden, arbeitstage, default_break_minutes FROM users WHERE id = ?', [userId], (err, user) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return res.status(500).json({ error: 'Fehler beim Abrufen der User-Daten' });
|
return res.status(500).json({ error: 'Fehler beim Abrufen der User-Daten' });
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
wochenstunden: user?.wochenstunden || 0,
|
wochenstunden: user?.wochenstunden || 0,
|
||||||
arbeitstage: user?.arbeitstage || 5
|
arbeitstage: user?.arbeitstage || 5,
|
||||||
|
default_break_minutes: user?.default_break_minutes ?? 30
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -107,6 +107,11 @@
|
|||||||
<label for="urlaubstage">Urlaubstage</label>
|
<label for="urlaubstage">Urlaubstage</label>
|
||||||
<input type="number" id="urlaubstage" name="urlaubstage" step="0.5" min="0" placeholder="z.B. 25">
|
<input type="number" id="urlaubstage" name="urlaubstage" step="0.5" min="0" placeholder="z.B. 25">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="defaultBreakMinutes">Standard-Pausenzeit (Min)</label>
|
||||||
|
<input type="number" id="defaultBreakMinutes" name="default_break_minutes" min="0" step="15" placeholder="30">
|
||||||
|
<small style="color: #666; display: block; margin-top: 5px;">Vorbelegung Pausenzeit pro Tag (Min., mind. 0).</small>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary">Benutzer anlegen</button>
|
<button type="submit" class="btn btn-primary">Benutzer anlegen</button>
|
||||||
@@ -136,6 +141,7 @@
|
|||||||
<th>Wochenstunden</th>
|
<th>Wochenstunden</th>
|
||||||
<th>Arbeitstage pro Woche</th>
|
<th>Arbeitstage pro Woche</th>
|
||||||
<th>Urlaubstage</th>
|
<th>Urlaubstage</th>
|
||||||
|
<th>Standard-Pause (Min)</th>
|
||||||
<th>Erstellt am</th>
|
<th>Erstellt am</th>
|
||||||
<th>Aktionen</th>
|
<th>Aktionen</th>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -194,6 +200,10 @@
|
|||||||
<span class="user-field-display" data-field="urlaubstage"><%= u.urlaubstage || '-' %></span>
|
<span class="user-field-display" data-field="urlaubstage"><%= u.urlaubstage || '-' %></span>
|
||||||
<input type="number" step="0.5" class="user-field-edit" data-field="urlaubstage" data-user-id="<%= u.id %>" value="<%= u.urlaubstage || '' %>" style="display: none; width: 80px;">
|
<input type="number" step="0.5" class="user-field-edit" data-field="urlaubstage" data-user-id="<%= u.id %>" value="<%= u.urlaubstage || '' %>" style="display: none; width: 80px;">
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="user-field-display" data-field="default_break_minutes"><%= (u.default_break_minutes != null && u.default_break_minutes !== '') ? u.default_break_minutes : '-' %></span>
|
||||||
|
<input type="number" min="0" step="15" class="user-field-edit" data-field="default_break_minutes" data-user-id="<%= u.id %>" value="<%= (u.default_break_minutes != null && u.default_break_minutes !== '') ? u.default_break_minutes : '' %>" style="display: none; width: 80px;">
|
||||||
|
</td>
|
||||||
<td><%= new Date(u.created_at).toLocaleDateString('de-DE') %></td>
|
<td><%= new Date(u.created_at).toLocaleDateString('de-DE') %></td>
|
||||||
<td>
|
<td>
|
||||||
<button onclick="editUser(<%= u.id %>)" class="btn btn-primary btn-sm edit-user-btn" data-user-id="<%= u.id %>">Bearbeiten</button>
|
<button onclick="editUser(<%= u.id %>)" class="btn btn-primary btn-sm edit-user-btn" data-user-id="<%= u.id %>">Bearbeiten</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user