Merge pull request '#28835068 Сводная таблица по наработке по -бурильщикам' (#225) from feature/28835068 into dev

Reviewed-on: http://test.digitaldrilling.ru:8080/DDrilling/AsbCloudServer/pulls/225
This commit is contained in:
Никита Фролов 2024-02-21 18:12:41 +05:00
commit 4c7ae125c1
8 changed files with 353 additions and 195 deletions

View File

@ -1,7 +1,4 @@
using System.Collections.Generic; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using AsbCloudApp.Data.User;
namespace AsbCloudApp.Data namespace AsbCloudApp.Data
{ {

View File

@ -0,0 +1,25 @@
using System.Collections.Generic;
using AsbCloudApp.Data.Subsystems;
namespace AsbCloudApp.Data;
/// <summary>
/// ñòàòèñòèêà íàðàáîòêè ïî áóðèëüùèêàì
/// </summary>
public class DrillerDetectedOperationStatDto
{
/// <summary>
/// Ñòàòèñòèêè ïîäñèñòåì
/// </summary>
public IEnumerable<SubsystemStatDto> Statistic { get; set; } = null!;
/// <summary>
/// Ðàñïèñàíèå áóðèëüùèêà
/// </summary>
public ScheduleDto Schedule { get; set; } = null!;
/// <summary>
/// Ñêâàæèíà
/// </summary>
public WellDto Well { get; set; } = null!;
}

View File

@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.Linq;
namespace AsbCloudApp.Requests;
/// <summary>
/// Çàïðîñ íà ïîëó÷åíèå ñòàòèñòèêè èñïîëüçîâàíèÿ ïîäñèñòåì áóðèëüùèêîì
/// </summary>
public class GetStatRequest: RequestBase
{
/// <summary>
/// id ñêâàæèí
/// </summary>
public IEnumerable<int> IdsWells { get; set; } = Enumerable.Empty<int>();
/// <summary>
/// id Áóðèëüùèêà
/// </summary>
public int? IdDriller { get; set; }
}

View File

@ -3,6 +3,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Requests;
namespace AsbCloudApp.Services namespace AsbCloudApp.Services
{ {
@ -28,5 +29,13 @@ namespace AsbCloudApp.Services
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<DrillerDto?> GetOrDefaultDrillerAsync(int idWell, DateTime workTime, CancellationToken token); Task<DrillerDto?> GetOrDefaultDrillerAsync(int idWell, DateTime workTime, CancellationToken token);
/// <summary>
/// Получить расписание смен
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<ScheduleDto>> GetPageAsync(GetStatRequest request, CancellationToken token);
} }
} }

View File

@ -4,6 +4,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Data;
namespace AsbCloudApp.Services; namespace AsbCloudApp.Services;
@ -27,4 +28,13 @@ public interface ISubsystemService
/// <param name="token"></param> /// <param name="token"></param>
/// <returns></returns> /// <returns></returns>
Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(IEnumerable<int> wellIds, CancellationToken token); Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(IEnumerable<int> wellIds, CancellationToken token);
/// <summary>
/// Получение статистики по бурильщику
/// </summary>
/// <param name="request"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<DrillerDetectedOperationStatDto>> GetByWellsAsync(GetStatRequest request,
CancellationToken token);
} }

View File

@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsbCloudApp.Requests;
using Mapster; using Mapster;
namespace AsbCloudInfrastructure.Repository namespace AsbCloudInfrastructure.Repository
@ -53,6 +54,21 @@ namespace AsbCloudInfrastructure.Repository
return entity?.Driller.Adapt<DrillerDto>(); return entity?.Driller.Adapt<DrillerDto>();
} }
public async Task<IEnumerable<ScheduleDto>> GetPageAsync(GetStatRequest request, CancellationToken token)
{
var idWell = request.IdsWells;
var idDriller = request.IdDriller;
var query = GetQuery().Where(s => request.IdsWells.Contains(s.IdWell));
if (idDriller is not null)
{
query.Where(s => s.IdDriller == idDriller);
}
var result = await query.ToArrayAsync(token);
return result.Select(Convert);
}
private IQueryable<Schedule> BuildQuery(int idWell, DateTime workTime) private IQueryable<Schedule> BuildQuery(int idWell, DateTime workTime)
{ {
var hoursOffset = wellService.GetTimezone(idWell).Hours; var hoursOffset = wellService.GetTimezone(idWell).Hours;

View File

@ -1,15 +1,15 @@
using AsbCloudApp.Data; using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.DetectedOperation; using AsbCloudApp.Data.DetectedOperation;
using AsbCloudApp.Data.Subsystems; using AsbCloudApp.Data.Subsystems;
using AsbCloudApp.Exceptions; using AsbCloudApp.Exceptions;
using AsbCloudApp.Requests; using AsbCloudApp.Requests;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudInfrastructure.Services.DetectOperations; using AsbCloudInfrastructure.Services.DetectOperations;
namespace AsbCloudInfrastructure.Services.Subsystems; namespace AsbCloudInfrastructure.Services.Subsystems;
@ -25,24 +25,76 @@ internal class SubsystemService : ISubsystemService
private readonly IWellService wellService; private readonly IWellService wellService;
private readonly IDetectedOperationService detectedOperationService; private readonly IDetectedOperationService detectedOperationService;
private readonly IScheduleRepository scheduleRepository;
private IDictionary<int, SubsystemDto> subsystems = new Dictionary<int, SubsystemDto>(); private IDictionary<int, SubsystemDto> subsystems = new Dictionary<int, SubsystemDto>();
public SubsystemService(ICrudRepository<SubsystemDto> subsystemRepository, public SubsystemService(ICrudRepository<SubsystemDto> subsystemRepository,
IWellService wellService, IWellService wellService,
IDetectedOperationService detectedOperationService) IDetectedOperationService detectedOperationService,
IScheduleRepository scheduleRepository)
{ {
this.wellService = wellService; this.wellService = wellService;
this.subsystemRepository = subsystemRepository; this.subsystemRepository = subsystemRepository;
this.detectedOperationService = detectedOperationService; this.detectedOperationService = detectedOperationService;
this.scheduleRepository = scheduleRepository;
}
// получить расписания бурильщиков по скважинам // ScheduleRepository добавить новый метод
// [
// get telemetryId by idWell // IWellService.GetOrDefaultStatAsync
// получить detectedOperation by telemetry //detectedOperationService.GetOperationsAsync
// сгруппировать по бурильщикам
// [
// рассчитать статистику // CalcStatAsync
// join driller from group
// ]
// join well (cluster, deposit)
// ]
public async Task<IEnumerable<DrillerDetectedOperationStatDto>> GetByWellsAsync(GetStatRequest request,
CancellationToken token)
{
var result = new List<DrillerDetectedOperationStatDto>();
var schedulePage = await scheduleRepository.GetPageAsync(request, token);
var wells = await wellService.GetAsync(new WellRequest { Ids = request.IdsWells }, token);
foreach (var schedule in schedulePage)
{
var idWell = schedule.IdWell;
var well = wells.FirstOrDefault(w=> w.Id == idWell)!;
var byWellRequest = new DetectedOperationByWellRequest(idWell, new DetectedOperationRequest());
var detectedOperations = await detectedOperationService
.GetOperationsAsync(byWellRequest, token);
var groupByDriller = detectedOperations
.Where(operation => operation.Driller is not null)
.GroupBy(operation => operation.Driller);
foreach (var entry in groupByDriller)
{
var drillerOperationsStat = await CalcStatAsync(entry, token);
var dto = new DrillerDetectedOperationStatDto
{
Statistic = drillerOperationsStat,
Schedule = schedule,
Well = well,
};
result.Add(dto);
}
}
return result;
} }
public async Task<IEnumerable<SubsystemStatDto>> GetStatAsync(SubsystemRequest request, CancellationToken token) public async Task<IEnumerable<SubsystemStatDto>> GetStatAsync(SubsystemRequest request, CancellationToken token)
{ {
var well = await wellService.GetOrDefaultAsync(request.IdWell, token) var well = await wellService.GetOrDefaultAsync(request.IdWell, token)
?? throw new ArgumentInvalidException(nameof(request.IdWell), $"Well Id: {request.IdWell} does not exist"); ?? throw new ArgumentInvalidException(nameof(request.IdWell),
$"Well Id: {request.IdWell} does not exist");
if(!well.IdTelemetry.HasValue) if (!well.IdTelemetry.HasValue)
return Enumerable.Empty<SubsystemStatDto>(); return Enumerable.Empty<SubsystemStatDto>();
var detectedOperationSummaryRequest = new DetectedOperationByWellRequest var detectedOperationSummaryRequest = new DetectedOperationByWellRequest
@ -70,14 +122,16 @@ internal class SubsystemService : ISubsystemService
return stat; return stat;
} }
public async Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(IEnumerable<int> wellIds, CancellationToken token) public async Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(IEnumerable<int> wellIds,
CancellationToken token)
{ {
var activeWells = await wellService.GetAsync(new() { Ids = wellIds, IdState = 1 }, token); var activeWells = await wellService.GetAsync(new() { Ids = wellIds, IdState = 1 }, token);
var result = await GetStatAsync(activeWells, null, null, token); var result = await GetStatAsync(activeWells, null, null, token);
return result; return result;
} }
private async Task<IEnumerable<SubsystemStatDto>> CalcStatAsync(IEnumerable<DetectedOperationWithDrillerDto> operations, CancellationToken token) private async Task<IEnumerable<SubsystemStatDto>> CalcStatAsync(
IEnumerable<DetectedOperationWithDrillerDto> operations, CancellationToken token)
{ {
if (!subsystems.Any()) if (!subsystems.Any())
subsystems = (await subsystemRepository.GetAllAsync(token)).ToDictionary(s => s.Id, s => s); subsystems = (await subsystemRepository.GetAllAsync(token)).ToDictionary(s => s.Id, s => s);
@ -100,7 +154,9 @@ internal class SubsystemService : ISubsystemService
var oscillationStat = new SubsystemStatDto var oscillationStat = new SubsystemStatDto
{ {
IdSubsystem = IdSubsystemOscillation, IdSubsystem = IdSubsystemOscillation,
SubsystemName = subsystems.TryGetValue(IdSubsystemOscillation, out var subsystemDto) ? subsystemDto.Name : "unknown", SubsystemName = subsystems.TryGetValue(IdSubsystemOscillation, out var subsystemDto)
? subsystemDto.Name
: "unknown",
UsedTimeHours = usedTimeHours, UsedTimeHours = usedTimeHours,
SumOperationDepthInterval = operations.Sum(o => o.DepthEnd - o.DepthStart), SumOperationDepthInterval = operations.Sum(o => o.DepthEnd - o.DepthStart),
SumOperationDurationHours = operations.Sum(o => o.DurationMinutes / 60), SumOperationDurationHours = operations.Sum(o => o.DurationMinutes / 60),
@ -124,7 +180,8 @@ internal class SubsystemService : ISubsystemService
{ {
WellOperationCategory.IdRotor => IdSubsystemAPDRotor, WellOperationCategory.IdRotor => IdSubsystemAPDRotor,
WellOperationCategory.IdSlide => IdSubsystemAPDSlide, WellOperationCategory.IdSlide => IdSubsystemAPDSlide,
_ => throw new ArgumentException($"IdCategory: {group.Key} does not supported in this method", nameof(group.Key)) _ => throw new ArgumentException($"IdCategory: {group.Key} does not supported in this method",
nameof(group.Key))
}; };
var (sumDepthInterval, usedTimeHours, operationCount) = AggregateOperations(idSubsystem, group); var (sumDepthInterval, usedTimeHours, operationCount) = AggregateOperations(idSubsystem, group);
@ -132,7 +189,9 @@ internal class SubsystemService : ISubsystemService
var subsystemStat = new SubsystemStatDto var subsystemStat = new SubsystemStatDto
{ {
IdSubsystem = idSubsystem, IdSubsystem = idSubsystem,
SubsystemName = subsystems.TryGetValue(idSubsystem, out var subsystemDto) ? subsystemDto.Name : "unknown", SubsystemName = subsystems.TryGetValue(idSubsystem, out var subsystemDto)
? subsystemDto.Name
: "unknown",
UsedTimeHours = usedTimeHours, UsedTimeHours = usedTimeHours,
SumOperationDepthInterval = group.Sum(o => o.DepthEnd - o.DepthStart), SumOperationDepthInterval = group.Sum(o => o.DepthEnd - o.DepthStart),
SumOperationDurationHours = group.Sum(o => o.DurationMinutes / 60), SumOperationDurationHours = group.Sum(o => o.DurationMinutes / 60),
@ -151,7 +210,8 @@ internal class SubsystemService : ISubsystemService
var apdSum = new SubsystemStatDto var apdSum = new SubsystemStatDto
{ {
IdSubsystem = IdSubsystemAPD, IdSubsystem = IdSubsystemAPD,
SubsystemName = subsystems.TryGetValue(IdSubsystemAPD, out var subsystemDto) ? subsystemDto.Name : "unknown", SubsystemName =
subsystems.TryGetValue(IdSubsystemAPD, out var subsystemDto) ? subsystemDto.Name : "unknown",
UsedTimeHours = apdRotorAndSlide.Sum(part => part.UsedTimeHours), UsedTimeHours = apdRotorAndSlide.Sum(part => part.UsedTimeHours),
SumOperationDepthInterval = apdRotorAndSlide.Sum(part => part.SumOperationDepthInterval), SumOperationDepthInterval = apdRotorAndSlide.Sum(part => part.SumOperationDepthInterval),
SumOperationDurationHours = apdRotorAndSlide.Sum(part => part.SumOperationDurationHours), SumOperationDurationHours = apdRotorAndSlide.Sum(part => part.SumOperationDurationHours),
@ -174,8 +234,10 @@ internal class SubsystemService : ISubsystemService
IdSubsystemAPDRotor => CalcOperationsByEnableSubsystems(operations, EnabledSubsystemsFlags.AutoRotor), IdSubsystemAPDRotor => CalcOperationsByEnableSubsystems(operations, EnabledSubsystemsFlags.AutoRotor),
IdSubsystemAPDSlide => CalcOperationsByEnableSubsystems(operations, IdSubsystemAPDSlide => CalcOperationsByEnableSubsystems(operations,
EnabledSubsystemsFlags.AutoSlide | EnabledSubsystemsFlags.AutoOscillation), EnabledSubsystemsFlags.AutoSlide | EnabledSubsystemsFlags.AutoOscillation),
IdSubsystemOscillation => CalcOperationsByEnableSubsystems(operations, EnabledSubsystemsFlags.AutoOscillation), IdSubsystemOscillation => CalcOperationsByEnableSubsystems(operations,
_ => throw new ArgumentException($"IdSubsystem: {idSubsystem} does not supported in this method", nameof(idSubsystem)) EnabledSubsystemsFlags.AutoOscillation),
_ => throw new ArgumentException($"IdSubsystem: {idSubsystem} does not supported in this method",
nameof(idSubsystem))
}; };
private static (double SumDepthInterval, double UsedTimeHours, int OperationCount) CalcOperationsByEnableSubsystems( private static (double SumDepthInterval, double UsedTimeHours, int OperationCount) CalcOperationsByEnableSubsystems(

View File

@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -32,6 +33,7 @@ namespace AsbCloudWebApi.Controllers.Subsystems
this.wellService = wellService; this.wellService = wellService;
this.telemetryDataSaubService = telemetryDataSaubService; this.telemetryDataSaubService = telemetryDataSaubService;
} }
/// <summary> /// <summary>
/// получить статистику /// получить статистику
/// </summary> /// </summary>
@ -61,6 +63,23 @@ namespace AsbCloudWebApi.Controllers.Subsystems
return Ok(dateRange); return Ok(dateRange);
} }
[HttpGet("drillerDetectedOperationStat")]
[ProducesResponseType(typeof(IEnumerable<DrillerDetectedOperationStatDto>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetByWellsAsync(GetStatRequest request,
CancellationToken token)
{
if (!request.IdsWells.Any())
return NoContent();
foreach(var idWell in request.IdsWells)
if (!await UserHasAccessToWellAsync(idWell, token))
return Forbid();
var result = await subsystemService.GetByWellsAsync(request, token);
return Ok(result);
}
private async Task<bool> UserHasAccessToWellAsync(int idWell, CancellationToken token) private async Task<bool> UserHasAccessToWellAsync(int idWell, CancellationToken token)
{ {
var idCompany = User.GetCompanyId(); var idCompany = User.GetCompanyId();