diff --git a/backend/src/main/java/core/api/controller/StatisticController.java b/backend/src/main/java/core/api/controller/StatisticController.java index 54f6a53..8afa704 100644 --- a/backend/src/main/java/core/api/controller/StatisticController.java +++ b/backend/src/main/java/core/api/controller/StatisticController.java @@ -22,6 +22,7 @@ public class StatisticController { @Autowired private TaskScheduleService taskScheduleService; @Autowired private StatisticService statisticService; + @Autowired private TaskgroupService taskgroupService; @GetMapping("/history/workingStatus") public ResponseEntity getWorkingStatus() { @@ -44,7 +45,22 @@ public class StatisticController { LocalDate starting = LocalDate.parse(startingDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")); LocalDate ending = LocalDate.parse(endingDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")); - var taskgroupActivityInfos = statisticService.calcActivityByUser(SecurityContextHolder.getContext().getAuthentication().getName(), starting, ending); + var taskgroupActivityInfos = statisticService.calcActivityByUser(null, SecurityContextHolder.getContext().getAuthentication().getName(), starting, ending); + List outgoingResult = StatisticService.convertInternActivityInfo(taskgroupActivityInfos); + return ResponseEntity.ok(outgoingResult); + } + + @GetMapping("/statistics/{taskgroupID}/{startingDate}/{endingDate}") + public ResponseEntity getTaskgroupActivity(@PathVariable long taskgroupID, @PathVariable String startingDate, @PathVariable String endingDate){ + LocalDate starting = LocalDate.parse(startingDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")); + LocalDate ending = LocalDate.parse(endingDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")); + String username = SecurityContextHolder.getContext().getAuthentication().getName(); + var permissionResult = taskgroupService.getTaskgroupByIDAndUsername(taskgroupID, username); + if(permissionResult.hasIssue()) { + return permissionResult.mapToResponseEntity(); + } + + var taskgroupActivityInfos = statisticService.calcActivityByUser(permissionResult.getResult(), username, starting, ending); List outgoingResult = StatisticService.convertInternActivityInfo(taskgroupActivityInfos); return ResponseEntity.ok(outgoingResult); } diff --git a/backend/src/main/java/core/services/StatisticService.java b/backend/src/main/java/core/services/StatisticService.java index 36f29f0..2a6fddc 100644 --- a/backend/src/main/java/core/services/StatisticService.java +++ b/backend/src/main/java/core/services/StatisticService.java @@ -21,11 +21,24 @@ public class StatisticService { @Autowired private ScheduleRepository scheduleRepository; - public HashMap> calcActivityByUser(String username, LocalDate startinDate, LocalDate endingDate) { + public HashMap> calcActivityByUser(Taskgroup taskgroup, String username, LocalDate startinDate, LocalDate endingDate) { HashMap> taskgroupActivityInfos = new HashMap<>(); List startedSchedules = scheduleRepository.getAllFinishedSchedulesByUser(username); for(AbstractSchedule schedule : startedSchedules) { - Taskgroup topTaskgroup = findTopTaskgroup(schedule.getTask().getTaskgroup()); + if(schedule.getStartTime().toLocalDate().isAfter(endingDate) || schedule.getStopTime().toLocalDate().isBefore(startinDate)) { + continue; + } + + Taskgroup topTaskgroup; + if(taskgroup == null) { + topTaskgroup = findTopTaskgroup(schedule.getTask().getTaskgroup()); + } else { + topTaskgroup = findTaskgroupOfLayer(taskgroup, schedule.getTask().getTaskgroup()); + if(topTaskgroup == null) { + continue; + } + } + HashMap taskgroupActivity; if(taskgroupActivityInfos.containsKey(topTaskgroup)) { taskgroupActivity = taskgroupActivityInfos.get(topTaskgroup); @@ -81,4 +94,20 @@ public class StatisticService { } return currentTaskgroup; } + + private Taskgroup findTaskgroupOfLayer(Taskgroup targetLayer, Taskgroup childTaskgroup) { + if(targetLayer.getTaskgroupID() == childTaskgroup.getTaskgroupID()) { + return childTaskgroup; + } + + Taskgroup currentTaskgroup = childTaskgroup; + while (currentTaskgroup.getParent() != null && currentTaskgroup.getParent().getTaskgroupID() != targetLayer.getTaskgroupID()) { + currentTaskgroup = currentTaskgroup.getParent(); + } + + if(currentTaskgroup.getParent() == null) { + return null; + } + return currentTaskgroup; + } } diff --git a/frontend/src/api/api/history.service.ts b/frontend/src/api/api/history.service.ts index f567d47..794a3ed 100644 --- a/frontend/src/api/api/history.service.ts +++ b/frontend/src/api/api/history.service.ts @@ -263,4 +263,69 @@ export class HistoryService { ); } + /** + * @param taskgroupID internal id of taskgroup + * @param startingDate starting date + * @param endingDate starting date + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public statisticsTaskgroupIDStartingDateEndingDateGet(taskgroupID: number, startingDate: string, endingDate: string, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>; + public statisticsTaskgroupIDStartingDateEndingDateGet(taskgroupID: number, startingDate: string, endingDate: string, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>>; + public statisticsTaskgroupIDStartingDateEndingDateGet(taskgroupID: number, startingDate: string, endingDate: string, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable>>; + public statisticsTaskgroupIDStartingDateEndingDateGet(taskgroupID: number, startingDate: string, endingDate: string, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json', context?: HttpContext}): Observable { + if (taskgroupID === null || taskgroupID === undefined) { + throw new Error('Required parameter taskgroupID was null or undefined when calling statisticsTaskgroupIDStartingDateEndingDateGet.'); + } + if (startingDate === null || startingDate === undefined) { + throw new Error('Required parameter startingDate was null or undefined when calling statisticsTaskgroupIDStartingDateEndingDateGet.'); + } + if (endingDate === null || endingDate === undefined) { + throw new Error('Required parameter endingDate was null or undefined when calling statisticsTaskgroupIDStartingDateEndingDateGet.'); + } + + let localVarHeaders = this.defaultHeaders; + + let localVarCredential: string | undefined; + // authentication (API_TOKEN) required + localVarCredential = this.configuration.lookupCredential('API_TOKEN'); + if (localVarCredential) { + localVarHeaders = localVarHeaders.set('Authorization', 'Bearer ' + localVarCredential); + } + + let localVarHttpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept; + if (localVarHttpHeaderAcceptSelected === undefined) { + // to determine the Accept header + const httpHeaderAccepts: string[] = [ + 'application/json' + ]; + localVarHttpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts); + } + if (localVarHttpHeaderAcceptSelected !== undefined) { + localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected); + } + + let localVarHttpContext: HttpContext | undefined = options && options.context; + if (localVarHttpContext === undefined) { + localVarHttpContext = new HttpContext(); + } + + + let responseType_: 'text' | 'json' = 'json'; + if(localVarHttpHeaderAcceptSelected && localVarHttpHeaderAcceptSelected.startsWith('text')) { + responseType_ = 'text'; + } + + return this.httpClient.get>(`${this.configuration.basePath}/statistics/${encodeURIComponent(String(taskgroupID))}/${encodeURIComponent(String(startingDate))}/${encodeURIComponent(String(endingDate))}`, + { + context: localVarHttpContext, + responseType: responseType_, + withCredentials: this.configuration.withCredentials, + headers: localVarHeaders, + observe: observe, + reportProgress: reportProgress + } + ); + } + } diff --git a/frontend/src/app/statistics/taskgroup-activity/simple-activity-diagram/simple-activity-diagram.component.ts b/frontend/src/app/statistics/taskgroup-activity/simple-activity-diagram/simple-activity-diagram.component.ts index 64ebb50..e912f58 100644 --- a/frontend/src/app/statistics/taskgroup-activity/simple-activity-diagram/simple-activity-diagram.component.ts +++ b/frontend/src/app/statistics/taskgroup-activity/simple-activity-diagram/simple-activity-diagram.component.ts @@ -2,7 +2,7 @@ import {Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild} from '@an import {FormControl} from "@angular/forms"; import {ChangeContext, LabelType, Options} from "ngx-slider-v2"; import {ApexAxisChartSeries, ChartComponent, ChartType} from "ng-apexcharts"; -import {HistoryService, TaskgroupPathInfo, TaskgroupService} from "../../../../api"; +import {HistoryService, TaskgroupActivityInfo, TaskgroupPathInfo, TaskgroupService} from "../../../../api"; import * as moment from "moment/moment"; import {ChartOptions} from "../taskgroup-activity.component"; @@ -32,51 +32,77 @@ export class SimpleActivityDiagramComponent implements OnChanges { @ViewChild("chart") chart?: ChartComponent; - series: ApexAxisChartSeries = [] chartOptions: Partial | undefined; constructor(private taskgroupService: TaskgroupService, private historyService: HistoryService) { } ngOnChanges() { - this.series = []; + this.fetchData() + } + + fetchData() { const startingDate = moment(this.dateRange[0]).format("yyyy-MM-DD"); const endingDate = moment(this.dateRange[this.dateRange.length-1]).format("yyyy-MM-DD"); - this.historyService.statisticsStartingDateEndingDateGet(startingDate, endingDate).subscribe({ - next: resp => { - resp.forEach(taskgroupActivityInfo => { - const data: any[] = []; - this.dateRange.map(date => { - const selectedActivity = taskgroupActivityInfo.activityInfos.find(activity => moment(date).isSame(moment(activity.date), "day")) - if(selectedActivity != undefined) { - data.push(selectedActivity.activeMinutes) - } else { - data.push(0) - } - }) - this.series.push({ - name: taskgroupActivityInfo.taskgroup.taskgroupName, - data: data - }) - }) - - this.chartOptions = { - series: this.series, - chart: { - height: 350, - type: this.selectedChartype as ChartType, - stacked: true - }, - title: { - text: "" - }, - xaxis: { - categories: this.selectedDateRange.map(date => date.toDateString()) - } + if(this.selectedTaskgroupPath == undefined) { + this.historyService.statisticsStartingDateEndingDateGet(startingDate, endingDate).subscribe({ + next: resp => { + const series = this.createChartSeries(resp); + this.chartOptions = this.createChartOptions(series); } - } + }) + } else { + this.historyService.statisticsTaskgroupIDStartingDateEndingDateGet( + this.selectedTaskgroupPath.rootTasktroup.taskgroupID, + startingDate, + endingDate + ).subscribe({ + next: resp => { + const series = this.createChartSeries(resp); + this.chartOptions = this.createChartOptions(series) + } + }) + } + } + + createChartSeries(data: TaskgroupActivityInfo[]) { + const series: ApexAxisChartSeries = []; + data.forEach(taskgroupActivityInfo => { + const data: any[] = []; + this.dateRange.map(date => { + const selectedActivity = taskgroupActivityInfo.activityInfos.find(activity => moment(date).isSame(moment(activity.date), "day")) + if(selectedActivity != undefined) { + data.push(selectedActivity.activeMinutes) + } else { + data.push(0) + } + }) + + series.push({ + name: taskgroupActivityInfo.taskgroup.taskgroupName, + data: data + }) }) + + return series; + } + + createChartOptions(series: any[] = []) { + return { + series: series, + chart: { + height: 350, + type: this.selectedChartype as ChartType, + stacked: true + }, + title: { + text: "" + }, + xaxis: { + categories: this.selectedDateRange.map(date => date.toDateString()) + } + } } createDateRange(): Date[] {