forked from ddrilling/AsbCloudServer
Merge branch 'dev' into feature/import
This commit is contained in:
commit
0c399f0693
@ -1,100 +1,85 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace AsbCloudApp.Data.DetectedOperation
|
||||
namespace AsbCloudApp.Data.DetectedOperation;
|
||||
|
||||
/// <summary>
|
||||
/// Автоматически определенная операция
|
||||
/// </summary>
|
||||
public class DetectedOperationDto: IId
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
[Required]
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Автоматически определяемая операция
|
||||
/// Id телеметрии
|
||||
/// </summary>
|
||||
public class DetectedOperationDto : IId, IWellRelated
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
[Required]
|
||||
public int Id { get; set; }
|
||||
[Required]
|
||||
public int IdTelemetry { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
[Required]
|
||||
public int IdWell { get; set; }
|
||||
/// <summary>
|
||||
/// Id названия/описания операции
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int IdCategory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id телеметрии
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int IdTelemetry { get; set; }
|
||||
/// <summary>
|
||||
/// Id пользователя панели на момент начала операции
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int IdUserAtStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id названия/описания операции
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int IdCategory { get; set; }
|
||||
/// <summary>
|
||||
/// Дата завершения операции в часовом поясе скважины
|
||||
/// </summary>
|
||||
[Required]
|
||||
public DateTimeOffset DateEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id пользователя панели
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int IdUsersAtStart { get; set; }
|
||||
/// <summary>
|
||||
/// Дата начала операции в часовом поясе скважины
|
||||
/// </summary>
|
||||
[Required]
|
||||
public DateTimeOffset DateStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Дата начала операции в часовом поясе скважины
|
||||
/// </summary>
|
||||
[Required]
|
||||
public DateTime DateStart { get; set; }
|
||||
/// <summary>
|
||||
/// глубина на завершения операции, м
|
||||
/// </summary>
|
||||
[Required]
|
||||
public double DepthEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Дата завершения операции в часовом поясе скважины
|
||||
/// </summary>
|
||||
[Required]
|
||||
public DateTime DateEnd { get; set; }
|
||||
/// <summary>
|
||||
/// глубина на начало операции, м
|
||||
/// </summary>
|
||||
[Required]
|
||||
public double DepthStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Продолжительность операции в минутах
|
||||
/// </summary>
|
||||
[Required]
|
||||
public double DurationMinutes => (DateEnd - DateStart).TotalMinutes;
|
||||
/// <summary>
|
||||
/// Продолжительность операции в минутах
|
||||
/// </summary>
|
||||
[Required]
|
||||
public double DurationMinutes => (DateEnd - DateStart).TotalMinutes;
|
||||
|
||||
/// <summary>
|
||||
/// глубина на начало операции, м
|
||||
/// </summary>
|
||||
[Required]
|
||||
public double DepthStart { get; set; }
|
||||
/// <summary>
|
||||
/// Флаг включенной подсистемы
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int EnabledSubsystems { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// глубина на завершения операции, м
|
||||
/// </summary>
|
||||
[Required]
|
||||
public double DepthEnd { get; set; }
|
||||
/// <summary>
|
||||
/// название/описание операции
|
||||
/// </summary>
|
||||
[Required]
|
||||
public WellOperationCategoryDto OperationCategory { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// название/описание операции
|
||||
/// </summary>
|
||||
[Required]
|
||||
public WellOperationCategoryDto OperationCategory { get; set; } = null!;
|
||||
/// <summary>
|
||||
/// Пользователь панели оператора
|
||||
/// </summary>
|
||||
public string? TelemetryUserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Пользователь панели оператора
|
||||
/// </summary>
|
||||
public string? TelemetryUserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Бурильщик
|
||||
/// </summary>
|
||||
public DrillerDto? Driller { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Целевые/нормативные показатели
|
||||
/// </summary>
|
||||
public OperationValueDto? OperationValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ключевой параметр операции
|
||||
/// </summary>
|
||||
[Required]
|
||||
public double Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Флаг включенной подсистемы
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int EnabledSubsystems { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Ключевой параметр операции
|
||||
/// </summary>
|
||||
[Required]
|
||||
public double Value { get; set; }
|
||||
}
|
@ -13,7 +13,7 @@ namespace AsbCloudApp.Data.DetectedOperation
|
||||
/// Список всех операций
|
||||
/// </summary>
|
||||
[Required]
|
||||
public IEnumerable<DetectedOperationDto> Operations { get; set; } = Enumerable.Empty<DetectedOperationDto>();
|
||||
public IEnumerable<DetectedOperationWithDrillerDto> Operations { get; set; } = Enumerable.Empty<DetectedOperationWithDrillerDto>();
|
||||
|
||||
/// <summary>
|
||||
/// Статистика по бурильщикам
|
||||
|
@ -0,0 +1,18 @@
|
||||
namespace AsbCloudApp.Data.DetectedOperation
|
||||
{
|
||||
/// <summary>
|
||||
/// Автоматически определяемая операция
|
||||
/// </summary>
|
||||
public class DetectedOperationWithDrillerDto : DetectedOperationDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Бурильщик
|
||||
/// </summary>
|
||||
public DrillerDto? Driller { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Целевые/нормативные показатели
|
||||
/// </summary>
|
||||
public OperationValueDto? OperationValue { get; set; }
|
||||
}
|
||||
}
|
@ -1,25 +1,32 @@
|
||||
using System;
|
||||
|
||||
namespace AsbCloudApp.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// временная зона
|
||||
/// временная зона
|
||||
/// </summary>
|
||||
public class SimpleTimezoneDto
|
||||
{
|
||||
/// <summary>
|
||||
/// смещение в часах относительно UTC
|
||||
/// смещение в часах относительно UTC
|
||||
/// </summary>
|
||||
public double Hours { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// идентификатор часовой зоны
|
||||
/// идентификатор часовой зоны
|
||||
/// </summary>
|
||||
public string? TimezoneId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// запрет на переопределение
|
||||
/// запрет на переопределение
|
||||
/// </summary>
|
||||
public bool IsOverride { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Смещение часового пояса
|
||||
/// </summary>
|
||||
public TimeSpan Offset => TimeSpan.FromHours(Hours);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
|
@ -86,6 +86,14 @@ namespace AsbCloudApp.Data
|
||||
second = fullDate.Second;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public TimeDto(DateTimeOffset fullDate)
|
||||
{
|
||||
hour = fullDate.Hour;
|
||||
minute = fullDate.Minute;
|
||||
second = fullDate.Second;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes System.TimeOnly
|
||||
/// </summary>
|
||||
|
@ -14,6 +14,7 @@ namespace AsbCloudApp.Exceptions
|
||||
/// </summary>
|
||||
public IDictionary<string, string[]> ErrorState { get; } = null!;
|
||||
|
||||
// TODO: swap arguments, inherit from ArgumentException
|
||||
/// <summary>
|
||||
/// конструктор
|
||||
/// </summary>
|
||||
|
66
AsbCloudApp/Repositories/IDetectedOperationRepository.cs
Normal file
66
AsbCloudApp/Repositories/IDetectedOperationRepository.cs
Normal file
@ -0,0 +1,66 @@
|
||||
using AsbCloudApp.Data.DetectedOperation;
|
||||
using AsbCloudApp.Requests;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
|
||||
namespace AsbCloudApp.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// Таблица автоматически определенных операций
|
||||
/// </summary>
|
||||
public interface IDetectedOperationRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Добавление записей
|
||||
/// </summary>
|
||||
/// <param name="idUser"></param>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> Insert(int? idUser, IEnumerable<DetectedOperationDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получить автоматически определенные операции по телеметрии
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<DetectedOperationDto>> Get(DetectedOperationByTelemetryRequest request, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Редактирование записей
|
||||
/// </summary>
|
||||
/// <param name="idUser"></param>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> Update(int idUser, IEnumerable<DetectedOperationDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Добавляет Dto у которых id == 0, изменяет dto у которых id != 0
|
||||
/// </summary>
|
||||
/// <param name="idUser"></param>
|
||||
/// <param name="dtos"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> UpdateOrInsert(int idUser, IEnumerable<DetectedOperationDto> dtos, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Удалить операции
|
||||
/// </summary>
|
||||
/// <param name="idUser"></param>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> Delete(int idUser, DetectedOperationByTelemetryRequest request, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Удаление записей
|
||||
/// </summary>
|
||||
/// <param name="idUser"></param>
|
||||
/// <param name="ids"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> DeleteRange(int idUser, IEnumerable<int> ids, CancellationToken token);
|
||||
}
|
17
AsbCloudApp/Repositories/IWellOperationCategoryRepository.cs
Normal file
17
AsbCloudApp/Repositories/IWellOperationCategoryRepository.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using AsbCloudApp.Data;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AsbCloudApp.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// сервис операций по скважине
|
||||
/// </summary>
|
||||
public interface IWellOperationCategoryRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// список названий операций
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IEnumerable<WellOperationCategoryDto> Get(bool includeParents);
|
||||
}
|
||||
}
|
@ -13,10 +13,12 @@ namespace AsbCloudApp.Repositories
|
||||
/// </summary>
|
||||
public interface IWellOperationRepository
|
||||
{
|
||||
//TODO: replace all references
|
||||
/// <summary>
|
||||
/// список названий операций
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[Obsolete("use IWellOperationCategoryRepository.GetCategories(bool includeParents)")]
|
||||
IEnumerable<WellOperationCategoryDto> GetCategories(bool includeParents);
|
||||
|
||||
/// <summary>
|
||||
|
@ -1,56 +1,114 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
|
||||
namespace AsbCloudApp.Requests
|
||||
namespace AsbCloudApp.Requests;
|
||||
|
||||
/// <summary>
|
||||
/// Запрос на получение операций определенных по телеметрии
|
||||
/// </summary>
|
||||
public class DetectedOperationByTelemetryRequest : DetectedOperationRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Параметры запроса на получение операций определенных по телеметрии
|
||||
/// id телеметрии
|
||||
/// </summary>
|
||||
public class DetectedOperationRequest : RequestBase
|
||||
[Required]
|
||||
public int IdTelemetry { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Запрос на получение операций определенных по id телеметрии
|
||||
/// </summary>
|
||||
public DetectedOperationByTelemetryRequest()
|
||||
{}
|
||||
|
||||
/// <summary>
|
||||
/// Запрос на получение операций определенных по id телеметрии. Copy
|
||||
/// </summary>
|
||||
/// <param name="idTelemetry"></param>
|
||||
/// <param name="request"></param>
|
||||
public DetectedOperationByTelemetryRequest(int idTelemetry, DetectedOperationRequest request)
|
||||
:base(request)
|
||||
{
|
||||
/// <summary>
|
||||
/// категория операций
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int IdWell { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Список id телеметрий
|
||||
/// пустой список - нет фильтрации
|
||||
/// </summary>
|
||||
public IEnumerable<int> IdsTelemetries { get; set; } = Array.Empty<int>();
|
||||
|
||||
/// <summary>
|
||||
/// категории операций
|
||||
/// </summary>
|
||||
public IEnumerable<int> IdsCategories { get; set; } = Array.Empty<int>();
|
||||
|
||||
/// <summary>
|
||||
/// Больше или равно дате
|
||||
/// </summary>
|
||||
public DateTimeOffset? GeDateStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Меньше или равно дате
|
||||
/// </summary>
|
||||
public DateTimeOffset? LeDateEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Больше или равно глубины забоя
|
||||
/// </summary>
|
||||
public double? GeDepth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Меньше или равно глубины забоя
|
||||
/// </summary>
|
||||
public double? LeDepth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Фильтр по пользователю панели
|
||||
/// </summary>
|
||||
public int? IdTelemetryUser { get; set; }
|
||||
|
||||
IdTelemetry = idTelemetry;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Запрос на получение операций определенных по id скважины
|
||||
/// </summary>
|
||||
public class DetectedOperationByWellRequest : DetectedOperationRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// id скважины
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int IdWell { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Запрос на получение операций определенных по id скважины
|
||||
/// </summary>
|
||||
public DetectedOperationByWellRequest()
|
||||
{}
|
||||
|
||||
/// <summary>
|
||||
/// Запрос на получение операций определенных по id скважины. Copy
|
||||
/// </summary>
|
||||
public DetectedOperationByWellRequest(int idWell, DetectedOperationRequest request)
|
||||
: base(request)
|
||||
{
|
||||
IdWell = idWell;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Запрос на получение операций определенных по телеметрии
|
||||
/// </summary>
|
||||
public class DetectedOperationRequest : RequestBase
|
||||
{
|
||||
/// <summary>
|
||||
/// категории операций
|
||||
/// </summary>
|
||||
public IEnumerable<int> IdsCategories { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Больше или равно дате
|
||||
/// </summary>
|
||||
public DateTimeOffset? GeDateStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Меньше или равно дате
|
||||
/// </summary>
|
||||
public DateTimeOffset? LeDateEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Больше или равно глубины забоя
|
||||
/// </summary>
|
||||
public double? GeDepthStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Меньше или равно глубины забоя
|
||||
/// </summary>
|
||||
public double? LeDepthEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Запрос на получение операций определенных по телеметрии
|
||||
/// </summary>
|
||||
public DetectedOperationRequest()
|
||||
{
|
||||
IdsCategories = new List<int>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Запрос на получение операций определенных по телеметрии. Copy
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
public DetectedOperationRequest(DetectedOperationRequest request)
|
||||
: base(request)
|
||||
{
|
||||
IdsCategories = request.IdsCategories;
|
||||
GeDateStart = request.GeDateStart;
|
||||
LeDateEnd = request.LeDateEnd;
|
||||
GeDepthStart = request.GeDepthStart;
|
||||
LeDepthEnd = request.LeDepthEnd;
|
||||
}
|
||||
}
|
||||
|
@ -23,5 +23,23 @@ namespace AsbCloudApp.Requests
|
||||
/// Указать направление сортировки можно через пробел "asc" или "desc"
|
||||
/// </summary>
|
||||
public IEnumerable<string>? SortFields { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Базовые параметры запроса
|
||||
/// </summary>
|
||||
public RequestBase()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Базовые параметры запроса. Копирующий конструктор
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
public RequestBase(RequestBase request)
|
||||
{
|
||||
Skip = request.Skip;
|
||||
Take = request.Take;
|
||||
SortFields = request.SortFields;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ namespace AsbCloudApp.Services
|
||||
/// <param name="idWell"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<WellOperationCategoryDto>?> GetCategoriesAsync(int? idWell, CancellationToken token);
|
||||
Task<IEnumerable<WellOperationCategoryDto>> GetCategoriesAsync(int? idWell, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получить автоматически определенные по телеметрии операции с анализом по бурильщикам
|
||||
@ -27,7 +27,7 @@ namespace AsbCloudApp.Services
|
||||
/// <param name="request"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<DetectedOperationListDto?> GetAsync(DetectedOperationRequest request, CancellationToken token);
|
||||
Task<DetectedOperationListDto> GetAsync(DetectedOperationByWellRequest request, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получить автоматически определенные по телеметрии операции
|
||||
@ -35,7 +35,7 @@ namespace AsbCloudApp.Services
|
||||
/// <param name="request"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<DetectedOperationDto>> GetOperationsAsync(DetectedOperationRequest request, CancellationToken token);
|
||||
Task<IEnumerable<DetectedOperationWithDrillerDto>> GetOperationsAsync(DetectedOperationByWellRequest request, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Удалить операции
|
||||
@ -43,7 +43,7 @@ namespace AsbCloudApp.Services
|
||||
/// <param name="request"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> DeleteAsync(DetectedOperationRequest request, CancellationToken token);
|
||||
Task<int> DeleteAsync(DetectedOperationByWellRequest request, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Статистика по операциям
|
||||
@ -51,6 +51,6 @@ namespace AsbCloudApp.Services
|
||||
/// <param name="request"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<DetectedOperationStatDto>?> GetOperationsStatAsync(DetectedOperationRequest request, CancellationToken token);
|
||||
Task<IEnumerable<DetectedOperationStatDto>> GetOperationsStatAsync(DetectedOperationByWellRequest request, CancellationToken token);
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,18 @@ namespace AsbCloudApp.Services
|
||||
/// </summary>
|
||||
public interface ITelemetryDataSaubService : ITelemetryDataService<TelemetryDataSaubDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Получение телеметрии для РТК статистики
|
||||
/// </summary>
|
||||
/// <param name="idTelemetry"></param>
|
||||
/// <param name="isBitOnBottom"></param>
|
||||
/// <param name="geDate"></param>
|
||||
/// <param name="leDate"></param>
|
||||
/// <param name="take"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<TelemetryDataSaubDto>> Get(int idTelemetry, bool isBitOnBottom, DateTimeOffset geDate, DateTimeOffset leDate, int take, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// усредненная статистика по 1м за весь период
|
||||
/// <para>
|
||||
|
34
AsbCloudDb/EFExtensionsExceptionHandling.cs
Normal file
34
AsbCloudDb/EFExtensionsExceptionHandling.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using AsbCloudDb.Model;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Npgsql;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudDb
|
||||
{
|
||||
public static class EFExtensionsExceptionHandling
|
||||
{
|
||||
public static async Task<int> SaveChangesWithExceptionHandling(this IAsbCloudDbContext db, CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await db.SaveChangesAsync(token);
|
||||
return result;
|
||||
}
|
||||
catch (DbUpdateException ex)
|
||||
{
|
||||
if (ex.InnerException is PostgresException pgException)
|
||||
TryConvertPostgresExceptionToValidateException(pgException);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private static void TryConvertPostgresExceptionToValidateException(PostgresException pgException)
|
||||
{
|
||||
if (pgException.SqlState == PostgresErrorCodes.ForeignKeyViolation)
|
||||
// TODO: replace ArgumentException by new Exception
|
||||
throw new ArgumentException(pgException.Message + "\r\n" + pgException.Detail, "dtos");
|
||||
}
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ using System.Reflection;
|
||||
|
||||
namespace AsbCloudDb
|
||||
{
|
||||
public static class EFExtentionsSortBy
|
||||
public static class EFExtensionsSortBy
|
||||
{
|
||||
struct TypeAcessor
|
||||
{
|
@ -1,10 +1,11 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Data.DetectedOperation;
|
||||
using AsbCloudApp.Data.SAUB;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Requests;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.Services.DetectOperations.Detectors;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using AsbCloudInfrastructure.Services.DetectOperations;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -19,7 +20,6 @@ namespace AsbCloudInfrastructure.Background.PeriodicWorks
|
||||
/// </summary>
|
||||
internal class WorkDataSaubStat : Work
|
||||
{
|
||||
private int MechanicalDrillingCategoryId = 4001;
|
||||
private int Gap = 60;
|
||||
|
||||
public WorkDataSaubStat() : base("Generate DataSaubStat entries and save them into Db")
|
||||
@ -29,7 +29,6 @@ namespace AsbCloudInfrastructure.Background.PeriodicWorks
|
||||
|
||||
protected override async Task Action(string id, IServiceProvider services, Action<string, double?> onProgressCallback, CancellationToken token)
|
||||
{
|
||||
using var db = services.GetRequiredService<IAsbCloudDbContext>();
|
||||
|
||||
var telemetryDataCache = services.GetRequiredService<ITelemetryDataCache<TelemetryDataSaubDto>>();
|
||||
|
||||
@ -43,96 +42,102 @@ namespace AsbCloudInfrastructure.Background.PeriodicWorks
|
||||
return;
|
||||
|
||||
var dataSaubStatRepo = services.GetRequiredService<IDataSaubStatRepository>();
|
||||
var dataSaubService = services.GetRequiredService<ITelemetryDataSaubService>();
|
||||
var detectedOperationRepository = services.GetRequiredService<IDetectedOperationRepository>();
|
||||
var stats = await dataSaubStatRepo.GetLastsAsync(idTelemetries, token);
|
||||
|
||||
for( var i =0; i < idTelemetries.Length; i++)
|
||||
{
|
||||
var idTelemetry = idTelemetries[i];
|
||||
var lastDate = stats.FirstOrDefault(s => s.IdTelemetry == idTelemetry)?.DateEnd ?? DateTimeOffset.UnixEpoch;
|
||||
var statsCount = await CreateStatForTelemetryFromDate(db, idTelemetry, lastDate, dataSaubStatRepo, token);
|
||||
var lastDate = stats.FirstOrDefault(s => s.IdTelemetry == idTelemetry)?.DateEnd.ToUniversalTime() ?? DateTimeOffset.UnixEpoch;
|
||||
var statsCount = await CreateStatForTelemetryFromDate(idTelemetry, lastDate, dataSaubService, dataSaubStatRepo, detectedOperationRepository, token);
|
||||
onProgressCallback($"Calculate stat for telemetry: {idTelemetry}; from {lastDate}; results count: {statsCount};", 100*i / idTelemetries.Length);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<int> CreateStatForTelemetryFromDate(IAsbCloudDbContext db, int idTelemetry, DateTimeOffset begin, IDataSaubStatRepository dataSaubStatRepo, CancellationToken token)
|
||||
private static async Task<int> CreateStatForTelemetryFromDate(
|
||||
int idTelemetry,
|
||||
DateTimeOffset begin,
|
||||
ITelemetryDataSaubService dataSaubService,
|
||||
IDataSaubStatRepository dataSaubStatRepo,
|
||||
IDetectedOperationRepository detectedOperationRepository,
|
||||
CancellationToken token)
|
||||
{
|
||||
var detectedOperations = await db.Set<DetectedOperation>()
|
||||
.Where(o => o.IdTelemetry == idTelemetry)
|
||||
.Where(o => o.DateStart > begin)
|
||||
.Where(o => o.OperationCategory.IdParent == MechanicalDrillingCategoryId)
|
||||
.OrderBy(o => o.DateStart)
|
||||
.Take(250)
|
||||
.ToArrayAsync(token);
|
||||
var detectedOperationRequest = new DetectedOperationByTelemetryRequest {
|
||||
GeDateStart = begin,
|
||||
IdTelemetry = idTelemetry,
|
||||
IdsCategories = WellOperationCategory.MechanicalDrillingSubIds,
|
||||
SortFields = new[] {nameof(DetectedOperation.DateStart) },
|
||||
Take = 250,
|
||||
};
|
||||
|
||||
var detectedOperations = await detectedOperationRepository.Get(detectedOperationRequest, token);
|
||||
|
||||
if (!detectedOperations.Any())
|
||||
return 0;
|
||||
|
||||
var minDate = detectedOperations.First().DateStart;
|
||||
var maxDate = detectedOperations.OrderByDescending(d => d.DateEnd).First().DateEnd;
|
||||
var geDate = detectedOperations.First().DateStart;
|
||||
var leDate = detectedOperations.OrderByDescending(d => d.DateEnd).First().DateEnd;
|
||||
|
||||
var telemetryDataSaub = await db.Set<TelemetryDataSaub>()
|
||||
.Where(t => t.IdTelemetry == idTelemetry)
|
||||
.Where(t => t.DateTime >= minDate)
|
||||
.Where(t => t.DateTime <= maxDate)
|
||||
.Where(t => Math.Abs(t.BitDepth - t.WellDepth) < 0.0001)
|
||||
.OrderBy(t => t.DateTime)
|
||||
.Take(100_000)
|
||||
.ToArrayAsync(token);
|
||||
var dataSaub = await dataSaubService.Get(idTelemetry, true, geDate, leDate, 100_000, token);
|
||||
|
||||
if (!telemetryDataSaub.Any())
|
||||
if (!dataSaub.Any())
|
||||
return 0;
|
||||
|
||||
var dataSaubStats = CreateDataSaubStat(detectedOperations, telemetryDataSaub);
|
||||
if(dataSaub is not TelemetryDataSaubDto[] dataSaubArray)
|
||||
dataSaubArray = dataSaub.ToArray();
|
||||
|
||||
var dataSaubStats = CreateDataSaubStat(detectedOperations, dataSaubArray);
|
||||
|
||||
return await dataSaubStatRepo.InsertRangeAsync(dataSaubStats, token);
|
||||
}
|
||||
|
||||
private static IEnumerable<DataSaubStatDto> CreateDataSaubStat(IEnumerable<DetectedOperation> detectedOperations, TelemetryDataSaub[] telemetryDataSaub)
|
||||
private static IEnumerable<DataSaubStatDto> CreateDataSaubStat(IEnumerable<DetectedOperationDto> detectedOperations, TelemetryDataSaubDto[] dataSaub)
|
||||
{
|
||||
var indexStart = 0;
|
||||
var indexEnd = 0;
|
||||
var result = new List<DataSaubStatDto>();
|
||||
|
||||
if (!telemetryDataSaub.Any())
|
||||
if (!dataSaub.Any())
|
||||
return result;
|
||||
|
||||
foreach (var operation in detectedOperations)
|
||||
{
|
||||
indexStart = Array.FindIndex(telemetryDataSaub, indexEnd, t => t.DateTime >= operation.DateStart);
|
||||
indexStart = Array.FindIndex(dataSaub, indexEnd, t => t.DateTime >= operation.DateStart);
|
||||
if (indexStart < 0)
|
||||
break;
|
||||
|
||||
indexEnd = Array.FindIndex(telemetryDataSaub, indexStart, t => t.DateTime > operation.DateEnd);
|
||||
indexEnd = Array.FindIndex(dataSaub, indexStart, t => t.DateTime > operation.DateEnd);
|
||||
|
||||
if (indexEnd < 0)
|
||||
indexEnd = telemetryDataSaub.Length - 1;
|
||||
indexEnd = dataSaub.Length - 1;
|
||||
|
||||
if (indexEnd == indexStart)
|
||||
continue;
|
||||
|
||||
var length = indexEnd - indexStart;
|
||||
|
||||
var subset = telemetryDataSaub.AsSpan(indexStart, length);
|
||||
var subset = dataSaub.AsSpan(indexStart, length);
|
||||
var stats = CalcStats(operation, subset);
|
||||
result.AddRange(stats);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IEnumerable<DataSaubStatDto> CalcStats(DetectedOperation operation, Span<TelemetryDataSaub> telemetryDataSaub)
|
||||
private static IEnumerable<DataSaubStatDto> CalcStats(DetectedOperationDto operation, Span<TelemetryDataSaubDto> dataSaub)
|
||||
{
|
||||
var result = new List<DataSaubStatDto>();
|
||||
|
||||
var indexStart = 0;
|
||||
for (var i = 1; i < telemetryDataSaub.Length; i++)
|
||||
for (var i = 1; i < dataSaub.Length; i++)
|
||||
{
|
||||
var previous = telemetryDataSaub[i - 1];
|
||||
var current = telemetryDataSaub[i];
|
||||
var previous = dataSaub[i - 1];
|
||||
var current = dataSaub[i];
|
||||
|
||||
if (IsNewCacheItem(previous, current) || i == telemetryDataSaub.Length - 1)
|
||||
if (IsNewCacheItem(previous, current) || i == dataSaub.Length - 1)
|
||||
{
|
||||
var length = i - indexStart;
|
||||
var span = telemetryDataSaub.Slice(indexStart, length);
|
||||
var span = dataSaub.Slice(indexStart, length);
|
||||
indexStart = i;
|
||||
if (length <= 2 || (span[^1].WellDepth - span[0].WellDepth) < 0.001)
|
||||
continue; // мелкие выборки не учитываем.
|
||||
@ -144,10 +149,9 @@ namespace AsbCloudInfrastructure.Background.PeriodicWorks
|
||||
return result;
|
||||
}
|
||||
|
||||
private static DataSaubStatDto CalcStat(DetectedOperation operation, Span<TelemetryDataSaub> span)
|
||||
private static DataSaubStatDto CalcStat(DetectedOperationDto operation, Span<TelemetryDataSaubDto> span)
|
||||
{
|
||||
var hasOscillation = operation.ExtraData.TryGetValue(DetectorDrilling.ExtraDataKeyHasOscillation, out object? hasOscillationObject)
|
||||
&& hasOscillationObject is true;
|
||||
var hasOscillation = EnabledSubsystemsFlags.AutoOscillation.HasEnabledSubsystems(operation.EnabledSubsystems);
|
||||
|
||||
var aggregatedValues = CalcAggregate(span);
|
||||
var processMapDrillingCacheItem = new DataSaubStatDto
|
||||
@ -184,7 +188,7 @@ namespace AsbCloudInfrastructure.Background.PeriodicWorks
|
||||
double RotorTorque,
|
||||
double RotorSpeed,
|
||||
double Flow
|
||||
) CalcAggregate(Span<TelemetryDataSaub> span)
|
||||
) CalcAggregate(Span<TelemetryDataSaubDto> span)
|
||||
{
|
||||
var sumPressure = 0.0;
|
||||
var sumAxialLoad = 0.0;
|
||||
@ -210,7 +214,7 @@ namespace AsbCloudInfrastructure.Background.PeriodicWorks
|
||||
);
|
||||
}
|
||||
|
||||
private static bool IsNewCacheItem(TelemetryDataSaub previous, TelemetryDataSaub current)
|
||||
private static bool IsNewCacheItem(TelemetryDataSaubDto previous, TelemetryDataSaubDto current)
|
||||
{
|
||||
return !(current.Mode == previous.Mode)
|
||||
|| !(current.WellDepth >= previous.WellDepth)
|
||||
|
@ -327,6 +327,8 @@ namespace AsbCloudInfrastructure
|
||||
services.AddTransient<IProcessMapPlanService<ProcessMapPlanWellReamDto>, ProcessMapPlanService<ProcessMapPlanWellReamDto>>();
|
||||
|
||||
services.AddTransient<IWellSectionPlanRepository, WellSectionPlanRepository>();
|
||||
services.AddTransient<IWellOperationCategoryRepository, WellOperationCategoryRepository>();
|
||||
services.AddTransient<IDetectedOperationRepository, DetectedOperationRepository>();
|
||||
|
||||
services.AddSingleton<ParserServiceFactory>();
|
||||
|
||||
|
@ -18,11 +18,11 @@ public abstract class ChangeLogRepositoryAbstract<TDto, TEntity, TRequest> : ICh
|
||||
where TEntity : ChangeLogAbstract
|
||||
where TRequest : ChangeLogBaseRequest
|
||||
{
|
||||
protected readonly IAsbCloudDbContext context;
|
||||
protected readonly IAsbCloudDbContext db;
|
||||
|
||||
public ChangeLogRepositoryAbstract(IAsbCloudDbContext context)
|
||||
public ChangeLogRepositoryAbstract(IAsbCloudDbContext db)
|
||||
{
|
||||
this.context = context;
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
public async Task<int> InsertRange(int idUser, IEnumerable<TDto> dtos, CancellationToken token)
|
||||
@ -30,9 +30,10 @@ public abstract class ChangeLogRepositoryAbstract<TDto, TEntity, TRequest> : ICh
|
||||
var result = 0;
|
||||
if (dtos.Any())
|
||||
{
|
||||
using var transaction = await db.Database.BeginTransactionAsync(token);
|
||||
var entities = dtos.Select(Convert);
|
||||
var creation = DateTimeOffset.UtcNow;
|
||||
var dbSet = context.Set<TEntity>();
|
||||
var dbSet = db.Set<TEntity>();
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
entity.Id = default;
|
||||
@ -46,6 +47,7 @@ public abstract class ChangeLogRepositoryAbstract<TDto, TEntity, TRequest> : ICh
|
||||
}
|
||||
|
||||
result += await SaveChangesWithExceptionHandling(token);
|
||||
await transaction.CommitAsync(token);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -62,9 +64,8 @@ public abstract class ChangeLogRepositoryAbstract<TDto, TEntity, TRequest> : ICh
|
||||
|
||||
var ids = dtos.Select(d => d.Id);
|
||||
|
||||
using var transaction = context.Database.BeginTransaction();
|
||||
var result = 0;
|
||||
var dbSet = context
|
||||
var dbSet = db
|
||||
.Set<TEntity>();
|
||||
|
||||
var entitiesToDelete = await dbSet
|
||||
@ -80,13 +81,14 @@ public abstract class ChangeLogRepositoryAbstract<TDto, TEntity, TRequest> : ICh
|
||||
throw new ArgumentInvalidException(nameof(dtos), $"записи с id:[{stringnotFoundIds}] не найдены, или не актуальны.");
|
||||
}
|
||||
|
||||
using var transaction = db.Database.BeginTransaction();
|
||||
foreach (var entity in entitiesToDelete)
|
||||
{
|
||||
entity.IdState = ChangeLogAbstract.IdStateReplaced;
|
||||
entity.Obsolete = updateTime;
|
||||
entity.IdEditor = idUser;
|
||||
}
|
||||
result += await context.SaveChangesAsync(token);
|
||||
result += await db.SaveChangesAsync(token);
|
||||
|
||||
var entitiesNew = dtos.Select(Convert);
|
||||
foreach (var entity in entitiesNew)
|
||||
@ -143,7 +145,7 @@ public abstract class ChangeLogRepositoryAbstract<TDto, TEntity, TRequest> : ICh
|
||||
public async Task<int> ClearAndInsertRange(int idUser, TRequest request, IEnumerable<TDto> dtos, CancellationToken token)
|
||||
{
|
||||
var result = 0;
|
||||
var transaction = await context.Database.BeginTransactionAsync(token);
|
||||
using var transaction = await db.Database.BeginTransactionAsync(token);
|
||||
result += await Clear(idUser, request, token);
|
||||
result += await InsertRange(idUser, dtos, token);
|
||||
await transaction.CommitAsync(token);
|
||||
@ -153,7 +155,7 @@ public abstract class ChangeLogRepositoryAbstract<TDto, TEntity, TRequest> : ICh
|
||||
public async Task<int> DeleteRange(int idUser, IEnumerable<int> ids, CancellationToken token)
|
||||
{
|
||||
var updateTime = DateTimeOffset.UtcNow;
|
||||
var query = context.Set<TEntity>()
|
||||
var query = db.Set<TEntity>()
|
||||
.Where(e => ids.Contains(e.Id))
|
||||
.Where(e => e.Obsolete == null);
|
||||
|
||||
@ -269,7 +271,7 @@ public abstract class ChangeLogRepositoryAbstract<TDto, TEntity, TRequest> : ICh
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await context.SaveChangesAsync(token);
|
||||
var result = await db.SaveChangesAsync(token);
|
||||
return result;
|
||||
}
|
||||
catch (DbUpdateException ex)
|
||||
|
191
AsbCloudInfrastructure/Repository/DetectedOperationRepository.cs
Normal file
191
AsbCloudInfrastructure/Repository/DetectedOperationRepository.cs
Normal file
@ -0,0 +1,191 @@
|
||||
using AsbCloudApp.Data.DetectedOperation;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Requests;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb;
|
||||
using AsbCloudDb.Model;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudInfrastructure.Repository;
|
||||
|
||||
public class DetectedOperationRepository : IDetectedOperationRepository
|
||||
{
|
||||
private readonly IAsbCloudDbContext db;
|
||||
private readonly ITelemetryService telemetryService;
|
||||
|
||||
public DetectedOperationRepository(
|
||||
IAsbCloudDbContext db,
|
||||
ITelemetryService telemetryService)
|
||||
{
|
||||
this.db = db;
|
||||
this.telemetryService = telemetryService;
|
||||
}
|
||||
|
||||
public async Task<int> Delete(int idUser, DetectedOperationByTelemetryRequest request, CancellationToken token)
|
||||
{
|
||||
var query = BuildQuery(request);
|
||||
db.Set<DetectedOperation>().RemoveRange(query);
|
||||
return await db.SaveChangesAsync(token);
|
||||
}
|
||||
|
||||
public async Task<int> DeleteRange(int idUser, IEnumerable<int> ids, CancellationToken token)
|
||||
{
|
||||
var query = db.Set<DetectedOperation>()
|
||||
.Where(e => ids.Contains( e.Id));
|
||||
|
||||
db.Set<DetectedOperation>()
|
||||
.RemoveRange(query);
|
||||
|
||||
return await db.SaveChangesAsync(token);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<DetectedOperationDto>> Get(DetectedOperationByTelemetryRequest request, CancellationToken token)
|
||||
{
|
||||
var query = BuildQuery(request)
|
||||
.Include(o => o.OperationCategory);
|
||||
var entities = await query.ToArrayAsync(token);
|
||||
var offset = telemetryService.GetTimezone(request.IdTelemetry).Offset;
|
||||
var dtos = entities.Select(o => Convert(o, offset));
|
||||
|
||||
return dtos;
|
||||
}
|
||||
|
||||
public async Task<int> Insert(int? idUser, IEnumerable<DetectedOperationDto> dtos, CancellationToken token)
|
||||
{
|
||||
if(!dtos.Any())
|
||||
return 0;
|
||||
|
||||
var entities = dtos.Select(Convert);
|
||||
var dbset = db.Set<DetectedOperation>();
|
||||
foreach(var entity in entities)
|
||||
{
|
||||
entity.Id = default;
|
||||
dbset.Add(entity);
|
||||
}
|
||||
|
||||
return await db.SaveChangesWithExceptionHandling(token);
|
||||
}
|
||||
|
||||
public async Task<int> Update(int idUser, IEnumerable<DetectedOperationDto> dtos, CancellationToken token)
|
||||
{
|
||||
if (!dtos.Any())
|
||||
return 0;
|
||||
|
||||
var ids = dtos
|
||||
.Select(o => o.Id)
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
|
||||
if (ids.Any(id => id == default))
|
||||
throw new ArgumentInvalidException(nameof(dtos), "Все записи должны иметь Id");
|
||||
|
||||
if (ids.Length != dtos.Count())
|
||||
throw new ArgumentInvalidException(nameof(dtos), "Все записи должны иметь уникальные Id");
|
||||
|
||||
var dbSet = db.Set<DetectedOperation>();
|
||||
|
||||
var existingEntitiesCount = await dbSet
|
||||
.Where(o => ids.Contains(o.Id))
|
||||
.CountAsync(token);
|
||||
|
||||
if (ids.Length != existingEntitiesCount)
|
||||
throw new ArgumentInvalidException(nameof(dtos), "Все записи должны существовать в БД");
|
||||
|
||||
var entities = dtos
|
||||
.Select(Convert)
|
||||
.ToArray();
|
||||
|
||||
var entries = new Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<DetectedOperation>[entities.Length];
|
||||
for(var i = 0; i < entities.Length; i++)
|
||||
entries[i] = dbSet.Update(entities[i]);
|
||||
|
||||
var result = await db.SaveChangesWithExceptionHandling(token);
|
||||
|
||||
for (var i = 0; i < entries.Length; i++)
|
||||
entries[i].State = EntityState.Detached;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<int> UpdateOrInsert(int idUser, IEnumerable<DetectedOperationDto> dtos, CancellationToken token)
|
||||
{
|
||||
var result = 0;
|
||||
|
||||
var itemsToInsert = dtos.Where(e => e.Id == 0);
|
||||
if (itemsToInsert.Any())
|
||||
result += await Insert(idUser, itemsToInsert, token);
|
||||
|
||||
var itemsToUpdate = dtos.Where(e => e.Id != 0);
|
||||
if (itemsToUpdate.Any())
|
||||
result += await Update(idUser, itemsToUpdate, token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private IQueryable<DetectedOperation> BuildQuery(DetectedOperationByTelemetryRequest request)
|
||||
{
|
||||
var query = db.Set<DetectedOperation>()
|
||||
.Where(o => o.IdTelemetry == request.IdTelemetry);
|
||||
|
||||
if (request.IdsCategories.Any())
|
||||
query = query.Where(o => request.IdsCategories.Contains(o.IdCategory));
|
||||
|
||||
if (request.GeDepthStart is not null)
|
||||
query = query.Where(o => o.DepthStart >= request.GeDepthStart);
|
||||
|
||||
if (request.LeDepthEnd is not null)
|
||||
query = query.Where(o => o.DepthEnd <= request.LeDepthEnd);
|
||||
|
||||
if (request.GeDateStart is not null)
|
||||
{
|
||||
var geDate = request.GeDateStart.Value.ToUniversalTime();
|
||||
query = query.Where(o => o.DateStart >= geDate);
|
||||
}
|
||||
|
||||
if (request.LeDateEnd is not null)
|
||||
{
|
||||
var leDate = request.LeDateEnd.Value.ToUniversalTime();
|
||||
query = query.Where(o => o.DateEnd <= leDate);
|
||||
}
|
||||
|
||||
if (request.SortFields?.Any() == true)
|
||||
{
|
||||
query = query.SortBy(request.SortFields);
|
||||
}
|
||||
else
|
||||
query = query
|
||||
.OrderBy(o => o.DateStart)
|
||||
.ThenBy(o => o.DepthStart);
|
||||
|
||||
if (request.Skip.HasValue)
|
||||
query = query.Skip((int)request.Skip);
|
||||
|
||||
if (request.Take.HasValue)
|
||||
query = query.Take((int)request.Take);
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
private static DetectedOperationDto Convert(DetectedOperation entity, TimeSpan offset)
|
||||
{
|
||||
var dto = entity.Adapt<DetectedOperationDto>();
|
||||
dto.DateStart = entity.DateStart.ToOffset(offset);
|
||||
dto.DateEnd = entity.DateEnd.ToOffset(offset);
|
||||
return dto;
|
||||
}
|
||||
|
||||
private static DetectedOperation Convert(DetectedOperationDto dto)
|
||||
{
|
||||
var entity = dto.Adapt<DetectedOperation>();
|
||||
entity.DateStart = dto.DateStart.ToUniversalTime();
|
||||
entity.DateEnd = dto.DateEnd.ToUniversalTime();
|
||||
return entity;
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@ public class ProcessMapPlanBaseRepository<TDto, TEntity> : ChangeLogRepositoryAb
|
||||
|
||||
protected override IQueryable<TEntity> BuildQuery(ProcessMapPlanBaseRequestWithWell request)
|
||||
{
|
||||
var query = context
|
||||
var query = db
|
||||
.Set<TEntity>()
|
||||
.Include(e => e.Author)
|
||||
.Include(e => e.Editor)
|
||||
|
@ -0,0 +1,44 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudDb.Model;
|
||||
using Mapster;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace AsbCloudInfrastructure.Repository;
|
||||
|
||||
public class WellOperationCategoryRepository : IWellOperationCategoryRepository
|
||||
{
|
||||
private readonly IAsbCloudDbContext db;
|
||||
private readonly IMemoryCache memoryCache;
|
||||
|
||||
public WellOperationCategoryRepository(IAsbCloudDbContext db, IMemoryCache memoryCache)
|
||||
{
|
||||
this.db = db;
|
||||
this.memoryCache = memoryCache;
|
||||
}
|
||||
|
||||
public IEnumerable<WellOperationCategoryDto> Get(bool includeParents)
|
||||
{
|
||||
var categories = memoryCache
|
||||
.GetOrCreateBasic(db.Set<WellOperationCategory>());
|
||||
|
||||
if (!includeParents)
|
||||
{
|
||||
var parentIds = categories
|
||||
.Select(o => o.IdParent)
|
||||
.Distinct();
|
||||
|
||||
categories = categories
|
||||
.Where(o => !parentIds.Contains(o.Id));
|
||||
}
|
||||
|
||||
var result = categories
|
||||
.OrderBy(o => o.Name)
|
||||
.Adapt<IEnumerable<WellOperationCategoryDto>>();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -28,35 +28,20 @@ public class WellOperationRepository : IWellOperationRepository
|
||||
private readonly IAsbCloudDbContext db;
|
||||
private readonly IMemoryCache memoryCache;
|
||||
private readonly IWellService wellService;
|
||||
private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
|
||||
|
||||
public WellOperationRepository(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService)
|
||||
public WellOperationRepository(IAsbCloudDbContext db, IMemoryCache memoryCache, IWellService wellService, IWellOperationCategoryRepository wellOperationCategoryRepository)
|
||||
{
|
||||
this.db = db;
|
||||
this.memoryCache = memoryCache;
|
||||
this.wellService = wellService;
|
||||
this.wellOperationCategoryRepository = wellOperationCategoryRepository;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<WellOperationCategoryDto> GetCategories(bool includeParents)
|
||||
{
|
||||
var categories = memoryCache
|
||||
.GetOrCreateBasic(db.Set<WellOperationCategory>());
|
||||
|
||||
if (!includeParents)
|
||||
{
|
||||
var parentIds = categories
|
||||
.Select(o => o.IdParent)
|
||||
.Distinct();
|
||||
|
||||
categories = categories
|
||||
.Where(o => !parentIds.Contains(o.Id));
|
||||
}
|
||||
|
||||
var result = categories
|
||||
.OrderBy(o => o.Name)
|
||||
.Adapt<IEnumerable<WellOperationCategoryDto>>();
|
||||
|
||||
return result;
|
||||
return wellOperationCategoryRepository.Get(includeParents);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
@ -282,7 +282,7 @@ public class DailyReportService : IDailyReportService
|
||||
var leDateEnd = dailyReport.Date.AddDays(1).ToDateTime(TimeOnly.MinValue, DateTimeKind.Unspecified);
|
||||
|
||||
dailyReport.TimeBalanceBlock.WellOperationSlipsTimeCount = (await detectedOperationService.GetAsync(
|
||||
new DetectedOperationRequest
|
||||
new DetectedOperationByWellRequest
|
||||
{
|
||||
IdsCategories = new[] { idWellOperationSlipsTime },
|
||||
IdWell = dailyReport.IdWell,
|
||||
|
@ -1,6 +1,5 @@
|
||||
using AsbCloudDb.Model;
|
||||
using ClosedXML.Excel;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@ -9,22 +8,21 @@ using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data.DetectedOperation;
|
||||
using AsbCloudInfrastructure.Services.DetectOperations.Detectors;
|
||||
using AsbCloudApp.Repositories;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudInfrastructure.Services.DetectOperations.Detectors;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations;
|
||||
|
||||
public class DetectedOperationExportService
|
||||
{
|
||||
private readonly DetectorAbstract[] detectors =
|
||||
{
|
||||
new DetectorDrilling(),
|
||||
new DetectorSlipsTime()
|
||||
};
|
||||
|
||||
private const int headerRowsCount = 1;
|
||||
private readonly IAsbCloudDbContext db;
|
||||
private readonly IWellService wellService;
|
||||
private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
|
||||
private const int headerRowsCount = 1;
|
||||
|
||||
private const string cellDepositName = "B1";
|
||||
private const string cellClusterName = "B2";
|
||||
@ -42,14 +40,14 @@ public class DetectedOperationExportService
|
||||
private const int columnIdReasonOfEnd = 9;
|
||||
private const int columnComment = 10;
|
||||
|
||||
//TODO: удалить неиспользуемую зависимость
|
||||
private readonly IAsbCloudDbContext dbContext;
|
||||
private readonly IWellOperationRepository wellOperationRepository;
|
||||
|
||||
public DetectedOperationExportService(IAsbCloudDbContext dbContext, IWellOperationRepository wellOperationRepository)
|
||||
public DetectedOperationExportService(
|
||||
IAsbCloudDbContext db,
|
||||
IWellService wellService,
|
||||
IWellOperationCategoryRepository wellOperationCategoryRepository)
|
||||
{
|
||||
this.dbContext = dbContext;
|
||||
this.wellOperationRepository = wellOperationRepository;
|
||||
this.db = db;
|
||||
this.wellService = wellService;
|
||||
this.wellOperationCategoryRepository = wellOperationCategoryRepository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -57,15 +55,12 @@ public class DetectedOperationExportService
|
||||
/// </summary>
|
||||
/// <param name="idWell">ключ скважины</param>
|
||||
/// <param name="host">хост</param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentInvalidException"></exception>
|
||||
public async Task<Stream> ExportAsync(int idWell, string host, CancellationToken cancellationToken)
|
||||
public async Task<Stream> ExportAsync(int idWell, string host, CancellationToken token)
|
||||
{
|
||||
var well = await dbContext.Set<Well>()
|
||||
.Include(w => w.Cluster)
|
||||
.ThenInclude(c => c.Deposit)
|
||||
.FirstOrDefaultAsync(w => w.Id == idWell, cancellationToken);
|
||||
var well = await wellService.GetOrDefaultAsync(idWell, token);
|
||||
|
||||
if (well is null)
|
||||
throw new ArgumentInvalidException(nameof(idWell), $"Well {idWell} does not exist");
|
||||
@ -73,19 +68,19 @@ public class DetectedOperationExportService
|
||||
if (!well.IdTelemetry.HasValue)
|
||||
throw new ArgumentInvalidException(nameof(idWell), $"Well {idWell} has no telemetry");
|
||||
|
||||
var operations = await DetectOperationsAsync(well.IdTelemetry.Value, DateTime.UnixEpoch, cancellationToken);
|
||||
var operations = await WorkOperationDetection.DetectOperationsAsync(well.IdTelemetry.Value, DateTime.UnixEpoch, db, token);
|
||||
|
||||
return await GenerateExcelFileStreamAsync(well, host, operations, cancellationToken);
|
||||
return await GenerateExcelFileStreamAsync(well, host, operations, token);
|
||||
}
|
||||
|
||||
private async Task<Stream> GenerateExcelFileStreamAsync(Well well, string host, IEnumerable<OperationDetectorResult> operationDetectorResults,
|
||||
private async Task<Stream> GenerateExcelFileStreamAsync(WellDto well, string host, IEnumerable<DetectedOperation> operationDetectorResults,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
using var excelTemplateStream = await GetExcelTemplateStreamAsync(cancellationToken);
|
||||
|
||||
using var workbook = new XLWorkbook(excelTemplateStream);
|
||||
|
||||
await AddToWorkbookAsync(workbook, well, host, operationDetectorResults, cancellationToken);
|
||||
AddToWorkbook(workbook, well, host, operationDetectorResults);
|
||||
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
workbook.SaveAs(memoryStream, new SaveOptions { });
|
||||
@ -93,36 +88,34 @@ public class DetectedOperationExportService
|
||||
return memoryStream;
|
||||
}
|
||||
|
||||
private async Task AddToWorkbookAsync(XLWorkbook workbook, Well well, string host, IEnumerable<OperationDetectorResult> operationDetectorResults,
|
||||
CancellationToken cancellationToken)
|
||||
private void AddToWorkbook(XLWorkbook workbook, WellDto well, string host, IEnumerable<DetectedOperation> operations)
|
||||
{
|
||||
const string sheetName = "Операции";
|
||||
|
||||
if (!operationDetectorResults.Any())
|
||||
if (!operations.Any())
|
||||
return;
|
||||
|
||||
var sheet = workbook.GetWorksheet(sheetName);
|
||||
|
||||
await AddToSheetAsync(sheet, well, host, operationDetectorResults
|
||||
.OrderBy(x => x.Operation.DateStart).ThenBy(x => x.Operation.DepthStart).ToArray(),
|
||||
cancellationToken);
|
||||
var orderedOperations = operations
|
||||
.OrderBy(x => x.DateStart)
|
||||
.ThenBy(x => x.DepthStart).ToArray();
|
||||
|
||||
AddToSheet(sheet, well, host, orderedOperations);
|
||||
}
|
||||
|
||||
private async Task AddToSheetAsync(IXLWorksheet sheet, Well well, string host, IList<OperationDetectorResult> operationDetectorResults,
|
||||
CancellationToken cancellationToken)
|
||||
private void AddToSheet(IXLWorksheet sheet, WellDto well, string host, IList<DetectedOperation> operations)
|
||||
{
|
||||
var wellOperationCategories = await dbContext.WellOperationCategories.ToListAsync(cancellationToken);
|
||||
var wellOperationCategories = wellOperationCategoryRepository.Get(true);
|
||||
|
||||
sheet.Cell(cellDepositName).SetCellValue(well.Cluster.Deposit.Caption);
|
||||
sheet.Cell(cellClusterName).SetCellValue(well.Cluster.Caption);
|
||||
sheet.Cell(cellDepositName).SetCellValue(well.Deposit);
|
||||
sheet.Cell(cellClusterName).SetCellValue(well.Cluster);
|
||||
sheet.Cell(cellWellName).SetCellValue(well.Caption);
|
||||
sheet.Cell(cellDeltaDate).SetCellValue(operationDetectorResults.Max(o => o.Operation.DateEnd) - operationDetectorResults.Min(o => o.Operation.DateStart));
|
||||
sheet.Cell(cellDeltaDate).SetCellValue((TimeSpan)(Enumerable.Max<DetectedOperation, DateTimeOffset>(operations, (Func<DetectedOperation, DateTimeOffset>)(o => o.DateEnd)) - Enumerable.Min<DetectedOperation, DateTimeOffset>(operations, (Func<DetectedOperation, DateTimeOffset>)(o => o.DateStart))));
|
||||
|
||||
var detectedOperations = operationDetectorResults.Select(o => o.Operation).ToArray();
|
||||
|
||||
for (int i = 0; i < operationDetectorResults.Count; i++)
|
||||
for (int i = 0; i < operations.Count; i++)
|
||||
{
|
||||
var current = detectedOperations[i];
|
||||
var current = operations[i];
|
||||
var dateStart = current.DateStart.ToRemoteDateTime(well.Timezone.Hours);
|
||||
var dateEnd = current.DateEnd.ToRemoteDateTime(well.Timezone.Hours);
|
||||
|
||||
@ -153,17 +146,18 @@ public class DetectedOperationExportService
|
||||
var link = $"{host}/well/{well.Id}/telemetry/monitoring{query}";
|
||||
row.Cell(columnDateStart).SetHyperlink(link);
|
||||
|
||||
var deltaDepth = i > 0 && i + 1 < detectedOperations.Length
|
||||
? current.DepthStart - detectedOperations[i - 1].DepthEnd
|
||||
var deltaDepth = i > 0 && i + 1 < operations.Count
|
||||
? current.DepthStart - operations[i - 1].DepthEnd
|
||||
: 0;
|
||||
|
||||
row.Cell(columnDeltaDepth).SetCellValue(deltaDepth);
|
||||
|
||||
var comment = CreateComment(operationDetectorResults[i]);
|
||||
var comment = CreateComment(operations[i]);
|
||||
row.Cell(columnComment).SetCellValue(comment);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetCategoryName(IEnumerable<WellOperationCategory> wellOperationCategories, DetectedOperation current)
|
||||
private static string GetCategoryName(IEnumerable<WellOperationCategoryDto> wellOperationCategories, DetectedOperation current)
|
||||
{
|
||||
var idCategory = current.IdCategory;
|
||||
if (idCategory == WellOperationCategory.IdSlide &&
|
||||
@ -204,9 +198,8 @@ public class DetectedOperationExportService
|
||||
return memoryStream;
|
||||
}
|
||||
|
||||
private static string CreateComment(OperationDetectorResult operationDetectorResult)
|
||||
private static string CreateComment(DetectedOperation operation)
|
||||
{
|
||||
var operation = operationDetectorResult.Operation;
|
||||
switch (operation.IdCategory)
|
||||
{
|
||||
case WellOperationCategory.IdRotor:
|
||||
@ -224,69 +217,4 @@ public class DetectedOperationExportService
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<OperationDetectorResult>> DetectOperationsAsync(int idTelemetry, DateTimeOffset begin,
|
||||
CancellationToken token)
|
||||
{
|
||||
var query = dbContext.TelemetryDataSaub
|
||||
.AsNoTracking()
|
||||
.Where(d => d.IdTelemetry == idTelemetry)
|
||||
.Where(d => d.BlockPosition >= 0)
|
||||
.Select(d => new DetectableTelemetry
|
||||
{
|
||||
DateTime = d.DateTime,
|
||||
IdUser = d.IdUser,
|
||||
WellDepth = d.WellDepth,
|
||||
Pressure = d.Pressure,
|
||||
HookWeight = d.HookWeight,
|
||||
BlockPosition = d.BlockPosition,
|
||||
BitDepth = d.BitDepth,
|
||||
RotorSpeed = d.RotorSpeed,
|
||||
})
|
||||
.OrderBy(d => d.DateTime);
|
||||
|
||||
var startDate = begin;
|
||||
var detectedOperationResults = new List<OperationDetectorResult>(8);
|
||||
DetectedOperation? lastDetectedOperation = null;
|
||||
const int minOperationLength = 5;
|
||||
const int maxDetectorsInterpolationFrameLength = 30;
|
||||
const int gap = maxDetectorsInterpolationFrameLength + minOperationLength;
|
||||
|
||||
while (true)
|
||||
{
|
||||
var data = await query
|
||||
.Where(d => d.DateTime > startDate)
|
||||
.ToArrayAsync(token);
|
||||
|
||||
if (data.Length < gap)
|
||||
break;
|
||||
|
||||
var isDetected = false;
|
||||
var positionBegin = 0;
|
||||
var positionEnd = data.Length - gap;
|
||||
while (positionEnd > positionBegin)
|
||||
{
|
||||
foreach (var detector in detectors)
|
||||
{
|
||||
if (!detector.TryDetect(idTelemetry, data, positionBegin, positionEnd, lastDetectedOperation, out var result))
|
||||
continue;
|
||||
|
||||
detectedOperationResults.Add(result!);
|
||||
lastDetectedOperation = result!.Operation;
|
||||
isDetected = true;
|
||||
positionBegin = result.TelemetryEnd;
|
||||
break;
|
||||
}
|
||||
|
||||
positionBegin += 1;
|
||||
}
|
||||
|
||||
if (isDetected)
|
||||
startDate = lastDetectedOperation!.DateEnd;
|
||||
else
|
||||
startDate = data[positionEnd].DateTime;
|
||||
}
|
||||
|
||||
return detectedOperationResults;
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Data.DetectedOperation;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Requests;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb;
|
||||
@ -11,274 +12,200 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations;
|
||||
|
||||
public class DetectedOperationService : IDetectedOperationService
|
||||
{
|
||||
private readonly IDetectedOperationRepository operationRepository;
|
||||
private readonly IWellOperationCategoryRepository wellOperationCategoryRepository;
|
||||
private readonly IWellService wellService;
|
||||
private readonly IRepositoryWellRelated<OperationValueDto> operationValueService;
|
||||
private readonly IScheduleRepository scheduleService;
|
||||
|
||||
public class DetectedOperationService : IDetectedOperationService
|
||||
public DetectedOperationService(
|
||||
IDetectedOperationRepository operationRepository,
|
||||
IWellOperationCategoryRepository wellOperationCategoryRepository,
|
||||
IWellService wellService,
|
||||
IRepositoryWellRelated<OperationValueDto> operationValueRepository,
|
||||
IScheduleRepository scheduleRepository)
|
||||
{
|
||||
private readonly IAsbCloudDbContext db;
|
||||
private readonly IWellService wellService;
|
||||
private readonly IRepositoryWellRelated<OperationValueDto> operationValueService;
|
||||
private readonly IScheduleRepository scheduleService;
|
||||
this.operationRepository = operationRepository;
|
||||
this.wellOperationCategoryRepository = wellOperationCategoryRepository;
|
||||
this.wellService = wellService;
|
||||
this.operationValueService = operationValueRepository;
|
||||
this.scheduleService = scheduleRepository;
|
||||
}
|
||||
|
||||
public DetectedOperationService(IAsbCloudDbContext db, IWellService wellService,
|
||||
IRepositoryWellRelated<OperationValueDto> operationValueService, IScheduleRepository scheduleService)
|
||||
public async Task<DetectedOperationListDto> GetAsync(DetectedOperationByWellRequest request, CancellationToken token)
|
||||
{
|
||||
var dtos = await GetOperationsAsync(request, token);
|
||||
if (dtos?.Any() != true)
|
||||
return new DetectedOperationListDto();
|
||||
|
||||
var stats = GetOperationsDrillersStat(dtos);
|
||||
var result = new DetectedOperationListDto
|
||||
{
|
||||
this.db = db;
|
||||
this.wellService = wellService;
|
||||
this.operationValueService = operationValueService;
|
||||
this.scheduleService = scheduleService;
|
||||
Operations = dtos,
|
||||
Stats = stats
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<DetectedOperationWithDrillerDto>> GetOperationsAsync(DetectedOperationByWellRequest request, CancellationToken token)
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(request.IdWell, token);
|
||||
if (well?.IdTelemetry is null)
|
||||
return Enumerable.Empty<DetectedOperationWithDrillerDto>();
|
||||
|
||||
var requestByTelemetry = new DetectedOperationByTelemetryRequest(well.IdTelemetry.Value, request);
|
||||
var data = await operationRepository.Get(requestByTelemetry, token);
|
||||
|
||||
var operationValues = await operationValueService.GetByIdWellAsync(request.IdWell, token);
|
||||
var schedules = await scheduleService.GetByIdWellAsync(request.IdWell, token);
|
||||
var dtos = data.Select(o => Convert(o, operationValues, schedules));
|
||||
return dtos;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<WellOperationCategoryDto>> GetCategoriesAsync(int? idWell, CancellationToken token)
|
||||
{
|
||||
if(idWell is null)
|
||||
{
|
||||
return wellOperationCategoryRepository.Get(false);
|
||||
}
|
||||
|
||||
public async Task<DetectedOperationListDto?> GetAsync(DetectedOperationRequest request, CancellationToken token)
|
||||
else
|
||||
{
|
||||
var dtos = await GetOperationsAsync(request, token);
|
||||
if (dtos?.Any() != true)
|
||||
return null;
|
||||
|
||||
var stats = GetOperationsDrillersStat(dtos);
|
||||
var result = new DetectedOperationListDto
|
||||
{
|
||||
Operations = dtos,
|
||||
Stats = stats
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<DetectedOperationDto>> GetOperationsAsync(DetectedOperationRequest request, CancellationToken token)
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(request.IdWell, token);
|
||||
var well = await wellService.GetOrDefaultAsync((int )idWell, token);
|
||||
if (well?.IdTelemetry is null)
|
||||
return Enumerable.Empty<DetectedOperationDto>();
|
||||
return Enumerable.Empty<WellOperationCategoryDto>();
|
||||
|
||||
var query = BuildQuery(well, request).AsNoTracking();
|
||||
|
||||
var data = await query.ToListAsync(token);
|
||||
|
||||
var operationValues = await operationValueService.GetByIdWellAsync(request.IdWell, token);
|
||||
var schedules = await scheduleService.GetByIdWellAsync(request.IdWell, token);
|
||||
var dtos = data.Select(o => Convert(o, well, operationValues, schedules));
|
||||
return dtos;
|
||||
}
|
||||
|
||||
private static IEnumerable<DetectedOperationDrillersStatDto> GetOperationsDrillersStat(IEnumerable<DetectedOperationDto> operations)
|
||||
{
|
||||
var groups = operations.GroupBy(o => o.Driller);
|
||||
|
||||
var stats = new List<DetectedOperationDrillersStatDto>(groups.Count());
|
||||
foreach (var group in groups)
|
||||
var request = new DetectedOperationByTelemetryRequest()
|
||||
{
|
||||
var itemsWithTarget = group.Where(i => i.OperationValue is not null);
|
||||
var stat = new DetectedOperationDrillersStatDto
|
||||
{
|
||||
Driller = group.Key,
|
||||
AverageValue = group.Sum(e => e.Value) / group.Count(),
|
||||
Count = group.Count(),
|
||||
};
|
||||
if (itemsWithTarget.Any())
|
||||
{
|
||||
var itemsOutOfTarget = itemsWithTarget.Where(o => !IsTargetOk(o));
|
||||
stat.AverageTargetValue = itemsWithTarget.Average(e => e.OperationValue?.TargetValue);
|
||||
stat.Efficiency = 100d * itemsOutOfTarget.Count() / itemsWithTarget.Count();
|
||||
stat.Loss = itemsOutOfTarget.Sum(DeltaToTarget);
|
||||
}
|
||||
|
||||
stats.Add(stat);
|
||||
}
|
||||
return stats;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<DetectedOperationStatDto>?> GetOperationsStatAsync(DetectedOperationRequest request, CancellationToken token)
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(request.IdWell, token);
|
||||
if (well?.IdTelemetry is null || well.Timezone is null)
|
||||
return null;
|
||||
|
||||
var query = BuildQuery(well, request)
|
||||
?.AsNoTracking();
|
||||
|
||||
if (query is null)
|
||||
return null;
|
||||
|
||||
var entities = await query
|
||||
.Select(o => new {
|
||||
o.IdCategory,
|
||||
DurationMinutes = (o.DateEnd - o.DateStart).TotalMinutes,
|
||||
o.Value,
|
||||
})
|
||||
.ToListAsync(token);
|
||||
|
||||
if (!entities.Any())
|
||||
return null;
|
||||
|
||||
var operationValues = await operationValueService.GetByIdWellAsync(request.IdWell, token);
|
||||
var categories = await query
|
||||
.Select(o => new {o.IdCategory, o.OperationCategory.Name })
|
||||
.Distinct()
|
||||
.ToDictionaryAsync(c=>c.IdCategory, c=>c.Name, token);
|
||||
|
||||
var dtos = entities
|
||||
.GroupBy(o => o.IdCategory)
|
||||
.OrderBy(g => g.Key)
|
||||
.Select(g => new DetectedOperationStatDto{
|
||||
IdCategory = g.Key,
|
||||
Category = categories[g.Key],
|
||||
Count = g.Count(),
|
||||
MinutesAverage = g.Average(o => o.DurationMinutes),
|
||||
MinutesMin = g.Min(o => o.DurationMinutes),
|
||||
MinutesMax = g.Max(o => o.DurationMinutes),
|
||||
MinutesTotal = g.Sum(o => o.DurationMinutes),
|
||||
ValueAverage = g.Average(o => o.Value),
|
||||
ValueMax = g.Max(o => o.Value),
|
||||
ValueMin = g.Min(o => o.Value),
|
||||
});
|
||||
|
||||
return dtos;
|
||||
}
|
||||
|
||||
public async Task<int> DeleteAsync(DetectedOperationRequest request, CancellationToken token)
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(request.IdWell, token);
|
||||
if (well?.IdTelemetry is null || well.Timezone is null)
|
||||
return 0;
|
||||
|
||||
var query = BuildQueryBase(well, request);
|
||||
|
||||
if (query is null)
|
||||
return 0;
|
||||
|
||||
db.DetectedOperations.RemoveRange(query);
|
||||
return await db.SaveChangesAsync(token);
|
||||
}
|
||||
|
||||
private static bool IsTargetOk(DetectedOperationDto op)
|
||||
{
|
||||
return (op.IdCategory) switch
|
||||
{
|
||||
WellOperationCategory.IdRotor => op.Value > op.OperationValue?.TargetValue,
|
||||
WellOperationCategory.IdSlide => op.Value > op.OperationValue?.TargetValue,
|
||||
WellOperationCategory.IdSlipsTime => op.Value > op.OperationValue?.TargetValue,
|
||||
_ => op.Value > op.OperationValue?.TargetValue,
|
||||
IdTelemetry = well.IdTelemetry.Value
|
||||
};
|
||||
}
|
||||
|
||||
private static double DeltaToTarget(DetectedOperationDto op)
|
||||
{
|
||||
return (op.IdCategory) switch
|
||||
{
|
||||
WellOperationCategory.IdRotor => 0,
|
||||
WellOperationCategory.IdSlide => 0,
|
||||
WellOperationCategory.IdSlipsTime => op.Value - op.OperationValue?.TargetValue??0,
|
||||
_ => 0,
|
||||
};
|
||||
}
|
||||
|
||||
private IQueryable<DetectedOperation> BuildQueryBase(WellDto well, DetectedOperationRequest request)
|
||||
{
|
||||
var query = db.Set<DetectedOperation>()
|
||||
.Where(o => o.IdTelemetry == well.IdTelemetry);
|
||||
|
||||
if (request.IdsTelemetries.Any())
|
||||
{
|
||||
query = query
|
||||
.Union(db.Set<DetectedOperation>().Where(o => request.IdsTelemetries.Contains(o.IdTelemetry)));
|
||||
}
|
||||
|
||||
if (request.IdsCategories.Any())
|
||||
query = query.Where(o => request.IdsCategories.Contains(o.IdCategory));
|
||||
|
||||
if (request.GeDateStart is not null)
|
||||
query = query.Where(o => o.DateStart >= request.GeDateStart.Value.Date.ToUtcDateTimeOffset(well.Timezone.Hours));
|
||||
|
||||
if (request.LeDateEnd is not null)
|
||||
query = query.Where(o => o.DateEnd <= request.LeDateEnd.Value.Date.ToUtcDateTimeOffset(well.Timezone.Hours));
|
||||
|
||||
if (request.GeDepth is not null)
|
||||
query = query.Where(o => o.DepthStart >= request.GeDepth);
|
||||
|
||||
if (request.LeDepth is not null)
|
||||
query = query.Where(o => o.DepthEnd <= request.LeDepth);
|
||||
|
||||
if (request.IdTelemetryUser is not null)
|
||||
query = query.Where(o => o.IdUsersAtStart == request.IdTelemetryUser);
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
private IQueryable<DetectedOperation> BuildQuery(WellDto well, DetectedOperationRequest request)
|
||||
{
|
||||
IQueryable<DetectedOperation> query = BuildQueryBase(well, request)
|
||||
.Include(o => o.OperationCategory);
|
||||
|
||||
if (request.SortFields?.Any() == true)
|
||||
{
|
||||
query = query.SortBy(request.SortFields);
|
||||
}
|
||||
else
|
||||
query = query
|
||||
.OrderBy(o => o.DateStart)
|
||||
.ThenBy(o => o.DepthStart);
|
||||
|
||||
if (request.Skip.HasValue)
|
||||
query = query.Skip((int)request.Skip);
|
||||
|
||||
if (request.Take.HasValue)
|
||||
query = query.Take((int)request.Take);
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
private static DetectedOperationDto Convert(DetectedOperation operation, WellDto well, IEnumerable<OperationValueDto> operationValues, IEnumerable<ScheduleDto> schedules)
|
||||
{
|
||||
var dto = operation.Adapt<DetectedOperationDto>();
|
||||
dto.IdWell = well.Id;
|
||||
var dateStart = operation.DateStart.ToRemoteDateTime(well.Timezone.Hours);
|
||||
dto.DateStart = dateStart;
|
||||
dto.DateEnd = operation.DateEnd.ToRemoteDateTime(well.Timezone.Hours);
|
||||
dto.OperationValue = operationValues.FirstOrDefault(v => v.IdOperationCategory == dto.IdCategory
|
||||
&& v.DepthStart <= dto.DepthStart
|
||||
&& v.DepthEnd > dto.DepthStart);
|
||||
|
||||
var timeStart = new TimeDto(dateStart);
|
||||
var driller = schedules.FirstOrDefault(s =>
|
||||
s.DrillStart <= dateStart &&
|
||||
s.DrillEnd > dateStart && (
|
||||
s.ShiftStart > s.ShiftEnd
|
||||
) ^ (s.ShiftStart <= timeStart &&
|
||||
s.ShiftEnd > timeStart
|
||||
))
|
||||
?.Driller;
|
||||
dto.Driller = driller;
|
||||
return dto;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<WellOperationCategoryDto>?> GetCategoriesAsync(int? idWell, CancellationToken token)
|
||||
{
|
||||
IQueryable<WellOperationCategory> query;
|
||||
if(idWell is null)
|
||||
{
|
||||
query = db.WellOperationCategories;
|
||||
}
|
||||
else
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync((int )idWell, token);
|
||||
if (well?.IdTelemetry is null)
|
||||
return null;
|
||||
var idTelemetry = (int)well.IdTelemetry;
|
||||
query = db.DetectedOperations
|
||||
.Include(o => o.OperationCategory)
|
||||
.Where(o => o.IdTelemetry == idTelemetry)
|
||||
.Select(o => o.OperationCategory)
|
||||
.Distinct();
|
||||
}
|
||||
|
||||
var result = await query
|
||||
.Where(c => c.Id < 1000)
|
||||
.AsNoTracking()
|
||||
.Select(c => c.Adapt<WellOperationCategoryDto>())
|
||||
.ToArrayAsync(token);
|
||||
return result;
|
||||
var operations = await operationRepository.Get(request, token);
|
||||
var categories = operations
|
||||
.Select(o => o.OperationCategory)
|
||||
.Distinct();
|
||||
return categories;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<DetectedOperationStatDto>> GetOperationsStatAsync(DetectedOperationByWellRequest request, CancellationToken token)
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(request.IdWell, token);
|
||||
if (well?.IdTelemetry is null || well.Timezone is null)
|
||||
return Enumerable.Empty<DetectedOperationStatDto>();
|
||||
|
||||
var requestByTelemetry = new DetectedOperationByTelemetryRequest(well.IdTelemetry.Value, request);
|
||||
|
||||
var operations = await operationRepository.Get(requestByTelemetry, token);
|
||||
|
||||
if (!operations.Any())
|
||||
return Enumerable.Empty<DetectedOperationStatDto>();
|
||||
|
||||
var operationValues = await operationValueService.GetByIdWellAsync(request.IdWell, token);
|
||||
|
||||
var dtos = operations
|
||||
.GroupBy(o => (o.IdCategory, o.OperationCategory.Name))
|
||||
.OrderBy(g => g.Key)
|
||||
.Select(g => new DetectedOperationStatDto
|
||||
{
|
||||
IdCategory = g.Key.IdCategory,
|
||||
Category = g.Key.Name,
|
||||
Count = g.Count(),
|
||||
MinutesAverage = g.Average(o => o.DurationMinutes),
|
||||
MinutesMin = g.Min(o => o.DurationMinutes),
|
||||
MinutesMax = g.Max(o => o.DurationMinutes),
|
||||
MinutesTotal = g.Sum(o => o.DurationMinutes),
|
||||
ValueAverage = g.Average(o => o.Value),
|
||||
ValueMax = g.Max(o => o.Value),
|
||||
ValueMin = g.Min(o => o.Value),
|
||||
});
|
||||
|
||||
return dtos;
|
||||
}
|
||||
|
||||
public async Task<int> DeleteAsync(DetectedOperationByWellRequest request, CancellationToken token)
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(request.IdWell, token);
|
||||
if (well?.IdTelemetry is null || well.Timezone is null)
|
||||
return 0;
|
||||
|
||||
var requestByTelemetry = new DetectedOperationByTelemetryRequest(well.IdTelemetry.Value, request);
|
||||
var result = await operationRepository.Delete(-1, requestByTelemetry, token);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IEnumerable<DetectedOperationDrillersStatDto> GetOperationsDrillersStat(IEnumerable<DetectedOperationWithDrillerDto> operations)
|
||||
{
|
||||
var groups = operations.GroupBy(o => o.Driller);
|
||||
|
||||
var stats = new List<DetectedOperationDrillersStatDto>(groups.Count());
|
||||
foreach (var group in groups)
|
||||
{
|
||||
var itemsWithTarget = group.Where(i => i.OperationValue is not null);
|
||||
var stat = new DetectedOperationDrillersStatDto
|
||||
{
|
||||
Driller = group.Key,
|
||||
AverageValue = group.Sum(e => e.Value) / group.Count(),
|
||||
Count = group.Count(),
|
||||
};
|
||||
if (itemsWithTarget.Any())
|
||||
{
|
||||
var itemsOutOfTarget = itemsWithTarget.Where(o => !IsTargetOk(o));
|
||||
stat.AverageTargetValue = itemsWithTarget.Average(e => e.OperationValue?.TargetValue);
|
||||
stat.Efficiency = 100d * itemsOutOfTarget.Count() / itemsWithTarget.Count();
|
||||
stat.Loss = itemsOutOfTarget.Sum(DeltaToTarget);
|
||||
}
|
||||
|
||||
stats.Add(stat);
|
||||
}
|
||||
return stats;
|
||||
}
|
||||
|
||||
private static bool IsTargetOk(DetectedOperationWithDrillerDto op)
|
||||
{
|
||||
return (op.IdCategory) switch
|
||||
{
|
||||
WellOperationCategory.IdRotor => op.Value > op.OperationValue?.TargetValue,
|
||||
WellOperationCategory.IdSlide => op.Value > op.OperationValue?.TargetValue,
|
||||
WellOperationCategory.IdSlipsTime => op.Value > op.OperationValue?.TargetValue,
|
||||
_ => op.Value > op.OperationValue?.TargetValue,
|
||||
};
|
||||
}
|
||||
|
||||
private static double DeltaToTarget(DetectedOperationWithDrillerDto op)
|
||||
{
|
||||
return (op.IdCategory) switch
|
||||
{
|
||||
WellOperationCategory.IdRotor => 0,
|
||||
WellOperationCategory.IdSlide => 0,
|
||||
WellOperationCategory.IdSlipsTime => op.Value - op.OperationValue?.TargetValue??0,
|
||||
_ => 0,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private static DetectedOperationWithDrillerDto Convert(DetectedOperationDto operation, IEnumerable<OperationValueDto> operationValues, IEnumerable<ScheduleDto> schedules)
|
||||
{
|
||||
var dto = operation.Adapt<DetectedOperationWithDrillerDto>();
|
||||
dto.OperationValue = operationValues.FirstOrDefault(v => v.IdOperationCategory == dto.IdCategory
|
||||
&& v.DepthStart <= dto.DepthStart
|
||||
&& v.DepthEnd > dto.DepthStart);
|
||||
|
||||
var dateStart = dto.DateStart;
|
||||
var timeStart = new TimeDto(dateStart);
|
||||
var driller = schedules.FirstOrDefault(s =>
|
||||
s.DrillStart <= dateStart &&
|
||||
s.DrillEnd > dateStart && (
|
||||
s.ShiftStart > s.ShiftEnd
|
||||
) ^ (s.ShiftStart <= timeStart &&
|
||||
s.ShiftEnd > timeStart
|
||||
))
|
||||
?.Driller;
|
||||
dto.Driller = driller;
|
||||
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,8 @@ public class WorkOperationDetection: Work
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<IEnumerable<DetectedOperation>> DetectOperationsAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
|
||||
//todo: move this logic to DetectedOperationsService
|
||||
internal static async Task<IEnumerable<DetectedOperation>> DetectOperationsAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
|
||||
{
|
||||
var query = db.TelemetryDataSaub
|
||||
.AsNoTracking()
|
||||
|
@ -1,5 +1,4 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Data.SAUB;
|
||||
using AsbCloudApp.Data.SAUB;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Services;
|
||||
@ -11,142 +10,163 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Csv;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.SAUB
|
||||
namespace AsbCloudInfrastructure.Services.SAUB;
|
||||
|
||||
public class TelemetryDataSaubService : TelemetryDataBaseService<TelemetryDataSaubDto, TelemetryDataSaub>, ITelemetryDataSaubService
|
||||
{
|
||||
private readonly ITelemetryUserService telemetryUserService;
|
||||
|
||||
public class TelemetryDataSaubService : TelemetryDataBaseService<TelemetryDataSaubDto, TelemetryDataSaub>, ITelemetryDataSaubService
|
||||
public TelemetryDataSaubService(
|
||||
IAsbCloudDbContext db,
|
||||
ITelemetryService telemetryService,
|
||||
ITelemetryUserService telemetryUserService,
|
||||
ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache)
|
||||
: base(db, telemetryService, telemetryDataCache)
|
||||
{
|
||||
private readonly ITelemetryUserService telemetryUserService;
|
||||
|
||||
public TelemetryDataSaubService(
|
||||
IAsbCloudDbContext db,
|
||||
ITelemetryService telemetryService,
|
||||
ITelemetryUserService telemetryUserService,
|
||||
ITelemetryDataCache<TelemetryDataSaubDto> telemetryDataCache)
|
||||
: base(db, telemetryService, telemetryDataCache)
|
||||
{
|
||||
this.telemetryUserService = telemetryUserService;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<TelemetryDataSaubStatDto>> GetTelemetryDataStatAsync(int idTelemetry, CancellationToken token)
|
||||
{
|
||||
var timezone = telemetryService.GetTimezone(idTelemetry);
|
||||
var timezoneOffset = TimeSpan.FromHours(timezone.Hours);
|
||||
int[] modes = new int[] { 0, 1, 3 };
|
||||
|
||||
db.Database.SetCommandTimeout(TimeSpan.FromMinutes(1.5));
|
||||
|
||||
var query = db.Set<TelemetryDataSaub>()
|
||||
.Where(t => t.IdTelemetry == idTelemetry)
|
||||
.Where(t => t.BlockPosition > 0.0001)
|
||||
.Where(t => t.WellDepth > 0.0001)
|
||||
.Where(t => modes.Contains(t.Mode))
|
||||
.Where(t => t.WellDepth - t.BitDepth < 0.01)
|
||||
.GroupBy(t => new {
|
||||
t.DateTime.Hour,
|
||||
WellDepthX10 = Math.Truncate(t.WellDepth * 10),
|
||||
t.Mode,
|
||||
t.IdFeedRegulator})
|
||||
.Select(g => new TelemetryDataSaubStatDto
|
||||
{
|
||||
Count = g.Count(),
|
||||
IdMode = g.Key.Mode,
|
||||
IdFeedRegulator = g.Key.IdFeedRegulator,
|
||||
|
||||
DateMin = DateTime.SpecifyKind(g.Min(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified),
|
||||
DateMax = DateTime.SpecifyKind(g.Max(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified),
|
||||
|
||||
WellDepthMin = g.Min(t => t.WellDepth),
|
||||
WellDepthMax = g.Max(t => t.WellDepth),
|
||||
|
||||
Pressure = g.Average(t => t.Pressure),
|
||||
PressureSp = g.Average(t => t.PressureSp!.Value),
|
||||
PressureIdle = g.Average(t => t.PressureIdle!.Value),
|
||||
PressureDeltaLimitMax = g.Average(t => t.PressureDeltaLimitMax!.Value),
|
||||
PressureDelta = g.Average(t => t.Pressure - t.PressureIdle!.Value),
|
||||
PressureSpDelta = g.Average(t => t.PressureSp!.Value - t.PressureIdle!.Value),
|
||||
|
||||
AxialLoad = g.Average(t => t.AxialLoad),
|
||||
AxialLoadSp = g.Average(t => t.AxialLoadSp!.Value),
|
||||
AxialLoadLimitMax = g.Average(t => t.AxialLoadLimitMax!.Value),
|
||||
|
||||
RotorTorque = g.Average(t => t.RotorTorque),
|
||||
RotorTorqueSp = g.Average(t => t.RotorTorqueSp!.Value),
|
||||
RotorTorqueLimitMax = g.Average(t => t.RotorTorqueLimitMax!.Value),
|
||||
|
||||
BlockSpeed = g.Average(t => t.BlockSpeed!.Value),
|
||||
BlockSpeedSp = g.Average(t => t.BlockSpeedSp!.Value),
|
||||
})
|
||||
.Where(s => s.WellDepthMin != s.WellDepthMax)
|
||||
.Where(s => s.Count > 3)
|
||||
.OrderBy(t => t.DateMin);
|
||||
|
||||
return await query.ToArrayAsync(token);
|
||||
}
|
||||
|
||||
public override TelemetryDataSaub Convert(TelemetryDataSaubDto src, double timezoneOffset)
|
||||
{
|
||||
var entity = src.Adapt<TelemetryDataSaub>();
|
||||
var telemetryUser = telemetryUserService
|
||||
.GetUsers(src.IdTelemetry, u => (u.Name == src.User || u.Surname == src.User))
|
||||
.FirstOrDefault();
|
||||
entity.IdUser = telemetryUser?.Id;
|
||||
entity.DateTime = src.DateTime.ToUtcDateTimeOffset(timezoneOffset);
|
||||
return entity;
|
||||
}
|
||||
|
||||
public override TelemetryDataSaubDto Convert(TelemetryDataSaub src, double timezoneOffset)
|
||||
{
|
||||
var dto = src.Adapt<TelemetryDataSaubDto>();
|
||||
var telemetryUser = telemetryUserService.GetOrDefault(src.IdTelemetry, src.IdUser??int.MinValue);
|
||||
dto.User = telemetryUser?.MakeDisplayName();
|
||||
dto.DateTime = src.DateTime.ToRemoteDateTime(timezoneOffset);
|
||||
dto.BitDepth = src.BitDepth <= src.WellDepth
|
||||
? src.BitDepth
|
||||
: src.WellDepth;
|
||||
return dto;
|
||||
}
|
||||
|
||||
public async Task<Stream> GetZippedCsv(int idWell, DateTime beginDate, DateTime endDate, CancellationToken token)
|
||||
{
|
||||
double intervalSec = (endDate - beginDate).TotalSeconds;
|
||||
if (intervalSec > 60*60*24*3)
|
||||
throw new ArgumentInvalidException(nameof(endDate), "Слишком большой диапазон");
|
||||
|
||||
var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell)
|
||||
?? throw new ArgumentInvalidException(nameof(idWell), $"Скважина id:{idWell} не содержит телеметрии");
|
||||
|
||||
var approxPointsCount = intervalSec switch
|
||||
{
|
||||
< 2048 => 2048,
|
||||
< 8_192 => 4_096,
|
||||
< 131_072 => 16_384,
|
||||
_ => 32_768
|
||||
};
|
||||
|
||||
var data = await GetAsync(idWell, beginDate, intervalSec, approxPointsCount, token );
|
||||
|
||||
var fileName = $"DataSaub idWell{idWell}";
|
||||
if (telemetry.Info is not null)
|
||||
fileName += $" {telemetry.Info?.Cluster}, {telemetry.Info?.Well}";
|
||||
fileName += $" {beginDate:yyyy-MM-DDTHH-mm} - {endDate:yyyy-MM-DDTHH-mm}.csv";
|
||||
|
||||
var outStream = new MemoryStream();
|
||||
using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
|
||||
{
|
||||
var entryFile = archive.CreateEntry(fileName, CompressionLevel.Optimal);
|
||||
using var entryStream = entryFile.Open();
|
||||
var serializer = new CsvSerializer<TelemetryDataSaubDto>();
|
||||
serializer.Serialize(data, entryStream);
|
||||
}
|
||||
outStream.Seek(0, SeekOrigin.Begin);
|
||||
return outStream;
|
||||
}
|
||||
this.telemetryUserService = telemetryUserService;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<TelemetryDataSaubDto>> Get(int idTelemetry, bool isBitOnBottom, DateTimeOffset geDate, DateTimeOffset leDate, int take, CancellationToken token)
|
||||
{
|
||||
var offset = telemetryService.GetTimezone(idTelemetry).Offset;
|
||||
var geDateUtc = geDate.ToUniversalTime();
|
||||
var leDateUtc = leDate.ToUniversalTime();
|
||||
|
||||
var query = db.Set<TelemetryDataSaub>()
|
||||
.Where(t => t.IdTelemetry == idTelemetry)
|
||||
.Where(t => t.DateTime >= geDateUtc)
|
||||
.Where(t => t.DateTime <= leDateUtc);
|
||||
|
||||
if (isBitOnBottom)
|
||||
query = query.Where(t => Math.Abs(t.BitDepth - t.WellDepth) < 0.0001);
|
||||
|
||||
query = query
|
||||
.OrderBy(t => t.DateTime)
|
||||
.Take(take);
|
||||
|
||||
var entities = await query.ToArrayAsync(token);
|
||||
var dtos = entities.Select(e => Convert(e, offset.TotalHours));
|
||||
return dtos;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<TelemetryDataSaubStatDto>> GetTelemetryDataStatAsync(int idTelemetry, CancellationToken token)
|
||||
{
|
||||
var timezone = telemetryService.GetTimezone(idTelemetry);
|
||||
var timezoneOffset = TimeSpan.FromHours(timezone.Hours);
|
||||
int[] modes = new int[] { 0, 1, 3 };
|
||||
|
||||
db.Database.SetCommandTimeout(TimeSpan.FromMinutes(1.5));
|
||||
|
||||
var query = db.Set<TelemetryDataSaub>()
|
||||
.Where(t => t.IdTelemetry == idTelemetry)
|
||||
.Where(t => t.BlockPosition > 0.0001)
|
||||
.Where(t => t.WellDepth > 0.0001)
|
||||
.Where(t => modes.Contains(t.Mode))
|
||||
.Where(t => t.WellDepth - t.BitDepth < 0.01)
|
||||
.GroupBy(t => new
|
||||
{
|
||||
t.DateTime.Hour,
|
||||
WellDepthX10 = Math.Truncate(t.WellDepth * 10),
|
||||
t.Mode,
|
||||
t.IdFeedRegulator
|
||||
})
|
||||
.Select(g => new TelemetryDataSaubStatDto
|
||||
{
|
||||
Count = g.Count(),
|
||||
IdMode = g.Key.Mode,
|
||||
IdFeedRegulator = g.Key.IdFeedRegulator,
|
||||
|
||||
DateMin = DateTime.SpecifyKind(g.Min(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified),
|
||||
DateMax = DateTime.SpecifyKind(g.Max(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified),
|
||||
|
||||
WellDepthMin = g.Min(t => t.WellDepth),
|
||||
WellDepthMax = g.Max(t => t.WellDepth),
|
||||
|
||||
Pressure = g.Average(t => t.Pressure),
|
||||
PressureSp = g.Average(t => t.PressureSp!.Value),
|
||||
PressureIdle = g.Average(t => t.PressureIdle!.Value),
|
||||
PressureDeltaLimitMax = g.Average(t => t.PressureDeltaLimitMax!.Value),
|
||||
PressureDelta = g.Average(t => t.Pressure - t.PressureIdle!.Value),
|
||||
PressureSpDelta = g.Average(t => t.PressureSp!.Value - t.PressureIdle!.Value),
|
||||
|
||||
AxialLoad = g.Average(t => t.AxialLoad),
|
||||
AxialLoadSp = g.Average(t => t.AxialLoadSp!.Value),
|
||||
AxialLoadLimitMax = g.Average(t => t.AxialLoadLimitMax!.Value),
|
||||
|
||||
RotorTorque = g.Average(t => t.RotorTorque),
|
||||
RotorTorqueSp = g.Average(t => t.RotorTorqueSp!.Value),
|
||||
RotorTorqueLimitMax = g.Average(t => t.RotorTorqueLimitMax!.Value),
|
||||
|
||||
BlockSpeed = g.Average(t => t.BlockSpeed!.Value),
|
||||
BlockSpeedSp = g.Average(t => t.BlockSpeedSp!.Value),
|
||||
})
|
||||
.Where(s => s.WellDepthMin != s.WellDepthMax)
|
||||
.Where(s => s.Count > 3)
|
||||
.OrderBy(t => t.DateMin);
|
||||
|
||||
return await query.ToArrayAsync(token);
|
||||
}
|
||||
|
||||
public override TelemetryDataSaub Convert(TelemetryDataSaubDto src, double timezoneOffset)
|
||||
{
|
||||
var entity = src.Adapt<TelemetryDataSaub>();
|
||||
var telemetryUser = telemetryUserService
|
||||
.GetUsers(src.IdTelemetry, u => (u.Name == src.User || u.Surname == src.User))
|
||||
.FirstOrDefault();
|
||||
entity.IdUser = telemetryUser?.Id;
|
||||
entity.DateTime = src.DateTime.ToUtcDateTimeOffset(timezoneOffset);
|
||||
return entity;
|
||||
}
|
||||
|
||||
public override TelemetryDataSaubDto Convert(TelemetryDataSaub src, double timezoneOffset)
|
||||
{
|
||||
var dto = src.Adapt<TelemetryDataSaubDto>();
|
||||
var telemetryUser = telemetryUserService.GetOrDefault(src.IdTelemetry, src.IdUser ?? int.MinValue);
|
||||
dto.User = telemetryUser?.MakeDisplayName();
|
||||
dto.DateTime = src.DateTime.ToRemoteDateTime(timezoneOffset);
|
||||
dto.BitDepth = src.BitDepth <= src.WellDepth
|
||||
? src.BitDepth
|
||||
: src.WellDepth;
|
||||
return dto;
|
||||
}
|
||||
|
||||
public async Task<Stream> GetZippedCsv(int idWell, DateTime beginDate, DateTime endDate, CancellationToken token)
|
||||
{
|
||||
double intervalSec = (endDate - beginDate).TotalSeconds;
|
||||
if (intervalSec > 60 * 60 * 24 * 3)
|
||||
throw new ArgumentInvalidException(nameof(endDate), "Слишком большой диапазон");
|
||||
|
||||
var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell)
|
||||
?? throw new ArgumentInvalidException(nameof(idWell), $"Скважина id:{idWell} не содержит телеметрии");
|
||||
|
||||
var approxPointsCount = intervalSec switch
|
||||
{
|
||||
< 2048 => 2048,
|
||||
< 8_192 => 4_096,
|
||||
< 131_072 => 16_384,
|
||||
_ => 32_768
|
||||
};
|
||||
|
||||
var data = await GetAsync(idWell, beginDate, intervalSec, approxPointsCount, token);
|
||||
|
||||
var fileName = $"DataSaub idWell{idWell}";
|
||||
if (telemetry.Info is not null)
|
||||
fileName += $" {telemetry.Info?.Cluster}, {telemetry.Info?.Well}";
|
||||
fileName += $" {beginDate:yyyy-MM-DDTHH-mm} - {endDate:yyyy-MM-DDTHH-mm}.csv";
|
||||
|
||||
var outStream = new MemoryStream();
|
||||
using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
|
||||
{
|
||||
var entryFile = archive.CreateEntry(fileName, CompressionLevel.Optimal);
|
||||
using var entryStream = entryFile.Open();
|
||||
var serializer = new CsvSerializer<TelemetryDataSaubDto>();
|
||||
serializer.Serialize(data, entryStream);
|
||||
}
|
||||
outStream.Seek(0, SeekOrigin.Begin);
|
||||
return outStream;
|
||||
}
|
||||
}
|
||||
|
@ -45,17 +45,16 @@ internal class SubsystemService : ISubsystemService
|
||||
if(!well.IdTelemetry.HasValue)
|
||||
return Enumerable.Empty<SubsystemStatDto>();
|
||||
|
||||
var detectedOperationSummaryRequest = new DetectedOperationRequest
|
||||
{
|
||||
var detectedOperationSummaryRequest = new DetectedOperationByWellRequest
|
||||
{
|
||||
IdWell = request.IdWell,
|
||||
IdsTelemetries = new[] { well.IdTelemetry.Value },
|
||||
IdsCategories = WellOperationCategory.MechanicalDrillingSubIds,
|
||||
|
||||
GeDateStart = request.GeDate,
|
||||
LeDateEnd = request.LeDate,
|
||||
|
||||
GeDepth = request.GeDepth,
|
||||
LeDepth = request.LeDepth,
|
||||
GeDepthStart = request.GeDepth,
|
||||
LeDepthEnd = request.LeDepth,
|
||||
};
|
||||
|
||||
var operations = await detectedOperationService.GetOperationsAsync(detectedOperationSummaryRequest,
|
||||
@ -78,7 +77,7 @@ internal class SubsystemService : ISubsystemService
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<SubsystemStatDto>> CalcStatAsync(IEnumerable<DetectedOperationDto> operations, CancellationToken token)
|
||||
private async Task<IEnumerable<SubsystemStatDto>> CalcStatAsync(IEnumerable<DetectedOperationWithDrillerDto> operations, CancellationToken token)
|
||||
{
|
||||
if (!subsystems.Any())
|
||||
subsystems = (await subsystemRepository.GetAllAsync(token)).ToDictionary(s => s.Id, s => s);
|
||||
@ -92,7 +91,7 @@ internal class SubsystemService : ISubsystemService
|
||||
return stat;
|
||||
}
|
||||
|
||||
private SubsystemStatDto CalcOscillationStat(IEnumerable<DetectedOperationDto> operations)
|
||||
private SubsystemStatDto CalcOscillationStat(IEnumerable<DetectedOperationWithDrillerDto> operations)
|
||||
{
|
||||
operations = operations.Where(o => o.IdCategory == WellOperationCategory.IdSlide);
|
||||
|
||||
@ -114,7 +113,7 @@ internal class SubsystemService : ISubsystemService
|
||||
return oscillationStat;
|
||||
}
|
||||
|
||||
private IEnumerable<SubsystemStatDto> CalcApdStat(IEnumerable<DetectedOperationDto> operations)
|
||||
private IEnumerable<SubsystemStatDto> CalcApdStat(IEnumerable<DetectedOperationWithDrillerDto> operations)
|
||||
{
|
||||
var apdRotorAndSlide = operations
|
||||
.Where(o => WellOperationCategory.MechanicalDrillingSubIds.Contains(o.IdCategory))
|
||||
@ -169,7 +168,7 @@ internal class SubsystemService : ISubsystemService
|
||||
}
|
||||
|
||||
private static (double SumDepthInterval, double UsedTimeHours, int Count) AggregateOperations(int idSubsystem,
|
||||
IEnumerable<DetectedOperationDto> operations) =>
|
||||
IEnumerable<DetectedOperationWithDrillerDto> operations) =>
|
||||
idSubsystem switch
|
||||
{
|
||||
IdSubsystemAPDRotor => CalcOperationsByEnableSubsystems(operations, EnabledSubsystemsFlags.AutoRotor),
|
||||
@ -180,7 +179,7 @@ internal class SubsystemService : ISubsystemService
|
||||
};
|
||||
|
||||
private static (double SumDepthInterval, double UsedTimeHours, int OperationCount) CalcOperationsByEnableSubsystems(
|
||||
IEnumerable<DetectedOperationDto> operations,
|
||||
IEnumerable<DetectedOperationWithDrillerDto> operations,
|
||||
EnabledSubsystemsFlags enabledSubsystems)
|
||||
{
|
||||
var filtered = operations.Where(o => enabledSubsystems.HasEnabledSubsystems(o.EnabledSubsystems));
|
||||
@ -215,7 +214,7 @@ internal class SubsystemService : ISubsystemService
|
||||
|
||||
var leDateUtc = leDate?.ToUtcDateTimeOffset(hoursOffset);
|
||||
|
||||
var request = new DetectedOperationRequest
|
||||
var request = new DetectedOperationByWellRequest
|
||||
{
|
||||
IdWell = well.Id,
|
||||
IdsCategories = WellOperationCategory.MechanicalDrillingSubIds,
|
||||
|
@ -36,13 +36,18 @@ namespace AsbCloudInfrastructure.Services
|
||||
.ThenInclude(r => r.Company)
|
||||
.AsNoTracking();
|
||||
|
||||
public WellService(IAsbCloudDbContext db, IMemoryCache memoryCache, ITelemetryService telemetryService, ITimezoneService timezoneService, WellInfoService wellInfoService)
|
||||
public WellService(IAsbCloudDbContext db,
|
||||
IMemoryCache memoryCache,
|
||||
ITelemetryService telemetryService,
|
||||
ITimezoneService timezoneService,
|
||||
WellInfoService wellInfoService,
|
||||
IWellOperationCategoryRepository wellOperationCategoryRepository)
|
||||
: base(db, memoryCache, MakeQueryWell)
|
||||
{
|
||||
this.telemetryService = telemetryService;
|
||||
this.timezoneService = timezoneService;
|
||||
this.wellInfoService = wellInfoService;
|
||||
this.wellOperationRepository = new WellOperationRepository(db, memoryCache, this);
|
||||
this.wellOperationRepository = new WellOperationRepository(db, memoryCache, this, wellOperationCategoryRepository);
|
||||
companyTypesService = new CrudCacheRepositoryBase<CompanyTypeDto, CompanyType>(dbContext, memoryCache);
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,6 @@ using AsbCloudApp.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudInfrastructure.Services.DetectOperations;
|
||||
@ -57,7 +56,7 @@ namespace AsbCloudWebApi.Controllers.SAUB
|
||||
[HttpGet]
|
||||
[ProducesResponseType(typeof(DetectedOperationListDto), (int)System.Net.HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> GetAsync(
|
||||
[FromQuery] DetectedOperationRequest request,
|
||||
[FromQuery] DetectedOperationByWellRequest request,
|
||||
CancellationToken token)
|
||||
{
|
||||
if (!await UserHasAccessToWellAsync(request.IdWell, token))
|
||||
@ -76,7 +75,7 @@ namespace AsbCloudWebApi.Controllers.SAUB
|
||||
[HttpGet("stat")]
|
||||
[ProducesResponseType(typeof(IEnumerable<DetectedOperationStatDto>), (int)System.Net.HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> GetStatAsync(
|
||||
[FromQuery] DetectedOperationRequest request,
|
||||
[FromQuery] DetectedOperationByWellRequest request,
|
||||
CancellationToken token)
|
||||
{
|
||||
if (!await UserHasAccessToWellAsync(request.IdWell, token))
|
||||
@ -98,7 +97,7 @@ namespace AsbCloudWebApi.Controllers.SAUB
|
||||
[Permission]
|
||||
[ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> DeleteAsync(
|
||||
[FromQuery] DetectedOperationRequest request,
|
||||
[FromQuery] DetectedOperationByWellRequest request,
|
||||
CancellationToken token)
|
||||
{
|
||||
if (!await UserHasAccessToWellAsync(request.IdWell, token))
|
||||
|
Loading…
Reference in New Issue
Block a user