all changes but database and but migrations

This commit is contained in:
eugeniy_ivanov 2022-12-02 15:54:55 +05:00
parent 2963d74f43
commit 64e51915c8
5 changed files with 270 additions and 36 deletions

View File

@ -0,0 +1,62 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace AsbCloudApp.Data;
#nullable enable
/// <summary>
/// Модель группированных операций по скважине
/// </summary>
public class WellGroupOpertionDto
{
/// <summary>
/// Id категории
/// </summary>
public int IdCategory { get; set; }
/// <summary>
/// Название категории
/// </summary>
public string Category { get; set; } = string.Empty;
/// <summary>
/// Идентификатор родителя
/// </summary>
[JsonIgnore]
public int? IdParent { get; set; }
/// <summary>
/// Количество операций
/// </summary>
public int Count { get; set; }
/// <summary>
/// Суммарное время операций, мин
/// </summary>
public double TotalMinutes { get; set; }
/// <summary>
/// Мин продолжительность операции, мин
/// </summary>
public double? MinutesMin { get; set; }
/// <summary>
/// Макс продолжительность операции, мин
/// </summary>
public double? MinutesMax { get; set; }
/// <summary>
/// Средняя продолжительность операции, мин
/// </summary>
public double? MinutesAverage { get; set; }
/// <summary>
/// Общая глубина забоя
/// </summary>
public double DeltaDepth { get; set; }
/// <summary>
/// дочерние операции
/// </summary>
public IEnumerable<WellGroupOpertionDto>? Items { get; set; }
}
#nullable disable

View File

@ -16,9 +16,9 @@ namespace AsbCloudApp.Data
public string Name { get; set; }
/// <summary>
/// код операции
/// Идентификатор родительской категории
/// </summary>
public int Code { get; set; }
public int? IdParent { get; set; }
/// <summary>
/// Название ключевого показателя операции

View File

@ -46,6 +46,30 @@ namespace AsbCloudApp.Services
int take = 32,
CancellationToken token = default);
/// <summary>
/// Получить статистику операции по скважине с группировкой по категориям
/// </summary>
/// <param name="idWell"></param>
/// <param name="operationType"></param>
/// <param name="sectionTypeIds"></param>
/// <param name="operationCategoryIds"></param>
/// <param name="begin"></param>
/// <param name="end"></param>
/// <param name="minDepth"></param>
/// <param name="maxDepth"></param>
/// <param name="token"></param>
/// <returns></returns>
Task<IEnumerable<WellGroupOpertionDto>> GetGroupOperationsStatAsync(
int idWell,
int? operationType = null,
IEnumerable<int> sectionTypeIds = null,
IEnumerable<int> operationCategoryIds = null,
DateTime begin = default,
DateTime end = default,
double minDepth = double.MinValue,
double maxDepth = double.MaxValue,
CancellationToken token = default);
/// <summary>
/// Получить операцию по id
/// </summary>

View File

@ -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<WellOperationDto>
{
@ -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<IEnumerable<WellGroupOpertionDto>?> GetGroupOperationsStatAsync(
int idWell,
int? operationType = default,
IEnumerable<int>? sectionTypeIds = default,
IEnumerable<int>? 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<WellOperationDto> GetAsync(int id,
CancellationToken token = default)
{
@ -222,6 +270,61 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
return await db.SaveChangesAsync(token)
.ConfigureAwait(false);
}
private IQueryable<WellOperation> BuildQuery(
int idWell,
int? operationType = default,
IEnumerable<int> sectionTypeIds = default,
IEnumerable<int> 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
}

View File

@ -109,6 +109,51 @@ namespace AsbCloudWebApi.Controllers
return Ok(result);
}
/// <summary>
/// Статистика операций по скважине, группированая по категориям
/// </summary>
/// <param name="idWell">id скважины</param>
/// <param name="opertaionType"></param>
/// <param name="sectionTypeIds"></param>
/// <param name="operationCategoryIds"></param>
/// <param name="begin"></param>
/// <param name="end"></param>
/// <param name="minDepth"></param>
/// <param name="maxDepth"></param>
/// <param name="token"></param>
/// <returns></returns>
[HttpGet]
[Route("groupStat")]
[Permission]
[ProducesResponseType(typeof(IEnumerable<WellGroupOpertionDto>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetGroupOperationsAsync(
[FromRoute] int idWell,
[FromQuery] int? opertaionType = default,
[FromQuery] IEnumerable<int> sectionTypeIds = default,
[FromQuery] IEnumerable<int> 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);
}
/// <summary>
/// Возвращает нужную операцию на скважине
/// </summary>