diff --git a/AsbCloudApp/Data/User/ContactDto.cs b/AsbCloudApp/Data/User/ContactDto.cs
index dd6b3212..8445d801 100644
--- a/AsbCloudApp/Data/User/ContactDto.cs
+++ b/AsbCloudApp/Data/User/ContactDto.cs
@@ -35,7 +35,7 @@ public class ContactDto : IId
///
/// Email
///
- [RegularExpression(@"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$", ErrorMessage = "Некорректный email")]
+ [RegularExpression(@"^[a-zA-Z0-9_\-\.]{3,128}@[a-zA-Z0-9_\-\.]{2,128}\.[a-zA-Z]{1,32}$", ErrorMessage = "Некорректный email")]
public string? Email { get; set; }
///
diff --git a/AsbCloudApp/Repositories/IWellOperationRepository.cs b/AsbCloudApp/Repositories/IWellOperationRepository.cs
index fcf31f00..612d58d9 100644
--- a/AsbCloudApp/Repositories/IWellOperationRepository.cs
+++ b/AsbCloudApp/Repositories/IWellOperationRepository.cs
@@ -33,6 +33,23 @@ namespace AsbCloudApp.Repositories
///
///
Task> GetPageAsync(WellOperationRequest request, CancellationToken token);
+
+ ///
+ /// Получить страницу с операцией
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task?> GetPageAsync(int idWell,
+ int id,
+ int operationType,
+ int? take,
+ IEnumerable? sortFields,
+ CancellationToken token);
///
/// Получить статистику операции по скважине с группировкой по категориям
diff --git a/AsbCloudApp/Requests/WellContactRequest.cs b/AsbCloudApp/Requests/WellContactRequest.cs
new file mode 100644
index 00000000..26fd4f1b
--- /dev/null
+++ b/AsbCloudApp/Requests/WellContactRequest.cs
@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+
+namespace AsbCloudApp.Requests
+{
+ ///
+ /// Запрос на получение контактов
+ ///
+ public class WellContactRequest
+ {
+ ///
+ /// Идентификаторы скважин
+ ///
+ public IEnumerable IdsWells { get; set; } = null!;
+
+ ///
+ /// Ключ типа контактов
+ ///
+ public int? ContactTypeId { get; set; }
+ }
+}
diff --git a/AsbCloudApp/Services/IDataSaubStatService.cs b/AsbCloudApp/Services/IDataSaubStatService.cs
new file mode 100644
index 00000000..f72d4480
--- /dev/null
+++ b/AsbCloudApp/Services/IDataSaubStatService.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace AsbCloudApp.Services
+{
+ ///
+ /// Сервис записи данных в таблицу DataSaubStat, которая используется для построения РТК-отчета
+ ///
+ public interface IDataSaubStatService
+ {
+ ///
+ /// Расчет статистики DataSaubStat
+ ///
+ ///
+ /// Количество дней за которые должны были приходить данные, чтобы телеметрия попала в обработку.
+ ///
+ ///
+ ///
+ ///
+ Task CreateStatAsync(int lastDaysFilter, Action onProgressCallback, CancellationToken token);
+
+ }
+}
diff --git a/AsbCloudApp/Services/IWellContactService.cs b/AsbCloudApp/Services/IWellContactService.cs
index 266da573..cf7124db 100644
--- a/AsbCloudApp/Services/IWellContactService.cs
+++ b/AsbCloudApp/Services/IWellContactService.cs
@@ -1,5 +1,6 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.User;
+using AsbCloudApp.Requests;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
@@ -12,13 +13,12 @@ namespace AsbCloudApp.Services
public interface IWellContactService
{
///
- /// Получение контактов по ключу скважины и типу контакта
+ /// Получение контактов по параметрам запроса
///
- /// ключ скважины
- /// тип контакта
+ /// ключ скважины
///
///
- Task> GetAllAsync(int idWell, int contactTypeId, CancellationToken token);
+ Task> GetAllAsync(WellContactRequest request, CancellationToken token);
///
/// Получение контакта по ключу
diff --git a/AsbCloudInfrastructure/Background/PeriodicWorks/WorkDataSaubStat.cs b/AsbCloudInfrastructure/Background/PeriodicWorks/WorkDataSaubStat.cs
index c7ea36ff..6a2f92de 100644
--- a/AsbCloudInfrastructure/Background/PeriodicWorks/WorkDataSaubStat.cs
+++ b/AsbCloudInfrastructure/Background/PeriodicWorks/WorkDataSaubStat.cs
@@ -16,7 +16,7 @@ using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Background.PeriodicWorks
{
///
- /// задача по добавлению данных в таблицу DataSaubStat, которая используется дл построения РТК-отчета
+ /// задача по добавлению данных в таблицу DataSaubStat, которая используется для построения РТК-отчета
///
internal class WorkDataSaubStat : Work
{
@@ -29,209 +29,11 @@ namespace AsbCloudInfrastructure.Background.PeriodicWorks
protected override async Task Action(string id, IServiceProvider services, Action onProgressCallback, CancellationToken token)
{
+ var dataSaubStatService = services.GetRequiredService();
- var telemetryDataCache = services.GetRequiredService>();
+ if (dataSaubStatService != null )
+ await dataSaubStatService.CreateStatAsync(Gap, onProgressCallback, token);
- var cacheRequest = new TelemetryDataRequest()
- {
- GeDate = DateTime.UtcNow.AddDays(-Gap)
- };
- var idTelemetries = telemetryDataCache.GetIds(cacheRequest).ToArray();
-
- if (!idTelemetries.Any())
- return;
-
- var dataSaubStatRepo = services.GetRequiredService();
- var dataSaubService = services.GetRequiredService();
- var detectedOperationRepository = services.GetRequiredService();
- var stats = await dataSaubStatRepo.GetLastsAsync(idTelemetries, token);
-
- for( var i =0; i < idTelemetries.Length; i++)
- {
- var idTelemetry = idTelemetries[i];
- var lastDate = stats.FirstOrDefault(s => s.IdTelemetry == idTelemetry)?.DateEnd.ToUniversalTime() ?? DateTimeOffset.UnixEpoch;
- var statsCount = await CreateStatForTelemetryFromDate(idTelemetry, lastDate, dataSaubService, dataSaubStatRepo, detectedOperationRepository, token);
- onProgressCallback($"Calculate stat for telemetry: {idTelemetry}; from {lastDate}; results count: {statsCount};", 100*i / idTelemetries.Length);
- }
- }
-
- private static async Task CreateStatForTelemetryFromDate(
- int idTelemetry,
- DateTimeOffset begin,
- ITelemetryDataSaubService dataSaubService,
- IDataSaubStatRepository dataSaubStatRepo,
- IDetectedOperationRepository detectedOperationRepository,
- CancellationToken token)
- {
- var detectedOperationRequest = new DetectedOperationByTelemetryRequest {
- GeDateStart = begin,
- IdTelemetry = idTelemetry,
- IdsCategories = WellOperationCategory.MechanicalDrillingSubIds,
- SortFields = new[] {nameof(DetectedOperation.DateStart) },
- Take = 250,
- };
-
- var detectedOperations = await detectedOperationRepository.Get(detectedOperationRequest, token);
-
- if (!detectedOperations.Any())
- return 0;
-
- var geDate = detectedOperations.First().DateStart;
- var leDate = detectedOperations.OrderByDescending(d => d.DateEnd).First().DateEnd;
-
- var dataSaub = await dataSaubService.Get(idTelemetry, true, geDate, leDate, 100_000, token);
-
- if (!dataSaub.Any())
- return 0;
-
- if(dataSaub is not TelemetryDataSaubDto[] dataSaubArray)
- dataSaubArray = dataSaub.ToArray();
-
- var dataSaubStats = CreateDataSaubStat(detectedOperations, dataSaubArray);
-
- return await dataSaubStatRepo.InsertRangeAsync(dataSaubStats, token);
- }
-
- private static IEnumerable CreateDataSaubStat(IEnumerable detectedOperations, TelemetryDataSaubDto[] dataSaub)
- {
- var indexStart = 0;
- var indexEnd = 0;
- var result = new List();
-
- if (!dataSaub.Any())
- return result;
-
- foreach (var operation in detectedOperations)
- {
- indexStart = Array.FindIndex(dataSaub, indexEnd, t => t.DateTime >= operation.DateStart);
- if (indexStart < 0)
- break;
-
- indexEnd = Array.FindIndex(dataSaub, indexStart, t => t.DateTime > operation.DateEnd);
-
- if (indexEnd < 0)
- indexEnd = dataSaub.Length - 1;
-
- if (indexEnd == indexStart)
- continue;
-
- var length = indexEnd - indexStart;
-
- var subset = dataSaub.AsSpan(indexStart, length);
- var stats = CalcStats(operation, subset);
- result.AddRange(stats);
- }
- return result;
- }
-
- private static IEnumerable CalcStats(DetectedOperationDto operation, Span dataSaub)
- {
- var result = new List();
-
- var indexStart = 0;
- for (var i = 1; i < dataSaub.Length; i++)
- {
- var previous = dataSaub[i - 1];
- var current = dataSaub[i];
-
- if (IsNewCacheItem(previous, current) || i == dataSaub.Length - 1)
- {
- var length = i - indexStart;
- var span = dataSaub.Slice(indexStart, length);
- indexStart = i;
- if (length <= 2 || (span[^1].WellDepth - span[0].WellDepth) < 0.001)
- continue; // мелкие выборки не учитываем.
- var stat = CalcStat(operation, span);
- result.Add(stat);
- }
- }
-
- return result;
- }
-
- private static DataSaubStatDto CalcStat(DetectedOperationDto operation, Span span)
- {
- var aggregatedValues = CalcAggregate(span);
- var dateStart = span[0].DateTime;
- var dateEnd = span[^1].DateTime;
- var depthStart = span[0].WellDepth;
- var depthEnd = span[^1].WellDepth;
- var speed = ((depthEnd - depthStart) / (dateEnd - dateStart).TotalHours);
-
- var processMapDrillingCacheItem = new DataSaubStatDto
- {
- DateStart = dateStart,
- DateEnd = dateEnd,
- DepthStart = depthStart,
- DepthEnd = depthEnd,
- Speed = speed,
- BlockSpeedSp = span[0].BlockSpeedSp,
- Pressure = aggregatedValues.Pressure,
- PressureIdle = span[0].PressureIdle,
- PressureSp = span[0].PressureSp,
- AxialLoad = aggregatedValues.AxialLoad,
- AxialLoadSp = span[0].AxialLoadSp,
- AxialLoadLimitMax = span[0].AxialLoadLimitMax,
- RotorTorque = aggregatedValues.RotorTorque,
- RotorTorqueSp = span[0].RotorTorqueSp,
- RotorTorqueLimitMax = span[0].RotorTorqueLimitMax,
- IdFeedRegulator = span[0].IdFeedRegulator,
- RotorSpeed = aggregatedValues.RotorSpeed,
- IdCategory = operation.IdCategory,
- EnabledSubsystems = operation.EnabledSubsystems,
- HasOscillation = operation.EnabledSubsystems.IsAutoOscillation,
- IdTelemetry = operation.IdTelemetry,
- Flow = aggregatedValues.Flow
- };
- return processMapDrillingCacheItem;
- }
-
- private static (
- double Pressure,
- double AxialLoad,
- double RotorTorque,
- double RotorSpeed,
- double Flow
- ) CalcAggregate(Span span)
- {
- var sumPressure = 0.0;
- var sumAxialLoad = 0.0;
- var sumRotorTorque = 0.0;
- var sumRotorSpeed = 0.0;
- var flow = span[0].Flow ?? 0.0;
- var diffDepthTotal = span[^1].WellDepth - span[0].WellDepth;
- for (var i = 0; i < span.Length - 1; i++)
- {
- var diffDepth = span[i + 1].WellDepth - span[i].WellDepth;
- sumPressure += diffDepth * span[i].Pressure;
- sumAxialLoad += diffDepth * span[i].AxialLoad;
- sumRotorTorque += diffDepth * span[i].RotorTorque;
- sumRotorSpeed += diffDepth * span[i].RotorSpeed;
- flow = span[i + 1].Flow > flow ? span[i + 1].Flow ?? 0.0 : flow;
- }
- return (
- Pressure: sumPressure / diffDepthTotal,
- AxialLoad: sumAxialLoad / diffDepthTotal,
- RotorTorque: sumRotorTorque / diffDepthTotal,
- RotorSpeed: sumRotorSpeed / diffDepthTotal,
- Flow: flow
- );
- }
-
- private static bool IsNewCacheItem(TelemetryDataSaubDto previous, TelemetryDataSaubDto current)
- {
- return !(current.Mode == previous.Mode)
- || !(current.WellDepth >= previous.WellDepth)
- || !(current.BlockSpeedSp == previous.BlockSpeedSp)
- || !(current.PressureIdle == previous.PressureIdle)
- || !(current.PressureSp == previous.PressureSp)
- || !(current.AxialLoadSp == previous.AxialLoadSp)
- || !(current.AxialLoadLimitMax == previous.AxialLoadLimitMax)
- || !(current.HookWeightIdle == previous.HookWeightIdle)
- || !(current.RotorTorqueIdle == previous.RotorTorqueIdle)
- || !(current.RotorTorqueSp == previous.RotorTorqueSp)
- || !(current.RotorTorqueLimitMax == previous.RotorTorqueLimitMax)
- || !(current.IdFeedRegulator == previous.IdFeedRegulator);
- }
+ }
}
}
diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs
index 9fbe1721..5ce1ada0 100644
--- a/AsbCloudInfrastructure/DependencyInjection.cs
+++ b/AsbCloudInfrastructure/DependencyInjection.cs
@@ -316,6 +316,7 @@ namespace AsbCloudInfrastructure
services.AddTransient();
services.AddTransient();
services.AddTransient();
+ services.AddTransient();
services.AddTransient<
IChangeLogRepository,
diff --git a/AsbCloudInfrastructure/Repository/ChangeLogRepositoryAbstract.cs b/AsbCloudInfrastructure/Repository/ChangeLogRepositoryAbstract.cs
index 157b204d..c47ebd05 100644
--- a/AsbCloudInfrastructure/Repository/ChangeLogRepositoryAbstract.cs
+++ b/AsbCloudInfrastructure/Repository/ChangeLogRepositoryAbstract.cs
@@ -117,6 +117,22 @@ public abstract class ChangeLogRepositoryAbstract : ICh
}
public async Task InsertRange(int idUser, IEnumerable dtos, CancellationToken token)
+ {
+ using var transaction = db.Database.BeginTransaction();
+ try
+ {
+ var result = await InsertRangeWithoutTransaction(idUser, dtos, token);
+ await transaction.CommitAsync(token);
+ return result;
+ }
+ catch
+ {
+ await transaction.RollbackAsync(token);
+ throw;
+ }
+ }
+
+ private async Task InsertRangeWithoutTransaction(int idUser, IEnumerable dtos, CancellationToken token)
{
var result = 0;
if (dtos.Any())
@@ -138,7 +154,8 @@ public abstract class ChangeLogRepositoryAbstract : ICh
result += await SaveChangesWithExceptionHandling(token);
}
- return result;
+
+ return result;
}
public async Task UpdateRange(int idUser, IEnumerable dtos, CancellationToken token)
@@ -248,7 +265,7 @@ public abstract class ChangeLogRepositoryAbstract : ICh
try
{
result += await Clear(idUser, request, token);
- result += await InsertRange(idUser, dtos, token);
+ result += await InsertRangeWithoutTransaction(idUser, dtos, token);
await transaction.CommitAsync(token);
return result;
diff --git a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs
index 8fa9433d..843956cb 100644
--- a/AsbCloudInfrastructure/Repository/WellOperationRepository.cs
+++ b/AsbCloudInfrastructure/Repository/WellOperationRepository.cs
@@ -40,7 +40,7 @@ public class WellOperationRepository : CrudRepositoryBase wellOperationCategoryRepository.Get(true, false).ToDictionary(c => c.Id));
LazyWellSectionTypes = new(() => GetSectionTypes().ToDictionary(c => c.Id));
}
-
+
public IEnumerable GetSectionTypes() =>
memoryCache
.GetOrCreateBasic(dbContext.WellSectionTypes)
@@ -71,6 +71,48 @@ public class WellOperationRepository : CrudRepositoryBase?> GetPageAsync(int idWell,
+ int id,
+ int operationType,
+ int? take,
+ IEnumerable? sortFields,
+ CancellationToken token)
+ {
+ var request = new WellOperationRequest(new[] { idWell })
+ {
+ OperationType = operationType,
+ SortFields = sortFields,
+ };
+
+ var (wellOperations, count) = await GetWithDaysAndNpvAsync(request, token);
+
+ var skip = 0;
+ take ??= 32;
+
+ while (skip < count)
+ {
+ var page = wellOperations.Skip(skip)
+ .Take(take.Value);
+
+ if (page.Any(x => x.Id == id))
+ {
+ var paginationContainer = new PaginationContainer
+ {
+ Skip = skip,
+ Take = take.Value,
+ Items = page,
+ Count = count
+ };
+
+ return paginationContainer;
+ }
+
+ skip += take.Value;
+ }
+
+ return null;
+ }
+
public async Task> GetGroupOperationsStatAsync(WellOperationRequest request, CancellationToken token)
{
var query = BuildQuery(request);
@@ -209,9 +251,7 @@ public class WellOperationRepository : CrudRepositoryBase e.DateStart)
- .FirstOrDefault()!;
+ var firstWellOperation = wellOperationsWithType.MinBy(e => e.DateStart);
var operationsWithNpt = wellOperationsWithType
.Where(o => WellOperationCategory.NonProductiveTimeSubIds.Contains(o.IdCategory));
@@ -224,11 +264,13 @@ public class WellOperationRepository : CrudRepositoryBase
{
- var dto = Convert(entity);
+ var dto = Convert(entity, timezoneOffset);
dto.Day = (entity.DateStart - firstWellOperation.DateStart).TotalDays;
dto.NptHours = operationsWithNpt
.Where(o => o.DateStart <= entity.DateStart)
@@ -427,15 +469,11 @@ public class WellOperationRepository : CrudRepositoryBase();
- dto.DateStart = src.DateStart.ToOffset(timeZoneOffset);
- dto.LastUpdateDate = src.LastUpdateDate.ToOffset(timeZoneOffset);
+ dto.DateStart = src.DateStart.ToOffset(timezoneOffset);
+ dto.LastUpdateDate = src.LastUpdateDate.ToOffset(timezoneOffset);
dto.OperationCategoryName = LazyWellCategories.Value.TryGetValue(src.IdCategory, out WellOperationCategoryDto? category) ? category.Name : string.Empty;
dto.WellSectionTypeCaption = LazyWellSectionTypes.Value.TryGetValue(src.IdWellSectionType, out WellSectionTypeDto? sectionType) ? sectionType.Caption : string.Empty;
diff --git a/AsbCloudInfrastructure/Services/DataSaubStatService.cs b/AsbCloudInfrastructure/Services/DataSaubStatService.cs
new file mode 100644
index 00000000..e54a380d
--- /dev/null
+++ b/AsbCloudInfrastructure/Services/DataSaubStatService.cs
@@ -0,0 +1,237 @@
+using AsbCloudApp.Data;
+using AsbCloudApp.Data.DetectedOperation;
+using AsbCloudApp.Data.SAUB;
+using AsbCloudApp.Repositories;
+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;
+
+namespace AsbCloudInfrastructure.Services
+{
+
+ public class DataSaubStatService : IDataSaubStatService
+ {
+ private IDataSaubStatRepository dataSaubStatRepository;
+ private ITelemetryDataCache telemetryDataCache;
+ private ITelemetryDataSaubService dataSaubService;
+ private IDetectedOperationRepository detectedOperationRepository;
+
+ public DataSaubStatService(
+ IDataSaubStatRepository dataSaubStatRepository,
+ ITelemetryDataCache telemetryDataCache,
+ ITelemetryDataSaubService dataSaubService,
+ IDetectedOperationRepository detectedOperationRepository)
+ {
+ this.dataSaubStatRepository = dataSaubStatRepository;
+ this.telemetryDataCache = telemetryDataCache;
+ this.dataSaubService = dataSaubService;
+ this.detectedOperationRepository = detectedOperationRepository;
+ }
+
+ public async Task CreateStatAsync(int lastDaysFilter, Action onProgressCallback, CancellationToken token)
+ {
+ var cacheRequest = new TelemetryDataRequest()
+ {
+ GeDate = DateTime.UtcNow.AddDays(-lastDaysFilter)
+ };
+ var idTelemetries = telemetryDataCache.GetIds(cacheRequest).ToArray();
+
+ if (!idTelemetries.Any())
+ return;
+
+ var stats = await dataSaubStatRepository.GetLastsAsync(idTelemetries, token);
+
+ for (var i = 0; i < idTelemetries.Length; i++)
+ {
+ var idTelemetry = idTelemetries[i];
+ var lastDate = stats.FirstOrDefault(s => s.IdTelemetry == idTelemetry)?.DateEnd.ToUniversalTime() ?? DateTimeOffset.UnixEpoch;
+ var statsCount = await CreateStatForTelemetryFromDate(idTelemetry, lastDate, token);
+ if(onProgressCallback != null)
+ onProgressCallback($"Calculate stat for telemetry: {idTelemetry}; from {lastDate}; results count: {statsCount};", 1d * i / idTelemetries.Length);
+ }
+ }
+
+ private async Task CreateStatForTelemetryFromDate(
+ int idTelemetry,
+ DateTimeOffset begin,
+ CancellationToken token)
+ {
+ var detectedOperationRequest = new DetectedOperationByTelemetryRequest
+ {
+ GeDateStart = begin,
+ IdTelemetry = idTelemetry,
+ IdsCategories = WellOperationCategory.MechanicalDrillingSubIds,
+ SortFields = new[] { nameof(DetectedOperation.DateStart) },
+ Take = 250,
+ };
+
+ var detectedOperations = await detectedOperationRepository.Get(detectedOperationRequest, token);
+
+ if (!detectedOperations.Any())
+ return 0;
+
+ var geDate = detectedOperations.First().DateStart;
+ var leDate = detectedOperations.OrderByDescending(d => d.DateEnd).First().DateEnd;
+
+ var dataSaub = await dataSaubService.Get(idTelemetry, true, geDate, leDate, 100_000, token);
+
+ if (!dataSaub.Any())
+ return 0;
+
+ if (dataSaub is not TelemetryDataSaubDto[] dataSaubArray)
+ dataSaubArray = dataSaub.ToArray();
+
+ var dataSaubStats = CreateDataSaubStat(detectedOperations, dataSaubArray);
+
+ return await dataSaubStatRepository.InsertRangeAsync(dataSaubStats, token);
+ }
+
+ private static IEnumerable CreateDataSaubStat(IEnumerable detectedOperations, TelemetryDataSaubDto[] dataSaub)
+ {
+ var indexStart = 0;
+ var indexEnd = 0;
+ var result = new List();
+
+ if (!dataSaub.Any())
+ return result;
+
+ foreach (var operation in detectedOperations)
+ {
+ indexStart = Array.FindIndex(dataSaub, indexEnd, t => t.DateTime >= operation.DateStart);
+ if (indexStart < 0)
+ break;
+
+ indexEnd = Array.FindIndex(dataSaub, indexStart, t => t.DateTime > operation.DateEnd);
+
+ if (indexEnd < 0)
+ indexEnd = dataSaub.Length - 1;
+
+ if (indexEnd == indexStart)
+ continue;
+
+ var length = indexEnd - indexStart + 1;
+
+ var subset = dataSaub.AsSpan(indexStart, length);
+ var stats = CalcStats(operation, subset);
+ result.AddRange(stats);
+ }
+ return result;
+ }
+
+ private static IEnumerable CalcStats(DetectedOperationDto operation, Span dataSaub)
+ {
+ var result = new List();
+
+ var indexStart = 0;
+ for (var i = 1; i < dataSaub.Length; i++)
+ {
+ var previous = dataSaub[i - 1];
+ var current = dataSaub[i];
+
+ if (IsNewCacheItem(previous, current) || i == dataSaub.Length - 1)
+ {
+ var length = i - indexStart + 1;
+ var span = dataSaub.Slice(indexStart, length);
+ indexStart = i;
+ if (length <= 2 || (span[^1].WellDepth - span[0].WellDepth) < 0.001)
+ continue; // мелкие выборки не учитываем.
+ var stat = CalcStat(operation, span);
+ result.Add(stat);
+ }
+ }
+
+ return result;
+ }
+
+ private static DataSaubStatDto CalcStat(DetectedOperationDto operation, Span span)
+ {
+ var aggregatedValues = CalcAggregate(span);
+ var dateStart = span[0].DateTime;
+ var dateEnd = span[^1].DateTime;
+ var depthStart = span[0].WellDepth;
+ var depthEnd = span[^1].WellDepth;
+ var speed = ((depthEnd - depthStart) / (dateEnd - dateStart).TotalHours);
+
+ var processMapDrillingCacheItem = new DataSaubStatDto
+ {
+ DateStart = dateStart,
+ DateEnd = dateEnd,
+ DepthStart = depthStart,
+ DepthEnd = depthEnd,
+ Speed = speed,
+ BlockSpeedSp = span[0].BlockSpeedSp,
+ Pressure = aggregatedValues.Pressure,
+ PressureIdle = span[0].PressureIdle,
+ PressureSp = span[0].PressureSp,
+ AxialLoad = aggregatedValues.AxialLoad,
+ AxialLoadSp = span[0].AxialLoadSp,
+ AxialLoadLimitMax = span[0].AxialLoadLimitMax,
+ RotorTorque = aggregatedValues.RotorTorque,
+ RotorTorqueSp = span[0].RotorTorqueSp,
+ RotorTorqueLimitMax = span[0].RotorTorqueLimitMax,
+ IdFeedRegulator = span[0].IdFeedRegulator,
+ RotorSpeed = aggregatedValues.RotorSpeed,
+ IdCategory = operation.IdCategory,
+ EnabledSubsystems = operation.EnabledSubsystems,
+ HasOscillation = operation.EnabledSubsystems.IsAutoOscillation,
+ IdTelemetry = operation.IdTelemetry,
+ Flow = aggregatedValues.Flow
+ };
+ return processMapDrillingCacheItem;
+ }
+
+ private static (
+ double Pressure,
+ double AxialLoad,
+ double RotorTorque,
+ double RotorSpeed,
+ double Flow
+ ) CalcAggregate(Span span)
+ {
+ var sumPressure = 0.0;
+ var sumAxialLoad = 0.0;
+ var sumRotorTorque = 0.0;
+ var sumRotorSpeed = 0.0;
+ var flow = span[0].Flow ?? 0.0;
+ var diffDepthTotal = span[^1].WellDepth - span[0].WellDepth;
+ for (var i = 0; i < span.Length - 1; i++)
+ {
+ var diffDepth = span[i + 1].WellDepth - span[i].WellDepth;
+ sumPressure += diffDepth * span[i].Pressure;
+ sumAxialLoad += diffDepth * span[i].AxialLoad;
+ sumRotorTorque += diffDepth * span[i].RotorTorque;
+ sumRotorSpeed += diffDepth * span[i].RotorSpeed;
+ flow = span[i + 1].Flow > flow ? span[i + 1].Flow ?? 0.0 : flow;
+ }
+ return (
+ Pressure: sumPressure / diffDepthTotal,
+ AxialLoad: sumAxialLoad / diffDepthTotal,
+ RotorTorque: sumRotorTorque / diffDepthTotal,
+ RotorSpeed: sumRotorSpeed / diffDepthTotal,
+ Flow: flow
+ );
+ }
+
+ private static bool IsNewCacheItem(TelemetryDataSaubDto previous, TelemetryDataSaubDto current)
+ {
+ return !(current.Mode == previous.Mode)
+ || !(current.WellDepth >= previous.WellDepth)
+ || !(current.BlockSpeedSp == previous.BlockSpeedSp)
+ || !(current.PressureIdle == previous.PressureIdle)
+ || !(current.PressureSp == previous.PressureSp)
+ || !(current.AxialLoadSp == previous.AxialLoadSp)
+ || !(current.AxialLoadLimitMax == previous.AxialLoadLimitMax)
+ || !(current.HookWeightIdle == previous.HookWeightIdle)
+ || !(current.RotorTorqueIdle == previous.RotorTorqueIdle)
+ || !(current.RotorTorqueSp == previous.RotorTorqueSp)
+ || !(current.RotorTorqueLimitMax == previous.RotorTorqueLimitMax)
+ || !(current.IdFeedRegulator == previous.IdFeedRegulator);
+ }
+ }
+
+}
diff --git a/AsbCloudInfrastructure/Services/Subsystems/SubsystemService.cs b/AsbCloudInfrastructure/Services/Subsystems/SubsystemService.cs
index e2ab1e13..76bcefa2 100644
--- a/AsbCloudInfrastructure/Services/Subsystems/SubsystemService.cs
+++ b/AsbCloudInfrastructure/Services/Subsystems/SubsystemService.cs
@@ -157,8 +157,8 @@ internal class SubsystemService : ISubsystemService
SumDepthInterval = sumDepthInterval,
OperationCount = operationCount,
};
-
- oscillationStat.KUsage = oscillationStat.SumDepthInterval / oscillationStat.SumOperationDepthInterval;
+ if(oscillationStat.SumOperationDepthInterval != 0d)
+ oscillationStat.KUsage = oscillationStat.SumDepthInterval / oscillationStat.SumOperationDepthInterval;
return oscillationStat;
}
diff --git a/AsbCloudInfrastructure/Services/WellContactService.cs b/AsbCloudInfrastructure/Services/WellContactService.cs
index 1bb45b77..770375f3 100644
--- a/AsbCloudInfrastructure/Services/WellContactService.cs
+++ b/AsbCloudInfrastructure/Services/WellContactService.cs
@@ -1,6 +1,7 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.User;
using AsbCloudApp.Exceptions;
+using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using Mapster;
@@ -21,17 +22,22 @@ namespace AsbCloudInfrastructure.Services
this.db = db;
}
- public async Task> GetAllAsync(int wellId, int contactTypeId, CancellationToken token)
+ public async Task> GetAllAsync(WellContactRequest request, CancellationToken token)
{
var query = db.Contacts
- .Where(c => c.IdCompanyType == contactTypeId)
- .Where(c => c.IdWell == wellId)
- .Select(c => c.Adapt());
+ .Where(c => request.IdsWells.Contains(c.IdWell));
+
+ if (request.ContactTypeId.HasValue)
+ {
+ query = query.Where(c => c.IdCompanyType == request.ContactTypeId);
+ };
var entities = await query.AsNoTracking()
.ToArrayAsync(token);
- return entities;
+ var dtos = entities.Select(c => c.Adapt());
+
+ return dtos;
}
public async Task GetAsync(int idWell, int id, CancellationToken token)
diff --git a/AsbCloudInfrastructure/Services/WellOperations/Templates/WellOperationFactTemplate.xlsx b/AsbCloudInfrastructure/Services/WellOperations/Templates/WellOperationFactTemplate.xlsx
index 12fc2a44..cc90ef89 100644
Binary files a/AsbCloudInfrastructure/Services/WellOperations/Templates/WellOperationFactTemplate.xlsx and b/AsbCloudInfrastructure/Services/WellOperations/Templates/WellOperationFactTemplate.xlsx differ
diff --git a/AsbCloudInfrastructure/Services/WellOperations/Templates/WellOperationPlanTemplate.xlsx b/AsbCloudInfrastructure/Services/WellOperations/Templates/WellOperationPlanTemplate.xlsx
index ca2d01c7..3ff28d43 100644
Binary files a/AsbCloudInfrastructure/Services/WellOperations/Templates/WellOperationPlanTemplate.xlsx and b/AsbCloudInfrastructure/Services/WellOperations/Templates/WellOperationPlanTemplate.xlsx differ
diff --git a/AsbCloudWebApi.Tests/Services/DataSaubStatServiceTest.cs b/AsbCloudWebApi.Tests/Services/DataSaubStatServiceTest.cs
new file mode 100644
index 00000000..6d65a1f2
--- /dev/null
+++ b/AsbCloudWebApi.Tests/Services/DataSaubStatServiceTest.cs
@@ -0,0 +1,323 @@
+using AsbCloudApp.Data;
+using AsbCloudApp.Data.DetectedOperation;
+using AsbCloudApp.Data.SAUB;
+using AsbCloudApp.Repositories;
+using AsbCloudApp.Requests;
+using AsbCloudApp.Services;
+using AsbCloudInfrastructure.Services;
+using Mapster;
+using NSubstitute;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace AsbCloudWebApi.Tests.Services;
+
+public class DataSaubStatServiceTest
+{
+ private readonly int Gap = 5;
+ private readonly IDataSaubStatRepository dataSaubStatRepositoryMock = Substitute.For();
+ private readonly ITelemetryDataCache telemetryDataCacheMock = Substitute.For>();
+ private readonly IDetectedOperationRepository detectedOperationRepositoryMock = Substitute.For();
+ private readonly ITelemetryDataSaubService dataSaubServiceMock = Substitute.For();
+
+ private DataSaubStatService dataSaubStatService;
+
+ private int[] idTelemetries = [1];
+ private IEnumerable dataSaubStatDtos = new List()
+ {
+ new DataSaubStatDto {
+ Id = 1,
+ AxialLoad = 1,
+ AxialLoadLimitMax = 1,
+ AxialLoadSp = 1,
+ BlockSpeedSp = 1,
+ DateEnd = DateTime.UtcNow,
+ DateStart = DateTime.UtcNow.AddHours(-1),
+ DepthEnd = 2,
+ DepthStart = 1,
+ EnabledSubsystems = 1,
+ Flow = 1,
+ HasOscillation = true,
+ IdCategory = 1,
+ IdFeedRegulator = 1,
+ IdTelemetry = 1,
+ Pressure = 1,
+ PressureIdle = 1,
+ PressureSp = 1,
+ RotorSpeed = 1,
+ RotorTorque = 1,
+ RotorTorqueLimitMax = 1,
+ RotorTorqueSp = 1,
+ Speed = 1
+ },
+ new DataSaubStatDto {
+ Id = 2,
+ AxialLoad = 2,
+ AxialLoadLimitMax = 2,
+ AxialLoadSp = 2,
+ BlockSpeedSp = 2,
+ DateEnd = DateTime.UtcNow,
+ DateStart = DateTime.UtcNow.AddHours(-1),
+ DepthEnd = 3,
+ DepthStart = 2,
+ EnabledSubsystems = 2,
+ Flow = 2,
+ HasOscillation = true,
+ IdCategory = 2,
+ IdFeedRegulator = 2,
+ IdTelemetry = 2,
+ Pressure = 2,
+ PressureIdle = 2,
+ PressureSp = 2,
+ RotorSpeed = 2,
+ RotorTorque = 2,
+ RotorTorqueLimitMax = 2,
+ RotorTorqueSp = 2,
+ Speed = 2
+ },
+ new DataSaubStatDto {
+ Id = 3,
+ AxialLoad = 3,
+ AxialLoadLimitMax = 3,
+ AxialLoadSp = 3,
+ BlockSpeedSp = 3,
+ DateEnd = DateTime.UtcNow,
+ DateStart = DateTime.UtcNow.AddHours(-1),
+ DepthEnd = 4,
+ DepthStart = 3,
+ EnabledSubsystems = 3,
+ Flow = 3,
+ HasOscillation = true,
+ IdCategory = 3,
+ IdFeedRegulator = 3,
+ IdTelemetry = 3,
+ Pressure = 3,
+ PressureIdle = 3,
+ PressureSp = 3,
+ RotorSpeed = 3,
+ RotorTorque = 3,
+ RotorTorqueLimitMax = 3,
+ RotorTorqueSp = 3,
+ Speed = 3
+ },
+ };
+
+ private List detectedOperationDtos = new List() {
+ new DetectedOperationDto {
+ Id = 1,
+ DateEnd = DateTimeOffset.UtcNow,
+ DateStart = DateTimeOffset.UtcNow.AddHours(-1),
+ DepthStart = 1,
+ DepthEnd = 2,
+ IdCategory = 5002,
+ IdTelemetry = 1,
+ Value = 1,
+ IdEditor = 1,
+ IdUserAtStart = 1
+ }
+ };
+
+ private List telemetryDataSaubDtos = new List {
+ new TelemetryDataSaubDto()
+ {
+ IdTelemetry = 1,
+ DateTime = DateTime.UtcNow.AddMinutes(-30),
+ AxialLoad = 1,
+ AxialLoadLimitMax = 1,
+ AxialLoadSp = 1,
+ BitDepth = 1,
+ BlockPosition = 1,
+ BlockPositionMax = 1,
+ BlockPositionMin = 1,
+ BlockSpeed = 1,
+ BlockSpeedSp = 1,
+ BlockSpeedSpDevelop = 1,
+ BlockSpeedSpRotor = 1,
+ BlockSpeedSpSlide = 1,
+ Flow = 1,
+ FlowDeltaLimitMax = 1,
+ FlowIdle = 1,
+ HookWeight = 1,
+ HookWeightIdle = 1,
+ HookWeightLimitMax = 1,
+ HookWeightLimitMin = 1,
+ IdFeedRegulator = 1,
+ IdUser = 1,
+ Mode = 1,
+ Mse = 1,
+ MseState = 1,
+ Pressure = 1,
+ PressureDeltaLimitMax = 1,
+ PressureIdle = 1,
+ PressureSp = 1,
+ PressureSpDevelop = 1,
+ PressureSpRotor = 1,
+ PressureSpSlide = 1,
+ Pump0Flow = 1,
+ Pump1Flow = 1,
+ Pump2Flow = 1,
+ RotorSpeed = 1,
+ RotorTorque = 1,
+ RotorTorqueIdle = 1,
+ RotorTorqueSp = 1,
+ RotorTorqueLimitMax = 1,
+ WellDepth = 10,
+ }
+ };
+
+ public DataSaubStatServiceTest()
+ {
+ telemetryDataCacheMock
+ .GetIds(Arg.Any())
+ .Returns(idTelemetries);
+
+ dataSaubStatRepositoryMock
+ .GetLastsAsync(Arg.Any(), Arg.Any())
+ .Returns(dataSaubStatDtos);
+
+ var telemetrySaubDto = telemetryDataSaubDtos.FirstOrDefault();
+ if (telemetrySaubDto != null)
+ {
+ //заполнение списка телеметрий следующим образом:
+ // - всего в списке 6 элементов:
+ // - все они попадают в диапазон, определенный датами DateStart и DateEnd соответствующей записи detectedOperation
+ // - из этих 6-х записей у 2-х записей меняется параметр,
+ // являющийся признаком начала нового интервала (новой записи dataSaubStat)
+ // таким образом, в базе данных должно создаться 1 новая запись dataSaubStat (insertedDataSaubStatCount = 1)
+ var telemetrySaubDto1 = telemetrySaubDto.Adapt();
+ telemetrySaubDto1.DateTime = DateTime.UtcNow.AddMinutes(-20);
+ telemetryDataSaubDtos.Add(telemetrySaubDto1);
+
+ var telemetrySaubDto2 = telemetrySaubDto.Adapt();
+ telemetrySaubDto2.DateTime = DateTime.UtcNow.AddMinutes(-10);
+ telemetrySaubDto2.RotorTorqueLimitMax = 2;
+ telemetryDataSaubDtos.Add(telemetrySaubDto2);
+
+ var telemetrySaubDto3 = telemetrySaubDto.Adapt();
+ telemetrySaubDto3.DateTime = DateTime.UtcNow.AddMinutes(-8);
+ telemetrySaubDto3.RotorTorqueLimitMax = 2;
+ telemetryDataSaubDtos.Add(telemetrySaubDto3);
+
+ var telemetrySaubDto4 = telemetrySaubDto.Adapt();
+ telemetrySaubDto4.DateTime = DateTime.UtcNow.AddMinutes(-6);
+ telemetrySaubDto4.RotorTorqueLimitMax = 2;
+ telemetryDataSaubDtos.Add(telemetrySaubDto4);
+
+ var telemetrySaubDto5 = telemetrySaubDto.Adapt();
+ telemetrySaubDto5.DateTime = DateTime.UtcNow.AddMinutes(-4);
+ telemetrySaubDto5.RotorTorqueLimitMax = 2;
+ telemetryDataSaubDtos.Add(telemetrySaubDto5);
+
+ var telemetrySaubDto6 = telemetrySaubDto.Adapt();
+ telemetrySaubDto6.DateTime = DateTime.UtcNow.AddMinutes(-2);
+ telemetrySaubDto6.RotorTorqueLimitMax = 3;
+ telemetrySaubDto6.WellDepth = 11;
+ telemetryDataSaubDtos.Add(telemetrySaubDto6);
+ }
+
+ dataSaubServiceMock
+ .Get(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any())
+ .Returns(telemetryDataSaubDtos);
+
+ dataSaubStatService = new DataSaubStatService(
+ dataSaubStatRepositoryMock,
+ telemetryDataCacheMock,
+ dataSaubServiceMock,
+ detectedOperationRepositoryMock);
+ }
+
+ [Fact]
+ public async Task Create_1DataSaubStatItems_ShouldReturn__Success()
+ {
+ var insertedDataSaubStatCount = 1;
+
+ detectedOperationRepositoryMock
+ .Get(Arg.Any(), Arg.Any())
+ .Returns(detectedOperationDtos);
+
+
+ dataSaubStatRepositoryMock
+ .InsertRangeAsync(Arg.Any>(), Arg.Any())
+ .Returns(insertedDataSaubStatCount);
+
+ Action action = (message, percent) =>
+ {
+ //assert
+ Assert.NotNull(percent);
+ Assert.InRange(percent.Value, 0.0, 1.0);
+ };
+
+ //act
+ await dataSaubStatService.CreateStatAsync(Gap, action, CancellationToken.None);
+
+ //assert
+ await dataSaubStatRepositoryMock.Received().InsertRangeAsync(
+ Arg.Is>(l => l.Count() == insertedDataSaubStatCount),
+ Arg.Any());
+ }
+
+
+
+ [Fact]
+ public async Task Create_2DataSaubStatItems_ShouldReturn__Success()
+ {
+ var insertedDataSaubStatCount = 2;
+
+ var detectedOperationDto = detectedOperationDtos.FirstOrDefault();
+ if (detectedOperationDto != null)
+ {
+ var detectedOperationDto1 = detectedOperationDto.Adapt();
+ detectedOperationDto1.DateStart = DateTimeOffset.UtcNow.AddMinutes(1);
+ detectedOperationDto1.DateEnd = DateTimeOffset.UtcNow.AddHours(1);
+
+ detectedOperationDtos.Add(detectedOperationDto1);
+ }
+
+ var telemetryDataSaubDto = telemetryDataSaubDtos.LastOrDefault();
+ if (telemetryDataSaubDto != null)
+ {
+ var telemetryDataSaubDto1 = telemetryDataSaubDto.Adapt();
+ telemetryDataSaubDto1.DateTime = DateTime.UtcNow.AddMinutes(10);
+ telemetryDataSaubDto1.WellDepth = telemetryDataSaubDto.WellDepth + 1;
+
+ var telemetryDataSaubDto2 = telemetryDataSaubDto.Adapt();
+ telemetryDataSaubDto2.DateTime = DateTime.UtcNow.AddMinutes(20);
+ telemetryDataSaubDto2.WellDepth = telemetryDataSaubDto1.WellDepth + 1;
+
+ var telemetryDataSaubDto3 = telemetryDataSaubDto.Adapt();
+ telemetryDataSaubDto3.DateTime = DateTime.UtcNow.AddMinutes(30);
+ telemetryDataSaubDto3.WellDepth = telemetryDataSaubDto2.WellDepth + 1;
+
+ telemetryDataSaubDtos.Add(telemetryDataSaubDto1);
+ telemetryDataSaubDtos.Add(telemetryDataSaubDto2);
+ telemetryDataSaubDtos.Add(telemetryDataSaubDto3);
+ }
+
+ detectedOperationRepositoryMock
+ .Get(Arg.Any(), Arg.Any())
+ .Returns(detectedOperationDtos);
+
+ dataSaubStatRepositoryMock
+ .InsertRangeAsync(Arg.Any>(), Arg.Any())
+ .Returns(insertedDataSaubStatCount);
+
+ Action action = (message, percent) =>
+ {
+ //assert
+ Assert.NotNull(percent);
+ Assert.InRange(percent.Value, 0.0, 1.0);
+ };
+
+ //act
+ await dataSaubStatService.CreateStatAsync(Gap, action, CancellationToken.None);
+
+ //assert
+ await dataSaubStatRepositoryMock.Received().InsertRangeAsync(
+ Arg.Is>(l => l.Count() == insertedDataSaubStatCount),
+ Arg.Any());
+ }
+}
\ No newline at end of file
diff --git a/AsbCloudWebApi/Controllers/WellContactController.cs b/AsbCloudWebApi/Controllers/WellContactController.cs
index bdb6a7ae..1bd43564 100644
--- a/AsbCloudWebApi/Controllers/WellContactController.cs
+++ b/AsbCloudWebApi/Controllers/WellContactController.cs
@@ -1,5 +1,6 @@
using AsbCloudApp.Data;
using AsbCloudApp.Data.User;
+using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudDb.Model;
using Microsoft.AspNetCore.Authorization;
@@ -49,12 +50,43 @@ namespace AsbCloudWebApi.Controllers
///
[HttpGet("type/{contactTypeId}")]
[ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)]
- public async Task GetAllAsync(int idWell, int contactTypeId, CancellationToken token)
+ public async Task GetByTypeAsync(int idWell, int contactTypeId, CancellationToken token)
{
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
return Forbid();
- var result = await wellContactsRepository.GetAllAsync(idWell, contactTypeId, token);
+ var request = new WellContactRequest()
+ {
+ IdsWells = new int[] { idWell },
+ ContactTypeId = contactTypeId
+ };
+
+ var result = await wellContactsRepository.GetAllAsync(request, token);
+ return Ok(result);
+ }
+
+ ///
+ /// Получение контактов по массиву ключей скважины
+ ///
+ /// ключи скважин
+ ///
+ ///
+ [HttpGet("/api/well/[controller]")]
+ [ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)]
+ public async Task GetAllAsync([FromQuery] IEnumerable idsWells, CancellationToken token)
+ {
+ foreach(var idWell in idsWells)
+ {
+ if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
+ return Forbid();
+ }
+
+ var request = new WellContactRequest()
+ {
+ IdsWells = idsWells
+ };
+
+ var result = await wellContactsRepository.GetAllAsync(request, token);
return Ok(result);
}
diff --git a/AsbCloudWebApi/Controllers/WellOperationController.cs b/AsbCloudWebApi/Controllers/WellOperationController.cs
index eda82a08..90b7404f 100644
--- a/AsbCloudWebApi/Controllers/WellOperationController.cs
+++ b/AsbCloudWebApi/Controllers/WellOperationController.cs
@@ -187,7 +187,7 @@ public class WellOperationController : ControllerBase
[HttpGet]
[Permission]
[ProducesResponseType(typeof(PaginationContainer), StatusCodes.Status200OK)]
- public async Task GetPageOperationsAsync(
+ public async Task GetPageAsync(
[FromRoute] int idWell,
[FromQuery] WellOperationRequestBase request,
CancellationToken token)
@@ -201,6 +201,37 @@ public class WellOperationController : ControllerBase
return Ok(result);
}
+ ///
+ /// Получение страницу с нужной операцией
+ ///
+ /// id скважины
+ /// id операции
+ /// тип получаемых операций
+ /// кол-во записей на странице
+ /// параметры сортировки страниц
+ ///
+ ///
+ [HttpGet("getPageWithOperation")]
+ [Permission]
+ [ProducesResponseType(typeof(PaginationContainer), StatusCodes.Status200OK)]
+ public async Task GetPageWithOperationAsync([FromRoute] int idWell,
+ int id,
+ int operationType,
+ int? take,
+ [FromQuery] IEnumerable? sortFields,
+ CancellationToken token)
+ {
+ if (!await CanUserAccessToWellAsync(idWell, token))
+ return Forbid();
+
+ var paginationContainer = await wellOperationRepository.GetPageAsync(idWell, id, operationType, take, sortFields, token);
+
+ if (paginationContainer == null)
+ return NoContent();
+
+ return Ok(paginationContainer);
+ }
+
///
/// Создает excel файл с "сетевым графиком"
///