From 64e51915c8042faa9b8494224838745a9401f944 Mon Sep 17 00:00:00 2001 From: eugeniy_ivanov Date: Fri, 2 Dec 2022 15:54:55 +0500 Subject: [PATCH] all changes but database and but migrations --- AsbCloudApp/Data/WellGroupOpertionDto.cs | 62 +++++++ AsbCloudApp/Data/WellOperationCategoryDto.cs | 4 +- AsbCloudApp/Services/IWellOperationService.cs | 24 +++ .../WellOperationService.cs | 171 ++++++++++++++---- .../Controllers/WellOperationController.cs | 45 +++++ 5 files changed, 270 insertions(+), 36 deletions(-) create mode 100644 AsbCloudApp/Data/WellGroupOpertionDto.cs diff --git a/AsbCloudApp/Data/WellGroupOpertionDto.cs b/AsbCloudApp/Data/WellGroupOpertionDto.cs new file mode 100644 index 00000000..9100a21b --- /dev/null +++ b/AsbCloudApp/Data/WellGroupOpertionDto.cs @@ -0,0 +1,62 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace AsbCloudApp.Data; +#nullable enable +/// +/// Модель группированных операций по скважине +/// +public class WellGroupOpertionDto +{ + /// + /// Id категории + /// + public int IdCategory { get; set; } + + /// + /// Название категории + /// + public string Category { get; set; } = string.Empty; + + /// + /// Идентификатор родителя + /// + [JsonIgnore] + public int? IdParent { get; set; } + + /// + /// Количество операций + /// + public int Count { get; set; } + + /// + /// Суммарное время операций, мин + /// + public double TotalMinutes { get; set; } + + /// + /// Мин продолжительность операции, мин + /// + public double? MinutesMin { get; set; } + + /// + /// Макс продолжительность операции, мин + /// + public double? MinutesMax { get; set; } + + /// + /// Средняя продолжительность операции, мин + /// + public double? MinutesAverage { get; set; } + + /// + /// Общая глубина забоя + /// + public double DeltaDepth { get; set; } + + /// + /// дочерние операции + /// + public IEnumerable? Items { get; set; } +} +#nullable disable \ No newline at end of file diff --git a/AsbCloudApp/Data/WellOperationCategoryDto.cs b/AsbCloudApp/Data/WellOperationCategoryDto.cs index fda6c4ee..220b3ee4 100644 --- a/AsbCloudApp/Data/WellOperationCategoryDto.cs +++ b/AsbCloudApp/Data/WellOperationCategoryDto.cs @@ -16,9 +16,9 @@ namespace AsbCloudApp.Data public string Name { get; set; } /// - /// код операции + /// Идентификатор родительской категории /// - public int Code { get; set; } + public int? IdParent { get; set; } /// /// Название ключевого показателя операции diff --git a/AsbCloudApp/Services/IWellOperationService.cs b/AsbCloudApp/Services/IWellOperationService.cs index 283bc150..a9105939 100644 --- a/AsbCloudApp/Services/IWellOperationService.cs +++ b/AsbCloudApp/Services/IWellOperationService.cs @@ -46,6 +46,30 @@ namespace AsbCloudApp.Services int take = 32, CancellationToken token = default); + /// + /// Получить статистику операции по скважине с группировкой по категориям + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + Task> GetGroupOperationsStatAsync( + int idWell, + int? operationType = null, + IEnumerable sectionTypeIds = null, + IEnumerable operationCategoryIds = null, + DateTime begin = default, + DateTime end = default, + double minDepth = double.MinValue, + double maxDepth = double.MaxValue, + CancellationToken token = default); + /// /// Получить операцию по id /// diff --git a/AsbCloudInfrastructure/Services/WellOperationService/WellOperationService.cs b/AsbCloudInfrastructure/Services/WellOperationService/WellOperationService.cs index f1ae1144..8cb9b606 100644 --- a/AsbCloudInfrastructure/Services/WellOperationService/WellOperationService.cs +++ b/AsbCloudInfrastructure/Services/WellOperationService/WellOperationService.cs @@ -89,39 +89,16 @@ namespace AsbCloudInfrastructure.Services.WellOperationService { var timezone = wellService.GetTimezone(idWell); - var query = db.WellOperations - .Include(s => s.WellSectionType) - .Include(s => s.OperationCategory) - .Where(s => s.IdWell == idWell); - - var dateStart = query.Min(o => o.DateStart); - - if (operationType != default) - query = query.Where(e => e.IdType == (int)operationType); - - if (sectionTypeIds != default && sectionTypeIds.Any()) - query = query.Where(e => sectionTypeIds.Contains(e.IdWellSectionType)); - - if (operationCategoryIds != default && operationCategoryIds.Any()) - query = query.Where(e => operationCategoryIds.Contains(e.IdCategory)); - - if (minDepth != double.MinValue) - query = query.Where(e => e.DepthEnd >= minDepth); - - if (maxDepth != double.MaxValue) - query = query.Where(e => e.DepthEnd <= maxDepth); - - if (begin != default) - { - var beginOffset = begin.ToUtcDateTimeOffset(timezone.Hours); - query = query.Where(e => e.DateStart >= beginOffset); - } - - if (end != default) - { - var endOffset = end.ToUtcDateTimeOffset(timezone.Hours); - query = query.Where(e => e.DateStart <= endOffset); - } + var query = BuildQuery( + idWell, + operationType, + sectionTypeIds, + operationCategoryIds, + begin, + end, + minDepth, + maxDepth, + token); var result = new PaginationContainer { @@ -129,7 +106,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService Take = take, Count = await query.CountAsync(token).ConfigureAwait(false), }; - + var dateStart = query.Min(o => o.DateStart); query = query .OrderBy(e => e.DateStart) .ThenBy(e => e.DepthEnd) @@ -162,6 +139,77 @@ namespace AsbCloudInfrastructure.Services.WellOperationService return result; } + public async Task?> GetGroupOperationsStatAsync( + int idWell, + int? operationType = default, + IEnumerable? sectionTypeIds = default, + IEnumerable? operationCategoryIds = default, + DateTime begin = default, + DateTime end = default, + double minDepth = double.MinValue, + double maxDepth = double.MaxValue, + CancellationToken token = default) + { + var query = BuildQuery( + idWell, + operationType, + sectionTypeIds, + operationCategoryIds, + begin, + end, + minDepth, + maxDepth, + token); + if (query is null) + return null; + var entities = await query + .Select(o => new { + o.IdCategory, + DurationMinutes = o.DurationHours * 60, + DurationDepth = o.DepthEnd - o.DepthStart + }) + .ToListAsync(token); + var parentRelationDictionary = GetCategories() + .ToDictionary(c => c.Id, cc => new + { + Name = cc.Name, + IdParent = cc.IdParent + }); + var dtos = entities + .GroupBy(o => o.IdCategory) + .Select(g => new WellGroupOpertionDto + { + IdCategory = g.Key, + Category = parentRelationDictionary[g.Key].Name, + Count = g.Count(), + MinutesAverage = g.Average(o => o.DurationMinutes), + MinutesMin = g.Min(o => o.DurationMinutes), + MinutesMax = g.Max(o => o.DurationMinutes), + TotalMinutes = g.Sum(o => o.DurationMinutes), + DeltaDepth = g.Sum(o => o.DurationDepth), + IdParent = parentRelationDictionary[g.Key].IdParent + }); + var defaultId = 0; + while (dtos.Any(x => x.IdParent != null)) + { + defaultId--; + dtos = dtos + .GroupBy(o => o.IdParent) + .Select(g => new WellGroupOpertionDto + { + IdCategory = g.Key.HasValue ? g.Key.Value : defaultId, + Category = g.Key.HasValue ? parentRelationDictionary[g.Key.Value].Name : "unknown", + Count = g.Sum(o => o.Count), + DeltaDepth = g.Sum(o => o.DeltaDepth), + TotalMinutes = g.Sum(o => o.TotalMinutes), + Items = g.ToList(), + IdParent = g.Key.HasValue ? parentRelationDictionary[g.Key.Value].IdParent : defaultId, + + }); + } + return dtos; + } + public async Task GetAsync(int id, CancellationToken token = default) { @@ -222,6 +270,61 @@ namespace AsbCloudInfrastructure.Services.WellOperationService return await db.SaveChangesAsync(token) .ConfigureAwait(false); } + + private IQueryable BuildQuery( + int idWell, + int? operationType = default, + IEnumerable sectionTypeIds = default, + IEnumerable operationCategoryIds = default, + DateTime begin = default, + DateTime end = default, + double minDepth = double.MinValue, + double maxDepth = double.MaxValue, + CancellationToken token = default) + { + var timezone = wellService.GetTimezone(idWell); + + var query = db.WellOperations + .Include(s => s.WellSectionType) + .Include(s => s.OperationCategory) + .Where(s => s.IdWell == idWell); + + var dateStart = query.Min(o => o.DateStart); + + if (operationType.HasValue) + query = query.Where(e => e.IdType == operationType.Value); + + if (sectionTypeIds != default && sectionTypeIds.Any()) + query = query.Where(e => sectionTypeIds.Contains(e.IdWellSectionType)); + + if (operationCategoryIds != default && operationCategoryIds.Any()) + query = query.Where(e => operationCategoryIds.Contains(e.IdCategory)); + + if (minDepth != double.MinValue) + query = query.Where(e => e.DepthEnd >= minDepth); + + if (maxDepth != double.MaxValue) + query = query.Where(e => e.DepthEnd <= maxDepth); + + if (begin != default) + { + var beginOffset = begin.ToUtcDateTimeOffset(timezone.Hours); + query = query.Where(e => e.DateStart >= beginOffset); + } + + if (end != default) + { + var endOffset = end.ToUtcDateTimeOffset(timezone.Hours); + query = query.Where(e => e.DateStart <= endOffset); + } + + query = query + .OrderBy(e => e.DateStart) + .ThenBy(e => e.DepthEnd) + .ThenBy(e => e.Id); + return query; + + } } #nullable disable } diff --git a/AsbCloudWebApi/Controllers/WellOperationController.cs b/AsbCloudWebApi/Controllers/WellOperationController.cs index 96f01ea8..9d1450ff 100644 --- a/AsbCloudWebApi/Controllers/WellOperationController.cs +++ b/AsbCloudWebApi/Controllers/WellOperationController.cs @@ -109,6 +109,51 @@ namespace AsbCloudWebApi.Controllers return Ok(result); } + /// + /// Статистика операций по скважине, группированая по категориям + /// + /// id скважины + /// + /// + /// + /// + /// + /// + /// + /// + /// + [HttpGet] + [Route("groupStat")] + [Permission] + [ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)] + public async Task GetGroupOperationsAsync( + [FromRoute] int idWell, + [FromQuery] int? opertaionType = default, + [FromQuery] IEnumerable sectionTypeIds = default, + [FromQuery] IEnumerable operationCategoryIds = default, + [FromQuery] DateTime begin = default, + [FromQuery] DateTime end = default, + [FromQuery] double minDepth = double.MinValue, + [FromQuery] double maxDepth = double.MaxValue, + CancellationToken token = default) + { + if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false)) + return Forbid(); + + var result = await operationService.GetGroupOperationsStatAsync( + idWell, + opertaionType, + sectionTypeIds, + operationCategoryIds, + begin, + end, + minDepth, + maxDepth, + token) + .ConfigureAwait(false); + return Ok(result); + } + /// /// Возвращает нужную операцию на скважине ///