Add workdays routes to backend and frontend; update routing and UI components for workdays tracking

This commit is contained in:
Torsten Schulz (local)
2025-10-17 21:37:47 +02:00
parent 2868d64e37
commit a58504a93e
7 changed files with 423 additions and 0 deletions

View File

@@ -0,0 +1,182 @@
const database = require('../config/database');
const { Op } = require('sequelize');
/**
* Service-Klasse für Arbeitstage-Statistiken
* Berechnet verschiedene Tage-Typen für ein Jahr
*/
class WorkdaysService {
constructor() {
this.defaultUserId = 1;
}
/**
* Berechnet Arbeitstage-Statistiken für ein Jahr
* @param {number} userId - Benutzer-ID
* @param {number} year - Jahr
* @returns {Promise<Object>} Statistiken
*/
async getWorkdaysStatistics(userId, year) {
const { Holiday, Sick, Vacation } = database.getModels();
const sequelize = database.sequelize;
// Berechne Anzahl Werktage (Mo-Fr) im Jahr
const workdays = this._countWorkdays(year);
// Hole alle Feiertage für das Jahr
const holidays = await Holiday.findAll({
where: {
date: {
[Op.gte]: `${year}-01-01`,
[Op.lte]: `${year}-12-31`
}
},
raw: true
});
// Zähle nur Feiertage die auf Werktage fallen
const holidayCount = holidays.filter(h => {
const holidayDate = new Date(h.date + 'T00:00:00');
const dayOfWeek = holidayDate.getDay();
return dayOfWeek >= 1 && dayOfWeek <= 5; // Mo-Fr
}).length;
// Hole alle Krankheitstage für das Jahr
const sickEntries = await Sick.findAll({
where: {
user_id: userId,
[Op.or]: [
{
first_day: {
[Op.between]: [`${year}-01-01`, `${year}-12-31`]
}
},
{
last_day: {
[Op.between]: [`${year}-01-01`, `${year}-12-31`]
}
},
{
[Op.and]: [
{ first_day: { [Op.lte]: `${year}-01-01` } },
{ last_day: { [Op.gte]: `${year}-12-31` } }
]
}
]
},
raw: true
});
// Zähle Krankheitstage (nur Werktage)
let sickDays = 0;
sickEntries.forEach(sick => {
const start = new Date(Math.max(new Date(sick.first_day + 'T00:00:00'), new Date(`${year}-01-01T00:00:00`)));
const end = new Date(Math.min(new Date(sick.last_day + 'T00:00:00'), new Date(`${year}-12-31T00:00:00`)));
for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
const dayOfWeek = d.getDay();
if (dayOfWeek >= 1 && dayOfWeek <= 5) { // Mo-Fr
sickDays++;
}
}
});
// Hole alle Urlaubstage für das Jahr
const vacationEntries = await Vacation.findAll({
where: {
user_id: userId,
[Op.or]: [
{
first_day: {
[Op.between]: [`${year}-01-01`, `${year}-12-31`]
}
},
{
last_day: {
[Op.between]: [`${year}-01-01`, `${year}-12-31`]
}
},
{
[Op.and]: [
{ first_day: { [Op.lte]: `${year}-01-01` } },
{ last_day: { [Op.gte]: `${year}-12-31` } }
]
}
]
},
raw: true
});
// Zähle Urlaubstage (nur Werktage, berücksichtige halbe Tage)
let vacationDays = 0;
vacationEntries.forEach(vac => {
const start = new Date(Math.max(new Date(vac.first_day + 'T00:00:00'), new Date(`${year}-01-01T00:00:00`)));
const end = new Date(Math.min(new Date(vac.last_day + 'T00:00:00'), new Date(`${year}-12-31T00:00:00`)));
const isHalfDay = vac.half_day === 1;
for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
const dayOfWeek = d.getDay();
if (dayOfWeek >= 1 && dayOfWeek <= 5) { // Mo-Fr
vacationDays += isHalfDay ? 0.5 : 1;
}
}
});
// Zähle gearbeitete Tage (Tage mit worklog-Einträgen)
const workedDaysQuery = `
SELECT COUNT(DISTINCT DATE(tstamp)) as count
FROM worklog
WHERE user_id = :userId
AND DATE(tstamp) BETWEEN :startDate AND :endDate
AND state LIKE '%start work%'
`;
const workedDaysResult = await sequelize.query(workedDaysQuery, {
replacements: {
userId,
startDate: `${year}-01-01`,
endDate: `${year}-12-31`
},
type: sequelize.QueryTypes.SELECT
});
const workedDays = workedDaysResult[0]?.count || 0;
// Berechne Prozentsatz Krankheitstage
const sickPercentage = workdays > 0 ? Math.round((sickDays / workdays) * 100) : 0;
return {
year,
workdays,
holidays: holidayCount,
sickDays,
sickPercentage,
vacationDays,
workedDays
};
}
/**
* Zählt Werktage (Mo-Fr) in einem Jahr
* @param {number} year - Jahr
* @returns {number} Anzahl Werktage
*/
_countWorkdays(year) {
let count = 0;
const start = new Date(year, 0, 1);
const end = new Date(year, 11, 31);
for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
const dayOfWeek = d.getDay();
if (dayOfWeek >= 1 && dayOfWeek <= 5) { // Mo-Fr
count++;
}
}
return count;
}
}
module.exports = new WorkdaysService();