diff --git a/AsbCloudApp/Requests/TelemetryRequest.cs b/AsbCloudApp/Requests/TelemetryRequest.cs new file mode 100644 index 00000000..66b43cb5 --- /dev/null +++ b/AsbCloudApp/Requests/TelemetryRequest.cs @@ -0,0 +1,59 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace AsbCloudApp.Requests; + +/// +/// Параметры запроса телеметрии +/// +public class TelemetryDataRequest +{ + /// + /// Максимально допустимое кол-во строк данных + /// + public const int MaxTake = 3072; + + /// + /// greater or equal then Date + /// + public DateTimeOffset? GeDate { get; set; } + + /// + /// less or equal then Date + /// + public DateTimeOffset? LeDate { get; set; } + + /// + /// Делитель для прореживания выборки. + /// + /// 1 - без прореживания (default); + /// 2 - каждое 2-е значение; + /// 10 - каждое 10-е значение; + /// + /// + [Range(0, 300)] + public int Divider { get; set; } = 1; + + /// + /// сортировка/выравнивание данных в запросе по дате + /// + /// 0 - более ранние данные вперед; + /// 1 - более поздние данные вперед; + /// + /// + [Range(0, 1)] + public int Order { get; set; } = 0; + + /// + /// Пропустить с начала + /// + [Range(0, int.MaxValue)] + public int Skip { get; set; } = 0; + + /// + /// Кол-во возвращаемых, но не больше MaxTake + /// + [Range(1, MaxTake)] + public int Take { get; set; } = 1024; + +} diff --git a/AsbCloudApp/Services/ITelemetryDataService.cs b/AsbCloudApp/Services/ITelemetryDataService.cs index c1704509..a2034c7f 100644 --- a/AsbCloudApp/Services/ITelemetryDataService.cs +++ b/AsbCloudApp/Services/ITelemetryDataService.cs @@ -1,4 +1,5 @@ using AsbCloudApp.Data; +using AsbCloudApp.Requests; using System; using System.Collections.Generic; using System.Threading; @@ -25,6 +26,7 @@ namespace AsbCloudApp.Services Task> GetAsync(int idWell, DateTime dateBegin = default, double intervalSec = 600d, int approxPointsCount = 1024, CancellationToken token = default); + Task> GetAsync(int idWell, TelemetryDataRequest request, CancellationToken token); /// /// Получение статистики за период diff --git a/AsbCloudInfrastructure/Services/AutoGeneratedDailyReports/AutoGeneratedDailyReportService.cs b/AsbCloudInfrastructure/Services/AutoGeneratedDailyReports/AutoGeneratedDailyReportService.cs index 03a19c44..0e364319 100644 --- a/AsbCloudInfrastructure/Services/AutoGeneratedDailyReports/AutoGeneratedDailyReportService.cs +++ b/AsbCloudInfrastructure/Services/AutoGeneratedDailyReports/AutoGeneratedDailyReportService.cs @@ -66,8 +66,6 @@ public class AutoGeneratedDailyReportService : IAutoGeneratedDailyReportService if (datesRange is null) return result; - - result.Count = (int)(Math.Ceiling((datesRange.To - DateTime.UnixEpoch).TotalDays) - Math.Floor((datesRange.From - DateTime.UnixEpoch).TotalDays)); if (request.StartDate.HasValue) { @@ -87,6 +85,9 @@ public class AutoGeneratedDailyReportService : IAutoGeneratedDailyReportService datesRange.To = finishDate; } + if (datesRange.From.AddDays(result.Skip) <= datesRange.To) + result.Count = (int)(Math.Ceiling((datesRange.To - DateTime.UnixEpoch).TotalDays) - Math.Floor((datesRange.From - DateTime.UnixEpoch).TotalDays)); + for (int day = result.Skip; (day - result.Skip) < result.Take && (datesRange.From.AddDays(day)) <= datesRange.To; day++) { var reportDate = DateOnly.FromDateTime(datesRange.From.AddDays(day)); @@ -149,8 +150,8 @@ public class AutoGeneratedDailyReportService : IAutoGeneratedDailyReportService return new DatesRangeDto { - From = factOperations.Min(o => o.DateStart), - To = factOperations.Max(o => o.DateStart) + From = factOperations.Min(o => o.DateStart).Date, + To = factOperations.Max(o => o.DateStart).Date }; } diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs index 8d76ee70..bfb173da 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataBaseService.cs @@ -1,4 +1,5 @@ using AsbCloudApp.Data; +using AsbCloudApp.Exceptions; using AsbCloudApp.Services; using AsbCloudDb; using AsbCloudDb.Model; @@ -137,10 +138,67 @@ namespace AsbCloudInfrastructure.Services.SAUB } var entities = await query - .OrderBy(d => d.DateTime) .AsNoTracking() - .ToListAsync(token) - .ConfigureAwait(false); + .ToArrayAsync(token); + + var dtos = entities.Select(e => Convert(e, timezone.Hours)); + + return dtos; + } + + /// + public virtual async Task> GetAsync(int idWell, AsbCloudApp.Requests.TelemetryDataRequest request, CancellationToken token) + { + var telemetry = telemetryService.GetOrDefaultTelemetryByIdWell(idWell); + if (telemetry is null) + return Enumerable.Empty(); + + var timezone = telemetryService.GetTimezone(telemetry.Id); + + var cache = telemetryDataCache.GetOrDefault(telemetry.Id, request); + if(cache is not null) + return cache; + + var dbSet = db.Set(); + + var query = dbSet + .Where(d => d.IdTelemetry == telemetry.Id) + .AsNoTracking(); + + if (request.GeDate.HasValue) + { + var geDate = request.GeDate.Value.UtcDateTime; + query = query.Where(d => d.DateTime >= geDate); + } + + if (request.LeDate.HasValue) + { + var leDate = request.LeDate.Value.UtcDateTime; + query = query.Where(d => d.DateTime <= leDate); + } + + if (request.Divider > 1) + query = query.Where((d) => (((d.DateTime.DayOfYear * 24 + d.DateTime.Hour) * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % request.Divider == 0); + + switch (request.Order) + { + case 1:// Поздние вперед + query = query + .OrderByDescending(d => d.DateTime) + .Skip(request.Skip) + .Take(request.Take) + .OrderBy(d => d.DateTime); + break; + default:// Ранние вперед + query = query + .OrderBy(d => d.DateTime) + .Skip(request.Skip) + .Take(request.Take); + break; + } + + var entities = await query + .ToArrayAsync(token); var dtos = entities.Select(e => Convert(e, timezone.Hours)); diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs index 53089f17..c99b6c95 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs @@ -11,6 +11,7 @@ using Microsoft.Extensions.DependencyInjection; using AsbCloudInfrastructure.Background; using System.Threading; using AsbCloudApp.Data; +using AsbCloudApp.Requests; namespace AsbCloudInfrastructure.Services.SAUB { @@ -21,6 +22,7 @@ namespace AsbCloudInfrastructure.Services.SAUB { public TDto? FirstByDate { get; init; } public CyclycArray LastData { get; init; } = null!; + public double TimezoneHours { get; init; } = 5; } private IServiceProvider provider = null!; @@ -225,8 +227,62 @@ namespace AsbCloudInfrastructure.Services.SAUB { FirstByDate = first, LastData = cacheItem, + TimezoneHours = hoursOffset, }; return item; } + + public IEnumerable? GetOrDefault(int idTelemetry, TelemetryDataRequest request) + { + if (!caches.TryGetValue(idTelemetry, out TelemetryDataCacheItem? cacheItem)) + return null; + + IEnumerable data = cacheItem.LastData; + + if (!data.Any()) + return null; + + if (request.GeDate.HasValue) + { + var geDate = request.GeDate.Value.ToRemoteDateTime(cacheItem.TimezoneHours); + if (data.First().DateTime > geDate) + return null; + + data = data.Where(d => d.DateTime >= geDate); + } + else + { + if (request.Order == 0) + return null; + } + + if (request.LeDate.HasValue) + { + var leDate = request.LeDate.Value.ToRemoteDateTime(cacheItem.TimezoneHours); + data = data.Where(d => d.DateTime >= request.LeDate); + } + + if (request.Divider > 1) + data = data.Where((d) => (((d.DateTime.DayOfYear * 24 + d.DateTime.Hour) * 60 + d.DateTime.Minute) * 60 + d.DateTime.Second) % request.Divider == 0); + + switch (request.Order) + { + case 1: // Поздние вперед + data = data + .OrderByDescending(d => d.DateTime) + .Skip(request.Skip) + .Take(request.Take) + .OrderBy(d => d.DateTime); + break; + default: // Ранние вперед + data = data + .OrderBy(d => d.DateTime) + .Skip(request.Skip) + .Take(request.Take); + break; + } + + return data; + } } } diff --git a/AsbCloudInfrastructure/Services/WellContactService.cs b/AsbCloudInfrastructure/Services/WellContactService.cs index a8e280da..261ed9f9 100644 --- a/AsbCloudInfrastructure/Services/WellContactService.cs +++ b/AsbCloudInfrastructure/Services/WellContactService.cs @@ -29,18 +29,21 @@ namespace AsbCloudInfrastructure.Services { Caption = c.Caption, Id = c.Id, - Users = c.Users.Select(u => new UserContactDto() - { - Id = u.Id, - Name = u.Name, - Patronymic = u.Patronymic, - Surname = u.Surname, - Company = u.Company.Adapt(), - Email = u.Email, - Phone = u.Phone, - Position = u.Position, - IsContact = u.RelationContactsWells.Any(rel => rel.IdWell == wellId) - }) + Users = c.Users + .Where(u => u.IdState == 1) + .OrderBy(u => u.Surname) + .Select(u => new UserContactDto() + { + Id = u.Id, + Name = u.Name, + Patronymic = u.Patronymic, + Surname = u.Surname, + Company = u.Company.Adapt(), + Email = u.Email, + Phone = u.Phone, + Position = u.Position, + IsContact = u.RelationContactsWells.Any(rel => rel.IdWell == wellId) + }) }); var entities = await query.AsNoTracking() diff --git a/AsbCloudInfrastructure/Services/WellboreService.cs b/AsbCloudInfrastructure/Services/WellboreService.cs index 79ef8a3c..5e0e439e 100644 --- a/AsbCloudInfrastructure/Services/WellboreService.cs +++ b/AsbCloudInfrastructure/Services/WellboreService.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -58,8 +59,8 @@ public class WellboreService : IWellboreService Id = group.Key, Name = sections[group.Key].Caption, Well = well.Adapt(), - DateStart = group.Min(operation => operation.DateStart), - DateEnd = group.Max(operation => operation.DateStart.AddHours(operation.DurationHours)), + DateStart = group.Min(operation => operation.DateStart).ToUtcDateTimeOffset(well.Timezone.Hours).ToOffset(TimeSpan.FromHours(well.Timezone.Hours)), + DateEnd = group.Max(operation => operation.DateStart.AddHours(operation.DurationHours)).ToUtcDateTimeOffset(well.Timezone.Hours).ToOffset(TimeSpan.FromHours(well.Timezone.Hours)), DepthStart = group.Min(operation => operation.DepthStart), DepthEnd = group.Max(operation => operation.DepthEnd), }); diff --git a/AsbCloudWebApi/Controllers/SAUB/TelemetryDataBaseController.cs b/AsbCloudWebApi/Controllers/SAUB/TelemetryDataBaseController.cs index f80693a1..cd9eb7b5 100644 --- a/AsbCloudWebApi/Controllers/SAUB/TelemetryDataBaseController.cs +++ b/AsbCloudWebApi/Controllers/SAUB/TelemetryDataBaseController.cs @@ -1,4 +1,5 @@ using AsbCloudApp.Data; +using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudWebApi.SignalR; using Microsoft.AspNetCore.Authorization; @@ -96,6 +97,36 @@ namespace AsbCloudWebApi.Controllers.SAUB return Ok(content); } + /// + /// Новая версия. Возвращает данные САУБ по скважине. + /// По умолчанию за последние 10 минут. + /// + /// id скважины + /// + /// Токен завершения задачи + /// + [HttpGet("{idWell}/data")] + [Permission] + public virtual async Task>> GetData2Async(int idWell, + [FromQuery]TelemetryDataRequest request, + CancellationToken token) + { + int? idCompany = User.GetCompanyId(); + + if (idCompany is null) + return Forbid(); + + bool isCompanyOwnsWell = await wellService.IsCompanyInvolvedInWellAsync((int)idCompany, + idWell, token).ConfigureAwait(false); + + if (!isCompanyOwnsWell) + return Forbid(); + + var content = await telemetryDataService.GetAsync(idWell, request, token); + + return Ok(content); + } + /// /// Возвращает диапазон дат за которые есть телеметрия за период времени ///