diff --git a/ogWebconsole/src/app/components/commands/commands-task/create-task-schedule/create-task-schedule.component.html b/ogWebconsole/src/app/components/commands/commands-task/create-task-schedule/create-task-schedule.component.html index 186ff83..ac8f63f 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/create-task-schedule/create-task-schedule.component.html +++ b/ogWebconsole/src/app/components/commands/commands-task/create-task-schedule/create-task-schedule.component.html @@ -8,7 +8,7 @@ Repetición - {{ type | titlecase }} + {{ opt.label }} diff --git a/ogWebconsole/src/app/components/commands/commands-task/create-task-schedule/create-task-schedule.component.ts b/ogWebconsole/src/app/components/commands/commands-task/create-task-schedule/create-task-schedule.component.ts index 5822467..afdedf8 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/create-task-schedule/create-task-schedule.component.ts +++ b/ogWebconsole/src/app/components/commands/commands-task/create-task-schedule/create-task-schedule.component.ts @@ -14,7 +14,10 @@ export class CreateTaskScheduleComponent implements OnInit{ form: FormGroup; baseUrl: string; apiUrl: string; - recurrenceTypes = ['none', 'custom']; + recurrenceTypes = [ + { value: 'none', label: 'Sin repetición' }, + { value: 'custom', label: 'Repetición personalizada' } + ]; weekDays: string[] = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']; isSingleDateSelected: boolean = true; monthsList: string[] = [ @@ -108,12 +111,27 @@ export class CreateTaskScheduleComponent implements OnInit{ } formatExecutionTime(time: string | Date): string { - const date = (time instanceof Date) ? time : new Date(time); - if (isNaN(date.getTime())) { - console.error('Invalid execution time:', time); + if (typeof time === 'string') { + const hhmmMatch = time.match(/^\d{2}:\d{2}/); + if (hhmmMatch) { + return hhmmMatch[0]; + } + const parsed = new Date(time); + if (!isNaN(parsed.getTime())) { + const hours = String(parsed.getHours()).padStart(2, '0'); + const minutes = String(parsed.getMinutes()).padStart(2, '0'); + return `${hours}:${minutes}`; + } return ''; } - return date.toISOString().substring(11, 16); + + if (time instanceof Date && !isNaN(time.getTime())) { + const hours = String(time.getHours()).padStart(2, '0'); + const minutes = String(time.getMinutes()).padStart(2, '0'); + return `${hours}:${minutes}`; + } + + return ''; } convertDateToLocalISO(date: Date): string { @@ -191,7 +209,7 @@ export class CreateTaskScheduleComponent implements OnInit{ private calculateNextExecutionAndCount(): void { const recurrence = this.form.get('recurrenceType')?.value; const time = this.form.get('executionTime')?.value; - + if (recurrence === 'none') { const execDate = this.form.get('executionDate')?.value; if (execDate && time) { @@ -200,31 +218,102 @@ export class CreateTaskScheduleComponent implements OnInit{ this.nextExecutionDate.setHours(parseInt(hours), parseInt(minutes), 0, 0); this.executionCount = 1; } - } else { - const startDate = this.form.get('recurrenceDetails.initDate')?.value; - const endDate = this.form.get('recurrenceDetails.endDate')?.value; - const days = Object.keys(this.selectedDays).filter(day => this.selectedDays[day]); - const months = Object.keys(this.selectedMonths).filter(month => this.selectedMonths[month]); - - if (startDate && endDate && days.length > 0 && months.length > 0) { - // Calcular próxima ejecución (simplificado) - this.nextExecutionDate = new Date(startDate); - const [hours, minutes] = time.split(':'); - this.nextExecutionDate.setHours(parseInt(hours), parseInt(minutes), 0, 0); - - // Calcular número aproximado de ejecuciones - this.executionCount = this.calculateExecutionCount(startDate, endDate, days.length, months.length); - } + return; } + + const startDateValue = this.form.get('recurrenceDetails.initDate')?.value; + const endDateValue = this.form.get('recurrenceDetails.endDate')?.value; + + const selectedDayNames = Object.keys(this.selectedDays).filter(day => this.selectedDays[day]); + const selectedMonthNames = Object.keys(this.selectedMonths).filter(month => this.selectedMonths[month]); + + if (!startDateValue || !endDateValue || selectedDayNames.length === 0 || selectedMonthNames.length === 0) { + this.nextExecutionDate = null; + this.executionCount = 0; + return; + } + + const startDate = new Date(startDateValue); + const endDate = new Date(endDateValue); + + const selectedDayIndices = new Set(selectedDayNames.map(name => this.getDayIndexFromName(name))); + const selectedMonthIndices = new Set(selectedMonthNames.map(name => this.getMonthIndexFromName(name))); + + // Conteo exacto de ejecuciones en el rango [startDate, endDate] + this.executionCount = this.calculateExecutionCountExact(startDate, endDate, selectedDayIndices, selectedMonthIndices); + + // Próxima ejecución >= ahora dentro del rango y criterios + this.nextExecutionDate = this.findNextExecutionDate(startDate, endDate, time, selectedDayIndices, selectedMonthIndices); } - private calculateExecutionCount(startDate: Date, endDate: Date, daysCount: number, monthsCount: number): number { - const start = new Date(startDate); + private calculateExecutionCountExact(startDate: Date, endDate: Date, selectedDays: Set, selectedMonths: Set): number { + const cursor = new Date(startDate); + cursor.setHours(0, 0, 0, 0); const end = new Date(endDate); - const daysDiff = Math.ceil((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)); - - // Aproximación: días seleccionados por semana * semanas * meses activos - return Math.ceil((daysCount / 7) * (daysDiff / 7) * (monthsCount / 12)); + end.setHours(23, 59, 59, 999); + + let count = 0; + while (cursor <= end) { + if (selectedMonths.has(cursor.getMonth()) && selectedDays.has(cursor.getDay())) { + count += 1; + } + cursor.setDate(cursor.getDate() + 1); + } + return count; + } + + private findNextExecutionDate(startDate: Date, endDate: Date, time: string, selectedDays: Set, selectedMonths: Set): Date | null { + const now = new Date(); + + const startCandidate = new Date(Math.max(new Date(startDate).setHours(0, 0, 0, 0), new Date(now).setHours(0, 0, 0, 0))); + const endLimit = new Date(endDate); + endLimit.setHours(23, 59, 59, 999); + + const [hours, minutes] = (time || '00:00').split(':'); + + const candidate = new Date(startCandidate); + while (candidate <= endLimit) { + if (selectedMonths.has(candidate.getMonth()) && selectedDays.has(candidate.getDay())) { + const candidateDateTime = new Date(candidate); + candidateDateTime.setHours(parseInt(hours), parseInt(minutes), 0, 0); + if (candidateDateTime >= now) { + return candidateDateTime; + } + } + candidate.setDate(candidate.getDate() + 1); + } + return null; + } + + private getDayIndexFromName(dayName: string): number { + const mapping: { [key: string]: number } = { + sunday: 0, + monday: 1, + tuesday: 2, + wednesday: 3, + thursday: 4, + friday: 5, + saturday: 6 + }; + return mapping[dayName.toLowerCase()] ?? -1; + } + + private getMonthIndexFromName(monthName: string): number { + const mapping: { [key: string]: number } = { + january: 0, + february: 1, + march: 2, + april: 3, + may: 4, + june: 5, + july: 6, + august: 7, + september: 8, + october: 9, + november: 10, + december: 11 + }; + return mapping[monthName.toLowerCase()] ?? -1; } formatDate(date: string | Date): string {