Implementierung Datenbank pflege wegen doppelten einträgen

This commit is contained in:
2026-03-16 15:59:33 +01:00
parent 164cd78f3d
commit 5a8dcf2cb5
3 changed files with 249 additions and 0 deletions

View File

@@ -66,6 +66,14 @@ document.addEventListener('DOMContentLoaded', function() {
// MSSQL-Konfiguration laden
loadMssqlConfig();
// Timesheet-Duplikate Button
const loadTimesheetDuplicatesBtn = document.getElementById('loadTimesheetDuplicatesBtn');
if (loadTimesheetDuplicatesBtn) {
loadTimesheetDuplicatesBtn.addEventListener('click', function() {
loadTimesheetDuplicates();
});
}
// Optionen-Formular
const optionsForm = document.getElementById('optionsForm');
if (optionsForm) {
@@ -298,6 +306,123 @@ document.addEventListener('DOMContentLoaded', function() {
}
});
async function loadTimesheetDuplicates() {
const container = document.getElementById('timesheetDuplicatesContainer');
if (!container) return;
container.innerHTML = '<p style="color: #666;">Lade Timesheet-Duplikate...</p>';
try {
const response = await fetch('/admin/api/timesheet-duplicates');
const result = await response.json();
if (!response.ok) {
const msg = result && result.error ? result.error : 'Fehler beim Laden der Timesheet-Duplikate.';
container.innerHTML = `<p style="color: red;">${msg}</p>`;
return;
}
const groups = Array.isArray(result.groups) ? result.groups : [];
if (groups.length === 0) {
container.innerHTML = '<p style="color: green;">Es wurden keine doppelten Timesheet-Einträge gefunden. Alles sauber.</p>';
return;
}
let html = '';
groups.forEach((group, index) => {
const headerLabel = `${group.user_name || group.username || ('User #' + group.user_id)} ${group.date} (Anzahl Einträge: ${group.entry_count})`;
html += `
<div class="timesheet-duplicate-group" style="border: 1px solid #ddd; border-radius: 4px; margin-bottom: 15px;">
<div style="padding: 10px 15px; background-color: #f5f5f5; display: flex; justify-content: space-between; align-items: center;">
<div>
<strong>Gruppe ${index + 1}</strong>: ${headerLabel}
</div>
</div>
<div style="padding: 10px 15px; overflow-x: auto;">
<table style="width: 100%; min-width: 800px; border-collapse: collapse;">
<thead>
<tr>
<th style="text-align:left; padding:4px;">ID</th>
<th style="text-align:left; padding:4px;">Start</th>
<th style="text-align:left; padding:4px;">Ende</th>
<th style="text-align:left; padding:4px;">Pause (Min)</th>
<th style="text-align:left; padding:4px;">Stunden (total_hours)</th>
<th style="text-align:left; padding:4px;">Status</th>
<th style="text-align:left; padding:4px;">Erstellt</th>
<th style="text-align:left; padding:4px;">Aktualisiert</th>
<th style="text-align:left; padding:4px;">Aktionen</th>
</tr>
</thead>
<tbody>
`;
(group.entries || []).forEach(entry => {
const created = entry.created_at ? new Date(entry.created_at).toLocaleString('de-DE') : '-';
const updated = entry.updated_at ? new Date(entry.updated_at).toLocaleString('de-DE') : '-';
const totalHours = entry.total_hours != null ? entry.total_hours : '-';
const status = entry.status || '-';
const breakMinutes = entry.break_minutes != null ? entry.break_minutes : 0;
html += `
<tr>
<td style="padding:4px;">${entry.id}</td>
<td style="padding:4px;">${entry.start_time || '-'}</td>
<td style="padding:4px;">${entry.end_time || '-'}</td>
<td style="padding:4px;">${breakMinutes}</td>
<td style="padding:4px;">${totalHours}</td>
<td style="padding:4px;">${status}</td>
<td style="padding:4px;">${created}</td>
<td style="padding:4px;">${updated}</td>
<td style="padding:4px;">
<button type="button" class="btn btn-danger btn-sm" onclick="deleteTimesheetEntry(${entry.id})">
Eintrag löschen
</button>
</td>
</tr>
`;
});
html += `
</tbody>
</table>
</div>
</div>
`;
});
container.innerHTML = html;
} catch (error) {
console.error('Fehler beim Laden der Timesheet-Duplikate:', error);
container.innerHTML = '<p style="color: red;">Fehler beim Laden der Timesheet-Duplikate.</p>';
}
}
async function deleteTimesheetEntry(entryId) {
try {
const response = await fetch(`/admin/api/timesheet-entry/${entryId}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
});
const result = await response.json();
if (response.ok && result && result.success) {
// Liste neu laden, um den aktuellen Stand anzuzeigen
loadTimesheetDuplicates();
} else {
const msg = (result && result.error) ? result.error : 'Timesheet-Eintrag konnte nicht gelöscht werden.';
alert('Fehler: ' + msg);
}
} catch (error) {
console.error('Fehler beim Löschen des Timesheet-Eintrags:', error);
alert('Fehler beim Löschen des Timesheet-Eintrags.');
}
}
// Optionen laden und Formular ausfüllen
async function loadOptions() {
try {