This commit is contained in:
Carsten Graf
2026-01-26 17:58:12 +01:00
parent dfbc7d8bbc
commit ca48cdf78f
9 changed files with 971 additions and 178 deletions

View File

@@ -54,7 +54,7 @@
</div>
<div class="actions">
<button id="submitWeek" class="btn btn-success" onclick="window.submitWeekHandler(event)">Woche abschicken</button>
<button id="submitWeek" class="btn btn-success" onclick="window.submitWeekHandler(event)" disabled>Woche abschicken</button>
<p class="help-text">Stunden werden automatisch gespeichert. Am Ende der Woche können Sie die Stunden abschicken.</p>
</div>
</div>
@@ -63,15 +63,30 @@
<div class="user-stats-panel">
<!-- Statistik-Karten -->
<div class="stat-card">
<div class="stat-label">Aktuelle Überstunden</div>
<div class="stat-label" style="display: flex; align-items: center; gap: 5px;">
Aktuelle Überstunden
<span class="help-icon" onclick="showHelpModal('overtime-help')" style="cursor: pointer; color: #3498db; font-size: 14px; font-weight: bold; width: 18px; height: 18px; border-radius: 50%; background: #e8f4f8; display: inline-flex; align-items: center; justify-content: center; line-height: 1;">?</span>
</div>
<div class="stat-value" id="currentOvertime">-</div>
<div class="stat-unit">Stunden</div>
</div>
<div class="stat-card stat-vacation">
<div class="stat-label">Verbleibende Urlaubstage</div>
<div class="stat-label" style="display: flex; align-items: center; gap: 5px;">
Verbleibende Urlaubstage
<span class="help-icon" onclick="showHelpModal('remaining-vacation-help')" style="cursor: pointer; color: #3498db; font-size: 14px; font-weight: bold; width: 18px; height: 18px; border-radius: 50%; background: #e8f4f8; display: inline-flex; align-items: center; justify-content: center; line-height: 1;">?</span>
</div>
<div class="stat-value" id="remainingVacation">-</div>
<div class="stat-unit">von <span id="totalVacation">-</span> Tagen</div>
</div>
<div class="stat-card stat-planned">
<div class="stat-label" style="display: flex; align-items: center; gap: 5px;">
Verplante Urlaubstage
<span class="help-icon" onclick="showHelpModal('planned-vacation-help')" style="cursor: pointer; color: #3498db; font-size: 14px; font-weight: bold; width: 18px; height: 18px; border-radius: 50%; background: #e8f4f8; display: inline-flex; align-items: center; justify-content: center; line-height: 1;">?</span>
</div>
<div class="stat-value" id="plannedVacation">-</div>
<div class="stat-unit">Tage</div>
<div id="plannedWeeks" style="font-size: 11px; color: #666; margin-top: 8px; line-height: 1.4;"></div>
</div>
<!-- Zeiterfassung (URL & IP) -->
<div style="margin-top: 20px; padding-top: 20px; border-top: 1px solid #e0e0e0;">
@@ -82,7 +97,10 @@
<div id="timeCaptureContent" style="display: none; margin-top: 15px;">
<!-- URL-Erfassung -->
<div style="margin-bottom: 20px;">
<h4 style="font-size: 13px; margin-bottom: 10px; color: #555;">Zeiterfassung per URL</h4>
<h4 style="font-size: 13px; margin-bottom: 10px; color: #555; display: flex; align-items: center; gap: 5px;">
Zeiterfassung per URL
<span class="help-icon" onclick="showHelpModal('url-help')" style="cursor: pointer; color: #3498db; font-size: 14px; font-weight: bold; width: 18px; height: 18px; border-radius: 50%; background: #e8f4f8; display: inline-flex; align-items: center; justify-content: center; line-height: 1;">?</span>
</h4>
<div class="form-group" style="margin-bottom: 15px;">
<label style="font-size: 12px; color: #666; margin-bottom: 5px;">Check-in URL</label>
<div style="display: flex; gap: 5px;">
@@ -101,13 +119,17 @@
<!-- IP-Erfassung -->
<div style="padding-top: 15px; border-top: 1px solid #e0e0e0;">
<h4 style="font-size: 13px; margin-bottom: 10px; color: #555;">IP-basierte Zeiterfassung</h4>
<h4 style="font-size: 13px; margin-bottom: 10px; color: #555; display: flex; align-items: center; gap: 5px;">
IP-basierte Zeiterfassung
<span class="help-icon" onclick="showHelpModal('ip-help')" style="cursor: pointer; color: #3498db; font-size: 14px; font-weight: bold; width: 18px; height: 18px; border-radius: 50%; background: #e8f4f8; display: inline-flex; align-items: center; justify-content: center; line-height: 1;">?</span>
</h4>
<div class="form-group" style="margin-bottom: 15px;">
<label style="font-size: 12px; color: #666; margin-bottom: 5px;">Ping-IP Adresse</label>
<div style="display: flex; gap: 5px;">
<div style="display: flex; gap: 5px; margin-bottom: 5px;">
<input type="text" id="pingIpInput" placeholder="z.B. 192.168.1.100" style="flex: 1; padding: 8px; font-size: 12px; border: 1px solid #ddd; border-radius: 4px;">
<button onclick="window.savePingIP()" class="btn btn-sm btn-success" style="padding: 8px 12px;">Speichern</button>
</div>
<button onclick="window.detectClientIP()" class="btn btn-sm" style="padding: 6px 12px; background-color: #3498db; color: white; border: none; border-radius: 4px; font-size: 11px; cursor: pointer; margin-bottom: 5px;">Aktuelle IP ermitteln</button>
<p style="font-size: 11px; color: #666; margin-top: 5px; font-style: italic;">Ihre IP-Adresse für automatische Zeiterfassung</p>
</div>
</div>
@@ -230,5 +252,154 @@
}
});
</script>
<!-- Help Modal -->
<div id="helpModal" style="display: none; position: fixed; z-index: 10000; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5);">
<div style="position: relative; background-color: #fff; margin: 10% auto; padding: 20px; border-radius: 8px; width: 90%; max-width: 500px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">
<span onclick="closeHelpModal()" style="position: absolute; right: 15px; top: 15px; color: #aaa; font-size: 28px; font-weight: bold; cursor: pointer; line-height: 1;">&times;</span>
<div id="helpModalContent" style="padding-right: 30px;">
<!-- Content wird dynamisch eingefügt -->
</div>
</div>
</div>
<script>
// Help Modal Funktionen
function showHelpModal(type) {
const modal = document.getElementById('helpModal');
const content = document.getElementById('helpModalContent');
let title = '';
let text = '';
if (type === 'url-help') {
title = 'Zeiterfassung per URL';
text = `
<h3 style="margin-top: 0; color: #2c3e50; font-size: 18px;">${title}</h3>
<p style="color: #555; line-height: 1.6;">
Mit den Check-in und Check-out URLs können Sie Ihre Arbeitszeit automatisch erfassen,
indem Sie die URLs in Ihrem Browser aufrufen oder als Lesezeichen speichern.
</p>
<p style="color: #555; line-height: 1.6;">
<strong>Check-in URL:</strong> Öffnen Sie diese URL, um Ihre Start-Zeit zu erfassen.<br>
<strong>Check-out URL:</strong> Öffnen Sie diese URL, um Ihre End-Zeit zu erfassen.
</p>
<p style="color: #555; line-height: 1.6;">
Die URLs sind personalisiert und funktionieren nur für Ihren Account. Sie können sie
kopieren und als Lesezeichen in Ihrem Browser speichern.
</p>
`;
} else if (type === 'ip-help') {
title = 'IP-basierte Zeiterfassung';
text = `
<h3 style="margin-top: 0; color: #2c3e50; font-size: 18px;">${title}</h3>
<p style="color: #555; line-height: 1.6;">
Die IP-basierte Zeiterfassung erkennt automatisch, wenn Sie sich im Firmennetzwerk befinden,
indem Ihre IP-Adresse regelmäßig geprüft wird.
</p>
<p style="color: #555; line-height: 1.6;">
<strong>So funktioniert es:</strong>
</p>
<ul style="color: #555; line-height: 1.8; padding-left: 20px;">
<li>Tragen Sie Ihre IP-Adresse ein (z.B. 192.168.1.100)</li>
<li>Das System prüft regelmäßig, ob diese IP-Adresse erreichbar ist</li>
<li>Wenn die IP erreichbar ist, wird automatisch eine Start-Zeit erfasst</li>
<li>Wenn die IP nicht mehr erreichbar ist, wird automatisch eine End-Zeit erfasst</li>
</ul>
<p style="color: #555; line-height: 1.6;">
<strong>Tipp:</strong> Verwenden Sie den Button "Aktuelle IP ermitteln", um Ihre aktuelle
IP-Adresse automatisch zu erkennen.
</p>
`;
} else if (type === 'remaining-vacation-help') {
title = 'Verbleibende Urlaubstage';
text = `
<h3 style="margin-top: 0; color: #2c3e50; font-size: 18px;">${title}</h3>
<p style="color: #555; line-height: 1.6;">
Die <strong>verbleibenden Urlaubstage</strong> zeigen an, wie viele Urlaubstage Sie noch
zur Verfügung haben.
</p>
<p style="color: #555; line-height: 1.6;">
<strong>Wichtig:</strong> Diese Zahl berücksichtigt nur Urlaubstage aus Wochen, die bereits
<strong>eingereicht</strong> wurden. Urlaubstage, die Sie nur geplant, aber noch nicht
abgeschickt haben, werden hier nicht abgezogen.
</p>
<p style="color: #555; line-height: 1.6;">
<strong>Beispiel:</strong> Wenn Sie 25 Urlaubstage haben und bereits 5 Tage in eingereichten
Wochen genommen haben, zeigt diese Anzeige 20 verbleibende Tage.
</p>
`;
} else if (type === 'planned-vacation-help') {
title = 'Verplante Urlaubstage';
text = `
<h3 style="margin-top: 0; color: #2c3e50; font-size: 18px;">${title}</h3>
<p style="color: #555; line-height: 1.6;">
Die <strong>verplanten Urlaubstage</strong> zeigen alle Urlaubstage an, die Sie in irgendeiner
Woche eingetragen haben - unabhängig davon, ob die Woche bereits eingereicht wurde oder nicht.
</p>
<p style="color: #555; line-height: 1.6;">
<strong>Unterschied zu "Verbleibende Urlaubstage":</strong>
</p>
<ul style="color: #555; line-height: 1.8; padding-left: 20px;">
<li><strong>Verbleibende Urlaubstage:</strong> Nur von eingereichten Wochen</li>
<li><strong>Verplante Urlaubstage:</strong> Alle geplanten Tage (auch nicht-eingereichte Wochen)</li>
</ul>
<p style="color: #555; line-height: 1.6;">
<strong>Beispiel:</strong> Wenn Sie in einer noch nicht eingereichten Woche 3 Tage Urlaub
eintragen, erscheinen diese sofort in "Verplante Urlaubstage", aber noch nicht in
"Verbleibende Urlaubstage". Erst nach dem Abschicken der Woche werden sie auch von den
verbleibenden Tagen abgezogen.
</p>
<p style="color: #555; line-height: 1.6; margin-top: 15px; padding-top: 15px; border-top: 1px solid #e0e0e0;">
<strong>Hinweis:</strong> Unter dieser Anzeige sehen Sie, in welchen Kalenderwochen
(KW) Sie Urlaub geplant haben.
</p>
`;
} else if (type === 'overtime-help') {
title = 'Aktuelle Überstunden';
text = `
<h3 style="margin-top: 0; color: #2c3e50; font-size: 18px;">${title}</h3>
<p style="color: #555; line-height: 1.6;">
Die <strong>aktuellen Überstunden</strong> zeigen Ihre gesamten Überstunden an, die sich aus
allen bereits eingereichten Wochen ergeben.
</p>
<p style="color: #555; line-height: 1.6;">
<strong>Wichtig:</strong> Überstunden werden erst berechnet und angezeigt, wenn die entsprechende
Woche <strong>abgeschickt</strong> wurde. Überstunden aus Wochen, die Sie nur geplant, aber noch
nicht abgeschickt haben, werden hier nicht berücksichtigt.
</p>
<p style="color: #555; line-height: 1.6;">
<strong>So funktioniert die Berechnung:</strong>
</p>
<ul style="color: #555; line-height: 1.8; padding-left: 20px;">
<li>Für jede eingereichte Woche werden Ihre tatsächlichen Arbeitsstunden mit den Sollstunden verglichen</li>
<li>Die Differenz ergibt die Überstunden (positiv) oder Minusstunden (negativ) für diese Woche</li>
<li>Alle Überstunden aus eingereichten Wochen werden summiert</li>
<li>Zusätzlich können manuelle Korrekturen (Offset) durch die Verwaltung hinzugefügt werden</li>
</ul>
<p style="color: #555; line-height: 1.6; margin-top: 15px; padding-top: 15px; border-top: 1px solid #e0e0e0;">
<strong>Beispiel:</strong> Wenn Sie diese Woche 42 Stunden arbeiten, aber nur 40 Stunden Soll haben,
entstehen 2 Überstunden. Diese werden jedoch erst nach dem Abschicken der Woche zu Ihren
aktuellen Überstunden hinzugefügt.
</p>
`;
}
content.innerHTML = text;
modal.style.display = 'block';
}
function closeHelpModal() {
document.getElementById('helpModal').style.display = 'none';
}
// Modal schließen wenn außerhalb geklickt wird
window.onclick = function(event) {
const modal = document.getElementById('helpModal');
if (event.target === modal) {
closeHelpModal();
}
}
</script>
</body>
</html>