diff --git a/AsbCloudApp/Data/DetectedOperationDto.cs b/AsbCloudApp/Data/DetectedOperationDto.cs
index d977d0f3..59b28043 100644
--- a/AsbCloudApp/Data/DetectedOperationDto.cs
+++ b/AsbCloudApp/Data/DetectedOperationDto.cs
@@ -2,6 +2,7 @@
namespace AsbCloudApp.Data
{
+#nullable enable
///
/// Автоматически определяемая операция
///
@@ -61,13 +62,17 @@ namespace AsbCloudApp.Data
///
/// Бурильщик
///
- public DrillerDto Driller { get; set; }
+ public DrillerDto? Driller { get; set; }
///
/// Целевые/нормативные показатели
///
- public OperationValueDto OperationValue { get; set; }
+ public OperationValueDto? OperationValue { get; set; }
+ ///
+ /// Ключевой параметр операции
+ ///
public double Value { get; set; }
}
+#nullable disable
}
diff --git a/AsbCloudApp/Data/DetectedOperationListDto.cs b/AsbCloudApp/Data/DetectedOperationListDto.cs
index 33669416..82718e2d 100644
--- a/AsbCloudApp/Data/DetectedOperationListDto.cs
+++ b/AsbCloudApp/Data/DetectedOperationListDto.cs
@@ -4,12 +4,16 @@ using System.Linq;
namespace AsbCloudApp.Data
{
+#nullable enable
+ ///
+ /// Статистика по операциям бурильщика
+ ///
public class DetectedOperationStatDto
{
///
- /// Бурильцик
+ /// Бурильщик
///
- public DrillerDto Driller { get; set; }
+ public DrillerDto? Driller { get; set; }
///
/// Количество операции
@@ -17,24 +21,24 @@ namespace AsbCloudApp.Data
public int Count { get; set; }
///
- /// Среднее по целевым показателям
+ /// Среднее по ключевому показателю
///
- public double Average { get; set; }
+ public double AverageValue { get; set; }
+
+ ///
+ /// Среднее целевого показателя
+ ///
+ public double? AverageTargetValue { get; set; }
///
/// Коэффициент эффективности
///
- public double Efficiency { get; set; }
-
- ///
- /// Среднее по ключевому показателю
- ///
- public double AverageByParam { get; set; }
+ public double? Efficiency { get; set; }
///
/// Коэффициент потерь
///
- public double Loss { get; set; }
+ public double? Loss { get; set; }
}
///
@@ -45,8 +49,9 @@ namespace AsbCloudApp.Data
///
/// Список всех операций
///
- public IEnumerable List { get; set; }
+ public IEnumerable Operations { get; set; }
- public ICollection Stats { get; set; }
+ public IEnumerable Stats { get; set; }
}
+#nullable disable
}
diff --git a/AsbCloudApp/Data/OperationValueDto.cs b/AsbCloudApp/Data/OperationValueDto.cs
index ef0dd1da..4e9ea565 100644
--- a/AsbCloudApp/Data/OperationValueDto.cs
+++ b/AsbCloudApp/Data/OperationValueDto.cs
@@ -5,7 +5,7 @@ namespace AsbCloudApp.Data
///
/// Описание целевых/нормативных показателей операций
///
- public class OperationValueDto : IId
+ public class OperationValueDto : IId, IWellRelated
{
///
/// Идентификатор в БД
diff --git a/AsbCloudApp/Data/ScheduleDto.cs b/AsbCloudApp/Data/ScheduleDto.cs
index ade938f4..00fb51bb 100644
--- a/AsbCloudApp/Data/ScheduleDto.cs
+++ b/AsbCloudApp/Data/ScheduleDto.cs
@@ -37,5 +37,10 @@ namespace AsbCloudApp.Data
/// Конец бурения
///
public DateTime DrillEnd { get; set; }
+
+ ///
+ /// Бурильщик
+ ///
+ public DrillerDto Driller { get; set; }
}
}
diff --git a/AsbCloudApp/Data/TimeDto.cs b/AsbCloudApp/Data/TimeDto.cs
index 28cb8916..7d628c91 100644
--- a/AsbCloudApp/Data/TimeDto.cs
+++ b/AsbCloudApp/Data/TimeDto.cs
@@ -5,7 +5,7 @@ namespace AsbCloudApp.Data
///
/// DTO времени
///
- public class TimeDto
+ public class TimeDto: IComparable
{
private int hour = 0;
private int minute = 0;
@@ -51,6 +51,11 @@ namespace AsbCloudApp.Data
}
}
+ ///
+ /// Кол-во секунд с начала суток
+ ///
+ public int TotalSeconds => (Hour * 60 + minute) * 60 + second;
+
///
public TimeDto()
{ }
@@ -71,6 +76,14 @@ namespace AsbCloudApp.Data
second = time.Second;
}
+ ///
+ public TimeDto(DateTime fullDate)
+ {
+ hour = fullDate.Hour;
+ minute = fullDate.Minute;
+ second = fullDate.Second;
+ }
+
///
/// Makes System.TimeOnly
///
@@ -83,5 +96,27 @@ namespace AsbCloudApp.Data
var str = $"{Hour:00}:{Minute:00}:{Second:00}";
return str;
}
+
+ ///
+ public static bool operator ==(TimeDto a, TimeDto b) => a?.TotalSeconds == b?.TotalSeconds;
+
+ ///
+ public static bool operator !=(TimeDto a, TimeDto b) => !(a == b);
+
+ ///
+ public static bool operator <=(TimeDto a, TimeDto b) => a.TotalSeconds <= b.TotalSeconds;
+
+ ///
+ public static bool operator >=(TimeDto a, TimeDto b) => a.TotalSeconds >= b.TotalSeconds;
+
+ ///
+ public static bool operator <(TimeDto a, TimeDto b) => a.TotalSeconds < b.TotalSeconds;
+
+ ///
+ public static bool operator >(TimeDto a, TimeDto b) => a.TotalSeconds > b.TotalSeconds;
+
+ ///
+ public int CompareTo(TimeDto other)
+ => TotalSeconds - other.TotalSeconds;
}
}
diff --git a/AsbCloudApp/Services/ICrudWellRelatedService.cs b/AsbCloudApp/Services/ICrudWellRelatedService.cs
index 8c350bf3..25e3d8f8 100644
--- a/AsbCloudApp/Services/ICrudWellRelatedService.cs
+++ b/AsbCloudApp/Services/ICrudWellRelatedService.cs
@@ -19,7 +19,7 @@ namespace AsbCloudApp.Services
/// id скважины
///
/// emptyList if nothing found
- Task> GetAllAsync(int idWell, CancellationToken token);
+ Task> GetByIdWellAsync(int idWell, CancellationToken token);
///
/// Получение всех записей по нескольким скважинам
@@ -27,7 +27,7 @@ namespace AsbCloudApp.Services
/// id скважин
///
/// emptyList if nothing found
- Task> GetAllAsync(IEnumerable idsWells, CancellationToken token);
+ Task> GetByIdWellAsync(IEnumerable idsWells, CancellationToken token);
}
#nullable disable
}
\ No newline at end of file
diff --git a/AsbCloudApp/Services/IOperationValueService.cs b/AsbCloudApp/Services/IOperationValueService.cs
index 67206dbb..a35af223 100644
--- a/AsbCloudApp/Services/IOperationValueService.cs
+++ b/AsbCloudApp/Services/IOperationValueService.cs
@@ -2,7 +2,7 @@
namespace AsbCloudApp.Services
{
- public interface IOperationValueService : ICrudService
+ public interface IOperationValueService : ICrudWellRelatedService
{
}
}
diff --git a/AsbCloudApp/Services/IScheduleService.cs b/AsbCloudApp/Services/IScheduleService.cs
index 5037ef43..326490e6 100644
--- a/AsbCloudApp/Services/IScheduleService.cs
+++ b/AsbCloudApp/Services/IScheduleService.cs
@@ -6,9 +6,8 @@ using System.Threading.Tasks;
namespace AsbCloudApp.Services
{
- public interface IScheduleService : ICrudService
+ public interface IScheduleService : ICrudWellRelatedService
{
- Task> GetByIdWellAsync(int idWell, CancellationToken token = default);
- Task GetDrillerAsync(int idWell, DateTime workTime, CancellationToken token = default);
+ Task GetDrillerAsync(int idWell, DateTime workTime, CancellationToken token);
}
}
diff --git a/AsbCloudDb/Model/OperationValue.cs b/AsbCloudDb/Model/OperationValue.cs
index 6fab8a3c..515c2db2 100644
--- a/AsbCloudDb/Model/OperationValue.cs
+++ b/AsbCloudDb/Model/OperationValue.cs
@@ -1,16 +1,11 @@
using Microsoft.EntityFrameworkCore;
-using System;
-using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace AsbCloudDb.Model
{
[Table("t_operationvalue"), Comment("Целевые/нормативные показатели операции")]
- public class OperationValue:IId
+ public class OperationValue: IId, IWellRelated
{
[Key]
[Column("id"), Comment("Идентификатор")]
diff --git a/AsbCloudDb/Model/Schedule.cs b/AsbCloudDb/Model/Schedule.cs
index 8b96995c..3704419a 100644
--- a/AsbCloudDb/Model/Schedule.cs
+++ b/AsbCloudDb/Model/Schedule.cs
@@ -6,7 +6,7 @@ using System.ComponentModel.DataAnnotations.Schema;
namespace AsbCloudDb.Model
{
[Table("t_schedule"), Comment("График работы бурильщика")]
- public class Schedule: IId
+ public class Schedule: IId, IWellRelated
{
[Key]
[Column("id"),Comment("Идентификатор")]
diff --git a/AsbCloudInfrastructure/Services/CrudWellRelatedServiceBase.cs b/AsbCloudInfrastructure/Services/CrudWellRelatedServiceBase.cs
index 3f34a245..044f6def 100644
--- a/AsbCloudInfrastructure/Services/CrudWellRelatedServiceBase.cs
+++ b/AsbCloudInfrastructure/Services/CrudWellRelatedServiceBase.cs
@@ -23,7 +23,7 @@ namespace AsbCloudInfrastructure.Services
public CrudWellRelatedServiceBase(IAsbCloudDbContext context, Func, IQueryable> makeQuery)
: base(context, makeQuery) { }
- public async Task> GetAllAsync(int idWell, CancellationToken token)
+ public async Task> GetByIdWellAsync(int idWell, CancellationToken token)
{
var entities = await GetQuery()
.Where(e => e.IdWell == idWell)
@@ -32,7 +32,7 @@ namespace AsbCloudInfrastructure.Services
return dtos;
}
- public async Task> GetAllAsync(IEnumerable idsWells, CancellationToken token)
+ public async Task> GetByIdWellAsync(IEnumerable idsWells, CancellationToken token)
{
if (!idsWells.Any())
return Enumerable.Empty();
diff --git a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs
index 8e368dd6..4caa5687 100644
--- a/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs
+++ b/AsbCloudInfrastructure/Services/DetectOperations/DetectedOperationService.cs
@@ -15,6 +15,10 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
{
public class DetectedOperationService: IDetectedOperationService
{
+ public const int IdOperationRotor = 1;
+ public const int IdOperationSlide = 3;
+ public const int IdOperationSlipsTime = 14;
+
private readonly IAsbCloudDbContext db;
private readonly IWellService wellService;
private readonly IOperationValueService operationValueService;
@@ -35,38 +39,43 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
if (well?.IdTelemetry is null || well.Timezone is null)
return null;
- var res = new DetectedOperationListDto();
var query = BuildQuery(well, request)
.AsNoTracking();
var data = await query.ToListAsync(token);
- var operationValues = await operationValueService.GetAllAsync(token);
- operationValues = operationValues.Where(o => o.IdWell == idWell);
- var dtos = data.Select(o => Convert(o, well, operationValues));
- foreach (var item in dtos)
+ var operationValues = await operationValueService.GetByIdWellAsync(idWell, token);
+ var schedules = await scheduleService.GetByIdWellAsync(idWell, token);
+ var dtos = data.Select(o => Convert(o, well, operationValues, schedules));
+ var groups = dtos.GroupBy(o => o.Driller);
+
+ var stats = new List(groups.Count());
+ foreach (var group in groups)
{
- item.Driller = await scheduleService.GetDrillerAsync(idWell, item.DateStart);
+ var itemsWithTarget = group.Where(i => i.OperationValue is not null);
+ var stat = new DetectedOperationStatDto
+ {
+ Driller = group.Key,
+ AverageValue = group.Sum(e => e.Value) / group.Count(),
+ Count = group.Count(),
+ };
+ if (itemsWithTarget.Any())
+ {
+ var itemsOutOfTarget = itemsWithTarget.Where(o => !IsTargetOk(o));
+ stat.AverageTargetValue = itemsWithTarget.Average(e => e.OperationValue.TargetValue);
+ stat.Efficiency = 100d * itemsOutOfTarget.Count() / itemsWithTarget.Count();
+ stat.Loss = itemsOutOfTarget.Sum(DeltaToTarget);
+ }
+
+ stats.Add(stat);
}
- var group = dtos.GroupBy(o => o.Driller == null ? 0 : o.Driller.Id,
- p => p,
- (key, gr) => (key, gr.ToList())).ToDictionary(e => e.key, e => e.Item2);
- res.List = dtos;
- res.Stats = new List();
- foreach (var item in group)
+
+ var result = new DetectedOperationListDto
{
- var obj = new DetectedOperationStatDto();
- obj.Driller = item.Value.FirstOrDefault()?.Driller;
- obj.Count = item.Value.Count();
- obj.Average = item.Value.Sum(e=>e.OperationValue?.TargetValue ?? 0)/obj.Count;
- obj.Efficiency = 100d * item.Value.Count(e => PredicateTarget(e)(e.Value)) / obj.Count;
- obj.AverageByParam = item.Value.Sum(e => e.Value) / obj.Count;
- obj.Loss = item.Value
- .Where(e => !PredicateTarget(e)(e.Value))
- .Sum(p => Math.Abs(p.Value - p.OperationValue?.TargetValue ?? 0));
- res.Stats.Add(obj);
- }
- return res;
+ Operations = dtos,
+ Stats = stats
+ };
+ return result;
}
public async Task DeleteAsync(int idWell, DetectedOperationRequest request, CancellationToken token)
@@ -80,17 +89,25 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
return await db.SaveChangesAsync(token);
}
- ///
- /// Определение применяемого предикат по типц операции
- ///
- /// Предикат для использования
- private static Predicate PredicateTarget(DetectedOperationDto op)
+ private static bool IsTargetOk(DetectedOperationDto op)
{
- return op.OperationValue.IdOperationCategory switch
+ return (op.IdCategory) switch
{
- 1 => (x) => false,
- 11 => (x) => x > op.OperationValue.TargetValue,
- _ => (x) => true
+ IdOperationRotor => op.Value > op.OperationValue.TargetValue,
+ IdOperationSlide => op.Value > op.OperationValue.TargetValue,
+ IdOperationSlipsTime => op.Value > op.OperationValue.TargetValue,
+ _ => op.Value > op.OperationValue.TargetValue,
+ };
+ }
+
+ private static double DeltaToTarget(DetectedOperationDto op)
+ {
+ return (op.IdCategory) switch
+ {
+ IdOperationRotor => 0,
+ IdOperationSlide => 0,
+ IdOperationSlipsTime => op.Value - op.OperationValue.TargetValue,
+ _ => 0,
};
}
@@ -142,14 +159,26 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
return query;
}
- private static DetectedOperationDto Convert(DetectedOperation operation, WellDto well, IEnumerable operationValues)
+ private DetectedOperationDto Convert(DetectedOperation operation, WellDto well, IEnumerable operationValues, IEnumerable schedules)
{
var dto = operation.Adapt();
dto.IdWell = well.Id;
- dto.DateStart = operation.DateStart.ToRemoteDateTime(well.Timezone.Hours);
+ var dateStart = operation.DateStart.ToRemoteDateTime(well.Timezone.Hours);
+ dto.DateStart = dateStart;
dto.DateEnd = operation.DateEnd.ToRemoteDateTime(well.Timezone.Hours);
dto.OperationValue = operationValues.FirstOrDefault(e => e.IdOperationCategory == dto.IdCategory
&& e.DepthStart <= dto.DepthStart);
+
+ var timeStart = new TimeDto(dateStart);
+ var driller = schedules.FirstOrDefault(s =>
+ s.DrillStart <= dateStart &&
+ s.DrillEnd > dateStart && (
+ s.ShiftStart > s.ShiftEnd
+ ) ^ (s.ShiftStart <= timeStart &&
+ s.ShiftEnd > timeStart
+ ))
+ ?.Driller;
+ dto.Driller = driller;
return dto;
}
diff --git a/AsbCloudInfrastructure/Services/DetectOperations/OperationDetectionBackgroundService.cs b/AsbCloudInfrastructure/Services/DetectOperations/OperationDetectionBackgroundService.cs
index 98ff3fff..afb43a57 100644
--- a/AsbCloudInfrastructure/Services/DetectOperations/OperationDetectionBackgroundService.cs
+++ b/AsbCloudInfrastructure/Services/DetectOperations/OperationDetectionBackgroundService.cs
@@ -97,15 +97,17 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
IdTelemetry = outer,
LastDate = inner.SingleOrDefault()?.LastDate ,
});
-
+ var affected = 0;
foreach (var item in JounedlastDetectedDates)
{
var newOperations = await DetectOperationsAsync(item.IdTelemetry, item.LastDate??DateTimeOffset.MinValue, db, token);
if (newOperations.Any())
+ {
db.DetectedOperations.AddRange(newOperations);
+ affected += await db.SaveChangesAsync(token);
+ }
}
-
- return await db.SaveChangesAsync(token);
+ return affected;
}
private async Task> DetectOperationsAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
@@ -131,7 +133,7 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
var dbRequests_ = 0;
var dbTime_ = 0d;
- var sw_ = new System.Diagnostics.Stopwatch();
+ var sw_ = new Stopwatch();
var otherTime_ = 0d;
while (true)
diff --git a/AsbCloudInfrastructure/Services/OperationValueService.cs b/AsbCloudInfrastructure/Services/OperationValueService.cs
index 75640b8a..1ca687fc 100644
--- a/AsbCloudInfrastructure/Services/OperationValueService.cs
+++ b/AsbCloudInfrastructure/Services/OperationValueService.cs
@@ -4,7 +4,7 @@ using AsbCloudDb.Model;
namespace AsbCloudInfrastructure.Services
{
- public class OperationValueService : CrudServiceBase, IOperationValueService
+ public class OperationValueService : CrudWellRelatedServiceBase, IOperationValueService
{
public OperationValueService(IAsbCloudDbContext context) : base(context)
{
diff --git a/AsbCloudInfrastructure/Services/ScheduleService.cs b/AsbCloudInfrastructure/Services/ScheduleService.cs
index 7df6026e..0a09331f 100644
--- a/AsbCloudInfrastructure/Services/ScheduleService.cs
+++ b/AsbCloudInfrastructure/Services/ScheduleService.cs
@@ -12,7 +12,7 @@ using System.Threading.Tasks;
namespace AsbCloudInfrastructure.Services
{
#nullable enable
- public class ScheduleService : CrudServiceBase, IScheduleService
+ public class ScheduleService : CrudWellRelatedServiceBase, IScheduleService
{
private readonly IWellService wellService;
@@ -22,16 +22,7 @@ namespace AsbCloudInfrastructure.Services
this.wellService = wellService;
}
- public async Task> GetByIdWellAsync(int idWell, CancellationToken token = default)
- {
- var entities = await GetQuery()
- .Where(s => s.IdWell == idWell)
- .ToListAsync(token);
- var dtos = entities.Select(Convert);
- return dtos;
- }
-
- public async Task GetDrillerAsync(int idWell, DateTime workTime, CancellationToken token = default)
+ public async Task GetDrillerAsync(int idWell, DateTime workTime, CancellationToken token)
{
var hoursOffset = wellService.GetTimezone(idWell).Hours;
var date = workTime.ToUtcDateTimeOffset(hoursOffset);
diff --git a/AsbCloudWebApi/Controllers/CrudWellRelatedController.cs b/AsbCloudWebApi/Controllers/CrudWellRelatedController.cs
index 9677c411..da6cb100 100644
--- a/AsbCloudWebApi/Controllers/CrudWellRelatedController.cs
+++ b/AsbCloudWebApi/Controllers/CrudWellRelatedController.cs
@@ -48,7 +48,7 @@ namespace AsbCloudWebApi.Controllers
return NoContent();
var idsWells = wells.Select(w => w.Id);
- var result = await service.GetAllAsync(idsWells, token);
+ var result = await service.GetByIdWellAsync(idsWells, token);
return Ok(result);
}
@@ -59,12 +59,12 @@ namespace AsbCloudWebApi.Controllers
///
///
[HttpGet("well/{idWell}")]
- public async Task>> GetAllAsync(int idWell, CancellationToken token)
+ public async Task>> GetByIdWellAsync(int idWell, CancellationToken token)
{
if (!await UserHasAccesToWellAsync(idWell, token))
return Forbid();
- var result = await service.GetAllAsync(idWell, token);
+ var result = await service.GetByIdWellAsync(idWell, token);
return Ok(result);
}
@@ -108,6 +108,7 @@ namespace AsbCloudWebApi.Controllers
return await base.UpdateAsync(value, token);
}
+ ///
[HttpDelete("{id}")]
public override async Task> DeleteAsync(int id, CancellationToken token)
{
diff --git a/AsbCloudWebApi/Controllers/OperationValueController.cs b/AsbCloudWebApi/Controllers/OperationValueController.cs
index f72a61c7..7f4d344a 100644
--- a/AsbCloudWebApi/Controllers/OperationValueController.cs
+++ b/AsbCloudWebApi/Controllers/OperationValueController.cs
@@ -5,12 +5,12 @@ using Microsoft.AspNetCore.Mvc;
namespace AsbCloudWebApi.Controllers
{
- [Route("api/operationvalue")]
+ [Route("api/operationValue")]
[ApiController]
[Authorize]
- public class OperationValueController : CrudController
+ public class OperationValueController : CrudWellRelatedController
{
- public OperationValueController(IOperationValueService service) : base(service)
+ public OperationValueController(IOperationValueService service, IWellService wellService) : base(wellService, service)
{
}
}
diff --git a/AsbCloudWebApi/Controllers/SAUB/DetectedOperationController.cs b/AsbCloudWebApi/Controllers/SAUB/DetectedOperationController.cs
index 70547e8f..ac551003 100644
--- a/AsbCloudWebApi/Controllers/SAUB/DetectedOperationController.cs
+++ b/AsbCloudWebApi/Controllers/SAUB/DetectedOperationController.cs
@@ -45,7 +45,7 @@ namespace AsbCloudWebApi.Controllers.SAUB
///
///
[HttpGet]
- [ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)]
+ [ProducesResponseType(typeof(DetectedOperationListDto), (int)System.Net.HttpStatusCode.OK)]
public async Task GetAsync(
int idWell,
[FromQuery] DetectedOperationRequest request,