diff --git a/.gitignore b/.gitignore index 4ce6fdde..2e1bbda1 100644 --- a/.gitignore +++ b/.gitignore @@ -30,7 +30,7 @@ bld/ # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ +wwwroot/ # Visual Studio 2017 auto generated files Generated\ Files/ diff --git a/AsbCloudApp/Data/OperationDetailsDto.cs b/AsbCloudApp/Data/OperationDetailsDto.cs index a487df4e..2868357f 100644 --- a/AsbCloudApp/Data/OperationDetailsDto.cs +++ b/AsbCloudApp/Data/OperationDetailsDto.cs @@ -1,11 +1,8 @@ -using System; - -namespace AsbCloudApp.Data +namespace AsbCloudApp.Data { public class OperationDetailsDto { public string OperationName { get; set; } - public DateTime OperationStartTime { get; set; } - public double DurationHours { get; set; } + public int Duration { get; set; } } } diff --git a/AsbCloudApp/Data/OperationPercentageDto.cs b/AsbCloudApp/Data/OperationDurationDto.cs similarity index 51% rename from AsbCloudApp/Data/OperationPercentageDto.cs rename to AsbCloudApp/Data/OperationDurationDto.cs index 90c455b7..199f5634 100644 --- a/AsbCloudApp/Data/OperationPercentageDto.cs +++ b/AsbCloudApp/Data/OperationDurationDto.cs @@ -1,8 +1,8 @@ namespace AsbCloudApp.Data { - public class OperationPercentageDto + public class OperationDurationDto { public string ProcessName { get; set; } - public double Percentage { get; set; } + public double Duration { get; set; } } } diff --git a/AsbCloudApp/Data/OperationInfoDto.cs b/AsbCloudApp/Data/OperationInfoDto.cs index 0cfcb53e..fcc3bc08 100644 --- a/AsbCloudApp/Data/OperationInfoDto.cs +++ b/AsbCloudApp/Data/OperationInfoDto.cs @@ -6,7 +6,6 @@ namespace AsbCloudApp.Data public class OperationInfoDto { public DateTime IntervalBegin { get; set; } - public DateTime IntervalEnd { get; set; } - public IEnumerable OperationData { get; set; } + public IEnumerable Operations { get; set; } } } diff --git a/AsbCloudApp/Services/IAnalyticsService.cs b/AsbCloudApp/Services/IAnalyticsService.cs index 735c545f..9a8aea55 100644 --- a/AsbCloudApp/Services/IAnalyticsService.cs +++ b/AsbCloudApp/Services/IAnalyticsService.cs @@ -10,10 +10,10 @@ namespace AsbCloudApp.Services IEnumerable GetWellDepthToDay(int wellId); IEnumerable GetWellDepthToInterval(int wellId, int intervalHoursTimestamp, int workBeginTimestamp); - IEnumerable GetOperationsSummary(int wellId, - DateTime begin = default, DateTime end = default); - IEnumerable GetOperationsToTime(int wellId, + IEnumerable GetOperationsSummary(int wellId, DateTime begin = default, DateTime end = default); + IEnumerable GetOperationsToInterval(int wellId, + int intervalHoursTimestamp, int workBeginTimestamp); DrillingAnalysis GetDrillingAnalysis(IEnumerable dataSaubBases); } } diff --git a/AsbCloudDb/Model/DrillingAnalysis.cs b/AsbCloudDb/Model/DrillingAnalysis.cs index 8e171981..1b4ca234 100644 --- a/AsbCloudDb/Model/DrillingAnalysis.cs +++ b/AsbCloudDb/Model/DrillingAnalysis.cs @@ -20,6 +20,12 @@ namespace AsbCloudDb.Model [Column("date", TypeName = "timestamp with time zone"), Comment("'2021-10-19 18:23:54+05'")] public DateTime Date { get; set; } + [Column("unix_date", TypeName = "bigint"), Comment("Unix timestamp для Linq запросов с вычислением дат")] + public long UnixDate { get; set; } + + [Column("duration"), Comment("Кол-во секунд после предыдущей операции")] + public int Duration { get; set; } + [Column("id_operation")] public int? IdOperation { get; set; } diff --git a/AsbCloudInfrastructure/Services/AnalyticsService.cs b/AsbCloudInfrastructure/Services/AnalyticsService.cs index 986df4fc..fca59dfa 100644 --- a/AsbCloudInfrastructure/Services/AnalyticsService.cs +++ b/AsbCloudInfrastructure/Services/AnalyticsService.cs @@ -60,9 +60,6 @@ namespace AsbCloudInfrastructure.Services { intervalHoursTimestamp = intervalHoursTimestamp == 0 ? 86400 : intervalHoursTimestamp; - var intervalTime = new TimeSpan(0, 0, intervalHoursTimestamp); - var workDayBeginTime = new TimeSpan(0, 0, workBeginTimestamp); - var telemetry = telemetryService.GetTelemetryByWellId(wellId); if (telemetry is null) @@ -70,8 +67,8 @@ namespace AsbCloudInfrastructure.Services var timezoneOffset = telemetryService.GetTimezoneOffsetByTelemetryId(telemetry.Id); - var drillingPeriodsInfo = db.GetDepthToInterval(telemetry.Id, (int)intervalTime.TotalSeconds, - (int)workDayBeginTime.TotalSeconds, timezoneOffset); + var drillingPeriodsInfo = db.GetDepthToInterval(telemetry.Id, intervalHoursTimestamp, + workBeginTimestamp, timezoneOffset); var wellDepthToIntervalData = drillingPeriodsInfo.Select(d => new WellDepthToIntervalDto { @@ -82,191 +79,125 @@ namespace AsbCloudInfrastructure.Services return wellDepthToIntervalData; } - public IEnumerable GetOperationsSummary(int wellId, + public IEnumerable GetOperationsSummary(int wellId, DateTime begin = default, DateTime end = default) { - return new List - { - new OperationPercentageDto { ProcessName = "Роторное бурение", Percentage = 19.7 }, - new OperationPercentageDto { ProcessName = "Подъем с проработкой", Percentage = 6.2 }, - new OperationPercentageDto { ProcessName = "Спуск с проработкой", Percentage = 9.4 }, - new OperationPercentageDto { ProcessName = "Подъем с промывкой", Percentage = 18.4 }, - new OperationPercentageDto { ProcessName = "Неподвижное состояние", Percentage = 12.1 }, - new OperationPercentageDto { ProcessName = "Вращение без циркуляции", Percentage = 7.4 }, - new OperationPercentageDto { ProcessName = "Спуск в скважину", Percentage = 16.7 }, - new OperationPercentageDto { ProcessName = "На поверхности", Percentage = 10.1 } - }; + var telemetry = telemetryService.GetTelemetryByWellId(wellId); + + if (telemetry is null) + return null; + + var operations = (from a in db.DrillingAnalysis + where a.IdTelemetry == telemetry.Id && + a.Date > begin && a.Date < end && + a.IdOperation != null + join o in db.Operations on a.IdOperation equals o.Id + group a by new { a.IdOperation, o.Name } into g + select new OperationDurationDto + { + ProcessName = g.Key.Name, + Duration = g.Where(g => g.Duration > 0) + .Sum(a => a.Duration) + }).ToList(); + + return operations; } - public IEnumerable GetOperationsToTime(int wellId, - DateTime begin = default, DateTime end = default) + public IEnumerable GetOperationsToInterval(int wellId, + int intervalHoursTimestamp, int workBeginTimestamp) { - return new List - { - new OperationInfoDto - { - IntervalBegin = new DateTime(2021, 06, 01, 08, 00, 00), - IntervalEnd = new DateTime(2021, 06, 02, 08, 00, 00), - OperationData = new List - { - new OperationDetailsDto - { - OperationName = "Роторное бурение", - OperationStartTime = new DateTime(2021, 06, 01, 10, 00, 00), - DurationHours = 1.2 - }, - new OperationDetailsDto - { - OperationName = "Подъем с проработкой", - OperationStartTime = new DateTime(2021, 06, 01, 11, 00, 00), - DurationHours = 3.2 - }, - new OperationDetailsDto - { - OperationName = "Роторное бурение", - OperationStartTime = new DateTime(2021, 06, 01, 12, 00, 00), - DurationHours = 1.5 - }, - new OperationDetailsDto - { - OperationName = "Неподвижное состояние", - OperationStartTime = new DateTime(2021, 06, 01, 13, 00, 00), - DurationHours = 0.2 - }, - new OperationDetailsDto - { - OperationName = "Роторное бурение", - OperationStartTime = new DateTime(2021, 06, 01, 14, 00, 00), - DurationHours = 3.2 - } - } - }, - new OperationInfoDto - { - IntervalBegin = new DateTime(2021, 06, 02, 08, 00, 00), - IntervalEnd = new DateTime(2021, 06, 03, 08, 00, 00), - OperationData = new List - { - new OperationDetailsDto - { - OperationName = "На поверхности", - OperationStartTime = new DateTime(2021, 06, 13, 10, 01, 00), - DurationHours = 2.2 - }, - new OperationDetailsDto - { - OperationName = "Спуск в скважину", - OperationStartTime = new DateTime(2021, 06, 13, 11, 10, 00), - DurationHours = 0.4 - }, - new OperationDetailsDto - { - OperationName = "На поверхности", - OperationStartTime = new DateTime(2021, 06, 13, 12, 20, 00), - DurationHours = 2.5 - }, - new OperationDetailsDto - { - OperationName = "Вращение без циркуляции", - OperationStartTime = new DateTime(2021, 06, 13, 13, 00, 00), - DurationHours = 1.2 - }, - new OperationDetailsDto - { - OperationName = "Роторное бурение", - OperationStartTime = new DateTime(2021, 06, 13, 14, 00, 00), - DurationHours = 5.2 - } - } - }, - new OperationInfoDto - { - IntervalBegin = new DateTime(2021, 06, 03, 08, 00, 00), - IntervalEnd = new DateTime(2021, 06, 04, 08, 00, 00), - OperationData = new List - { - new OperationDetailsDto - { - OperationName = "Подъем с проработкой", - OperationStartTime = new DateTime(2021, 06, 12, 10, 00, 00), - DurationHours = 3.2 - }, - new OperationDetailsDto - { - OperationName = "Спуск с проработкой", - OperationStartTime = new DateTime(2021, 06, 12, 11, 00, 00), - DurationHours = 1.4 - }, - new OperationDetailsDto - { - OperationName = "Подъем с проработкой", - OperationStartTime = new DateTime(2021, 06, 12, 12, 00, 00), - DurationHours = 0.5 - }, - new OperationDetailsDto - { - OperationName = "На поверхности", - OperationStartTime = new DateTime(2021, 06, 12, 13, 00, 00), - DurationHours = 3.2 - }, - new OperationDetailsDto - { - OperationName = "Роторное бурение", - OperationStartTime = new DateTime(2021, 06, 13, 14, 00, 00), - DurationHours = 1.2 - } - } - } - }; + intervalHoursTimestamp = intervalHoursTimestamp == 0 ? 86400 : intervalHoursTimestamp; + + var telemetry = telemetryService.GetTelemetryByWellId(wellId); + + if (telemetry is null) + return null; + + var timezoneOffset = telemetryService.GetTimezoneOffsetByTelemetryId(telemetry.Id); + + var operations = (from a in db.DrillingAnalysis + where a.IdTelemetry == telemetry.Id && + a.IdOperation != null + join o in db.Operations on a.IdOperation equals o.Id + group a by new { + Interval = Math.Floor((a.UnixDate - workBeginTimestamp + timezoneOffset) / intervalHoursTimestamp), + OperationId = a.IdOperation, + o.Name } into g + select new + { + IntervalStart = g.Min(d => d.Date).Date, + OperationName = g.Key.Name, + OperationsDuration = g.Sum(an => an.Duration) + }).ToList(); + + var operationsGroupedByInterval = operations.GroupBy(op => op.IntervalStart) + .Select(o => new OperationInfoDto { + IntervalBegin = o.Key, + Operations = o.Select(opr => new OperationDetailsDto { + OperationName = opr.OperationName, + Duration = opr.OperationsDuration + }).ToList() + }) + .OrderBy(ops => ops.IntervalBegin); + + return operationsGroupedByInterval; } public DrillingAnalysis GetDrillingAnalysis(IEnumerable dataSaubBases) { - var saubWellDepths = dataSaubBases.Select(s => (s.WellDepth, - TotalSeconds: (s.Date - - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds - 1530000000)); - var saubBitDepths = dataSaubBases.Select(s => (s.BitDepth, - TotalSeconds: (s.Date - - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds - 1530000000)); - var saubBlockPositions = dataSaubBases.Select(s => (s.BlockPosition, - TotalSeconds: (s.Date - - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds - 1530000000)); - var saubRotorSpeeds = dataSaubBases.Select(s => (s.RotorSpeed, - TotalSeconds: (s.Date - - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds - 1530000000)); - var saubPressures = dataSaubBases.Select(s => (s.Pressure, - TotalSeconds: (s.Date - - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds - 1530000000)); - var saubHookWeights = dataSaubBases.Select(s => (s.HookWeight, - TotalSeconds: (s.Date - - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds - 1530000000)); + var lastSaubDate = dataSaubBases.Last().Date; - var wellDepthChangingIndex = GetAForLinearFormula(saubWellDepths); - var bitPositionChangingIndex = GetAForLinearFormula(saubBitDepths); - var blockPositionChangingIndex = GetAForLinearFormula(saubBlockPositions); - var rotorSpeedChangingIndex = GetAForLinearFormula(saubRotorSpeeds); - var pressureChangingIndex = GetAForLinearFormula(saubPressures); - var hookWeightChangingIndex = GetAForLinearFormula(saubHookWeights); + var saubWellDepths = dataSaubBases.Where(sw => sw.WellDepth is not null) + .Select(s => (Value: (double)s.WellDepth, + (s.Date - dataSaubBases.First().Date).TotalSeconds)); + var saubBitDepths = dataSaubBases.Where(sw => sw.BitDepth is not null) + .Select(s => (Value: (double)s.BitDepth, + (s.Date - dataSaubBases.First().Date).TotalSeconds)); + var saubBlockPositions = dataSaubBases.Where(sw => sw.BlockPosition is not null) + .Select(s => (Value: (double)s.BlockPosition, + (s.Date - dataSaubBases.First().Date).TotalSeconds)); + var saubRotorSpeeds = dataSaubBases.Where(sw => sw.RotorSpeed is not null) + .Select(s => (Value: (double)s.RotorSpeed, + (s.Date - dataSaubBases.First().Date).TotalSeconds)); + var saubPressures = dataSaubBases.Where(sw => sw.Pressure is not null) + .Select(s => (Value: (double)s.Pressure, + (s.Date - dataSaubBases.First().Date).TotalSeconds)); + var saubHookWeights = dataSaubBases.Where(sw => sw.HookWeight is not null) + .Select(s => (Value: (double)s.HookWeight, + (s.Date - dataSaubBases.First().Date).TotalSeconds)); + + var wellDepthChangingIndex = LinearFunctionCalculator.GetAForLinearFormula(saubWellDepths); + var bitPositionChangingIndex = LinearFunctionCalculator.GetAForLinearFormula(saubBitDepths); + var blockPositionChangingIndex = LinearFunctionCalculator.GetAForLinearFormula(saubBlockPositions); + var rotorSpeedChangingIndex = LinearFunctionCalculator.GetAForLinearFormula(saubRotorSpeeds); + var pressureChangingIndex = LinearFunctionCalculator.GetAForLinearFormula(saubPressures); + var hookWeightChangingIndex = LinearFunctionCalculator.GetAForLinearFormula(saubHookWeights); + + var IsBlockRising = LinearFunctionCalculator.IsValueGoesDown(blockPositionChangingIndex, -0.0001); + var IsBlockGoesDown = LinearFunctionCalculator.IsValueGoesUp(blockPositionChangingIndex, 0.0001); + var IsBlockStandsStill = LinearFunctionCalculator.IsValueNotChanges(blockPositionChangingIndex, (0.0001, -0.0001)); var drillingAnalysis = new DrillingAnalysis { IdTelemetry = dataSaubBases.First().IdTelemetry, - Date = dataSaubBases.Last().Date, - IsDepthChanges = wellDepthChangingIndex >= 0.0001 || wellDepthChangingIndex <= -0.0001, - IsDepthNotChanges = wellDepthChangingIndex < 0.0001 && wellDepthChangingIndex > -0.0001, - IsBitRising = bitPositionChangingIndex >= 0.0001, - IsBitGoesDown = bitPositionChangingIndex <= -0.0001, - IsBitStandsStill = bitPositionChangingIndex < 0.0001 && bitPositionChangingIndex > -0.0001, - IsBitDepthLess20 = (saubBitDepths.Sum(s => s.BitDepth) / saubBitDepths.Count()) < 20.0, - IsBlockRising = blockPositionChangingIndex >= 0.0001, - IsBlockGoesDown = blockPositionChangingIndex <= -0.0001, - IsBlockStandsStill = blockPositionChangingIndex < 0.001 && blockPositionChangingIndex > -0.0001, - IsRotorSpeedLess3 = (saubRotorSpeeds.Sum(s => s.RotorSpeed) / saubRotorSpeeds.Count()) < 3, - IsRotorSpeedMore3 = (saubRotorSpeeds.Sum(s => s.RotorSpeed) / saubRotorSpeeds.Count()) >= 3, - IsPressureLess20 = (saubPressures.Sum(s => s.Pressure) / saubPressures.Count()) < 20.0, - IsPressureMore20 = (saubPressures.Sum(s => s.Pressure) / saubPressures.Count()) >= 20.0, - IsHookWeightNotChanges = hookWeightChangingIndex < 0.0001 && hookWeightChangingIndex > 0.0001, - IsHookWeightLess3 = (saubHookWeights.Sum(s => s.HookWeight) / saubHookWeights.Count()) < 3.0, + Date = lastSaubDate, + UnixDate = (long)(lastSaubDate - new DateTime(1970,1,1,0,0,0)).TotalSeconds, + Duration = (int)(dataSaubBases.Last().Date - dataSaubBases.ElementAt(dataSaubBases.Count() - 2).Date).TotalSeconds, + IsDepthChanges = LinearFunctionCalculator.IsValueChanges(wellDepthChangingIndex, (0.0001, -0.0001)), + IsDepthNotChanges = LinearFunctionCalculator.IsValueNotChanges(wellDepthChangingIndex, (0.0001, -0.0001)), + IsBitRising = LinearFunctionCalculator.IsValueGoesDown(bitPositionChangingIndex, -0.0001), + IsBitGoesDown = LinearFunctionCalculator.IsValueGoesUp(bitPositionChangingIndex, 0.0001), + IsBitStandsStill = LinearFunctionCalculator.IsValueNotChanges(bitPositionChangingIndex, (0.0001, -0.0001)), + IsBitDepthLess20 = LinearFunctionCalculator.IsAverageLessThanBound(saubBitDepths, 20), + IsBlockRising = LinearFunctionCalculator.IsValueGoesDown(blockPositionChangingIndex, -0.0001), + IsBlockGoesDown = LinearFunctionCalculator.IsValueGoesUp(blockPositionChangingIndex, 0.0001), + IsBlockStandsStill = LinearFunctionCalculator.IsValueNotChanges(blockPositionChangingIndex, (0.0001, -0.0001)), + IsRotorSpeedLess3 = LinearFunctionCalculator.IsAverageLessThanBound(saubRotorSpeeds, 3), + IsRotorSpeedMore3 = LinearFunctionCalculator.IsAverageMoreThanBound(saubRotorSpeeds, 3), + IsPressureLess20 = LinearFunctionCalculator.IsAverageLessThanBound(saubPressures, 20), + IsPressureMore20 = LinearFunctionCalculator.IsAverageMoreThanBound(saubPressures, 20), + IsHookWeightNotChanges = LinearFunctionCalculator.IsValueNotChanges(hookWeightChangingIndex, (0.0001, -0.0001)), + IsHookWeightLess3 = LinearFunctionCalculator.IsAverageLessThanBound(saubHookWeights, 3), IdOperation = 1 }; @@ -275,7 +206,7 @@ namespace AsbCloudInfrastructure.Services return drillingAnalysis; } - private static double GetAForLinearFormula(IEnumerable<(double? x, double y)> rawData) + private static double GetAForLinearFormula(IEnumerable<(double?, double)> rawData) { var (xSum, ySum, xySum, x2Sum) = GetFormulaVariables(rawData); diff --git a/AsbCloudInfrastructure/Services/DataService.cs b/AsbCloudInfrastructure/Services/DataService.cs index a1d472f1..43c0c52b 100644 --- a/AsbCloudInfrastructure/Services/DataService.cs +++ b/AsbCloudInfrastructure/Services/DataService.cs @@ -103,8 +103,10 @@ namespace AsbCloudInfrastructure.Services if (saubDataCache.GetOrCreateCache(dataSaub.IdTelemetry).Count() > 1) { - var drillingAnalysis = analyticsService.GetDrillingAnalysis( - saubDataCache.GetOrCreateCache(dataSaub.IdTelemetry)); + var dataSaubs = saubDataCache.GetOrCreateCache(dataSaub.IdTelemetry) + .OrderBy(d => d.Date); + + var drillingAnalysis = analyticsService.GetDrillingAnalysis(dataSaubs); db.DrillingAnalysis.Add(drillingAnalysis); } diff --git a/AsbCloudInfrastructure/Services/LinearFunctionCalculator.cs b/AsbCloudInfrastructure/Services/LinearFunctionCalculator.cs new file mode 100644 index 00000000..5f905b67 --- /dev/null +++ b/AsbCloudInfrastructure/Services/LinearFunctionCalculator.cs @@ -0,0 +1,66 @@ +using System.Collections.Generic; +using System.Linq; + +namespace AsbCloudInfrastructure.Services +{ + public static class LinearFunctionCalculator + { + public static double GetAForLinearFormula(IEnumerable<(double value, double timestamp)> rawData) + { + var (xSum, ySum, xySum, x2Sum) = GetFormulaVariables(rawData); + + var result = (xSum * ySum - rawData.Count() * xySum) / + (xSum * xSum - rawData.Count() * x2Sum); + + return (double)result; + } + + public static double GetBForLinearFormula(IEnumerable<(double value, double timestamp)> rawData) + { + var (xSum, ySum, xySum, x2Sum) = GetFormulaVariables(rawData); + + var result = (xSum * xySum - x2Sum * ySum) / + (xSum * xSum - rawData.Count() * x2Sum); + + return (double)result; + } + + public static bool IsValueChanges(double value, + (double upperBound, double lowerBound) bounds) => + value >= bounds.upperBound || value <= bounds.lowerBound; + + public static bool IsValueNotChanges(double value, + (double upperBound, double lowerBound) bounds) => + value < bounds.upperBound && value > bounds.lowerBound; + + public static bool IsValueGoesUp(double value, double bound) => + value >= bound; + + public static bool IsValueGoesDown(double value, double bound) => + value <= bound; + + public static bool IsAverageLessThanBound(IEnumerable<(double Value, double TotalSeconds)> values, + double bound) => + (values.Sum(s => s.Value) / values.Count()) < bound; + + public static bool IsAverageMoreThanBound(IEnumerable<(double Value, double TotalSeconds)> values, + double bound) => + (values.Sum(s => s.Value) / values.Count()) >= bound; + + private static (decimal xSum, decimal ySum, decimal xySum, decimal x2Sum) GetFormulaVariables( + IEnumerable<(double value, double timestamp)> rawData) + { + var data = rawData.Select((d) => new + { + X = d.timestamp, + Y = d.value + }); + var xSum = (decimal)data.Sum(d => d.X); + var ySum = (decimal)data.Sum(d => d.Y); + var xySum = (decimal)data.Sum(d => d.X * d.Y); + var x2Sum = (decimal)data.Sum(d => d.X * d.X); + + return (xSum, ySum, xySum, x2Sum); + } + } +} diff --git a/AsbCloudInfrastructure/Services/ReportService.cs b/AsbCloudInfrastructure/Services/ReportService.cs index dca2f934..2c998fe8 100644 --- a/AsbCloudInfrastructure/Services/ReportService.cs +++ b/AsbCloudInfrastructure/Services/ReportService.cs @@ -44,7 +44,7 @@ namespace AsbCloudInfrastructure.Services var newReportName = generator.Make(); if(newReportName is not null) { - var shorReportName = newReportName.Split(Path.DirectorySeparatorChar).Last(); + var shorReportName = Path.GetFileName(newReportName); reportNameHandler.Invoke(shorReportName, id); var newReportProperties = new Report @@ -99,25 +99,22 @@ namespace AsbCloudInfrastructure.Services if (telemetry is null) return null; - try - { - var datesRange = (from d in db.DataSaubBases - where d.IdTelemetry == telemetry.Id - select d.Date).Union( - from m in db.Messages - where m.IdTelemetry == telemetry.Id - select m.Date).GroupBy(g => true) - .Select(g => new - { - From = g.Min(), - To = g.Max() - }).FirstOrDefault(); - return new DatesRangeDto { From = datesRange.From, To = datesRange.To }; - } - catch(InvalidOperationException) - { - return new DatesRangeDto { From = DateTime.MinValue, To = DateTime.MaxValue }; - } + var datesRange = (from d in db.DataSaubBases + where d.IdTelemetry == telemetry.Id + select d.Date).Union( + from m in db.Messages + where m.IdTelemetry == telemetry.Id + select m.Date).DefaultIfEmpty().GroupBy(g => true) + .Select(g => new + { + From = g.Min(), + To = g.Max() + }).OrderBy(gr => gr.From).FirstOrDefault(); + + return new DatesRangeDto { + From = datesRange.From, + To = datesRange.To.Year == 1 ? DateTime.MaxValue : datesRange.To + }; } private IEnumerable GetSuitableReportsFromDb(int wellId, DateTime begin, DateTime end, int stepSeconds, int format) diff --git a/AsbCloudWebApi/AsbCloudWebApi.csproj b/AsbCloudWebApi/AsbCloudWebApi.csproj index da3b1513..7806d11b 100644 --- a/AsbCloudWebApi/AsbCloudWebApi.csproj +++ b/AsbCloudWebApi/AsbCloudWebApi.csproj @@ -13,6 +13,7 @@ + diff --git a/AsbCloudWebApi/Controllers/AnalyticsController.cs b/AsbCloudWebApi/Controllers/AnalyticsController.cs index d0142912..ef246888 100644 --- a/AsbCloudWebApi/Controllers/AnalyticsController.cs +++ b/AsbCloudWebApi/Controllers/AnalyticsController.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Collections.Generic; using AsbCloudApp.Data; using AsbCloudApp.Services; @@ -33,14 +34,14 @@ namespace AsbCloudWebApi.Controllers { int? idCustomer = User.GetCustomerId(); - if (idCustomer is null) - return BadRequest(); - - if (!wellService.CheckWellOwnership((int)idCustomer, wellId)) + if (idCustomer is null || !wellService.CheckWellOwnership((int)idCustomer, wellId)) return Forbid(); var wellDepthToDayData = analyticsService.GetWellDepthToDay(wellId); + if (wellDepthToDayData is null || !wellDepthToDayData.Any()) + return NoContent(); + return Ok(wellDepthToDayData); } @@ -54,17 +55,19 @@ namespace AsbCloudWebApi.Controllers [HttpGet] [Route("{wellId}/wellDepthToInterval")] [ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)] - public IActionResult GetWellDepthToInterval(int wellId, int intervalHoursTimestamp, int workBeginTimestamp) + public IActionResult GetWellDepthToInterval(int wellId, + int intervalHoursTimestamp, int workBeginTimestamp) { int? idCustomer = User.GetCustomerId(); - if (idCustomer is null) - return BadRequest(); - - if (!wellService.CheckWellOwnership((int)idCustomer, wellId)) + if (idCustomer is null || !wellService.CheckWellOwnership((int)idCustomer, wellId)) return Forbid(); - var wellDepthToIntervalData = analyticsService.GetWellDepthToInterval(wellId, intervalHoursTimestamp, workBeginTimestamp); + var wellDepthToIntervalData = analyticsService.GetWellDepthToInterval(wellId, + intervalHoursTimestamp, workBeginTimestamp); + + if (wellDepthToIntervalData is null || !wellDepthToIntervalData.Any()) + return NoContent(); return Ok(wellDepthToIntervalData); } @@ -78,19 +81,19 @@ namespace AsbCloudWebApi.Controllers /// Коллекцию операций на скважине [HttpGet] [Route("{wellId}/operationsSummary")] - [ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)] + [ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)] public IActionResult GetOperationsSummary(int wellId, DateTime begin = default, DateTime end = default) { int? idCustomer = User.GetCustomerId(); - if (idCustomer is null) - return BadRequest(); - - if (!wellService.CheckWellOwnership((int)idCustomer, wellId)) + if (idCustomer is null || !wellService.CheckWellOwnership((int)idCustomer, wellId)) return Forbid(); var analytics = analyticsService.GetOperationsSummary(wellId, begin, end); + if (analytics is null || !analytics.Any()) + return NoContent(); + return Ok(analytics); } @@ -98,24 +101,25 @@ namespace AsbCloudWebApi.Controllers /// Возвращает детальные данные по операциям на скважине за период /// /// id скважины - /// дата начала интервала - /// дата окончания интервала + /// количество секунд в необходимом интервале времени + /// количество секунд в времени начала смены /// Коллекцию операций на скважине [HttpGet] - [Route("{wellId}/operationsToTime")] - [ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)] - public IActionResult GetOperationsToTime(int wellId, DateTime begin = default, DateTime end = default) + [Route("{wellId}/operationsToInterval")] + [ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)] + public IActionResult GetOperationsToInterval(int wellId, + int intervalHoursTimestamp, int workBeginTimestamp) { int? idCustomer = User.GetCustomerId(); - if (idCustomer is null) - return BadRequest(); - - if (!wellService.CheckWellOwnership((int)idCustomer, wellId)) + if (idCustomer is null || !wellService.CheckWellOwnership((int)idCustomer, wellId)) return Forbid(); - var analytics = analyticsService.GetOperationsToTime(wellId, begin, end); + var analytics = analyticsService.GetOperationsToInterval(wellId, intervalHoursTimestamp, workBeginTimestamp); + + if (analytics is null || !analytics.Any()) + return NoContent(); return Ok(analytics); } diff --git a/AsbCloudWebApi/Controllers/DataController.cs b/AsbCloudWebApi/Controllers/DataController.cs index 1778ff00..63df6e8c 100644 --- a/AsbCloudWebApi/Controllers/DataController.cs +++ b/AsbCloudWebApi/Controllers/DataController.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; +using System.Linq; namespace AsbCloudWebApi.Controllers { @@ -41,6 +42,10 @@ namespace AsbCloudWebApi.Controllers if (begin == default) begin = DateTime.Now.AddSeconds(-intervalSec); var content = telemetryDataService.Get(wellId, begin, intervalSec, approxPointsCount); + + if (content is null || !content.Any()) + return NoContent(); + return Ok(content); } @@ -52,7 +57,7 @@ namespace AsbCloudWebApi.Controllers int? idCustomer = User.GetCustomerId(); if (idCustomer is null) - return BadRequest(); + return Forbid(); bool isCustomerOwnsWell = wellService.CheckWellOwnership((int)idCustomer, wellId); diff --git a/AsbCloudWebApi/Controllers/MessageController.cs b/AsbCloudWebApi/Controllers/MessageController.cs index 3331eb04..fbce313f 100644 --- a/AsbCloudWebApi/Controllers/MessageController.cs +++ b/AsbCloudWebApi/Controllers/MessageController.cs @@ -41,6 +41,10 @@ namespace AsbCloudWebApi.Controllers begin = default; var result = messageService.GetMessages(wellId, categoryids, begin, end, skip, take); + + if (result is null || result.Count == 0) + return NoContent(); + return Ok(result); } @@ -52,7 +56,7 @@ namespace AsbCloudWebApi.Controllers int? idCustomer = User.GetCustomerId(); if (idCustomer is null) - return BadRequest(); + return Forbid(); bool isCustomerOwnsWell = wellService.CheckWellOwnership((int)idCustomer, wellId); diff --git a/AsbCloudWebApi/Controllers/ReportController.cs b/AsbCloudWebApi/Controllers/ReportController.cs index 9a8488c6..846b3281 100644 --- a/AsbCloudWebApi/Controllers/ReportController.cs +++ b/AsbCloudWebApi/Controllers/ReportController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; @@ -63,7 +64,7 @@ namespace AsbCloudWebApi.Controllers int? idCustomer = User.GetCustomerId(); if (idCustomer is null) - return BadRequest(); + return Forbid(); if (!wellService.CheckWellOwnership((int)idCustomer, wellId)) return Forbid(); @@ -89,7 +90,7 @@ namespace AsbCloudWebApi.Controllers int? idCustomer = User.GetCustomerId(); if (idCustomer is null) - return BadRequest(); + return Forbid(); if (!wellService.CheckWellOwnership((int)idCustomer, wellId)) return Forbid(); @@ -120,6 +121,10 @@ namespace AsbCloudWebApi.Controllers DateTime begin = default, DateTime end = default) { var suitableReportsNames = reportService.GetSuitableReports(wellId, begin, end, stepSeconds, format); + + if (suitableReportsNames is null || !suitableReportsNames.Any()) + return NoContent(); + return Ok(suitableReportsNames); } @@ -140,7 +145,7 @@ namespace AsbCloudWebApi.Controllers int? idCustomer = User.GetCustomerId(); if (idCustomer is null) - return BadRequest(); + return Forbid(); if (!wellService.CheckWellOwnership((int)idCustomer, wellId)) return Forbid(); @@ -163,7 +168,7 @@ namespace AsbCloudWebApi.Controllers int? idCustomer = User.GetCustomerId(); if (idCustomer is null) - return BadRequest(); + return Forbid(); if (!wellService.CheckWellOwnership((int)idCustomer, wellId)) return Forbid(); diff --git a/AsbCloudWebApi/Controllers/WellController.cs b/AsbCloudWebApi/Controllers/WellController.cs index 4033eead..1e16a167 100644 --- a/AsbCloudWebApi/Controllers/WellController.cs +++ b/AsbCloudWebApi/Controllers/WellController.cs @@ -3,6 +3,7 @@ using AsbCloudApp.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; +using System.Linq; namespace AsbCloudWebApi.Controllers { @@ -31,6 +32,9 @@ namespace AsbCloudWebApi.Controllers var wells = wellService.GetWellsByCustomer((int)idCustomer); + if (wells is null || !wells.Any()) + return NoContent(); + return Ok(wells); } @@ -47,6 +51,9 @@ namespace AsbCloudWebApi.Controllers var transmittingWells = wellService.GetTransmittingWells((int)idCustomer); + if (transmittingWells is null || !transmittingWells.Any()) + return NoContent(); + return Ok(transmittingWells); } diff --git a/AsbCloudWebApi/Startup.cs b/AsbCloudWebApi/Startup.cs index 87182bb4..dd309051 100644 --- a/AsbCloudWebApi/Startup.cs +++ b/AsbCloudWebApi/Startup.cs @@ -75,6 +75,11 @@ namespace AsbCloudWebApi endpoints.MapHub("/hubs/telemetry"); endpoints.MapHub("/hubs/reports"); }); + + app.UseSpa(spa => + { + spa.Options.SourcePath = "wwwroot"; + }); } } } diff --git a/AsbCloudWebApi/wwwroot/asset-manifest.json b/AsbCloudWebApi/wwwroot/asset-manifest.json new file mode 100644 index 00000000..8191ad04 --- /dev/null +++ b/AsbCloudWebApi/wwwroot/asset-manifest.json @@ -0,0 +1,34 @@ +{ + "files": { + "main.css": "/static/css/main.78f652ed.chunk.css", + "main.js": "/static/js/main.bc9ed2e6.chunk.js", + "main.js.map": "/static/js/main.bc9ed2e6.chunk.js.map", + "runtime-main.js": "/static/js/runtime-main.bfbc5d7c.js", + "runtime-main.js.map": "/static/js/runtime-main.bfbc5d7c.js.map", + "static/js/2.d2927f6c.chunk.js": "/static/js/2.d2927f6c.chunk.js", + "static/js/2.d2927f6c.chunk.js.map": "/static/js/2.d2927f6c.chunk.js.map", + "static/js/3.e81cf339.chunk.js": "/static/js/3.e81cf339.chunk.js", + "static/js/3.e81cf339.chunk.js.map": "/static/js/3.e81cf339.chunk.js.map", + "index.html": "/index.html", + "static/css/main.78f652ed.chunk.css.map": "/static/css/main.78f652ed.chunk.css.map", + "static/js/2.d2927f6c.chunk.js.LICENSE.txt": "/static/js/2.d2927f6c.chunk.js.LICENSE.txt", + "static/media/40752.04f88a90.png": "/static/media/40752.04f88a90.png", + "static/media/40808.9c38815a.png": "/static/media/40808.9c38815a.png", + "static/media/40997.3601b273.png": "/static/media/40997.3601b273.png", + "static/media/42483.54ae2d28.png": "/static/media/42483.54ae2d28.png", + "static/media/43745.0c1185c0.png": "/static/media/43745.0c1185c0.png", + "static/media/asb-logo.5d662174.png": "/static/media/asb-logo.5d662174.png", + "static/media/map_background.08470ca4.png": "/static/media/map_background.08470ca4.png", + "static/media/pointer.31629e02.svg": "/static/media/pointer.31629e02.svg", + "static/media/well-chart-1.0ba3a280.png": "/static/media/well-chart-1.0ba3a280.png", + "static/media/well-chart-2.d79caafa.png": "/static/media/well-chart-2.d79caafa.png", + "static/media/well-chart-3.98133e57.png": "/static/media/well-chart-3.98133e57.png", + "static/media/well-chart-8.9c38815a.png": "/static/media/well-chart-8.9c38815a.png" + }, + "entrypoints": [ + "static/js/runtime-main.bfbc5d7c.js", + "static/js/2.d2927f6c.chunk.js", + "static/css/main.78f652ed.chunk.css", + "static/js/main.bc9ed2e6.chunk.js" + ] +} \ No newline at end of file diff --git a/AsbCloudWebApi/wwwroot/favicon.ico b/AsbCloudWebApi/wwwroot/favicon.ico new file mode 100644 index 00000000..0427b291 Binary files /dev/null and b/AsbCloudWebApi/wwwroot/favicon.ico differ diff --git a/AsbCloudWebApi/wwwroot/index.html b/AsbCloudWebApi/wwwroot/index.html index 75687662..eddbbf9f 100644 --- a/AsbCloudWebApi/wwwroot/index.html +++ b/AsbCloudWebApi/wwwroot/index.html @@ -1,10 +1 @@ - - - - - - - - - - \ No newline at end of file +АСБ Vision
\ No newline at end of file diff --git a/AsbCloudWebApi/wwwroot/manifest.json b/AsbCloudWebApi/wwwroot/manifest.json new file mode 100644 index 00000000..080d6c77 --- /dev/null +++ b/AsbCloudWebApi/wwwroot/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/AsbCloudWebApi/wwwroot/robots.txt b/AsbCloudWebApi/wwwroot/robots.txt new file mode 100644 index 00000000..e9e57dc4 --- /dev/null +++ b/AsbCloudWebApi/wwwroot/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: