2025-07-01 17:20:48 +10:00
using AutoMapper ;
using FluentValidation ;
using Microsoft.AspNetCore.Authorization ;
using Microsoft.AspNetCore.Mvc ;
using Microsoft.EntityFrameworkCore ;
using PARR.API.Contracts.V1 ;
using PARR.API.Contracts.V1.Requests ;
using PARR.API.Contracts.V1.Requests.Queries ;
using PARR.API.Contracts.V1.Responses ;
using PARR.API.Contracts.V1.Responses.Base ;
using PARR.API.Controllers.V1.Base ;
using PARR.API.Extensions ;
using PARR.API.Services.Interfaces ;
using PARR.Constants ;
using PARR.DAL.Contracts ;
using PARR.DAL.DomainModels ;
using PARR.DAL.Models.Job ;
using PARR.DAL.Services.Interfaces ;
using PARR.DAL.Services.Interfaces.Job ;
namespace PARR.API.Controllers.V1
{
/// <summary>
/// Управление работами
/// </summary>
[Authorize(Roles = ParrRoles.Administrator.Role)]
public class JobController : BaseApiController
{
private readonly ILogger < JobController > logger ;
private readonly IMapper mapper ;
private readonly IUriService uriService ;
private readonly IJobService jobService ;
private readonly ITemplateService templateService ;
private readonly IValidator < JobRequest > validator ;
public JobController (
ILogger < JobController > logger ,
IMapper mapper ,
IUriService uriService ,
IJobService jobService ,
ITemplateService templateService ,
IValidator < JobRequest > validator
)
{
this . logger = logger ;
this . mapper = mapper ;
this . uriService = uriService ;
this . jobService = jobService ;
this . templateService = templateService ;
this . validator = validator ;
}
/// <summary>
/// Получить список заданий на выполнение работ(Job) постранично
/// </summary>
/// <returns></returns>
[HttpGet(ApiRoutes.Job.GetAll)]
public async Task < IActionResult > GetAll ( [ FromQuery ] PaginationQuery paginationQuery , [ FromQuery ] JobQuery filter )
{
var paginationFilter = mapper . Map < PaginationFilter > ( paginationQuery ) ;
2025-08-22 11:25:51 +10:00
IQueryable < Job > query = jobService . Get ( ) . Include ( t = > t . Tnk ) . Include ( t = > t . Group ) ;
2025-07-01 17:20:48 +10:00
query = query . OrderBy ( t = > t . Name ) ;
if ( ! string . IsNullOrEmpty ( filter . Name ) )
query = query . Where ( t = > t . Name . ToLower ( ) . Contains ( filter . Name . ToLower ( ) ) ) ;
if ( filter . GroupId . HasValue )
query = query . Where ( t = > t . GroupId = = filter . GroupId . Value ) ;
var jobs = await jobService . GetPage ( query , paginationFilter ) . ToListAsync ( ) ;
if ( ! jobs . Any ( ) )
return NoContent ( ) ;
var response = mapper . Map < List < JobResponse > > ( jobs ) ; //TODO Migration to job
var paginationResponse = new PagedResponse < JobResponse > ( response , true ) . GetPaginatedProps ( paginationFilter , query ) ;
return Ok ( paginationResponse ) ;
}
/// <summary>
/// Получить задание на выполнение работ по id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet(ApiRoutes.Job.Get)]
public async Task < IActionResult > GetById ( [ FromRoute ] Guid id )
{
var job = await jobService . Get ( ) . Include ( t = > t . Tnk ) . FirstOrDefaultAsync ( t = > t . Id = = id ) ;
if ( job = = null )
return NotFound ( ) ;
var response = mapper . Map < JobResponse > ( job ) ;
response . TemplatesCount = await templateService . Get ( ) . CountAsync ( t = > t . JobId = = id ) ;
var statistics = await GetStatisticsAsync ( response . Id ) ;
BindStatistics ( response , statistics ) ;
return Ok ( new Response < JobResponse > ( response , true ) ) ;
}
/// <summary>
/// Создать задание на выполнение работ (Job)
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost(ApiRoutes.Job.Create)]
public async Task < IActionResult > Create ( [ FromBody ] JobRequest request )
{
var resultValidate = await validator . ValidateAsync ( request ) ;
if ( ! resultValidate . IsValid )
return BadRequest ( new Response ( resultValidate . Errors ) ) ;
var job = new Job
{
Id = Guid . NewGuid ( ) ,
Name = request . Name . Trim ( ) ,
WorkName = request . WorkName . Trim ( ) ,
MinValueRelationships = request . MinValueRelationships ,
MaxValueRelationships = request . MaxValueRelationships ,
2025-08-22 11:25:51 +10:00
isParentRelationships = request . isParentRelationships ,
TemplateNameMask = request . TemplateNameMask . Trim ( ) ,
WorkGroupMask = request . WorkGroupMask . Trim ( ) ,
2025-07-01 17:20:48 +10:00
TnkId = request . TnkId ,
GroupId = request . GroupId
} ;
if ( ! await jobService . CreateAsync ( job ) | | ! await jobService . CommitAsync ( ) )
return BadRequest ( new Response ( false , new List < ErrorModel > { new ErrorModel { Message = "Ошибка при созании задания на выполнение работ" } } ) ) ;
logger . LogInformation ( $"Пользователь {User.Identity?.Name} добавил задание на выполнение работ: {job.Id}, {job.Name}, {job.WorkName}" ) ;
var createdJob = await jobService . Get ( ) . Include ( t = > t . Tnk )
. FirstAsync ( t = > t . Id = = job . Id ) ;
var locationUri = uriService . GetUri ( ApiRoutes . Job . Get , ApiRoutes . Job . getParam , createdJob . Id ) ;
var response = mapper . Map < JobResponse > ( createdJob ) ;
// так как мы только что создали Job, то у него нет шаблонов, смело ставим = 0 (ускоряем запрос)
response . TemplatesCount = 0 ;
return Created ( locationUri , new Response < JobResponse > ( response , true ) ) ;
}
/// <summary>
/// Обновить задание на выполнение работ (Job)
/// </summary>
/// <param name="id"></param>
/// <param name="request"></param>
/// <returns></returns>
[HttpPut(ApiRoutes.Job.Update)]
public async Task < IActionResult > Update ( [ FromRoute ] Guid id , [ FromBody ] JobRequest request )
{
var resultValidate = await validator . ValidateAsync ( request ) ;
if ( ! resultValidate . IsValid )
return BadRequest ( new Response ( resultValidate . Errors ) ) ;
var orig = await jobService . Get ( ) . Include ( t = > t . Tnk )
. FirstOrDefaultAsync ( t = > t . Id = = id ) ;
if ( orig = = null )
return BadRequest ( new Response ( false , new List < ErrorModel > { new ErrorModel { Message = $"Ошибка при изменении задания на выполнение работ. Н е найдено задание с Id: {id}" } } ) ) ;
orig . Name = request . Name . Trim ( ) ;
orig . WorkName = request . WorkName . Trim ( ) ;
orig . MinValueRelationships = request . MinValueRelationships ;
orig . MaxValueRelationships = request . MaxValueRelationships ;
2025-08-22 11:25:51 +10:00
orig . isParentRelationships = request . isParentRelationships ;
orig . TemplateNameMask = request . TemplateNameMask . Trim ( ) ;
orig . WorkGroupMask = request . WorkGroupMask . Trim ( ) ;
2025-07-01 17:20:48 +10:00
orig . TnkId = request . TnkId ;
orig . GroupId = request . GroupId ;
if ( ! await jobService . CommitAsync ( ) )
return BadRequest ( new Response ( false , new List < ErrorModel > { new ErrorModel { Message = "Ошибка при изменении задания на выполнение работ." } } ) ) ;
logger . LogInformation ( $"Пользователь {User.Identity?.Name} обновил задание на выполнение работ: {orig.Id}," +
$" {orig.Name}, {orig.WorkName}, {orig.MinValueRelationships}, {orig.MaxValueRelationships}," +
$" {orig.TemplateNameMask}, {orig.TnkId}, {nameof(orig.GroupId)}" ) ;
var updatedApplicationInWork = await jobService . Get ( ) . Include ( t = > t . Tnk )
. FirstAsync ( t = > t . Id = = orig . Id ) ;
var response = mapper . Map < JobResponse > ( updatedApplicationInWork ) ;
response . TemplatesCount = await templateService . Get ( ) . CountAsync ( t = > t . JobId = = id ) ;
var statistics = await GetStatisticsAsync ( response . Id ) ;
BindStatistics ( response , statistics ) ;
return Ok ( new Response < JobResponse > ( response , true ) ) ;
}
/// <summary>
/// Удалить задание на выполнение работ (только если нет связанных шаблонов)
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpDelete(ApiRoutes.Job.Delete)]
public async Task < IActionResult > Delete ( [ FromRoute ] Guid id )
{
var job = await jobService . Get ( ) . Include ( t = > t . Tnk )
. FirstOrDefaultAsync ( t = > t . Id = = id ) ;
if ( job = = null )
return BadRequest ( new Response ( false , new List < ErrorModel > { new ErrorModel {
Message = $"Ошибка при удалении задания на выполнение работ. Н е найдено задание на выполнение работ Id: {id}"
} } ) ) ;
var templateCount = await templateService . Get ( ) . CountAsync ( t = > t . JobId = = id ) ;
if ( templateCount > 0 )
return BadRequest ( new Response ( false , new List < ErrorModel > { new ErrorModel {
Message = $"Ошибка при удалении задания на выполнение работ. С данным заданием связаны шаблоны: {templateCount} шт."
} } ) ) ;
if ( ! jobService . Delete ( job ) | | ! await jobService . CommitAsync ( ) )
return BadRequest ( new Response ( false , new List < ErrorModel > { new ErrorModel {
Message = $"Ошибка при удалении задания на выполнение работ"
} } ) ) ;
logger . LogInformation ( $"Пользователь {User.Identity?.Name} удалил задание на выполнение работ: {job.Id},{job.Name}," +
$" {job.WorkName}, {job.MinValueRelationships}, {job.MaxValueRelationships}," +
$" {job.TemplateNameMask}, {job.TnkId}, {job.GroupId}" ) ;
return NoContent ( ) ;
}
/// <summary>
/// Загрузка статистики
/// </summary>
/// <param name="jobId"></param>
/// <returns></returns>
private async Task < JobStatModel > GetStatisticsAsync ( Guid jobId )
{
var statResult = await jobService . Get ( )
. Include ( t = > t . Templates )
. ThenInclude ( t = > t . RobotConfigurations )
. Where ( x = > x . Id = = jobId )
. Select ( t = > new
{
TemplateActivated = t . Templates . Count ( x = > x . IsActiveTemplate ) ,
TemplateSynchronized = t . Templates . Count ( x = > x . RobotConfigurations . Any ( c = > c . TaskStatusCode = = ( int ) TaskStatusEnum . Ok & & c . RobotCode = = ( int ) RobotsEnum . TemplateOrder ) ) ,
TemplateErrors = t . Templates . Count ( x = > x . RobotConfigurations . Any ( c = > c . RobotStatusCode = = ( int ) RobotStatusEnum . Error & & c . RobotCode = = ( int ) RobotsEnum . TemplateOrder ) ) ,
ScheduleActivated = t . Templates . Count ( x = > x . IsActiveSchedule ) ,
ScheduleSynchronized = t . Templates . Count ( x = > x . RobotConfigurations . Any ( c = > c . TaskStatusCode = = ( int ) TaskStatusEnum . Ok & & c . RobotCode = = ( int ) RobotsEnum . ScheduleOrder ) ) ,
ScheduleErrors = t . Templates . Count ( x = > x . RobotConfigurations . Any ( c = > c . RobotStatusCode = = ( int ) RobotStatusEnum . Error & & c . RobotCode = = ( int ) RobotsEnum . ScheduleOrder ) )
} ) . FirstOrDefaultAsync ( ) ;
return new JobStatModel
{
ScheduleStatistics = new ScheduleStats { Activated = statResult ? . ScheduleActivated ? ? 0 , Errors = statResult ? . ScheduleErrors ? ? 0 , Synchronized = statResult ? . ScheduleSynchronized ? ? 0 } ,
TemplateStatistics = new TemplateStats { Activated = statResult ? . TemplateActivated ? ? 0 , Errors = statResult ? . TemplateErrors ? ? 0 , Synchronized = statResult ? . TemplateSynchronized ? ? 0 }
} ;
}
private void BindStatistics ( JobResponse job , JobStatModel statistics )
{
job . TemplateStatistics = new TemplateStats { Activated = statistics . TemplateStatistics . Activated , Errors = statistics . TemplateStatistics . Errors , Synchronized = statistics . TemplateStatistics . Synchronized } ;
job . ScheduleStatistics = new ScheduleStats { Activated = statistics . ScheduleStatistics . Activated , Errors = statistics . ScheduleStatistics . Errors , Synchronized = statistics . ScheduleStatistics . Synchronized } ;
}
}
public class JobStatModel
{
2025-08-22 11:25:51 +10:00
public required TemplateStats TemplateStatistics { get ; set ; }
2025-07-01 17:20:48 +10:00
2025-08-22 11:25:51 +10:00
public required ScheduleStats ScheduleStatistics { get ; set ; }
2025-07-01 17:20:48 +10:00
}
}