forked from ddrilling/AsbCloudServer
Merge branch 'fix/ggd-exported-dates-tests' of http://test.digitaldrilling.ru:8080/DDrilling/AsbCloudServer into fix/ggd-exported-dates-tests
This commit is contained in:
commit
9d5f124af6
@ -12,6 +12,11 @@ namespace AsbCloudApp.Data.DetectedOperation
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int IdWell { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id телеметрии
|
||||
/// </summary>
|
||||
public int IdTelemetry { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id названия/описания операции
|
||||
@ -72,5 +77,10 @@ namespace AsbCloudApp.Data.DetectedOperation
|
||||
/// Ключевой параметр операции
|
||||
/// </summary>
|
||||
public double Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Флаг включенной подсистемы
|
||||
/// </summary>
|
||||
public int EnabledSubsystems { get; set; }
|
||||
}
|
||||
}
|
||||
|
50
AsbCloudApp/Data/DetectedOperation/EnabledSubsystemsFlags.cs
Normal file
50
AsbCloudApp/Data/DetectedOperation/EnabledSubsystemsFlags.cs
Normal file
@ -0,0 +1,50 @@
|
||||
using System;
|
||||
|
||||
namespace AsbCloudApp.Data.DetectedOperation;
|
||||
|
||||
/// <summary>
|
||||
/// Флаги включенных подсистем
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum EnabledSubsystemsFlags
|
||||
{
|
||||
/// <summary>
|
||||
/// Автоподача долота
|
||||
/// </summary>
|
||||
AutoRotor = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// БУРЕНИЕ В СЛАЙДЕ
|
||||
/// </summary>
|
||||
AutoSlide = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// ПРОРАБОТКА
|
||||
/// </summary>
|
||||
AutoConditionig = 1 << 2,
|
||||
|
||||
/// <summary>
|
||||
/// СПУСК СПО
|
||||
/// </summary>
|
||||
AutoSinking = 1 << 3,
|
||||
|
||||
/// <summary>
|
||||
/// ПОДЪЕМ СПО
|
||||
/// </summary>
|
||||
AutoLifting = 1 << 4,
|
||||
|
||||
/// <summary>
|
||||
/// ПОДЪЕМ С ПРОРАБОТКОЙ
|
||||
/// </summary>
|
||||
AutoLiftingWithConditionig = 1 << 5,
|
||||
|
||||
/// <summary>
|
||||
/// блокировка
|
||||
/// </summary>
|
||||
AutoBlocknig = 1 << 6,
|
||||
|
||||
/// <summary>
|
||||
/// осцилляция
|
||||
/// </summary>
|
||||
AutoOscillation = 1 << 7,
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
namespace AsbCloudApp.Data.DetectedOperation;
|
||||
|
||||
/// <summary>
|
||||
/// Статистика по операциям
|
||||
/// </summary>
|
||||
public class OperationsSummaryDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Id телеметрии
|
||||
/// </summary>
|
||||
public int IdTelemetry { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id названия/описания операции
|
||||
/// </summary>
|
||||
public int IdCategory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Количество операций
|
||||
/// </summary>
|
||||
public int Count { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cумма проходок операций
|
||||
/// </summary>
|
||||
public double SumDepthIntervals { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cумма продолжительностей операций
|
||||
/// </summary>
|
||||
public double SumDurationHours { get; set; }
|
||||
}
|
@ -1,30 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
namespace AsbCloudApp.Data.Subsystems
|
||||
namespace AsbCloudApp.Data.Subsystems;
|
||||
|
||||
/// <summary>
|
||||
/// Статистика наработки подсистем по активным скважинам
|
||||
/// </summary>
|
||||
public class SubsystemActiveWellStatDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Статистика наработки подсистем по активным скважинам
|
||||
/// </summary>
|
||||
public class SubsystemActiveWellStatDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Активная скважина
|
||||
/// </summary>
|
||||
public WellInfoDto Well { get; set; } = null!;
|
||||
/// <summary>
|
||||
/// Наработки подсистемы АКБ
|
||||
/// </summary>
|
||||
public SubsystemStatDto? SubsystemAKB { get; set; }
|
||||
/// <summary>
|
||||
/// Наработки подсистемы МСЕ
|
||||
/// </summary>
|
||||
public SubsystemStatDto? SubsystemMSE { get; set; }
|
||||
/// <summary>
|
||||
/// Наработки подсистемы СПИН
|
||||
/// </summary>
|
||||
public SubsystemStatDto? SubsystemSpinMaster { get; set; }
|
||||
/// <summary>
|
||||
/// Наработки подсистемы ТОРК
|
||||
/// </summary>
|
||||
public SubsystemStatDto? SubsystemTorqueMaster { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Активная скважина
|
||||
/// </summary>
|
||||
public WellInfoDto Well { get; set; } = null!;
|
||||
/// <summary>
|
||||
/// Наработки подсистемы АПД
|
||||
/// </summary>
|
||||
public SubsystemStatDto? SubsystemAPD { get; set; }
|
||||
/// <summary>
|
||||
/// Наработки подсистемы с осцилляцией
|
||||
/// </summary>
|
||||
public SubsystemStatDto? SubsystemOscillation { get; set; }
|
||||
/// <summary>
|
||||
/// Наработки подсистемы ТОРК
|
||||
/// </summary>
|
||||
public SubsystemStatDto? SubsystemTorqueMaster { get; set; }
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
using System;
|
||||
namespace AsbCloudApp.Data.Subsystems
|
||||
{
|
||||
/// <summary>
|
||||
/// Модель информации о работе подсистемы
|
||||
/// </summary>
|
||||
public class SubsystemOperationTimeDto:IId
|
||||
{
|
||||
/// <summary>
|
||||
/// Идентификатор
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
/// <summary>
|
||||
/// идентификатор подсистемы
|
||||
/// </summary>
|
||||
public int IdSubsystem { get; set; }
|
||||
/// <summary>
|
||||
/// Название подсистемы
|
||||
/// </summary>
|
||||
public string SubsystemName { get; set; } = null!;
|
||||
/// <summary>
|
||||
/// дата/время включения подсистемы
|
||||
/// </summary>
|
||||
public DateTime DateStart { get; set; }
|
||||
/// <summary>
|
||||
/// дата/время выключения подсистемы
|
||||
/// </summary>
|
||||
public DateTime DateEnd { get; set; }
|
||||
/// <summary>
|
||||
/// глубина забоя на момент включения подсистемы
|
||||
/// </summary>
|
||||
public double DepthStart { get; set; }
|
||||
/// <summary>
|
||||
/// глубина забоя на момент выключения подсистемы
|
||||
/// </summary>
|
||||
public double DepthEnd { get; set; }
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
|
||||
namespace AsbCloudApp.Requests
|
||||
{
|
||||
@ -14,31 +15,37 @@ namespace AsbCloudApp.Requests
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int IdWell { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Список id телеметрий
|
||||
/// пустой список - нет фильтрации
|
||||
/// </summary>
|
||||
public IEnumerable<int> IdsTelemetries { get; set; } = Enumerable.Empty<int>();
|
||||
|
||||
/// <summary>
|
||||
/// категории операций
|
||||
/// </summary>
|
||||
public IEnumerable<int>? IdsCategories { get; set; }
|
||||
public IEnumerable<int> IdsCategories { get; set; } = Enumerable.Empty<int>();
|
||||
|
||||
/// <summary>
|
||||
/// Больше или равно дате
|
||||
/// </summary>
|
||||
public DateTime? GtDate { get; set; }
|
||||
public DateTimeOffset? GeDateStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Меньше или равно дате
|
||||
/// </summary>
|
||||
public DateTime? LtDate { get; set; }
|
||||
public DateTimeOffset? LeDateEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Больше или равно глубины забоя
|
||||
/// </summary>
|
||||
public double? GtDepth { get; set; }
|
||||
public double? GeDepth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Меньше или равно глубины забоя
|
||||
/// </summary>
|
||||
public double? LtDepth { get; set; }
|
||||
public double? LeDepth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Фильтр по пользователю панели
|
||||
|
@ -1,53 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace AsbCloudApp.Requests;
|
||||
|
||||
/// <summary>
|
||||
/// Запрос на получение обобщенных данных по операцим
|
||||
/// </summary>
|
||||
public class DetectedOperationSummaryRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Список id телеметрий
|
||||
/// пустой список - нет фильтрации
|
||||
/// </summary>
|
||||
public IEnumerable<int> IdsTelemetries { get;set;} = Enumerable.Empty<int>();
|
||||
|
||||
/// <summary>
|
||||
/// Список id категорий операций
|
||||
/// пустой список - нет фильтрации
|
||||
/// </summary>
|
||||
public IEnumerable<int> IdsOperationCategories { get; set; } = Enumerable.Empty<int>();
|
||||
|
||||
/// <summary>
|
||||
/// Больше или равно даты начала операции
|
||||
/// </summary>
|
||||
public DateTimeOffset? GeDateStart {get;set;}
|
||||
|
||||
/// <summary>
|
||||
/// Меньше или равно даты начала операции
|
||||
/// </summary>
|
||||
public DateTimeOffset? LeDateStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Меньше или равно даты окончания операции
|
||||
/// </summary>
|
||||
public DateTimeOffset? LeDateEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Больше или равно глубины начала операции
|
||||
/// </summary>
|
||||
public double? GeDepthStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Меньше или равно глубины начала операции
|
||||
/// </summary>
|
||||
public double? LeDepthStart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Меньше или равно глубины окончания операции
|
||||
/// </summary>
|
||||
public double? LeDepthEnd { get; set; }
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
|
||||
namespace AsbCloudApp.Requests
|
||||
{
|
||||
/// <summary>
|
||||
/// класс с фильтрами для запроса
|
||||
/// </summary>
|
||||
public class SubsystemOperationTimeRequest: RequestBase, IValidatableObject
|
||||
{
|
||||
private static readonly DateTime validationMinDate = new DateTime(2020,01,01,0,0,0,DateTimeKind.Utc);
|
||||
|
||||
/// <summary>
|
||||
/// идентификатор скважины
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int IdWell { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// идентификатор подсистемы
|
||||
/// </summary>
|
||||
public IEnumerable<int> IdsSubsystems { get; set; } = Enumerable.Empty<int>();
|
||||
|
||||
/// <summary>
|
||||
/// Больше или равно дате
|
||||
/// </summary>
|
||||
public DateTime? GtDate { get; set; }//TODO: its Ge*
|
||||
|
||||
/// <summary>
|
||||
/// Меньше или равно дате
|
||||
/// </summary>
|
||||
public DateTime? LtDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Больше или равно глубины забоя
|
||||
/// </summary>
|
||||
public double? GtDepth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Меньше или равно глубины забоя
|
||||
/// </summary>
|
||||
public double? LtDepth { get; set; }
|
||||
|
||||
//TODO: Replace modes by DateTimeOffset LeDateStart, LeDateEnd
|
||||
/// <summary>
|
||||
/// информация попадает в выборку, если интервал выборки частично или полностью пересекается с запрашиваемым интервалом
|
||||
/// </summary>
|
||||
public const int SelectModeOuter = 0;
|
||||
|
||||
/// <summary>
|
||||
/// информация попадает в выборку, если интервал выборки строго полностью пересекается с запрашиваемым интервалом.
|
||||
/// </summary>
|
||||
public const int SelectModeInner = 1;
|
||||
|
||||
/// <summary>
|
||||
/// аналогично outer, но интервалы в частично пересекающиеся укорачиваются по границам интервала выборки.
|
||||
/// </summary>
|
||||
public const int SelectModeTrim = 2;
|
||||
|
||||
/// <summary>
|
||||
/// Режим выборки элементов
|
||||
/// </summary>
|
||||
public int SelectMode { get; set; } = SelectModeOuter;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if (GtDate.HasValue && GtDate < validationMinDate)
|
||||
yield return new ValidationResult(
|
||||
$"Должно быть больше {validationMinDate:O})",
|
||||
new[] { nameof(GtDate) });
|
||||
|
||||
if (LtDate.HasValue && GtDate.HasValue)
|
||||
{
|
||||
if (LtDate < GtDate)
|
||||
yield return new ValidationResult(
|
||||
$"{nameof(LtDate)} должно быть больше {nameof(GtDate)}. ({LtDate:O} < {GtDate:O})",
|
||||
new[] { nameof(LtDate), nameof(GtDate) });
|
||||
}
|
||||
|
||||
if (LtDepth.HasValue && GtDepth.HasValue)
|
||||
{
|
||||
if (LtDepth < GtDepth)
|
||||
yield return new ValidationResult(
|
||||
$"{nameof(LtDepth)} должно быть больше {nameof(GtDepth)}. ({LtDepth} < {GtDepth})",
|
||||
new[] { nameof(LtDepth), nameof(GtDepth) });
|
||||
}
|
||||
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
72
AsbCloudApp/Requests/SubsystemRequest.cs
Normal file
72
AsbCloudApp/Requests/SubsystemRequest.cs
Normal file
@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace AsbCloudApp.Requests
|
||||
{
|
||||
/// <summary>
|
||||
/// класс с фильтрами для запроса
|
||||
/// </summary>
|
||||
public class SubsystemRequest: RequestBase, IValidatableObject
|
||||
{
|
||||
private static readonly DateTime validationMinDate = new DateTime(2020,01,01,0,0,0,DateTimeKind.Utc);
|
||||
|
||||
/// <summary>
|
||||
/// идентификатор скважины
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int IdWell { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Идентификатор бурильщика
|
||||
/// </summary>
|
||||
public int? IdDriller { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Больше или равно дате
|
||||
/// </summary>
|
||||
public DateTimeOffset? GeDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Меньше или равно дате
|
||||
/// </summary>
|
||||
public DateTimeOffset? LeDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Больше или равно глубины забоя
|
||||
/// </summary>
|
||||
public double? GeDepth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Меньше или равно глубины забоя
|
||||
/// </summary>
|
||||
public double? LeDepth { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if (GeDate.HasValue && GeDate < validationMinDate)
|
||||
yield return new ValidationResult(
|
||||
$"Должно быть больше {validationMinDate:O})",
|
||||
new[] { nameof(GeDate) });
|
||||
|
||||
if (LeDate.HasValue && GeDate.HasValue)
|
||||
{
|
||||
if (LeDate < GeDate)
|
||||
yield return new ValidationResult(
|
||||
$"{nameof(LeDate)} должно быть больше {nameof(GeDate)}. ({LeDate:O} < {GeDate:O})",
|
||||
new[] { nameof(LeDate), nameof(GeDate) });
|
||||
}
|
||||
|
||||
if (LeDepth.HasValue && GeDepth.HasValue)
|
||||
{
|
||||
if (LeDepth < GeDepth)
|
||||
yield return new ValidationResult(
|
||||
$"{nameof(LeDepth)} должно быть больше {nameof(GeDepth)}. ({LeDepth} < {GeDepth})",
|
||||
new[] { nameof(LeDepth), nameof(GeDepth) });
|
||||
}
|
||||
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
@ -35,15 +35,7 @@ namespace AsbCloudApp.Services
|
||||
/// <param name="request"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<DetectedOperationDto>?> GetOperationsAsync(DetectedOperationRequest request, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получить интервалы глубин по всем скважинам
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns>кортеж - ид телеметрии, интервалы глубины забоя (ротор,слайд) </returns>
|
||||
Task<IEnumerable<OperationsSummaryDto>> GetOperationSummaryAsync(DetectedOperationSummaryRequest request, CancellationToken token);
|
||||
Task<IEnumerable<DetectedOperationDto>> GetOperationsAsync(DetectedOperationRequest request, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Удалить операции
|
||||
|
40
AsbCloudApp/Services/ISubsystemService.cs
Normal file
40
AsbCloudApp/Services/ISubsystemService.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using AsbCloudApp.Data.Subsystems;
|
||||
using AsbCloudApp.Requests;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudApp.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Получение инфо о наработке подсистем
|
||||
/// </summary>
|
||||
public interface ISubsystemService
|
||||
{
|
||||
/// <summary>
|
||||
/// Статистика о наработке подсистем
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<SubsystemStatDto>> GetStatAsync(SubsystemRequest request, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получение статистики по наработке подсистем по активным скважинам
|
||||
/// </summary>
|
||||
/// <param name="idCompany"></param>
|
||||
/// <param name="gtDate"></param>
|
||||
/// <param name="ltDate"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(int idCompany, DateTime? gtDate, DateTime? ltDate, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получение статистики по наработке подсистем по активным скважинам
|
||||
/// </summary>
|
||||
/// <param name="wellIds"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(IEnumerable<int> wellIds, CancellationToken token);
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Data.Subsystems;
|
||||
using AsbCloudApp.Requests;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudApp.Services.Subsystems
|
||||
{
|
||||
/// <summary>
|
||||
/// Получение инфо о наработке подсистем
|
||||
/// </summary>
|
||||
public interface ISubsystemOperationTimeService
|
||||
{
|
||||
/// <summary>
|
||||
/// Статистика о наработке подсистем
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<SubsystemStatDto>> GetStatAsync(SubsystemOperationTimeRequest request, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Удаление наработки по подсистемам.
|
||||
/// Если удаляется конец, то фоновый сервис подсчета наработки восстановит эти данные.
|
||||
/// Может потребоваться для запуска повторного расчета по новому алгоритму.
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<int> DeleteAsync(SubsystemOperationTimeRequest request, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Интервалы работы подсистем
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<SubsystemOperationTimeDto>> GetOperationTimeAsync(SubsystemOperationTimeRequest request, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Временной диапазон за который есть статистика работы подсистем
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<DatesRangeDto?> GetDateRangeOperationTimeAsync(SubsystemOperationTimeRequest request, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получение статистики по наработке подсистем по активным скважинам
|
||||
/// </summary>
|
||||
/// <param name="idCompany"></param>
|
||||
/// <param name="gtDate"></param>
|
||||
/// <param name="ltDate"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(int idCompany, DateTime? gtDate, DateTime? ltDate, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получение статистики по наработке подсистем по активным скважинам
|
||||
/// </summary>
|
||||
/// <param name="wellIds"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(IEnumerable<int> wellIds, CancellationToken token);
|
||||
}
|
||||
}
|
9015
AsbCloudDb/Migrations/20231216060437_Update_Subsystems.Designer.cs
generated
Normal file
9015
AsbCloudDb/Migrations/20231216060437_Update_Subsystems.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
71
AsbCloudDb/Migrations/20231216060437_Update_Subsystems.cs
Normal file
71
AsbCloudDb/Migrations/20231216060437_Update_Subsystems.cs
Normal file
@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace AsbCloudDb.Migrations
|
||||
{
|
||||
public partial class Update_Subsystems : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "t_subsystem_operation_time");
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "t_subsystem",
|
||||
keyColumn: "id",
|
||||
keyValue: 2);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "t_subsystem_operation_time",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
id_subsystem = table.Column<int>(type: "integer", nullable: false),
|
||||
id_telemetry = table.Column<int>(type: "integer", nullable: false, comment: "ИД телеметрии по которой выдается информация"),
|
||||
date_end = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "дата/время выключения подсистемы"),
|
||||
date_start = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "дата/время включения подсистемы"),
|
||||
depth_end = table.Column<float>(type: "real", nullable: true, comment: "глубина забоя на момент выключения подсистемы"),
|
||||
depth_start = table.Column<float>(type: "real", nullable: true, comment: "глубина забоя на момент включения подсистемы")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_t_subsystem_operation_time", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "FK_t_subsystem_operation_time_t_subsystem_id_subsystem",
|
||||
column: x => x.id_subsystem,
|
||||
principalTable: "t_subsystem",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_t_subsystem_operation_time_t_telemetry_id_telemetry",
|
||||
column: x => x.id_telemetry,
|
||||
principalTable: "t_telemetry",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
},
|
||||
comment: "наработки подсистем");
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "t_subsystem",
|
||||
columns: new[] { "id", "description", "name" },
|
||||
values: new object[] { 2, "Алгоритм поиска оптимальных параметров бурения САУБ", "MSE" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_t_subsystem_operation_time_id_subsystem",
|
||||
table: "t_subsystem_operation_time",
|
||||
column: "id_subsystem");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_t_subsystem_operation_time_id_telemetry",
|
||||
table: "t_subsystem_operation_time",
|
||||
column: "id_telemetry");
|
||||
}
|
||||
}
|
||||
}
|
9115
AsbCloudDb/Migrations/20231218192700_Update_DetectedOperations_And_Subsystems.Designer.cs
generated
Normal file
9115
AsbCloudDb/Migrations/20231218192700_Update_DetectedOperations_And_Subsystems.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,49 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace AsbCloudDb.Migrations
|
||||
{
|
||||
public partial class Update_DetectedOperations_And_Subsystems : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "enabled_subsystems",
|
||||
table: "t_detected_operation",
|
||||
type: "integer",
|
||||
nullable: false,
|
||||
comment: "флаги включенных подсистем",
|
||||
oldClrType: typeof(int),
|
||||
oldType: "integer",
|
||||
oldComment: "флаги аключенных подсистем");
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "t_subsystem",
|
||||
keyColumn: "id",
|
||||
keyValue: 1,
|
||||
column: "name",
|
||||
value: "АПД");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "enabled_subsystems",
|
||||
table: "t_detected_operation",
|
||||
type: "integer",
|
||||
nullable: false,
|
||||
comment: "флаги аключенных подсистем",
|
||||
oldClrType: typeof(int),
|
||||
oldType: "integer",
|
||||
oldComment: "флаги включенных подсистем");
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "t_subsystem",
|
||||
keyColumn: "id",
|
||||
keyValue: 1,
|
||||
column: "name",
|
||||
value: "АКБ");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using AsbCloudDb.Model;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
using System.Collections.Generic;
|
||||
|
||||
#nullable disable
|
||||
|
||||
@ -386,7 +386,7 @@ namespace AsbCloudDb.Migrations
|
||||
b.Property<int>("EnabledSubsystems")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("enabled_subsystems")
|
||||
.HasComment("флаги аключенных подсистем");
|
||||
.HasComment("флаги включенных подсистем");
|
||||
|
||||
b.Property<IDictionary<string, object>>("ExtraData")
|
||||
.IsRequired()
|
||||
@ -4543,7 +4543,7 @@ namespace AsbCloudDb.Migrations
|
||||
b.HasComment("Запросы на изменение уставок панели оператора");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AsbCloudDb.Model.Subsystems.Subsystem", b =>
|
||||
modelBuilder.Entity("AsbCloudDb.Model.Subsystem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
@ -4574,7 +4574,7 @@ namespace AsbCloudDb.Migrations
|
||||
{
|
||||
Id = 1,
|
||||
Description = "Совместная работа режимов \"Бурение в роторе\" и \"Бурение в слайде\"",
|
||||
Name = "АКБ"
|
||||
Name = "АПД"
|
||||
},
|
||||
new
|
||||
{
|
||||
@ -4589,12 +4589,6 @@ namespace AsbCloudDb.Migrations
|
||||
Name = "АПД слайд"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 2,
|
||||
Description = "Алгоритм поиска оптимальных параметров бурения САУБ",
|
||||
Name = "MSE"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 65536,
|
||||
Description = "Осцилляция",
|
||||
@ -4608,55 +4602,6 @@ namespace AsbCloudDb.Migrations
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AsbCloudDb.Model.Subsystems.SubsystemOperationTime", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTimeOffset>("DateEnd")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("date_end")
|
||||
.HasComment("дата/время выключения подсистемы");
|
||||
|
||||
b.Property<DateTimeOffset>("DateStart")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("date_start")
|
||||
.HasComment("дата/время включения подсистемы");
|
||||
|
||||
b.Property<float?>("DepthEnd")
|
||||
.HasColumnType("real")
|
||||
.HasColumnName("depth_end")
|
||||
.HasComment("глубина забоя на момент выключения подсистемы");
|
||||
|
||||
b.Property<float?>("DepthStart")
|
||||
.HasColumnType("real")
|
||||
.HasColumnName("depth_start")
|
||||
.HasComment("глубина забоя на момент включения подсистемы");
|
||||
|
||||
b.Property<int>("IdSubsystem")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id_subsystem");
|
||||
|
||||
b.Property<int>("IdTelemetry")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id_telemetry")
|
||||
.HasComment("ИД телеметрии по которой выдается информация");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IdSubsystem");
|
||||
|
||||
b.HasIndex("IdTelemetry");
|
||||
|
||||
b.ToTable("t_subsystem_operation_time");
|
||||
|
||||
b.HasComment("наработки подсистем");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AsbCloudDb.Model.Telemetry", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@ -8683,25 +8628,6 @@ namespace AsbCloudDb.Migrations
|
||||
b.Navigation("Well");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AsbCloudDb.Model.Subsystems.SubsystemOperationTime", b =>
|
||||
{
|
||||
b.HasOne("AsbCloudDb.Model.Subsystems.Subsystem", "Subsystem")
|
||||
.WithMany()
|
||||
.HasForeignKey("IdSubsystem")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("AsbCloudDb.Model.Telemetry", "Telemetry")
|
||||
.WithMany()
|
||||
.HasForeignKey("IdTelemetry")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Subsystem");
|
||||
|
||||
b.Navigation("Telemetry");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AsbCloudDb.Model.TelemetryDataSaub", b =>
|
||||
{
|
||||
b.HasOne("AsbCloudDb.Model.Telemetry", "Telemetry")
|
||||
|
@ -1,5 +1,4 @@
|
||||
using AsbCloudDb.Model.GTR;
|
||||
using AsbCloudDb.Model.Subsystems;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@ -38,7 +37,6 @@ namespace AsbCloudDb.Model
|
||||
public virtual DbSet<ReportProperty> ReportProperties => Set<ReportProperty>();
|
||||
public virtual DbSet<SetpointsRequest> SetpointsRequests => Set<SetpointsRequest>();
|
||||
public virtual DbSet<Subsystem> Subsystems => Set<Subsystem>();
|
||||
public virtual DbSet<SubsystemOperationTime> SubsystemOperationTimes => Set<SubsystemOperationTime>();
|
||||
public virtual DbSet<Telemetry> Telemetries => Set<Telemetry>();
|
||||
public virtual DbSet<TelemetryDataSaub> TelemetryDataSaub => Set<TelemetryDataSaub>();
|
||||
public virtual DbSet<TelemetryDataSaubStat> TelemetryDataSaubStats => Set<TelemetryDataSaubStat>();
|
||||
|
@ -24,7 +24,7 @@ namespace AsbCloudDb.Model.DefaultData
|
||||
{ typeof(WellType), new EntityFillerWellType()},
|
||||
{ typeof(MeasureCategory), new EntityFillerMeasureCategory()},
|
||||
{ typeof(CompanyType), new EntityFillerCompanyType()},
|
||||
{ typeof(Subsystems.Subsystem), new EntityFillerSubsystem() },
|
||||
{ typeof(Subsystem), new EntityFillerSubsystem() },
|
||||
{ typeof(NotificationCategory), new EntityNotificationCategory()},
|
||||
};
|
||||
return fillers;
|
||||
|
@ -1,14 +1,12 @@
|
||||
using AsbCloudDb.Model.Subsystems;
|
||||
namespace AsbCloudDb.Model.DefaultData
|
||||
namespace AsbCloudDb.Model.DefaultData
|
||||
{
|
||||
internal class EntityFillerSubsystem : EntityFiller<Subsystem>
|
||||
{
|
||||
public override Subsystem[] GetData() => new Subsystem[]{
|
||||
// САУБ - ид подсистем с 1 до 65_535
|
||||
new () {Id = 1, Name = "АКБ", Description = "Совместная работа режимов \"Бурение в роторе\" и \"Бурение в слайде\""},
|
||||
new () {Id = 1, Name = "АПД", Description = "Совместная работа режимов \"Бурение в роторе\" и \"Бурение в слайде\""},
|
||||
new () {Id = 11, Name = "АПД ротор", Description = "Режим работы \"Бурение в роторе\""},
|
||||
new () {Id = 12, Name = "АПД слайд", Description = "Режим работы \"Бурение в слайде\""},
|
||||
new () {Id = 2, Name = "MSE", Description = "Алгоритм поиска оптимальных параметров бурения САУБ"},
|
||||
//Spin master - id подсистем с 65_536 до 131_071
|
||||
new () {Id = 65536, Name = "Осцилляция", Description = "Осцилляция"},
|
||||
new () {Id = 65537, Name = "Демпфер", Description = "Демпфер"}
|
||||
|
@ -4,6 +4,6 @@ public class EntityNotificationCategory : EntityFiller<NotificationCategory>
|
||||
{
|
||||
public override NotificationCategory[] GetData() => new NotificationCategory[]
|
||||
{
|
||||
new() { Id = 1, Name = "Системные уведомления" }
|
||||
new() { Id = NotificationCategory.IdSystemNotificationCategory, Name = "Системные уведомления" }
|
||||
};
|
||||
}
|
@ -41,7 +41,7 @@ namespace AsbCloudDb.Model
|
||||
[Column("value"), Comment("Ключевой показатель операции")]
|
||||
public double Value { get; set; }
|
||||
|
||||
[Column("enabled_subsystems"), Comment("флаги аключенных подсистем")]
|
||||
[Column("enabled_subsystems"), Comment("флаги включенных подсистем")]
|
||||
public int EnabledSubsystems { get; set; }
|
||||
|
||||
[Column("extra_data", TypeName = "jsonb"), Comment("доп. инфо по операции")]
|
||||
@ -57,57 +57,5 @@ namespace AsbCloudDb.Model
|
||||
|
||||
public override string ToString()
|
||||
=> $"{IdCategory}\t{DateStart:G}\t{DateEnd:G}\t{DurationMinutes:#0.#}\t{DepthStart:#0.#}\t{DepthEnd:#0.#}";
|
||||
|
||||
/// <summary>
|
||||
/// Флаги аключенных подсистем
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum EnabledSubsystemsFlags
|
||||
{
|
||||
/// <summary>
|
||||
/// Автоподача долота
|
||||
/// </summary>
|
||||
AutoRotor = 1 << 0,
|
||||
/// <summary>
|
||||
/// БУРЕНИЕ В СЛАЙДЕ
|
||||
/// </summary>
|
||||
AutoSlide = 1 << 1,
|
||||
/// <summary>
|
||||
/// ПРОРАБОТКА
|
||||
/// </summary>
|
||||
AutoConditionig = 1 << 2,
|
||||
/// <summary>
|
||||
/// СПУСК СПО
|
||||
/// </summary>
|
||||
AutoSinking = 1 << 3,
|
||||
/// <summary>
|
||||
/// ПОДЪЕМ СПО
|
||||
/// </summary>
|
||||
AutoLifting = 1 << 4,
|
||||
/// <summary>
|
||||
/// ПОДЪЕМ С ПРОРАБОТКОЙ
|
||||
/// </summary>
|
||||
AutoLiftingWithConditionig = 1 << 5,
|
||||
/// <summary>
|
||||
/// блокировка
|
||||
/// </summary>
|
||||
AutoBlocknig = 1 << 6,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Есть ли флаг подсистемы у операции
|
||||
/// </summary>
|
||||
/// <param name="flag"></param>
|
||||
/// <returns></returns>
|
||||
public bool HasSubsystemFlag(EnabledSubsystemsFlags flag)
|
||||
=> HasSubsystemFlag((int)flag);
|
||||
|
||||
/// <summary>
|
||||
/// Есть ли флаг/флаги подсистемы у операции
|
||||
/// </summary>
|
||||
/// <param name="flags"></param>
|
||||
/// <returns></returns>
|
||||
public bool HasSubsystemFlag(int flags)
|
||||
=> (EnabledSubsystems & flags) > 0;
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
using AsbCloudDb.Model.GTR;
|
||||
using AsbCloudDb.Model.Subsystems;
|
||||
using AsbCloudDb.Model.WITS;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
@ -41,7 +40,6 @@ namespace AsbCloudDb.Model
|
||||
DbSet<RelationContactWell> RelationContactsWells { get; }
|
||||
DbSet<ReportProperty> ReportProperties { get; }
|
||||
DbSet<Subsystem> Subsystems { get; }
|
||||
DbSet<SubsystemOperationTime> SubsystemOperationTimes { get; }
|
||||
DbSet<Telemetry> Telemetries { get; }
|
||||
DbSet<TelemetryDataSaub> TelemetryDataSaub { get; }
|
||||
DbSet<TelemetryDataSaubStat> TelemetryDataSaubStats { get; }
|
||||
|
@ -8,7 +8,14 @@ namespace AsbCloudDb.Model;
|
||||
[Table("t_notification_category"), Comment("Категории уведомлений")]
|
||||
public class NotificationCategory : IId
|
||||
{
|
||||
[Key]
|
||||
#region constants category notifications ids
|
||||
/// <summary>
|
||||
/// СИСТЕМНЫЕ УВЕДОМЛЕНИЯ
|
||||
/// </summary>
|
||||
public const int IdSystemNotificationCategory = 1;
|
||||
#endregion
|
||||
|
||||
[Key]
|
||||
[Column("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace AsbCloudDb.Model.Subsystems
|
||||
namespace AsbCloudDb.Model
|
||||
{
|
||||
[Table("t_subsystem"), Comment("Описание подсистем")]
|
||||
public class Subsystem : IId
|
@ -1,41 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace AsbCloudDb.Model.Subsystems
|
||||
{
|
||||
[Table("t_subsystem_operation_time"), Comment("наработки подсистем")]
|
||||
public partial class SubsystemOperationTime : IId
|
||||
{
|
||||
[Column("id"), Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column("id_telemetry"), Comment("ИД телеметрии по которой выдается информация")]
|
||||
public int IdTelemetry { get; set; }
|
||||
|
||||
[Column("id_subsystem")]
|
||||
public int IdSubsystem { get; set; }
|
||||
|
||||
[Column("date_start"), Comment("дата/время включения подсистемы")]
|
||||
public DateTimeOffset DateStart { get; set; }
|
||||
|
||||
[Column("date_end"), Comment("дата/время выключения подсистемы")]
|
||||
public DateTimeOffset DateEnd { get; set; }
|
||||
|
||||
[Column("depth_start"), Comment("глубина забоя на момент включения подсистемы")]
|
||||
public float? DepthStart { get; set; }
|
||||
|
||||
[Column("depth_end"), Comment("глубина забоя на момент выключения подсистемы")]
|
||||
public float? DepthEnd { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[ForeignKey(nameof(IdSubsystem))]
|
||||
public virtual Subsystem Subsystem { get; set; } = null!;
|
||||
|
||||
[JsonIgnore]
|
||||
[ForeignKey(nameof(IdTelemetry))]
|
||||
public virtual Telemetry Telemetry { get; set; } = null!;
|
||||
}
|
||||
}
|
@ -56,6 +56,7 @@
|
||||
<PackageReference Include="ClosedXML" Version="0.96.0" />
|
||||
<PackageReference Include="itext7" Version="7.2.3" />
|
||||
<PackageReference Include="Mapster" Version="7.3.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.23.1" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.23.1" />
|
||||
|
@ -1,127 +0,0 @@
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudDb.Model.Subsystems;
|
||||
using AsbCloudInfrastructure.Services.Subsystems;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudInfrastructure.Background.PeriodicWorks;
|
||||
|
||||
public class WorkSubsystemAbfOperationTimeCalc : WorkSubsystemOperationTimeCalcAbstract
|
||||
{
|
||||
public WorkSubsystemAbfOperationTimeCalc()
|
||||
: base("Subsystem automated bit feeding operation time calc")
|
||||
{
|
||||
Timeout = TimeSpan.FromMinutes(30);
|
||||
}
|
||||
|
||||
protected override async Task<IEnumerable<SubsystemOperationTime>> OperationTimeAsync(int idTelemetry, DateTimeOffset geDate, IAsbCloudDbContext db, CancellationToken token)
|
||||
{
|
||||
static bool isSubsytemAkbRotor(short? mode) => mode == 1;
|
||||
|
||||
static bool isSubsytemAkbSlide(short? mode) => mode == 3;
|
||||
|
||||
static bool IsSubsystemMse(short? state) => (state & 1) > 0;
|
||||
|
||||
var query =
|
||||
$"select tt.date, tt.mode, tt.well_depth, tt.mse_state " +
|
||||
$"from ( " +
|
||||
$" select " +
|
||||
$" date, " +
|
||||
$" mode, " +
|
||||
$" mse_state, " +
|
||||
$" well_depth, " +
|
||||
$" lag(mode,1) over (order by date) as mode_lag, " +
|
||||
$" lead(mode,1) over (order by date) as mode_lead " +
|
||||
$" from t_telemetry_data_saub " +
|
||||
$" where id_telemetry = {idTelemetry} and well_depth is not null and well_depth > 0 " +
|
||||
$" order by date ) as tt " +
|
||||
$"where (tt.mode_lag is null or (tt.mode != tt.mode_lag and tt.mode_lead != tt.mode_lag)) and tt.date >= '{geDate:u}' " +
|
||||
$"order by tt.date;";
|
||||
|
||||
using var result = await ExecuteReaderAsync(db, query, token);
|
||||
|
||||
var subsystemsOperationTimes = new List<SubsystemOperationTime>();
|
||||
var detectorRotor = new SubsystemDetector(idTelemetry, idSubsystemAPDRotor, isSubsytemAkbRotor, IsValid);
|
||||
var detectorSlide = new SubsystemDetector(idTelemetry, idSubsystemAPDSlide, isSubsytemAkbSlide, IsValid);
|
||||
var detectorMse = new SubsystemDetector(idTelemetry, idSubsystemMse, IsSubsystemMse, IsValid);
|
||||
|
||||
while (result.Read())
|
||||
{
|
||||
var mode = result.GetFieldValue<short?>(1);
|
||||
var state = result.GetFieldValue<short?>(3);
|
||||
|
||||
var isAkbRotorEnable = isSubsytemAkbRotor(mode);
|
||||
var isAkbSlideEnable = isSubsytemAkbSlide(mode);
|
||||
var isMseEnable = IsSubsystemMse(state);
|
||||
var date = result.GetFieldValue<DateTimeOffset>(0);
|
||||
var depth = result.GetFieldValue<float>(2);
|
||||
|
||||
if (detectorRotor.TryDetect(mode, date, depth, out var detectedRotor))
|
||||
subsystemsOperationTimes.Add(detectedRotor!);
|
||||
|
||||
if (detectorSlide.TryDetect(mode, date, depth, out var detectedSlide))
|
||||
subsystemsOperationTimes.Add(detectedSlide!);
|
||||
|
||||
if (detectorMse.TryDetect(mode, date, depth, out var detectedMse))
|
||||
subsystemsOperationTimes.Add(detectedMse!);
|
||||
}
|
||||
|
||||
return subsystemsOperationTimes;
|
||||
}
|
||||
|
||||
private static async Task<DbDataReader> ExecuteReaderAsync(IAsbCloudDbContext db, string query, CancellationToken token)
|
||||
{
|
||||
var connection = db.Database.GetDbConnection();
|
||||
if (
|
||||
connection?.State is null ||
|
||||
connection.State == ConnectionState.Broken ||
|
||||
connection.State == ConnectionState.Closed)
|
||||
{
|
||||
await db.Database.OpenConnectionAsync(token);
|
||||
connection = db.Database.GetDbConnection();
|
||||
}
|
||||
using var command = connection.CreateCommand();
|
||||
command.CommandText = query;
|
||||
|
||||
var result = await command.ExecuteReaderAsync(token);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool IsValid(SubsystemOperationTime item)
|
||||
{
|
||||
var validateCode = GetValidateErrorCode(item);
|
||||
if (validateCode != 0)
|
||||
{
|
||||
var str = System.Text.Json.JsonSerializer.Serialize(item);
|
||||
Trace.TraceWarning($"Wrong({validateCode}) SubsystemOperationTime: {str}");
|
||||
}
|
||||
return validateCode == 0;
|
||||
}
|
||||
|
||||
private static int GetValidateErrorCode(SubsystemOperationTime item)
|
||||
{
|
||||
if (item.DateStart > item.DateEnd)
|
||||
return -1;
|
||||
if ((item.DateEnd - item.DateStart).TotalHours > 48)
|
||||
return -2;
|
||||
if (item.DepthEnd < item.DepthStart)
|
||||
return -3;
|
||||
if (item.DepthEnd - item.DepthStart > 2000d)
|
||||
return -4;
|
||||
if (item.DepthEnd < 0d)
|
||||
return -5;
|
||||
if (item.DepthStart < 0d)
|
||||
return -6;
|
||||
if (item.DepthEnd > 24_0000d)
|
||||
return -7;
|
||||
if (item.DepthStart > 24_0000d)
|
||||
return -8;
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
using AsbCloudApp.Data.SAUB;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudDb.Model.Subsystems;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudInfrastructure.Background.PeriodicWorks;
|
||||
|
||||
public abstract class WorkSubsystemOperationTimeCalcAbstract : Work
|
||||
{
|
||||
protected const int idSubsystemTorqueMaster = 65537;
|
||||
protected const int idSubsystemSpinMaster = 65536;
|
||||
protected const int idSubsystemAPDRotor = 11;
|
||||
protected const int idSubsystemAPDSlide = 12;
|
||||
protected const int idSubsystemMse = 2;
|
||||
|
||||
private static TimeSpan obsoleteTime = TimeSpan.FromDays(365 * 100);
|
||||
|
||||
public WorkSubsystemOperationTimeCalcAbstract(string workId)
|
||||
: base(workId)
|
||||
{
|
||||
Timeout = TimeSpan.FromMinutes(30);
|
||||
}
|
||||
|
||||
protected override async Task Action(string id, IServiceProvider services, Action<string, double?> onProgressCallback, CancellationToken token)
|
||||
{
|
||||
var db = services.GetRequiredService<IAsbCloudDbContext>();
|
||||
db.Database.SetCommandTimeout(TimeSpan.FromMinutes(5));
|
||||
|
||||
var telemetryLastDetectedDates = await GetTelemetryLastDetectedDates(services, db, token);
|
||||
|
||||
var count = telemetryLastDetectedDates.Count();
|
||||
var i = 0d;
|
||||
|
||||
foreach (var item in telemetryLastDetectedDates)
|
||||
{
|
||||
onProgressCallback($"Start handling telemetry: {item.IdTelemetry} from {item.DateDetectedLast}", i++ / count);
|
||||
var newOperationsSaub = await OperationTimeAsync(item.IdTelemetry, item.DateDetectedLast, db, token);
|
||||
if (newOperationsSaub.Any())
|
||||
{
|
||||
db.SubsystemOperationTimes.AddRange(newOperationsSaub);
|
||||
await db.SaveChangesAsync(token);
|
||||
}
|
||||
}
|
||||
|
||||
obsoleteTime = TimeSpan.FromDays(3);
|
||||
}
|
||||
|
||||
protected abstract Task<IEnumerable<SubsystemOperationTime>> OperationTimeAsync(int idTelemetry, DateTimeOffset geDate, IAsbCloudDbContext db, CancellationToken token);
|
||||
|
||||
private static async Task<IEnumerable<TelemetryDateLast>> GetTelemetryLastDetectedDates(IServiceProvider services, IAsbCloudDbContext db, CancellationToken token)
|
||||
{
|
||||
var telemetryDataCache = services.GetRequiredService<ITelemetryDataCache<TelemetryDataSaubDto>>();
|
||||
|
||||
var updatingTelemetries = telemetryDataCache.GetStat()
|
||||
.Where(tstat => (DateTimeOffset.Now - tstat.DateLast) < obsoleteTime);
|
||||
|
||||
var telemetryIds = updatingTelemetries
|
||||
.Select(t => t.IdTelemetry)
|
||||
.ToArray();
|
||||
|
||||
IEnumerable<TelemetryDateLast> lastDetectedDates = await GetLastSubsystemOperationTimeAsync(db, token);
|
||||
lastDetectedDates = lastDetectedDates
|
||||
.Where(s => telemetryIds.Contains(s.IdTelemetry));
|
||||
|
||||
var result = updatingTelemetries.Select(tstat => new TelemetryDateLast
|
||||
{
|
||||
IdTelemetry = tstat.IdTelemetry,
|
||||
DateDetectedLast = lastDetectedDates.FirstOrDefault(ldd => ldd.IdTelemetry == tstat.IdTelemetry)?.DateDetectedLast
|
||||
?? DateTimeOffset.UnixEpoch,
|
||||
DateTelemetryLast = tstat.DateLast
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
private static async Task<IEnumerable<TelemetryDateLast>> GetLastSubsystemOperationTimeAsync(IAsbCloudDbContext db, CancellationToken token)
|
||||
{
|
||||
var result = await db.SubsystemOperationTimes
|
||||
.GroupBy(o => o.IdTelemetry)
|
||||
.Select(g => new TelemetryDateLast
|
||||
{
|
||||
IdTelemetry = g.Key,
|
||||
DateDetectedLast = g.Max(o => o.DateEnd)
|
||||
})
|
||||
.ToArrayAsync(token);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected class TelemetryDateLast
|
||||
{
|
||||
public int IdTelemetry { get; set; }
|
||||
public DateTimeOffset DateDetectedLast { get; set; }
|
||||
public DateTimeOffset DateTelemetryLast { get; internal set; }
|
||||
}
|
||||
}
|
@ -1,186 +0,0 @@
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudDb.Model.Subsystems;
|
||||
using AsbCloudInfrastructure.Background;
|
||||
using AsbCloudInfrastructure.Services.Subsystems;
|
||||
using AsbCloudInfrastructure.Services.Subsystems.Utils;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudInfrastructure.Background.PeriodicWorks;
|
||||
|
||||
public class WorkSubsystemOscillationOperationTimeCalc : WorkSubsystemOperationTimeCalcAbstract
|
||||
{
|
||||
public WorkSubsystemOscillationOperationTimeCalc()
|
||||
: base("Subsystem operation time calc")
|
||||
{
|
||||
Timeout = TimeSpan.FromMinutes(30);
|
||||
}
|
||||
|
||||
protected override async Task<IEnumerable<SubsystemOperationTime>> OperationTimeAsync(int idTelemetry, DateTimeOffset geDate, IAsbCloudDbContext db, CancellationToken token)
|
||||
{
|
||||
static int? GetSubsytemId(short? mode, int? state)
|
||||
{
|
||||
// При изменении следующего кода сообщи в Vladimir.Sobolev@nedra.digital
|
||||
if (state == 7 && (mode & 2) > 0)
|
||||
return idSubsystemTorqueMaster;// демпфер
|
||||
|
||||
if (state != 0 && state != 5 && state != 6 && state != 7)
|
||||
return idSubsystemSpinMaster;// осцилляция
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var querySpin =
|
||||
$"select " +
|
||||
$" tspin.date, " +
|
||||
$" tspin.mode, " +
|
||||
$" tspin.state " +
|
||||
$"from ( " +
|
||||
$" select " +
|
||||
$" date, " +
|
||||
$" mode, " +
|
||||
$" lag(mode, 1) over (order by date) as mode_lag, " +
|
||||
$" lead(mode, 1) over (order by date) as mode_lead, " +
|
||||
$" state, " +
|
||||
$" lag(state, 1) over (order by date) as state_lag " +
|
||||
$" from t_telemetry_data_spin " +
|
||||
$" where id_telemetry = {idTelemetry} and date >= '{geDate:u}'" +
|
||||
$" order by date ) as tspin " +
|
||||
$"where mode_lag is null or state_lag is null or (mode != mode_lag and mode_lead != mode_lag) or state != state_lag " +
|
||||
$"order by date;";
|
||||
|
||||
var rows = new List<(int? IdSubsystem, DateTimeOffset Date)>(32);
|
||||
|
||||
using var resultSpin = await ExecuteReaderAsync(db, querySpin, token);
|
||||
int? idSubsystemLast = null;
|
||||
while (resultSpin.Read())
|
||||
{
|
||||
var mode = resultSpin.GetFieldValue<short?>(1);
|
||||
var state = resultSpin.GetFieldValue<short?>(2);
|
||||
var idSubsystem = GetSubsytemId(mode, state);
|
||||
if (idSubsystemLast != idSubsystem)
|
||||
{
|
||||
idSubsystemLast = idSubsystem;
|
||||
var date = resultSpin.GetFieldValue<DateTimeOffset>(0);
|
||||
rows.Add((idSubsystem, date));
|
||||
}
|
||||
}
|
||||
await resultSpin.DisposeAsync();
|
||||
|
||||
if (rows.Count < 2)
|
||||
return Enumerable.Empty<SubsystemOperationTime>();
|
||||
|
||||
var minSpinDate = rows.Min(i => i.Date);
|
||||
var maxSpinDate = rows.Max(i => i.Date);
|
||||
var depthInterpolation = await GetInterpolation(db, idTelemetry, minSpinDate, maxSpinDate, token);
|
||||
|
||||
if (depthInterpolation is null)
|
||||
return Enumerable.Empty<SubsystemOperationTime>();
|
||||
|
||||
var subsystemsOperationTimes = new List<SubsystemOperationTime>(32);
|
||||
|
||||
for (int i = 1; i < rows.Count; i++)
|
||||
{
|
||||
var r0 = rows[i - 1];
|
||||
var r1 = rows[i];
|
||||
if (r0.IdSubsystem is not null && r0.IdSubsystem != r1.IdSubsystem)
|
||||
{
|
||||
var subsystemOperationTime = new SubsystemOperationTime()
|
||||
{
|
||||
IdTelemetry = idTelemetry,
|
||||
IdSubsystem = r0.IdSubsystem.Value,
|
||||
DateStart = r0.Date,
|
||||
DateEnd = r1.Date,
|
||||
DepthStart = depthInterpolation.GetDepth(r0.Date),
|
||||
DepthEnd = depthInterpolation.GetDepth(r1.Date),
|
||||
};
|
||||
|
||||
if (IsValid(subsystemOperationTime))
|
||||
subsystemsOperationTimes.Add(subsystemOperationTime);
|
||||
}
|
||||
}
|
||||
|
||||
return subsystemsOperationTimes;
|
||||
}
|
||||
|
||||
private static async Task<DbDataReader> ExecuteReaderAsync(IAsbCloudDbContext db, string query, CancellationToken token)
|
||||
{
|
||||
var connection = db.Database.GetDbConnection();
|
||||
if (
|
||||
connection?.State is null ||
|
||||
connection.State == ConnectionState.Broken ||
|
||||
connection.State == ConnectionState.Closed)
|
||||
{
|
||||
await db.Database.OpenConnectionAsync(token);
|
||||
connection = db.Database.GetDbConnection();
|
||||
}
|
||||
using var command = connection.CreateCommand();
|
||||
command.CommandText = query;
|
||||
|
||||
var result = await command.ExecuteReaderAsync(token);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool IsValid(SubsystemOperationTime item)
|
||||
{
|
||||
var validateCode = GetValidateErrorCode(item);
|
||||
if (validateCode != 0)
|
||||
{
|
||||
var str = System.Text.Json.JsonSerializer.Serialize(item);
|
||||
Trace.TraceWarning($"Wrong({validateCode}) SubsystemOperationTime: {str}");
|
||||
}
|
||||
return validateCode == 0;
|
||||
}
|
||||
|
||||
private static int GetValidateErrorCode(SubsystemOperationTime item)
|
||||
{
|
||||
if (item.DateStart > item.DateEnd)
|
||||
return -1;
|
||||
if ((item.DateEnd - item.DateStart).TotalHours > 48)
|
||||
return -2;
|
||||
if (item.DepthEnd < item.DepthStart)
|
||||
return -3;
|
||||
if (item.DepthEnd - item.DepthStart > 2000d)
|
||||
return -4;
|
||||
if (item.DepthEnd < 0d)
|
||||
return -5;
|
||||
if (item.DepthStart < 0d)
|
||||
return -6;
|
||||
if (item.DepthEnd > 24_0000d)
|
||||
return -7;
|
||||
if (item.DepthStart > 24_0000d)
|
||||
return -8;
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static async Task<DepthInterpolation?> GetInterpolation(IAsbCloudDbContext db, int idTelemetry, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token)
|
||||
{
|
||||
var dataDepthFromSaub = await db.TelemetryDataSaub
|
||||
.Where(d => d.IdTelemetry == idTelemetry)
|
||||
.Where(d => d.DateTime >= dateBegin)
|
||||
.Where(d => d.DateTime <= dateEnd)
|
||||
.Where(d => d.WellDepth > 0)
|
||||
.GroupBy(d => Math.Ceiling(d.WellDepth * 10))
|
||||
.Select(g => new
|
||||
{
|
||||
DateMin = g.Min(d => d.DateTime),
|
||||
DepthMin = g.Min(d => d.WellDepth),
|
||||
})
|
||||
.OrderBy(i => i.DateMin)
|
||||
.ToArrayAsync(token);
|
||||
|
||||
if (!dataDepthFromSaub.Any())
|
||||
return null;
|
||||
|
||||
var depthInterpolation = new DepthInterpolation(dataDepthFromSaub.Select(i => (i.DateMin, i.DepthMin)));
|
||||
return depthInterpolation;
|
||||
}
|
||||
}
|
@ -12,12 +12,10 @@ using AsbCloudApp.Services;
|
||||
using AsbCloudApp.Services.Notifications;
|
||||
using AsbCloudApp.Services.ProcessMaps;
|
||||
using AsbCloudApp.Services.ProcessMaps.WellDrilling;
|
||||
using AsbCloudApp.Services.Subsystems;
|
||||
using AsbCloudApp.Services.WellOperationImport;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudDb.Model.Manuals;
|
||||
using AsbCloudDb.Model.ProcessMaps;
|
||||
using AsbCloudDb.Model.Subsystems;
|
||||
using AsbCloudDb.Model.Trajectory;
|
||||
using AsbCloudInfrastructure.Background;
|
||||
using AsbCloudInfrastructure.Repository;
|
||||
@ -211,7 +209,7 @@ namespace AsbCloudInfrastructure
|
||||
services.AddTransient<IWellOperationRepository, WellOperationRepository>();
|
||||
services.AddTransient<IDailyReportService, DailyReportService>();
|
||||
services.AddTransient<IDetectedOperationService, DetectedOperationService>();
|
||||
services.AddTransient<ISubsystemOperationTimeService, SubsystemOperationTimeService>();
|
||||
services.AddTransient<ISubsystemService, SubsystemService>();
|
||||
services.AddTransient<IScheduleRepository, ScheduleRepository>();
|
||||
services.AddTransient<IRepositoryWellRelated<OperationValueDto>, CrudWellRelatedRepositoryBase<OperationValueDto, OperationValue>>();
|
||||
services.AddTransient<IUserSettingsRepository, UserSettingsRepository>();
|
||||
@ -222,6 +220,7 @@ namespace AsbCloudInfrastructure
|
||||
services.AddTransient<IProcessMapPlanImportService, ProcessMapPlanImportWellDrillingService>();
|
||||
services.AddTransient<WellInfoService>();
|
||||
services.AddTransient<IHelpPageService, HelpPageService>();
|
||||
services.AddTransient<IScheduleReportService, ScheduleReportService>();
|
||||
|
||||
services.AddTransient<TrajectoryService>();
|
||||
|
||||
|
@ -16,7 +16,6 @@ using AsbCloudApp.Data.DailyReport.Blocks.WellOperation;
|
||||
using AsbCloudApp.Requests;
|
||||
using AsbCloudApp.Services.DailyReport;
|
||||
using AsbCloudApp.Services.ProcessMaps.WellDrilling;
|
||||
using AsbCloudApp.Services.Subsystems;
|
||||
using AsbCloudDb.Model;
|
||||
using Mapster;
|
||||
|
||||
@ -29,7 +28,7 @@ public class DailyReportService : IDailyReportService
|
||||
private readonly IDailyReportRepository dailyReportRepository;
|
||||
private readonly IScheduleRepository scheduleRepository;
|
||||
private readonly IWellOperationRepository wellOperationRepository;
|
||||
private readonly ISubsystemOperationTimeService subsystemOperationTimeService;
|
||||
private readonly ISubsystemService subsystemService;
|
||||
private readonly IProcessMapReportWellDrillingService processMapReportWellDrillingService;
|
||||
private readonly IDetectedOperationService detectedOperationService;
|
||||
|
||||
@ -38,7 +37,7 @@ public class DailyReportService : IDailyReportService
|
||||
IDailyReportRepository dailyReportRepository,
|
||||
IScheduleRepository scheduleRepository,
|
||||
IWellOperationRepository wellOperationRepository,
|
||||
ISubsystemOperationTimeService subsystemOperationTimeService,
|
||||
ISubsystemService subsystemService,
|
||||
IProcessMapReportWellDrillingService processMapReportWellDrillingService,
|
||||
IDetectedOperationService detectedOperationService)
|
||||
{
|
||||
@ -47,7 +46,7 @@ public class DailyReportService : IDailyReportService
|
||||
this.dailyReportRepository = dailyReportRepository;
|
||||
this.scheduleRepository = scheduleRepository;
|
||||
this.wellOperationRepository = wellOperationRepository;
|
||||
this.subsystemOperationTimeService = subsystemOperationTimeService;
|
||||
this.subsystemService = subsystemService;
|
||||
this.processMapReportWellDrillingService = processMapReportWellDrillingService;
|
||||
this.detectedOperationService = detectedOperationService;
|
||||
}
|
||||
@ -264,8 +263,8 @@ public class DailyReportService : IDailyReportService
|
||||
{
|
||||
IdsCategories = new[] { idWellOperationSlipsTime },
|
||||
IdWell = dailyReport.IdWell,
|
||||
GtDate = dailyReport.Date,
|
||||
LtDate = dailyReport.Date.AddHours(24)
|
||||
GeDateStart = dailyReport.Date,
|
||||
LeDateEnd = dailyReport.Date.AddHours(24)
|
||||
}, cancellationToken))?.Stats.Sum(s => s.Count);
|
||||
|
||||
dailyReport.TimeBalanceBlock.WellDepth.Fact = factWellOperations
|
||||
@ -311,24 +310,24 @@ public class DailyReportService : IDailyReportService
|
||||
|
||||
async Task<IEnumerable<SubsystemRecordDto>> GetSubsystemsAsync()
|
||||
{
|
||||
var subsystemOperationTimesPerWell = await subsystemOperationTimeService.GetStatAsync(new SubsystemOperationTimeRequest
|
||||
var subsystemsStatPerWell = await subsystemService.GetStatAsync(new SubsystemRequest
|
||||
{
|
||||
IdWell = dailyReport.IdWell
|
||||
}, cancellationToken);
|
||||
|
||||
var subsystemOperationTimesPerDay = await subsystemOperationTimeService.GetStatAsync(new SubsystemOperationTimeRequest
|
||||
var subsystemsStatPerDay = await subsystemService.GetStatAsync(new SubsystemRequest
|
||||
{
|
||||
IdWell = dailyReport.IdWell,
|
||||
GtDate = dailyReport.Date,
|
||||
LtDate = dailyReport.Date.AddHours(24)
|
||||
GeDate = dailyReport.Date,
|
||||
LeDate = dailyReport.Date.AddHours(24)
|
||||
}, cancellationToken);
|
||||
|
||||
var subsystems = subsystemOperationTimesPerWell
|
||||
.Select(subsystemOperationTime => new SubsystemRecordDto
|
||||
var subsystems = subsystemsStatPerWell
|
||||
.Select(subsystemStatPerWell => new SubsystemRecordDto
|
||||
{
|
||||
Name = subsystemOperationTime.SubsystemName,
|
||||
UsagePerDay = subsystemOperationTimesPerDay.FirstOrDefault(s => s.IdSubsystem == subsystemOperationTime.IdSubsystem)?.Adapt<SubsystemParametersDto>(),
|
||||
UsagePerWell = subsystemOperationTime.Adapt<SubsystemParametersDto>()
|
||||
Name = subsystemStatPerWell.SubsystemName,
|
||||
UsagePerDay = subsystemsStatPerDay.FirstOrDefault(s => s.IdSubsystem == subsystemStatPerWell.IdSubsystem)?.Adapt<SubsystemParametersDto>(),
|
||||
UsagePerWell = subsystemStatPerWell.Adapt<SubsystemParametersDto>()
|
||||
}).ToList();
|
||||
|
||||
if (dailyReport.SubsystemBlock?.Subsystems != null && dailyReport.SubsystemBlock.Subsystems.Any())
|
||||
|
@ -8,8 +8,10 @@ using System.Linq;
|
||||
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;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations;
|
||||
|
||||
@ -21,12 +23,6 @@ public class DetectedOperationExportService
|
||||
new DetectorSlipsTime()
|
||||
};
|
||||
|
||||
private readonly IDictionary<int, string> domains = new Dictionary<int, string>
|
||||
{
|
||||
{ 1, "https://cloud.digitaldrilling.ru" },
|
||||
{ 2, "https://cloud.autodrilling.ru" }
|
||||
};
|
||||
|
||||
private const int headerRowsCount = 1;
|
||||
|
||||
private const string cellDepositName = "B1";
|
||||
@ -54,7 +50,15 @@ public class DetectedOperationExportService
|
||||
this.wellOperationRepository = wellOperationRepository;
|
||||
}
|
||||
|
||||
public async Task<Stream> ExportAsync(int idWell, int idDomain, CancellationToken cancellationToken)
|
||||
/// <summary>
|
||||
/// Экспорт excel файла с операциями по скважине
|
||||
/// </summary>
|
||||
/// <param name="idWell">ключ скважины</param>
|
||||
/// <param name="host">хост</param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public async Task<Stream> ExportAsync(int idWell, string host, CancellationToken cancellationToken)
|
||||
{
|
||||
var well = await dbContext.Wells
|
||||
.Include(w => w.Cluster)
|
||||
@ -69,17 +73,17 @@ public class DetectedOperationExportService
|
||||
|
||||
var operations = await DetectOperationsAsync(well.IdTelemetry.Value, DateTime.UnixEpoch, cancellationToken);
|
||||
|
||||
return await GenerateExcelFileStreamAsync(well, idDomain, operations, cancellationToken);
|
||||
return await GenerateExcelFileStreamAsync(well, host, operations, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task<Stream> GenerateExcelFileStreamAsync(Well well, int idDomain, IEnumerable<OperationDetectorResult> operationDetectorResults,
|
||||
private async Task<Stream> GenerateExcelFileStreamAsync(Well well, string host, IEnumerable<OperationDetectorResult> operationDetectorResults,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
using var excelTemplateStream = await GetExcelTemplateStreamAsync(cancellationToken);
|
||||
|
||||
using var workbook = new XLWorkbook(excelTemplateStream, XLEventTracking.Disabled);
|
||||
|
||||
await AddToWorkbookAsync(workbook, well, idDomain, operationDetectorResults, cancellationToken);
|
||||
await AddToWorkbookAsync(workbook, well, host, operationDetectorResults, cancellationToken);
|
||||
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
workbook.SaveAs(memoryStream, new SaveOptions { });
|
||||
@ -87,7 +91,7 @@ public class DetectedOperationExportService
|
||||
return memoryStream;
|
||||
}
|
||||
|
||||
private async Task AddToWorkbookAsync(XLWorkbook workbook, Well well, int idDomain, IEnumerable<OperationDetectorResult> operationDetectorResults,
|
||||
private async Task AddToWorkbookAsync(XLWorkbook workbook, Well well, string host, IEnumerable<OperationDetectorResult> operationDetectorResults,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
const string sheetName = "Операции";
|
||||
@ -98,12 +102,12 @@ public class DetectedOperationExportService
|
||||
var sheet = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetName)
|
||||
?? throw new FileFormatException($"Книга excel не содержит листа {sheetName}.");
|
||||
|
||||
await AddToSheetAsync(sheet, well, idDomain, operationDetectorResults
|
||||
await AddToSheetAsync(sheet, well, host, operationDetectorResults
|
||||
.OrderBy(x => x.Operation.DateStart).ThenBy(x => x.Operation.DepthStart).ToArray(),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
private async Task AddToSheetAsync(IXLWorksheet sheet, Well well, int idDomain, IList<OperationDetectorResult> operationDetectorResults,
|
||||
private async Task AddToSheetAsync(IXLWorksheet sheet, Well well, string host, IList<OperationDetectorResult> operationDetectorResults,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var wellOperationCategories = await dbContext.WellOperationCategories.ToListAsync(cancellationToken);
|
||||
@ -134,8 +138,11 @@ public class DetectedOperationExportService
|
||||
&& idReasonOfEndObject is int idReasonOfEnd)
|
||||
row.Cell(columnIdReasonOfEnd).Value = GetIdReasonOfEnd(idReasonOfEnd);
|
||||
|
||||
var link =
|
||||
$"{domains[idDomain]}/well/{well.Id}/telemetry/monitoring?end={Uri.EscapeDataString(dateStart.AddSeconds(1800 * 0.9).ToString("yyyy-MM-ddTHH:mm:ss.fff"))}&range=1800";
|
||||
var query = new QueryBuilder();
|
||||
query.Add("end", dateStart.AddSeconds(1800 * 0.9).ToString("yyyy-MM-ddTHH:mm:ss.fff"));
|
||||
query.Add("range", "1800");
|
||||
|
||||
var link = $"{host}/well/{well.Id}/telemetry/monitoring{query}";
|
||||
|
||||
row.Cell(columnDateStart).Value = dateStart;
|
||||
row.Cell(columnDateStart).SetHyperlink(new XLHyperlink(link));
|
||||
@ -151,9 +158,8 @@ public class DetectedOperationExportService
|
||||
private static string GetCategoryName(IEnumerable<WellOperationCategory> wellOperationCategories, DetectedOperation current)
|
||||
{
|
||||
var idCategory = current.IdCategory;
|
||||
if (idCategory == WellOperationCategory.IdSlide
|
||||
&& current.ExtraData[DetectorDrilling.ExtraDataKeyHasOscillation] is bool hasOscillation
|
||||
&& hasOscillation)
|
||||
if (idCategory == WellOperationCategory.IdSlide &&
|
||||
EnabledSubsystemsFlags.AutoOscillation.HasEnabledSubsystems(current.EnabledSubsystems))
|
||||
return "Бурение в слайде с осцилляцией";
|
||||
|
||||
var category = wellOperationCategories.FirstOrDefault(o => o.Id == current.IdCategory);
|
||||
|
@ -45,17 +45,13 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<DetectedOperationDto>?> GetOperationsAsync(DetectedOperationRequest request, CancellationToken token)
|
||||
public async Task<IEnumerable<DetectedOperationDto>> GetOperationsAsync(DetectedOperationRequest request, CancellationToken token)
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(request.IdWell, token);
|
||||
if (well?.IdTelemetry is null || well.Timezone is null)
|
||||
return null;
|
||||
if (well?.IdTelemetry is null)
|
||||
return Enumerable.Empty<DetectedOperationDto>();
|
||||
|
||||
var query = BuildQuery(well, request)
|
||||
?.AsNoTracking();
|
||||
|
||||
if (query is null)
|
||||
return null;
|
||||
var query = BuildQuery(well, request).AsNoTracking();
|
||||
|
||||
var data = await query.ToListAsync(token);
|
||||
|
||||
@ -65,61 +61,6 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||
return dtos;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<OperationsSummaryDto>> GetOperationSummaryAsync(DetectedOperationSummaryRequest request, CancellationToken token)
|
||||
{
|
||||
var query = db.Set<DetectedOperation>()
|
||||
.AsNoTracking();
|
||||
|
||||
if (request.IdsTelemetries.Any())
|
||||
query = query.Where(operation => request.IdsTelemetries.Contains(operation.IdTelemetry));
|
||||
|
||||
if (request.IdsOperationCategories.Any())
|
||||
query = query.Where(operation => request.IdsOperationCategories.Contains(operation.IdCategory));
|
||||
|
||||
if (request.GeDateStart.HasValue)
|
||||
{
|
||||
var geDateStart = request.GeDateStart.Value.ToUniversalTime();
|
||||
query = query.Where(operation => operation.DateStart >= geDateStart);
|
||||
}
|
||||
|
||||
if (request.LeDateStart.HasValue)
|
||||
{
|
||||
var leDateStart = request.LeDateStart.Value.ToUniversalTime();
|
||||
query = query.Where(operation => operation.DateStart <= leDateStart);
|
||||
}
|
||||
|
||||
if (request.LeDateEnd.HasValue)
|
||||
{
|
||||
var leDateEnd = request.LeDateEnd.Value.ToUniversalTime();
|
||||
query = query.Where(operation => operation.DateEnd <= leDateEnd);
|
||||
}
|
||||
|
||||
if (request.GeDepthStart.HasValue)
|
||||
query = query.Where(operation => operation.DepthStart >= request.GeDepthStart.Value);
|
||||
|
||||
if (request.LeDepthStart.HasValue)
|
||||
query = query.Where(operation => operation.DepthStart <= request.LeDepthStart.Value);
|
||||
|
||||
if (request.LeDepthEnd.HasValue)
|
||||
query = query.Where(operation => operation.DepthEnd <= request.LeDepthEnd.Value);
|
||||
|
||||
var queryGroup = query
|
||||
.GroupBy(operation => new { operation.IdTelemetry, operation.IdCategory })
|
||||
.Select(group => new OperationsSummaryDto
|
||||
{
|
||||
IdTelemetry = group.Key.IdTelemetry,
|
||||
IdCategory = group.Key.IdCategory,
|
||||
Count = group.Count(),
|
||||
SumDepthIntervals = group.Sum(operation => operation.DepthEnd - operation.DepthStart),
|
||||
SumDurationHours = group.Sum(operation => (operation.DateEnd - operation.DateStart).TotalHours)
|
||||
})
|
||||
.OrderBy(summ => summ.IdTelemetry)
|
||||
.ThenBy(summ => summ.IdCategory);
|
||||
|
||||
var result = await queryGroup.ToArrayAsync(token);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IEnumerable<DetectedOperationDrillersStatDto> GetOperationsDrillersStat(IEnumerable<DetectedOperationDto> operations)
|
||||
{
|
||||
var groups = operations.GroupBy(o => o.Driller);
|
||||
@ -240,20 +181,23 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||
|
||||
if (request is not null)
|
||||
{
|
||||
if (request.IdsCategories?.Any() == true)
|
||||
if (request.IdsTelemetries.Any())
|
||||
query = query.Where(o => request.IdsTelemetries.Contains(o.IdTelemetry));
|
||||
|
||||
if (request.IdsCategories.Any())
|
||||
query = query.Where(o => request.IdsCategories.Contains(o.IdCategory));
|
||||
|
||||
if (request.GtDate is not null)
|
||||
query = query.Where(o => o.DateStart >= request.GtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours));
|
||||
if (request.GeDateStart is not null)
|
||||
query = query.Where(o => o.DateStart >= request.GeDateStart.Value.Date.ToUtcDateTimeOffset(well.Timezone.Hours));
|
||||
|
||||
if (request.LtDate is not null)
|
||||
query = query.Where(o => o.DateEnd <= request.LtDate.Value.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.GtDepth is not null)
|
||||
query = query.Where(o => o.DepthStart >= request.GtDepth);
|
||||
if (request.GeDepth is not null)
|
||||
query = query.Where(o => o.DepthStart >= request.GeDepth);
|
||||
|
||||
if (request.LtDepth is not null)
|
||||
query = query.Where(o => o.DepthEnd <= request.LtDepth);
|
||||
if (request.LeDepth is not null)
|
||||
query = query.Where(o => o.DepthEnd <= request.LeDepth);
|
||||
|
||||
if (request.EqIdTelemetryUser is not null)
|
||||
query = query.Where(o => o.IdUsersAtStart == request.EqIdTelemetryUser);
|
||||
|
@ -1,7 +1,7 @@
|
||||
using AsbCloudDb.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AsbCloudApp.Data.DetectedOperation;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
{
|
||||
@ -126,7 +126,7 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
DepthEnd = (double)pEnd.WellDepth,
|
||||
ExtraData = ExtraData,
|
||||
Value = CalcValue(telemetry, begin, end),
|
||||
EnabledSubsystems = DetectEnabledSubsystems(telemetry, begin, end)
|
||||
EnabledSubsystems = DetectEnabledSubsystems(telemetry, begin, end, ExtraData)
|
||||
};
|
||||
|
||||
return operation;
|
||||
@ -155,35 +155,40 @@ namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
/// <param name="telemetry"></param>
|
||||
/// <param name="begin"></param>
|
||||
/// <param name="end"></param>
|
||||
/// <param name="extraData"></param>
|
||||
/// <returns></returns>
|
||||
private static int DetectEnabledSubsystems(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
private static int DetectEnabledSubsystems(DetectableTelemetry[] telemetry, int begin, int end, IDictionary<string, object> extraData)
|
||||
{
|
||||
var enabledSubsystems = 0;
|
||||
|
||||
for (var i = begin; i < end; i += 2)
|
||||
{
|
||||
var mode = telemetry[i].Mode;
|
||||
|
||||
|
||||
if (extraData.TryGetValue(DetectorDrilling.ExtraDataKeyHasOscillation, out var hasOscillation)
|
||||
&& hasOscillation is true)
|
||||
enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoOscillation;
|
||||
|
||||
if(mode == 1)
|
||||
enabledSubsystems |= (int)DetectedOperation.EnabledSubsystemsFlags.AutoRotor;
|
||||
enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoRotor;
|
||||
|
||||
if (mode == 3)
|
||||
enabledSubsystems |= (int)DetectedOperation.EnabledSubsystemsFlags.AutoSlide;
|
||||
enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoSlide;
|
||||
|
||||
if (mode == 2)
|
||||
enabledSubsystems |= (int)DetectedOperation.EnabledSubsystemsFlags.AutoConditionig;
|
||||
enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoConditionig;
|
||||
|
||||
if (mode == 4)
|
||||
enabledSubsystems |= (int)DetectedOperation.EnabledSubsystemsFlags.AutoSinking;
|
||||
enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoSinking;
|
||||
|
||||
if (mode == 5)
|
||||
enabledSubsystems |= (int)DetectedOperation.EnabledSubsystemsFlags.AutoLifting;
|
||||
enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoLifting;
|
||||
|
||||
if (mode == 6)
|
||||
enabledSubsystems |= (int)DetectedOperation.EnabledSubsystemsFlags.AutoLiftingWithConditionig;
|
||||
enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoLiftingWithConditionig;
|
||||
|
||||
if (mode == 10)
|
||||
enabledSubsystems |= (int)DetectedOperation.EnabledSubsystemsFlags.AutoBlocknig;
|
||||
enabledSubsystems |= (int)EnabledSubsystemsFlags.AutoBlocknig;
|
||||
}
|
||||
|
||||
return enabledSubsystems;
|
||||
|
@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using AsbCloudDb.Model;
|
||||
|
||||
@ -65,15 +64,15 @@ public class DetectorDrilling : DetectorAbstract
|
||||
{
|
||||
[ExtraDataKeyAvgRotorSpeed] = avgRotorSpeed,
|
||||
[ExtraDataKeyDispersionOfNormalizedRotorSpeed] = dispersionOfNormalizedRotorSpeed,
|
||||
[ExtraDataKeyHasOscillation] = dispersionOfNormalizedRotorSpeed > dispersionOfNormalizedRotorSpeedThreshold
|
||||
[ExtraDataKeyHasOscillation] = avgRotorSpeed > 1 && dispersionOfNormalizedRotorSpeed > dispersionOfNormalizedRotorSpeedThreshold
|
||||
};
|
||||
return (idCategory, extraData);
|
||||
}
|
||||
|
||||
private static (double avgRotorSpeed, double dispersionOfNormalizedRotorSpeed) CalcCriteries(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
{
|
||||
var telemetryRange = telemetry[begin..end];
|
||||
var avgRotorSpeed = telemetryRange.Average(t => t.RotorSpeed);
|
||||
var telemetryRange = telemetry[begin..end];
|
||||
var avgRotorSpeed = telemetryRange.Average(t => t.RotorSpeed);
|
||||
var dispersion = telemetryRange.Average(t => Math.Pow(t.RotorSpeed / avgRotorSpeed - 1, 2));
|
||||
return (avgRotorSpeed, dispersion);
|
||||
}
|
||||
@ -85,10 +84,10 @@ public class DetectorDrilling : DetectorAbstract
|
||||
if (avgRotorSpeed < 5)
|
||||
return WellOperationCategory.IdSlide;
|
||||
|
||||
if (dispersionOfNormalizedRotorSpeed < dispersionOfNormalizedRotorSpeedThreshold)
|
||||
if(dispersionOfNormalizedRotorSpeed < dispersionOfNormalizedRotorSpeedThreshold)
|
||||
return WellOperationCategory.IdRotor;
|
||||
else
|
||||
return idSlideWithOscillation;
|
||||
}
|
||||
|
||||
return idSlideWithOscillation;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
using AsbCloudApp.Data.DetectedOperation;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations;
|
||||
|
||||
public static class EnabledSubsystemsFlagsExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Есть ли флаг подсистемы у операции
|
||||
/// </summary>
|
||||
/// <param name="flags"></param>
|
||||
/// <param name="enabledSubsystems"></param>
|
||||
/// <returns></returns>
|
||||
public static bool HasEnabledSubsystems(this EnabledSubsystemsFlags flags, int enabledSubsystems)
|
||||
=> (enabledSubsystems & (int)flags) > 0;
|
||||
}
|
@ -24,4 +24,4 @@
|
||||
## Метод определения бурения в роторе, слайде с осцилляцией
|
||||
Необходимо рассчитать десперсию нормированных оборотов ротора по(по среднему значению)
|
||||
1. Если полученное значение больше константы(0,2), то мы подтвердили что бурение в роторе.
|
||||
2. Если полученное значение меньше константы, то это бурение в слайде с осцилляцией.
|
||||
2. Если полученное значение меньше константы, и средние обороты ротора больше 1, то это бурение ~~~~в слайде с осцилляцией.
|
@ -35,7 +35,6 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
private readonly BackgroundWorker backgroundWorker;
|
||||
private readonly NotificationService notificationService;
|
||||
|
||||
private const int idNotificationCategory = 20000;
|
||||
private const int idTransportType = 1;
|
||||
|
||||
private const int idFileCategoryDrillingProgram = 1000;
|
||||
@ -377,7 +376,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
await notificationService.NotifyAsync(new NotifyRequest
|
||||
{
|
||||
IdUser = user.Id,
|
||||
IdNotificationCategory = idNotificationCategory,
|
||||
IdNotificationCategory = NotificationCategory.IdSystemNotificationCategory,
|
||||
Title = subject,
|
||||
Message = body,
|
||||
IdTransportType = idTransportType
|
||||
@ -398,7 +397,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
await notificationService.NotifyAsync(new NotifyRequest
|
||||
{
|
||||
IdUser = user.Id,
|
||||
IdNotificationCategory = idNotificationCategory,
|
||||
IdNotificationCategory = NotificationCategory.IdSystemNotificationCategory,
|
||||
Title = subject,
|
||||
Message = body,
|
||||
IdTransportType = idTransportType
|
||||
@ -422,7 +421,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
await notificationService.NotifyAsync(new NotifyRequest
|
||||
{
|
||||
IdUser = user.Id,
|
||||
IdNotificationCategory = idNotificationCategory,
|
||||
IdNotificationCategory = NotificationCategory.IdSystemNotificationCategory,
|
||||
Title = subject,
|
||||
Message = body,
|
||||
IdTransportType = idTransportType
|
||||
@ -442,7 +441,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
await notificationService.NotifyAsync(new NotifyRequest
|
||||
{
|
||||
IdUser = user.Id,
|
||||
IdNotificationCategory = idNotificationCategory,
|
||||
IdNotificationCategory = NotificationCategory.IdSystemNotificationCategory,
|
||||
Title = subject,
|
||||
Message = body,
|
||||
IdTransportType = idTransportType
|
||||
|
@ -1,395 +0,0 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Data.DetectedOperation;
|
||||
using AsbCloudApp.Data.Subsystems;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Requests;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudApp.Services.Subsystems;
|
||||
using AsbCloudDb;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudDb.Model.Subsystems;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.Subsystems;
|
||||
|
||||
/// Todo: Выделить репозиторий
|
||||
internal class SubsystemOperationTimeService : ISubsystemOperationTimeService
|
||||
{
|
||||
private readonly IAsbCloudDbContext db;
|
||||
private readonly IWellService wellService;
|
||||
private readonly ICrudRepository<SubsystemDto> subsystemService;
|
||||
private readonly IDetectedOperationService detectedOperationService;
|
||||
public const int IdSubsystemAKB = 1;
|
||||
public const int IdSubsystemAKBRotor = 11;
|
||||
public const int IdSubsystemAKBSlide = 12;
|
||||
public const int IdSubsystemMSE = 2;
|
||||
public const int IdSubsystemSpin = 65536;
|
||||
public const int IdSubsystemTorque = 65537;
|
||||
|
||||
public SubsystemOperationTimeService(IAsbCloudDbContext db, IWellService wellService, ICrudRepository<SubsystemDto> subsystemService, IDetectedOperationService detectedOperationService)
|
||||
{
|
||||
this.db = db;
|
||||
this.wellService = wellService;
|
||||
this.subsystemService = subsystemService;
|
||||
this.detectedOperationService = detectedOperationService;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<int> DeleteAsync(SubsystemOperationTimeRequest request, CancellationToken token)
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(request.IdWell, token)
|
||||
?? throw new ArgumentInvalidException(nameof(request.IdWell), $"Well Id: {request.IdWell} does not exist");
|
||||
|
||||
var query = BuildQuery(request, well);
|
||||
db.SubsystemOperationTimes.RemoveRange(query);
|
||||
return await db.SaveChangesAsync(token);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<IEnumerable<SubsystemOperationTimeDto>> GetOperationTimeAsync(SubsystemOperationTimeRequest request, CancellationToken token)
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(request.IdWell, token)
|
||||
?? throw new ArgumentInvalidException(nameof(request.IdWell), $"Well Id: {request.IdWell} does not exist");
|
||||
|
||||
var dtos = await GetOperationTimeAsync(request, well, token);
|
||||
return dtos;
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<SubsystemOperationTimeDto>> GetOperationTimeAsync(SubsystemOperationTimeRequest request, WellDto well, CancellationToken token)
|
||||
{
|
||||
var query = BuildQuery(request, well);
|
||||
IEnumerable<SubsystemOperationTime> data = await query.ToListAsync(token);
|
||||
|
||||
if (request.SelectMode == SubsystemOperationTimeRequest.SelectModeInner)
|
||||
{
|
||||
if (request.GtDate is not null)
|
||||
data = data.Where(o => o.DateStart >= request.GtDate.Value);
|
||||
|
||||
if (request.LtDate is not null)
|
||||
data = data.Where(o => o.DateEnd <= request.LtDate.Value);
|
||||
}
|
||||
else if (request.SelectMode == SubsystemOperationTimeRequest.SelectModeTrim)
|
||||
{
|
||||
var begin = request.GtDate?.ToUtcDateTimeOffset(well.Timezone.Hours);
|
||||
var end = request.LtDate?.ToUtcDateTimeOffset(well.Timezone.Hours);
|
||||
data = TrimOperation(data, begin, end);
|
||||
}
|
||||
|
||||
var dtos = data.Select(o => Convert(o, well.Timezone.Hours));
|
||||
return dtos;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<IEnumerable<SubsystemStatDto>> GetStatAsync(SubsystemOperationTimeRequest request, CancellationToken token)
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(request.IdWell, token)
|
||||
?? throw new ArgumentInvalidException(nameof(request.IdWell), $"Well Id: {request.IdWell} does not exist");
|
||||
|
||||
request.SelectMode = SubsystemOperationTimeRequest.SelectModeTrim;
|
||||
var subsystemsTimes = await GetOperationTimeAsync(request, well, token);
|
||||
if (subsystemsTimes is null)
|
||||
return Enumerable.Empty<SubsystemStatDto>();
|
||||
|
||||
var detectedOperationSummaryRequest = new DetectedOperationSummaryRequest()
|
||||
{
|
||||
IdsTelemetries = new[] {well.IdTelemetry!.Value},
|
||||
IdsOperationCategories = WellOperationCategory.MechanicalDrillingSubIds,
|
||||
|
||||
GeDateStart = request.GtDate,
|
||||
LeDateStart = request.LtDate,
|
||||
|
||||
GeDepthStart = request.GtDepth,
|
||||
LeDepthStart = request.LtDepth,
|
||||
};
|
||||
var operationsSummaries = await detectedOperationService.GetOperationSummaryAsync(detectedOperationSummaryRequest, token);
|
||||
if(!operationsSummaries.Any())
|
||||
return Enumerable.Empty<SubsystemStatDto>();
|
||||
|
||||
var statList = CalcStat(subsystemsTimes, operationsSummaries);
|
||||
return statList;
|
||||
}
|
||||
|
||||
private static IEnumerable<SubsystemOperationTime> TrimOperation(IEnumerable<SubsystemOperationTime> data, DateTimeOffset? gtDate, DateTimeOffset? ltDate)
|
||||
{
|
||||
if (!ltDate.HasValue && !gtDate.HasValue)
|
||||
return data.Select(d => d.Adapt<SubsystemOperationTime>());
|
||||
|
||||
var items = data.Select((item) =>
|
||||
{
|
||||
var operationTime = item.Adapt<SubsystemOperationTime>();
|
||||
if (!(item.DepthStart.HasValue && item.DepthEnd.HasValue))
|
||||
return operationTime;
|
||||
|
||||
var dateDiff = (item.DateEnd - item.DateStart).TotalSeconds;
|
||||
var depthDiff = item.DepthEnd.Value - item.DepthStart.Value;
|
||||
var a = depthDiff / dateDiff;
|
||||
var b = item.DepthStart.Value;
|
||||
|
||||
if (gtDate.HasValue && item.DateStart < gtDate.Value)
|
||||
{
|
||||
operationTime.DateStart = gtDate.Value;
|
||||
var x = (gtDate.Value - item.DateStart).TotalSeconds;
|
||||
operationTime.DepthStart = (float)(a * x + b);
|
||||
}
|
||||
if (ltDate.HasValue && item.DateEnd > ltDate.Value)
|
||||
{
|
||||
operationTime.DateEnd = ltDate.Value;
|
||||
var x = (ltDate.Value - item.DateStart).TotalSeconds;
|
||||
operationTime.DepthEnd = (float)(a * x + b);
|
||||
}
|
||||
return operationTime;
|
||||
});
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private IEnumerable<SubsystemStatDto> CalcStat(
|
||||
IEnumerable<SubsystemOperationTimeDto> subsystemsTimes,
|
||||
IEnumerable<OperationsSummaryDto> operationsSummaries)
|
||||
{
|
||||
var groupedSubsystemsTimes = subsystemsTimes
|
||||
.OrderBy(o => o.Id)
|
||||
.GroupBy(o => o.IdSubsystem);
|
||||
|
||||
var periodGroupTotal = subsystemsTimes.Sum(o => (o.DateEnd - o.DateStart).TotalHours);
|
||||
|
||||
var result = groupedSubsystemsTimes.Select(g =>
|
||||
{
|
||||
var periodGroup = g.Sum(o => (o.DateEnd - o.DateStart).TotalHours);
|
||||
var periodGroupDepth = g.Sum(o => o.DepthEnd - o.DepthStart);
|
||||
var (sumOprationsDepth, sumOprationsDurationHours) = AggregateOperationsSummaries(g.Key, operationsSummaries);
|
||||
var subsystemStat = new SubsystemStatDto()
|
||||
{
|
||||
IdSubsystem = g.Key,
|
||||
SubsystemName = subsystemService.GetOrDefault(g.Key)?.Name ?? "unknown",
|
||||
UsedTimeHours = periodGroup,
|
||||
SumOperationDepthInterval = sumOprationsDepth,
|
||||
SumOperationDurationHours = sumOprationsDurationHours,
|
||||
SumDepthInterval = periodGroupDepth,
|
||||
KUsage = periodGroupDepth / sumOprationsDepth,
|
||||
OperationCount = g.Count(),
|
||||
};
|
||||
if (subsystemStat.KUsage > 1)
|
||||
subsystemStat.KUsage = 1;
|
||||
return subsystemStat;
|
||||
});
|
||||
|
||||
var apdParts = result.Where(x => x.IdSubsystem == 11 || x.IdSubsystem == 12);
|
||||
if (apdParts.Any())
|
||||
{
|
||||
var apdSum = new SubsystemStatDto()
|
||||
{
|
||||
IdSubsystem = IdSubsystemAKB,
|
||||
SubsystemName = "АПД",
|
||||
UsedTimeHours = apdParts.Sum(part => part.UsedTimeHours),
|
||||
SumOperationDepthInterval = apdParts.Sum(part => part.SumOperationDepthInterval),
|
||||
SumOperationDurationHours = apdParts.Sum(part => part.SumOperationDurationHours),
|
||||
SumDepthInterval = apdParts.Sum(part => part.SumDepthInterval),
|
||||
OperationCount = apdParts.Sum(part => part.OperationCount),
|
||||
};
|
||||
apdSum.KUsage = apdSum.SumDepthInterval / apdSum.SumOperationDepthInterval;
|
||||
if (apdSum.KUsage > 1)
|
||||
apdSum.KUsage = 1;
|
||||
result = result.Append(apdSum).OrderBy(m => m.IdSubsystem);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static (double SumDepth, double SumDurationHours) AggregateOperationsSummaries(int idSubsystem, IEnumerable<OperationsSummaryDto> operationsSummaries)
|
||||
=> idSubsystem switch
|
||||
{
|
||||
IdSubsystemAKBRotor or IdSubsystemTorque => CalcOperationSummariesByCategories(operationsSummaries, WellOperationCategory.IdRotor),
|
||||
IdSubsystemAKBSlide or IdSubsystemSpin => CalcOperationSummariesByCategories(operationsSummaries, WellOperationCategory.IdSlide),
|
||||
IdSubsystemAKB or IdSubsystemMSE => CalcOperationSummariesByCategories(operationsSummaries, WellOperationCategory.IdRotor, WellOperationCategory.IdSlide),
|
||||
_ => throw new ArgumentException($"idSubsystem: {idSubsystem} does not supported in this method", nameof(idSubsystem)),
|
||||
};
|
||||
|
||||
private static (double SumDepth, double SumDurationHours) CalcOperationSummariesByCategories(
|
||||
IEnumerable<OperationsSummaryDto> operationsSummaries,
|
||||
params int[] idsOperationCategories)
|
||||
{
|
||||
var filtered = operationsSummaries.Where(sum => idsOperationCategories.Contains(sum.IdCategory));
|
||||
var sumDepth = filtered.Sum(summ => summ.SumDepthIntervals);
|
||||
var sumDurationHours = filtered.Sum(summ => summ.SumDurationHours);
|
||||
return (sumDepth, sumDurationHours);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(int idCompany, DateTime? gtDate, DateTime? ltDate, CancellationToken token)
|
||||
{
|
||||
var activeWells = await wellService.GetAsync(new() { IdCompany = idCompany, IdState = 1 }, token);
|
||||
var result = await GetStatAsync(activeWells, gtDate, ltDate, token);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(IEnumerable<int> wellIds, CancellationToken token)
|
||||
{
|
||||
var activeWells = await wellService.GetAsync(new() { Ids = wellIds, IdState = 1 }, token);
|
||||
var result = await GetStatAsync(activeWells, null, null, token);
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatAsync(IEnumerable<WellDto> wells, DateTime? gtDate, DateTime? ltDate, CancellationToken token)
|
||||
{
|
||||
if (!wells.Any())
|
||||
return Enumerable.Empty<SubsystemActiveWellStatDto>();
|
||||
|
||||
var hoursOffset = wells
|
||||
.FirstOrDefault(well => well.Timezone is not null)
|
||||
?.Timezone.Hours
|
||||
?? 5d;
|
||||
|
||||
var beginUTC = gtDate.HasValue
|
||||
? gtDate.Value.ToUtcDateTimeOffset(hoursOffset)
|
||||
: db.SubsystemOperationTimes.Min(s => s.DateStart)
|
||||
.DateTime
|
||||
.ToUtcDateTimeOffset(hoursOffset);
|
||||
|
||||
var endUTC = ltDate.HasValue
|
||||
? ltDate.Value.ToUtcDateTimeOffset(hoursOffset)
|
||||
: db.SubsystemOperationTimes.Max(s => s.DateEnd)
|
||||
.DateTime
|
||||
.ToUtcDateTimeOffset(hoursOffset);
|
||||
|
||||
IEnumerable<int> idsTelemetries = wells
|
||||
.Where(w => w.IdTelemetry is not null)
|
||||
.Select(w => w.IdTelemetry!.Value)
|
||||
.Distinct();
|
||||
|
||||
var query = db.SubsystemOperationTimes
|
||||
.Where(o => idsTelemetries.Contains(o.IdTelemetry) &&
|
||||
o.DateStart >= beginUTC &&
|
||||
o.DateEnd <= endUTC)
|
||||
.AsNoTracking();
|
||||
|
||||
var subsystemsOperationTime = await query.ToArrayAsync(token);
|
||||
|
||||
var operationSummaries = await detectedOperationService
|
||||
.GetOperationSummaryAsync(new ()
|
||||
{
|
||||
IdsTelemetries = idsTelemetries,
|
||||
IdsOperationCategories = WellOperationCategory.MechanicalDrillingSubIds,
|
||||
GeDateStart = beginUTC,
|
||||
LeDateEnd = endUTC,
|
||||
}, token);
|
||||
|
||||
var result = wells
|
||||
.Select(well => {
|
||||
var dtos = subsystemsOperationTime
|
||||
.Where(s => s.IdTelemetry == well.IdTelemetry)
|
||||
.Select(s => Convert(s, well.Timezone.Hours));
|
||||
|
||||
var wellStat = new SubsystemActiveWellStatDto{ Well = well };
|
||||
|
||||
var telemetryOperationSummaries = operationSummaries.Where(summ => summ.IdTelemetry == well.IdTelemetry);
|
||||
if (telemetryOperationSummaries.Any())
|
||||
{
|
||||
var subsystemStat = CalcStat(dtos, telemetryOperationSummaries);
|
||||
if (subsystemStat.Any())
|
||||
{
|
||||
wellStat.SubsystemAKB = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemAKB);
|
||||
wellStat.SubsystemMSE = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemMSE);
|
||||
wellStat.SubsystemSpinMaster = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemSpin);
|
||||
wellStat.SubsystemTorqueMaster = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemTorque);
|
||||
}
|
||||
}
|
||||
|
||||
return wellStat;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<DatesRangeDto?> GetDateRangeOperationTimeAsync(SubsystemOperationTimeRequest request, CancellationToken token)
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(request.IdWell, token)
|
||||
?? throw new ArgumentInvalidException(nameof(request.IdWell), $"Well Id: {request.IdWell} does not exist");
|
||||
|
||||
var query = BuildQuery(request, well);
|
||||
if (query is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var result = await query
|
||||
.GroupBy(o => o.IdTelemetry)
|
||||
.Select(g => new DatesRangeDto
|
||||
{
|
||||
From = g.Min(o => o.DateStart).DateTime,
|
||||
To = g.Max(o => o.DateEnd).DateTime
|
||||
})
|
||||
.FirstOrDefaultAsync(token);
|
||||
return result;
|
||||
}
|
||||
|
||||
private IQueryable<SubsystemOperationTime> BuildQuery(SubsystemOperationTimeRequest request, WellDto well)
|
||||
{
|
||||
var idTelemetry = well.IdTelemetry
|
||||
?? throw new ArgumentInvalidException(nameof(request.IdWell), $"Well Id: {request.IdWell} has no telemetry");
|
||||
|
||||
var query = db.SubsystemOperationTimes
|
||||
.Include(o => o.Subsystem)
|
||||
.Where(o => o.IdTelemetry == idTelemetry)
|
||||
.AsNoTracking();
|
||||
|
||||
if (request.IdsSubsystems.Any())
|
||||
query = query.Where(o => request.IdsSubsystems.Contains(o.IdSubsystem));
|
||||
|
||||
// # Dates range condition
|
||||
// [GtDate LtDate]
|
||||
// [DateStart DateEnd] [DateStart DateEnd]
|
||||
if (request.GtDate.HasValue)
|
||||
{
|
||||
DateTimeOffset gtDate = request.GtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours);
|
||||
query = query.Where(o => o.DateEnd >= gtDate);
|
||||
}
|
||||
|
||||
if (request.LtDate.HasValue)
|
||||
{
|
||||
DateTimeOffset ltDate = request.LtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours);
|
||||
query = query.Where(o => o.DateStart <= ltDate);
|
||||
}
|
||||
|
||||
if (request.GtDepth.HasValue)
|
||||
query = query.Where(o => o.DepthEnd >= request.GtDepth.Value);
|
||||
|
||||
if (request.LtDepth.HasValue)
|
||||
query = query.Where(o => o.DepthStart <= request.LtDepth.Value);
|
||||
|
||||
if (request?.SortFields?.Any() == true)
|
||||
{
|
||||
query = query.SortBy(request.SortFields);
|
||||
}
|
||||
else
|
||||
{
|
||||
query = query
|
||||
.OrderBy(o => o.DateStart)
|
||||
.ThenBy(o => o.DepthStart);
|
||||
}
|
||||
|
||||
if (request?.Skip > 0)
|
||||
query = query.Skip((int)request.Skip);
|
||||
|
||||
if (request?.Take > 0)
|
||||
query = query.Take((int)request.Take);
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
private static SubsystemOperationTimeDto Convert(SubsystemOperationTime operationTime, double? timezoneHours = null)
|
||||
{
|
||||
var dto = operationTime.Adapt<SubsystemOperationTimeDto>();
|
||||
var hours = timezoneHours ?? operationTime.Telemetry.TimeZone.Hours;
|
||||
dto.DateStart = operationTime.DateStart.ToRemoteDateTime(hours);
|
||||
dto.DateEnd = operationTime.DateEnd.ToRemoteDateTime(hours);
|
||||
return dto;
|
||||
}
|
||||
}
|
257
AsbCloudInfrastructure/Services/Subsystems/SubsystemService.cs
Normal file
257
AsbCloudInfrastructure/Services/Subsystems/SubsystemService.cs
Normal file
@ -0,0 +1,257 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Data.DetectedOperation;
|
||||
using AsbCloudApp.Data.Subsystems;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Requests;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudInfrastructure.Services.DetectOperations;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.Subsystems;
|
||||
|
||||
internal class SubsystemService : ISubsystemService
|
||||
{
|
||||
private const int IdSubsystemAPD = 1;
|
||||
private const int IdSubsystemAPDRotor = 11;
|
||||
private const int IdSubsystemAPDSlide = 12;
|
||||
private const int IdSubsystemOscillation = 65536;
|
||||
|
||||
private readonly ICrudRepository<SubsystemDto> subsystemRepository;
|
||||
|
||||
private readonly IWellService wellService;
|
||||
private readonly IDetectedOperationService detectedOperationService;
|
||||
private readonly ITelemetryDataSaubService telemetryDataSaubService;
|
||||
|
||||
private IDictionary<int, SubsystemDto> subsystems = new Dictionary<int, SubsystemDto>();
|
||||
|
||||
public SubsystemService(ICrudRepository<SubsystemDto> subsystemRepository,
|
||||
IWellService wellService,
|
||||
IDetectedOperationService detectedOperationService,
|
||||
ITelemetryDataSaubService telemetryDataSaubService)
|
||||
{
|
||||
this.wellService = wellService;
|
||||
this.subsystemRepository = subsystemRepository;
|
||||
this.detectedOperationService = detectedOperationService;
|
||||
this.telemetryDataSaubService = telemetryDataSaubService;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SubsystemStatDto>> GetStatAsync(SubsystemRequest request, CancellationToken token)
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync(request.IdWell, token)
|
||||
?? throw new ArgumentInvalidException(nameof(request.IdWell), $"Well Id: {request.IdWell} does not exist");
|
||||
|
||||
var detectedOperationSummaryRequest = new DetectedOperationRequest
|
||||
{
|
||||
IdWell = request.IdWell,
|
||||
IdsTelemetries = new[] { well.IdTelemetry!.Value },
|
||||
IdsCategories = WellOperationCategory.MechanicalDrillingSubIds,
|
||||
|
||||
GeDateStart = request.GeDate,
|
||||
LeDateEnd = request.LeDate,
|
||||
|
||||
GeDepth = request.GeDepth,
|
||||
LeDepth = request.LeDepth,
|
||||
};
|
||||
|
||||
var operations = await detectedOperationService.GetOperationsAsync(detectedOperationSummaryRequest,
|
||||
token);
|
||||
|
||||
if (request.IdDriller.HasValue)
|
||||
operations = operations.Where(o => o.Driller is not null && o.Driller.Id == request.IdDriller.Value);
|
||||
|
||||
if (!operations.Any())
|
||||
return Enumerable.Empty<SubsystemStatDto>();
|
||||
|
||||
var stat = await CalcStatAsync(operations, token);
|
||||
return stat;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(int idCompany,
|
||||
DateTime? gtDate,
|
||||
DateTime? ltDate,
|
||||
CancellationToken token)
|
||||
{
|
||||
var activeWells = await wellService.GetAsync(new() { IdCompany = idCompany, IdState = 1 }, token);
|
||||
var result = await GetStatAsync(activeWells, gtDate, ltDate, token);
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatByActiveWells(IEnumerable<int> wellIds, CancellationToken token)
|
||||
{
|
||||
var activeWells = await wellService.GetAsync(new() { Ids = wellIds, IdState = 1 }, token);
|
||||
var result = await GetStatAsync(activeWells, null, null, token);
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<SubsystemStatDto>> CalcStatAsync(IEnumerable<DetectedOperationDto> operations, CancellationToken token)
|
||||
{
|
||||
if (!subsystems.Any())
|
||||
subsystems = (await subsystemRepository.GetAllAsync(token)).ToDictionary(s => s.Id, s => s);
|
||||
|
||||
var oscillationStat = CalcOscillationStat(operations);
|
||||
var apdStat = CalcApdStat(operations);
|
||||
|
||||
var stat = new List<SubsystemStatDto> { oscillationStat };
|
||||
stat.AddRange(apdStat);
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
private SubsystemStatDto CalcOscillationStat(IEnumerable<DetectedOperationDto> operations)
|
||||
{
|
||||
operations = operations.Where(o => o.IdCategory == WellOperationCategory.IdSlide);
|
||||
|
||||
var (sumDepthInterval, usedTimeHours, operationCount) = AggregateOperations(IdSubsystemOscillation, operations);
|
||||
|
||||
var oscillationStat = new SubsystemStatDto
|
||||
{
|
||||
IdSubsystem = IdSubsystemOscillation,
|
||||
SubsystemName = subsystems.TryGetValue(IdSubsystemOscillation, out var subsystemDto) ? subsystemDto.Name : "unknown",
|
||||
UsedTimeHours = usedTimeHours,
|
||||
SumOperationDepthInterval = operations.Sum(o => o.DepthEnd - o.DepthStart),
|
||||
SumOperationDurationHours = operations.Sum(o => o.DurationMinutes / 60),
|
||||
SumDepthInterval = sumDepthInterval,
|
||||
OperationCount = operationCount,
|
||||
};
|
||||
|
||||
oscillationStat.KUsage = oscillationStat.SumDepthInterval / oscillationStat.SumOperationDepthInterval;
|
||||
|
||||
return oscillationStat;
|
||||
}
|
||||
|
||||
private IEnumerable<SubsystemStatDto> CalcApdStat(IEnumerable<DetectedOperationDto> operations)
|
||||
{
|
||||
var apdRotorAndSlide = operations
|
||||
.Where(o => WellOperationCategory.MechanicalDrillingSubIds.Contains(o.IdCategory))
|
||||
.GroupBy(o => o.IdCategory)
|
||||
.Select(group =>
|
||||
{
|
||||
var idSubsystem = group.Key switch
|
||||
{
|
||||
WellOperationCategory.IdRotor => IdSubsystemAPDRotor,
|
||||
WellOperationCategory.IdSlide => IdSubsystemAPDSlide,
|
||||
_ => throw new ArgumentException($"IdCategory: {group.Key} does not supported in this method", nameof(group.Key))
|
||||
};
|
||||
|
||||
var (sumDepthInterval, usedTimeHours, operationCount) = AggregateOperations(idSubsystem, group);
|
||||
|
||||
var subsystemStat = new SubsystemStatDto
|
||||
{
|
||||
IdSubsystem = idSubsystem,
|
||||
SubsystemName = subsystems.TryGetValue(idSubsystem, out var subsystemDto) ? subsystemDto.Name : "unknown",
|
||||
UsedTimeHours = usedTimeHours,
|
||||
SumOperationDepthInterval = group.Sum(o => o.DepthEnd - o.DepthStart),
|
||||
SumOperationDurationHours = group.Sum(o => o.DurationMinutes / 60),
|
||||
SumDepthInterval = sumDepthInterval,
|
||||
OperationCount = operationCount,
|
||||
};
|
||||
|
||||
subsystemStat.KUsage = subsystemStat.SumDepthInterval / subsystemStat.SumOperationDepthInterval;
|
||||
|
||||
return subsystemStat;
|
||||
});
|
||||
|
||||
if (!apdRotorAndSlide.Any())
|
||||
return Enumerable.Empty<SubsystemStatDto>();
|
||||
|
||||
var apdSum = new SubsystemStatDto
|
||||
{
|
||||
IdSubsystem = IdSubsystemAPD,
|
||||
SubsystemName = subsystems.TryGetValue(IdSubsystemAPD, out var subsystemDto) ? subsystemDto.Name : "unknown",
|
||||
UsedTimeHours = apdRotorAndSlide.Sum(part => part.UsedTimeHours),
|
||||
SumOperationDepthInterval = apdRotorAndSlide.Sum(part => part.SumOperationDepthInterval),
|
||||
SumOperationDurationHours = apdRotorAndSlide.Sum(part => part.SumOperationDurationHours),
|
||||
SumDepthInterval = apdRotorAndSlide.Sum(part => part.SumDepthInterval),
|
||||
OperationCount = apdRotorAndSlide.Sum(part => part.OperationCount),
|
||||
};
|
||||
|
||||
apdSum.KUsage = apdSum.SumDepthInterval / apdSum.SumOperationDepthInterval;
|
||||
|
||||
var apdStat = new List<SubsystemStatDto> { apdSum };
|
||||
apdStat.AddRange(apdRotorAndSlide);
|
||||
|
||||
return apdStat;
|
||||
}
|
||||
|
||||
private static (double SumDepthInterval, double UsedTimeHours, int Count) AggregateOperations(int idSubsystem,
|
||||
IEnumerable<DetectedOperationDto> operations) =>
|
||||
idSubsystem switch
|
||||
{
|
||||
IdSubsystemAPDRotor => CalcOperationsByEnableSubsystems(operations, EnabledSubsystemsFlags.AutoRotor),
|
||||
IdSubsystemAPDSlide => CalcOperationsByEnableSubsystems(operations,
|
||||
EnabledSubsystemsFlags.AutoSlide | EnabledSubsystemsFlags.AutoOscillation),
|
||||
IdSubsystemOscillation => CalcOperationsByEnableSubsystems(operations, EnabledSubsystemsFlags.AutoOscillation),
|
||||
_ => throw new ArgumentException($"IdSubsystem: {idSubsystem} does not supported in this method", nameof(idSubsystem))
|
||||
};
|
||||
|
||||
private static (double SumDepthInterval, double UsedTimeHours, int OperationCount) CalcOperationsByEnableSubsystems(
|
||||
IEnumerable<DetectedOperationDto> operations,
|
||||
EnabledSubsystemsFlags enabledSubsystems)
|
||||
{
|
||||
var filtered = operations.Where(o => enabledSubsystems.HasEnabledSubsystems(o.EnabledSubsystems));
|
||||
|
||||
var sumDepthInterval = filtered.Sum(o => o.DepthEnd - o.DepthStart);
|
||||
var usedTimeHours = filtered.Sum(o => o.DurationMinutes / 60);
|
||||
var operationCount = filtered.Count();
|
||||
|
||||
return (sumDepthInterval, usedTimeHours, operationCount);
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<SubsystemActiveWellStatDto>> GetStatAsync(IEnumerable<WellDto> wells,
|
||||
DateTime? geDate,
|
||||
DateTime? leDate,
|
||||
CancellationToken token)
|
||||
{
|
||||
if (!wells.Any())
|
||||
return Enumerable.Empty<SubsystemActiveWellStatDto>();
|
||||
|
||||
var idsTelemetries = wells
|
||||
.Where(w => w.IdTelemetry is not null)
|
||||
.Select(w => w.IdTelemetry!.Value)
|
||||
.Distinct();
|
||||
|
||||
var wellsStat = new List<SubsystemActiveWellStatDto>();
|
||||
|
||||
foreach (var well in wells)
|
||||
{
|
||||
var hoursOffset = well.Timezone.Hours;
|
||||
|
||||
var geDateStartUtc = geDate?.ToUtcDateTimeOffset(hoursOffset);
|
||||
|
||||
var leDateUtc = leDate?.ToUtcDateTimeOffset(hoursOffset);
|
||||
|
||||
var request = new DetectedOperationRequest
|
||||
{
|
||||
IdsTelemetries = idsTelemetries,
|
||||
IdsCategories = WellOperationCategory.MechanicalDrillingSubIds,
|
||||
GeDateStart = geDateStartUtc,
|
||||
LeDateEnd = leDateUtc,
|
||||
};
|
||||
|
||||
var operations = await detectedOperationService
|
||||
.GetOperationsAsync(request, token);
|
||||
|
||||
var wellStat = new SubsystemActiveWellStatDto { Well = well };
|
||||
|
||||
var telemetryOperations = operations.Where(o => o.IdTelemetry == well.IdTelemetry);
|
||||
|
||||
if (!telemetryOperations.Any())
|
||||
continue;
|
||||
|
||||
var subsystemStat = await CalcStatAsync(telemetryOperations, token);
|
||||
|
||||
if (!subsystemStat.Any())
|
||||
continue;
|
||||
|
||||
wellStat.SubsystemAPD = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemAPD);
|
||||
wellStat.SubsystemOscillation = subsystemStat.FirstOrDefault(s => s.IdSubsystem == IdSubsystemOscillation);
|
||||
}
|
||||
|
||||
return wellsStat;
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
using AsbCloudDb.Model.Subsystems;
|
||||
using System;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.Subsystems
|
||||
{
|
||||
public class SubsystemDetector
|
||||
{
|
||||
private readonly int idTelemetry;
|
||||
private readonly int idSubsystem;
|
||||
private readonly Func<short?, bool> isEnable;
|
||||
private readonly Func<SubsystemOperationTime, bool> isValid;
|
||||
(bool isEnable, DateTimeOffset date, float depth) pre = default;
|
||||
|
||||
public SubsystemDetector(
|
||||
int idTelemetry,
|
||||
int idSubsystem,
|
||||
Func<short?, bool> isEnable,
|
||||
Func<SubsystemOperationTime, bool> isValid)
|
||||
{
|
||||
this.idTelemetry = idTelemetry;
|
||||
this.idSubsystem = idSubsystem;
|
||||
this.isEnable = isEnable;
|
||||
this.isValid = isValid;
|
||||
}
|
||||
|
||||
public bool TryDetect(short? mode, DateTimeOffset date, float depth, out SubsystemOperationTime? subsystemOperationTime)
|
||||
{
|
||||
var isEnable = this.isEnable(mode);
|
||||
|
||||
if (!pre.isEnable && isEnable)
|
||||
{
|
||||
pre = (true, date, depth);
|
||||
}
|
||||
else if (pre.isEnable && !isEnable)
|
||||
{
|
||||
var detected = new SubsystemOperationTime
|
||||
{
|
||||
IdTelemetry = idTelemetry,
|
||||
IdSubsystem = idSubsystem,
|
||||
DateStart = pre.date,
|
||||
DateEnd = date,
|
||||
DepthStart = pre.depth,
|
||||
DepthEnd = depth,
|
||||
};
|
||||
pre.isEnable = false;
|
||||
if (isValid(detected))
|
||||
{
|
||||
subsystemOperationTime = detected;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
subsystemOperationTime = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Services.Notifications;
|
||||
using AsbCloudDb.Model;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services
|
||||
{
|
||||
@ -136,7 +137,6 @@ namespace AsbCloudInfrastructure.Services
|
||||
private async Task SendMessageAsync(WellDto well, UserDto user, string documentCategory, string message,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
const int idNotificationCategory = 20000;
|
||||
const int idTransportType = 1;
|
||||
|
||||
var factory = new WellFinalDocumentMailBodyFactory(configuration);
|
||||
@ -151,7 +151,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
await notificationService.NotifyAsync(new NotifyRequest
|
||||
{
|
||||
IdUser = user.Id,
|
||||
IdNotificationCategory = idNotificationCategory,
|
||||
IdNotificationCategory = NotificationCategory.IdSystemNotificationCategory,
|
||||
Title = subject,
|
||||
Message = body,
|
||||
IdTransportType = idTransportType
|
||||
|
@ -4,9 +4,7 @@ using AsbCloudApp.Data.WITS;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Requests;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudApp.Services.Subsystems;
|
||||
using AsbCloudInfrastructure.Background;
|
||||
using AsbCloudInfrastructure.Services.SAUB;
|
||||
using Mapster;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
@ -35,7 +33,7 @@ public class WellInfoService
|
||||
var wellService = services.GetRequiredService<IWellService>();
|
||||
var operationsStatService = services.GetRequiredService<IOperationsStatService>();
|
||||
var processMapPlanWellDrillingRepository = services.GetRequiredService<IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto>>();
|
||||
var subsystemOperationTimeService = services.GetRequiredService<ISubsystemOperationTimeService>();
|
||||
var subsystemService = services.GetRequiredService<ISubsystemService>();
|
||||
var telemetryDataSaubCache = services.GetRequiredService<ITelemetryDataCache<TelemetryDataSaubDto>>();
|
||||
var messageHub = services.GetRequiredService<IIntegrationEventHandler<UpdateWellInfoEvent>>();
|
||||
|
||||
@ -57,7 +55,7 @@ public class WellInfoService
|
||||
|
||||
var operationsStat = await operationsStatService.GetWellsStatAsync(wellsIds, token);
|
||||
|
||||
var subsystemStat = await subsystemOperationTimeService
|
||||
var subsystemStat = await subsystemService
|
||||
.GetStatByActiveWells(wellsIds, token);
|
||||
subsystemStat = subsystemStat.ToArray();
|
||||
|
||||
@ -157,8 +155,8 @@ public class WellInfoService
|
||||
};
|
||||
|
||||
var wellSubsystemStat = subsystemStat.FirstOrDefault(s => s.Well.Id == well.Id);
|
||||
wellMapInfo.SaubUsage = wellSubsystemStat?.SubsystemAKB?.KUsage ?? 0d;
|
||||
wellMapInfo.SpinUsage = wellSubsystemStat?.SubsystemSpinMaster?.KUsage ?? 0d;
|
||||
wellMapInfo.SaubUsage = wellSubsystemStat?.SubsystemAPD?.KUsage ?? 0d;
|
||||
wellMapInfo.SpinUsage = wellSubsystemStat?.SubsystemOscillation?.KUsage ?? 0d;
|
||||
wellMapInfo.TorqueKUsage = wellSubsystemStat?.SubsystemTorqueMaster?.KUsage ?? 0d;
|
||||
wellMapInfo.TvdLagDays = wellOperationsStat?.TvdLagDays;
|
||||
wellMapInfo.TvdDrillingDays = wellOperationsStat?.TvdDrillingDays;
|
||||
|
@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@ -36,17 +35,15 @@ public class WellOperationExportService : IWellOperationExportService
|
||||
IdWell = idWell
|
||||
}, cancellationToken);
|
||||
|
||||
var timezone = wellService.GetTimezone(idWell);
|
||||
|
||||
return MakeExcelFileStream(operations, timezone.Hours);
|
||||
return MakeExcelFileStream(operations);
|
||||
}
|
||||
|
||||
private Stream MakeExcelFileStream(IEnumerable<WellOperationDto> operations, double timezoneOffset)
|
||||
private Stream MakeExcelFileStream(IEnumerable<WellOperationDto> operations)
|
||||
{
|
||||
using Stream ecxelTemplateStream = wellOperationImportTemplateService.GetExcelTemplateStream();
|
||||
|
||||
using var workbook = new XLWorkbook(ecxelTemplateStream, XLEventTracking.Disabled);
|
||||
AddOperationsToWorkbook(workbook, operations, timezoneOffset);
|
||||
AddOperationsToWorkbook(workbook, operations);
|
||||
|
||||
var memoryStream = new MemoryStream();
|
||||
workbook.SaveAs(memoryStream, new SaveOptions { });
|
||||
@ -54,14 +51,14 @@ public class WellOperationExportService : IWellOperationExportService
|
||||
return memoryStream;
|
||||
}
|
||||
|
||||
private void AddOperationsToWorkbook(XLWorkbook workbook, IEnumerable<WellOperationDto> operations, double timezoneOffset)
|
||||
private void AddOperationsToWorkbook(XLWorkbook workbook, IEnumerable<WellOperationDto> operations)
|
||||
{
|
||||
var planOperations = operations.Where(o => o.IdType == 0);
|
||||
if (planOperations.Any())
|
||||
{
|
||||
var sheetPlan = workbook.Worksheets.FirstOrDefault(ws => ws.Name == DefaultTemplateInfo.SheetNamePlan);
|
||||
if (sheetPlan is not null)
|
||||
AddOperationsToSheet(sheetPlan, planOperations, timezoneOffset);
|
||||
AddOperationsToSheet(sheetPlan, planOperations);
|
||||
}
|
||||
|
||||
var factOperations = operations.Where(o => o.IdType == 1);
|
||||
@ -69,11 +66,11 @@ public class WellOperationExportService : IWellOperationExportService
|
||||
{
|
||||
var sheetFact = workbook.Worksheets.FirstOrDefault(ws => ws.Name == DefaultTemplateInfo.SheetNameFact);
|
||||
if (sheetFact is not null)
|
||||
AddOperationsToSheet(sheetFact, factOperations, timezoneOffset);
|
||||
AddOperationsToSheet(sheetFact, factOperations);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddOperationsToSheet(IXLWorksheet sheet, IEnumerable<WellOperationDto> operations, double timezoneOffset)
|
||||
private void AddOperationsToSheet(IXLWorksheet sheet, IEnumerable<WellOperationDto> operations)
|
||||
{
|
||||
var operationsToArray = operations.ToArray();
|
||||
|
||||
@ -83,19 +80,19 @@ public class WellOperationExportService : IWellOperationExportService
|
||||
for (int i = 0; i < operationsToArray.Length; i++)
|
||||
{
|
||||
var row = sheet.Row(1 + i + DefaultTemplateInfo.HeaderRowsCount);
|
||||
AddOperationToRow(row, operationsToArray[i], sections, categories, timezoneOffset);
|
||||
AddOperationToRow(row, operationsToArray[i], sections, categories);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddOperationToRow(IXLRow row, WellOperationDto operation, IEnumerable<WellSectionTypeDto> sections,
|
||||
IEnumerable<WellOperationCategoryDto> categories, double timezoneOffset)
|
||||
IEnumerable<WellOperationCategoryDto> categories)
|
||||
{
|
||||
row.Cell(DefaultTemplateInfo.ColumnSection).Value = sections.First(s => s.Id == operation.IdWellSectionType).Caption;
|
||||
row.Cell(DefaultTemplateInfo.ColumnCategory).Value = categories.First(o => o.Id == operation.IdCategory).Name;
|
||||
row.Cell(DefaultTemplateInfo.ColumnCategoryInfo).Value = operation.CategoryInfo;
|
||||
row.Cell(DefaultTemplateInfo.ColumnDepthStart).Value = operation.DepthStart;
|
||||
row.Cell(DefaultTemplateInfo.ColumnDepthEnd).Value = operation.DepthEnd;
|
||||
row.Cell(DefaultTemplateInfo.ColumnDate).Value = new DateTimeOffset(operation.DateStart).ToRemoteDateTime(timezoneOffset);
|
||||
row.Cell(DefaultTemplateInfo.ColumnDate).Value = operation.DateStart;
|
||||
row.Cell(DefaultTemplateInfo.ColumnDuration).Value = operation.DurationHours;
|
||||
row.Cell(DefaultTemplateInfo.ColumnComment).Value = operation.Comment;
|
||||
}
|
||||
|
@ -32,8 +32,6 @@ namespace AsbCloudInfrastructure
|
||||
backgroundWorker.Add<WorkToDeleteOldReports>(TimeSpan.FromDays(1));
|
||||
backgroundWorker.Add<WellInfoService.WorkWellInfoUpdate>(TimeSpan.FromMinutes(30));
|
||||
backgroundWorker.Add<WorkOperationDetection>(TimeSpan.FromMinutes(15));
|
||||
backgroundWorker.Add<WorkSubsystemAbfOperationTimeCalc>(TimeSpan.FromMinutes(30));
|
||||
backgroundWorker.Add<WorkSubsystemOscillationOperationTimeCalc>(TimeSpan.FromMinutes(30));
|
||||
backgroundWorker.Add<WorkLimitingParameterCalc>(TimeSpan.FromMinutes(30));
|
||||
backgroundWorker.Add(MakeMemoryMonitoringWork(), TimeSpan.FromMinutes(1));
|
||||
|
||||
|
@ -17,7 +17,6 @@ using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Requests;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudApp.Services.ProcessMaps.WellDrilling;
|
||||
using AsbCloudApp.Services.Subsystems;
|
||||
using AsbCloudInfrastructure.Services.DailyReport;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
@ -191,7 +190,7 @@ public class DailyReportServiceTest
|
||||
}
|
||||
};
|
||||
|
||||
private readonly SubsystemStatDto fakeStatSubsystemOperationTime = new()
|
||||
private readonly SubsystemStatDto fakeSubsystemsStat = new()
|
||||
{
|
||||
SubsystemName = "АПД",
|
||||
SumDepthInterval = 250,
|
||||
@ -204,7 +203,7 @@ public class DailyReportServiceTest
|
||||
private readonly IDailyReportRepository dailyReportRepositoryMock = Substitute.For<IDailyReportRepository>();
|
||||
private readonly IScheduleRepository scheduleRepositoryMock = Substitute.For<IScheduleRepository>();
|
||||
private readonly IWellOperationRepository wellOperationRepositoryMock = Substitute.For<IWellOperationRepository>();
|
||||
private readonly ISubsystemOperationTimeService subsystemOperationTimeServiceMock = Substitute.For<ISubsystemOperationTimeService>();
|
||||
private readonly ISubsystemService subsystemServiceMock = Substitute.For<ISubsystemService>();
|
||||
private readonly IProcessMapReportWellDrillingService processMapReportWellDrillingServiceMock = Substitute.For<IProcessMapReportWellDrillingService>();
|
||||
private readonly IDetectedOperationService detectedOperationServiceMock = Substitute.For<IDetectedOperationService>();
|
||||
|
||||
@ -245,7 +244,7 @@ public class DailyReportServiceTest
|
||||
dailyReportRepositoryMock,
|
||||
scheduleRepositoryMock,
|
||||
wellOperationRepositoryMock,
|
||||
subsystemOperationTimeServiceMock,
|
||||
subsystemServiceMock,
|
||||
processMapReportWellDrillingServiceMock,
|
||||
detectedOperationServiceMock);
|
||||
|
||||
@ -276,8 +275,8 @@ public class DailyReportServiceTest
|
||||
detectedOperationServiceMock.GetAsync(Arg.Any<DetectedOperationRequest>(), Arg.Any<CancellationToken>())
|
||||
.ReturnsForAnyArgs(fakeWellOperationSlipsTime);
|
||||
|
||||
subsystemOperationTimeServiceMock.GetStatAsync(Arg.Any<SubsystemOperationTimeRequest>(), Arg.Any<CancellationToken>())
|
||||
.ReturnsForAnyArgs(new[] { fakeStatSubsystemOperationTime });
|
||||
subsystemServiceMock.GetStatAsync(Arg.Any<SubsystemRequest>(), Arg.Any<CancellationToken>())
|
||||
.ReturnsForAnyArgs(new[] { fakeSubsystemsStat });
|
||||
|
||||
scheduleRepositoryMock.GetAsync(idWell, dateDailyReport, Arg.Any<CancellationToken>())
|
||||
.ReturnsForAnyArgs(new[] { fakeShedule });
|
||||
|
@ -152,10 +152,10 @@ public abstract class ProcessMapBaseController<T> : ControllerBase
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[ProducesResponseType(typeof(ValidationResultDto<>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||
public async Task<ActionResult<ValidationResultDto<T>>> GetAsync(int idWell, CancellationToken cancellationToken)
|
||||
public async Task<ActionResult<IEnumerable<ValidationResultDto<T>>>> GetAsync(int idWell, CancellationToken cancellationToken)
|
||||
{
|
||||
var processMaps = await service.GetAsync(idWell, cancellationToken);
|
||||
|
||||
|
@ -122,21 +122,21 @@ namespace AsbCloudWebApi.Controllers.SAUB
|
||||
/// Создает excel файл с операциями по скважине
|
||||
/// </summary>
|
||||
/// <param name="idWell">id скважины</param>
|
||||
/// <param name="idDomain">Идентификатор домена</param>
|
||||
/// <param name="token"></param>
|
||||
[HttpGet("export")]
|
||||
[Permission]
|
||||
[ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK, "application/octet-stream")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public async Task<IActionResult> ExportAsync(int idWell, [Range(1, 2)] int idDomain, CancellationToken token)
|
||||
public async Task<IActionResult> ExportAsync(int idWell, CancellationToken token)
|
||||
{
|
||||
var idCompany = User.GetCompanyId();
|
||||
|
||||
if (idCompany is null)
|
||||
return Forbid();
|
||||
|
||||
var stream = await detectedOperationExportService.ExportAsync(idWell, idDomain, token);
|
||||
|
||||
var host = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}";
|
||||
var stream = await detectedOperationExportService.ExportAsync(idWell, host, token);
|
||||
|
||||
return File(stream, "application/octet-stream", "operations.xlsx");
|
||||
}
|
||||
|
92
AsbCloudWebApi/Controllers/Subsystems/SubsystemController.cs
Normal file
92
AsbCloudWebApi/Controllers/Subsystems/SubsystemController.cs
Normal file
@ -0,0 +1,92 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Data.Subsystems;
|
||||
using AsbCloudApp.Requests;
|
||||
using AsbCloudApp.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudWebApi.Controllers.Subsystems
|
||||
{
|
||||
/// <summary>
|
||||
/// Наработка подсистем
|
||||
/// </summary>
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class SubsystemController : ControllerBase
|
||||
{
|
||||
private readonly ISubsystemService subsystemService;
|
||||
private readonly ITelemetryDataSaubService telemetryDataSaubService;
|
||||
private readonly IWellService wellService;
|
||||
|
||||
public SubsystemController(
|
||||
ISubsystemService subsystemService,
|
||||
IWellService wellService,
|
||||
ITelemetryDataSaubService telemetryDataSaubService)
|
||||
{
|
||||
this.subsystemService = subsystemService;
|
||||
this.wellService = wellService;
|
||||
this.telemetryDataSaubService = telemetryDataSaubService;
|
||||
}
|
||||
/// <summary>
|
||||
/// получить статистику
|
||||
/// </summary>
|
||||
[HttpGet("stat")]
|
||||
[ProducesResponseType(typeof(IEnumerable<SubsystemStatDto>), (int)System.Net.HttpStatusCode.OK)]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public async Task<IActionResult> GetStatAsync([FromQuery] SubsystemRequest request, CancellationToken token)
|
||||
{
|
||||
if (!await UserHasAccessToWellAsync(request.IdWell, token))
|
||||
return Forbid();
|
||||
var subsystemResult = await subsystemService.GetStatAsync(request, token);
|
||||
return Ok(subsystemResult);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// получить период, за который будет рассчитываться статистика
|
||||
/// </summary>
|
||||
[HttpGet("operationsPeriod/{idWell}")]
|
||||
[ProducesResponseType(typeof(DatesRangeDto), (int)System.Net.HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> GetStatDateRangeAsync([FromRoute] int idWell, CancellationToken token)
|
||||
{
|
||||
if (!await UserHasAccessToWellAsync(idWell, token))
|
||||
return Forbid();
|
||||
|
||||
var dateRange = telemetryDataSaubService.GetRange(idWell);
|
||||
|
||||
return Ok(dateRange);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// получить статистику по активным скважинам
|
||||
/// </summary>
|
||||
/// <param name="gtDate"> Больше или равно дате </param>
|
||||
/// <param name="ltDate"> Меньше или равно дате </param>
|
||||
/// <param name="token"> Токен </param>
|
||||
/// <returns> </returns>
|
||||
[HttpGet("statByActiveWell")]
|
||||
[ProducesResponseType(typeof(IEnumerable<SubsystemActiveWellStatDto>), (int)System.Net.HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> GetStatByWellAsync(DateTime? gtDate, DateTime? ltDate, CancellationToken token)
|
||||
{
|
||||
var idCompany = User.GetCompanyId();
|
||||
if (!idCompany.HasValue)
|
||||
return Forbid();
|
||||
var subsystemResult = await subsystemService.GetStatByActiveWells(idCompany.Value, gtDate, ltDate, token);
|
||||
return Ok(subsystemResult);
|
||||
}
|
||||
|
||||
private async Task<bool> UserHasAccessToWellAsync(int idWell, CancellationToken token)
|
||||
{
|
||||
var idCompany = User.GetCompanyId();
|
||||
if (idCompany is not null &&
|
||||
await wellService.IsCompanyInvolvedInWellAsync((int)idCompany, idWell, token)
|
||||
.ConfigureAwait(false))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,162 +0,0 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Data.Subsystems;
|
||||
using AsbCloudApp.Requests;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudApp.Services.Subsystems;
|
||||
using AsbCloudDb.Model;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudWebApi.Controllers.Subsystems
|
||||
{
|
||||
/// <summary>
|
||||
/// Наработка подсистем
|
||||
/// </summary>
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class SubsystemOperationTimeController : ControllerBase
|
||||
{
|
||||
private readonly ISubsystemOperationTimeService subsystemOperationTimeService;
|
||||
private readonly ITelemetryDataSaubService telemetryDataSaubService;
|
||||
private readonly IWellService wellService;
|
||||
|
||||
private readonly Dictionary<int, string> subsystemNames = new()
|
||||
{
|
||||
{ 1, "SAUB" },
|
||||
{ 65537, "Torque Master" },
|
||||
{ 65536, "Spin Master" }
|
||||
};
|
||||
|
||||
public SubsystemOperationTimeController(
|
||||
ISubsystemOperationTimeService subsystemOperationTimeService,
|
||||
IWellService wellService,
|
||||
ITelemetryDataSaubService telemetryDataSaubService)
|
||||
{
|
||||
this.subsystemOperationTimeService = subsystemOperationTimeService;
|
||||
this.wellService = wellService;
|
||||
this.telemetryDataSaubService = telemetryDataSaubService;
|
||||
}
|
||||
/// <summary>
|
||||
/// получить статистику
|
||||
/// </summary>
|
||||
[HttpGet("stat")]
|
||||
[ProducesResponseType(typeof(IEnumerable<SubsystemStatDto>), (int)System.Net.HttpStatusCode.OK)]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public async Task<IActionResult> GetStatAsync([FromQuery] SubsystemOperationTimeRequest request, CancellationToken token)
|
||||
{
|
||||
if (!await UserHasAccessToWellAsync(request.IdWell, token))
|
||||
return Forbid();
|
||||
var subsystemResult = await subsystemOperationTimeService.GetStatAsync(request, token);
|
||||
return Ok(subsystemResult);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// получить период, за который будет рассчитываться статистика
|
||||
/// </summary>
|
||||
[HttpGet("operationsPeriod/{idWell}")]
|
||||
[ProducesResponseType(typeof(DatesRangeDto), (int)System.Net.HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> GetStatDateRangeAsync([FromRoute] int idWell, CancellationToken token)
|
||||
{
|
||||
if (!await UserHasAccessToWellAsync(idWell, token))
|
||||
return Forbid();
|
||||
|
||||
var dateRange = telemetryDataSaubService.GetRange(idWell);
|
||||
|
||||
return Ok(dateRange);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// получить статистику по активным скважинам
|
||||
/// </summary>
|
||||
/// <param name="GtDate"> Больше или равно дате </param>
|
||||
/// <param name="LtDate"> Меньше или равно дате </param>
|
||||
/// <param name="token"> Токен </param>
|
||||
/// <returns> </returns>
|
||||
[HttpGet("statByActiveWell")]
|
||||
[ProducesResponseType(typeof(IEnumerable<SubsystemActiveWellStatDto>), (int)System.Net.HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> GetStatByWellAsync(DateTime? GtDate, DateTime? LtDate, CancellationToken token)
|
||||
{
|
||||
var idCompany = User.GetCompanyId();
|
||||
if (!idCompany.HasValue)
|
||||
return Forbid();
|
||||
var subsystemResult = await subsystemOperationTimeService.GetStatByActiveWells(idCompany.Value, GtDate, LtDate, token);
|
||||
return Ok(subsystemResult);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// получить доступный диапазон дат наработки подсистемы.
|
||||
/// </summary>
|
||||
[HttpGet("datesRange")]
|
||||
[ProducesResponseType(typeof(DatesRangeDto), (int)System.Net.HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> GetDateRangeOperationTimeAsync([FromQuery] SubsystemOperationTimeRequest request, CancellationToken token)
|
||||
{
|
||||
if (!await UserHasAccessToWellAsync(request.IdWell, token))
|
||||
return Forbid();
|
||||
var result = await subsystemOperationTimeService.GetDateRangeOperationTimeAsync(request, token);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// получить список наработок подсистем
|
||||
/// </summary>
|
||||
[HttpGet("operationTime")]
|
||||
[ProducesResponseType(typeof(IEnumerable<SubsystemOperationTimeDto>), (int)System.Net.HttpStatusCode.OK)]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public async Task<IActionResult> GetOperationTimeAsync(
|
||||
[FromQuery] SubsystemOperationTimeRequest request,
|
||||
CancellationToken token)
|
||||
{
|
||||
if (!await UserHasAccessToWellAsync(request.IdWell, token))
|
||||
return Forbid();
|
||||
|
||||
var result = await subsystemOperationTimeService.GetOperationTimeAsync(request, token);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Удалить наработки.
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpDelete]
|
||||
[Permission]
|
||||
[ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
|
||||
public async Task<IActionResult> DeleteAsync(
|
||||
[FromQuery] SubsystemOperationTimeRequest request,
|
||||
CancellationToken token)
|
||||
{
|
||||
if (!await UserHasAccessToWellAsync(request.IdWell, token))
|
||||
return Forbid();
|
||||
var result = await subsystemOperationTimeService.DeleteAsync(request, token);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение словаря названий подсистем
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("names")]
|
||||
[ProducesResponseType(typeof(Dictionary<int, string>), (int)System.Net.HttpStatusCode.OK)]
|
||||
public IActionResult GetSubsystemsNames()
|
||||
{
|
||||
return Ok(subsystemNames);
|
||||
}
|
||||
|
||||
protected async Task<bool> UserHasAccessToWellAsync(int idWell, CancellationToken token)
|
||||
{
|
||||
var idCompany = User.GetCompanyId();
|
||||
if (idCompany is not null &&
|
||||
await wellService.IsCompanyInvolvedInWellAsync((int)idCompany, idWell, token)
|
||||
.ConfigureAwait(false))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user