Implementierung Datenbank pflege wegen doppelten einträgen
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user