diff --git a/Backend/src/main/java/unical/demacs/rdm/controller/JsonController.java b/Backend/src/main/java/unical/demacs/rdm/controller/JsonController.java index 7b0783a..715e488 100644 --- a/Backend/src/main/java/unical/demacs/rdm/controller/JsonController.java +++ b/Backend/src/main/java/unical/demacs/rdm/controller/JsonController.java @@ -102,7 +102,11 @@ public ResponseEntity> importMachine(@RequestBody List> exportMachine() { List machines = machineService.getAllMachines(); - return ResponseEntity.ok(modelMapperExtended.mapList(machines, MachineDTO.class)); + List list = modelMapperExtended.mapList(machines, MachineDTO.class); + for(int i = 0; i< list.size(); i++){ + list.get(i).setTypeId(machines.get(i).getMachine_type_id().getId()); + } + return ResponseEntity.ok(list); } diff --git a/Frontend/src/app/components/graphs/graphs.component.html b/Frontend/src/app/components/graphs/graphs.component.html index 7f73e7f..9da8b64 100644 --- a/Frontend/src/app/components/graphs/graphs.component.html +++ b/Frontend/src/app/components/graphs/graphs.component.html @@ -35,5 +35,14 @@

No data available for the status chart.

- +
+ + +

No data available for the machine jobs chart.

+ diff --git a/Frontend/src/app/components/graphs/graphs.component.ts b/Frontend/src/app/components/graphs/graphs.component.ts index 16d68f8..10998cf 100644 --- a/Frontend/src/app/components/graphs/graphs.component.ts +++ b/Frontend/src/app/components/graphs/graphs.component.ts @@ -122,6 +122,43 @@ export class GraphsComponent implements OnInit { } }; + machineJobsChart = { + type: ChartType.LineChart, + data: [] as [string, number, number, number][], + columns: ['Macchina', 'Schedulati', 'In Progresso', 'Completati'], + options: { + title: 'Job per Specifica Macchina', + width: 650, + height: 450, + colors: ['#F39C12', '#3498DB', '#2ECC71'], + fontSize: 12, + fontName: 'Roboto', + titleTextStyle: { + fontSize: 18, + bold: true, + color: '#2C3E50' + }, + backgroundColor: { + fill: '#FFFFFF' + }, + hAxis: { + title: 'Macchine', + titleTextStyle: { color: '#2C3E50', italic: false }, + textStyle: { color: '#2C3E50' } + }, + vAxis: { + title: 'Numero di Job', + titleTextStyle: { color: '#2C3E50', italic: false }, + textStyle: { color: '#2C3E50' } + }, + animation: { + startup: true, + duration: 1000, + easing: 'out' + } + } + }; + isLoading = false; jobs: any[] = []; machineTypes: any[] = []; @@ -138,35 +175,52 @@ export class GraphsComponent implements OnInit { loadJobs(): void { this.isLoading = true; + forkJoin({ jobs: this.jobService.getAllJobs(), types: this.jsonService.exportMachineType(), - scheduledJobs: this.jsonService.exportJobScheduledDueDate() + machine: this.jsonService.exportMachine(), + scheduledDueDateJobs: this.jsonService.exportJobScheduledDueDate(), + scheduledDurationJobs: this.jsonService.exportJobScheduledDuration(), + scheduledPriorityJobs: this.jsonService.exportJobScheduledPriority() }).subscribe({ next: async (response) => { const jobDTOs = Array.isArray(response.jobs) ? (response.jobs as JobDTO[]) : []; - const scheduledJobDTOs = Array.isArray(response.scheduledJobs) ? (response.scheduledJobs as ScheduleDTO[]) : []; - + const scheduledDueDateJobs = Array.isArray(response.scheduledDueDateJobs) ? (response.scheduledDueDateJobs as ScheduleDTO[]) : []; + const scheduledDurationJobs = Array.isArray(response.scheduledDurationJobs) ? (response.scheduledDurationJobs as ScheduleDTO[]) : []; + const scheduledPriorityJobs = Array.isArray(response.scheduledPriorityJobs) ? (response.scheduledPriorityJobs as ScheduleDTO[]) : []; + const allScheduledJobs = [ + ...scheduledDueDateJobs, + ...scheduledDurationJobs, + ...scheduledPriorityJobs + ]; + const scheduledJobDTOs = Array.from( + new Map(allScheduledJobs.map(job => [job.jobId, job])).values() + ); + const scheduledJobIds = new Set(scheduledJobDTOs.map(scheduleDto => scheduleDto.jobId)); const combinedJobs = [ - ...jobDTOs.map(dto => ({ - id: dto.id!, - title: dto.title, - description: dto.description, - status: dto.status, - priority: dto.priority, - duration: dto.duration, - idMachineType: dto.idMachineType, - assigneeEmail: this.loginService.getUserEmail()! - })), + ...jobDTOs + .filter(dto => !scheduledJobIds.has(dto.id)) + .map(dto => ({ + id: dto.id!, + title: dto.title, + description: dto.description, + status: dto.status, + priority: dto.priority, + duration: dto.duration, + idMachineType: dto.idMachineType, + assigneeEmail: this.loginService.getUserEmail()! + })), ...scheduledJobDTOs.map(scheduleDto => { const matchingJob = jobDTOs.find(job => job.id === scheduleDto.jobId); - return { id: scheduleDto.id!, title: matchingJob?.title || 'Scheduled Job', - status: 'SCHEDULED', + status: scheduleDto.status || matchingJob?.status || 'SCHEDULED', priority: matchingJob?.priority, duration: scheduleDto.duration, + machineId: scheduleDto.assignedMachineId, + machineName: scheduleDto.assignedMachineName, idMachineType: scheduleDto.machineTypeId, dueDate: scheduleDto.dueDate, startTime: scheduleDto.startTime @@ -175,11 +229,13 @@ export class GraphsComponent implements OnInit { ]; const types = this.transformMachineTypes(response.types); + const machines = this.transformMachine(response.machine); this.machineTypes = types; const scheduledJobs = combinedJobs.filter(job => job.status === 'SCHEDULED'); this.pieChart.data = this.aggregateMachineTypes(scheduledJobs, types); this.barChart.data = this.prepareBarChartData(combinedJobs); this.statusChart.data = this.prepareStatusChartData(combinedJobs); + this.machineJobsChart.data = this.prepareMachineJobsChartData(scheduledJobDTOs, machines); this.isLoading = false; }, @@ -191,6 +247,7 @@ export class GraphsComponent implements OnInit { }); } + private prepareBarChartData(jobs: any[]): [string, number, number][] { const jobStatusCounts: { [key: string]: { completed: number, scheduled: number } } = {}; @@ -217,10 +274,19 @@ export class GraphsComponent implements OnInit { private transformMachineTypes(types: any): any[] { return Array.isArray(types) ? types.map(type => ({ - id: type.id, - name: type.name, - usageCount: typeof type.usageCount === 'number' ? type.usageCount : 0 - })) + id: type.id, + name: type.name, + usageCount: typeof type.usageCount === 'number' ? type.usageCount : 0 + })) + : []; + } + + private transformMachine(machines: any): any[] { + return Array.isArray(machines) + ? machines.map(machine => ({ + id: machine.id, + name: machine.name + })) : []; } @@ -270,6 +336,46 @@ export class GraphsComponent implements OnInit { return aggregatedData; } + private prepareMachineJobsChartData(scheduledJobs: any[], machines: any[]): [string, number, number, number][] { + console.log(scheduledJobs); + const machineIdToNameMap: { [key: string]: string } = {}; + machines.forEach(machine => { + machineIdToNameMap[machine.id] = machine.name; + }); + + const machineJobCounts: { [key: string]: { scheduled: number, inProgress: number, completed: number } } = {}; + + scheduledJobs.forEach(job => { + const machineName = job.machineName || machineIdToNameMap[job.machineId] || `Machine ${job.machineId}`; + + if (!machineJobCounts[machineName]) { + machineJobCounts[machineName] = { scheduled: 0, inProgress: 0, completed: 0 }; + } + switch (job.status) { + case 'SCHEDULED': + machineJobCounts[machineName].scheduled++; + break; + case 'IN_PROGRESS': + machineJobCounts[machineName].inProgress++; + break; + case 'COMPLETED': + machineJobCounts[machineName].completed++; + break; + } + }); + const chartData: [string, number, number, number][] = Object.entries(machineJobCounts) + .map(([machineName, counts]) => [ + machineName, + counts.scheduled, + counts.inProgress, + counts.completed + ]); + if (chartData.length === 0) { + chartData.push(['No Machines', 0, 0, 0]); + } + return chartData; + } + private showMessage(message: string): void { alert(message); }