feat(core,api): Детали по заданиями роботов
This commit is contained in:
@@ -10,6 +10,8 @@ using PARR.Core.Services.NextRunServices;
|
||||
using PARR.Core.Services.NextRunServices.Subservices;
|
||||
using PARR.Core.Services.RobotMetrics;
|
||||
using PARR.Core.Services.RobotSnapshotServices;
|
||||
using PARR.Core.Services.RobotStatusDetails.Implementations;
|
||||
using PARR.Core.Services.RobotStatusDetails.Interfaces;
|
||||
using PARR.Core.Services.RobotTask.Implementations;
|
||||
using PARR.Core.Services.RobotTask.Interfaces;
|
||||
using PARR.Core.Services.RobotTaskDetailsServices.Implementations;
|
||||
@@ -117,6 +119,7 @@ namespace PARR.Core
|
||||
services.AddScoped<IRobotSnapshotService, RobotSnapshotService>();
|
||||
services.AddScoped<IRobotTaskRobotStatusService, RobotTaskRobotStatusService>();
|
||||
services.AddScoped<IRobotTaskDetailsService, RobotTaskDetailsService>();
|
||||
services.AddScoped<IRobotStatusDetailsService, RobotStatusDetailsService>();
|
||||
|
||||
services.AddScoped<IUnitService, UnitService>();
|
||||
services.AddScoped<UnitCacheService>();
|
||||
|
||||
@@ -25,8 +25,4 @@
|
||||
<!-- Разрешаем Castle DynamicProxy (Moq / NSubstitute) видеть internal классы PARR.Core -->
|
||||
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Services\RobotStatusDetails\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using PARR.Core.Repositories.Interfaces;
|
||||
using PARR.Core.Services.RobotStatusDetails.Interfaces;
|
||||
using PARR.Domain.DTOs.RobotStatusDetails;
|
||||
using PARR.Domain.DTOs.Shared;
|
||||
using PARR.Domain.Enums;
|
||||
using PARR.Domain.Exceptions;
|
||||
|
||||
namespace PARR.Core.Services.RobotStatusDetails.Implementations
|
||||
{
|
||||
internal class RobotStatusDetailsService : IRobotStatusDetailsService
|
||||
{
|
||||
private readonly ILogger<RobotStatusDetailsService> _logger;
|
||||
private readonly IRobotConfigurationRepository _robotConfigurationRepository;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly IRobotRepository _robotRepository;
|
||||
private readonly IRobotStatusRepository _robotStatusRepository;
|
||||
|
||||
public RobotStatusDetailsService(
|
||||
ILogger<RobotStatusDetailsService> logger,
|
||||
IRobotConfigurationRepository robotConfigurationRepository,
|
||||
IMapper mapper,
|
||||
IRobotRepository robotRepository,
|
||||
IRobotStatusRepository robotStatusRepository
|
||||
)
|
||||
{
|
||||
_logger = logger;
|
||||
_robotConfigurationRepository = robotConfigurationRepository;
|
||||
_mapper = mapper;
|
||||
_robotRepository = robotRepository;
|
||||
_robotStatusRepository = robotStatusRepository;
|
||||
}
|
||||
|
||||
|
||||
public async Task<RobotStatusDetailsResult> GetDetailsAsync(RobotsEnum robot, RobotStatusEnum status, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var groupedDetails = await _robotConfigurationRepository.Get()
|
||||
.AsNoTracking()
|
||||
.Where(config => config.RobotCode == (int)robot && config.RobotStatusCode == (int)status)
|
||||
.GroupBy(config => config.Template!.Job!.Group)
|
||||
.Select(t => new
|
||||
{
|
||||
JobGroup = t.Key,
|
||||
TemplatesCount = t.Count()
|
||||
})
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var robotEntity = await _robotRepository.Get()
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(r => r.Code == (int)robot, cancellationToken);
|
||||
|
||||
var robotStatusEntity = await _robotStatusRepository.Get()
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(t => t.Code == (int)status, cancellationToken);
|
||||
|
||||
if (robotEntity == null)
|
||||
{
|
||||
_logger.LogWarning("Робот с кодом {RobotCode} не найден в БД", robot);
|
||||
throw new AppValidationException($"Робот с кодом {(int)robot} не найден");
|
||||
}
|
||||
|
||||
if (robotStatusEntity == null)
|
||||
{
|
||||
_logger.LogWarning("Статус робота с кодом {StatusCode} не найден в БД", status);
|
||||
throw new AppValidationException($"Статус робота с кодом {(int)status} не найден");
|
||||
}
|
||||
|
||||
var result = new RobotStatusDetailsResult
|
||||
{
|
||||
Robot = _mapper.Map<RobotResult>(robotEntity),
|
||||
Status = _mapper.Map<RobotStatusResult>(robotStatusEntity),
|
||||
Details = groupedDetails
|
||||
.Select(t => new RobotStatusGroupDetailsResult
|
||||
{
|
||||
JobGroup = _mapper.Map<JobGroupShortResult>(t.JobGroup),
|
||||
TemplatesCount = t.TemplatesCount
|
||||
}).OrderBy(t => t.JobGroup.GroupName)
|
||||
.ToList()
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using PARR.Domain.DTOs.RobotStatusDetails;
|
||||
using PARR.Domain.Enums;
|
||||
|
||||
namespace PARR.Core.Services.RobotStatusDetails.Interfaces
|
||||
{
|
||||
public interface IRobotStatusDetailsService
|
||||
{
|
||||
Task<RobotStatusDetailsResult> GetDetailsAsync(RobotsEnum robot, RobotStatusEnum status, CancellationToken cancellationToken = default);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ using PARR.Core.Services.RobotTaskDetailsServices.Interfaces;
|
||||
using PARR.Domain.DTOs.RobotTaskDetails;
|
||||
using PARR.Domain.DTOs.Shared;
|
||||
using PARR.Domain.Enums;
|
||||
using PARR.Domain.Exceptions;
|
||||
|
||||
namespace PARR.Core.Services.RobotTaskDetailsServices.Implementations
|
||||
{
|
||||
@@ -32,34 +33,55 @@ namespace PARR.Core.Services.RobotTaskDetailsServices.Implementations
|
||||
_taskStatusRepository = taskStatusRepository;
|
||||
}
|
||||
|
||||
public async Task<RobotTaskDetailsResult> GetDetailsAsync(RobotsEnum robot, TaskStatusEnum task)
|
||||
public async Task<RobotTaskDetailsResult> GetDetailsAsync(RobotsEnum robot, TaskStatusEnum task, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var details = await _robotConfigurationRepository.Get()
|
||||
.Where(t => t.RobotCode == (int)robot && t.TaskStatusCode == (int)task)
|
||||
.GroupBy(t => t.Template!.Job!.Group)
|
||||
.Select(t => new
|
||||
{
|
||||
JobGroup = t.Key,
|
||||
TemplatesCount = t.Count()
|
||||
}).ToListAsync();
|
||||
// 1. Получаем группировку конфигураций
|
||||
var groupedDetails = await _robotConfigurationRepository.Get()
|
||||
.AsNoTracking()
|
||||
.Where(config => config.RobotCode == (int)robot && config.TaskStatusCode == (int)task)
|
||||
.GroupBy(config => config.Template!.Job!.Group)
|
||||
.Select(t => new
|
||||
{
|
||||
JobGroup = t.Key,
|
||||
TemplatesCount = t.Count()
|
||||
})
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var robotObj = await _robotRepository.Get()
|
||||
// 2. Получаем сущности робота и статуса задачи)
|
||||
var robotEntity = await _robotRepository.Get()
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(t => t.Code == (int)robot);
|
||||
.FirstOrDefaultAsync(r => r.Code == (int)robot, cancellationToken);
|
||||
|
||||
var taskObj = await _taskStatusRepository.Get()
|
||||
var taskStatusEntity = await _taskStatusRepository.Get()
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(t => t.Code == (int)task);
|
||||
.FirstOrDefaultAsync(t => t.Code == (int)task, cancellationToken);
|
||||
|
||||
|
||||
if (robotEntity == null)
|
||||
{
|
||||
_logger.LogWarning("Робот с кодом {RobotCode} не найден в БД", robot);
|
||||
throw new AppValidationException($"Робот с кодом {(int)robot} не найден");
|
||||
}
|
||||
|
||||
if (taskStatusEntity == null)
|
||||
{
|
||||
_logger.LogWarning("Статус задачи с кодом {TaskCode} не найден в БД", task);
|
||||
throw new AppValidationException($"Статус задачи с кодом {(int)task} не найден");
|
||||
}
|
||||
|
||||
// 3. Маппинг и сборка результирующего DTO
|
||||
var result = new RobotTaskDetailsResult
|
||||
{
|
||||
Robot = _mapper.Map<RobotResult>(robotObj),
|
||||
Task = _mapper.Map<RobotTaskStatusResult>(taskObj),
|
||||
Details = details.Select(t => new RobotTaskGroupDetailsResult
|
||||
{
|
||||
JobGroup = _mapper.Map<JobGroupShortResult>(t.JobGroup),
|
||||
TemplatesCount = t.TemplatesCount
|
||||
}).OrderBy(t => t.JobGroup.GroupName).ToList()
|
||||
Robot = _mapper.Map<RobotResult>(robotEntity),
|
||||
Task = _mapper.Map<RobotTaskStatusResult>(taskStatusEntity),
|
||||
Details = groupedDetails
|
||||
.Select(t => new RobotTaskGroupDetailsResult
|
||||
{
|
||||
JobGroup = _mapper.Map<JobGroupShortResult>(t.JobGroup),
|
||||
TemplatesCount = t.TemplatesCount
|
||||
})
|
||||
.OrderBy(d => d.JobGroup.GroupName)
|
||||
.ToList()
|
||||
};
|
||||
|
||||
return result;
|
||||
|
||||
@@ -11,6 +11,6 @@ namespace PARR.Core.Services.RobotTaskDetailsServices.Interfaces
|
||||
/// <param name="robot"></param>
|
||||
/// <param name="task"></param>
|
||||
/// <returns></returns>
|
||||
Task<RobotTaskDetailsResult> GetDetailsAsync(RobotsEnum robot, TaskStatusEnum task);
|
||||
Task<RobotTaskDetailsResult> GetDetailsAsync(RobotsEnum robot, TaskStatusEnum task, CancellationToken cancellationToken = default);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user