diff --git a/PARR.API/Contracts/V1/ApiRoutes.cs b/PARR.API/Contracts/V1/ApiRoutes.cs index ce4b5288..870afec2 100644 --- a/PARR.API/Contracts/V1/ApiRoutes.cs +++ b/PARR.API/Contracts/V1/ApiRoutes.cs @@ -22,6 +22,11 @@ namespace PARR.API.Contracts.V1 public const string Base = Root + "/" + Version; + /// + /// Статистика + /// + public const string BaseStat = Base + "/statistics"; + public static class ApiStatus { public const string Version = Base + "/version"; @@ -160,6 +165,20 @@ namespace PARR.API.Contracts.V1 #endregion + #region Статистика + + public static class StatRobotTask + { + public const string Get = BaseStat + "/robot-tasks/"; + } + + public static class StatRobotStatus + { + public const string Get = BaseStat + "/robot-statuses/"; + } + + #endregion + } } diff --git a/PARR.API/Contracts/V1/Responses/Statistics/StatRobotStatusResponse.cs b/PARR.API/Contracts/V1/Responses/Statistics/StatRobotStatusResponse.cs new file mode 100644 index 00000000..ffab340b --- /dev/null +++ b/PARR.API/Contracts/V1/Responses/Statistics/StatRobotStatusResponse.cs @@ -0,0 +1,14 @@ +namespace PARR.API.Contracts.V1.Responses.Statistics +{ + public class StatRobotStatusResponse + { + public RobotResponse? Robot { get; set; } + public List Statistics { get; set; } = new List(); + } + + public class StatRobotStatusItemResponse + { + public RobotStatusResponse? Status { get; set; } + public int Count { get; set; } + } +} diff --git a/PARR.API/Contracts/V1/Responses/Statistics/StatRobotTaskResponse.cs b/PARR.API/Contracts/V1/Responses/Statistics/StatRobotTaskResponse.cs new file mode 100644 index 00000000..a3455675 --- /dev/null +++ b/PARR.API/Contracts/V1/Responses/Statistics/StatRobotTaskResponse.cs @@ -0,0 +1,14 @@ +namespace PARR.API.Contracts.V1.Responses.Statistics +{ + public class StatRobotTaskResponse + { + public RobotResponse? Robot { get; set; } + public List Statistics { get; set; } = new List(); + } + + public class StatRobotTasksResponse + { + public TaskStatusResponse? Status { get; set; } + public int Count { get; set; } + } +} diff --git a/PARR.API/Controllers/V1/Statistics/StatRobotStatusController.cs b/PARR.API/Controllers/V1/Statistics/StatRobotStatusController.cs new file mode 100644 index 00000000..9d57f9f6 --- /dev/null +++ b/PARR.API/Controllers/V1/Statistics/StatRobotStatusController.cs @@ -0,0 +1,76 @@ +using AutoMapper; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using PARR.API.Contracts.V1; +using PARR.API.Contracts.V1.Responses; +using PARR.API.Contracts.V1.Responses.Base; +using PARR.API.Contracts.V1.Responses.Statistics; +using PARR.API.Controllers.V1.Base; +using PARR.Constants; +using PARR.DAL.Services.Interfaces; + +namespace PARR.API.Controllers.V1.Statistics +{ + /// + /// Статистика выполняения заданий роботами, по полю RobotConfigurations.RobotStatusCode + /// + [Authorize(Roles = ParrRoles.Administrator.Role)] + public class StatRobotStatusController : BaseApiController + { + private readonly IRobotService robotService; + private readonly IRobotConfigurationService robotConfigurationService; + private readonly IRobotStatusService robotStatusService; + private readonly IMapper mapper; + + public StatRobotStatusController( + IRobotService robotService, + IRobotConfigurationService robotConfigurationService, + IRobotStatusService robotStatusService, + IMapper mapper + ) + { + this.robotService = robotService; + this.robotConfigurationService = robotConfigurationService; + this.robotStatusService = robotStatusService; + this.mapper = mapper; + } + + /// + /// Статистика работы роботов + /// + /// + [HttpGet(ApiRoutes.StatRobotStatus.Get)] + public async Task Get() + { + var confStat = await robotConfigurationService.Get() + .GroupBy(t => new { t.RobotCode, t.RobotStatusCode }) + .Select(t => new { RobotCode = t.Key.RobotCode, RobotStatusCode = t.Key.RobotStatusCode, Count = t.Count() }) + .ToListAsync(); + + var robots = await robotService.Get().ToListAsync(); + var robotStatuses = await robotStatusService.Get().ToListAsync(); + + var response = new List(); + + foreach (var robot in robots) + { + var item = new StatRobotStatusResponse { Robot = mapper.Map(robot) }; + robotStatuses.ForEach(stat => + { + item.Statistics.Add(new StatRobotStatusItemResponse + { + Status = mapper.Map(stat), + Count = confStat.FirstOrDefault(t => t.RobotStatusCode == stat.Code && t.RobotCode == robot.Code)?.Count ?? 0 + }); + }); + item.Statistics = item.Statistics.OrderByDescending(t => t.Status?.Code).ToList(); + response.Add(item); + } + + response = response.OrderBy(t => t.Robot?.Code).ToList(); + + return Ok(new Response>(response, true)); + } + } +} diff --git a/PARR.API/Controllers/V1/Statistics/StatRobotTaskController.cs b/PARR.API/Controllers/V1/Statistics/StatRobotTaskController.cs new file mode 100644 index 00000000..4bd26c13 --- /dev/null +++ b/PARR.API/Controllers/V1/Statistics/StatRobotTaskController.cs @@ -0,0 +1,76 @@ +using AutoMapper; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using PARR.API.Contracts.V1; +using PARR.API.Contracts.V1.Responses; +using PARR.API.Contracts.V1.Responses.Base; +using PARR.API.Contracts.V1.Responses.Statistics; +using PARR.API.Controllers.V1.Base; +using PARR.Constants; +using PARR.DAL.Services.Interfaces; + +namespace PARR.API.Controllers.V1.Statistics +{ + /// + /// Статистика по заданиям для робота, по полю RobotConfigurations.TaskStatusCode + /// + [Authorize(Roles = ParrRoles.Administrator.Role)] + public class StatRobotTaskController : BaseApiController + { + private readonly IRobotService robotService; + private readonly IRobotConfigurationService robotConfigurationService; + private readonly ITaskStatusService taskStatusService; + private readonly IMapper mapper; + + public StatRobotTaskController( + IRobotService robotService, + IRobotConfigurationService robotConfigurationService, + ITaskStatusService taskStatusService, + IMapper mapper + ) + { + this.robotService = robotService; + this.robotConfigurationService = robotConfigurationService; + this.taskStatusService = taskStatusService; + this.mapper = mapper; + } + + /// + /// Статистика по заданиям для роботов + /// + /// + [HttpGet(ApiRoutes.StatRobotTask.Get)] + public async Task Get() + { + var confStat = await robotConfigurationService.Get() + .GroupBy(t => new { t.RobotCode, t.TaskStatusCode }) + .Select(t => new { RobotCode = t.Key.RobotCode, TaskStatusCode = t.Key.TaskStatusCode, Count = t.Count() }) + .ToListAsync(); + + var robots = await robotService.Get().ToListAsync(); + var statuses = await taskStatusService.Get().ToListAsync(); + + var response = new List(); + + foreach (var robot in robots) + { + var item = new StatRobotTaskResponse { Robot = mapper.Map(robot) }; + statuses.ForEach(stat => + { + item.Statistics.Add(new StatRobotTasksResponse + { + Status = mapper.Map(stat), + Count = confStat.FirstOrDefault(t => t.TaskStatusCode == stat.Code && t.RobotCode == robot.Code)?.Count ?? 0 + }); + }); + item.Statistics = item.Statistics.OrderBy(t => t.Status?.Code).ToList(); + response.Add(item); + } + + response = response.OrderBy(t => t.Robot?.Code).ToList(); + + return Ok(new Response>(response, true)); + } + } +} diff --git a/PARR.DAL/ParrDalInstaller.cs b/PARR.DAL/ParrDalInstaller.cs index 851fd9cc..8ef0c90c 100644 --- a/PARR.DAL/ParrDalInstaller.cs +++ b/PARR.DAL/ParrDalInstaller.cs @@ -64,6 +64,7 @@ namespace PARR.DAL services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); // TransformServices services.AddTransient(); diff --git a/PARR.DAL/Services/Implementations/TaskStatusService.cs b/PARR.DAL/Services/Implementations/TaskStatusService.cs new file mode 100644 index 00000000..21f10faf --- /dev/null +++ b/PARR.DAL/Services/Implementations/TaskStatusService.cs @@ -0,0 +1,20 @@ +using PARR.DAL.Context; +using PARR.DAL.Services.Interfaces; + +namespace PARR.DAL.Services.Implementations +{ + internal class TaskStatusService : ITaskStatusService + { + private readonly DataContext dataContext; + + public TaskStatusService(DataContext dataContext) + { + this.dataContext = dataContext; + } + + public IQueryable Get() + { + return dataContext.TaskStatuses; + } + } +} diff --git a/PARR.DAL/Services/Interfaces/ITaskStatusService.cs b/PARR.DAL/Services/Interfaces/ITaskStatusService.cs new file mode 100644 index 00000000..bb4d330d --- /dev/null +++ b/PARR.DAL/Services/Interfaces/ITaskStatusService.cs @@ -0,0 +1,7 @@ +namespace PARR.DAL.Services.Interfaces +{ + public interface ITaskStatusService + { + IQueryable Get(); + } +}