refs #2645. Fixed bug schedule datetime
testing/ogGui-multibranch/pipeline/head There was a failure building this commit Details

pull/39/head
Manuel Aranda Rosales 2025-09-03 08:05:35 +02:00
parent 1c91b97e31
commit 570af1ed2b
2 changed files with 117 additions and 28 deletions

View File

@ -8,7 +8,7 @@
<mat-form-field appearance="fill" class="w-full"> <mat-form-field appearance="fill" class="w-full">
<mat-label>Repetición</mat-label> <mat-label>Repetición</mat-label>
<mat-select formControlName="recurrenceType"> <mat-select formControlName="recurrenceType">
<mat-option *ngFor="let type of recurrenceTypes" [value]="type">{{ type | titlecase }}</mat-option> <mat-option *ngFor="let opt of recurrenceTypes" [value]="opt.value">{{ opt.label }}</mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>

View File

@ -14,7 +14,10 @@ export class CreateTaskScheduleComponent implements OnInit{
form: FormGroup; form: FormGroup;
baseUrl: string; baseUrl: string;
apiUrl: 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']; weekDays: string[] = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];
isSingleDateSelected: boolean = true; isSingleDateSelected: boolean = true;
monthsList: string[] = [ monthsList: string[] = [
@ -108,12 +111,27 @@ export class CreateTaskScheduleComponent implements OnInit{
} }
formatExecutionTime(time: string | Date): string { formatExecutionTime(time: string | Date): string {
const date = (time instanceof Date) ? time : new Date(time); if (typeof time === 'string') {
if (isNaN(date.getTime())) { const hhmmMatch = time.match(/^\d{2}:\d{2}/);
console.error('Invalid execution time:', time); 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 '';
} }
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 { convertDateToLocalISO(date: Date): string {
@ -200,31 +218,102 @@ export class CreateTaskScheduleComponent implements OnInit{
this.nextExecutionDate.setHours(parseInt(hours), parseInt(minutes), 0, 0); this.nextExecutionDate.setHours(parseInt(hours), parseInt(minutes), 0, 0);
this.executionCount = 1; this.executionCount = 1;
} }
} else { return;
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);
}
}
} }
private calculateExecutionCount(startDate: Date, endDate: Date, daysCount: number, monthsCount: number): number { const startDateValue = this.form.get('recurrenceDetails.initDate')?.value;
const start = new Date(startDate); 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<number>(selectedDayNames.map(name => this.getDayIndexFromName(name)));
const selectedMonthIndices = new Set<number>(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 calculateExecutionCountExact(startDate: Date, endDate: Date, selectedDays: Set<number>, selectedMonths: Set<number>): number {
const cursor = new Date(startDate);
cursor.setHours(0, 0, 0, 0);
const end = new Date(endDate); const end = new Date(endDate);
const daysDiff = Math.ceil((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)); end.setHours(23, 59, 59, 999);
// Aproximación: días seleccionados por semana * semanas * meses activos let count = 0;
return Math.ceil((daysCount / 7) * (daysDiff / 7) * (monthsCount / 12)); 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<number>, selectedMonths: Set<number>): 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 { formatDate(date: string | Date): string {