Initial commit: TimeClock v3 - Node.js/Vue.js Zeiterfassung
Features: - Backend: Node.js/Express mit MySQL/MariaDB - Frontend: Vue.js 3 mit Composition API - UTC-Zeithandling für korrekte Zeiterfassung - Timewish-basierte Überstundenberechnung - Wochenübersicht mit Urlaubs-/Krankheits-/Feiertagshandling - Bereinigtes Arbeitsende (Generell/Woche) - Überstunden-Offset für historische Daten - Fixed Layout mit scrollbarem Content - Kompakte UI mit grünem Theme
This commit is contained in:
265
backend/src/controllers/TimeEntryController.js
Normal file
265
backend/src/controllers/TimeEntryController.js
Normal file
@@ -0,0 +1,265 @@
|
||||
const timeEntryService = require('../services/TimeEntryService');
|
||||
|
||||
/**
|
||||
* Controller-Klasse für Zeiteinträge
|
||||
* Verantwortlich für HTTP-Request/Response-Handling
|
||||
*/
|
||||
class TimeEntryController {
|
||||
/**
|
||||
* Alle Zeiteinträge abrufen
|
||||
* GET /api/time-entries
|
||||
*/
|
||||
async getAllEntries(req, res) {
|
||||
try {
|
||||
const entries = timeEntryService.getAllEntries();
|
||||
res.json(entries);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Abrufen der Einträge:', error);
|
||||
res.status(500).json({
|
||||
error: 'Fehler beim Abrufen der Einträge',
|
||||
message: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Einzelnen Zeiteintrag anhand der ID abrufen
|
||||
* GET /api/time-entries/:id
|
||||
*/
|
||||
async getEntryById(req, res) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const entry = timeEntryService.getEntryById(id);
|
||||
|
||||
if (!entry) {
|
||||
return res.status(404).json({
|
||||
error: 'Eintrag nicht gefunden',
|
||||
id: parseInt(id)
|
||||
});
|
||||
}
|
||||
|
||||
res.json(entry);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Abrufen des Eintrags:', error);
|
||||
res.status(500).json({
|
||||
error: 'Fehler beim Abrufen des Eintrags',
|
||||
message: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Neuen Zeiteintrag erstellen (Timer starten)
|
||||
* POST /api/time-entries
|
||||
*/
|
||||
async createEntry(req, res) {
|
||||
try {
|
||||
const entryData = req.body;
|
||||
const newEntry = timeEntryService.createEntry(entryData);
|
||||
|
||||
res.status(201).json(newEntry);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Erstellen des Eintrags:', error);
|
||||
|
||||
// Spezifische Fehlerbehandlung
|
||||
if (error.message.includes('läuft bereits')) {
|
||||
return res.status(400).json({
|
||||
error: 'Validierungsfehler',
|
||||
message: error.message
|
||||
});
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
error: 'Fehler beim Erstellen des Eintrags',
|
||||
message: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeiteintrag aktualisieren (Timer stoppen oder Daten ändern)
|
||||
* PUT /api/time-entries/:id
|
||||
*/
|
||||
async updateEntry(req, res) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const updateData = req.body;
|
||||
|
||||
const updatedEntry = timeEntryService.updateEntry(id, updateData);
|
||||
res.json(updatedEntry);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Aktualisieren des Eintrags:', error);
|
||||
|
||||
// Spezifische Fehlerbehandlung
|
||||
if (error.message.includes('nicht gefunden')) {
|
||||
return res.status(404).json({
|
||||
error: 'Eintrag nicht gefunden',
|
||||
message: error.message
|
||||
});
|
||||
}
|
||||
|
||||
if (error.message.includes('Endzeit') || error.message.includes('Startzeit')) {
|
||||
return res.status(400).json({
|
||||
error: 'Validierungsfehler',
|
||||
message: error.message
|
||||
});
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
error: 'Fehler beim Aktualisieren des Eintrags',
|
||||
message: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeiteintrag löschen
|
||||
* DELETE /api/time-entries/:id
|
||||
*/
|
||||
async deleteEntry(req, res) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
timeEntryService.deleteEntry(id);
|
||||
|
||||
res.status(204).send();
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Löschen des Eintrags:', error);
|
||||
|
||||
if (error.message.includes('nicht gefunden')) {
|
||||
return res.status(404).json({
|
||||
error: 'Eintrag nicht gefunden',
|
||||
message: error.message
|
||||
});
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
error: 'Fehler beim Löschen des Eintrags',
|
||||
message: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aktuellen Status abrufen (letzter Worklog-Eintrag)
|
||||
* GET /api/time-entries/current-state
|
||||
*/
|
||||
async getCurrentState(req, res) {
|
||||
try {
|
||||
const userId = req.user.userId;
|
||||
const state = await timeEntryService.getCurrentState(userId);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
state: state
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Abrufen des aktuellen Status:', error);
|
||||
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Fehler beim Abrufen des Status'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stempeln (Clock In/Out, Pause Start/Stop)
|
||||
* POST /api/time-entries/clock
|
||||
*/
|
||||
async clock(req, res) {
|
||||
try {
|
||||
const userId = req.user.userId;
|
||||
const { action } = req.body;
|
||||
|
||||
if (!action) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Aktion ist erforderlich'
|
||||
});
|
||||
}
|
||||
|
||||
const result = await timeEntryService.clock(userId, action);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Erfolgreich gestempelt',
|
||||
entry: result
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Stempeln:', error);
|
||||
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Statistiken abrufen
|
||||
* GET /api/time-entries/stats/summary
|
||||
*/
|
||||
async getStats(req, res) {
|
||||
try {
|
||||
const userId = req.user?.userId;
|
||||
const stats = await timeEntryService.getStatistics(userId);
|
||||
res.json(stats || {});
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Abrufen der Statistiken:', error);
|
||||
res.status(500).json({
|
||||
error: 'Fehler beim Abrufen der Statistiken',
|
||||
message: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aktuell laufenden Timer abrufen
|
||||
* GET /api/time-entries/running
|
||||
*/
|
||||
async getRunningEntry(req, res) {
|
||||
try {
|
||||
const userId = req.user.userId;
|
||||
const runningEntry = await timeEntryService.getRunningEntry(userId);
|
||||
|
||||
if (!runningEntry) {
|
||||
return res.json({}); // Leeres Objekt wenn nichts läuft
|
||||
}
|
||||
|
||||
res.json(runningEntry);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Abrufen des laufenden Timers:', error);
|
||||
res.status(500).json({
|
||||
error: 'Fehler beim Abrufen des laufenden Timers',
|
||||
message: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Einträge nach Projekt filtern
|
||||
* GET /api/time-entries/project/:projectName
|
||||
*/
|
||||
async getEntriesByProject(req, res) {
|
||||
try {
|
||||
const { projectName } = req.params;
|
||||
const entries = timeEntryService.getEntriesByProject(projectName);
|
||||
|
||||
res.json({
|
||||
project: projectName,
|
||||
count: entries.length,
|
||||
entries
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Filtern nach Projekt:', error);
|
||||
res.status(500).json({
|
||||
error: 'Fehler beim Filtern nach Projekt',
|
||||
message: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Singleton-Instanz exportieren
|
||||
module.exports = new TimeEntryController();
|
||||
|
||||
Reference in New Issue
Block a user