diff --git a/AsbCloudApp/Data/Subsystems/SubsystemDto.cs b/AsbCloudApp/Data/Subsystems/SubsystemDto.cs index 7bf2c0b6..515c69a7 100644 --- a/AsbCloudApp/Data/Subsystems/SubsystemDto.cs +++ b/AsbCloudApp/Data/Subsystems/SubsystemDto.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace AsbCloudApp.Data.Subsystems +namespace AsbCloudApp.Data.Subsystems { /// /// Описание параметров подсистемы diff --git a/AsbCloudApp/Data/Subsystems/SubsystemOperationTimeDto.cs b/AsbCloudApp/Data/Subsystems/SubsystemOperationTimeDto.cs index ccb923d7..98047c84 100644 --- a/AsbCloudApp/Data/Subsystems/SubsystemOperationTimeDto.cs +++ b/AsbCloudApp/Data/Subsystems/SubsystemOperationTimeDto.cs @@ -1,9 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - namespace AsbCloudApp.Data.Subsystems { /// @@ -15,17 +10,14 @@ namespace AsbCloudApp.Data.Subsystems /// Идентификатор /// public int Id { get; set; } - /// - /// ИД телеметрии по которой выдается информация - /// - public int IdTelemetry { get; set; } - public TelemetryBaseDto Telemetry { get; set; } - /// /// идентификатор подсистемы /// public int IdSubsystem { get; set; } - public SubsystemDto Subsystem { get; set; } + /// + /// Название подсистемы + /// + public string SubsystemName { get; set; } /// /// дата/время включения подсистемы /// @@ -42,7 +34,5 @@ namespace AsbCloudApp.Data.Subsystems /// глубина забоя на момент выключения подсистемы /// public double DepthEnd { get; set; } - - } } diff --git a/AsbCloudApp/Data/Subsystems/SubsystemStatDto.cs b/AsbCloudApp/Data/Subsystems/SubsystemStatDto.cs index 4ef6d98d..8e6f8bf4 100644 --- a/AsbCloudApp/Data/Subsystems/SubsystemStatDto.cs +++ b/AsbCloudApp/Data/Subsystems/SubsystemStatDto.cs @@ -1,17 +1,11 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - namespace AsbCloudApp.Data.Subsystems { /// /// Статистика подсистемы /// public class SubsystemStatDto - { - + { /// /// Идентификатор подсистемы /// diff --git a/AsbCloudApp/Data/Subsystems/SubsystemsSpinWithDepthDto.cs b/AsbCloudApp/Data/Subsystems/SubsystemsSpinWithDepthDto.cs new file mode 100644 index 00000000..196d3ac9 --- /dev/null +++ b/AsbCloudApp/Data/Subsystems/SubsystemsSpinWithDepthDto.cs @@ -0,0 +1,30 @@ +using System; +namespace AsbCloudDb.Model.Subsystems +{ + /// + /// Результат запроса в t_telemetry_data_spin, используется фоновым сервисом анализирующим наработки подсистем + /// + public class SubsystemsSpinWithDepthDto + { + /// + /// Режим работы + /// + public short Mode { get; set; } + /// + /// Состояние + /// + public int State { get; set; } + /// + /// Дата + /// + public DateTimeOffset Date { get; set; } + /// + /// Глубина забоя + /// + public float Depth { get; set; } + /// + /// ИД + /// + public int IdSubsystem { get; set; } + } +} diff --git a/AsbCloudDb/Model/DefaultData/DefaultData.cs b/AsbCloudDb/Model/DefaultData/DefaultData.cs index bc405ecb..0bfe29a7 100644 --- a/AsbCloudDb/Model/DefaultData/DefaultData.cs +++ b/AsbCloudDb/Model/DefaultData/DefaultData.cs @@ -22,6 +22,7 @@ namespace AsbCloudDb.Model.DefaultData new EntityFillerWellType(), new EntityFillerMeasureCategory(), new EntityFillerCompanyType(), + new EntityFillerSubsystem(), }; foreach (var filler in fillers) diff --git a/AsbCloudDb/Model/DefaultData/EntityFillerSubsystem.cs b/AsbCloudDb/Model/DefaultData/EntityFillerSubsystem.cs new file mode 100644 index 00000000..9e32c4ed --- /dev/null +++ b/AsbCloudDb/Model/DefaultData/EntityFillerSubsystem.cs @@ -0,0 +1,24 @@ +using AsbCloudDb.Model.Subsystems; +namespace AsbCloudDb.Model.DefaultData +{ + internal class EntityFillerSubsystem : EntityFiller + { + protected override Subsystem[] GetData() => new Subsystem[]{ + // САУБ - ид подсистем с 1 до 65_535 + new () {Id = 1, Name = "Ручной", Description = "Ручной"}, + new () {Id = 2, Name = "Бурение в роторе", Description = "Бурение в роторе"}, + new () {Id = 3, Name = "Проработка", Description = "Проработка"}, + new () {Id = 4, Name = "Бурение в слайде", Description = "Бурение в слайде"}, + new () {Id = 5, Name = "Спуск СПО", Description = "Спуск СПО"}, + new () {Id = 6, Name = "Подъем СПО", Description = "Подъем СПО"}, + new () {Id = 7, Name = "Подъем с проработкой", Description = "Подъем с проработкой"}, + new () {Id = 11, Name = "Блокировка", Description = "Блокировка"}, + + //Spin master - id подсистем с 65_536 до 131_071 + new () {Id = 65536, Name = "Spin master", Description = "Spin master"}, + new () {Id = 65537, Name = "Torque master", Description = "Torque master"} + + + }; + } +} diff --git a/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeBackgroundService.cs b/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeBackgroundService.cs index ca25f361..f70e181d 100644 --- a/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeBackgroundService.cs +++ b/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeBackgroundService.cs @@ -6,6 +6,8 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using System; using System.Collections.Generic; +using System.Data; +using System.Data.Common; using System.Diagnostics; using System.Linq; using System.Text; @@ -18,10 +20,12 @@ namespace AsbCloudInfrastructure.Services.Subsystems { private readonly string connectionString; private readonly TimeSpan period = TimeSpan.FromHours(1); + private const int idSubsytemTorqueMaster = 65537; + private const int idSubsytemSpinMaster = 65536; + public SubsystemOperationTimeBackgroundService(IConfiguration configuration) { connectionString = configuration.GetConnectionString("DefaultConnection"); - } protected override async Task ExecuteAsync(CancellationToken token) { @@ -39,7 +43,7 @@ namespace AsbCloudInfrastructure.Services.Subsystems { using var context = new AsbCloudDbContext(options); var added = await OperationTimeAllTelemetriesAsync(context, token); - Trace.TraceInformation($"Total operation time subsystem complete. Added {added} operations time."); + Trace.TraceInformation($"Total subsystem operation time complete. Added {added} operations time."); } catch (Exception ex) { @@ -60,7 +64,7 @@ namespace AsbCloudInfrastructure.Services.Subsystems private static async Task OperationTimeAllTelemetriesAsync(IAsbCloudDbContext db, CancellationToken token) { - var lastDetectedDates = await db.DetectedOperations + var lastDetectedDates = await db.SubsystemOperationTimes .GroupBy(o => o.IdTelemetry) .Select(g => new { @@ -87,19 +91,19 @@ namespace AsbCloudInfrastructure.Services.Subsystems foreach (var item in JounedlastDetectedDates) { var stopwatch = Stopwatch.StartNew(); - var newOperationsSaub = await OperationTimeSaubAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token); - //var newOperationsSpin = await OperationTimeSpinAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token); + var newOperationsSaub = await OperationTimeSaubAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token); stopwatch.Stop(); - if (newOperationsSaub.Any()) + if (newOperationsSaub is not null && newOperationsSaub.Any()) { db.SubsystemOperationTimes.AddRange(newOperationsSaub); affected += await db.SaveChangesAsync(token); } - //if (newOperationsSpin.Any()) - //{ - // db.SubsystemOperationTimes.AddRange(newOperationsSpin); - // affected += await db.SaveChangesAsync(token); - //} + var newOperationsSpin = await OperationTimeSpinAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token); + if (newOperationsSpin is not null && newOperationsSpin.Any()) + { + db.SubsystemOperationTimes.AddRange(newOperationsSpin); + affected += await db.SaveChangesAsync(token); + } } return affected; } @@ -115,8 +119,7 @@ namespace AsbCloudInfrastructure.Services.Subsystems Mode = d.Mode, Depth = d.WellDepth }) - .OrderBy(d => d.DateTime); - + .OrderBy(d => d.DateTime); var take = 4 * 86_400; // 4 дня var startDate = begin; var firstItem = query.FirstOrDefault(); @@ -125,8 +128,7 @@ namespace AsbCloudInfrastructure.Services.Subsystems short? mode = firstItem.Mode; DateTimeOffset dateBegin = firstItem.DateTime; float? depthStart = firstItem.Depth; - var resultSubsystemOperationTime = new List(); - + var resultSubsystemOperationTime = new List(); var data = await query .Where(d => d.DateTime > startDate) .Take(take) @@ -139,11 +141,10 @@ namespace AsbCloudInfrastructure.Services.Subsystems { IdTelemetry = idTelemetry, DateStart = dateBegin, - IdSubsystem = (int)data[i - 1].Mode, + IdSubsystem = (int)data[i - 1].Mode + 1, DateEnd = data[i - 1].DateTime, DepthStart = depthStart, DepthEnd = data[i - 1].Depth - }; resultSubsystemOperationTime.Add(operationTimeItem); mode = data[i].Mode; @@ -151,64 +152,97 @@ namespace AsbCloudInfrastructure.Services.Subsystems depthStart = data[i].Depth; } } - startDate = data.Last().DateTime; - + startDate = data.Last().DateTime; return resultSubsystemOperationTime; } - - private static async Task> OperationTimeSpinAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token) { - var query = db.TelemetryDataSpin - .AsNoTracking() - .Where(d => d.IdTelemetry == idTelemetry) - .Select(d => new + Predicate isSubsystemTorqueState = (int state) => state == 7; + Predicate isSubsystemTorqueMode = (short mode) => (mode & 2) > 0; + Predicate isSubsystemSpin = (int state) => state != 0 & state != 6 & state != 7; + var operationTimeSpinWithDepth = + $"select tspin.\"date\", tspin.\"mode\", tspin.\"state\", tsaub.\"well_depth\"" + + $" from (select \"date\" ,\"mode\" ,lag(mode, 1) over (order by \"date\") as mode_pre, state , " + + $"lag(state, 1) over (order by \"date\") as state_pre from t_telemetry_data_spin where id_telemetry = {idTelemetry}) as tspin " + + $"join (select \"date\", well_depth from t_telemetry_data_saub where id_telemetry = {idTelemetry}) as tsaub " + + $"on EXTRACT(EPOCH from tspin.date) = EXTRACT(EPOCH from tsaub.date) " + + $"where mode!=mode_pre or state != state_pre order by \"date\";"; + using var command = db.Database.GetDbConnection().CreateCommand(); + command.CommandText = operationTimeSpinWithDepth; + db.Database.OpenConnection(); + using var result = command.ExecuteReader(); + var query = new List(); + //DataTable dt = new DataTable(); + //dt.Load(result); + //var query = from c in dt.AsEnumerable() + // select new + // { + // Date = (DateTimeOffset)c["date"], + // Mode = (short)c["mode"], + // State = (int)c["state"], + // Depth = (float)c["float"] + // }; + if (result.HasRows) + while (result.Read()) { - DateTime = d.DateTime, - Mode = d.Mode, - Depth = db.TelemetryDataSaub.Where(t => t.DateTime == d.DateTime & t.IdTelemetry ==idTelemetry) - .GroupBy(t => t.IdTelemetry) - .Select(group => group.Min(t => t.WellDepth)) - .FirstOrDefault() - }) - .OrderBy(d => d.DateTime); - + var itemEntity = new SubsystemsSpinWithDepthDto() + { + Date = result.GetFieldValue(0), + Mode = result.GetFieldValue(1), + State = result.GetFieldValue(2), + Depth = result.GetFieldValue(3) + }; + int? subsystemId = isSubsystemTorqueState(itemEntity.State) && isSubsystemTorqueMode(itemEntity.Mode) + ? idSubsytemTorqueMaster + : isSubsystemSpin(itemEntity.State) + ? idSubsytemSpinMaster + : 0; + if (subsystemId.HasValue) + { + itemEntity.IdSubsystem = subsystemId.Value; + query.Add(itemEntity); + } + } var take = 4 * 86_400; // 4 дня var startDate = begin; var firstItem = query.FirstOrDefault(); if (firstItem is null) - return null; - short? mode = firstItem.Mode; - DateTimeOffset dateBegin = firstItem.DateTime; + return null; + int idSubsystem = firstItem.IdSubsystem; + DateTimeOffset dateBegin = firstItem.Date; float? depthStart = firstItem.Depth; var resultSubsystemOperationTime = new List(); - var data = await query - .Where(d => d.DateTime > startDate) + var data = query + .Where(d => d.Date > startDate) .Take(take) - .ToArrayAsync(token); + .ToArray(); + if (data.Length==0) + return null; for (int i = 1; i < data.Length; i++) { - if (data[i].Mode != mode) + if (data[i].IdSubsystem != idSubsystem) { var operationTimeItem = new SubsystemOperationTime() { IdTelemetry = idTelemetry, DateStart = dateBegin, - IdSubsystem = (int)data[i - 1].Mode, - DateEnd = data[i - 1].DateTime, + IdSubsystem = data[i - 1].IdSubsystem, + DateEnd = data[i - 1].Date, DepthStart = depthStart, DepthEnd = data[i - 1].Depth - }; - resultSubsystemOperationTime.Add(operationTimeItem); - mode = data[i].Mode; - dateBegin = data[i].DateTime; + }; + dateBegin = data[i].Date; depthStart = data[i].Depth; + idSubsystem = data[i].IdSubsystem; + if (data[i-1].IdSubsystem != 0) + { + resultSubsystemOperationTime.Add(operationTimeItem); + } } - } - startDate = data.Last().DateTime; - + } + startDate = data.LastOrDefault().Date; return resultSubsystemOperationTime; } } diff --git a/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeService.cs b/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeService.cs index 2a793d1a..ff379581 100644 --- a/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeService.cs +++ b/AsbCloudInfrastructure/Services/Subsystems/SubsystemOperationTimeService.cs @@ -1,11 +1,11 @@ -using AsbCloudApp.Data.Subsystems; +using AsbCloudApp.Data; +using AsbCloudApp.Data.Subsystems; using AsbCloudApp.Requests; using AsbCloudApp.Services; using AsbCloudApp.Services.Subsystems; using AsbCloudDb; using AsbCloudDb.Model; using AsbCloudDb.Model.Subsystems; -using AsbCloudInfrastructure.Repository; using Mapster; using Microsoft.EntityFrameworkCore; using System; @@ -23,9 +23,6 @@ namespace AsbCloudInfrastructure.Services.Subsystems private readonly IAsbCloudDbContext db; private readonly IWellService wellService; private readonly ICrudService subsystemService; - - - public SubsystemOperationTimeService(IAsbCloudDbContext db, IWellService wellService, ICrudService subsystemService) { this.db = db; @@ -33,7 +30,7 @@ namespace AsbCloudInfrastructure.Services.Subsystems this.subsystemService = subsystemService; } - private async Task> GetSubsystemByIdWellAsync(int idWell, CancellationToken token) + private async Task?> GetSubsystemByIdWellAsync(int idWell, CancellationToken token) { var well = await wellService.GetOrDefaultAsync(idWell, token); if (well?.IdTelemetry is null || well.Timezone is null) @@ -53,39 +50,37 @@ namespace AsbCloudInfrastructure.Services.Subsystems .ToListAsync(token); return wellSubsystem; } - - public async Task> GetSubsystemAsync(int? idWell, CancellationToken token) + public async Task?> GetSubsystemAsync(int? idWell, CancellationToken token) { - if (idWell is null) + if (idWell.HasValue) { - var subsystem = await subsystemService.GetAllAsync(token); - return subsystem; - } - var subsystemWell = await GetSubsystemAsync(idWell, token); - return subsystemWell; - + var subsystemWell = await GetSubsystemByIdWellAsync(idWell.Value, token); + return subsystemWell; + } + var subsystem = await subsystemService.GetAllAsync(token); + return subsystem; } - - public async Task DeleteAsync(SubsystemOperationTimeRequest request, CancellationToken token) { var well = await wellService.GetOrDefaultAsync(request.IdWell, token); if (well?.IdTelemetry is null || well.Timezone is null) return 0; var query = BuildQuery(request); + if (query is null) + return 0; db.SubsystemOperationTimes.RemoveRange(query); return await db.SaveChangesAsync(token); } - public async Task> GetOperationTimeAsync(SubsystemOperationTimeRequest request, CancellationToken token) - { - var query = BuildQuery(request) - .AsNoTracking(); + public async Task?> GetOperationTimeAsync(SubsystemOperationTimeRequest request, CancellationToken token) + { + var well = await wellService.GetOrDefaultAsync(request.IdWell, token); + if (well?.IdTelemetry is null || well.Timezone is null) + return null; + var query = BuildQuery(request); if (query is null) return null; - var data = await query.ToListAsync(token); - if (request.SelectMode == SubsystemOperationTimeRequest.SelectModeInner) { if (request.GtDate is not null) @@ -100,22 +95,20 @@ namespace AsbCloudInfrastructure.Services.Subsystems var end = request.GtDate ?? throw new ArgumentNullException(nameof(request.LtDate)); data = Trim(data, begin,end ); } - var dtos = data.Select(o => Convert(o)); + var dtos = data.Select(o => Convert(o,well)); return dtos; } - - - public async Task?> GetStatAsync(SubsystemOperationTimeRequest request, CancellationToken token) { var data = await GetOperationTimeAsync(request, token); + if (data is null) + return null; var statList = CalcStat(data, request); return statList; } - private List Trim(List data, DateTime gtDate, DateTime ltDate) { - var itemsToTrim = data.Where(q => true) + var itemsToTrim = data.Where(q => q.DateStart == gtDate & q.DateEnd == ltDate) .Select(o => new SubsystemOperationTime { Id = o.Id, @@ -131,7 +124,6 @@ namespace AsbCloudInfrastructure.Services.Subsystems .ToList(); return itemsToTrim; } - private IEnumerable CalcStat(IEnumerable groupedData, SubsystemOperationTimeRequest request) { var result = new List(); @@ -151,8 +143,7 @@ namespace AsbCloudInfrastructure.Services.Subsystems var subsystemStat = new SubsystemStatDto() { IdSubsystem = idSubsystem, - Subsystem = subsystemService.GetOrDefault(idSubsystem)?.Name ?? "unknown", - //Subsystem = db.Subsystems.Where(n => n.Id == idSubsystem).FirstOrDefault()?.Name ?? "unknown", + Subsystem = subsystemService.GetOrDefault(idSubsystem)?.Name ?? "unknown", UsedTimeHours = TimeSpan.FromHours(periodGroup), KUsage = 1d*periodGroup / periodRequest, K2 = 1d*periodGroup / periodGroupTotal, @@ -161,8 +152,6 @@ namespace AsbCloudInfrastructure.Services.Subsystems } return result; } - - private IQueryable? BuildQuery(SubsystemOperationTimeRequest request) { var idTelemetry = wellService.GetOrDefault(request.IdWell)?.IdTelemetry; @@ -210,15 +199,13 @@ namespace AsbCloudInfrastructure.Services.Subsystems return query; } - - private SubsystemOperationTimeDto Convert(SubsystemOperationTime operationTime) + private SubsystemOperationTimeDto Convert(SubsystemOperationTime operationTime, WellDto well) { - var dto = operationTime.Adapt(); + var dto = operationTime.Adapt(); + dto.DateStart = operationTime.DateStart.ToRemoteDateTime(well.Timezone.Hours); + dto.DateEnd = operationTime.DateEnd.ToRemoteDateTime(well.Timezone.Hours); return dto; } - - - } #nullable disable } diff --git a/AsbCloudWebApi/Controllers/Subsystems/SubsystemOperationTimeController.cs b/AsbCloudWebApi/Controllers/Subsystems/SubsystemOperationTimeController.cs index ba75773a..e4d15ebc 100644 --- a/AsbCloudWebApi/Controllers/Subsystems/SubsystemOperationTimeController.cs +++ b/AsbCloudWebApi/Controllers/Subsystems/SubsystemOperationTimeController.cs @@ -19,13 +19,11 @@ namespace AsbCloudWebApi.Controllers.Subsystems [Authorize] public class SubsystemOperationTimeController : ControllerBase { - private readonly ISubsystemOperationTimeService subsystemOperationTimeService; - private readonly ICrudService subsystemService; + private readonly ISubsystemOperationTimeService subsystemOperationTimeService; private readonly IWellService wellService; - public SubsystemOperationTimeController(ISubsystemOperationTimeService subsystemOperationTimeService, ICrudService subsystemService, IWellService wellService) + public SubsystemOperationTimeController(ISubsystemOperationTimeService subsystemOperationTimeService, IWellService wellService) { - this.subsystemOperationTimeService = subsystemOperationTimeService; - this.subsystemService = subsystemService; + this.subsystemOperationTimeService = subsystemOperationTimeService; this.wellService = wellService; } ///