forked from ddrilling/AsbCloudServer
Merge branch 'dev' into gtr
This commit is contained in:
commit
f14b0064ed
@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace AsbCloudApp.Data.DailyReport
|
namespace AsbCloudApp.Data
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// хранение дополнительной информации о записи
|
/// хранение дополнительной информации о записи
|
@ -1,13 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace AsbCloudApp.Data.ProcessMap
|
namespace AsbCloudApp.Data.ProcessMap
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// РТК
|
/// РТК
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ProcessMapDto : IId, IWellRelated
|
public class ProcessMapPlanDto : IId, IWellRelated
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
@ -24,7 +23,7 @@ namespace AsbCloudApp.Data.ProcessMap
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id режима 1-ротор, 2 - слайд
|
/// Id режима 1-ротор, 2 - слайд
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Range(1, 2, ErrorMessage = "Id режима должен быть либо 1-ротор либо 2-слайд")]
|
[Range(0, 2, ErrorMessage = "Id режима должен быть либо 0-ручной либо, 1-ротор либо 2-слайд")]
|
||||||
public int IdMode { get; set; }
|
public int IdMode { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
@ -13,13 +13,31 @@ namespace AsbCloudApp.Data.ProcessMap
|
|||||||
public int IdWell { get; set; }
|
public int IdWell { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Глубина по стволу, м
|
/// название секции скважины
|
||||||
|
/// </summary>
|
||||||
|
public int IdWellSectionType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// название секции скважины
|
||||||
|
/// </summary>
|
||||||
|
public string WellSectionTypeName { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Глубина по стволу от, м
|
||||||
/// <para>
|
/// <para>
|
||||||
/// на начало интервала
|
/// на начало интервала
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double DepthStart { get; set; }
|
public double DepthStart { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Глубина по стволу до, м
|
||||||
|
/// <para>
|
||||||
|
/// на конец интервала
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
public double DepthEnd { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Дата/ время
|
/// Дата/ время
|
||||||
/// <para>
|
/// <para>
|
||||||
@ -34,23 +52,48 @@ namespace AsbCloudApp.Data.ProcessMap
|
|||||||
public double MechDrillingHours { get; set; }
|
public double MechDrillingHours { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Слайд
|
/// Режим бурения (Ротор/слайд/ручной)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ProcessMapReportRowDto Slide { get; set; } = null!;
|
public string DrillingMode { get; set; } = null!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ротор
|
/// Проходка, м
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ProcessMapReportRowDto Rotor { get; set; } = null!;
|
public double? DeltaDepth { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// название секции скважины
|
/// Перепад давления, атм
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int IdWellSectionType { get; set; }
|
public ProcessMapReportParamsDto PressureDiff { get; set; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// название секции скважины
|
/// Нагрузка, т
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string WellSectionTypeName { get; set; } = null!;
|
public ProcessMapReportParamsDto AxialLoad { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Момент на ВСП, кНхМ
|
||||||
|
/// </summary>
|
||||||
|
public ProcessMapReportParamsDto TopDriveTorque { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ограничение скорости, м/ч
|
||||||
|
/// </summary>
|
||||||
|
public ProcessMapReportParamsDto SpeedLimit { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Процент использования системы АПД план, %
|
||||||
|
/// </summary>
|
||||||
|
public double UsagePlan { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Процент использования системы АПД факт, %
|
||||||
|
/// </summary>
|
||||||
|
public double UsageFact { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Фактическая механическая скорость, м/ч
|
||||||
|
/// </summary>
|
||||||
|
public double? Rop { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,4 @@
|
|||||||
using System;
|
namespace AsbCloudApp.Data.ProcessMap
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace AsbCloudApp.Data.ProcessMap
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Параметры РТК
|
/// Параметры РТК
|
||||||
@ -34,6 +28,6 @@ namespace AsbCloudApp.Data.ProcessMap
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Процент бурения по уставке, %
|
/// Процент бурения по уставке, %
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double? PercDrillingSetpoint { get; set; }
|
public double? SetpointUsage { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
namespace AsbCloudApp.Data.ProcessMap
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Строки РТК
|
|
||||||
/// </summary>
|
|
||||||
public class ProcessMapReportRowDto
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Проходка, м
|
|
||||||
/// </summary>
|
|
||||||
public double? DeltaDepth { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Перепад давления, атм
|
|
||||||
/// </summary>
|
|
||||||
public ProcessMapReportParamsDto PressureDiff { get; set; } = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Нагрузка, т
|
|
||||||
/// </summary>
|
|
||||||
public ProcessMapReportParamsDto AxialLoad { get; set; } = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Момент на ВСП, кНхМ
|
|
||||||
/// </summary>
|
|
||||||
public ProcessMapReportParamsDto TopDriveTorque { get; set; } = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Ограничение скорости, м/ч
|
|
||||||
/// </summary>
|
|
||||||
public ProcessMapReportParamsDto SpeedLimit { get; set; } = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Процент использования системы АПД, %
|
|
||||||
/// </summary>
|
|
||||||
public double Usage { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Фактическая механическая скорость, м/ч
|
|
||||||
/// </summary>
|
|
||||||
public double Rop { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -47,16 +47,6 @@ namespace AsbCloudApp.Data.SAUB
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public float PressureIdle { get; set; }
|
public float PressureIdle { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// задание давления для роторного режима
|
|
||||||
/// </summary>
|
|
||||||
public float PressureSpRotor { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// задание давления для режима слайда
|
|
||||||
/// </summary>
|
|
||||||
public float PressureSpSlide { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ограничение макс перепада давления
|
/// ограничение макс перепада давления
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -108,13 +98,13 @@ namespace AsbCloudApp.Data.SAUB
|
|||||||
public float BlockSpeedSp { get; set; }
|
public float BlockSpeedSp { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Талевый блок. Задание скорости для роторного бурения
|
/// Режим САУБ
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float BlockSpeedSpRotor { get; set; }
|
public short IdMode { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Талевый блок. Задание скорости для режима слайда
|
/// Текущий критерий бурения
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float BlockSpeedSpSlide { get; set; }
|
public short? IdFeedRegulator { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ namespace AsbCloudApp.Data
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Операции на скважине (заведенные пользователем)
|
/// Операции на скважине (заведенные пользователем)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WellOperationDto : IId, IWellRelated
|
public class WellOperationDto : ItemInfoDto, IId, IWellRelated
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ namespace AsbCloudApp.Repositories
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// ÐÒÊ
|
/// ÐÒÊ
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IProcessMapRepository : IRepositoryWellRelated<ProcessMapDto>
|
public interface IProcessMapPlanRepository : IRepositoryWellRelated<ProcessMapPlanDto>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ïîëó÷èòü ïàðàìåòðû áóðåíèÿ íà÷èíàÿ ñ äàòû.
|
/// Ïîëó÷èòü ïàðàìåòðû áóðåíèÿ íà÷èíàÿ ñ äàòû.
|
||||||
@ -20,7 +20,7 @@ namespace AsbCloudApp.Repositories
|
|||||||
/// <param name="updateFrom"></param>
|
/// <param name="updateFrom"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<IEnumerable<ProcessMapDto>> GetAllAsync(int idWell,
|
Task<IEnumerable<ProcessMapPlanDto>> GetAllAsync(int idWell,
|
||||||
DateTime? updateFrom, CancellationToken token = default);
|
DateTime? updateFrom, CancellationToken token = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -29,6 +29,6 @@ namespace AsbCloudApp.Repositories
|
|||||||
/// <param name="requests"></param>
|
/// <param name="requests"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<IEnumerable<ProcessMapDto>> GetProcessMapAsync(IEnumerable<ProcessMapRequest> requests, CancellationToken token);
|
Task<IEnumerable<ProcessMapPlanDto>> GetProcessMapAsync(IEnumerable<ProcessMapRequest> requests, CancellationToken token);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -34,6 +34,6 @@ namespace AsbCloudApp.Repositories
|
|||||||
/// <param name="idWell"></param>
|
/// <param name="idWell"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<IEnumerable<ProcessMapDto>> GetCompositeProcessMap(int idWell, CancellationToken token);
|
Task<IEnumerable<ProcessMapPlanDto>> GetCompositeProcessMap(int idWell, CancellationToken token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using AsbCloudApp.Data.DailyReport;
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Data.DailyReport;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
@ -16,7 +16,7 @@ namespace AsbCloudApp.Services
|
|||||||
/// <param name="idWell"></param>
|
/// <param name="idWell"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<ClusterRopStatDto> GetRopStatAsync(int idWell, CancellationToken token);
|
Task<ClusterRopStatDto?> GetOrDefaultRopStatAsync(int idWell, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получить статистику по скважинам куста, которые доступны компании
|
/// Получить статистику по скважинам куста, которые доступны компании
|
||||||
@ -25,7 +25,7 @@ namespace AsbCloudApp.Services
|
|||||||
/// <param name="idCompany"></param>
|
/// <param name="idCompany"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<StatClusterDto> GetStatClusterAsync(int idCluster, int idCompany, CancellationToken token = default);
|
Task<StatClusterDto?> GetOrDefaultStatClusterAsync(int idCluster, int idCompany, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// получить статистику по скважине
|
/// получить статистику по скважине
|
||||||
@ -33,7 +33,7 @@ namespace AsbCloudApp.Services
|
|||||||
/// <param name="idWell"></param>
|
/// <param name="idWell"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<StatWellDto> GetWellStatAsync(int idWell, CancellationToken token = default);
|
Task<StatWellDto?> GetOrDefaultWellStatAsync(int idWell, CancellationToken token);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получить данные для графика TVD
|
/// Получить данные для графика TVD
|
||||||
|
@ -7,7 +7,7 @@ namespace AsbCloudApp.Services
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Сервис формирования РТК.
|
/// Сервис формирования РТК.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IProcessMapReportService
|
public interface IProcessMapReportMakerService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Сформировать.
|
/// Сформировать.
|
@ -8,7 +8,7 @@ namespace AsbCloudApp.Services
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Сервис формирования РТК
|
/// Сервис формирования РТК
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IProcessMapService
|
public interface IProcessMapReportService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получение моделей РТК
|
/// Получение моделей РТК
|
||||||
@ -16,6 +16,6 @@ namespace AsbCloudApp.Services
|
|||||||
/// <param name="idWell"></param>
|
/// <param name="idWell"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<IEnumerable<ProcessMapReportDto>> GetProcessMapAsync(int idWell, CancellationToken token);
|
Task<IEnumerable<ProcessMapReportDto>> GetProcessMapReportAsync(int idWell, CancellationToken token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
7824
AsbCloudDb/Migrations/20230404045901_Add_UserEditor_To_WellOperation_Table.Designer.cs
generated
Normal file
7824
AsbCloudDb/Migrations/20230404045901_Add_UserEditor_To_WellOperation_Table.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace AsbCloudDb.Migrations
|
||||||
|
{
|
||||||
|
public partial class Add_UserEditor_To_WellOperation_Table : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "IdUser",
|
||||||
|
table: "t_well_operation",
|
||||||
|
type: "integer",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTimeOffset>(
|
||||||
|
name: "LastUpdateDate",
|
||||||
|
table: "t_well_operation",
|
||||||
|
type: "timestamp with time zone",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "IdUser",
|
||||||
|
table: "t_well_operation");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "LastUpdateDate",
|
||||||
|
table: "t_well_operation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5135,6 +5135,9 @@ namespace AsbCloudDb.Migrations
|
|||||||
.HasColumnName("id_type")
|
.HasColumnName("id_type")
|
||||||
.HasComment("0 = План или 1 = Факт");
|
.HasComment("0 = План или 1 = Факт");
|
||||||
|
|
||||||
|
b.Property<int?>("IdUser")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
b.Property<int>("IdWell")
|
b.Property<int>("IdWell")
|
||||||
.HasColumnType("integer")
|
.HasColumnType("integer")
|
||||||
.HasColumnName("id_well")
|
.HasColumnName("id_well")
|
||||||
@ -5145,6 +5148,9 @@ namespace AsbCloudDb.Migrations
|
|||||||
.HasColumnName("id_well_section_type")
|
.HasColumnName("id_well_section_type")
|
||||||
.HasComment("Id тип секции скважины");
|
.HasComment("Id тип секции скважины");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastUpdateDate")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.HasIndex("DateStart");
|
b.HasIndex("DateStart");
|
||||||
|
@ -7,7 +7,7 @@ using System.Text.Json.Serialization;
|
|||||||
namespace AsbCloudDb.Model
|
namespace AsbCloudDb.Model
|
||||||
{
|
{
|
||||||
[Table("t_well_operation"), Comment("Данные по операциям на скважине")]
|
[Table("t_well_operation"), Comment("Данные по операциям на скважине")]
|
||||||
public class WellOperation : IId
|
public class WellOperation : ItemInfo, IId
|
||||||
{
|
{
|
||||||
public const int IdOperationTypePlan = 0;
|
public const int IdOperationTypePlan = 0;
|
||||||
public const int IdOperationTypeFact = 1;
|
public const int IdOperationTypeFact = 1;
|
||||||
|
@ -37,5 +37,44 @@ namespace AsbCloudInfrastructure
|
|||||||
var dateTz = date.ToOffset(TimeSpan.FromHours(remoteTimezoneOffsetHours));
|
var dateTz = date.ToOffset(TimeSpan.FromHours(remoteTimezoneOffsetHours));
|
||||||
return dateTz.DateTime;
|
return dateTz.DateTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Поиск индекса близкого к value значения в span.
|
||||||
|
/// Элементы в span должны быть отсортированы по возрастанию по полю propertyGetter.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <typeparam name="TProp"></typeparam>
|
||||||
|
/// <param name="span"></param>
|
||||||
|
/// <param name="propertyGetter">метод получения свойства из объекта класса T</param>
|
||||||
|
/// <param name="value">искомое значение</param>
|
||||||
|
/// <param name="maxIterations">максимальное кол-во итераций. Прим.:
|
||||||
|
/// в span из 4000 записей достаточно 9-ти итераций
|
||||||
|
/// 8_000 => 10 итераций;
|
||||||
|
/// 16_000 => 11;
|
||||||
|
/// ...
|
||||||
|
/// 256_000 => 15;
|
||||||
|
/// При недостаточном кол-ве итераций индекс может оказаться близко, но это будет не ближайшее значение
|
||||||
|
/// </param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static int BinarySearch<T, TProp>(this Span<T> span, Func<T, TProp> propertyGetter, TProp value, int maxIterations = 16)
|
||||||
|
where TProp : IComparable
|
||||||
|
{
|
||||||
|
if (span.Length < 2 || --maxIterations < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var indexOfMiddle = span.Length >> 1;
|
||||||
|
|
||||||
|
var comparison = value.CompareTo(propertyGetter(span[indexOfMiddle]));
|
||||||
|
|
||||||
|
if (comparison > 0)
|
||||||
|
{
|
||||||
|
var index = indexOfMiddle + 1 + BinarySearch(span[(indexOfMiddle + 1)..], propertyGetter, value, maxIterations);
|
||||||
|
return index < span.Length ? index : span.Length - 1;
|
||||||
|
}
|
||||||
|
else if (comparison < 0)
|
||||||
|
return BinarySearch(span[..(indexOfMiddle)], propertyGetter, value, maxIterations);
|
||||||
|
else //if (comparison == 0)
|
||||||
|
return indexOfMiddle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,7 @@ namespace AsbCloudInfrastructure
|
|||||||
|
|
||||||
services.AddTransient<IAuthService, AuthService>();
|
services.AddTransient<IAuthService, AuthService>();
|
||||||
services.AddTransient<IDepositRepository, DepositRepository>();
|
services.AddTransient<IDepositRepository, DepositRepository>();
|
||||||
services.AddTransient<IProcessMapRepository, ProcessMapRepository>();
|
services.AddTransient<IProcessMapPlanRepository, ProcessMapRepository>();
|
||||||
services.AddTransient<IDrillingProgramService, DrillingProgramService>();
|
services.AddTransient<IDrillingProgramService, DrillingProgramService>();
|
||||||
services.AddTransient<IEventService, EventService>();
|
services.AddTransient<IEventService, EventService>();
|
||||||
services.AddTransient<FileService>();
|
services.AddTransient<FileService>();
|
||||||
@ -135,8 +135,8 @@ namespace AsbCloudInfrastructure
|
|||||||
services.AddTransient<IWellFinalDocumentsService, WellFinalDocumentsService>();
|
services.AddTransient<IWellFinalDocumentsService, WellFinalDocumentsService>();
|
||||||
services.AddTransient<IFileCategoryService, FileCategoryService>();
|
services.AddTransient<IFileCategoryService, FileCategoryService>();
|
||||||
services.AddTransient<ILimitingParameterService, LimitingParameterService>();
|
services.AddTransient<ILimitingParameterService, LimitingParameterService>();
|
||||||
|
services.AddTransient<IProcessMapReportMakerService, ProcessMapReportMakerService>();
|
||||||
services.AddTransient<IProcessMapReportService, ProcessMapReportService>();
|
services.AddTransient<IProcessMapReportService, ProcessMapReportService>();
|
||||||
services.AddTransient<IProcessMapService, ProcessMapService>();
|
|
||||||
services.AddTransient<ITrajectoryVisualizationService, TrajectoryVisualizationService>();
|
services.AddTransient<ITrajectoryVisualizationService, TrajectoryVisualizationService>();
|
||||||
services.AddTransient<IGtrRepository, GtrWitsRepository>();
|
services.AddTransient<IGtrRepository, GtrWitsRepository>();
|
||||||
|
|
||||||
|
@ -4,10 +4,8 @@ using AsbCloudApp.Repositories;
|
|||||||
using AsbCloudApp.Requests;
|
using AsbCloudApp.Requests;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using DocumentFormat.OpenXml.Spreadsheet;
|
|
||||||
using Mapster;
|
using Mapster;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Org.BouncyCastle.Asn1.Ocsp;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -18,8 +16,8 @@ using System.Threading.Tasks;
|
|||||||
namespace AsbCloudInfrastructure.Repository
|
namespace AsbCloudInfrastructure.Repository
|
||||||
{
|
{
|
||||||
#nullable enable
|
#nullable enable
|
||||||
public class ProcessMapRepository : CrudWellRelatedRepositoryBase<ProcessMapDto, ProcessMap>,
|
public class ProcessMapRepository : CrudWellRelatedRepositoryBase<ProcessMapPlanDto, ProcessMap>,
|
||||||
IProcessMapRepository
|
IProcessMapPlanRepository
|
||||||
{
|
{
|
||||||
private readonly IWellService wellService;
|
private readonly IWellService wellService;
|
||||||
|
|
||||||
@ -32,7 +30,7 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
this.wellService = wellService;
|
this.wellService = wellService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<ProcessMapDto>> GetAllAsync(int idWell,
|
public async Task<IEnumerable<ProcessMapPlanDto>> GetAllAsync(int idWell,
|
||||||
DateTime? updateFrom, CancellationToken token)
|
DateTime? updateFrom, CancellationToken token)
|
||||||
{
|
{
|
||||||
var requests = new[]
|
var requests = new[]
|
||||||
@ -53,7 +51,7 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
return dtos;
|
return dtos;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<ProcessMapDto>> GetProcessMapAsync(IEnumerable<ProcessMapRequest> requests, CancellationToken token)
|
public async Task<IEnumerable<ProcessMapPlanDto>> GetProcessMapAsync(IEnumerable<ProcessMapRequest> requests, CancellationToken token)
|
||||||
{
|
{
|
||||||
var entities = await BuildQuery(requests)
|
var entities = await BuildQuery(requests)
|
||||||
.ToListAsync(token)
|
.ToListAsync(token)
|
||||||
@ -62,7 +60,7 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
return dtos;
|
return dtos;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<int> InsertAsync(ProcessMapDto dto,
|
public override async Task<int> InsertAsync(ProcessMapPlanDto dto,
|
||||||
CancellationToken token)
|
CancellationToken token)
|
||||||
{
|
{
|
||||||
dto.LastUpdate = DateTime.UtcNow;
|
dto.LastUpdate = DateTime.UtcNow;
|
||||||
@ -70,7 +68,7 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<int> UpdateAsync(ProcessMapDto dto,
|
public override async Task<int> UpdateAsync(ProcessMapPlanDto dto,
|
||||||
CancellationToken token)
|
CancellationToken token)
|
||||||
{
|
{
|
||||||
dto.LastUpdate = DateTime.UtcNow;
|
dto.LastUpdate = DateTime.UtcNow;
|
||||||
@ -105,9 +103,9 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
}
|
}
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
protected override ProcessMapDto Convert(ProcessMap entity)
|
protected override ProcessMapPlanDto Convert(ProcessMap entity)
|
||||||
{
|
{
|
||||||
var dto = entity.Adapt<ProcessMapDto>();
|
var dto = entity.Adapt<ProcessMapPlanDto>();
|
||||||
dto.LastUpdate = entity.LastUpdate.ToRemoteDateTime(entity.Well.Timezone.Hours);
|
dto.LastUpdate = entity.LastUpdate.ToRemoteDateTime(entity.Well.Timezone.Hours);
|
||||||
dto.AxialLoad = new PlanLimitDto
|
dto.AxialLoad = new PlanLimitDto
|
||||||
{
|
{
|
||||||
@ -137,7 +135,7 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override ProcessMap Convert(ProcessMapDto dto)
|
protected override ProcessMap Convert(ProcessMapPlanDto dto)
|
||||||
{
|
{
|
||||||
var entity = dto.Adapt<ProcessMap>();
|
var entity = dto.Adapt<ProcessMap>();
|
||||||
entity.AxialLoadPlan = dto.AxialLoad.Plan;
|
entity.AxialLoadPlan = dto.AxialLoad.Plan;
|
||||||
|
@ -17,9 +17,9 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
public class WellCompositeRepository : IWellCompositeRepository
|
public class WellCompositeRepository : IWellCompositeRepository
|
||||||
{
|
{
|
||||||
private readonly IAsbCloudDbContext db;
|
private readonly IAsbCloudDbContext db;
|
||||||
private readonly IProcessMapRepository processMapRepository;
|
private readonly IProcessMapPlanRepository processMapRepository;
|
||||||
|
|
||||||
public WellCompositeRepository(IAsbCloudDbContext db, IProcessMapRepository processMapRepository)
|
public WellCompositeRepository(IAsbCloudDbContext db, IProcessMapPlanRepository processMapRepository)
|
||||||
{
|
{
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.processMapRepository = processMapRepository;
|
this.processMapRepository = processMapRepository;
|
||||||
@ -50,7 +50,7 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<IEnumerable<ProcessMapDto>> GetCompositeProcessMap(int idWell, CancellationToken token)
|
public async Task<IEnumerable<ProcessMapPlanDto>> GetCompositeProcessMap(int idWell, CancellationToken token)
|
||||||
{
|
{
|
||||||
var dtos = await GetAsync(idWell, token);
|
var dtos = await GetAsync(idWell, token);
|
||||||
|
|
||||||
|
@ -373,7 +373,9 @@ namespace AsbCloudInfrastructure.Repository
|
|||||||
.Where(subOp => subOp.IdType == o.IdType)
|
.Where(subOp => subOp.IdType == o.IdType)
|
||||||
.Where(subOp => subOp.DateStart <= o.DateStart)
|
.Where(subOp => subOp.DateStart <= o.DateStart)
|
||||||
.Min(subOp => subOp.DateStart))
|
.Min(subOp => subOp.DateStart))
|
||||||
.TotalDays
|
.TotalDays,
|
||||||
|
IdUser = o.IdUser,
|
||||||
|
LastUpdateDate = o.LastUpdateDate.ToOffset(TimeSpan.FromHours(timezone.Hours))
|
||||||
});
|
});
|
||||||
|
|
||||||
if (request.SortFields?.Any() == true)
|
if (request.SortFields?.Any() == true)
|
||||||
|
@ -186,18 +186,24 @@ namespace AsbCloudInfrastructure.Services.DailyReport
|
|||||||
var dto = entity.Info.Adapt<DailyReportDto>();
|
var dto = entity.Info.Adapt<DailyReportDto>();
|
||||||
dto.StartDate = entity.StartDate;
|
dto.StartDate = entity.StartDate;
|
||||||
|
|
||||||
var dailyFactOperation = factOperationsForDtos
|
var dailyFactOperations = factOperationsForDtos
|
||||||
.Where(o => DateOnly.FromDateTime(o.DateStart) == dto.StartDate)
|
.Where(o => DateOnly.FromDateTime(o.DateStart) == dto.StartDate)
|
||||||
.Where(o => o.IdParentCategory is not null)
|
.Where(o => o.IdParentCategory is not null);
|
||||||
|
|
||||||
|
var lastDailyFactOperation = dailyFactOperations
|
||||||
|
.OrderByDescending(o => o.LastUpdateDate)
|
||||||
|
.FirstOrDefault();
|
||||||
|
dto.TimeBalance.IdUser = lastDailyFactOperation?.IdUser;
|
||||||
|
dto.TimeBalance.LastUpdateDate = lastDailyFactOperation?.LastUpdateDate;
|
||||||
|
dto.TimeBalance.OperationsStat = dailyFactOperations
|
||||||
.GroupBy(o => o.IdParentCategory!.Value)
|
.GroupBy(o => o.IdParentCategory!.Value)
|
||||||
.ToDictionary(g => g.Key, g => g.Sum(o => o.DurationHours));
|
.ToDictionary(g => g.Key, g => g.Sum(o => o.DurationHours));
|
||||||
|
|
||||||
dto.TimeBalance.OperationsStat = dailyFactOperation;
|
|
||||||
|
|
||||||
var blocks = new ItemInfoDto[] {
|
var blocks = new ItemInfoDto[] {
|
||||||
dto.Head,
|
dto.Head,
|
||||||
dto.Bha,
|
dto.Bha,
|
||||||
dto.NoDrilling,
|
dto.NoDrilling,
|
||||||
|
dto.TimeBalance,
|
||||||
dto.Saub,
|
dto.Saub,
|
||||||
dto.Sign
|
dto.Sign
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,209 @@
|
|||||||
|
using AsbCloudApp.Data.ProcessMap;
|
||||||
|
using AsbCloudApp.Services;
|
||||||
|
using ClosedXML.Excel;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services.ProcessMap
|
||||||
|
{
|
||||||
|
#nullable enable
|
||||||
|
public class ProcessMapReportMakerService : IProcessMapReportMakerService
|
||||||
|
{
|
||||||
|
const int firstColumn = 2;
|
||||||
|
const int lastColumn = 49;
|
||||||
|
|
||||||
|
const int headerRowsCount = 5;
|
||||||
|
|
||||||
|
private readonly IProcessMapReportService processMapService;
|
||||||
|
|
||||||
|
public ProcessMapReportMakerService(IProcessMapReportService processMapService)
|
||||||
|
{
|
||||||
|
this.processMapService = processMapService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Stream> MakeReportAsync(int idWell, CancellationToken token)
|
||||||
|
{
|
||||||
|
var stream = GetExcelTemplateStream();
|
||||||
|
using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled);
|
||||||
|
|
||||||
|
var data = await processMapService.GetProcessMapReportAsync(idWell, token);
|
||||||
|
|
||||||
|
FillProcessMapToWorkbook(workbook, data);
|
||||||
|
|
||||||
|
MemoryStream memoryStream = new MemoryStream();
|
||||||
|
workbook.SaveAs(memoryStream, new SaveOptions { });
|
||||||
|
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
return memoryStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void FillProcessMapToWorkbook(XLWorkbook workbook, IEnumerable<ProcessMapReportDto> data)
|
||||||
|
{
|
||||||
|
var sheet = workbook.Worksheets.FirstOrDefault();
|
||||||
|
if (sheet is null)
|
||||||
|
return;
|
||||||
|
var dataBySections = data.GroupBy(p => p.IdWellSectionType);
|
||||||
|
FillSheet(sheet, dataBySections);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void FillSheet(IXLWorksheet sheet, IEnumerable<IGrouping<int, ProcessMapReportDto>> dataBySections)
|
||||||
|
{
|
||||||
|
var startRow = headerRowsCount + 1;
|
||||||
|
foreach (var sectionData in dataBySections)
|
||||||
|
{
|
||||||
|
if(sectionData.Any())
|
||||||
|
startRow = FillSection(sheet, sectionData, startRow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int FillSection(IXLWorksheet sheet, IGrouping<int, ProcessMapReportDto> sectionData, int row)
|
||||||
|
{
|
||||||
|
var rowStart = row;
|
||||||
|
|
||||||
|
var sectionName = sectionData.FirstOrDefault()?.WellSectionTypeName
|
||||||
|
?? sectionData.Key.ToString();
|
||||||
|
|
||||||
|
sheet.Range(row, firstColumn, row, lastColumn)
|
||||||
|
.Merge()
|
||||||
|
.FirstCell()
|
||||||
|
.SetVal(sectionName)
|
||||||
|
.Style
|
||||||
|
.Fill.SetBackgroundColor(XLColor.LightGray);
|
||||||
|
|
||||||
|
row++;
|
||||||
|
|
||||||
|
foreach (var interval in sectionData)
|
||||||
|
row = FillIntervalData(sheet, interval, row);
|
||||||
|
|
||||||
|
var sectionStyle = sheet.Range(rowStart, firstColumn, row - 1, lastColumn).Style;
|
||||||
|
SetBorders(sectionStyle);
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int FillIntervalData(IXLWorksheet sheet, ProcessMapReportDto interval, int row)
|
||||||
|
{
|
||||||
|
const int columnDepth = firstColumn + 1;
|
||||||
|
const int columnDate = firstColumn + 2;
|
||||||
|
const int columnRopTime = firstColumn + 3;
|
||||||
|
const int columnMode = firstColumn + 4;
|
||||||
|
|
||||||
|
sheet.Cell(row, firstColumn)
|
||||||
|
.SetVal(interval.DepthStart, "0.0");
|
||||||
|
|
||||||
|
sheet.Cell(row, columnDepth)
|
||||||
|
.SetVal(interval.DepthEnd, "0.0");
|
||||||
|
|
||||||
|
sheet.Cell(row, columnDate)
|
||||||
|
.SetVal(interval.DateStart);
|
||||||
|
|
||||||
|
sheet.Cell(row, columnRopTime)
|
||||||
|
.SetVal(interval.MechDrillingHours);
|
||||||
|
|
||||||
|
row = FillIntervalModeData(sheet, interval, columnMode, row);
|
||||||
|
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int FillIntervalModeData(IXLWorksheet sheet, ProcessMapReportDto modeData, int column, int row)
|
||||||
|
{
|
||||||
|
int columnDeltaDepth = column + 1;
|
||||||
|
int columnPressure = columnDeltaDepth + 1;
|
||||||
|
int columnLoad = columnPressure + 5;
|
||||||
|
int columnTorque = columnLoad + 5;
|
||||||
|
int columnSpeed = columnTorque + 5;
|
||||||
|
int columnUsagePlan = columnSpeed + 5;
|
||||||
|
int columnUsageFact = columnUsagePlan + 1;
|
||||||
|
int columnRop = columnUsageFact + 12;
|
||||||
|
|
||||||
|
sheet.Cell(row, column)
|
||||||
|
.SetVal(modeData.DrillingMode);
|
||||||
|
|
||||||
|
sheet.Cell(row, columnDeltaDepth)
|
||||||
|
.SetVal(modeData.DeltaDepth);
|
||||||
|
|
||||||
|
FillIntervalModeDataParam(sheet, modeData.PressureDiff, columnPressure, row);
|
||||||
|
FillIntervalModeDataParam(sheet, modeData.AxialLoad, columnLoad, row);
|
||||||
|
FillIntervalModeDataParam(sheet, modeData.TopDriveTorque, columnTorque, row);
|
||||||
|
FillIntervalModeDataSpeed(sheet, modeData.SpeedLimit, columnSpeed, row);
|
||||||
|
|
||||||
|
sheet.Cell(row, columnUsagePlan)
|
||||||
|
.SetVal(modeData.UsagePlan);
|
||||||
|
|
||||||
|
sheet.Cell(row, columnUsageFact)
|
||||||
|
.SetVal(modeData.UsageFact);
|
||||||
|
|
||||||
|
sheet.Cell(row, columnRop)
|
||||||
|
.SetVal(modeData.Rop);
|
||||||
|
|
||||||
|
return row + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void FillIntervalModeDataParam(IXLWorksheet sheet, ProcessMapReportParamsDto dataParam, int column, int row)
|
||||||
|
{
|
||||||
|
const int columnOffsetSpPlan = 0;
|
||||||
|
const int columnOffsetSpFact = 1;
|
||||||
|
const int columnOffsetFact = 2;
|
||||||
|
const int columnOffsetLimit = 3;
|
||||||
|
const int columnOffsetPercent = 4;
|
||||||
|
|
||||||
|
sheet.Cell(row, column + columnOffsetSpPlan)
|
||||||
|
.SetVal(dataParam.SetpointPlan);
|
||||||
|
|
||||||
|
sheet.Cell(row, column + columnOffsetSpFact)
|
||||||
|
.SetVal(dataParam.SetpointFact);
|
||||||
|
|
||||||
|
sheet.Cell(row, column + columnOffsetFact)
|
||||||
|
.SetVal(dataParam.Fact);
|
||||||
|
|
||||||
|
sheet.Cell(row, column + columnOffsetLimit)
|
||||||
|
.SetVal(dataParam.Limit);
|
||||||
|
|
||||||
|
sheet.Cell(row, column + columnOffsetPercent)
|
||||||
|
.SetVal(dataParam.SetpointUsage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void FillIntervalModeDataSpeed(IXLWorksheet sheet, ProcessMapReportParamsDto dataParam, int column, int row)
|
||||||
|
{
|
||||||
|
const int columnOffsetSpPlan = 0;
|
||||||
|
const int columnOffsetSpFact = 1;
|
||||||
|
const int columnOffsetFact = 2;
|
||||||
|
const int columnOffsetLimit = 3;
|
||||||
|
const int columnOffsetPercent = 4;
|
||||||
|
|
||||||
|
sheet.Cell(row, column + columnOffsetSpPlan)
|
||||||
|
.SetVal(dataParam.SetpointPlan);
|
||||||
|
|
||||||
|
sheet.Cell(row, column + columnOffsetSpFact)
|
||||||
|
.SetVal(dataParam.SetpointFact);
|
||||||
|
|
||||||
|
sheet.Cell(row, column + columnOffsetFact)
|
||||||
|
.SetVal(dataParam.Fact);
|
||||||
|
|
||||||
|
sheet.Cell(row, column + columnOffsetLimit)
|
||||||
|
.SetVal(dataParam.Limit);
|
||||||
|
|
||||||
|
sheet.Cell(row, column + columnOffsetPercent)
|
||||||
|
.SetVal(dataParam.SetpointUsage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Stream GetExcelTemplateStream()
|
||||||
|
{
|
||||||
|
var stream = System.Reflection.Assembly.GetExecutingAssembly()
|
||||||
|
.GetManifestResourceStream("AsbCloudInfrastructure.Services.ProcessMap.ProcessMapReportTemplate.xlsx");
|
||||||
|
return stream!;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IXLStyle SetBorders(IXLStyle style)
|
||||||
|
{
|
||||||
|
style.Border.RightBorder = XLBorderStyleValues.Thin ;
|
||||||
|
style.Border.LeftBorder = XLBorderStyleValues.Thin;
|
||||||
|
style.Border.TopBorder = XLBorderStyleValues.Thin ;
|
||||||
|
style.Border.BottomBorder = XLBorderStyleValues.Thin ;
|
||||||
|
style.Border.InsideBorder = XLBorderStyleValues.Thin ;
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#nullable disable
|
||||||
|
}
|
@ -1,216 +1,394 @@
|
|||||||
using AsbCloudApp.Data.ProcessMap;
|
using AsbCloudApp.Data.ProcessMap;
|
||||||
|
using AsbCloudApp.Data.SAUB;
|
||||||
|
using AsbCloudApp.Exceptions;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
using ClosedXML.Excel;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.ProcessMap
|
namespace AsbCloudInfrastructure.Services.ProcessMap
|
||||||
{
|
{
|
||||||
#nullable enable
|
#nullable enable
|
||||||
public class ProcessMapReportService : IProcessMapReportService
|
public partial class ProcessMapReportService : IProcessMapReportService
|
||||||
{
|
{
|
||||||
const int firstColumn = 2;
|
private readonly IWellService wellService;
|
||||||
const int lastColumn = 61;
|
private readonly IWellOperationRepository wellOperationRepository;
|
||||||
|
private readonly IProcessMapPlanRepository processMapPlanRepository;
|
||||||
|
private readonly ITelemetryDataSaubService telemetryDataSaubService;
|
||||||
|
|
||||||
const int headerRowsCount = 8;
|
public ProcessMapReportService(
|
||||||
|
IWellService wellService,
|
||||||
private readonly IProcessMapService processMapService;
|
IWellOperationRepository wellOperationRepository,
|
||||||
|
IProcessMapPlanRepository processMapPlanRepository,
|
||||||
public ProcessMapReportService(IProcessMapService processMapService)
|
ITelemetryDataSaubService telemetryDataSaubService)
|
||||||
{
|
{
|
||||||
this.processMapService = processMapService;
|
this.wellService = wellService;
|
||||||
|
this.wellOperationRepository = wellOperationRepository;
|
||||||
|
this.processMapPlanRepository = processMapPlanRepository;
|
||||||
|
this.telemetryDataSaubService = telemetryDataSaubService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Stream> MakeReportAsync(int idWell, CancellationToken token)
|
/// <inheritdoc/>
|
||||||
|
public async Task<IEnumerable<ProcessMapReportDto>> GetProcessMapReportAsync(int idWell, CancellationToken token)
|
||||||
{
|
{
|
||||||
var stream = GetExcelTemplateStream();
|
var well = wellService.GetOrDefault(idWell)
|
||||||
using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled);
|
?? throw new ArgumentInvalidException("idWell not found", nameof(idWell));
|
||||||
|
|
||||||
var data = await processMapService.GetProcessMapAsync(idWell, token);
|
var idTelemetry = well.IdTelemetry
|
||||||
|
?? throw new ArgumentInvalidException("telemetry by well not found", nameof(idWell));
|
||||||
|
|
||||||
FillProcessMapToWorkbook(workbook, data);
|
var processMapPlan = await processMapPlanRepository.GetByIdWellAsync(idWell, token);
|
||||||
|
|
||||||
MemoryStream memoryStream = new MemoryStream();
|
if (!processMapPlan.Any())
|
||||||
workbook.SaveAs(memoryStream, new SaveOptions { });
|
return Enumerable.Empty<ProcessMapReportDto>();
|
||||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
|
||||||
return memoryStream;
|
var telemetryDataStat = (await telemetryDataSaubService.GetTelemetryDataStatAsync(idTelemetry, token)).ToArray();
|
||||||
|
if (!telemetryDataStat.Any())
|
||||||
|
return Enumerable.Empty<ProcessMapReportDto>();
|
||||||
|
|
||||||
|
var result = CalcByIntervals(processMapPlan, telemetryDataStat);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void FillProcessMapToWorkbook(XLWorkbook workbook, IEnumerable<ProcessMapReportDto> data)
|
private IEnumerable<ProcessMapReportDto> CalcByIntervals(IEnumerable<ProcessMapPlanDto> processMapPlan, TelemetryDataSaubStatDto[] telemetryDataStat)
|
||||||
{
|
{
|
||||||
var sheet = workbook.Worksheets.FirstOrDefault();
|
var processMapIntervals = CalcDepthIntervals(processMapPlan);
|
||||||
if (sheet is null)
|
|
||||||
return;
|
var result = new List<ProcessMapReportDto>(processMapIntervals.Count() * 4);
|
||||||
var dataBySections = data.GroupBy(p => p.IdWellSectionType);
|
|
||||||
FillSheet(sheet, dataBySections);
|
var telemetryIndexStart = Array.FindIndex(telemetryDataStat, t => t.WellDepthMin >= processMapIntervals.First().DepthStart);
|
||||||
|
if (telemetryIndexStart < 0)
|
||||||
|
return Enumerable.Empty<ProcessMapReportDto>();
|
||||||
|
|
||||||
|
IDictionary<int, string> sectionTypes = wellOperationRepository.GetSectionTypes();
|
||||||
|
|
||||||
|
foreach (var interval in processMapIntervals)
|
||||||
|
{
|
||||||
|
var processMapPlanInterval = processMapPlan
|
||||||
|
.Where(p => p.DepthStart >= interval.DepthStart && p.DepthEnd <= interval.DepthEnd);
|
||||||
|
|
||||||
|
var telemetryIndexEnd = Array.FindIndex(telemetryDataStat, telemetryIndexStart, t => t.WellDepthMin >= interval.DepthEnd);
|
||||||
|
if (telemetryIndexEnd < 0)
|
||||||
|
telemetryIndexEnd = telemetryDataStat.Length - 1;
|
||||||
|
var telemetryDataInterval = telemetryDataStat.AsSpan(telemetryIndexStart, telemetryIndexEnd - telemetryIndexStart);
|
||||||
|
|
||||||
|
IEnumerable<ProcessMapReportDto> subIntervalsResult = CalcSubIntervals(interval, processMapPlanInterval, telemetryDataInterval, sectionTypes);
|
||||||
|
|
||||||
|
result.AddRange(subIntervalsResult);
|
||||||
|
telemetryIndexStart = telemetryIndexEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void FillSheet(IXLWorksheet sheet, IEnumerable<IGrouping<int, ProcessMapReportDto>> dataBySections)
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<(double DepthStart, double DepthEnd)> CalcDepthIntervals(IEnumerable<ProcessMapPlanDto> processMapPlan)
|
||||||
{
|
{
|
||||||
var startRow = headerRowsCount + 1;
|
if(!processMapPlan.Any())
|
||||||
foreach (var sectionData in dataBySections)
|
yield break;
|
||||||
|
|
||||||
|
var intervalStarts = processMapPlan
|
||||||
|
.OrderBy(i => i.DepthStart)
|
||||||
|
.Select(p => p.DepthStart)
|
||||||
|
.Distinct()
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
for (var i = 1; i < intervalStarts.Length; i++)
|
||||||
|
yield return (intervalStarts[i - 1], intervalStarts[i]);
|
||||||
|
|
||||||
|
yield return (intervalStarts[^1], processMapPlan.Max(p=>p.DepthEnd));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<ProcessMapReportDto> CalcSubIntervals(
|
||||||
|
(double DepthStart, double DepthEnd) interval,
|
||||||
|
IEnumerable<ProcessMapPlanDto> processMapPlanInterval,
|
||||||
|
Span<TelemetryDataSaubStatDto> telemetryDataInterval,
|
||||||
|
IDictionary<int, string> sectionTypes)
|
||||||
{
|
{
|
||||||
if(sectionData.Any())
|
var telemetryDataIntervalLength = telemetryDataInterval.Length;
|
||||||
startRow = FillSection(sheet, sectionData, startRow);
|
if (telemetryDataInterval.Length == 0)
|
||||||
|
return Enumerable.Empty<ProcessMapReportDto>();
|
||||||
|
|
||||||
|
var result = new List<ProcessMapReportDto>();
|
||||||
|
var telemetryIndexStart = 0;
|
||||||
|
var subInterval = interval;
|
||||||
|
|
||||||
|
for (var i = telemetryIndexStart + 1; i < telemetryDataIntervalLength; i++)
|
||||||
|
{
|
||||||
|
if (IsDifferent(telemetryDataInterval[telemetryIndexStart], telemetryDataInterval[i]))
|
||||||
|
{
|
||||||
|
subInterval.DepthEnd = telemetryDataInterval[i - 1].WellDepthMax;
|
||||||
|
var telemetryRowSpan = telemetryDataInterval[telemetryIndexStart..(i - 1)];
|
||||||
|
if (!telemetryRowSpan.IsEmpty)
|
||||||
|
{
|
||||||
|
var intervalReportRow = CalcSubIntervalReportRow(subInterval, processMapPlanInterval, telemetryRowSpan, sectionTypes);
|
||||||
|
result.Add(intervalReportRow);
|
||||||
|
}
|
||||||
|
telemetryIndexStart = i;
|
||||||
|
subInterval.DepthStart = subInterval.DepthEnd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int FillSection(IXLWorksheet sheet, IGrouping<int, ProcessMapReportDto> sectionData, int row)
|
subInterval.DepthEnd = interval.DepthEnd;
|
||||||
{
|
var intervalReportRowLast = CalcSubIntervalReportRow(subInterval, processMapPlanInterval, telemetryDataInterval[telemetryIndexStart..telemetryDataIntervalLength], sectionTypes);
|
||||||
var rowStart = row;
|
result.Add(intervalReportRowLast);
|
||||||
|
return result;
|
||||||
var sectionName = sectionData.FirstOrDefault()?.WellSectionTypeName
|
|
||||||
?? sectionData.Key.ToString();
|
|
||||||
|
|
||||||
sheet.Range(row, firstColumn, row, lastColumn)
|
|
||||||
.Merge()
|
|
||||||
.FirstCell()
|
|
||||||
.SetVal(sectionName)
|
|
||||||
.Style
|
|
||||||
.Fill.SetBackgroundColor(XLColor.LightGray);
|
|
||||||
|
|
||||||
row++;
|
|
||||||
|
|
||||||
foreach (var interval in sectionData)
|
|
||||||
row = FillIntervalData(sheet, interval, row);
|
|
||||||
|
|
||||||
var sectionStyle = sheet.Range(rowStart, firstColumn, row - 1, lastColumn).Style;
|
|
||||||
SetBorders(sectionStyle);
|
|
||||||
return row;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int FillIntervalData(IXLWorksheet sheet, ProcessMapReportDto interval, int row)
|
private static ProcessMapReportDto CalcSubIntervalReportRow(
|
||||||
|
(double DepthStart, double DepthEnd) subInterval,
|
||||||
|
IEnumerable<ProcessMapPlanDto> processMap,
|
||||||
|
Span<TelemetryDataSaubStatDto> telemetryRowSpan,
|
||||||
|
IDictionary<int, string> sectionTypes)
|
||||||
{
|
{
|
||||||
const int columnDepth = firstColumn + 1;
|
var telemetryStat = new TelemetryStat(telemetryRowSpan);
|
||||||
const int columnDate = firstColumn + 2;
|
var processMapByMode = processMap.FirstOrDefault(p => p.IdMode == telemetryStat.IdMode);
|
||||||
const int columnRopTime = firstColumn + 3;
|
var processMapFirst = processMap.First();
|
||||||
const int columnMode = firstColumn + 4;
|
var idWellSectionType = processMapByMode?.IdWellSectionType ?? processMapFirst.IdWellSectionType;
|
||||||
|
|
||||||
int rowRotor = row;
|
var result = new ProcessMapReportDto
|
||||||
int rowSlide = row + 1;
|
{
|
||||||
|
IdWell = processMapByMode?.IdWell ?? processMapFirst.IdWell,
|
||||||
|
IdWellSectionType = idWellSectionType,
|
||||||
|
WellSectionTypeName = sectionTypes[idWellSectionType],
|
||||||
|
|
||||||
sheet.Range(rowRotor, firstColumn, rowSlide, firstColumn)
|
DepthStart = subInterval.DepthStart,
|
||||||
.Merge();
|
DepthEnd = subInterval.DepthEnd,
|
||||||
|
DateStart = telemetryStat.DateStart,
|
||||||
|
|
||||||
sheet.Range(rowRotor, columnDepth, rowSlide, columnDepth)
|
MechDrillingHours = telemetryStat.MechDrillingHours,
|
||||||
.Merge().FirstCell()
|
DrillingMode = telemetryStat.ModeName,
|
||||||
.SetVal(interval.DepthStart, "0.0");
|
|
||||||
|
|
||||||
sheet.Range(rowRotor, columnDate, rowSlide, columnDate)
|
DeltaDepth = telemetryStat.DeltaDepth,
|
||||||
.Merge().FirstCell()
|
|
||||||
.SetVal(interval.DateStart);
|
|
||||||
|
|
||||||
sheet.Range(rowRotor, columnRopTime, rowSlide, columnRopTime)
|
PressureDiff = telemetryStat.Pressure.MakeParams(processMapByMode?.Pressure.Plan),
|
||||||
.Merge().FirstCell()
|
AxialLoad = telemetryStat.AxialLoad.MakeParams(processMapByMode?.AxialLoad.Plan),
|
||||||
.SetVal(interval.MechDrillingHours);
|
TopDriveTorque = telemetryStat.RotorTorque.MakeParams(processMapByMode?.TopDriveTorque.Plan),
|
||||||
|
SpeedLimit = telemetryStat.BlockSpeed.MakeParams(processMapByMode?.RopPlan),
|
||||||
|
|
||||||
row = FillIntervalModeData(sheet, "Ротор", interval.Rotor, columnMode, row);
|
Rop = telemetryStat.Rop,
|
||||||
row = FillIntervalModeData(sheet, "Слайд", interval.Slide, columnMode, row);
|
UsagePlan = processMapByMode?.UsageSaub ?? telemetryStat.UsagePredictPlan,
|
||||||
|
UsageFact = telemetryStat.UsageSaub,
|
||||||
return row;
|
};
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int FillIntervalModeData(IXLWorksheet sheet, string modeName, ProcessMapReportRowDto modeData, int column, int row)
|
private static bool IsDifferent(TelemetryDataSaubStatDto intervalStart, TelemetryDataSaubStatDto current)
|
||||||
{
|
{
|
||||||
int columnDeltaDepth = column + 1;
|
if (intervalStart.WellDepthMin > current.WellDepthMin)
|
||||||
int columnPressure = columnDeltaDepth + 1;
|
return true;
|
||||||
int columnLoad = columnPressure + 5;
|
|
||||||
int columnTorque = columnLoad + 5;
|
|
||||||
int columnSpeed = columnTorque + 5;
|
|
||||||
int columnUsagePlan = columnSpeed + 5;
|
|
||||||
int columnUsageFact = columnUsagePlan + 1;
|
|
||||||
int columnRop = columnUsageFact + 12;
|
|
||||||
|
|
||||||
sheet.Cell(row, column)
|
if (intervalStart.IdMode != current.IdMode)
|
||||||
.SetVal(modeName);
|
return true;
|
||||||
|
|
||||||
sheet.Cell(row, columnDeltaDepth)
|
if (Math.Abs(intervalStart.PressureSp - current.PressureSp) > 5d)
|
||||||
.SetVal(modeData.DeltaDepth);
|
return true;
|
||||||
|
|
||||||
FillIntervalModeDataParam(sheet, modeData.PressureDiff, columnPressure, row);
|
if (Math.Abs(intervalStart.AxialLoadSp - current.AxialLoadSp) > 1d)
|
||||||
FillIntervalModeDataParam(sheet, modeData.AxialLoad, columnLoad, row);
|
return true;
|
||||||
FillIntervalModeDataParam(sheet, modeData.TopDriveTorque, columnTorque, row);
|
|
||||||
FillIntervalModeDataSpeed(sheet, modeData.SpeedLimit, columnSpeed, row);
|
|
||||||
|
|
||||||
sheet.Cell(row, columnUsagePlan)
|
if (Math.Abs(intervalStart.RotorTorqueSp - current.RotorTorqueSp) > 5d)
|
||||||
.SetVal(100);
|
return true;
|
||||||
|
|
||||||
sheet.Cell(row, columnUsageFact)
|
var blockSpeedSpDiff = Math.Abs(intervalStart.BlockSpeedSp - current.BlockSpeedSp);
|
||||||
.SetVal(modeData.Usage);
|
if (blockSpeedSpDiff > 5d)
|
||||||
|
{
|
||||||
sheet.Cell(row, columnRop)
|
if (intervalStart.BlockSpeedSp <= 30)
|
||||||
.SetVal(modeData.Rop);
|
return true;
|
||||||
|
else if (intervalStart.BlockSpeedSp > 30 && blockSpeedSpDiff > 15d)
|
||||||
return row + 1;
|
return true;
|
||||||
|
else if (intervalStart.BlockSpeedSp > 80 && blockSpeedSpDiff > 20d)
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void FillIntervalModeDataParam(IXLWorksheet sheet, ProcessMapReportParamsDto dataParam, int column, int row)
|
return false;
|
||||||
{
|
|
||||||
const int columnOffsetSpPlan = 0;
|
|
||||||
const int columnOffsetSpFact = 1;
|
|
||||||
const int columnOffsetFact = 2;
|
|
||||||
const int columnOffsetLimit = 3;
|
|
||||||
const int columnOffsetPercent = 4;
|
|
||||||
|
|
||||||
sheet.Cell(row, column + columnOffsetSpPlan)
|
|
||||||
.SetVal(dataParam.SetpointPlan);
|
|
||||||
|
|
||||||
sheet.Cell(row, column + columnOffsetSpFact)
|
|
||||||
.SetVal(dataParam.SetpointFact);
|
|
||||||
|
|
||||||
sheet.Cell(row, column + columnOffsetFact)
|
|
||||||
.SetVal(dataParam.Fact);
|
|
||||||
|
|
||||||
sheet.Cell(row, column + columnOffsetLimit)
|
|
||||||
.SetVal(dataParam.Limit);
|
|
||||||
|
|
||||||
sheet.Cell(row, column + columnOffsetPercent)
|
|
||||||
.SetVal(dataParam.PercDrillingSetpoint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void FillIntervalModeDataSpeed(IXLWorksheet sheet, ProcessMapReportParamsDto dataParam, int column, int row)
|
|
||||||
{
|
|
||||||
const int columnOffsetSpPlan = 0;
|
|
||||||
const int columnOffsetSpFact = 1;
|
|
||||||
const int columnOffsetFact = 2;
|
|
||||||
const int columnOffsetLimit = 3;
|
|
||||||
const int columnOffsetPercent = 4;
|
|
||||||
|
|
||||||
sheet.Cell(row, column + columnOffsetSpPlan)
|
|
||||||
.SetVal(dataParam.SetpointPlan);
|
|
||||||
|
|
||||||
sheet.Cell(row, column + columnOffsetSpFact)
|
|
||||||
.SetVal(dataParam.SetpointFact);
|
|
||||||
|
|
||||||
sheet.Cell(row, column + columnOffsetFact)
|
|
||||||
.SetVal(dataParam.Fact);
|
|
||||||
|
|
||||||
sheet.Cell(row, column + columnOffsetLimit)
|
|
||||||
.SetVal(dataParam.Limit);
|
|
||||||
|
|
||||||
sheet.Cell(row, column + columnOffsetPercent)
|
|
||||||
.SetVal(dataParam.PercDrillingSetpoint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Stream GetExcelTemplateStream()
|
class ParamStat
|
||||||
{
|
{
|
||||||
var stream = System.Reflection.Assembly.GetExecutingAssembly()
|
private double spWSum;
|
||||||
.GetManifestResourceStream("AsbCloudInfrastructure.Services.ProcessMap.ProcessMapReportTemplate.xlsx");
|
private double pvWSum;
|
||||||
return stream!;
|
private double limitMaxWSum;
|
||||||
|
|
||||||
|
private double deltaDepthSum;
|
||||||
|
|
||||||
|
private readonly Func<TelemetryDataSaubStatDto, double> getterSp;
|
||||||
|
private readonly Func<TelemetryDataSaubStatDto, double> getterPv;
|
||||||
|
private readonly Func<TelemetryDataSaubStatDto, double>? getterLimitMax;
|
||||||
|
|
||||||
|
private readonly int idFeedRegulator;
|
||||||
|
private readonly int idMode;
|
||||||
|
private TelemetryDataSaubStatDto? previous;
|
||||||
|
|
||||||
|
public double SpUsageDepth { get; private set; }
|
||||||
|
private static double spUsageTotal;
|
||||||
|
|
||||||
|
public ParamStat(Func<TelemetryDataSaubStatDto, double> getterSp,
|
||||||
|
Func<TelemetryDataSaubStatDto, double> getterPv,
|
||||||
|
Func<TelemetryDataSaubStatDto, double>? getterLimitMax,
|
||||||
|
int idFeedRegulator,
|
||||||
|
int idMode)
|
||||||
|
{
|
||||||
|
this.getterSp = getterSp;
|
||||||
|
this.getterPv = getterPv;
|
||||||
|
this.getterLimitMax = getterLimitMax;
|
||||||
|
this.idFeedRegulator = idFeedRegulator;
|
||||||
|
this.idMode = idMode;
|
||||||
|
spUsageTotal = 0d;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IXLStyle SetBorders(IXLStyle style)
|
public void UpdateStat(TelemetryDataSaubStatDto current)
|
||||||
{
|
{
|
||||||
style.Border.RightBorder = XLBorderStyleValues.Thin ;
|
if(previous is not null)
|
||||||
style.Border.LeftBorder = XLBorderStyleValues.Thin;
|
{
|
||||||
style.Border.TopBorder = XLBorderStyleValues.Thin ;
|
var deltaDepth = current.WellDepthMin - previous.WellDepthMin;
|
||||||
style.Border.BottomBorder = XLBorderStyleValues.Thin ;
|
if (deltaDepth > 0)
|
||||||
style.Border.InsideBorder = XLBorderStyleValues.Thin ;
|
{
|
||||||
return style;
|
var deltaDepthHalf = deltaDepth / 2;
|
||||||
|
double CalculateWeight(Func<TelemetryDataSaubStatDto, double> getter) => (getter(previous!) + getter(current)) * deltaDepthHalf;
|
||||||
|
|
||||||
|
spWSum += CalculateWeight(getterSp);
|
||||||
|
pvWSum += CalculateWeight(getterPv);
|
||||||
|
if(getterLimitMax is not null)
|
||||||
|
limitMaxWSum += CalculateWeight(getterLimitMax!);
|
||||||
|
|
||||||
|
if (current.IdFeedRegulator is not null)
|
||||||
|
{
|
||||||
|
if (current.IdFeedRegulator == idFeedRegulator)
|
||||||
|
{
|
||||||
|
SpUsageDepth += deltaDepth;
|
||||||
|
spUsageTotal += deltaDepth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var pvErr = (getterSp(current) - getterPv(current)) / getterSp(current);
|
||||||
|
if (pvErr < 0.03d) //3%
|
||||||
|
{
|
||||||
|
SpUsageDepth += deltaDepth;
|
||||||
|
spUsageTotal += deltaDepth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deltaDepthSum += deltaDepth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
previous = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProcessMapReportParamsDto MakeParams(double? spPlan)
|
||||||
|
{
|
||||||
|
var result = new ProcessMapReportParamsDto
|
||||||
|
{
|
||||||
|
SetpointPlan = spPlan,
|
||||||
|
Fact = DivideValByDepth(pvWSum),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (idMode == 0)
|
||||||
|
{
|
||||||
|
result.SetpointFact = null;
|
||||||
|
result.Limit = null;
|
||||||
|
result.SetpointUsage = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.SetpointFact = DivideValByDepth(spWSum);
|
||||||
|
result.Limit = (getterLimitMax is not null) ? DivideValByDepth(limitMaxWSum) : null;
|
||||||
|
result.SetpointUsage = deltaDepthSum > 0d ? 100d * SpUsageDepth / spUsageTotal : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double? DivideValByDepth(double? val)
|
||||||
|
{
|
||||||
|
if(val is null || val == 0d || deltaDepthSum == 0d)
|
||||||
|
return null;
|
||||||
|
return val / deltaDepthSum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TelemetryStat {
|
||||||
|
public ParamStat Pressure { get; }
|
||||||
|
public ParamStat AxialLoad {get; }
|
||||||
|
public ParamStat RotorTorque {get; }
|
||||||
|
public ParamStat BlockSpeed {get; }
|
||||||
|
|
||||||
|
private TelemetryDataSaubStatDto? previous;
|
||||||
|
private double depthSum = 0d;
|
||||||
|
private double hoursSum = 0d;
|
||||||
|
|
||||||
|
public double? Rop => hoursSum == 0d ? null : depthSum / hoursSum;
|
||||||
|
|
||||||
|
private double depthWithSaub = 0d;
|
||||||
|
public double UsageSaub { get; }
|
||||||
|
public double UsagePredictPlan { get; }
|
||||||
|
public DateTime DateStart { get; }
|
||||||
|
public float DeltaDepth { get; }
|
||||||
|
public int IdMode { get; }
|
||||||
|
public string ModeName { get; }
|
||||||
|
public double MechDrillingHours { get; }
|
||||||
|
|
||||||
|
public TelemetryStat(Span<TelemetryDataSaubStatDto> telemetry)
|
||||||
|
{
|
||||||
|
var telemetryFirst = telemetry[0];
|
||||||
|
var telemetryLast = telemetry[^1];
|
||||||
|
|
||||||
|
IdMode = telemetryFirst.IdMode;
|
||||||
|
ModeName = GetModeName(IdMode);
|
||||||
|
DateStart = telemetryFirst.DateMin;
|
||||||
|
DeltaDepth = telemetryLast.WellDepthMax - telemetryFirst.WellDepthMin;
|
||||||
|
MechDrillingHours = (telemetryLast.DateMax - telemetryFirst.DateMin).TotalHours;
|
||||||
|
|
||||||
|
BlockSpeed = new(t => t.BlockSpeedSp, t => t.BlockSpeed, null, 1, IdMode);
|
||||||
|
Pressure = new(t => t.PressureSp, t => t.Pressure, t=>t.PressureDeltaLimitMax, 2, IdMode);
|
||||||
|
RotorTorque = new(t => t.RotorTorqueSp, t => t.RotorTorque, t=>t.RotorTorqueLimitMax, 3, IdMode);
|
||||||
|
AxialLoad = new(t => t.AxialLoadSp, t => t.AxialLoad, t=>t.AxialLoadLimitMax, 4, IdMode);
|
||||||
|
|
||||||
|
for (int i = 0; i < telemetry.Length; i++)
|
||||||
|
UpdateStat(telemetry[i]);
|
||||||
|
|
||||||
|
UsageSaub = 100d * depthWithSaub / depthSum;
|
||||||
|
UsagePredictPlan = IdMode != 0 ? 100d : 0d;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateStat(TelemetryDataSaubStatDto current)
|
||||||
|
{
|
||||||
|
if(previous is not null)
|
||||||
|
{
|
||||||
|
var deltaDepth = current.WellDepthMin - previous.WellDepthMin;
|
||||||
|
if(deltaDepth > 0)
|
||||||
|
{
|
||||||
|
var deltaHours = (current.DateMin - previous.DateMax).TotalHours;
|
||||||
|
depthSum += deltaDepth;
|
||||||
|
hoursSum += deltaHours;
|
||||||
|
|
||||||
|
if(current.IdMode == 1 || current.IdMode == 3)
|
||||||
|
depthWithSaub += deltaDepth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
previous = current;
|
||||||
|
Pressure.UpdateStat(current);
|
||||||
|
AxialLoad.UpdateStat(current);
|
||||||
|
RotorTorque.UpdateStat(current);
|
||||||
|
BlockSpeed.UpdateStat(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetModeName(int idMode)
|
||||||
|
=> idMode switch
|
||||||
|
{
|
||||||
|
1 => "Ротор",
|
||||||
|
3 => "Слайд",
|
||||||
|
_ => "Ручной",
|
||||||
|
};
|
||||||
|
}
|
||||||
#nullable disable
|
#nullable disable
|
||||||
}
|
}
|
Binary file not shown.
@ -1,348 +0,0 @@
|
|||||||
using AsbCloudApp.Data;
|
|
||||||
using AsbCloudApp.Data.ProcessMap;
|
|
||||||
using AsbCloudApp.Data.SAUB;
|
|
||||||
using AsbCloudApp.Exceptions;
|
|
||||||
using AsbCloudApp.Repositories;
|
|
||||||
using AsbCloudApp.Requests;
|
|
||||||
using AsbCloudApp.Services;
|
|
||||||
using AsbCloudApp.Services.Subsystems;
|
|
||||||
using AsbCloudDb.Model;
|
|
||||||
using AsbCloudApp.Data.Subsystems;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using AsbCloudInfrastructure.Services.Subsystems;
|
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.ProcessMap
|
|
||||||
{
|
|
||||||
#nullable enable
|
|
||||||
public partial class ProcessMapService : IProcessMapService
|
|
||||||
{
|
|
||||||
private readonly IWellService wellService;
|
|
||||||
private readonly IWellOperationRepository wellOperationRepository;
|
|
||||||
private readonly IProcessMapRepository processMapRepository;
|
|
||||||
private readonly ITelemetryDataSaubService telemetryDataSaubService;
|
|
||||||
private readonly ILimitingParameterRepository limitingParameterRepository;
|
|
||||||
private readonly ISubsystemOperationTimeService subsystemOperationTimeService;
|
|
||||||
|
|
||||||
public ProcessMapService(
|
|
||||||
IWellService wellService,
|
|
||||||
IWellOperationRepository wellOperationService,
|
|
||||||
IProcessMapRepository processMapRepository,
|
|
||||||
ITelemetryDataSaubService telemetryDataSaubService,
|
|
||||||
ILimitingParameterRepository limitingParameterRepository,
|
|
||||||
ISubsystemOperationTimeService subsystemOperationTimeService)
|
|
||||||
{
|
|
||||||
this.wellService = wellService;
|
|
||||||
this.wellOperationRepository = wellOperationService;
|
|
||||||
this.processMapRepository = processMapRepository;
|
|
||||||
this.telemetryDataSaubService = telemetryDataSaubService;
|
|
||||||
this.limitingParameterRepository = limitingParameterRepository;
|
|
||||||
this.subsystemOperationTimeService = subsystemOperationTimeService;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public async Task<IEnumerable<ProcessMapReportDto>> GetProcessMapAsync(int idWell, CancellationToken token)
|
|
||||||
{
|
|
||||||
var well = wellService.GetOrDefault(idWell)
|
|
||||||
?? throw new ArgumentInvalidException("idWell not found", nameof(idWell));
|
|
||||||
var idTelemetry = well.IdTelemetry
|
|
||||||
?? throw new ArgumentInvalidException("telemetry by well not found", nameof(idWell));
|
|
||||||
|
|
||||||
var processMap = (await processMapRepository.GetByIdWellAsync(idWell, token))!;
|
|
||||||
var factDrillingOperations = await GetFactDrillingOperationsAsync(idWell, token);
|
|
||||||
var telemetryDataStat = await telemetryDataSaubService.GetTelemetryDataStatAsync(idTelemetry, token);
|
|
||||||
var limitingParameters = await limitingParameterRepository.GetLimitingParametersAsync(new(), well, token);
|
|
||||||
var subsystemsOperationTime = await GetOperationTimeAsync(idWell, token);
|
|
||||||
|
|
||||||
var result = factDrillingOperations
|
|
||||||
.GroupBy(o => o.IdWellSectionType)
|
|
||||||
.SelectMany(sectionOperations =>
|
|
||||||
{
|
|
||||||
var sectionProcessMap = processMap.Where(p => p.IdWellSectionType == sectionOperations.Key);
|
|
||||||
return HandleSection(sectionOperations, sectionProcessMap, telemetryDataStat, limitingParameters, subsystemsOperationTime!);
|
|
||||||
})
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task<IEnumerable<SubsystemOperationTimeDto>?> GetOperationTimeAsync(int idWell, CancellationToken token)
|
|
||||||
{
|
|
||||||
var request = new SubsystemOperationTimeRequest
|
|
||||||
{
|
|
||||||
IdWell = idWell,
|
|
||||||
IdsSubsystems = new int[] { SubsystemOperationTimeService.IdSubsystemAKB, SubsystemOperationTimeService.IdSubsystemSpin },
|
|
||||||
};
|
|
||||||
return subsystemOperationTimeService.GetOperationTimeAsync(request, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<IEnumerable<WellOperationDto>> GetFactDrillingOperationsAsync(int idWell, CancellationToken token)
|
|
||||||
{
|
|
||||||
var operationsRequest = new WellOperationRequest
|
|
||||||
{
|
|
||||||
IdWell = idWell,
|
|
||||||
OperationCategoryIds = WellOperationCategory.MechanicalDrillingSubIds,
|
|
||||||
OperationType = WellOperation.IdOperationTypeFact,
|
|
||||||
SortFields = new[] { nameof(WellOperation.DateStart) }
|
|
||||||
};
|
|
||||||
|
|
||||||
var allFactDrillingOperations = await wellOperationRepository.GetAsync(operationsRequest, token);
|
|
||||||
var factDrillingOperations = allFactDrillingOperations.Where(o => o.DepthEnd > o.DepthStart);
|
|
||||||
return factDrillingOperations;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<ProcessMapReportDto> HandleSection(
|
|
||||||
IEnumerable<WellOperationDto> sectionOperations,
|
|
||||||
IEnumerable<ProcessMapDto> sectionProcessMap,
|
|
||||||
IEnumerable<TelemetryDataSaubStatDto> telemetryDataStat,
|
|
||||||
IEnumerable<LimitingParameterDataDto> limitingParameters,
|
|
||||||
IEnumerable<SubsystemOperationTimeDto> subsystemsOperationTime)
|
|
||||||
{
|
|
||||||
var minDepth = sectionOperations.Min(o => o.DepthStart);
|
|
||||||
var maxDepth = sectionOperations.Max(o => o.DepthEnd);
|
|
||||||
|
|
||||||
var depthIntervals = SplitByIntervals(minDepth, maxDepth).ToArray();
|
|
||||||
var result = new ProcessMapReportDto[depthIntervals.Length];
|
|
||||||
|
|
||||||
for (var i = 0; i < depthIntervals.Length; i++ )
|
|
||||||
result[i] = MakeProcessMapReportDto(depthIntervals[i], sectionOperations, sectionProcessMap, telemetryDataStat, limitingParameters, subsystemsOperationTime);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ProcessMapReportDto MakeProcessMapReportDto(
|
|
||||||
(double min, double max) depthInterval,
|
|
||||||
IEnumerable<WellOperationDto> sectionOperations,
|
|
||||||
IEnumerable<ProcessMapDto> sectionProcessMap,
|
|
||||||
IEnumerable<TelemetryDataSaubStatDto> telemetryDataStat,
|
|
||||||
IEnumerable<LimitingParameterDataDto> limitingParameters,
|
|
||||||
IEnumerable<SubsystemOperationTimeDto> subsystemsOperationTime)
|
|
||||||
{
|
|
||||||
var dto = new ProcessMapReportDto{
|
|
||||||
DepthStart = depthInterval.min
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: trim items by detpth intervals. Use linear interpolation.
|
|
||||||
var intervalOperations = sectionOperations.Where(o => o.DepthEnd >= depthInterval.min && o.DepthStart <= depthInterval.max);
|
|
||||||
var intervalProcessMap = sectionProcessMap.Where(map => map.DepthEnd >= depthInterval.min && map.DepthStart <= depthInterval.max);
|
|
||||||
var intervalTelemetryDataStat = CalcIntervalTelemetryDataStat(depthInterval, telemetryDataStat);
|
|
||||||
var intervalLimitingParametrs = limitingParameters.Where(l => l.DepthEnd >= depthInterval.min && l.DepthStart <= depthInterval.max);
|
|
||||||
var intervalSubsystemsOperationTime = subsystemsOperationTime.Where(o => o.DepthEnd >= depthInterval.min && o.DepthStart <= depthInterval.max);
|
|
||||||
|
|
||||||
var firstIntervalOperation = intervalOperations.FirstOrDefault();
|
|
||||||
if (firstIntervalOperation is not null)
|
|
||||||
{
|
|
||||||
dto.DateStart = GetInterpolatedDate(firstIntervalOperation, depthInterval.min);
|
|
||||||
dto.IdWell = firstIntervalOperation.IdWell;
|
|
||||||
dto.IdWellSectionType = firstIntervalOperation.IdWellSectionType;
|
|
||||||
dto.WellSectionTypeName = firstIntervalOperation.WellSectionTypeName ?? string.Empty;
|
|
||||||
dto.MechDrillingHours = CalcHours(depthInterval, intervalOperations);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Разделить интервальные коллекции на ротор и слайд. Пока нет готовой методики.
|
|
||||||
var slideOperations = intervalOperations.Where(o => o.IdCategory == WellOperationCategory.IdSlide);
|
|
||||||
var rotorOperations = intervalOperations.Where(o => o.IdCategory == WellOperationCategory.IdRotor);
|
|
||||||
|
|
||||||
dto.Slide = CalcDrillModeStat(depthInterval, slideOperations, intervalProcessMap, intervalTelemetryDataStat, intervalLimitingParametrs, intervalSubsystemsOperationTime);
|
|
||||||
dto.Rotor = CalcDrillModeStat(depthInterval, rotorOperations, intervalProcessMap, intervalTelemetryDataStat, intervalLimitingParametrs, intervalSubsystemsOperationTime);
|
|
||||||
|
|
||||||
return dto;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TelemetryDataSaubStatDto? CalcIntervalTelemetryDataStat((double min, double max) depthInterval, IEnumerable<TelemetryDataSaubStatDto> telemetryDataStat)
|
|
||||||
{
|
|
||||||
TelemetryDataSaubStatDto[] data = telemetryDataStat
|
|
||||||
.Where(d => d.WellDepthMin <= depthInterval.max && d.WellDepthMax >= depthInterval.min)
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
if (!data.Any())
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (data.Length == 1)
|
|
||||||
return data.First();
|
|
||||||
|
|
||||||
var result = new TelemetryDataSaubStatDto
|
|
||||||
{
|
|
||||||
WellDepthMin = data.Min(d => d.WellDepthMin),
|
|
||||||
WellDepthMax = data.Max(d => d.WellDepthMax),
|
|
||||||
DateMin = data.Min(d => d.DateMin),
|
|
||||||
DateMax = data.Max(d => d.DateMax),
|
|
||||||
};
|
|
||||||
|
|
||||||
var intervalDeltaDepth = result.WellDepthMax - result.WellDepthMin;
|
|
||||||
|
|
||||||
foreach (var item in data)
|
|
||||||
{
|
|
||||||
var itemWeight = (item.WellDepthMax - item.WellDepthMin) / intervalDeltaDepth;
|
|
||||||
|
|
||||||
result.Pressure += item.Pressure * itemWeight;
|
|
||||||
result.PressureSp += item.PressureSp * itemWeight;
|
|
||||||
result.PressureSpRotor += item.PressureSpSlide * itemWeight;
|
|
||||||
result.PressureIdle += item.PressureIdle * itemWeight;
|
|
||||||
result.PressureDelta += item.PressureDelta * itemWeight;
|
|
||||||
|
|
||||||
result.AxialLoad += item.AxialLoad * itemWeight;
|
|
||||||
result.AxialLoadSp += item.AxialLoadSp * itemWeight;
|
|
||||||
result.AxialLoadLimitMax += item.AxialLoadLimitMax * itemWeight;
|
|
||||||
|
|
||||||
result.RotorTorque += item.RotorTorque * itemWeight;
|
|
||||||
result.RotorTorqueSp += item.RotorTorqueSp * itemWeight;
|
|
||||||
result.RotorTorqueLimitMax += item.RotorTorqueLimitMax * itemWeight;
|
|
||||||
|
|
||||||
result.BlockSpeed += item.BlockSpeed * itemWeight;
|
|
||||||
result.BlockSpeedSp += item.BlockSpeedSp * itemWeight;
|
|
||||||
result.BlockSpeedSpRotor += item.BlockSpeedSpRotor * itemWeight;
|
|
||||||
result.BlockSpeedSpSlide += item.BlockSpeedSpSlide * itemWeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ProcessMapReportRowDto CalcDrillModeStat(
|
|
||||||
(double min, double max) depthInterval,
|
|
||||||
IEnumerable<WellOperationDto> intervalModeOperations,
|
|
||||||
IEnumerable<ProcessMapDto> intervalProcessMap,
|
|
||||||
TelemetryDataSaubStatDto? telemetryDataStat,
|
|
||||||
IEnumerable<LimitingParameterDataDto> intervalLimitingParametrs,
|
|
||||||
IEnumerable<SubsystemOperationTimeDto> intervalSubsystemsOperationTime)
|
|
||||||
{
|
|
||||||
var dto = new ProcessMapReportRowDto();
|
|
||||||
if (intervalModeOperations.Any())
|
|
||||||
{
|
|
||||||
var deltaDepth = CalcDeltaDepth(depthInterval, intervalModeOperations);
|
|
||||||
dto.DeltaDepth = deltaDepth;
|
|
||||||
dto.Rop = deltaDepth / CalcHours(depthInterval, intervalModeOperations);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (intervalProcessMap.Any())
|
|
||||||
{
|
|
||||||
var processMapFirst = intervalProcessMap.First();
|
|
||||||
dto.PressureDiff.SetpointPlan = processMapFirst.Pressure.Plan;
|
|
||||||
dto.AxialLoad.SetpointPlan = processMapFirst.AxialLoad.Plan;
|
|
||||||
dto.TopDriveTorque.SetpointPlan = processMapFirst.TopDriveTorque.Plan;
|
|
||||||
//dto.SpeedLimit.SetpointPlan = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (telemetryDataStat is not null)
|
|
||||||
{
|
|
||||||
dto.PressureDiff.SetpointFact = telemetryDataStat.PressureSp;
|
|
||||||
dto.PressureDiff.Fact = telemetryDataStat.PressureDelta;
|
|
||||||
dto.PressureDiff.Limit = telemetryDataStat.PressureDeltaLimitMax;
|
|
||||||
|
|
||||||
dto.AxialLoad.SetpointFact = telemetryDataStat.AxialLoadSp;
|
|
||||||
dto.AxialLoad.Fact = telemetryDataStat.AxialLoad;
|
|
||||||
dto.AxialLoad.Limit = telemetryDataStat.AxialLoadLimitMax;
|
|
||||||
|
|
||||||
dto.TopDriveTorque.SetpointFact = telemetryDataStat.RotorTorqueSp;
|
|
||||||
dto.TopDriveTorque.Fact = telemetryDataStat.RotorTorque;
|
|
||||||
dto.TopDriveTorque.Limit = telemetryDataStat.RotorTorqueLimitMax;
|
|
||||||
|
|
||||||
dto.SpeedLimit.SetpointFact = telemetryDataStat.BlockSpeedSp;
|
|
||||||
dto.SpeedLimit.Fact = telemetryDataStat.BlockSpeed;
|
|
||||||
//dto.SpeedLimit.Limit = mull;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(intervalLimitingParametrs.Any())
|
|
||||||
{
|
|
||||||
const int idLimParamRop = 1;
|
|
||||||
const int idLimParamPressure = 2;
|
|
||||||
const int idLimParamAxialLoad = 3;
|
|
||||||
const int idLimParamTorque = 4;
|
|
||||||
|
|
||||||
var intervalLimitingParametrsStat = intervalLimitingParametrs
|
|
||||||
.GroupBy(p => p.IdFeedRegulator)
|
|
||||||
.Select(g => new
|
|
||||||
{
|
|
||||||
IdLimParam = g.Key,
|
|
||||||
SumDepth = g.Sum(p => p.DepthEnd - p.DepthStart),
|
|
||||||
});
|
|
||||||
|
|
||||||
var totalDepth = intervalLimitingParametrsStat
|
|
||||||
.Sum(s => s.SumDepth);
|
|
||||||
|
|
||||||
if (totalDepth > 0)
|
|
||||||
{
|
|
||||||
dto.AxialLoad.PercDrillingSetpoint = intervalLimitingParametrsStat
|
|
||||||
.FirstOrDefault(s => s.IdLimParam == idLimParamAxialLoad)?.SumDepth / totalDepth;
|
|
||||||
|
|
||||||
dto.PressureDiff.PercDrillingSetpoint = intervalLimitingParametrsStat
|
|
||||||
.FirstOrDefault(s => s.IdLimParam == idLimParamPressure)?.SumDepth / totalDepth;
|
|
||||||
|
|
||||||
dto.TopDriveTorque.PercDrillingSetpoint = intervalLimitingParametrsStat
|
|
||||||
.FirstOrDefault(s => s.IdLimParam == idLimParamTorque)?.SumDepth / totalDepth;
|
|
||||||
|
|
||||||
dto.SpeedLimit.PercDrillingSetpoint = intervalLimitingParametrsStat
|
|
||||||
.FirstOrDefault(s => s.IdLimParam == idLimParamRop)?.SumDepth / totalDepth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (intervalSubsystemsOperationTime.Any() && dto.DeltaDepth > 0)
|
|
||||||
{
|
|
||||||
dto.Usage = intervalSubsystemsOperationTime.Sum(t => t.DepthEnd - t.DepthStart) / dto.DeltaDepth.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dto;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static double CalcDeltaDepth((double min, double max) depthInterval, IEnumerable<WellOperationDto> intervalOperations)
|
|
||||||
{
|
|
||||||
var ddepth = 0d;
|
|
||||||
foreach (var operation in intervalOperations)
|
|
||||||
{
|
|
||||||
var depthStart = operation.DepthStart > depthInterval.min
|
|
||||||
? operation.DepthStart
|
|
||||||
: depthInterval.min;
|
|
||||||
|
|
||||||
var depthEnd = operation.DepthEnd < depthInterval.max
|
|
||||||
? operation.DepthEnd
|
|
||||||
: depthInterval.max;
|
|
||||||
|
|
||||||
ddepth += (depthEnd - depthEnd);
|
|
||||||
}
|
|
||||||
return ddepth;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static double CalcHours((double min, double max) depthInterval, IEnumerable<WellOperationDto> intervalOperations)
|
|
||||||
{
|
|
||||||
var hours = 0d;
|
|
||||||
foreach (var operation in intervalOperations)
|
|
||||||
{
|
|
||||||
var dateStart = operation.DepthStart > depthInterval.min
|
|
||||||
? operation.DateStart
|
|
||||||
: GetInterpolatedDate(operation, depthInterval.min);
|
|
||||||
|
|
||||||
var dateEnd = operation.DepthEnd < depthInterval.max
|
|
||||||
? operation.DateStart + TimeSpan.FromHours(operation.DurationHours)
|
|
||||||
: GetInterpolatedDate(operation, depthInterval.max);
|
|
||||||
|
|
||||||
hours += (dateEnd - dateStart).TotalHours;
|
|
||||||
}
|
|
||||||
return hours;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static DateTime GetInterpolatedDate(WellOperationDto operation, double depth)
|
|
||||||
{
|
|
||||||
var ratio = (depth - operation.DepthStart) / (operation.DepthEnd - operation.DepthStart);
|
|
||||||
var deltaHours = operation.DurationHours * ratio;
|
|
||||||
var interpolatedDate = operation.DateStart + TimeSpan.FromHours(deltaHours);
|
|
||||||
return interpolatedDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<(double min, double max)> SplitByIntervals(double min, double max)
|
|
||||||
{
|
|
||||||
const double step = 100;
|
|
||||||
var iMin = min;
|
|
||||||
var iMax = (1 + (int)(min / step)) * step;
|
|
||||||
for (; iMax < max; iMax += step)
|
|
||||||
{
|
|
||||||
yield return (iMin, iMax);
|
|
||||||
iMin = iMax;
|
|
||||||
}
|
|
||||||
yield return (iMin, max);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#nullable disable
|
|
||||||
}
|
|
@ -5,27 +5,6 @@ namespace AsbCloudInfrastructure.Services.ProcessMap;
|
|||||||
|
|
||||||
internal static class XLExtentions
|
internal static class XLExtentions
|
||||||
{
|
{
|
||||||
public static IXLCell SetVal(this IXLCell cell, object value)
|
|
||||||
{
|
|
||||||
switch (value)
|
|
||||||
{
|
|
||||||
case DateTime dateTime:
|
|
||||||
cell.SetVal(dateTime);
|
|
||||||
break;
|
|
||||||
case IFormattable formattable:
|
|
||||||
cell.SetVal(formattable);
|
|
||||||
break;
|
|
||||||
case string valueString:
|
|
||||||
cell.SetVal(valueString);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cell.Value = value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cell;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IXLCell SetVal(this IXLCell cell, string value, bool adaptRowHeight = false)
|
public static IXLCell SetVal(this IXLCell cell, string value, bool adaptRowHeight = false)
|
||||||
{
|
{
|
||||||
cell.Value = value;
|
cell.Value = value;
|
||||||
@ -53,11 +32,19 @@ internal static class XLExtentions
|
|||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IXLCell SetVal(this IXLCell cell, IFormattable value, string format = "0.00")
|
public static IXLCell SetVal(this IXLCell cell, int? value, string format = "0.00")
|
||||||
{
|
{
|
||||||
cell.Value = value;
|
cell.Value = value;
|
||||||
cell.DataType = XLDataType.Number;
|
cell.DataType = XLDataType.Number;
|
||||||
cell.Style.NumberFormat.Format = format;
|
cell.Style.NumberFormat.Format = format;
|
||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IXLCell SetVal(this IXLCell cell, double? value, string format = "0.00")
|
||||||
|
{
|
||||||
|
cell.Value = (value is not null && double.IsFinite(value.Value)) ? value : null;
|
||||||
|
cell.DataType = XLDataType.Number;
|
||||||
|
cell.Style.NumberFormat.Format = format;
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,16 +36,25 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
{
|
{
|
||||||
var timezone = telemetryService.GetTimezone(idTelemetry);
|
var timezone = telemetryService.GetTimezone(idTelemetry);
|
||||||
var timezoneOffset = TimeSpan.FromHours(timezone.Hours);
|
var timezoneOffset = TimeSpan.FromHours(timezone.Hours);
|
||||||
|
int[] modes = new int[] { 0, 1, 3 };
|
||||||
|
|
||||||
var query = db.Set<TelemetryDataSaub>()
|
var query = db.Set<TelemetryDataSaub>()
|
||||||
.Where(t => t.IdTelemetry == idTelemetry)
|
.Where(t => t.IdTelemetry == idTelemetry)
|
||||||
.Where(t => t.BlockPosition > 0.0001)
|
.Where(t => t.BlockPosition > 0.0001)
|
||||||
.Where(t => t.WellDepth > 0.0001)
|
.Where(t => t.WellDepth > 0.0001)
|
||||||
|
.Where(t => t.Mode != null)
|
||||||
|
.Where(t => modes.Contains(t.Mode!.Value))
|
||||||
.Where(t => t.WellDepth - t.BitDepth < 0.01)
|
.Where(t => t.WellDepth - t.BitDepth < 0.01)
|
||||||
.GroupBy(t => new { H = t.DateTime.Hour, W = Math.Truncate(t.WellDepth!.Value) })
|
.GroupBy(t => new {
|
||||||
|
t.DateTime.Hour,
|
||||||
|
WellDepthX10 = Math.Truncate(t.WellDepth!.Value * 10),
|
||||||
|
t.Mode,
|
||||||
|
t.IdFeedRegulator})
|
||||||
.Select(g => new TelemetryDataSaubStatDto
|
.Select(g => new TelemetryDataSaubStatDto
|
||||||
{
|
{
|
||||||
Count = g.Count(),
|
Count = g.Count(),
|
||||||
|
IdMode = g.Key.Mode??0,
|
||||||
|
IdFeedRegulator = g.Key.IdFeedRegulator,
|
||||||
|
|
||||||
DateMin = DateTime.SpecifyKind(g.Min(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified),
|
DateMin = DateTime.SpecifyKind(g.Min(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified),
|
||||||
DateMax = DateTime.SpecifyKind(g.Max(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified),
|
DateMax = DateTime.SpecifyKind(g.Max(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified),
|
||||||
@ -55,8 +64,6 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
|
|
||||||
Pressure = g.Average(t => t.Pressure!.Value),
|
Pressure = g.Average(t => t.Pressure!.Value),
|
||||||
PressureSp = g.Average(t => t.PressureSp!.Value),
|
PressureSp = g.Average(t => t.PressureSp!.Value),
|
||||||
PressureSpRotor = g.Average(t => t.PressureSpRotor!.Value),
|
|
||||||
PressureSpSlide = g.Average(t => t.PressureSpSlide!.Value),
|
|
||||||
PressureIdle = g.Average(t => t.PressureIdle!.Value),
|
PressureIdle = g.Average(t => t.PressureIdle!.Value),
|
||||||
PressureDeltaLimitMax = g.Average(t => t.PressureDeltaLimitMax!.Value),
|
PressureDeltaLimitMax = g.Average(t => t.PressureDeltaLimitMax!.Value),
|
||||||
PressureDelta = g.Average(t => t.Pressure!.Value - t.PressureIdle!.Value),
|
PressureDelta = g.Average(t => t.Pressure!.Value - t.PressureIdle!.Value),
|
||||||
@ -71,8 +78,6 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
|||||||
|
|
||||||
BlockSpeed = g.Average(t => t.BlockSpeed!.Value),
|
BlockSpeed = g.Average(t => t.BlockSpeed!.Value),
|
||||||
BlockSpeedSp = g.Average(t => t.BlockSpeedSp!.Value),
|
BlockSpeedSp = g.Average(t => t.BlockSpeedSp!.Value),
|
||||||
BlockSpeedSpRotor = g.Average(t => t.BlockSpeedSpRotor!.Value),
|
|
||||||
BlockSpeedSpSlide = g.Average(t => t.BlockSpeedSpSlide!.Value),
|
|
||||||
})
|
})
|
||||||
.Where(s => s.WellDepthMin != s.WellDepthMax)
|
.Where(s => s.WellDepthMin != s.WellDepthMax)
|
||||||
.Where(s => s.Count > 3)
|
.Where(s => s.Count > 3)
|
||||||
|
@ -44,7 +44,7 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
var db = serviceProvider.GetRequiredService<IAsbCloudDbContext>();
|
var db = serviceProvider.GetRequiredService<IAsbCloudDbContext>();
|
||||||
var wellService = serviceProvider.GetRequiredService<IWellService>();
|
var wellService = serviceProvider.GetRequiredService<IWellService>();
|
||||||
var operationsStatService = serviceProvider.GetRequiredService<IOperationsStatService>();
|
var operationsStatService = serviceProvider.GetRequiredService<IOperationsStatService>();
|
||||||
var processMapRepository = serviceProvider.GetRequiredService<IProcessMapRepository>();
|
var processMapRepository = serviceProvider.GetRequiredService<IProcessMapPlanRepository>();
|
||||||
var subsystemOperationTimeService = serviceProvider.GetRequiredService<ISubsystemOperationTimeService>();
|
var subsystemOperationTimeService = serviceProvider.GetRequiredService<ISubsystemOperationTimeService>();
|
||||||
|
|
||||||
var activeWells = await wellService.GetAsync(new() {IdState = 1}, token);
|
var activeWells = await wellService.GetAsync(new() {IdState = 1}, token);
|
||||||
@ -105,7 +105,7 @@ namespace AsbCloudInfrastructure.Services
|
|||||||
|
|
||||||
int? idSection = wellLastFactSection?.Id;
|
int? idSection = wellLastFactSection?.Id;
|
||||||
|
|
||||||
ProcessMapDto? welllProcessMap;
|
ProcessMapPlanDto? welllProcessMap;
|
||||||
if (idSection is not null)
|
if (idSection is not null)
|
||||||
{
|
{
|
||||||
welllProcessMap = wellProcessMaps.FirstOrDefault(p => p.IdWellSectionType == idSection);
|
welllProcessMap = wellProcessMaps.FirstOrDefault(p => p.IdWellSectionType == idSection);
|
||||||
|
@ -7,12 +7,12 @@ using Microsoft.Extensions.Caching.Memory;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.WellOperationService
|
namespace AsbCloudInfrastructure.Services.WellOperationService
|
||||||
{
|
{
|
||||||
|
#nullable enable
|
||||||
public class OperationsStatService : IOperationsStatService
|
public class OperationsStatService : IOperationsStatService
|
||||||
{
|
{
|
||||||
private readonly IAsbCloudDbContext db;
|
private readonly IAsbCloudDbContext db;
|
||||||
@ -26,8 +26,15 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
|||||||
this.wellService = wellService;
|
this.wellService = wellService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<StatClusterDto> GetStatClusterAsync(int idCluster, int idCompany, CancellationToken token = default)
|
public async Task<StatClusterDto?> GetOrDefaultStatClusterAsync(int idCluster, int idCompany, CancellationToken token)
|
||||||
{
|
{
|
||||||
|
var cluster = (await memoryCache
|
||||||
|
.GetOrCreateBasicAsync(db.Set<Cluster>(), token))
|
||||||
|
.FirstOrDefault(c => c.Id == idCluster);
|
||||||
|
|
||||||
|
if (cluster is null)
|
||||||
|
return null;
|
||||||
|
|
||||||
var allWellsByCompany = await wellService.GetAsync(new() { IdCompany = idCompany }, token).ConfigureAwait(false);
|
var allWellsByCompany = await wellService.GetAsync(new() { IdCompany = idCompany }, token).ConfigureAwait(false);
|
||||||
|
|
||||||
var idWellsByCompany = allWellsByCompany.Select(w => w.Id).Distinct();
|
var idWellsByCompany = allWellsByCompany.Select(w => w.Id).Distinct();
|
||||||
@ -41,9 +48,6 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
|||||||
|
|
||||||
var statsWells = await GetWellsStatAsync(wells, token).ConfigureAwait(false);
|
var statsWells = await GetWellsStatAsync(wells, token).ConfigureAwait(false);
|
||||||
|
|
||||||
var cluster = (await memoryCache
|
|
||||||
.GetOrCreateBasicAsync(db.Set<Cluster>(), token))
|
|
||||||
.FirstOrDefault(c => c.Id == idCluster);
|
|
||||||
var statClusterDto = new StatClusterDto
|
var statClusterDto = new StatClusterDto
|
||||||
{
|
{
|
||||||
Id = idCluster,
|
Id = idCluster,
|
||||||
@ -71,7 +75,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
|||||||
return statsWells;
|
return statsWells;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<StatWellDto> GetWellStatAsync(int idWell,
|
public async Task<StatWellDto?> GetOrDefaultWellStatAsync(int idWell,
|
||||||
CancellationToken token = default)
|
CancellationToken token = default)
|
||||||
{
|
{
|
||||||
var well = await db.Wells
|
var well = await db.Wells
|
||||||
@ -79,11 +83,14 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
|||||||
.FirstOrDefaultAsync(w => w.Id == idWell, token)
|
.FirstOrDefaultAsync(w => w.Id == idWell, token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
if(well is null)
|
||||||
|
return null;
|
||||||
|
|
||||||
var statWellDto = await CalcWellStatAsync(well, token);
|
var statWellDto = await CalcWellStatAsync(well, token);
|
||||||
return statWellDto;
|
return statWellDto;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ClusterRopStatDto> GetRopStatAsync(int idWell, CancellationToken token)
|
public async Task<ClusterRopStatDto?> GetOrDefaultRopStatAsync(int idWell, CancellationToken token)
|
||||||
{
|
{
|
||||||
var clusterWellsIds = await wellService.GetClusterWellsIdsAsync(idWell, token)
|
var clusterWellsIds = await wellService.GetClusterWellsIdsAsync(idWell, token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
@ -110,13 +117,15 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
|||||||
.ToListAsync(token)
|
.ToListAsync(token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
var statsList = clusterWellsIds.Select(clusterWellId =>
|
var statsList = new List<StatOperationsDto>(clusterWellsIds.Count());
|
||||||
|
foreach (var clusterWellId in clusterWellsIds)
|
||||||
{
|
{
|
||||||
var currentWellOps = operations.Where(o => o.IdWell == clusterWellId);
|
var currentWellOps = operations.Where(o => o.IdWell == clusterWellId);
|
||||||
var timezoneOffsetH = wellService.GetTimezone(clusterWellId).Hours;
|
var timezoneOffsetHours = wellService.GetTimezone(clusterWellId).Hours;
|
||||||
var stat = CalcStat(currentWellOps, timezoneOffsetH);
|
var stat = CalcStat(currentWellOps, timezoneOffsetHours);
|
||||||
return stat;
|
if(stat is not null)
|
||||||
}).Where(c => c is not null);
|
statsList.Add(stat);
|
||||||
|
};
|
||||||
|
|
||||||
if (!statsList.Any())
|
if (!statsList.Any())
|
||||||
return null;
|
return null;
|
||||||
@ -130,7 +139,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
|||||||
return clusterRops;
|
return clusterRops;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<StatWellDto> CalcWellStatAsync(Well well, CancellationToken token = default)
|
private async Task<StatWellDto> CalcWellStatAsync(Well well, CancellationToken token)
|
||||||
{
|
{
|
||||||
var wellType = (await memoryCache
|
var wellType = (await memoryCache
|
||||||
.GetOrCreateBasicAsync(db.Set<WellType>(), token))
|
.GetOrCreateBasicAsync(db.Set<WellType>(), token))
|
||||||
@ -164,7 +173,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
|||||||
return statWellDto;
|
return statWellDto;
|
||||||
}
|
}
|
||||||
|
|
||||||
private double CalcTvdLagDays(IOrderedEnumerable<WellOperation> wellOperations)
|
private static double CalcTvdLagDays(IOrderedEnumerable<WellOperation> wellOperations)
|
||||||
{
|
{
|
||||||
var operationsOrdered = wellOperations
|
var operationsOrdered = wellOperations
|
||||||
.OrderBy(o => o.DateStart);
|
.OrderBy(o => o.DateStart);
|
||||||
@ -178,9 +187,13 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
|||||||
if (lastCorrespondingFactOperation is null)
|
if (lastCorrespondingFactOperation is null)
|
||||||
return 0d;
|
return 0d;
|
||||||
|
|
||||||
var lastCorrespondingPlanOperation = wellOperations.FirstOrDefault(o => o.Id == lastCorrespondingFactOperation.IdPlan);
|
var lastCorrespondingPlanOperation = wellOperations
|
||||||
|
.FirstOrDefault(o => o.Id == lastCorrespondingFactOperation.IdPlan);
|
||||||
|
|
||||||
var lastFactOperation = factOperations.LastOrDefault();
|
if (lastCorrespondingPlanOperation is null)
|
||||||
|
return 0d;
|
||||||
|
|
||||||
|
var lastFactOperation = factOperations.Last();
|
||||||
|
|
||||||
var remainingPlanOperations = operationsOrdered
|
var remainingPlanOperations = operationsOrdered
|
||||||
.Where(o => o.IdType == WellOperation.IdOperationTypePlan)
|
.Where(o => o.IdType == WellOperation.IdOperationTypePlan)
|
||||||
@ -240,27 +253,27 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
|||||||
return section;
|
return section;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static StatOperationsDto CalcSectionStat(IEnumerable<WellOperation> operations, int idSectionType, double timezoneOffsetH)
|
private static StatOperationsDto? CalcSectionStat(IEnumerable<WellOperation> operations, int idSectionType, double timezoneOffsetHours)
|
||||||
{
|
{
|
||||||
var sectionOperations = operations
|
var sectionOperations = operations
|
||||||
.Where(o => o.IdWellSectionType == idSectionType)
|
.Where(o => o.IdWellSectionType == idSectionType)
|
||||||
.OrderBy(o => o.DateStart)
|
.OrderBy(o => o.DateStart)
|
||||||
.ThenBy(o => o.DepthStart);
|
.ThenBy(o => o.DepthStart);
|
||||||
|
|
||||||
return CalcStat(sectionOperations, timezoneOffsetH);
|
return CalcStat(sectionOperations, timezoneOffsetHours);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static StatOperationsDto CalcStat(IEnumerable<WellOperation> operations, double timezoneOffsetH)
|
private static StatOperationsDto? CalcStat(IEnumerable<WellOperation> operations, double timezoneOffsetHours)
|
||||||
{
|
{
|
||||||
if (!operations.Any())
|
if (!operations.Any())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var races = GetCompleteRaces(operations, timezoneOffsetH);
|
var races = GetCompleteRaces(operations, timezoneOffsetHours);
|
||||||
|
|
||||||
var section = new StatOperationsDto
|
var section = new StatOperationsDto
|
||||||
{
|
{
|
||||||
Start = operations.FirstOrDefault()?.DateStart.ToRemoteDateTime(timezoneOffsetH),
|
Start = operations.FirstOrDefault()?.DateStart.ToRemoteDateTime(timezoneOffsetHours),
|
||||||
End = operations.Max(o => o.DateStart.ToRemoteDateTime(timezoneOffsetH).AddHours(o.DurationHours)),
|
End = operations.Max(o => o.DateStart.ToRemoteDateTime(timezoneOffsetHours).AddHours(o.DurationHours)),
|
||||||
WellDepthStart = operations.Min(o => o.DepthStart),
|
WellDepthStart = operations.Min(o => o.DepthStart),
|
||||||
WellDepthEnd = operations.Max(o => o.DepthStart),
|
WellDepthEnd = operations.Max(o => o.DepthStart),
|
||||||
Rop = CalcROP(operations),
|
Rop = CalcROP(operations),
|
||||||
@ -356,7 +369,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
|||||||
{
|
{
|
||||||
var dDepth = 0d;
|
var dDepth = 0d;
|
||||||
var dHours = 0d;
|
var dHours = 0d;
|
||||||
foreach (var race in races)
|
foreach (Race race in races)
|
||||||
{
|
{
|
||||||
dDepth += race.StartWellDepth;
|
dDepth += race.StartWellDepth;
|
||||||
for (var i = 0; i < race.Operations.Count; i++)
|
for (var i = 0; i < race.Operations.Count; i++)
|
||||||
@ -417,78 +430,71 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
|||||||
|
|
||||||
var tzOffsetHours = wellService.GetTimezone(idWell).Hours;
|
var tzOffsetHours = wellService.GetTimezone(idWell).Hours;
|
||||||
|
|
||||||
if (!wellOperationsPlan.Any())
|
var merged = MergeArraysBySections(sectionsIds, wellOperationsPlan, wellOperationsFact).ToList();
|
||||||
return null;
|
|
||||||
|
|
||||||
var merged = MergeArraysBySections(sectionsIds, wellOperationsPlan, wellOperationsFact);
|
|
||||||
var tvd = new List<PlanFactPredictBase<WellOperationDto>>(merged.Count);
|
var tvd = new List<PlanFactPredictBase<WellOperationDto>>(merged.Count);
|
||||||
var firstPoint = merged.First();
|
var (Plan, Fact) = merged.First();
|
||||||
var dateStart = firstPoint.Item1?.DateStart ?? firstPoint.Item2.DateStart;
|
var dateStart = Plan?.DateStart ?? Fact!.DateStart;
|
||||||
int iLastMatch = 0;
|
int? iLastMatch = null;
|
||||||
int iLastFact = 0;
|
int iLastFact = 0;
|
||||||
var nptHours = 0d;
|
var nptHours = 0d;
|
||||||
for (int i = 0; i < merged.Count; i++)
|
for (int i = 0; i < merged.Count; i++)
|
||||||
{
|
{
|
||||||
var item = merged[i];
|
var item = merged[i];
|
||||||
var plan = item.Item1;
|
var plan = item.Plan;
|
||||||
var fact = item.Item2;
|
var fact = item.Fact;
|
||||||
|
|
||||||
if (fact is not null && WellOperationCategory.NonProductiveTimeSubIds.Contains(fact.IdCategory))
|
var planFactPredict = new PlanFactPredictBase<WellOperationDto>();
|
||||||
|
if (plan is not null)
|
||||||
{
|
{
|
||||||
nptHours += fact.DurationHours;
|
planFactPredict.Plan = Convert(plan, tzOffsetHours);
|
||||||
|
planFactPredict.Plan.Day = (planFactPredict.Plan.DateStart - dateStart).TotalDays;
|
||||||
|
if (fact is not null)
|
||||||
|
iLastMatch = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
var planFactPredict = new PlanFactPredictBase<WellOperationDto>
|
if (fact is not null)
|
||||||
{
|
{
|
||||||
Plan = Convert(plan, tzOffsetHours),
|
if(WellOperationCategory.NonProductiveTimeSubIds.Contains(fact.IdCategory))
|
||||||
Fact = Convert(fact, tzOffsetHours),
|
nptHours += fact.DurationHours;
|
||||||
Predict = null,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (planFactPredict.Plan is not null)
|
planFactPredict.Fact = Convert(fact, tzOffsetHours);
|
||||||
planFactPredict.Plan.Day = (planFactPredict.Plan.DateStart - dateStart).TotalDays;
|
|
||||||
|
|
||||||
if (planFactPredict.Fact is not null)
|
|
||||||
{
|
|
||||||
planFactPredict.Fact.Day = (planFactPredict.Fact.DateStart - dateStart).TotalDays;
|
planFactPredict.Fact.Day = (planFactPredict.Fact.DateStart - dateStart).TotalDays;
|
||||||
planFactPredict.Fact.NptHours = nptHours;
|
planFactPredict.Fact.NptHours = nptHours;
|
||||||
}
|
|
||||||
|
|
||||||
tvd.Add(planFactPredict);
|
|
||||||
if ((plan is not null) && (fact is not null))
|
|
||||||
iLastMatch = i;
|
|
||||||
if (fact is not null)
|
|
||||||
iLastFact = i;
|
iLastFact = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iLastMatch == 0 || iLastMatch == merged.Count - 1)
|
tvd.Add(planFactPredict);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iLastMatch is null || iLastMatch == merged.Count - 1)
|
||||||
return tvd;
|
return tvd;
|
||||||
|
|
||||||
var lastMatchPlan = merged[iLastMatch].Item1;
|
var lastMatchPlan = merged[iLastMatch.Value].Plan!;
|
||||||
var lastMatchPlanOperationEnd = lastMatchPlan.DateStart.AddHours(lastMatchPlan.DurationHours);
|
var lastMatchPlanOperationEnd = lastMatchPlan.DateStart.AddHours(lastMatchPlan.DurationHours);
|
||||||
var lastFact = merged[iLastFact].Item2;
|
var lastFact = merged[iLastFact].Fact!;
|
||||||
var lastFactDateEnd = lastFact.DateStart.AddHours(lastFact.DurationHours);
|
var lastFactDateEnd = lastFact.DateStart.AddHours(lastFact.DurationHours);
|
||||||
var startOffset = lastFactDateEnd - lastMatchPlanOperationEnd;
|
var startOffset = lastFactDateEnd - lastMatchPlanOperationEnd;
|
||||||
|
|
||||||
for (int i = iLastMatch + 1; i < merged.Count; i++)
|
for (int i = iLastMatch.Value + 1; i < merged.Count; i++)
|
||||||
{
|
{
|
||||||
if (merged[i].Item1 is null)
|
if (merged[i].Plan is null)
|
||||||
continue;
|
continue;
|
||||||
tvd[i].Predict = Convert(merged[i].Item1, tzOffsetHours);
|
var predict = Convert(merged[i].Plan!, tzOffsetHours);
|
||||||
tvd[i].Predict.IdType = 2;
|
predict.IdType = 2;
|
||||||
tvd[i].Predict.DateStart = tvd[i].Predict.DateStart + startOffset;
|
predict.DateStart = predict.DateStart + startOffset;
|
||||||
tvd[i].Predict.Day = (tvd[i].Predict.DateStart - dateStart).TotalDays;
|
predict.Day = (predict.DateStart - dateStart).TotalDays;
|
||||||
|
tvd[i].Predict = predict;
|
||||||
}
|
}
|
||||||
|
|
||||||
return tvd;
|
return tvd;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Tuple<WellOperation, WellOperation>> MergeArraysBySections(
|
private static IEnumerable<(WellOperation? Plan, WellOperation? Fact)> MergeArraysBySections(
|
||||||
IEnumerable<int> sectionsIds,
|
IEnumerable<int> sectionsIds,
|
||||||
IOrderedEnumerable<WellOperation> wellOperationsPlan,
|
IOrderedEnumerable<WellOperation> wellOperationsPlan,
|
||||||
IOrderedEnumerable<WellOperation> wellOperationsFact)
|
IOrderedEnumerable<WellOperation> wellOperationsFact)
|
||||||
{
|
{
|
||||||
var merged = new List<Tuple<WellOperation, WellOperation>>(wellOperationsPlan.Count());
|
var merged = new List<(WellOperation? Plan, WellOperation? Fact)>(wellOperationsPlan.Count());
|
||||||
foreach (var sectionId in sectionsIds)
|
foreach (var sectionId in sectionsIds)
|
||||||
{
|
{
|
||||||
var sectionOperationsPlan = wellOperationsPlan
|
var sectionOperationsPlan = wellOperationsPlan
|
||||||
@ -501,46 +507,38 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
|||||||
return merged;
|
return merged;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Tuple<WellOperation, WellOperation>> MergeArrays(IEnumerable<WellOperation> operationsPlan, IEnumerable<WellOperation> operationsFact)
|
private static IEnumerable<(WellOperation? Plan, WellOperation? Fact)> MergeArrays(IEnumerable<WellOperation> operationsPlan, IEnumerable<WellOperation> operationsFact)
|
||||||
{
|
{
|
||||||
var result = new List<Tuple<WellOperation, WellOperation>>();
|
var operationsFactWithNoPlan = operationsFact.Where(x => x.IdPlan == null).ToArray();
|
||||||
|
var operationsFactWithPlan = operationsFact.Where(x => x.IdPlan != null).ToArray();
|
||||||
|
|
||||||
var oparationsFactWithNoPlan = operationsFact
|
var idsPlanWithFact = operationsFact.Where(x => x.IdPlan is not null).Select(x => x.IdPlan).Distinct();
|
||||||
.Where(x => x.IdPlan == null)
|
var operationsPlanWithNoFact = operationsPlan.Where(x => !idsPlanWithFact.Contains(x.IdPlan)).ToArray();
|
||||||
.Select(x => new Tuple<WellOperation, WellOperation>(null, x));
|
|
||||||
|
|
||||||
var oparationsFactWithPlan = operationsFact
|
var result = new List<(WellOperation? Plan, WellOperation? Fact)>(operationsFactWithNoPlan.Length + operationsFactWithPlan.Length + operationsPlanWithNoFact.Length);
|
||||||
.Where(x => x.IdPlan != null)
|
|
||||||
.Select(x => new Tuple<WellOperation, WellOperation>(x.OperationPlan, x));
|
|
||||||
|
|
||||||
var idsPlanWithFact = operationsFact
|
foreach (var operation in operationsFactWithPlan)
|
||||||
.Where(x => x.IdPlan is not null)
|
result.Add((operation.OperationPlan, operation));
|
||||||
.Select(x => x.IdPlan)
|
|
||||||
.Distinct();
|
|
||||||
var oparationsPlanWithNoFact = operationsPlan
|
|
||||||
.Where(x => !idsPlanWithFact.Contains(x.IdPlan))
|
|
||||||
.Select(x => new Tuple<WellOperation, WellOperation>(x, null));
|
|
||||||
|
|
||||||
result.AddRange(oparationsFactWithNoPlan);
|
foreach (var operation in operationsFactWithNoPlan)
|
||||||
result.AddRange(oparationsFactWithPlan);
|
result.Add((null, operation));
|
||||||
result.AddRange(oparationsPlanWithNoFact);
|
|
||||||
|
|
||||||
result = result
|
foreach (var operation in operationsPlanWithNoFact)
|
||||||
.OrderBy(x => x.Item1?.DateStart)
|
result.Add((operation, null));
|
||||||
.ThenBy(x => x.Item2?.DateStart)
|
|
||||||
.ToList();
|
return result
|
||||||
return result;
|
.OrderBy(x => x.Plan?.DateStart)
|
||||||
|
.ThenBy(x => x.Fact?.DateStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static WellOperationDto Convert(WellOperation source, double tzOffsetHours)
|
private static WellOperationDto Convert(WellOperation source, double tzOffsetHours)
|
||||||
{
|
{
|
||||||
if (source is null)
|
var destination = source.Adapt<WellOperationDto>();
|
||||||
return null;
|
destination.CategoryName = source.OperationCategory?.Name;
|
||||||
var dest = source.Adapt<WellOperationDto>();
|
destination.WellSectionTypeName = source.WellSectionType?.Caption;
|
||||||
dest.CategoryName = source.OperationCategory?.Name;
|
destination.DateStart = source.DateStart.ToRemoteDateTime(tzOffsetHours);
|
||||||
dest.WellSectionTypeName = source.WellSectionType?.Caption;
|
return destination;
|
||||||
dest.DateStart = source.DateStart.ToRemoteDateTime(tzOffsetHours);
|
|
||||||
return dest;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#nullable disable
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using AsbCloudDb.Model;
|
using AsbCloudDb.Model;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure.Services.WellOperationService
|
namespace AsbCloudInfrastructure.Services.WellOperationService
|
||||||
{
|
{
|
||||||
@ -60,7 +61,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Список операций за рейс
|
/// Список операций за рейс
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<WellOperation>? Operations { get; internal set; }
|
public List<WellOperation> Operations { get; internal set; } = new List<WellOperation>();
|
||||||
}
|
}
|
||||||
#nullable disable
|
#nullable disable
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using AsbCloudApp.Data.DailyReport;
|
using AsbCloudApp.Data;
|
||||||
|
using AsbCloudApp.Data.DailyReport;
|
||||||
using AsbCloudApp.Exceptions;
|
using AsbCloudApp.Exceptions;
|
||||||
using AsbCloudApp.Repositories;
|
using AsbCloudApp.Repositories;
|
||||||
using AsbCloudApp.Services;
|
using AsbCloudApp.Services;
|
||||||
|
@ -9,6 +9,7 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace AsbCloudWebApi.Controllers
|
namespace AsbCloudWebApi.Controllers
|
||||||
{
|
{
|
||||||
|
#nullable enable
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Статистика по операциям (заведенным вручную) на скважине
|
/// Статистика по операциям (заведенным вручную) на скважине
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -41,7 +42,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
|
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
|
||||||
return Forbid();
|
return Forbid();
|
||||||
|
|
||||||
var result = await operationsStatService.GetRopStatAsync(
|
var result = await operationsStatService.GetOrDefaultRopStatAsync(
|
||||||
idWell, token).ConfigureAwait(false);
|
idWell, token).ConfigureAwait(false);
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
@ -64,7 +65,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
if (idWell is null)
|
if (idWell is null)
|
||||||
return NoContent();
|
return NoContent();
|
||||||
|
|
||||||
var result = await operationsStatService.GetRopStatAsync(
|
var result = await operationsStatService.GetOrDefaultRopStatAsync(
|
||||||
(int)idWell, token).ConfigureAwait(false);
|
(int)idWell, token).ConfigureAwait(false);
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
@ -87,7 +88,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
if (idCompany is null)
|
if (idCompany is null)
|
||||||
return Forbid();
|
return Forbid();
|
||||||
|
|
||||||
var result = await operationsStatService.GetStatClusterAsync(idCluster, idCompany.Value, token)
|
var result = await operationsStatService.GetOrDefaultStatClusterAsync(idCluster, idCompany.Value, token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
@ -132,7 +133,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
|
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
|
||||||
return Forbid();
|
return Forbid();
|
||||||
|
|
||||||
var result = await operationsStatService.GetWellStatAsync(idWell, token)
|
var result = await operationsStatService.GetOrDefaultWellStatAsync(idWell, token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
@ -165,4 +166,5 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
idWell, token).ConfigureAwait(false);
|
idWell, token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#nullable disable
|
||||||
}
|
}
|
||||||
|
@ -18,17 +18,17 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class ProcessMapController : CrudWellRelatedController<ProcessMapDto, IProcessMapRepository>
|
public class ProcessMapController : CrudWellRelatedController<ProcessMapPlanDto, IProcessMapPlanRepository>
|
||||||
{
|
{
|
||||||
private readonly ITelemetryService telemetryService;
|
private readonly ITelemetryService telemetryService;
|
||||||
private readonly IProcessMapReportService processMapReportService;
|
private readonly IProcessMapReportMakerService processMapReportService;
|
||||||
private readonly IProcessMapService processMapService;
|
private readonly IProcessMapReportService processMapService;
|
||||||
|
|
||||||
public ProcessMapController(
|
public ProcessMapController(
|
||||||
IWellService wellService,
|
IWellService wellService,
|
||||||
IProcessMapRepository repository,
|
IProcessMapPlanRepository repository,
|
||||||
IProcessMapReportService processMapReportService,
|
IProcessMapReportMakerService processMapReportService,
|
||||||
IProcessMapService processMapService,
|
IProcessMapReportService processMapService,
|
||||||
ITelemetryService telemetryService)
|
ITelemetryService telemetryService)
|
||||||
: base(wellService, repository)
|
: base(wellService, repository)
|
||||||
{
|
{
|
||||||
@ -49,14 +49,14 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
[Obsolete("use GetByUidAsync(..) instead")]
|
[Obsolete("use GetByUidAsync(..) instead")]
|
||||||
[Route("/api/telemetry/{uid}/drillFlowChart")]
|
[Route("/api/telemetry/{uid}/drillFlowChart")]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[ProducesResponseType(typeof(IEnumerable<ProcessMapDto>), (int)System.Net.HttpStatusCode.OK)]
|
[ProducesResponseType(typeof(IEnumerable<ProcessMapPlanDto>), (int)System.Net.HttpStatusCode.OK)]
|
||||||
public IActionResult GetByTelemetry(string uid, DateTime updateFrom, CancellationToken token)
|
public IActionResult GetByTelemetry(string uid, DateTime updateFrom, CancellationToken token)
|
||||||
{
|
{
|
||||||
var idWell = telemetryService.GetIdWellByTelemetryUid(uid);
|
var idWell = telemetryService.GetIdWellByTelemetryUid(uid);
|
||||||
if (idWell is null)
|
if (idWell is null)
|
||||||
return BadRequest($"Wrong uid {uid}");
|
return BadRequest($"Wrong uid {uid}");
|
||||||
|
|
||||||
var dto = Enumerable.Empty<ProcessMapDto>();
|
var dto = Enumerable.Empty<ProcessMapPlanDto>();
|
||||||
return Ok(dto);
|
return Ok(dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("/api/telemetry/{uid}/processMap")]
|
[Route("/api/telemetry/{uid}/processMap")]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[ProducesResponseType(typeof(IEnumerable<ProcessMapDto>), (int)System.Net.HttpStatusCode.OK)]
|
[ProducesResponseType(typeof(IEnumerable<ProcessMapPlanDto>), (int)System.Net.HttpStatusCode.OK)]
|
||||||
public async Task<IActionResult> GetByUidAsync(string uid, DateTime updateFrom, CancellationToken token)
|
public async Task<IActionResult> GetByUidAsync(string uid, DateTime updateFrom, CancellationToken token)
|
||||||
{
|
{
|
||||||
var idWell = telemetryService.GetIdWellByTelemetryUid(uid);
|
var idWell = telemetryService.GetIdWellByTelemetryUid(uid);
|
||||||
@ -122,7 +122,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
[ProducesResponseType(typeof(IEnumerable<ProcessMapReportDto>), (int)System.Net.HttpStatusCode.OK)]
|
[ProducesResponseType(typeof(IEnumerable<ProcessMapReportDto>), (int)System.Net.HttpStatusCode.OK)]
|
||||||
public async Task<IActionResult> GetDrillProcessMap(int wellId, CancellationToken token)
|
public async Task<IActionResult> GetDrillProcessMap(int wellId, CancellationToken token)
|
||||||
{
|
{
|
||||||
var data = await processMapService.GetProcessMapAsync(wellId, token);
|
var data = await processMapService.GetProcessMapReportAsync(wellId, token);
|
||||||
return Ok(data);
|
return Ok(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +133,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public override async Task<ActionResult<int>> InsertAsync([FromBody] ProcessMapDto value, CancellationToken token)
|
public override async Task<ActionResult<int>> InsertAsync([FromBody] ProcessMapPlanDto value, CancellationToken token)
|
||||||
{
|
{
|
||||||
value.IdUser = User.GetUserId() ?? -1;
|
value.IdUser = User.GetUserId() ?? -1;
|
||||||
return await base.InsertAsync(value, token);
|
return await base.InsertAsync(value, token);
|
||||||
@ -146,7 +146,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
/// <returns>1 - успешно отредактировано, 0 - нет</returns>
|
/// <returns>1 - успешно отредактировано, 0 - нет</returns>
|
||||||
[HttpPut]
|
[HttpPut]
|
||||||
public override async Task<ActionResult<int>> UpdateAsync([FromBody] ProcessMapDto value, CancellationToken token)
|
public override async Task<ActionResult<int>> UpdateAsync([FromBody] ProcessMapPlanDto value, CancellationToken token)
|
||||||
{
|
{
|
||||||
value.IdUser = User.GetUserId() ?? -1;
|
value.IdUser = User.GetUserId() ?? -1;
|
||||||
return await base.UpdateAsync(value, token);
|
return await base.UpdateAsync(value, token);
|
||||||
|
@ -73,7 +73,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpGet("getCompositeProcessMap")]
|
[HttpGet("getCompositeProcessMap")]
|
||||||
[Permission]
|
[Permission]
|
||||||
[ProducesResponseType(typeof(IEnumerable<ProcessMapDto>), (int)System.Net.HttpStatusCode.OK)]
|
[ProducesResponseType(typeof(IEnumerable<ProcessMapPlanDto>), (int)System.Net.HttpStatusCode.OK)]
|
||||||
public async Task<IActionResult> GetCompositeProcessMap(int idWell, CancellationToken token = default)
|
public async Task<IActionResult> GetCompositeProcessMap(int idWell, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
|
if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
|
||||||
|
@ -51,14 +51,15 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Возвращает список имен типов операций на скважине
|
/// Возвращает список имен типов операций на скважине
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="includeParents">флаг, нужно ли включать родителей в список</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("categories")]
|
[Route("categories")]
|
||||||
[Permission]
|
[Permission]
|
||||||
[ProducesResponseType(typeof(IEnumerable<WellOperationCategoryDto>), (int)System.Net.HttpStatusCode.OK)]
|
[ProducesResponseType(typeof(IEnumerable<WellOperationCategoryDto>), (int)System.Net.HttpStatusCode.OK)]
|
||||||
public IActionResult GetCategories()
|
public IActionResult GetCategories(bool includeParents = true)
|
||||||
{
|
{
|
||||||
var result = operationRepository.GetCategories(false);
|
var result = operationRepository.GetCategories(includeParents);
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,7 +210,11 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
return Forbid();
|
return Forbid();
|
||||||
|
|
||||||
foreach (var value in values)
|
foreach (var value in values)
|
||||||
|
{
|
||||||
value.IdWell = idWell;
|
value.IdWell = idWell;
|
||||||
|
value.LastUpdateDate = DateTimeOffset.UtcNow;
|
||||||
|
value.IdUser = User.GetUserId();
|
||||||
|
}
|
||||||
|
|
||||||
var result = await operationRepository.InsertRangeAsync(values, token)
|
var result = await operationRepository.InsertRangeAsync(values, token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
@ -236,6 +241,8 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
|
|
||||||
value.IdWell = idWell;
|
value.IdWell = idWell;
|
||||||
value.Id = idOperation;
|
value.Id = idOperation;
|
||||||
|
value.LastUpdateDate = DateTimeOffset.UtcNow;
|
||||||
|
value.IdUser = User.GetUserId();
|
||||||
|
|
||||||
var result = await operationRepository.UpdateAsync(value, token)
|
var result = await operationRepository.UpdateAsync(value, token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
@ -372,7 +379,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
[Route("template")]
|
[Route("template")]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK)]
|
[ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK)]
|
||||||
public IActionResult GetTamplate()
|
public IActionResult GetTemplate()
|
||||||
{
|
{
|
||||||
var stream = wellOperationImportService.GetExcelTemplateStream();
|
var stream = wellOperationImportService.GetExcelTemplateStream();
|
||||||
var fileName = "ЕЦП_шаблон_файла_операций.xlsx";
|
var fileName = "ЕЦП_шаблон_файла_операций.xlsx";
|
||||||
|
46
AsbCloudWebApi/Rest/OperationStat.http
Normal file
46
AsbCloudWebApi/Rest/OperationStat.http
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
@baseUrl = http://127.0.0.1:5000
|
||||||
|
@contentType = application/json
|
||||||
|
@auth = Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImN0eSI6IkpXVCJ9.eyJpZCI6IjEiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiZGV2IiwiaWRDb21wYW55IjoiMSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6InJvb3QiLCJuYmYiOjE2NjI1NDgxNjIsImV4cCI6MTY5NDEwNTc2MiwiaXNzIjoiYSIsImF1ZCI6ImEifQ.OEAlNzxi7Jat6pzDBTAjTbChskc-tdJthJexyWwwUKE
|
||||||
|
|
||||||
|
@uid = 20210910_012752700
|
||||||
|
@idCluster = 1
|
||||||
|
@idWell = 1
|
||||||
|
#295
|
||||||
|
|
||||||
|
# https://marketplace.visualstudio.com/items?itemName=humao.rest-client
|
||||||
|
|
||||||
|
###
|
||||||
|
GET {{baseUrl}}/api/well/{{idWell}}/ropStat
|
||||||
|
Content-Type: {{contentType}}
|
||||||
|
accept: */*
|
||||||
|
Authorization: {{auth}}
|
||||||
|
|
||||||
|
###
|
||||||
|
GET {{baseUrl}}/api/telemetry/{{uid}}/ropStat
|
||||||
|
Content-Type: {{contentType}}
|
||||||
|
accept: */*
|
||||||
|
Authorization: {{auth}}
|
||||||
|
|
||||||
|
###
|
||||||
|
GET {{baseUrl}}/api/cluster/{{idCluster}}/stat
|
||||||
|
Content-Type: {{contentType}}
|
||||||
|
accept: */*
|
||||||
|
Authorization: {{auth}}
|
||||||
|
|
||||||
|
###
|
||||||
|
GET {{baseUrl}}/api/wellsStats?idWells=1&idWells={{idWell}}
|
||||||
|
Content-Type: {{contentType}}
|
||||||
|
accept: */*
|
||||||
|
Authorization: {{auth}}
|
||||||
|
|
||||||
|
###
|
||||||
|
GET {{baseUrl}}/api/well/{{idWell}}/stat
|
||||||
|
Content-Type: {{contentType}}
|
||||||
|
accept: */*
|
||||||
|
Authorization: {{auth}}
|
||||||
|
|
||||||
|
###
|
||||||
|
GET {{baseUrl}}/api/well/{{idWell}}/tvd
|
||||||
|
Content-Type: {{contentType}}
|
||||||
|
accept: */*
|
||||||
|
Authorization: {{auth}}
|
20
AsbCloudWebApi/Rest/ProcessMap.http
Normal file
20
AsbCloudWebApi/Rest/ProcessMap.http
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
@baseUrl = http://127.0.0.1:5000
|
||||||
|
@contentType = application/json
|
||||||
|
@auth = Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImN0eSI6IkpXVCJ9.eyJpZCI6IjEiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiZGV2IiwiaWRDb21wYW55IjoiMSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6InJvb3QiLCJuYmYiOjE2NjI1NDgxNjIsImV4cCI6MTY5NDEwNTc2MiwiaXNzIjoiYSIsImF1ZCI6ImEifQ.OEAlNzxi7Jat6pzDBTAjTbChskc-tdJthJexyWwwUKE
|
||||||
|
|
||||||
|
@wellId = 1
|
||||||
|
|
||||||
|
# https://marketplace.visualstudio.com/items?itemName=humao.rest-client
|
||||||
|
|
||||||
|
###
|
||||||
|
GET {{baseUrl}}/api/processMap/getDrillProcessMap/{{wellId}}
|
||||||
|
Content-Type: {{contentType}}
|
||||||
|
accept: */*
|
||||||
|
Authorization: {{auth}}
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
GET {{baseUrl}}/api/processMap/getReportFile/{{wellId}}
|
||||||
|
Content-Type: {{contentType}}
|
||||||
|
accept: */*
|
||||||
|
Authorization: {{auth}}
|
7
AsbCloudWebApi/Rest/Readme.md
Normal file
7
AsbCloudWebApi/Rest/Readme.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Эта папка предназначена для хранения файлов для отладки/проверки web-api.
|
||||||
|
|
||||||
|
Файлы *.http (или *.rest) позволяют вызывать endpoint api без swagger (или postman).
|
||||||
|
|
||||||
|
[Документация по созданию файлов](https://marketplace.visualstudio.com/items?itemName=humao.rest-client)
|
||||||
|
|
||||||
|
Желательно создавать 1 файл на 1 контроллер.
|
Loading…
Reference in New Issue
Block a user