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-label>Repetición</mat-label>
<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-form-field>

View File

@ -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<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 calculateExecutionCount(startDate: Date, endDate: Date, daysCount: number, monthsCount: number): number {
const start = new Date(startDate);
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 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<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 {