oggui/ogWebconsole/src/app/components/commands/commands-task/show-task-schedule/show-task-schedule.componen...

356 lines
12 KiB
TypeScript

import {Component, Inject, OnInit} from '@angular/core';
import {MatTableDataSource} from "@angular/material/table";
import {Client} from "../../../groups/model/model";
import {ToastrService} from "ngx-toastr";
import {HttpClient} from "@angular/common/http";
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from "@angular/material/dialog";
import {ConfigService} from "@services/config.service";
import {DeleteModalComponent} from "../../../../shared/delete_modal/delete-modal/delete-modal.component";
import {CreateTaskScheduleComponent} from "../create-task-schedule/create-task-schedule.component";
import {DatePipe} from "@angular/common";
@Component({
selector: 'app-show-task-schedule',
templateUrl: './show-task-schedule.component.html',
styleUrl: './show-task-schedule.component.css'
})
export class ShowTaskScheduleComponent implements OnInit{
baseUrl: string;
dataSource = new MatTableDataSource<any>([]);
length = 0;
itemsPerPage: number = 10;
pageSizeOptions: number[] = [5, 10, 20];
page = 0;
loading: boolean = false;
filters: { [key: string]: string } = {};
datePipe: DatePipe = new DatePipe('es-ES');
columns = [
{ columnDef: 'id', header: 'ID', cell: (schedule: any) => schedule.id },
{ columnDef: 'recurrenceType', header: 'Tipo de Programación', cell: (schedule: any) => this.getRecurrenceTypeDisplay(schedule) },
{ columnDef: 'executionTime', header: 'Hora de ejecución', cell: (schedule: any) => this.datePipe.transform(schedule.executionTime, 'HH:mm') },
{ columnDef: 'nextExecution', header: 'Próxima ejecución', cell: (schedule: any) => this.calculateNextExecution(schedule) },
{ columnDef: 'daysOfWeek', header: 'Días de la semana', cell: (schedule: any) => this.formatDaysOfWeek(schedule.recurrenceDetails?.daysOfWeek) },
{ columnDef: 'months', header: 'Meses', cell: (schedule: any) => this.formatMonths(schedule.recurrenceDetails?.months) },
{ columnDef: 'enabled', header: 'Estado', cell: (schedule: any) => schedule.enabled }
];
displayedColumns: string[] = ['id', 'recurrenceType', 'executionTime', 'nextExecution', 'daysOfWeek', 'months', 'enabled', 'actions'];
constructor(
private toastService: ToastrService,
private http: HttpClient,
public dialogRef: MatDialogRef<ShowTaskScheduleComponent>,
public dialog: MatDialog,
private configService: ConfigService,
@Inject(MAT_DIALOG_DATA) public data: any
) {
this.baseUrl = this.configService.apiUrl;
}
ngOnInit(): void {
if (this.data) {
this.loadData();
}
}
loadData() {
this.loading = true;
this.http.get<any>(`${this.baseUrl}/command-task-schedules?page=${this.page + 1}&itemsPerPage=${this.itemsPerPage}&commandTask.id=${this.data.commandTask?.id}`, { params: this.filters }).subscribe(
(data) => {
this.dataSource.data = data['hydra:member'];
this.length = data['hydra:totalItems'];
this.loading = false;
},
(error) => {
this.loading = false;
this.toastService.error('Error al cargar las programaciones');
}
);
}
createNewSchedule(): void {
this.dialog.open(CreateTaskScheduleComponent, {
width: '800px',
data: { task: this.data.commandTask }
}).afterClosed().subscribe(result => {
if (result) {
this.loadData();
this.toastService.success('Programación creada correctamente');
}
});
}
editSchedule(schedule: any): void {
this.dialog.open(CreateTaskScheduleComponent, {
width: '800px',
data: { schedule: schedule, task: this.data.commandTask }
}).afterClosed().subscribe(result => {
if (result) {
this.loadData();
this.toastService.success('Programación actualizada correctamente');
}
});
}
deleteSchedule(schedule: any): void {
const dialogRef = this.dialog.open(DeleteModalComponent, {
width: '300px',
data: { name: 'programación de tarea' }
});
dialogRef.afterClosed().subscribe(result => {
if (result) {
this.http.delete(`${this.baseUrl}${schedule['@id']}`).subscribe(
() => {
this.toastService.success('Programación eliminada correctamente');
this.loadData();
},
(error) => {
this.toastService.error(error.error['hydra:description'] || 'Error al eliminar la programación');
}
);
}
})
}
calculateNextExecution(schedule: any): string {
if (!schedule.enabled) {
return 'Deshabilitada';
}
try {
if (schedule.recurrenceType === 'none') {
if (schedule.executionDate && schedule.executionTime) {
const executionDate = new Date(schedule.executionDate);
const [hours, minutes] = this.parseExecutionTime(schedule.executionTime);
const fullExecutionDateTime = new Date(
executionDate.getFullYear(),
executionDate.getMonth(),
executionDate.getDate(),
hours,
minutes,
0,
0
);
const now = new Date();
if (fullExecutionDateTime < now) {
return 'Ya ejecutada';
}
return this.datePipe.transform(fullExecutionDateTime, 'dd/MM/yyyy HH:mm') || 'Fecha inválida';
}
return 'Sin fecha/hora definida';
}
// Personalizada (u otros tipos con detalles): calcular siguiente ejecución real
if (schedule.recurrenceDetails) {
const startDate = schedule.recurrenceDetails.initDate ? new Date(schedule.recurrenceDetails.initDate) : null;
const endDate = schedule.recurrenceDetails.endDate ? new Date(schedule.recurrenceDetails.endDate) : null;
const days = Array.isArray(schedule.recurrenceDetails.daysOfWeek) ? schedule.recurrenceDetails.daysOfWeek : [];
const months = Array.isArray(schedule.recurrenceDetails.months) ? schedule.recurrenceDetails.months : [];
if (!startDate || !endDate || days.length === 0 || months.length === 0) {
return 'Configuración incompleta';
}
const selectedDayIndices = new Set<number>(days.map((d: string) => this.getDayIndexFromName(d)));
const selectedMonthIndices = new Set<number>(months.map((m: string) => this.getMonthIndexFromName(m)));
const [hours, minutes] = this.parseExecutionTime(schedule.executionTime);
const next = this.findNextExecutionDate(startDate, endDate, hours, minutes, selectedDayIndices, selectedMonthIndices);
if (next) {
return this.datePipe.transform(next, 'dd/MM/yyyy HH:mm') || 'Fecha inválida';
}
return 'No hay próximas ejecuciones';
}
return 'Configuración incompleta';
} catch (error) {
return 'Error en cálculo';
}
}
private parseExecutionTime(executionTime: any): [number, number] {
if (typeof executionTime === 'string') {
const match = executionTime.match(/^(\d{2}):(\d{2})/);
if (match) {
return [parseInt(match[1], 10), parseInt(match[2], 10)];
}
const parsed = new Date(executionTime);
if (!isNaN(parsed.getTime())) {
return [parsed.getHours(), parsed.getMinutes()];
}
return [0, 0];
}
if (executionTime instanceof Date && !isNaN(executionTime.getTime())) {
return [executionTime.getHours(), executionTime.getMinutes()];
}
return [0, 0];
}
private findNextExecutionDate(startDate: Date, endDate: Date, hours: number, minutes: number, 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 cursor = new Date(startCandidate);
while (cursor <= endLimit) {
if (selectedMonths.has(cursor.getMonth()) && selectedDays.has(cursor.getDay())) {
const candidateDateTime = new Date(cursor);
candidateDateTime.setHours(hours, minutes, 0, 0);
if (candidateDateTime >= now) {
return candidateDateTime;
}
}
cursor.setDate(cursor.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;
}
onPageChange(event: any): void {
this.page = event.pageIndex;
this.itemsPerPage = event.pageSize;
this.loadData();
}
onNoClick(): void {
this.dialogRef.close(false);
}
getRecurrenceTypeDisplay(schedule: any): any {
if (schedule.recurrenceType === 'none') {
return {
type: 'none',
label: 'Ejecución única',
icon: 'event',
color: 'primary',
details: schedule.executionDate ?
`Fecha: ${this.datePipe.transform(schedule.executionDate, 'dd/MM/yyyy')}` :
'Sin fecha definida'
};
} else if (schedule.recurrenceType === 'daily') {
return {
type: 'daily',
label: 'Diaria',
icon: 'repeat',
color: 'accent',
details: 'Todos los días'
};
} else if (schedule.recurrenceType === 'weekly') {
return {
type: 'weekly',
label: 'Semanal',
icon: 'view_week',
color: 'accent',
details: schedule.recurrenceDetails?.daysOfWeek?.length > 0 ?
`Días: ${schedule.recurrenceDetails.daysOfWeek.join(', ')}` :
'Todos los días'
};
} else if (schedule.recurrenceType === 'monthly') {
return {
type: 'monthly',
label: 'Mensual',
icon: 'calendar_month',
color: 'accent',
details: schedule.recurrenceDetails?.months?.length > 0 ?
`Meses: ${schedule.recurrenceDetails.months.join(', ')}` :
'Todos los meses'
};
} else if (schedule.recurrenceType === 'yearly') {
return {
type: 'yearly',
label: 'Anual',
icon: 'event_note',
color: 'accent',
details: 'Una vez al año'
};
} else {
return {
type: 'custom',
label: 'Personalizada',
icon: 'settings',
color: 'warn',
details: 'Configuración especial'
};
}
}
formatDaysOfWeek(days: string[]): any {
if (!days || days.length === 0) return null;
const dayMap: { [key: string]: string } = {
'monday': 'Lun',
'tuesday': 'Mar',
'wednesday': 'Mié',
'thursday': 'Jue',
'friday': 'Vie',
'saturday': 'Sáb',
'sunday': 'Dom'
};
return {
days: days.map(day => dayMap[day.toLowerCase()] || day),
count: days.length
};
}
formatMonths(months: string[]): any {
if (!months || months.length === 0) return null;
const monthMap: { [key: string]: string } = {
'january': 'Ene',
'february': 'Feb',
'march': 'Mar',
'april': 'Abr',
'may': 'May',
'june': 'Jun',
'july': 'Jul',
'august': 'Ago',
'september': 'Sep',
'october': 'Oct',
'november': 'Nov',
'december': 'Dic'
};
return {
months: months.map(month => monthMap[month.toLowerCase()] || month),
count: months.length
};
}
}