forked from ddrilling/AsbCloudServer
merge
This commit is contained in:
commit
5de4e43ad9
@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace AsbCloudApp.Requests
|
||||
{
|
||||
@ -9,9 +9,16 @@ namespace AsbCloudApp.Requests
|
||||
public class DetectedOperationRequest : RequestBase
|
||||
{
|
||||
/// <summary>
|
||||
/// категории операций
|
||||
/// категория операций
|
||||
/// </summary>
|
||||
public IEnumerable<int> CategoryIds { get; set; }
|
||||
[Required]
|
||||
public int IdWell { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// категория операций
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int IdCategory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Больше или равно дате
|
||||
|
@ -31,14 +31,14 @@ namespace AsbCloudApp.Services
|
||||
/// <param name="id"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns>null if not found</returns>
|
||||
Task<TDto?> GetAsync(int id, CancellationToken token);
|
||||
Task<TDto?> GetOrDefaultAsync(int id, CancellationToken token);
|
||||
|
||||
/// <summary>
|
||||
/// Получить запись по id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns>null if not found</returns>
|
||||
TDto? Get(int id);
|
||||
TDto? GetOrDefault(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Добавление новой записи
|
||||
|
@ -8,8 +8,8 @@ namespace AsbCloudApp.Services
|
||||
{
|
||||
public interface IDetectedOperationService
|
||||
{
|
||||
Task<IEnumerable<WellOperationCategoryDto>> GetCategoriesAsync(CancellationToken token);
|
||||
Task<DetectedOperationListDto> GetAsync(int idWell, Requests.DetectedOperationRequest request, CancellationToken token);
|
||||
Task<int> DeleteAsync(int idWell, DetectedOperationRequest request, CancellationToken token);
|
||||
Task<IEnumerable<WellOperationCategoryDto>> GetCategoriesAsync(int? idWell, CancellationToken token);
|
||||
Task<DetectedOperationListDto> GetAsync(DetectedOperationRequest request, CancellationToken token);
|
||||
Task<int> DeleteAsync(DetectedOperationRequest request, CancellationToken token);
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ namespace AsbCloudApp.Services
|
||||
Task<IEnumerable<SetpointsRequestDto>> GetAsync(int idWell, CancellationToken token);
|
||||
Task<IEnumerable<SetpointsRequestDto>> GetForPanelAsync(string uid, CancellationToken token);
|
||||
Task<int> TryDelete(int id, CancellationToken token);
|
||||
Task<int> UpdateStateAsync(int id, SetpointsRequestDto setpointsRequestDto, CancellationToken token);
|
||||
Task<int> UpdateStateAsync(SetpointsRequestDto setpointsRequestDto, CancellationToken token);
|
||||
IEnumerable<SetpointInfoDto> GetSetpointsNames();
|
||||
}
|
||||
}
|
||||
|
15
AsbCloudApp/Services/IUserSettingsRepository.cs
Normal file
15
AsbCloudApp/Services/IUserSettingsRepository.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudApp.Services
|
||||
{
|
||||
public interface IUserSettingsRepository
|
||||
{
|
||||
public const int ErrorKeyNotFound = -1;
|
||||
public const int ErrorKeyIsUsed = -2;
|
||||
Task<object> GetOrDefaultAsync(int userId, string key, CancellationToken token);
|
||||
Task<int> InsertAsync(int userId, string key, object value, CancellationToken token);
|
||||
Task<int> UpdateAsync(int userId, string key, object value, CancellationToken token);
|
||||
Task<int> DeleteAsync(int userId, string key, CancellationToken token);
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -11,6 +12,38 @@ namespace AsbCloudDb
|
||||
{
|
||||
public static class EFExtentions
|
||||
{
|
||||
private static readonly System.Text.Json.JsonSerializerOptions jsonSerializerOptions = new()
|
||||
{
|
||||
AllowTrailingCommas = true,
|
||||
WriteIndented = true,
|
||||
NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString |
|
||||
System.Text.Json.Serialization.JsonNumberHandling.AllowNamedFloatingPointLiterals,
|
||||
};
|
||||
|
||||
public static Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder<TProperty> HasJsonConversion<TProperty>(
|
||||
this Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder<TProperty> builder)
|
||||
=> HasJsonConversion(builder, jsonSerializerOptions);
|
||||
|
||||
public static Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder<TProperty> HasJsonConversion<TProperty>(
|
||||
this Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder<TProperty> builder,
|
||||
System.Text.Json.JsonSerializerOptions jsonSerializerOptions)
|
||||
{
|
||||
builder.HasConversion(
|
||||
s => System.Text.Json.JsonSerializer.Serialize(s, jsonSerializerOptions),
|
||||
s => System.Text.Json.JsonSerializer.Deserialize<TProperty>(s, jsonSerializerOptions)!);
|
||||
|
||||
ValueComparer<TProperty> valueComparer = new (
|
||||
(a,b) =>
|
||||
(a!=null) && (b != null)
|
||||
? a.GetHashCode() == b.GetHashCode()
|
||||
: (a == null) && (b == null),
|
||||
i => (i == null) ?-1 : i.GetHashCode(),
|
||||
i => i);
|
||||
|
||||
builder.Metadata.SetValueComparer(valueComparer);
|
||||
return builder;
|
||||
}
|
||||
|
||||
static Dictionary<Type, IQueryStringFactory> QueryFactories { get; set; } = new();
|
||||
|
||||
static QueryStringFactory<T> GetQueryStringFactory<T>(DbSet<T> dbSet)
|
||||
@ -32,7 +65,7 @@ namespace AsbCloudDb
|
||||
{
|
||||
var factory = GetQueryStringFactory(dbSet);
|
||||
var query = factory.MakeInsertOrUpdateSql(items);
|
||||
|
||||
|
||||
return database.ExecuteSqlRawAsync(query, token);
|
||||
}
|
||||
|
||||
@ -97,7 +130,10 @@ namespace AsbCloudDb
|
||||
pk = pkColsNames is null ? string.Empty : $"({string.Join(", ", pkColsNames)})";
|
||||
|
||||
TableName = dbset.EntityType.GetTableName()!;
|
||||
getters = properties.Select(p => p.GetGetter());
|
||||
getters = properties
|
||||
.Where(p => !p.IsShadowProperty())
|
||||
.Select(p => p.GetGetter()).ToList();
|
||||
|
||||
Columns = properties.Select(p => $"\"{p.GetColumnBaseName()}\"");
|
||||
var colunmsString = $"({string.Join(", ", Columns)})";
|
||||
|
||||
@ -142,13 +178,21 @@ namespace AsbCloudDb
|
||||
private static string FormatValue(object? v)
|
||||
=> v switch
|
||||
{
|
||||
string vStr => $"'{vStr}'",
|
||||
string vStr => $"'{EscapeCurlyBraces(vStr)}'",
|
||||
DateTime vDate => $"'{FormatDateValue(vDate)}'",
|
||||
DateTimeOffset vDate => $"'{FormatDateValue(vDate.UtcDateTime)}'",
|
||||
IFormattable vFormattable => FormatFormattableValue(vFormattable),
|
||||
_ => System.Text.Json.JsonSerializer.Serialize(v),
|
||||
};
|
||||
|
||||
private static string EscapeCurlyBraces(string vStr)
|
||||
{
|
||||
var result = vStr
|
||||
.Replace("{", "{{")
|
||||
.Replace("}", "}}");
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string FormatFormattableValue(IFormattable v)
|
||||
=> v switch
|
||||
{
|
||||
|
6083
AsbCloudDb/Migrations/20220629122922_Add_new_well_operations_17_18.Designer.cs
generated
Normal file
6083
AsbCloudDb/Migrations/20220629122922_Add_new_well_operations_17_18.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,34 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace AsbCloudDb.Migrations
|
||||
{
|
||||
public partial class Add_new_well_operations_17_18 : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.InsertData(
|
||||
table: "t_well_operation_category",
|
||||
columns: new[] { "id", "code", "name" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ 18, 0, "Проработка перед наращиванием" },
|
||||
{ 19, 0, "Шаблонировка перед наращиванием" }
|
||||
});
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DeleteData(
|
||||
table: "t_well_operation_category",
|
||||
keyColumn: "id",
|
||||
keyValue: 18);
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "t_well_operation_category",
|
||||
keyColumn: "id",
|
||||
keyValue: 19);
|
||||
}
|
||||
}
|
||||
}
|
6083
AsbCloudDb/Migrations/20220719050018_Rename_WITS_base_table.Designer.cs
generated
Normal file
6083
AsbCloudDb/Migrations/20220719050018_Rename_WITS_base_table.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
185
AsbCloudDb/Migrations/20220719050018_Rename_WITS_base_table.cs
Normal file
185
AsbCloudDb/Migrations/20220719050018_Rename_WITS_base_table.cs
Normal file
@ -0,0 +1,185 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace AsbCloudDb.Migrations
|
||||
{
|
||||
public partial class Rename_WITS_base_table : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_t_telemetry_wits_1_RecordBase_id_telemetry_date",
|
||||
table: "t_telemetry_wits_1");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_t_telemetry_wits_50_RecordBase_id_telemetry_date",
|
||||
table: "t_telemetry_wits_50");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_t_telemetry_wits_60_RecordBase_id_telemetry_date",
|
||||
table: "t_telemetry_wits_60");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_t_telemetry_wits_61_RecordBase_id_telemetry_date",
|
||||
table: "t_telemetry_wits_61");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_t_telemetry_wits_7_RecordBase_id_telemetry_date",
|
||||
table: "t_telemetry_wits_7");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_t_telemetry_wits_8_RecordBase_id_telemetry_date",
|
||||
table: "t_telemetry_wits_8");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_RecordBase",
|
||||
table: "RecordBase");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "RecordBase",
|
||||
newName: "t_telemetry_wits_base");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_t_telemetry_wits_base",
|
||||
table: "t_telemetry_wits_base",
|
||||
columns: new[] { "id_telemetry", "date" });
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_t_telemetry_wits_1_t_telemetry_wits_base_id_telemetry_date",
|
||||
table: "t_telemetry_wits_1",
|
||||
columns: new[] { "id_telemetry", "date" },
|
||||
principalTable: "t_telemetry_wits_base",
|
||||
principalColumns: new[] { "id_telemetry", "date" },
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_t_telemetry_wits_50_t_telemetry_wits_base_id_telemetry_date",
|
||||
table: "t_telemetry_wits_50",
|
||||
columns: new[] { "id_telemetry", "date" },
|
||||
principalTable: "t_telemetry_wits_base",
|
||||
principalColumns: new[] { "id_telemetry", "date" },
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_t_telemetry_wits_60_t_telemetry_wits_base_id_telemetry_date",
|
||||
table: "t_telemetry_wits_60",
|
||||
columns: new[] { "id_telemetry", "date" },
|
||||
principalTable: "t_telemetry_wits_base",
|
||||
principalColumns: new[] { "id_telemetry", "date" },
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_t_telemetry_wits_61_t_telemetry_wits_base_id_telemetry_date",
|
||||
table: "t_telemetry_wits_61",
|
||||
columns: new[] { "id_telemetry", "date" },
|
||||
principalTable: "t_telemetry_wits_base",
|
||||
principalColumns: new[] { "id_telemetry", "date" },
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_t_telemetry_wits_7_t_telemetry_wits_base_id_telemetry_date",
|
||||
table: "t_telemetry_wits_7",
|
||||
columns: new[] { "id_telemetry", "date" },
|
||||
principalTable: "t_telemetry_wits_base",
|
||||
principalColumns: new[] { "id_telemetry", "date" },
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_t_telemetry_wits_8_t_telemetry_wits_base_id_telemetry_date",
|
||||
table: "t_telemetry_wits_8",
|
||||
columns: new[] { "id_telemetry", "date" },
|
||||
principalTable: "t_telemetry_wits_base",
|
||||
principalColumns: new[] { "id_telemetry", "date" },
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_t_telemetry_wits_1_t_telemetry_wits_base_id_telemetry_date",
|
||||
table: "t_telemetry_wits_1");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_t_telemetry_wits_50_t_telemetry_wits_base_id_telemetry_date",
|
||||
table: "t_telemetry_wits_50");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_t_telemetry_wits_60_t_telemetry_wits_base_id_telemetry_date",
|
||||
table: "t_telemetry_wits_60");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_t_telemetry_wits_61_t_telemetry_wits_base_id_telemetry_date",
|
||||
table: "t_telemetry_wits_61");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_t_telemetry_wits_7_t_telemetry_wits_base_id_telemetry_date",
|
||||
table: "t_telemetry_wits_7");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_t_telemetry_wits_8_t_telemetry_wits_base_id_telemetry_date",
|
||||
table: "t_telemetry_wits_8");
|
||||
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_t_telemetry_wits_base",
|
||||
table: "t_telemetry_wits_base");
|
||||
|
||||
migrationBuilder.RenameTable(
|
||||
name: "t_telemetry_wits_base",
|
||||
newName: "RecordBase");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_RecordBase",
|
||||
table: "RecordBase",
|
||||
columns: new[] { "id_telemetry", "date" });
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_t_telemetry_wits_1_RecordBase_id_telemetry_date",
|
||||
table: "t_telemetry_wits_1",
|
||||
columns: new[] { "id_telemetry", "date" },
|
||||
principalTable: "RecordBase",
|
||||
principalColumns: new[] { "id_telemetry", "date" },
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_t_telemetry_wits_50_RecordBase_id_telemetry_date",
|
||||
table: "t_telemetry_wits_50",
|
||||
columns: new[] { "id_telemetry", "date" },
|
||||
principalTable: "RecordBase",
|
||||
principalColumns: new[] { "id_telemetry", "date" },
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_t_telemetry_wits_60_RecordBase_id_telemetry_date",
|
||||
table: "t_telemetry_wits_60",
|
||||
columns: new[] { "id_telemetry", "date" },
|
||||
principalTable: "RecordBase",
|
||||
principalColumns: new[] { "id_telemetry", "date" },
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_t_telemetry_wits_61_RecordBase_id_telemetry_date",
|
||||
table: "t_telemetry_wits_61",
|
||||
columns: new[] { "id_telemetry", "date" },
|
||||
principalTable: "RecordBase",
|
||||
principalColumns: new[] { "id_telemetry", "date" },
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_t_telemetry_wits_7_RecordBase_id_telemetry_date",
|
||||
table: "t_telemetry_wits_7",
|
||||
columns: new[] { "id_telemetry", "date" },
|
||||
principalTable: "RecordBase",
|
||||
principalColumns: new[] { "id_telemetry", "date" },
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_t_telemetry_wits_8_RecordBase_id_telemetry_date",
|
||||
table: "t_telemetry_wits_8",
|
||||
columns: new[] { "id_telemetry", "date" },
|
||||
principalTable: "RecordBase",
|
||||
principalColumns: new[] { "id_telemetry", "date" },
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
}
|
||||
}
|
6089
AsbCloudDb/Migrations/20220719050312_Add_Well_operation_Flashing.Designer.cs
generated
Normal file
6089
AsbCloudDb/Migrations/20220719050312_Add_Well_operation_Flashing.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,25 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace AsbCloudDb.Migrations
|
||||
{
|
||||
public partial class Add_Well_operation_Flashing : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.InsertData(
|
||||
table: "t_well_operation_category",
|
||||
columns: new[] { "id", "code", "name" },
|
||||
values: new object[] { 20, 0, "Промывка перед наращиванием" });
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DeleteData(
|
||||
table: "t_well_operation_category",
|
||||
keyColumn: "id",
|
||||
keyValue: 20);
|
||||
}
|
||||
}
|
||||
}
|
6095
AsbCloudDb/Migrations/20220719095738_Add_Well_operation_StaticSurveying.Designer.cs
generated
Normal file
6095
AsbCloudDb/Migrations/20220719095738_Add_Well_operation_StaticSurveying.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,39 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace AsbCloudDb.Migrations
|
||||
{
|
||||
public partial class Add_Well_operation_StaticSurveying : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.UpdateData(
|
||||
table: "t_well_operation_category",
|
||||
keyColumn: "id",
|
||||
keyValue: 20,
|
||||
column: "name",
|
||||
value: "Промывка перед наращиванием");
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "t_well_operation_category",
|
||||
columns: new[] { "id", "code", "name" },
|
||||
values: new object[] { 21, 0, "Статический замер телесистемы" });
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DeleteData(
|
||||
table: "t_well_operation_category",
|
||||
keyColumn: "id",
|
||||
keyValue: 21);
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "t_well_operation_category",
|
||||
keyColumn: "id",
|
||||
keyValue: 20,
|
||||
column: "name",
|
||||
value: "Шаблонировка перед наращиванием");
|
||||
}
|
||||
}
|
||||
}
|
6129
AsbCloudDb/Migrations/20220727111254_Add_user_settings.Designer.cs
generated
Normal file
6129
AsbCloudDb/Migrations/20220727111254_Add_user_settings.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
38
AsbCloudDb/Migrations/20220727111254_Add_user_settings.cs
Normal file
38
AsbCloudDb/Migrations/20220727111254_Add_user_settings.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace AsbCloudDb.Migrations
|
||||
{
|
||||
public partial class Add_user_settings : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "t_user_settings",
|
||||
columns: table => new
|
||||
{
|
||||
idUser = table.Column<int>(type: "integer", nullable: false),
|
||||
key = table.Column<string>(type: "text", nullable: false, comment: "Ключ настроек пользователя"),
|
||||
setting_value = table.Column<object>(type: "jsonb", nullable: true, comment: "Значение настроек пользователя")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_t_user_settings", x => new { x.idUser, x.key });
|
||||
table.ForeignKey(
|
||||
name: "FK_t_user_settings_t_user_idUser",
|
||||
column: x => x.idUser,
|
||||
principalTable: "t_user",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
},
|
||||
comment: "настройки интерфейса пользователя");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "t_user_settings");
|
||||
}
|
||||
}
|
||||
}
|
6130
AsbCloudDb/Migrations/20220727124759_Add_user_settings_key_size_limit.Designer.cs
generated
Normal file
6130
AsbCloudDb/Migrations/20220727124759_Add_user_settings_key_size_limit.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,37 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace AsbCloudDb.Migrations
|
||||
{
|
||||
public partial class Add_user_settings_key_size_limit : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "key",
|
||||
table: "t_user_settings",
|
||||
type: "character varying(255)",
|
||||
maxLength: 255,
|
||||
nullable: false,
|
||||
comment: "Ключ настроек пользователя",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "text",
|
||||
oldComment: "Ключ настроек пользователя");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "key",
|
||||
table: "t_user_settings",
|
||||
type: "text",
|
||||
nullable: false,
|
||||
comment: "Ключ настроек пользователя",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(255)",
|
||||
oldMaxLength: 255,
|
||||
oldComment: "Ключ настроек пользователя");
|
||||
}
|
||||
}
|
||||
}
|
6130
AsbCloudDb/Migrations/20220728053614_UserSettings_rename_idUser.Designer.cs
generated
Normal file
6130
AsbCloudDb/Migrations/20220728053614_UserSettings_rename_idUser.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,49 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace AsbCloudDb.Migrations
|
||||
{
|
||||
public partial class UserSettings_rename_idUser : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_t_user_settings_t_user_idUser",
|
||||
table: "t_user_settings");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "idUser",
|
||||
table: "t_user_settings",
|
||||
newName: "id_user");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_t_user_settings_t_user_id_user",
|
||||
table: "t_user_settings",
|
||||
column: "id_user",
|
||||
principalTable: "t_user",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_t_user_settings_t_user_id_user",
|
||||
table: "t_user_settings");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "id_user",
|
||||
table: "t_user_settings",
|
||||
newName: "idUser");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_t_user_settings_t_user_idUser",
|
||||
table: "t_user_settings",
|
||||
column: "idUser",
|
||||
principalTable: "t_user",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AsbCloudDb.Model;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
@ -52,7 +51,7 @@ namespace AsbCloudDb.Migrations
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("longitude");
|
||||
|
||||
b.Property<SimpleTimezone>("Timezone")
|
||||
b.Property<string>("Timezone")
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("timezone")
|
||||
.HasComment("Смещение часового пояса от UTC");
|
||||
@ -149,7 +148,7 @@ namespace AsbCloudDb.Migrations
|
||||
.HasColumnName("start_date")
|
||||
.HasComment("Дата отчёта");
|
||||
|
||||
b.Property<DailyReportInfo>("Info")
|
||||
b.Property<string>("Info")
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("info")
|
||||
.HasComment("Список параметров для отчёта");
|
||||
@ -184,7 +183,7 @@ namespace AsbCloudDb.Migrations
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("longitude");
|
||||
|
||||
b.Property<SimpleTimezone>("Timezone")
|
||||
b.Property<string>("Timezone")
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("timezone")
|
||||
.HasComment("Смещение часового пояса от UTC");
|
||||
@ -704,7 +703,7 @@ namespace AsbCloudDb.Migrations
|
||||
.HasColumnName("name")
|
||||
.HasComment("Название файла");
|
||||
|
||||
b.Property<FilePublishInfo>("PublishInfo")
|
||||
b.Property<string>("PublishInfo")
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("publish_info")
|
||||
.HasComment("Информация о файле в облаке");
|
||||
@ -791,7 +790,7 @@ namespace AsbCloudDb.Migrations
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<RawData>("Data")
|
||||
b.Property<string>("Data")
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("data")
|
||||
.HasComment("Данные таблицы последних данных");
|
||||
@ -2727,7 +2726,7 @@ namespace AsbCloudDb.Migrations
|
||||
.HasColumnName("obsolescence")
|
||||
.HasComment("сек. до устаревания");
|
||||
|
||||
b.Property<Dictionary<string, double>>("Setpoints")
|
||||
b.Property<string>("Setpoints")
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("setpoint_set")
|
||||
.HasComment("Набор уставок");
|
||||
@ -2756,7 +2755,7 @@ namespace AsbCloudDb.Migrations
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<TelemetryInfo>("Info")
|
||||
b.Property<string>("Info")
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("info")
|
||||
.HasComment("Информация с панели о скважине");
|
||||
@ -2766,7 +2765,7 @@ namespace AsbCloudDb.Migrations
|
||||
.HasColumnName("remote_uid")
|
||||
.HasComment("Идентификатор передающего устройства. Может повторяться в списке, так как комплекты оборудования переезжают от скв. к скв.");
|
||||
|
||||
b.Property<SimpleTimezone>("TimeZone")
|
||||
b.Property<string>("TimeZone")
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("timezone")
|
||||
.HasComment("Смещение часового пояса от UTC");
|
||||
@ -3873,6 +3872,30 @@ namespace AsbCloudDb.Migrations
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AsbCloudDb.Model.UserSetting", b =>
|
||||
{
|
||||
b.Property<int>("IdUser")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id_user");
|
||||
|
||||
b.Property<string>("Key")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("character varying(255)")
|
||||
.HasColumnName("key")
|
||||
.HasComment("Ключ настроек пользователя");
|
||||
|
||||
b.Property<object>("Value")
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("setting_value")
|
||||
.HasComment("Значение настроек пользователя");
|
||||
|
||||
b.HasKey("IdUser", "Key");
|
||||
|
||||
b.ToTable("t_user_settings");
|
||||
|
||||
b.HasComment("настройки интерфейса пользователя");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AsbCloudDb.Model.Well", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@ -3912,7 +3935,7 @@ namespace AsbCloudDb.Migrations
|
||||
.HasColumnType("double precision")
|
||||
.HasColumnName("longitude");
|
||||
|
||||
b.Property<SimpleTimezone>("Timezone")
|
||||
b.Property<string>("Timezone")
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("timezone")
|
||||
.HasComment("Смещение часового пояса от UTC");
|
||||
@ -4164,6 +4187,30 @@ namespace AsbCloudDb.Migrations
|
||||
Name = "На поверхности"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 18,
|
||||
Code = 0,
|
||||
Name = "Проработка перед наращиванием"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 19,
|
||||
Code = 0,
|
||||
Name = "Шаблонировка перед наращиванием"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 20,
|
||||
Code = 0,
|
||||
Name = "Промывка перед наращиванием"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 21,
|
||||
Code = 0,
|
||||
Name = "Статический замер телесистемы"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = 1001,
|
||||
Code = 0,
|
||||
@ -4721,7 +4768,7 @@ namespace AsbCloudDb.Migrations
|
||||
|
||||
b.HasKey("IdTelemetry", "DateTime");
|
||||
|
||||
b.ToTable("RecordBase", (string)null);
|
||||
b.ToTable("t_telemetry_wits_base");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AsbCloudDb.Model.WITS.Record1", b =>
|
||||
@ -5787,6 +5834,17 @@ namespace AsbCloudDb.Migrations
|
||||
b.Navigation("Company");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AsbCloudDb.Model.UserSetting", b =>
|
||||
{
|
||||
b.HasOne("AsbCloudDb.Model.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("IdUser")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AsbCloudDb.Model.Well", b =>
|
||||
{
|
||||
b.HasOne("AsbCloudDb.Model.Cluster", "Cluster")
|
||||
|
@ -38,6 +38,7 @@ namespace AsbCloudDb.Model
|
||||
public virtual DbSet<TelemetryUser> TelemetryUsers => Set<TelemetryUser>();
|
||||
public virtual DbSet<User> Users => Set<User>();
|
||||
public virtual DbSet<UserRole> UserRoles => Set<UserRole>();
|
||||
public virtual DbSet<UserSetting> UserSettings => Set<UserSetting>();
|
||||
public virtual DbSet<Well> Wells => Set<Well>();
|
||||
public virtual DbSet<WellComposite> WellComposites => Set<WellComposite>();
|
||||
public virtual DbSet<WellOperation> WellOperations => Set<WellOperation>();
|
||||
@ -56,6 +57,14 @@ namespace AsbCloudDb.Model
|
||||
public DbSet<WITS.Record60> Record60 => Set<WITS.Record60>();
|
||||
public DbSet<WITS.Record61> Record61 => Set<WITS.Record61>();
|
||||
|
||||
private System.Text.Json.JsonSerializerOptions jsonSerializerOptions = new()
|
||||
{
|
||||
AllowTrailingCommas = true,
|
||||
WriteIndented = true,
|
||||
NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString |
|
||||
System.Text.Json.Serialization.JsonNumberHandling.AllowNamedFloatingPointLiterals,
|
||||
};
|
||||
|
||||
public AsbCloudDbContext() : base()
|
||||
{
|
||||
}
|
||||
@ -76,12 +85,47 @@ namespace AsbCloudDb.Model
|
||||
modelBuilder.HasPostgresExtension("adminpack")
|
||||
.HasAnnotation("Relational:Collation", "Russian_Russia.1251");
|
||||
|
||||
modelBuilder.Entity<Deposit>(entity =>
|
||||
{
|
||||
entity.Property(e => e.Timezone)
|
||||
.HasJsonConversion();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Cluster>(entity =>
|
||||
{
|
||||
entity.HasOne(d => d.Deposit)
|
||||
.WithMany(p => p.Clusters)
|
||||
.HasForeignKey(d => d.IdDeposit)
|
||||
.HasConstraintName("t_cluster_t_deposit_id_fk");
|
||||
|
||||
entity.Property(e => e.Timezone)
|
||||
.HasJsonConversion();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Well>(entity =>
|
||||
{
|
||||
entity.HasOne(d => d.Cluster)
|
||||
.WithMany(p => p.Wells)
|
||||
.HasForeignKey(d => d.IdCluster)
|
||||
.HasConstraintName("t_well_t_cluster_id_fk");
|
||||
|
||||
entity.HasOne(d => d.Telemetry)
|
||||
.WithOne(p => p.Well)
|
||||
.HasForeignKey<Well>(d => d.IdTelemetry)
|
||||
.OnDelete(DeleteBehavior.SetNull)
|
||||
.HasConstraintName("t_well_t_telemetry_id_fk");
|
||||
|
||||
entity.Property(e => e.Timezone)
|
||||
.HasJsonConversion();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Telemetry>(entity =>
|
||||
{
|
||||
entity.Property(e => e.Info)
|
||||
.HasJsonConversion();
|
||||
|
||||
entity.Property(e => e.TimeZone)
|
||||
.HasJsonConversion();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<WellComposite>(entity =>
|
||||
@ -175,20 +219,6 @@ namespace AsbCloudDb.Model
|
||||
.IsUnique();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Well>(entity =>
|
||||
{
|
||||
entity.HasOne(d => d.Cluster)
|
||||
.WithMany(p => p.Wells)
|
||||
.HasForeignKey(d => d.IdCluster)
|
||||
.HasConstraintName("t_well_t_cluster_id_fk");
|
||||
|
||||
entity.HasOne(d => d.Telemetry)
|
||||
.WithOne(p => p.Well)
|
||||
.HasForeignKey<Well>(d => d.IdTelemetry)
|
||||
.OnDelete(DeleteBehavior.SetNull)
|
||||
.HasConstraintName("t_well_t_telemetry_id_fk");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<RelationCompanyWell>(entity =>
|
||||
{
|
||||
entity.HasKey(nameof(RelationCompanyWell.IdCompany), nameof(RelationCompanyWell.IdWell));
|
||||
@ -241,6 +271,18 @@ namespace AsbCloudDb.Model
|
||||
.IsUnique();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Measure>(entity =>
|
||||
{
|
||||
entity.Property(e => e.Data)
|
||||
.HasJsonConversion();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<FileInfo>(entity =>
|
||||
{
|
||||
entity.Property(e => e.PublishInfo)
|
||||
.HasJsonConversion();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<FileMark>(entity =>
|
||||
{
|
||||
entity.HasOne(d => d.User)
|
||||
@ -278,6 +320,8 @@ namespace AsbCloudDb.Model
|
||||
{
|
||||
entity.HasKey(e => new { e.IdWell, e.StartDate })
|
||||
.HasName("t_id_well_date_start_pk");
|
||||
entity.Property(e => e.Info)
|
||||
.HasJsonConversion();
|
||||
});
|
||||
|
||||
modelBuilder.Entity<TelemetryDataSaubStat>(entity =>
|
||||
@ -294,17 +338,23 @@ namespace AsbCloudDb.Model
|
||||
.HasConstraintName("t_schedule_t_driller_id_driller");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<SetpointsRequest>(entity => {
|
||||
entity.Property(e => e.Setpoints)
|
||||
.HasJsonConversion();
|
||||
});
|
||||
|
||||
FillData(modelBuilder);
|
||||
}
|
||||
|
||||
public Task<int> RefreshMaterializedViewAsync<TEntity>(CancellationToken token = default)
|
||||
public Task<int> RefreshMaterializedViewAsync<TEntity>(CancellationToken token)
|
||||
where TEntity : class
|
||||
{
|
||||
var materializedViewName = Set<TEntity>().EntityType.GetViewName();
|
||||
return RefreshMaterializedViewAsync(materializedViewName!, token);
|
||||
var materializedViewName = Set<TEntity>().EntityType.GetViewName()
|
||||
?? throw new System.Exception($"RefreshMaterializedViewAsync<{typeof(TEntity).Name}>(..) db table for this type does not found.");
|
||||
return RefreshMaterializedViewAsync(materializedViewName, token);
|
||||
}
|
||||
|
||||
public Task<int> RefreshMaterializedViewAsync(string materializedViewName, CancellationToken token = default)
|
||||
public Task<int> RefreshMaterializedViewAsync(string materializedViewName, CancellationToken token)
|
||||
{
|
||||
var sql = $"REFRESH MATERIALIZED VIEW {materializedViewName};";
|
||||
return Database.ExecuteSqlRawAsync(sql, token);
|
||||
@ -632,6 +682,11 @@ namespace AsbCloudDb.Model
|
||||
new WellOperationCategory {Id = 15, Name = "Неподвижное состояние", Code = 0 },
|
||||
new WellOperationCategory {Id = 16, Name = "Вращение без циркуляции", Code = 0 },
|
||||
new WellOperationCategory {Id = 17, Name = "На поверхности", Code = 0 },
|
||||
new WellOperationCategory {Id = 18, Name = "Проработка перед наращиванием", Code = 0 },
|
||||
new WellOperationCategory {Id = 19, Name = "Шаблонировка перед наращиванием", Code = 0 },
|
||||
new WellOperationCategory {Id = 20, Name = "Промывка перед наращиванием", Code = 0 },
|
||||
new WellOperationCategory {Id = 21, Name = "Статический замер телесистемы", Code = 0 },
|
||||
|
||||
// Операции ручного ввода
|
||||
new WellOperationCategory {Id = 1001, Name = "Бурение", Code = 0 },
|
||||
new WellOperationCategory {Id = 1002, Name = "ГИС", Code = 0 },
|
||||
@ -783,6 +838,10 @@ namespace AsbCloudDb.Model
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity<UserSetting>(entity =>
|
||||
{
|
||||
entity.HasKey(nameof(UserSetting.IdUser), nameof(UserSetting.Key));
|
||||
});
|
||||
}
|
||||
|
||||
public Task<int> RefreshMaterializedViewAsync<TEntity>(string? mwName = null, CancellationToken token = default) where TEntity : class
|
||||
|
@ -56,8 +56,8 @@ namespace AsbCloudDb.Model
|
||||
|
||||
DatabaseFacade Database { get; }
|
||||
|
||||
Task<int> RefreshMaterializedViewAsync(string? mwName = null, CancellationToken token = default);
|
||||
Task<int> RefreshMaterializedViewAsync<TEntity>(CancellationToken token = default) where TEntity : class;
|
||||
Task<int> RefreshMaterializedViewAsync(string mwName, CancellationToken token);
|
||||
Task<int> RefreshMaterializedViewAsync<TEntity>(CancellationToken token) where TEntity : class;
|
||||
int SaveChanges();
|
||||
int SaveChanges(bool acceptAllChangesOnSuccess);
|
||||
Task<int> SaveChangesAsync(CancellationToken cancellationToken);
|
||||
|
24
AsbCloudDb/Model/UserSetting.cs
Normal file
24
AsbCloudDb/Model/UserSetting.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace AsbCloudDb.Model
|
||||
{
|
||||
|
||||
[Table("t_user_settings"), Comment("настройки интерфейса пользователя")]
|
||||
public class UserSetting
|
||||
{
|
||||
[Column("id_user")]
|
||||
public int IdUser { get; set; }
|
||||
|
||||
[Column("key"), Comment("Ключ настроек пользователя"), StringLength(255)]
|
||||
public string Key { get; set; } = null!;
|
||||
|
||||
[Column("setting_value", TypeName = "jsonb"), Comment("Значение настроек пользователя")]
|
||||
public object? Value { get; set; }
|
||||
|
||||
[ForeignKey(nameof(IdUser))]
|
||||
public User User { get; set; } = null!;
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ namespace AsbCloudDb.Model.WITS
|
||||
/// <summary>
|
||||
/// This is base class for all WITS-0 records
|
||||
/// </summary>
|
||||
[Table("t_telemetry_wits_base")]
|
||||
public abstract class RecordBase : ITelemetryData
|
||||
{
|
||||
[Column("id_telemetry")]
|
||||
|
@ -2,6 +2,7 @@
|
||||
using AsbCloudApp.Data.SAUB;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.Repository;
|
||||
using AsbCloudInfrastructure.Services;
|
||||
using AsbCloudInfrastructure.Services.Cache;
|
||||
using AsbCloudInfrastructure.Services.DailyReport;
|
||||
@ -66,8 +67,6 @@ namespace AsbCloudInfrastructure
|
||||
.ForType<ClusterDto, Cluster>()
|
||||
.Ignore(dst => dst.Deposit,
|
||||
dst => dst.Wells);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
|
||||
@ -118,6 +117,7 @@ namespace AsbCloudInfrastructure
|
||||
services.AddTransient<IDrillerService, DrillerService>();
|
||||
services.AddTransient<IScheduleService, ScheduleService>();
|
||||
services.AddTransient<IOperationValueService, OperationValueService>();
|
||||
services.AddTransient<IUserSettingsRepository, UserSettingsRepository>();
|
||||
|
||||
// admin crud services:
|
||||
services.AddTransient<ICrudService<TelemetryDto>, CrudServiceBase<TelemetryDto, Telemetry>>(s =>
|
||||
|
@ -7,7 +7,7 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services
|
||||
namespace AsbCloudInfrastructure.Repository
|
||||
{
|
||||
#nullable enable
|
||||
/// <summary>
|
||||
@ -17,7 +17,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
public class CrudCacheServiceBase<TDto, TEntity> : CrudServiceBase<TDto, TEntity>
|
||||
where TDto : AsbCloudApp.Data.IId
|
||||
where TEntity : class, AsbCloudDb.Model.IId
|
||||
where TEntity : class, IId
|
||||
{
|
||||
protected string CacheTag = typeof(TDto).Name;
|
||||
protected TimeSpan CacheOlescence = TimeSpan.FromMinutes(5);
|
||||
@ -53,9 +53,8 @@ namespace AsbCloudInfrastructure.Services
|
||||
/// <inheritdoc/>
|
||||
public override async Task<IEnumerable<TDto>> GetAllAsync(CancellationToken token)
|
||||
{
|
||||
var result = await GetQuery()
|
||||
.FromCacheDictionaryAsync(CacheTag, CacheOlescence, KeySelector, Convert, token);
|
||||
return result.Values;
|
||||
var cache = await GetCacheAsync(token);
|
||||
return cache.Values;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -63,19 +62,17 @@ namespace AsbCloudInfrastructure.Services
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public override TDto? Get(int id)
|
||||
public override TDto? GetOrDefault(int id)
|
||||
{
|
||||
var result = GetQuery()
|
||||
.FromCacheDictionary(CacheTag, CacheOlescence, KeySelector, Convert);
|
||||
return result.GetValueOrDefault(id);
|
||||
var cache = GetCache();
|
||||
return cache.GetValueOrDefault(id);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task<TDto?> GetAsync(int id, CancellationToken token)
|
||||
public override async Task<TDto?> GetOrDefaultAsync(int id, CancellationToken token)
|
||||
{
|
||||
var result = await GetQuery()
|
||||
.FromCacheDictionaryAsync(CacheTag, CacheOlescence, KeySelector, Convert, token);
|
||||
return result.GetValueOrDefault(id);
|
||||
var cache = await GetCacheAsync(token);
|
||||
return cache.GetValueOrDefault(id);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
@ -8,9 +8,9 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services
|
||||
namespace AsbCloudInfrastructure.Repository
|
||||
{
|
||||
|
||||
#nullable enable
|
||||
/// <summary>
|
||||
/// CRUD сервис для работы с БД
|
||||
/// </summary>
|
||||
@ -18,7 +18,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
public class CrudServiceBase<TDto, TEntity> : ICrudService<TDto>
|
||||
where TDto : AsbCloudApp.Data.IId
|
||||
where TEntity : class, AsbCloudDb.Model.IId
|
||||
where TEntity : class, IId
|
||||
{
|
||||
protected readonly IAsbCloudDbContext dbContext;
|
||||
protected readonly DbSet<TEntity> dbSet;
|
||||
@ -26,7 +26,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
|
||||
public CrudServiceBase(IAsbCloudDbContext context)
|
||||
{
|
||||
this.dbContext = context;
|
||||
dbContext = context;
|
||||
dbSet = context.Set<TEntity>();
|
||||
GetQuery = () => dbSet;
|
||||
}
|
||||
@ -47,7 +47,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
|
||||
public CrudServiceBase(IAsbCloudDbContext context, Func<DbSet<TEntity>, IQueryable<TEntity>> makeQuery)
|
||||
{
|
||||
this.dbContext = context;
|
||||
dbContext = context;
|
||||
dbSet = context.Set<TEntity>();
|
||||
GetQuery = () => makeQuery(dbSet);
|
||||
}
|
||||
@ -65,7 +65,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task<TDto?> GetAsync(int id, CancellationToken token = default)
|
||||
public virtual async Task<TDto?> GetOrDefaultAsync(int id, CancellationToken token = default)
|
||||
{
|
||||
var entity = await GetQuery()
|
||||
.AsNoTracking()
|
||||
@ -78,7 +78,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual TDto? Get(int id)
|
||||
public virtual TDto? GetOrDefault(int id)
|
||||
{
|
||||
var entity = GetQuery()
|
||||
.AsNoTracking()
|
@ -0,0 +1,51 @@
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudInfrastructure.Repository
|
||||
{
|
||||
#nullable enable
|
||||
public class CrudWellRelatedCacheServiceBase<TDto, TEntity> : CrudCacheServiceBase<TDto, TEntity>, ICrudWellRelatedService<TDto>
|
||||
where TDto : AsbCloudApp.Data.IId, AsbCloudApp.Data.IWellRelated
|
||||
where TEntity : class, IId, IWellRelated
|
||||
{
|
||||
public CrudWellRelatedCacheServiceBase(IAsbCloudDbContext context)
|
||||
: base(context) { }
|
||||
|
||||
public CrudWellRelatedCacheServiceBase(IAsbCloudDbContext dbContext, ISet<string> includes)
|
||||
: base(dbContext, includes) { }
|
||||
|
||||
public CrudWellRelatedCacheServiceBase(IAsbCloudDbContext context, Func<DbSet<TEntity>, IQueryable<TEntity>> makeQuery)
|
||||
: base(context, makeQuery) { }
|
||||
|
||||
public async Task<IEnumerable<TDto>> GetByIdWellAsync(int idWell, CancellationToken token)
|
||||
{
|
||||
var cache = await GetCacheAsync(token);
|
||||
|
||||
var dtos = cache.Values
|
||||
.Where(e => e.IdWell == idWell)
|
||||
.ToList();
|
||||
|
||||
return dtos;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<TDto>> GetByIdWellAsync(IEnumerable<int> idsWells, CancellationToken token)
|
||||
{
|
||||
if (!idsWells.Any())
|
||||
return Enumerable.Empty<TDto>();
|
||||
|
||||
var cache = await GetCacheAsync(token);
|
||||
|
||||
var dtos = cache.Values
|
||||
.Where(e => idsWells.Contains(e.IdWell))
|
||||
.ToList();
|
||||
return dtos;
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
}
|
@ -7,12 +7,12 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services
|
||||
namespace AsbCloudInfrastructure.Repository
|
||||
{
|
||||
#nullable enable
|
||||
public class CrudWellRelatedServiceBase<TDto, TEntity> : CrudServiceBase<TDto, TEntity>, ICrudWellRelatedService<TDto>
|
||||
where TDto : AsbCloudApp.Data.IId, AsbCloudApp.Data.IWellRelated
|
||||
where TEntity : class, AsbCloudDb.Model.IId, AsbCloudDb.Model.IWellRelated
|
||||
where TEntity : class, IId, IWellRelated
|
||||
{
|
||||
public CrudWellRelatedServiceBase(IAsbCloudDbContext context)
|
||||
: base(context) { }
|
@ -0,0 +1,36 @@
|
||||
using AsbCloudApp.Data.SAUB;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
|
||||
namespace AsbCloudInfrastructure.Repository
|
||||
{
|
||||
public class SetpointsRequestRepository : CrudWellRelatedCacheServiceBase<SetpointsRequestDto, SetpointsRequest>
|
||||
{
|
||||
private readonly IWellService wellService;
|
||||
|
||||
public SetpointsRequestRepository(IAsbCloudDbContext dbContext, IWellService wellService)
|
||||
: base(dbContext, q => q.Include(s => s.Author)
|
||||
.Include(s => s.Well))
|
||||
{
|
||||
this.wellService = wellService;
|
||||
}
|
||||
|
||||
protected override SetpointsRequestDto Convert(SetpointsRequest src)
|
||||
{
|
||||
var result = base.Convert(src);
|
||||
var timezoneOffsetHours = wellService.GetTimezone(src.IdWell).Hours;
|
||||
result.UploadDate = src.UploadDate.ToRemoteDateTime(timezoneOffsetHours);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected override SetpointsRequest Convert(SetpointsRequestDto src)
|
||||
{
|
||||
var result = base.Convert(src);
|
||||
var timezoneOffsetHours = wellService.GetTimezone(src.IdWell).Hours;
|
||||
result.UploadDate = src.UploadDate.ToUtcDateTimeOffset(timezoneOffsetHours);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
9
AsbCloudInfrastructure/Repository/readme.md
Normal file
9
AsbCloudInfrastructure/Repository/readme.md
Normal file
@ -0,0 +1,9 @@
|
||||
# Repository
|
||||
`Repository` - CRUD сервис для сущности в проекте. Не содержит бизнес логику.
|
||||
|
||||
Вся логика такого сервиса - преобразование данных полученых из БД в Data Transfer Object (DTO) и обратно.
|
||||
Преобразования осуществляются методами `Convert` с базовым маппингом:
|
||||
|
||||
protected virtual TDto Convert(TEntity src) => src.Adapt<TDto>();
|
||||
protected virtual TEntity Convert(TDto src) => src.Adapt<TEntity>();
|
||||
|
@ -51,7 +51,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
if (identity == default || user.IdState == 0)
|
||||
return null;
|
||||
|
||||
var userDto = await userService.GetAsync(user.Id, token)
|
||||
var userDto = await userService.GetOrDefaultAsync(user.Id, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var userTokenDto = userDto.Adapt<UserTokenDto>();
|
||||
@ -195,10 +195,13 @@ namespace AsbCloudInfrastructure.Services
|
||||
|
||||
private bool CheckPassword(string passwordHash, string password)
|
||||
{
|
||||
if (passwordHash.Length == 0 && password.Length == 0)
|
||||
if (passwordHash?.Length == 0 && password.Length == 0)
|
||||
return true;
|
||||
|
||||
if (passwordHash.Length < PasswordSaltLength)
|
||||
if (passwordHash?.Length < PasswordSaltLength)
|
||||
return false;
|
||||
|
||||
if (passwordHash is null)
|
||||
return false;
|
||||
|
||||
var salt = passwordHash[0..PasswordSaltLength];
|
||||
|
@ -6,11 +6,11 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||
{
|
||||
public DateTimeOffset DateTime { get; set; }
|
||||
public int? IdUser { get; set; }
|
||||
public float? WellDepth { get; set; }
|
||||
public float? Pressure { get; set; }
|
||||
public float? HookWeight { get; set; }
|
||||
public float? BlockPosition { get; set; }
|
||||
public float? BitDepth { get; set; }
|
||||
public float? RotorSpeed { get; set; }
|
||||
public float WellDepth { get; set; }
|
||||
public float Pressure { get; set; }
|
||||
public float HookWeight { get; set; }
|
||||
public float BlockPosition { get; set; }
|
||||
public float BitDepth { get; set; }
|
||||
public float RotorSpeed { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -33,9 +33,9 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||
this.scheduleService = scheduleService;
|
||||
}
|
||||
|
||||
public async Task<DetectedOperationListDto> GetAsync(int idWell, DetectedOperationRequest request, CancellationToken token)
|
||||
public async Task<DetectedOperationListDto> GetAsync(DetectedOperationRequest request, CancellationToken token)
|
||||
{
|
||||
var well = await wellService.GetAsync(idWell, token);
|
||||
var well = await wellService.GetOrDefaultAsync(request.IdWell, token);
|
||||
if (well?.IdTelemetry is null || well.Timezone is null)
|
||||
return null;
|
||||
|
||||
@ -44,8 +44,8 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||
|
||||
var data = await query.ToListAsync(token);
|
||||
|
||||
var operationValues = await operationValueService.GetByIdWellAsync(idWell, token);
|
||||
var schedules = await scheduleService.GetByIdWellAsync(idWell, token);
|
||||
var operationValues = await operationValueService.GetByIdWellAsync(request.IdWell, token);
|
||||
var schedules = await scheduleService.GetByIdWellAsync(request.IdWell, token);
|
||||
var dtos = data.Select(o => Convert(o, well, operationValues, schedules));
|
||||
var groups = dtos.GroupBy(o => o.Driller);
|
||||
|
||||
@ -78,9 +78,9 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<int> DeleteAsync(int idWell, DetectedOperationRequest request, CancellationToken token)
|
||||
public async Task<int> DeleteAsync(DetectedOperationRequest request, CancellationToken token)
|
||||
{
|
||||
var well = await wellService.GetAsync(idWell, token);
|
||||
var well = await wellService.GetOrDefaultAsync(request.IdWell, token);
|
||||
if (well?.IdTelemetry is null || well.Timezone is null)
|
||||
return 0;
|
||||
|
||||
@ -122,8 +122,7 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||
|
||||
if (request is not null)
|
||||
{
|
||||
if (request.CategoryIds is not null)
|
||||
query = query.Where(o => request.CategoryIds.Contains(o.IdCategory));
|
||||
query = query.Where(o => request.IdCategory == o.IdCategory);
|
||||
|
||||
if (request.GtDate is not null)
|
||||
query = query.Where(o => o.DateStart >= request.GtDate.Value.ToUtcDateTimeOffset(well.Timezone.Hours));
|
||||
@ -166,8 +165,9 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||
var dateStart = operation.DateStart.ToRemoteDateTime(well.Timezone.Hours);
|
||||
dto.DateStart = dateStart;
|
||||
dto.DateEnd = operation.DateEnd.ToRemoteDateTime(well.Timezone.Hours);
|
||||
dto.OperationValue = operationValues.FirstOrDefault(e => e.IdOperationCategory == dto.IdCategory
|
||||
&& e.DepthStart <= dto.DepthStart);
|
||||
dto.OperationValue = operationValues.FirstOrDefault(v => v.IdOperationCategory == dto.IdCategory
|
||||
&& v.DepthStart <= dto.DepthStart
|
||||
&& v.DepthEnd > dto.DepthStart);
|
||||
|
||||
var timeStart = new TimeDto(dateStart);
|
||||
var driller = schedules.FirstOrDefault(s =>
|
||||
@ -182,15 +182,32 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||
return dto;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<WellOperationCategoryDto>> GetCategoriesAsync(CancellationToken token)
|
||||
public async Task<IEnumerable<WellOperationCategoryDto>> GetCategoriesAsync(int? idWell, CancellationToken token)
|
||||
{
|
||||
var result = await db.WellOperationCategories
|
||||
IQueryable<WellOperationCategory> query = null;
|
||||
if(idWell is null)
|
||||
{
|
||||
query = db.WellOperationCategories;
|
||||
}
|
||||
else
|
||||
{
|
||||
var well = await wellService.GetOrDefaultAsync((int )idWell, token);
|
||||
if (well?.IdTelemetry is null)
|
||||
return null;
|
||||
var idTelemetry = (int)well.IdTelemetry;
|
||||
query = db.DetectedOperations
|
||||
.Include(o => o.OperationCategory)
|
||||
.Where(o => o.IdTelemetry == idTelemetry)
|
||||
.Select(o => o.OperationCategory)
|
||||
.Distinct();
|
||||
}
|
||||
|
||||
var result = await query
|
||||
.Where(c => c.Id < 1000)
|
||||
.AsNoTracking()
|
||||
.Select(c => c.Adapt<WellOperationCategoryDto>())
|
||||
.ToArrayAsync(token);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,71 +1,307 @@
|
||||
using AsbCloudDb.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
{
|
||||
|
||||
#nullable enable
|
||||
|
||||
abstract class DetectorAbstract
|
||||
internal abstract class DetectorAbstract
|
||||
{
|
||||
public int StepLength { get; set; } = 3;
|
||||
public int FragmentLength { get; set; } = 6;
|
||||
public int IdCategory { get; }
|
||||
private readonly int idOperation;
|
||||
private readonly int stepLength = 3;
|
||||
|
||||
// TODO: assert MaxDurationSeconds and MinDurationSeconds
|
||||
public double MaxDurationSeconds { get; } = 31 * 24 * 60 * 60;
|
||||
public double MinDurationSeconds { get; } = 3;
|
||||
|
||||
/// <summary>
|
||||
/// Конструктор детектора.
|
||||
/// Словарь с IdCategory в дефолтных данных AsbCloudDbContext для таблицы WellOperationCategory
|
||||
/// </summary>
|
||||
/// <param name="IdCategory">ключ названия/описания операции из таблицы WellOperationCategory</param>
|
||||
public DetectorAbstract(int IdCategory)
|
||||
protected DetectorAbstract(int idOperation)
|
||||
{
|
||||
this.IdCategory = IdCategory;
|
||||
this.idOperation = idOperation;
|
||||
}
|
||||
|
||||
public virtual DetectedOperation? DetectOrDefault(DetectableTelemetry[] telemetry, ref int position)
|
||||
public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end, DetectedOperation? previousOperation, out OperationDetectorResult? result)
|
||||
{
|
||||
if ((telemetry.Length > position + FragmentLength + StepLength) && DetectStart(telemetry, position))
|
||||
// Проверка соответствия критерию начала операции
|
||||
if (DetectBegin(telemetry, begin, previousOperation))
|
||||
{
|
||||
var skip = position + StepLength;
|
||||
while (telemetry.Length > skip + FragmentLength)
|
||||
// Поиск окончания соответствия критерию
|
||||
var positionEnd = begin;
|
||||
while (positionEnd < end)
|
||||
{
|
||||
if (DetectEnd(telemetry, skip))
|
||||
positionEnd += stepLength;
|
||||
if ((positionEnd > end))
|
||||
break;
|
||||
|
||||
if (DetectEnd(telemetry, positionEnd, previousOperation))
|
||||
{
|
||||
var dateStart = telemetry[position].DateTime;
|
||||
var dateEnd = telemetry[skip].DateTime;
|
||||
var durationSec = (dateEnd - dateStart).TotalSeconds;
|
||||
if (durationSec < MinDurationSeconds || durationSec > MaxDurationSeconds)
|
||||
return null;
|
||||
|
||||
var result = new DetectedOperation
|
||||
{
|
||||
IdCategory = IdCategory,
|
||||
IdUsersAtStart = telemetry[position].IdUser ?? -1,
|
||||
DateStart = dateStart,
|
||||
DateEnd = dateEnd,
|
||||
DepthStart = telemetry[position].WellDepth ?? -1d,
|
||||
DepthEnd = telemetry[skip].WellDepth ?? -1d,
|
||||
};
|
||||
CalcValue(ref result);
|
||||
position = skip + FragmentLength;
|
||||
return result;
|
||||
result = MakeOperation(idTelemetry, telemetry, begin, positionEnd);
|
||||
return true;
|
||||
}
|
||||
|
||||
skip = skip + StepLength;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected abstract void CalcValue(ref DetectedOperation result);
|
||||
protected abstract bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation);
|
||||
protected virtual bool DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
=> !DetectBegin(telemetry, position, previousOperation);
|
||||
|
||||
protected abstract bool DetectStart(DetectableTelemetry[] telemetry, int position);
|
||||
private OperationDetectorResult MakeOperation(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end)
|
||||
{
|
||||
var pBegin = telemetry[begin];
|
||||
var pEnd = telemetry[end];
|
||||
var result = new OperationDetectorResult
|
||||
{
|
||||
TelemetryBegin = begin,
|
||||
TelemetryEnd = end,
|
||||
Operation = new DetectedOperation
|
||||
{
|
||||
IdTelemetry = idTelemetry,
|
||||
IdCategory = idOperation,
|
||||
IdUsersAtStart = pBegin.IdUser ?? -1,
|
||||
DateStart = pBegin.DateTime,
|
||||
DateEnd = pEnd.DateTime,
|
||||
DepthStart = (double)pBegin.WellDepth,
|
||||
DepthEnd = (double)pEnd.WellDepth,
|
||||
Value = CalcValue(telemetry, begin, end),
|
||||
},
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
protected abstract bool DetectEnd(DetectableTelemetry[] telemetry, int position);
|
||||
protected abstract bool IsValid(DetectableTelemetry[] telemetry, int begin, int end);
|
||||
|
||||
protected abstract double CalcValue(DetectableTelemetry[] telemetry, int begin, int end);
|
||||
|
||||
public static InterpolationLine MakeInterpolationLine(
|
||||
Func<DetectableTelemetry, double> yGetter,
|
||||
DetectableTelemetry[] telemetry,
|
||||
int begin,
|
||||
int fragmentLength)
|
||||
{
|
||||
DetectableTelemetry[] data;
|
||||
if (fragmentLength > 0 && (begin + fragmentLength) < telemetry.Length)
|
||||
data = telemetry[begin..(begin + fragmentLength)];
|
||||
else
|
||||
data = telemetry[begin..];
|
||||
var line = new InterpolationLine(data.Select(d => (yGetter(d), (d.DateTime - telemetry[0].DateTime).TotalHours)));
|
||||
return line;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// расчет продолжительности операции
|
||||
/// </summary>
|
||||
/// <param name="telemetry"></param>
|
||||
/// <param name="begin"></param>
|
||||
/// <param name="end"></param>
|
||||
/// <returns></returns>
|
||||
protected static double CalcDeltaMinutes(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
{
|
||||
var pBegin = telemetry[begin];
|
||||
var pEnd = telemetry[end];
|
||||
var result = (pEnd.DateTime - pBegin.DateTime).TotalMinutes;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// часто используемый предикат для определения отсутствия изменения глубины ствола скважины
|
||||
/// </summary>
|
||||
/// <param name="telemetry"></param>
|
||||
/// <param name="begin"></param>
|
||||
/// <param name="end"></param>
|
||||
/// <returns></returns>
|
||||
protected static bool IsValidByWellDepthDoesNotChange(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
{
|
||||
var pBegin = telemetry[begin];
|
||||
var pEnd = telemetry[end];
|
||||
if (Math.Abs((double)(pBegin.WellDepth - pEnd.WellDepth)) > 0.01)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static bool IsValidByWellDepthIncreasing(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
{
|
||||
var pBegin = telemetry[begin];
|
||||
var pEnd = telemetry[end];
|
||||
if (pBegin.WellDepth >= pEnd.WellDepth)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static double CalcRop(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
{
|
||||
var pBegin = telemetry[begin];
|
||||
var pEnd = telemetry[end];
|
||||
var result = (double)(pEnd.WellDepth - pBegin.WellDepth) / (pEnd.DateTime - pBegin.DateTime).TotalHours;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Расчет статистики по массиву данных за интервал
|
||||
/// </summary>
|
||||
/// <param name="telemetry"></param>
|
||||
/// <param name="getter"></param>
|
||||
/// <param name="begin"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <returns></returns>
|
||||
protected static (double min, double max, double sum, int count) CalcStat(
|
||||
DetectableTelemetry[] telemetry,
|
||||
Func<DetectableTelemetry, double> getter,
|
||||
int begin,
|
||||
int count)
|
||||
{
|
||||
var sum = 0d;
|
||||
var min = double.MaxValue;
|
||||
var max = double.MinValue;
|
||||
var end = begin + count;
|
||||
end = end < telemetry.Length ? end : telemetry.Length;
|
||||
|
||||
for (var i = begin; i < end; i++)
|
||||
{
|
||||
var item = telemetry[i];
|
||||
var itemValue = getter(item);
|
||||
if (min > itemValue)
|
||||
min = itemValue;
|
||||
if (max < itemValue)
|
||||
max = itemValue;
|
||||
sum += itemValue;
|
||||
}
|
||||
return (min, max, sum, end - begin);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Максимальное отклонение от среднего за интервал
|
||||
/// </summary>
|
||||
/// <param name="telemetry"></param>
|
||||
/// <param name="getter"></param>
|
||||
/// <param name="begin"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <returns></returns>
|
||||
protected static double CalcMaxDeviation(
|
||||
DetectableTelemetry[] telemetry,
|
||||
Func<DetectableTelemetry, double> getter,
|
||||
int begin,
|
||||
int count)
|
||||
{
|
||||
var stat = CalcStat(telemetry, getter, begin, count);
|
||||
var avg = stat.sum / stat.count;
|
||||
var dev1 = avg - stat.min;
|
||||
var dev2 = stat.max - avg;
|
||||
var dev = dev1 > dev2 ? dev1 : dev2;
|
||||
return dev;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Определяет наличие разброса значений в интервале большего указанного значения.
|
||||
/// </summary>
|
||||
/// <param name="telemetry"></param>
|
||||
/// <param name="getter"></param>
|
||||
/// <param name="begin"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <param name="deviation"></param>
|
||||
/// <returns></returns>
|
||||
protected static bool ContainsDeviation(
|
||||
DetectableTelemetry[] telemetry,
|
||||
Func<DetectableTelemetry, double> getter,
|
||||
int begin,
|
||||
int count,
|
||||
double deviation)
|
||||
{
|
||||
var min = double.MaxValue;
|
||||
var max = double.MinValue;
|
||||
var end = begin + count;
|
||||
end = end < telemetry.Length ? end : telemetry.Length;
|
||||
|
||||
for (var i = begin; i < end; i ++)
|
||||
{
|
||||
var item = telemetry[i];
|
||||
var itemValue = getter(item);
|
||||
if (min > itemValue)
|
||||
min = itemValue;
|
||||
if (max < itemValue)
|
||||
max = itemValue;
|
||||
if(max - min > deviation)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Определяет наличие разброса значений в интервале большего указанного значения. По нескольким значениям из интервала.
|
||||
/// </summary>
|
||||
/// <param name="telemetry"></param>
|
||||
/// <param name="getter"></param>
|
||||
/// <param name="begin"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <param name="deviation"></param>
|
||||
/// <returns></returns>
|
||||
protected static bool ContainsDeviationApprox(
|
||||
DetectableTelemetry[] telemetry,
|
||||
Func<DetectableTelemetry, double> getter,
|
||||
int begin,
|
||||
int count,
|
||||
double deviation)
|
||||
{
|
||||
var min = double.MaxValue;
|
||||
var max = double.MinValue;
|
||||
var end = begin + count;
|
||||
end = end < telemetry.Length ? end : telemetry.Length;
|
||||
var step = count > 15 ? count / 5 : count > 3 ? 3: 1;
|
||||
for (var i = begin; i < end; i+= step)
|
||||
{
|
||||
var item = telemetry[i];
|
||||
var itemValue = getter(item);
|
||||
if (min > itemValue)
|
||||
min = itemValue;
|
||||
if (max < itemValue)
|
||||
max = itemValue;
|
||||
if (max - min > deviation)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static bool DeviatesFromBegin(
|
||||
DetectableTelemetry[] telemetry,
|
||||
Func<DetectableTelemetry, double> getter,
|
||||
int begin,
|
||||
int count,
|
||||
double deviation)
|
||||
{
|
||||
var beginPointValue = getter(telemetry[begin]);
|
||||
var end = begin + count;
|
||||
end = end < telemetry.Length ? end : telemetry.Length;
|
||||
var step = count > 15 ? count / 5 : count > 3 ? 3 : 1;
|
||||
for (var i = begin; i < end; i += step)
|
||||
{
|
||||
var item = telemetry[i];
|
||||
var itemValue = getter(item);
|
||||
if (Math.Abs(beginPointValue - itemValue) > deviation)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static bool RisesFromBegin(
|
||||
DetectableTelemetry[] telemetry,
|
||||
Func<DetectableTelemetry, double> getter,
|
||||
int begin,
|
||||
int count,
|
||||
double deviation)
|
||||
{
|
||||
var beginPointValue = getter(telemetry[begin]);
|
||||
var end = begin + count;
|
||||
end = end < telemetry.Length ? end : telemetry.Length;
|
||||
var step = count > 15 ? count / 5 : count > 3 ? 3 : 1;
|
||||
for (var i = begin; i < end; i += step)
|
||||
{
|
||||
var item = telemetry[i];
|
||||
var itemValue = getter(item);
|
||||
if ( itemValue - beginPointValue > deviation)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#nullable disable
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,64 @@
|
||||
using AsbCloudDb.Model;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
{
|
||||
#nullable enable
|
||||
internal class DetectorDevelopment : DetectorAbstract
|
||||
{
|
||||
public DetectorDevelopment()
|
||||
: base(18) { }
|
||||
|
||||
protected override double CalcValue(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
=> CalcDeltaMinutes(telemetry, begin, end);
|
||||
|
||||
protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
{
|
||||
if (previousOperation?.IdCategory == 14)
|
||||
return false;
|
||||
|
||||
var point0 = telemetry[position];
|
||||
var delta = point0.WellDepth - point0.BitDepth;
|
||||
if (delta < 0.03d || delta > 30)
|
||||
return false;
|
||||
|
||||
if (point0.Pressure < 15)
|
||||
return false;
|
||||
|
||||
if (point0.BlockPosition > 2.5)
|
||||
return false;
|
||||
|
||||
if (point0.RotorSpeed < 10)
|
||||
return false;
|
||||
|
||||
if (!ContainsDeviationApprox(telemetry, d => d.BlockPosition, position, 60, 0.03))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
{
|
||||
var point0 = telemetry[position];
|
||||
var delta = point0.WellDepth - point0.BitDepth;
|
||||
if (delta < 0.03d || delta > 30)
|
||||
return true;
|
||||
|
||||
if (point0.Pressure < 15)
|
||||
return true;
|
||||
|
||||
if (point0.BlockPosition > 31)
|
||||
return true;
|
||||
|
||||
if (point0.RotorSpeed < 10)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool IsValid(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
=> IsValidByWellDepthDoesNotChange(telemetry, begin, end);
|
||||
}
|
||||
|
||||
#nullable disable
|
||||
}
|
||||
|
@ -1,53 +0,0 @@
|
||||
using AsbCloudDb.Model;
|
||||
using System.Linq;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
{
|
||||
#nullable enable
|
||||
class DetectorDrillingRotor : DetectorAbstract
|
||||
{
|
||||
public DetectorDrillingRotor() : base(1)
|
||||
{
|
||||
FragmentLength = 15;
|
||||
StepLength = 10;
|
||||
}
|
||||
|
||||
protected override bool DetectStart(DetectableTelemetry[] telemetry, int position)
|
||||
{
|
||||
var firstItem = telemetry[position];
|
||||
var delta = firstItem.WellDepth - firstItem.BitDepth;
|
||||
if (delta is not null &&
|
||||
System.Math.Abs((float)delta) > 1d)
|
||||
return false;
|
||||
|
||||
var fragment = telemetry[position..(position + FragmentLength)];
|
||||
|
||||
const double minRop = 5; //м/час
|
||||
const double minRotorSpeed = 5; //об/мин
|
||||
const double ticksPerHour = 60 * 60 * 10_000_000d;
|
||||
|
||||
var lineBlockPosition = new InterpolationLine(fragment.Select(d => (d.BlockPosition ?? 0d, d.DateTime.Ticks / ticksPerHour)));
|
||||
if (!lineBlockPosition.IsYDecreases(minRop))
|
||||
return false;
|
||||
|
||||
var lineWellDepth = new InterpolationLine(fragment.Select(d => (d.WellDepth ?? 0d, d.DateTime.Ticks / ticksPerHour)));
|
||||
if (!lineWellDepth.IsYIncreases(minRop))
|
||||
return false;
|
||||
|
||||
var lineRotorSpeed = new InterpolationLine(fragment.Select(d => (d.RotorSpeed ?? 0d, d.DateTime.Ticks / ticksPerHour)));
|
||||
if (!lineRotorSpeed.IsAverageYLessThanBound(minRotorSpeed))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool DetectEnd(DetectableTelemetry[] telemetry, int position)
|
||||
=> !DetectStart(telemetry, position);
|
||||
|
||||
protected override void CalcValue(ref DetectedOperation result)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
using AsbCloudDb.Model;
|
||||
using System.Linq;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
{
|
||||
#nullable enable
|
||||
class DetectorDrillingSlide : DetectorAbstract
|
||||
{
|
||||
public DetectorDrillingSlide() : base(3)
|
||||
{
|
||||
FragmentLength = 10;
|
||||
}
|
||||
|
||||
protected override bool DetectStart(DetectableTelemetry[] telemetry, int position)
|
||||
{
|
||||
var firstItem = telemetry[position];
|
||||
var delta = firstItem.WellDepth - firstItem.BitDepth;
|
||||
if (delta is not null &&
|
||||
System.Math.Abs((float)delta) > 1d)
|
||||
return false;
|
||||
|
||||
var fragment = telemetry[position..(position + FragmentLength)];
|
||||
|
||||
const double minRop = 5; //м/час
|
||||
const double minRotorSpeed = 5; //об/мин
|
||||
const double ticksPerHour = 60 * 60 * 10_000_000d;
|
||||
|
||||
var lineBlockPosition = new InterpolationLine(fragment.Select(d => (d.BlockPosition ?? 0d, d.DateTime.Ticks / ticksPerHour)));
|
||||
if (!lineBlockPosition.IsYDecreases(minRop))
|
||||
return false;
|
||||
|
||||
var lineWellDepth = new InterpolationLine(fragment.Select(d => (d.WellDepth ?? 0d, d.DateTime.Ticks / ticksPerHour)));
|
||||
if (!lineWellDepth.IsYIncreases(minRop))
|
||||
return false;
|
||||
|
||||
var lineRotorSpeed = new InterpolationLine(fragment.Select(d => (d.RotorSpeed ?? 0d, d.DateTime.Ticks / ticksPerHour)));
|
||||
if (!lineRotorSpeed.IsAverageYMoreThanBound(minRotorSpeed))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool DetectEnd(DetectableTelemetry[] telemetry, int position)
|
||||
=> !DetectStart(telemetry, position);
|
||||
|
||||
protected override void CalcValue(ref DetectedOperation result)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
using AsbCloudDb.Model;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Промывка перед наращиванием
|
||||
/// </summary>
|
||||
internal class DetectorFlashing : DetectorAbstract
|
||||
{
|
||||
public DetectorFlashing()
|
||||
: base(20) { }
|
||||
|
||||
protected override double CalcValue(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
=> CalcDeltaMinutes(telemetry, begin, end);
|
||||
|
||||
protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
{
|
||||
if (!((previousOperation?.IdCategory == 2) ||
|
||||
(previousOperation?.IdCategory == 3)))
|
||||
return false;
|
||||
|
||||
var point0 = telemetry[position];
|
||||
var delta = point0.WellDepth - point0.BitDepth;
|
||||
if (delta > 0.05d)
|
||||
return false;
|
||||
|
||||
if (point0.Pressure < 15)
|
||||
return false;
|
||||
|
||||
if (point0.BlockPosition > 3)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
{
|
||||
var point0 = telemetry[position];
|
||||
var delta = point0.WellDepth - point0.BitDepth;
|
||||
if ((delta > 0.03d )
|
||||
&& (point0.Pressure > 15)
|
||||
&& ContainsDeviationApprox(telemetry, t=>t.BlockPosition, position, 60, 0.03))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool IsValid(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
=> IsValidByWellDepthDoesNotChange(telemetry, begin, end);
|
||||
}
|
||||
|
||||
#nullable disable
|
||||
}
|
||||
|
@ -0,0 +1,61 @@
|
||||
using AsbCloudDb.Model;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
{
|
||||
#nullable enable
|
||||
internal class DetectorRotor : DetectorAbstract
|
||||
{
|
||||
public DetectorRotor()
|
||||
: base(2) { }
|
||||
|
||||
protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
{
|
||||
var point0 = telemetry[position];
|
||||
var delta = point0.WellDepth - point0.BitDepth;
|
||||
if (delta > 0.03d)
|
||||
return false;
|
||||
|
||||
if (point0.Pressure < 25)
|
||||
return false;
|
||||
|
||||
if (point0.RotorSpeed < 5)
|
||||
return false;
|
||||
|
||||
var point1 = telemetry[position + 1];
|
||||
if (point1.WellDepth - point0.WellDepth <= 0.003)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
{
|
||||
var point0 = telemetry[position];
|
||||
var delta = point0.WellDepth - point0.BitDepth;
|
||||
if (delta > 0.03d)
|
||||
return true;
|
||||
|
||||
if (point0.Pressure < 25)
|
||||
return true;
|
||||
|
||||
var lineRotorSpeed = MakeInterpolationLine(d => d.RotorSpeed, telemetry, position, 10);
|
||||
|
||||
if (lineRotorSpeed.IsAverageYLessThan(5))
|
||||
return true;
|
||||
|
||||
if (!DeviatesFromBegin(telemetry, t => t.WellDepth, position, 60, 0.003))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool IsValid(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
=> IsValidByWellDepthIncreasing(telemetry, begin, end);
|
||||
|
||||
protected override double CalcValue(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
=> CalcRop(telemetry, begin, end);
|
||||
}
|
||||
|
||||
#nullable disable
|
||||
}
|
||||
|
@ -0,0 +1,61 @@
|
||||
using AsbCloudDb.Model;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
{
|
||||
#nullable enable
|
||||
internal class DetectorSlide : DetectorAbstract
|
||||
{
|
||||
public DetectorSlide()
|
||||
: base(3) { }
|
||||
|
||||
protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
{
|
||||
var point0 = telemetry[position];
|
||||
var delta = point0.WellDepth - point0.BitDepth;
|
||||
if (delta > 0.03d)
|
||||
return false;
|
||||
|
||||
if (point0.Pressure < 25)
|
||||
return false;
|
||||
|
||||
if (point0.RotorSpeed > 5)
|
||||
return false;
|
||||
|
||||
var point1 = telemetry[position + 1];
|
||||
if (point1.WellDepth - point0.WellDepth <= 0.003)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
{
|
||||
var point0 = telemetry[position];
|
||||
var delta = point0.WellDepth - point0.BitDepth;
|
||||
if (delta > 0.03d)
|
||||
return true;
|
||||
|
||||
if (point0.Pressure < 25)
|
||||
return true;
|
||||
|
||||
var lineRotorSpeed = MakeInterpolationLine(d => d.RotorSpeed, telemetry, position, 10);
|
||||
|
||||
if (lineRotorSpeed.IsAverageYGreaterThan(5))
|
||||
return true;
|
||||
|
||||
if (!DeviatesFromBegin(telemetry, t => t.WellDepth, position, 60, 0.003))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool IsValid(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
=> IsValidByWellDepthIncreasing(telemetry, begin, end);
|
||||
|
||||
protected override double CalcValue(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
=> CalcRop(telemetry, begin, end);
|
||||
}
|
||||
|
||||
#nullable disable
|
||||
}
|
||||
|
@ -3,41 +3,37 @@
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
{
|
||||
#nullable enable
|
||||
class DetectorSlipsTime : DetectorAbstract
|
||||
internal class DetectorSlipsTime : DetectorAbstract
|
||||
{
|
||||
public DetectorSlipsTime() : base(14) { }
|
||||
public double HookWeightSP { get; set; } = 20;
|
||||
public double PressureSP { get; set; } = 15;
|
||||
public double PosisionSP { get; set; } = 8;
|
||||
public double DeltaWellDepthMax { get; set; } = 2.5;
|
||||
public DetectorSlipsTime()
|
||||
: base(14) { }
|
||||
|
||||
protected override bool DetectStart(DetectableTelemetry[] telemetry, int position)
|
||||
protected override double CalcValue(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
=> CalcDeltaMinutes(telemetry, begin, end);
|
||||
|
||||
protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
{
|
||||
var item = telemetry[position];
|
||||
var point0 = telemetry[position];
|
||||
var delta = point0.WellDepth - point0.BitDepth;
|
||||
if (delta > 2.5d)
|
||||
return false;
|
||||
|
||||
var result =
|
||||
item.HookWeight < HookWeightSP &&
|
||||
item.Pressure < PressureSP &&
|
||||
item.BlockPosition < PosisionSP &&
|
||||
(item.WellDepth - item.BitDepth) < DeltaWellDepthMax;
|
||||
if (point0.Pressure > 15)
|
||||
return false;
|
||||
|
||||
return result;
|
||||
if (point0.BlockPosition > 8)
|
||||
return false;
|
||||
|
||||
if (point0.HookWeight > 20)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool DetectEnd(DetectableTelemetry[] telemetry, int position)
|
||||
{
|
||||
var item = telemetry[position];
|
||||
|
||||
var result = item.Pressure > PressureSP &&
|
||||
item.BlockPosition > PosisionSP;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected override void CalcValue(ref DetectedOperation result)
|
||||
{
|
||||
result.Value = result.DurationMinutes;
|
||||
}
|
||||
protected override bool IsValid(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
=> IsValidByWellDepthDoesNotChange(telemetry, begin, end);
|
||||
}
|
||||
|
||||
#nullable disable
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,70 @@
|
||||
using AsbCloudDb.Model;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
{
|
||||
#nullable enable
|
||||
|
||||
/// <summary>
|
||||
/// Статический замер телесистемы
|
||||
/// </summary>
|
||||
internal class DetectorStaticSurveying: DetectorAbstract
|
||||
{
|
||||
public DetectorStaticSurveying()
|
||||
: base(21) { }
|
||||
|
||||
protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
{
|
||||
var point0 = telemetry[position];
|
||||
|
||||
if (point0.Pressure < 15)
|
||||
return false;
|
||||
|
||||
var delta = point0.WellDepth - point0.BitDepth;
|
||||
if (delta > 2.5d)
|
||||
return false;
|
||||
|
||||
if (point0.RotorSpeed > 15)
|
||||
return false;
|
||||
|
||||
if (ContainsDeviation(telemetry, t => t.BlockPosition, position, 60, 0.03))
|
||||
return false;
|
||||
|
||||
if (ContainsDeviation(telemetry, t => t.Pressure, position, 60, 10))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
{
|
||||
var point0 = telemetry[position];
|
||||
|
||||
var delta = point0.WellDepth - point0.BitDepth;
|
||||
if (delta > 2.5d)
|
||||
return true;
|
||||
|
||||
if (point0.RotorSpeed > 15)
|
||||
return true;
|
||||
|
||||
if (RisesFromBegin(telemetry, t => t.Pressure, position, 10, 10))
|
||||
return true;
|
||||
|
||||
if (ContainsDeviation(telemetry, t => t.BlockPosition, position, 10, 0.03))
|
||||
return false;
|
||||
|
||||
//if (DeviatesFromBegin(telemetry, t => t.Pressure, position, 60, 10))
|
||||
// return false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool IsValid(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
=> IsValidByWellDepthDoesNotChange(telemetry, begin, end);
|
||||
|
||||
protected override double CalcValue(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
=> CalcDeltaMinutes(telemetry, begin, end);
|
||||
}
|
||||
|
||||
#nullable disable
|
||||
}
|
||||
|
@ -0,0 +1,65 @@
|
||||
using AsbCloudDb.Model;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
{
|
||||
#nullable enable
|
||||
internal class DetectorTemplating : DetectorAbstract
|
||||
{
|
||||
public DetectorTemplating()
|
||||
: base(19) { }
|
||||
|
||||
protected override double CalcValue(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
=> CalcDeltaMinutes(telemetry, begin, end);
|
||||
|
||||
protected override bool DetectBegin(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
{
|
||||
if(previousOperation?.IdCategory == 14)
|
||||
return false;
|
||||
|
||||
var point0 = telemetry[position];
|
||||
var delta = point0.WellDepth - point0.BitDepth;
|
||||
if (delta < 0.03d || delta > 30)
|
||||
return false;
|
||||
|
||||
if (point0.Pressure < 15)
|
||||
return false;
|
||||
|
||||
if (point0.BlockPosition > 2.5)
|
||||
return false;
|
||||
|
||||
if (point0.RotorSpeed > 10)
|
||||
return false;
|
||||
|
||||
if (!ContainsDeviationApprox(telemetry, d => d.BlockPosition, position, 60, 0.03))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool DetectEnd(DetectableTelemetry[] telemetry, int position, DetectedOperation? previousOperation)
|
||||
{
|
||||
var point0 = telemetry[position];
|
||||
var delta = point0.WellDepth - point0.BitDepth;
|
||||
if (delta < 0.03d || delta > 30)
|
||||
return true;
|
||||
|
||||
if (point0.Pressure < 15)
|
||||
return true;
|
||||
|
||||
if (point0.BlockPosition > 31)
|
||||
return true;
|
||||
|
||||
if (point0.RotorSpeed > 10)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override bool IsValid(DetectableTelemetry[] telemetry, int begin, int end)
|
||||
=> IsValidByWellDepthDoesNotChange(telemetry, begin, end);
|
||||
}
|
||||
|
||||
#nullable disable
|
||||
}
|
||||
|
@ -0,0 +1,11 @@
|
||||
using AsbCloudDb.Model;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors
|
||||
{
|
||||
class OperationDetectorResult
|
||||
{
|
||||
public int TelemetryBegin { get; set; }
|
||||
public int TelemetryEnd { get; set; }
|
||||
public DetectedOperation Operation { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
|
@ -46,10 +46,10 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||
public bool IsYDecreases(double bound = 0d) =>
|
||||
A < bound;
|
||||
|
||||
public bool IsAverageYLessThanBound(double bound) =>
|
||||
public bool IsAverageYLessThan(double bound) =>
|
||||
(ySum / count) < bound;
|
||||
|
||||
public bool IsAverageYMoreThanBound(double bound) =>
|
||||
public bool IsAverageYGreaterThan(double bound) =>
|
||||
(ySum / count) >= bound;
|
||||
}
|
||||
}
|
||||
|
@ -8,31 +8,29 @@ using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudInfrastructure.Services.DetectOperations.Detectors;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||
{
|
||||
#nullable enable
|
||||
public class OperationDetectionBackgroundService : BackgroundService
|
||||
{
|
||||
private readonly IEnumerable<DetectorAbstract> detectors = new List<DetectorAbstract>
|
||||
{
|
||||
new Detectors.DetectorSlipsTime(),
|
||||
// new Detectors.DetectorDrillingRotor(),
|
||||
// new Detectors.DetectorDrillingSlide(),
|
||||
};
|
||||
|
||||
private readonly int minStepLength;
|
||||
private readonly int minFragmentLength;
|
||||
private readonly string connectionString;
|
||||
private readonly TimeSpan period = TimeSpan.FromHours(1);
|
||||
|
||||
private static readonly DetectorAbstract[] detectors = new DetectorAbstract[]
|
||||
{
|
||||
new DetectorRotor(),
|
||||
new DetectorSlide(),
|
||||
new DetectorDevelopment(),
|
||||
new DetectorTemplating(),
|
||||
new DetectorSlipsTime(),
|
||||
//new DetectorStaticSurveying(),
|
||||
new DetectorFlashing(),
|
||||
};
|
||||
|
||||
public OperationDetectionBackgroundService(IConfiguration configuration)
|
||||
{
|
||||
minStepLength = detectors.Min(d => d.StepLength);
|
||||
minStepLength = minStepLength > 0 ? minStepLength : 3;
|
||||
|
||||
minFragmentLength = detectors.Min(d => d.FragmentLength);
|
||||
minFragmentLength = minFragmentLength > 0 ? minFragmentLength : 6;
|
||||
|
||||
connectionString = configuration.GetConnectionString("DefaultConnection");
|
||||
}
|
||||
|
||||
@ -72,7 +70,7 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||
await base.StopAsync(token).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task<int> DetectedAllTelemetriesAsync(IAsbCloudDbContext db, CancellationToken token)
|
||||
private static async Task<int> DetectedAllTelemetriesAsync(IAsbCloudDbContext db, CancellationToken token)
|
||||
{
|
||||
var lastDetectedDates = await db.DetectedOperations
|
||||
.GroupBy(o => o.IdTelemetry)
|
||||
@ -95,12 +93,14 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||
(outer, inner) => new
|
||||
{
|
||||
IdTelemetry = outer,
|
||||
LastDate = inner.SingleOrDefault()?.LastDate,
|
||||
inner.SingleOrDefault()?.LastDate,
|
||||
});
|
||||
var affected = 0;
|
||||
foreach (var item in JounedlastDetectedDates)
|
||||
{
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
var newOperations = await DetectOperationsAsync(item.IdTelemetry, item.LastDate ?? DateTimeOffset.MinValue, db, token);
|
||||
stopwatch.Stop();
|
||||
if (newOperations.Any())
|
||||
{
|
||||
db.DetectedOperations.AddRange(newOperations);
|
||||
@ -110,7 +110,7 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||
return affected;
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<DetectedOperation>> DetectOperationsAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
|
||||
private static async Task<IEnumerable<DetectedOperation>> DetectOperationsAsync(int idTelemetry, DateTimeOffset begin, IAsbCloudDbContext db, CancellationToken token)
|
||||
{
|
||||
var query = db.TelemetryDataSaub
|
||||
.AsNoTracking()
|
||||
@ -119,83 +119,60 @@ namespace AsbCloudInfrastructure.Services.DetectOperations
|
||||
{
|
||||
DateTime = d.DateTime,
|
||||
IdUser = d.IdUser,
|
||||
WellDepth = d.WellDepth,
|
||||
Pressure = d.Pressure,
|
||||
HookWeight = d.HookWeight,
|
||||
BlockPosition = d.BlockPosition,
|
||||
BitDepth = d.BitDepth,
|
||||
RotorSpeed = d.RotorSpeed,
|
||||
WellDepth = d.WellDepth ?? float.NaN,
|
||||
Pressure = d.Pressure ?? float.NaN,
|
||||
HookWeight = d.HookWeight ?? float.NaN,
|
||||
BlockPosition = d.BlockPosition ?? float.NaN,
|
||||
BitDepth = d.BitDepth ?? float.NaN,
|
||||
RotorSpeed = d.RotorSpeed ?? float.NaN,
|
||||
})
|
||||
.OrderBy(d => d.DateTime);
|
||||
|
||||
var take = 4 * 86_400;
|
||||
var take = 4 * 86_400; // 4 дня
|
||||
var startDate = begin;
|
||||
var detectedOperations = new List<DetectedOperation>(8);
|
||||
|
||||
var dbRequests_ = 0;
|
||||
var dbTime_ = 0d;
|
||||
var sw_ = new Stopwatch();
|
||||
var otherTime_ = 0d;
|
||||
DetectedOperation? lastDetectedOperation = null;
|
||||
const int minOperationLength = 5;
|
||||
const int maxDetectorsInterpolationFrameLength = 30;
|
||||
const int gap = maxDetectorsInterpolationFrameLength + minOperationLength;
|
||||
|
||||
while (true)
|
||||
{
|
||||
sw_.Restart();
|
||||
var data = await query
|
||||
.Where(d => d.DateTime > startDate)
|
||||
.Take(take)
|
||||
.ToArrayAsync(token);
|
||||
|
||||
sw_.Stop();
|
||||
dbTime_ += sw_.ElapsedMilliseconds;
|
||||
dbRequests_++;
|
||||
sw_.Restart();
|
||||
|
||||
if (data.Length < minFragmentLength)
|
||||
if (data.Length < gap)
|
||||
break;
|
||||
|
||||
var skip = 0;
|
||||
|
||||
var isDetected = false;
|
||||
|
||||
while (data.Length > skip + minFragmentLength)
|
||||
var positionBegin = 0;
|
||||
var positionEnd = data.Length - gap;
|
||||
while (positionEnd > positionBegin)
|
||||
{
|
||||
var isDetected1 = false;
|
||||
|
||||
foreach (var detector in detectors)
|
||||
for (int i = 0; i < detectors.Length; i++)
|
||||
{
|
||||
if (data.Length < skip + detector.StepLength + detector.FragmentLength)
|
||||
continue;
|
||||
|
||||
var detectedOperation = detector.DetectOrDefault(data, ref skip);
|
||||
if (detectedOperation is not null)
|
||||
if (detectors[i].TryDetect(idTelemetry, data, positionBegin, positionEnd, lastDetectedOperation, out OperationDetectorResult? result))
|
||||
{
|
||||
isDetected1 = true;
|
||||
detectedOperations.Add(result!.Operation);
|
||||
lastDetectedOperation = result.Operation;
|
||||
isDetected = true;
|
||||
detectedOperation.IdTelemetry = idTelemetry;
|
||||
detectedOperations.Add(detectedOperation);
|
||||
startDate = detectedOperation.DateEnd;
|
||||
positionBegin = result.TelemetryEnd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isDetected1)
|
||||
skip += minStepLength;
|
||||
positionBegin++;
|
||||
}
|
||||
|
||||
sw_.Stop();
|
||||
otherTime_ += sw_.ElapsedMilliseconds;
|
||||
|
||||
if (!isDetected)
|
||||
{
|
||||
if (data.Length < take)
|
||||
break;
|
||||
|
||||
var lastPartDate = data.Last().DateTime;
|
||||
startDate = startDate + (0.75 * (lastPartDate - startDate));
|
||||
}
|
||||
if (isDetected)
|
||||
startDate = lastDetectedOperation!.DateEnd;
|
||||
else
|
||||
startDate = data[positionEnd].DateTime;
|
||||
}
|
||||
|
||||
return detectedOperations;
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
# Алгоритм определения бурения в роторе
|
||||
## Описание
|
||||
|
||||
## Метод определения бурения в роторе
|
||||
|
||||
Признак начала операции =
|
||||
( расстояние от долота до забоя < 0.03м ) И
|
||||
( давление > 25атм ) И
|
||||
( глубина забоя за следующую секунду больше текущей на 0.003м ) И
|
||||
( обороты ротора > 5 об/м );
|
||||
|
||||
Признак окончания операции =
|
||||
( расстояние от долота до забоя > 0.03м ) ИЛИ
|
||||
( давление < 25атм ) ИЛИ
|
||||
( среднее арифметическое оборотов ротора за 10 сек < 5 об/м ) ИЛИ
|
||||
( глубина забоя в течении следующих 60 сек не изменяется больше чем на 0.003 );
|
||||
|
||||
## Метод определения бурения в слайде
|
||||
Повторяет метод определения бурения в роторе, за исключением условия с оборотами ротора. Это уловие нужно инвертировать.
|
||||
|
||||
## Ключевой параметр
|
||||
МСП = разность глубины забоя на конец и начало операции / продолжительность операции.
|
@ -1,44 +0,0 @@
|
||||
> Из писма Гранова А.П. от 19.04.2022 13:29 "Алгоритм определения наращивания БИ.docx"
|
||||
|
||||
# Алгоритм определения времени в клиньях
|
||||
|
||||
## Описание:
|
||||
Наращивание бурильного инструмента – операция, во время которой после добуривания очередной трубы/ свечи
|
||||
циркуляция выключается, инструмент разгружается в клиньях (остается только вес крюкоблока и ВСП),
|
||||
происходит развинчивание трубы от верхнего силового привода, берется очередная труба/ свеча,
|
||||
свинчивается с инструментом в клиньях, свинчивается с верхним силовым приводом, происходит подъем инструмента,
|
||||
вес на крюке увеличивается. Далее включается циркуляция и происходит механическое бурение.
|
||||
|
||||
Наращиванию предшествует механическое бурение (наличие давления, увеличение глубины забоя) и
|
||||
после наращивания механическое бурение возобновляется (наличие давления, Увеличение глубины забоя).
|
||||
|
||||
> Это не учитывать в методе, так как предыдущая и последующая операция могут быть определены не корректно.
|
||||
|
||||
Наращивается определяется как время между:
|
||||
- разгрузкой инструмента на клинья (остается только вес крюкоблока и ВСП).
|
||||
При этом давление менее 15 атм. В случае давления более 15 атм считать началом операции как
|
||||
снижение давления менее 15 атм и началом движения талевого блока вверх.
|
||||
- снятие инструмента с клиньев (вес увеличивается более, чем на 1т).
|
||||
- При этом движение талевого блока происходит вверх.
|
||||
|
||||
## Метод определения:
|
||||
|
||||
> Исправлено на совещании от 19.04.2022 16:50
|
||||
|
||||
> Исправлено задачей в кайтен от 12.05.2022 16:49
|
||||
|
||||
считать время в клиньях только при соотношении глубина забоя - глубина долота меньше 2,5 метра
|
||||
|
||||
```
|
||||
Признак начала операции =
|
||||
(параметр «вес на крюке» < 22 тонн) И
|
||||
(давление < 15 атм) И
|
||||
(положение талевого блока < 8) И
|
||||
(глубина забоя - глубина долота < 2,5)
|
||||
|
||||
|
||||
Признак окончания операции =
|
||||
(вес на крюке > 22 ) И
|
||||
(давление > 15 атм)
|
||||
```
|
||||
|
@ -0,0 +1,26 @@
|
||||
# Алгоритм определения промывки перед проработкой/ шаблонировкой перед наращиванием
|
||||
|
||||
## Описание
|
||||
|
||||
Промывка перед проработкой/ шаблонировкой перед наращиванием – операция, во время которой после добуривания очередной трубы происходит снижение осевой нагрузки и дифференциального давления, талевый блок остается условно неподвижным.
|
||||
|
||||
Проработка перед наращиванием определяется как время между:
|
||||
- окончанием операции бурения (ротор/ слайд/ ручное бурение)
|
||||
- началом операции проработки/ шаблонировки перед наращивании
|
||||
|
||||
## Метод определения
|
||||
|
||||
Признак начала операции =
|
||||
( предыдущая операция == бурение в роторе или слайде)
|
||||
( расстояние от долота до забоя < 0,05м ) И
|
||||
( давление > 15 атм ) И
|
||||
( положение блока < 3м )
|
||||
|
||||
Признак окончания операции =
|
||||
( расстояние от долота до забоя > 0.03м ) И
|
||||
( давление > 15 атм ) И
|
||||
( высота блока изменяется больше чем на 0.03м в течении 60 сек с начала операции);
|
||||
|
||||
|
||||
## Ключевой параметр
|
||||
Продолжительность операции.
|
@ -0,0 +1,31 @@
|
||||
# Алгоритм определения шаблонировки перед наращиванием
|
||||
## Описание
|
||||
|
||||
Проработка перед наращиванием бурильного инструмента – операция, во время которой после добуривания очередной трубы/ свечи начинается подъем и спуск бурильного инструмента с вращением. Следующей операцией после проработки будет либо шаблонировка (аналогично проработке, но без вращения), либо разгрузка инструмента в клинья (снижение веса на крюке) - наращивание
|
||||
|
||||
Проработка перед наращиванием определяется как время между:
|
||||
- начало подъема/ спуска бурильного инструмента с вращением
|
||||
- разгрузкой инструмента на клинья (остается только вес крюкоблока и ВСП). При этом давление менее 15 атм. ЛИБО
|
||||
- начало подъема/ спуска бурильного инструмента БЕЗ вращения
|
||||
- считать время на проработку только при соотношении глубина забоя - глубина долота не больше меньше 30 метров
|
||||
|
||||
## Метод определения
|
||||
|
||||
Признак начала операции =
|
||||
( предыдущая операция НЕ удержание в клиньях) И
|
||||
( расстояние от долота до забоя > 0.03м ) И
|
||||
( расстояние от долота до забоя < 30м ) И
|
||||
( давление > 15 атм ) И
|
||||
( положение блока < 2.5м ) И
|
||||
( обороты ротора > 10 об/м ) И
|
||||
( высота блока изменяется больше чем на 0.03м в течении 60 сек с начала операции);
|
||||
|
||||
Признак окончания операции =
|
||||
( расстояние от долота до забоя < 0.03м ) ИЛИ
|
||||
( расстояние от долота до забоя < 30м ) ИЛИ
|
||||
( давление < 15 атм ) ИЛИ
|
||||
( положение блока > 31м ) ИЛИ
|
||||
( обороты ротора < 10 об/м );
|
||||
|
||||
## Ключевой параметр
|
||||
Продолжительность операции.
|
@ -0,0 +1,21 @@
|
||||
# Статический замер телесистемы
|
||||
Статический замер телесистемы перед бурением - операция после удержания в клиньях и наращивания очередной трубы/ свечи.
|
||||
Замер ТС (статический замер) при бурении свечами (промежуточный замер) - операция при добуривании одной трубки, без наращивании и удержания в клиньях.
|
||||
|
||||
## метод определения 1
|
||||
|
||||
Признак начала операции =
|
||||
( давление > 15 атм ) И
|
||||
( расстояние от долота до забоя < 2.5м ) И
|
||||
( обороты ротора < 15 об/м ) И
|
||||
( движение тал.блока в течении 60 сек изменяется менее чем на 3 см ) И
|
||||
( давление за следующие 60 сек изменяется менее чем на 10 атм )
|
||||
|
||||
Признак окончания операции =
|
||||
( расстояние от долота до забоя > 2.5м ) ИЛИ
|
||||
( обороты ротора > 15 об/м ) ИЛИ
|
||||
( давление за следующие 10 сек вырастет на 10 атм ) ИЛИ
|
||||
( движение тал.блока в течении 60 сек изменяется более чем на 3 см )
|
||||
|
||||
## Ключевой параметр
|
||||
Продолжительность операции.
|
@ -0,0 +1,21 @@
|
||||
# Алгоритм определения времени в клиньях
|
||||
## Описание
|
||||
|
||||
Наращивание бурильного инструмента – операция, во время которой после добуривания очередной трубы/ свечи циркуляция выключается, инструмент разгружается в клиньях (остается только вес крюкоблока и ВСП), происходит развинчивание трубы от верхнего силового привода, берется очередная труба/ свеча, свинчивается с инструментом в клиньях, свинчивается с верхним силовым приводом, происходит подъем инструмента, вес на крюке увеличивается. Далее включается циркуляция и происходит механическое бурение.
|
||||
|
||||
Наращивается определяется как время между:
|
||||
- разгрузкой инструмента на клинья (остается только вес крюкоблока и ВСП). При этом давление менее 15 атм. В случае давления более 15 атм считать началом операции как снижение давления менее 15 атм и началом движения талевого блока вверх.
|
||||
- снятие инструмента с клиньев (вес увеличивается более, чем на 1т). При этом движение талевого блока происходит вверх.
|
||||
|
||||
## Метод определения
|
||||
|
||||
Признак начала операции =
|
||||
( расстояние от долота до забоя < 2.5м ) И
|
||||
( положение талевого блока < 8 ) И
|
||||
( вес на крюке < 20 тонн ) И
|
||||
( давление < 15 атм );
|
||||
|
||||
Признак окончания операции = НЕ выполняется признак начала операции;
|
||||
|
||||
## Ключевой параметр
|
||||
Продолжительность операции.
|
@ -0,0 +1,31 @@
|
||||
# Алгоритм определения шаблонировки перед наращиванием
|
||||
## Описание
|
||||
|
||||
Шаблонировкаперед наращиванием бурильного инструмента – операция, во время которой после добуривания очередной трубы/ свечи начинается подъем и спуск бурильного инструмента БЕЗ вращения. Следующей операцией после шаблонировки будет либо проработка (аналогично шаблонировке, но С вращением), либо разгрузка инструмента в клинья (снижение веса на крюке) - наращивание
|
||||
|
||||
Шаблонировка перед наращиванием определяется как время между:
|
||||
- начало подъема/ спуска бурильного инструмента БЕЗ вращения
|
||||
- разгрузкой инструмента на клинья (остается только вес крюкоблока и ВСП). При этом давление менее 15 атм. ЛИБО
|
||||
- начало подъема/ спуска бурильного инструмента БЕЗ вращения
|
||||
- считать время на шаблонировку только при соотношении глубина забоя - глубина долота не больше меньше 30 метров
|
||||
|
||||
## Метод определения
|
||||
|
||||
Признак начала операции =
|
||||
( предыдущая операция НЕ удержание в клиньях) И
|
||||
( расстояние от долота до забоя > 0.03м ) И
|
||||
( расстояние от долота до забоя < 30м ) И
|
||||
( давление > 15 атм ) И
|
||||
( положение блока < 2.5м ) И
|
||||
( обороты ротора < 10 об/м ) И
|
||||
( высота блока изменяется больше чем на 0.03м в течении 60 сек с начала операции);
|
||||
|
||||
Признак окончания операции =
|
||||
( расстояние от долота до забоя < 0.03м ) ИЛИ
|
||||
( расстояние от долота до забоя < 30м ) ИЛИ
|
||||
( давление < 15 атм ) ИЛИ
|
||||
( положение блока > 31м ) ИЛИ
|
||||
( обороты ротора > 10 об/м );
|
||||
|
||||
## Ключевой параметр
|
||||
Продолжительность операции.
|
@ -1,6 +1,7 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.Repository;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.Repository;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Collections.Generic;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.Repository;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services
|
||||
{
|
||||
|
@ -0,0 +1,41 @@
|
||||
using AsbCloudApp.Data;
|
||||
using ClosedXML.Excel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
{
|
||||
#nullable enable
|
||||
public class ContentListSheet
|
||||
{
|
||||
private readonly List<DrillingProgramPartDto> parts;
|
||||
|
||||
public ContentListSheet(IEnumerable<DrillingProgramPartDto> parts)
|
||||
{
|
||||
this.parts = parts.ToList();
|
||||
}
|
||||
|
||||
public void Draw(IXLWorksheet sheet)
|
||||
{
|
||||
sheet.Style.Font.FontName = "Calibri";
|
||||
sheet.Style.Font.FontSize = 12;
|
||||
|
||||
sheet.Cell(2, 2)
|
||||
.SetValue("Содержание")
|
||||
.Style
|
||||
.Font.SetBold(true)
|
||||
.Font.SetFontSize(14);
|
||||
|
||||
for (int i = 0; i < parts.Count; i++)
|
||||
{
|
||||
sheet.Cell(4 + i, 1)
|
||||
.SetValue(i + 1);
|
||||
|
||||
sheet.Cell(4 + i, 2)
|
||||
.SetValue(parts[i].Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
}
|
@ -10,9 +10,18 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
{
|
||||
private const int maxAllowedColumns = 256;
|
||||
|
||||
public static void UniteExcelFiles(IEnumerable<string> excelFilesNames, string resultExcelPath)
|
||||
public static void UniteExcelFiles(IEnumerable<string> excelFilesNames, string resultExcelPath, IEnumerable<AsbCloudApp.Data.DrillingProgramPartDto> parts, AsbCloudApp.Data.WellDto well)
|
||||
{
|
||||
var resultExcelFile = new XLWorkbook(XLEventTracking.Disabled);
|
||||
|
||||
var titleSheet = resultExcelFile.AddWorksheet("Титульный лист");
|
||||
var marks = parts.SelectMany(p => p.File.FileMarks);
|
||||
var titleSheetMaker = new TitleListSheet(marks, well);
|
||||
titleSheetMaker.Draw(titleSheet);
|
||||
|
||||
var contentSheet = resultExcelFile.AddWorksheet("Содержание");
|
||||
var contentListSheetMaker = new ContentListSheet(parts);
|
||||
contentListSheetMaker.Draw(contentSheet);
|
||||
|
||||
var filteredFileNames = excelFilesNames.Distinct();
|
||||
|
||||
|
@ -109,6 +109,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
var partEntities = await context.DrillingProgramParts
|
||||
.Include(p => p.RelatedUsers)
|
||||
.ThenInclude(r => r.User)
|
||||
.ThenInclude(u => u.Company)
|
||||
.Where(p => p.IdWell == idWell)
|
||||
.ToListAsync(token);
|
||||
|
||||
@ -224,7 +225,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
|
||||
public async Task<int> AddUserAsync(int idWell, int idFileCategory, int idUser, int idUserRole, CancellationToken token = default)
|
||||
{
|
||||
var user = await userService.GetAsync(idUser, token);
|
||||
var user = await userService.GetOrDefaultAsync(idUser, token);
|
||||
if (user is null)
|
||||
throw new ArgumentInvalidException($"User id == {idUser} does not exist", nameof(idUser));
|
||||
|
||||
@ -356,7 +357,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
private async Task NotifyPublisherOnFullAccepAsync(FileMarkDto fileMark, CancellationToken token)
|
||||
{
|
||||
var file = await fileService.GetInfoAsync(fileMark.IdFile, token);
|
||||
var well = await wellService.GetAsync(file.IdWell, token);
|
||||
var well = await wellService.GetOrDefaultAsync(file.IdWell, token);
|
||||
var user = file.Author;
|
||||
var factory = new MailBodyFactory(configuration);
|
||||
var subject = MailBodyFactory.MakeSubject(well, "Загруженный вами документ полностью согласован");
|
||||
@ -368,7 +369,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
private async Task NotifyPublisherOnRejectAsync(FileMarkDto fileMark, CancellationToken token)
|
||||
{
|
||||
var file = await fileService.GetInfoAsync(fileMark.IdFile, token);
|
||||
var well = await wellService.GetAsync(file.IdWell, token);
|
||||
var well = await wellService.GetOrDefaultAsync(file.IdWell, token);
|
||||
var user = file.Author;
|
||||
var factory = new MailBodyFactory(configuration);
|
||||
var subject = MailBodyFactory.MakeSubject(well, "Загруженный вами документ отклонен");
|
||||
@ -379,7 +380,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
|
||||
private async Task NotifyApproversAsync(DrillingProgramPart part, int idFile, string fileName, CancellationToken token)
|
||||
{
|
||||
var well = await wellService.GetAsync(part.IdWell, token);
|
||||
var well = await wellService.GetOrDefaultAsync(part.IdWell, token);
|
||||
var factory = new MailBodyFactory(configuration);
|
||||
var subject = MailBodyFactory.MakeSubject(well, "Загружен новый документ для согласования.");
|
||||
var users = part.RelatedUsers
|
||||
@ -395,7 +396,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
|
||||
private async Task NotifyNewPublisherAsync(int idWell, UserDto user, string documentCategory, CancellationToken token)
|
||||
{
|
||||
var well = await wellService.GetAsync(idWell, token);
|
||||
var well = await wellService.GetOrDefaultAsync(idWell, token);
|
||||
var factory = new MailBodyFactory(configuration);
|
||||
var subject = MailBodyFactory.MakeSubject(well, $"От вас ожидается загрузка на портал документа «{documentCategory}»");
|
||||
var body = factory.MakeMailBodyForNewPublisher(well, user.Name, documentCategory);
|
||||
@ -469,7 +470,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
var workId = MakeWorkId(idWell);
|
||||
if (!backgroundWorker.Contains(workId))
|
||||
{
|
||||
var well = await wellService.GetAsync(idWell, token);
|
||||
var well = await wellService.GetOrDefaultAsync(idWell, token);
|
||||
var resultFileName = $"Программа бурения {well.Cluster} {well.Caption}.xlsx";
|
||||
var tempResultFilePath = Path.Combine(Path.GetTempPath(), "drillingProgram", resultFileName);
|
||||
var mailService = new EmailService(backgroundWorker, configuration);
|
||||
@ -481,7 +482,7 @@ namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
using var context = new AsbCloudDbContext(contextOptions);
|
||||
var fileService = new FileService(context);
|
||||
var files = state.Parts.Select(p => fileService.GetUrl(p.File));
|
||||
DrillingProgramMaker.UniteExcelFiles(files, tempResultFilePath);
|
||||
DrillingProgramMaker.UniteExcelFiles(files, tempResultFilePath, state.Parts, well);
|
||||
await fileService.MoveAsync(idWell, null, idFileCategoryDrillingProgram, resultFileName, tempResultFilePath, token);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,160 @@
|
||||
using AsbCloudApp.Data;
|
||||
using ClosedXML.Excel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.DrillingProgram
|
||||
{
|
||||
#nullable enable
|
||||
public class TitleListSheet
|
||||
{
|
||||
private const string directionDirectorPositionName = "Руководитель направления по ТСБ";
|
||||
|
||||
private readonly DateTime totalDate;
|
||||
private readonly FileMarkDto? acceptDirectionDirector;
|
||||
private readonly List<FileMarkDto> acceptsOthers;
|
||||
private readonly WellDto well;
|
||||
|
||||
public TitleListSheet(IEnumerable<FileMarkDto> fileMarks, WellDto well)
|
||||
{
|
||||
totalDate = fileMarks.Max(f => f.DateCreated);
|
||||
acceptDirectionDirector = fileMarks
|
||||
.OrderByDescending(f => f.DateCreated)
|
||||
.FirstOrDefault(f => f.User.Position == directionDirectorPositionName);
|
||||
acceptsOthers = fileMarks
|
||||
.Where(f => f.Id != acceptDirectionDirector?.Id)
|
||||
.OrderBy(f => f.DateCreated)
|
||||
.ToList();
|
||||
this.well = well;
|
||||
}
|
||||
|
||||
public void Draw(IXLWorksheet sheet)
|
||||
{
|
||||
const double santimetr = 0.393701;
|
||||
sheet.Style.Font.FontName = "Calibri";
|
||||
sheet.Style.Font.FontSize = 12;
|
||||
sheet.PageSetup.PaperSize = XLPaperSize.A4Paper;
|
||||
sheet.PageSetup.Margins
|
||||
.SetTop(santimetr)
|
||||
.SetLeft(2 * santimetr)
|
||||
.SetBottom(santimetr)
|
||||
.SetRight(santimetr);
|
||||
|
||||
DrawTopRightSign(sheet);
|
||||
DrawMainTilte(sheet);
|
||||
DrawOtherAcceptors(sheet);
|
||||
|
||||
sheet.Range(51, 1, 51, 5)
|
||||
.Merge()
|
||||
.SetValue($"{totalDate.Year:00}")
|
||||
.Style.Alignment.SetHorizontal(XLAlignmentHorizontalValues.Center);
|
||||
|
||||
var k = 4.95867768595041;
|
||||
sheet.Column(1).Width = k*2.3;
|
||||
sheet.Column(2).Width = k*6;
|
||||
sheet.Column(3).Width = k*0.53;
|
||||
sheet.Column(4).Width = k*2.3;
|
||||
sheet.Column(5).Width = k*6;
|
||||
}
|
||||
|
||||
private void DrawTopRightSign(IXLWorksheet sheet)
|
||||
{
|
||||
if (acceptDirectionDirector is null)
|
||||
return;
|
||||
|
||||
var user = acceptDirectionDirector.User;
|
||||
|
||||
sheet.Cell(1, 5)
|
||||
.SetValue("Согласовано:");
|
||||
|
||||
sheet.Cell(2, 5)
|
||||
.SetValue(user.Position);
|
||||
|
||||
sheet.Cell(3, 5)
|
||||
.SetValue(user.Company?.Caption);
|
||||
|
||||
sheet.Cell(4, 5)
|
||||
.SetValue($"{user.Surname} {user.Name} {user.Patronymic}");
|
||||
|
||||
sheet.Cell(5, 5)
|
||||
.SetValue(FormatDate(acceptDirectionDirector.DateCreated));
|
||||
|
||||
sheet.Range(1,5, 5,5).Style.Alignment
|
||||
.SetHorizontal(XLAlignmentHorizontalValues.Right);
|
||||
}
|
||||
|
||||
private void DrawMainTilte(IXLWorksheet sheet)
|
||||
{
|
||||
sheet.Range(11, 1, 11, 5)
|
||||
.Merge()
|
||||
.SetValue($"Программа на бурение скважины №{well.Caption}, куст №{well.Cluster}");
|
||||
|
||||
sheet.Range(12, 1, 12, 5)
|
||||
.Merge()
|
||||
.SetValue($"{well.Deposit} месторождения");
|
||||
|
||||
sheet.Range(11, 1, 12, 5).Style
|
||||
.Alignment.SetHorizontal(XLAlignmentHorizontalValues.Center)
|
||||
.Font.SetFontSize(14)
|
||||
.Font.SetBold(true);
|
||||
}
|
||||
|
||||
private void DrawOtherAcceptors(IXLWorksheet sheet)
|
||||
{
|
||||
const int baseRow = 16;
|
||||
const int deltaRow = 7;
|
||||
(int row, int col)[] addresses =
|
||||
{
|
||||
(baseRow + 4 * deltaRow, 4), (baseRow + 4 * deltaRow, 1),
|
||||
(baseRow + 3 * deltaRow, 4), (baseRow + 3 * deltaRow, 1),
|
||||
(baseRow + 2 * deltaRow, 4), (baseRow + 2 * deltaRow, 1),
|
||||
(baseRow + 1 * deltaRow, 4), (baseRow + 1 * deltaRow, 1),
|
||||
(baseRow + 0 * deltaRow, 4), (baseRow + 0 * deltaRow, 1),
|
||||
};
|
||||
var i = 0;
|
||||
for (; i < acceptsOthers.Count && i < 10; i++)
|
||||
DrawAccept(sheet, acceptsOthers[i], addresses[i]);
|
||||
|
||||
sheet.Cell(addresses[i-1].row - 2, 1)
|
||||
.SetValue("Утверждаю:");
|
||||
}
|
||||
|
||||
private void DrawAccept(IXLWorksheet sheet, FileMarkDto mark, (int row, int col) startAddress)
|
||||
{
|
||||
int startRow = startAddress.row;
|
||||
int startCol = startAddress.col;
|
||||
var user = mark.User;
|
||||
sheet.Cell(startRow, startCol)
|
||||
.SetValue("Должность");
|
||||
|
||||
sheet.Range(startRow, startCol + 1, startRow + 1, startCol + 1)
|
||||
.Merge()
|
||||
.SetValue(user.Position);
|
||||
|
||||
sheet.Cell(startRow + 2, startCol)
|
||||
.SetValue("Компания");
|
||||
|
||||
sheet.Range(startRow + 2, startCol + 1, startRow + 3, startCol + 1)
|
||||
.Merge()
|
||||
.SetValue(user.Company?.Caption);
|
||||
|
||||
sheet.Range(startRow + 4, startCol, startRow + 4, startCol + 1)
|
||||
.Merge()
|
||||
.SetValue($"{user.Surname} {user.Name} {user.Patronymic}");
|
||||
|
||||
sheet.Range(startRow + 5, startCol, startRow + 5, startCol + 1)
|
||||
.Merge()
|
||||
.SetValue(FormatDate(mark.DateCreated));
|
||||
|
||||
sheet.Range(startRow, startCol, startRow + 5, startCol + 1)
|
||||
.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thin)
|
||||
.Alignment.SetVertical(XLAlignmentVerticalValues.Top)
|
||||
.Alignment.SetHorizontal(XLAlignmentHorizontalValues.Left);
|
||||
}
|
||||
|
||||
private static string FormatDate(DateTime dateTime)
|
||||
=> $"{dateTime.Day:00}.{dateTime.Month:00}.{dateTime.Year:00}";
|
||||
}
|
||||
#nullable disable
|
||||
}
|
Binary file not shown.
@ -1,6 +1,7 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.Repository;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
using AsbCloudApp.Data.SAUB;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.Repository;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -26,14 +27,12 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
||||
//{ "", new SetpointInfoDto { Name = "", DisplayName = "Обороты ВСП, об/мин" } }, // Оно в ПЛК спинмастера, пока сделать нельзя, позднее можно.
|
||||
//{ "", new SetpointInfoDto { Name = "", DisplayName = "Расход промывочной жидкости, л/с" } }, // Нет в контроллере
|
||||
};
|
||||
private readonly IAsbCloudDbContext db;
|
||||
private readonly SetpointsRequestRepository setpointsRepository;
|
||||
private readonly ITelemetryService telemetryService;
|
||||
private readonly CrudCacheServiceBase<SetpointsRequestDto, SetpointsRequest> setpointsRepository;
|
||||
|
||||
public SetpointsService(IAsbCloudDbContext db, ITelemetryService telemetryService)
|
||||
public SetpointsService(IAsbCloudDbContext db, ITelemetryService telemetryService, IWellService wellService)
|
||||
{
|
||||
setpointsRepository = new CrudCacheServiceBase<SetpointsRequestDto, SetpointsRequest>(db, q => q.Include(s => s.Author).Include(s => s.Well));
|
||||
this.db = db;
|
||||
setpointsRepository = new SetpointsRequestRepository(db, wellService);
|
||||
this.telemetryService = telemetryService;
|
||||
}
|
||||
|
||||
@ -62,25 +61,38 @@ namespace AsbCloudInfrastructure.Services.SAUB
|
||||
var filtered = all.Where(s =>
|
||||
s.IdWell == idWell &&
|
||||
s.IdState == 1 &&
|
||||
s.UploadDate.AddSeconds(s.ObsolescenceSec) > DateTime.Now);
|
||||
s.UploadDate.AddSeconds(s.ObsolescenceSec) > DateTime.UtcNow)
|
||||
.ToList();
|
||||
|
||||
if (!filtered.Any())
|
||||
return null;
|
||||
|
||||
foreach (var entity in filtered)
|
||||
entity.IdState = 2;
|
||||
foreach (var item in filtered)
|
||||
{
|
||||
item.IdState = 2;
|
||||
item.UploadDate = DateTime.SpecifyKind(item.UploadDate, DateTimeKind.Utc);
|
||||
}
|
||||
|
||||
await setpointsRepository.UpdateRangeAsync(filtered, token);
|
||||
|
||||
return filtered;
|
||||
}
|
||||
|
||||
public async Task<int> UpdateStateAsync(int id, SetpointsRequestDto setpointsRequestDto, CancellationToken token)
|
||||
public async Task<int> UpdateStateAsync(SetpointsRequestDto setpointsRequestDto, CancellationToken token)
|
||||
{
|
||||
if (setpointsRequestDto.IdState != 3 && setpointsRequestDto.IdState != 4)
|
||||
throw new ArgumentOutOfRangeException(nameof(setpointsRequestDto), $"{nameof(setpointsRequestDto.IdState)} = {setpointsRequestDto.IdState}. Mast be 3 or 4.");
|
||||
|
||||
var entity = await setpointsRepository.GetAsync(id, token);
|
||||
if (setpointsRequestDto.Id <= 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(setpointsRequestDto), $"{nameof(setpointsRequestDto.Id)} = {setpointsRequestDto.Id}. Mast be > 0");
|
||||
|
||||
if (setpointsRequestDto.IdWell <= 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(setpointsRequestDto), $"{nameof(setpointsRequestDto.IdWell)} = {setpointsRequestDto.IdWell}. Mast be > 0");
|
||||
|
||||
var entity = await setpointsRepository.GetOrDefaultAsync(setpointsRequestDto.Id, token);
|
||||
|
||||
if (entity.IdWell != setpointsRequestDto.IdWell)
|
||||
return 0;
|
||||
|
||||
if (entity is null)
|
||||
return 0;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.Repository;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
|
@ -56,7 +56,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
var dtos = entities?.Select(Convert);
|
||||
return dtos;
|
||||
}
|
||||
public UserRoleDto Get(int id)
|
||||
public UserRoleDto GetOrDefault(int id)
|
||||
{
|
||||
var entity = cacheUserRoles.FirstOrDefault(r => r.Id == id);
|
||||
if (entity is null)
|
||||
@ -65,7 +65,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
return dto;
|
||||
}
|
||||
|
||||
public async Task<UserRoleDto> GetAsync(int id, CancellationToken token = default)
|
||||
public async Task<UserRoleDto> GetOrDefaultAsync(int id, CancellationToken token = default)
|
||||
{
|
||||
var entity = await cacheUserRoles.FirstOrDefaultAsync(r => r.Id == id, token)
|
||||
.ConfigureAwait(false);
|
||||
|
@ -81,7 +81,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
return dtos;
|
||||
}
|
||||
|
||||
public UserExtendedDto Get(int id)
|
||||
public UserExtendedDto GetOrDefault(int id)
|
||||
{
|
||||
var entity = cacheUsers.FirstOrDefault(u => u.Id == id);
|
||||
var dto = Convert(entity);
|
||||
@ -89,7 +89,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
return dto;
|
||||
}
|
||||
|
||||
public async Task<UserExtendedDto> GetAsync(int id, CancellationToken token = default)
|
||||
public async Task<UserExtendedDto> GetOrDefaultAsync(int id, CancellationToken token = default)
|
||||
{
|
||||
var entity = await cacheUsers.FirstOrDefaultAsync(u => u.Id == id, token).ConfigureAwait(false);
|
||||
var dto = Convert(entity);
|
||||
|
72
AsbCloudInfrastructure/Services/UserSettingsRepository.cs
Normal file
72
AsbCloudInfrastructure/Services/UserSettingsRepository.cs
Normal file
@ -0,0 +1,72 @@
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services
|
||||
{
|
||||
public class UserSettingsRepository : IUserSettingsRepository
|
||||
{
|
||||
private readonly IAsbCloudDbContext context;
|
||||
|
||||
public UserSettingsRepository(IAsbCloudDbContext context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public Task<object> GetOrDefaultAsync(int userId, string key, CancellationToken token)
|
||||
=> context.Set<UserSetting>()
|
||||
.Where(s => s.IdUser == userId && s.Key == key)
|
||||
.Select(s=>s.Value)
|
||||
.FirstOrDefaultAsync(token);
|
||||
|
||||
public async Task<int> InsertAsync(int userId, string key, object value, CancellationToken token)
|
||||
{
|
||||
var set = context.Set<UserSetting>();
|
||||
|
||||
if (await set.AnyAsync(s=>s.IdUser == userId && s.Key == key, token))
|
||||
return IUserSettingsRepository.ErrorKeyIsUsed;
|
||||
|
||||
var entity = new UserSetting
|
||||
{
|
||||
IdUser = userId,
|
||||
Key = key,
|
||||
Value = value,
|
||||
};
|
||||
|
||||
context.Set<UserSetting>()
|
||||
.Add(entity);
|
||||
|
||||
return await context.SaveChangesAsync(token);
|
||||
}
|
||||
|
||||
public async Task<int> UpdateAsync(int userId, string key, object value, CancellationToken token)
|
||||
{
|
||||
var set = context.Set<UserSetting>();
|
||||
var updatingItem = await set
|
||||
.FirstOrDefaultAsync(s => s.IdUser == userId && s.Key == key, token);
|
||||
|
||||
if (updatingItem is null)
|
||||
return IUserSettingsRepository.ErrorKeyNotFound;
|
||||
|
||||
updatingItem.Value = value;
|
||||
set.Update(updatingItem);
|
||||
|
||||
return await context.SaveChangesAsync(token);
|
||||
}
|
||||
public async Task<int> DeleteAsync(int userId, string key, CancellationToken token)
|
||||
{
|
||||
var set = context.Set<UserSetting>();
|
||||
var removingItem = await set
|
||||
.FirstOrDefaultAsync(s=>s.IdUser == userId && s.Key ==key, token);
|
||||
|
||||
if(removingItem is null)
|
||||
return IUserSettingsRepository.ErrorKeyNotFound;
|
||||
|
||||
set.Remove(removingItem);
|
||||
return await context.SaveChangesAsync(token);
|
||||
}
|
||||
}
|
||||
}
|
@ -31,7 +31,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
||||
if (!tvd.Any())
|
||||
return null;
|
||||
|
||||
var well = await wellService.GetAsync(idWell, token);
|
||||
var well = await wellService.GetOrDefaultAsync(idWell, token);
|
||||
|
||||
var ecxelTemplateStream = GetExcelTemplateStream();
|
||||
using var workbook = new XLWorkbook(ecxelTemplateStream, XLEventTracking.Disabled);
|
||||
|
@ -12,6 +12,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.WellOperationService
|
||||
{
|
||||
#nullable enable
|
||||
public class WellOperationService : IWellOperationService
|
||||
{
|
||||
private readonly IAsbCloudDbContext db;
|
||||
@ -219,4 +220,5 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.EfCache;
|
||||
using AsbCloudInfrastructure.Repository;
|
||||
using AsbCloudInfrastructure.Services.Cache;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@ -62,7 +63,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
|
||||
public DateTimeOffset GetLastTelemetryDate(int idWell)
|
||||
{
|
||||
var well = Get(idWell);
|
||||
var well = GetOrDefault(idWell);
|
||||
|
||||
if (well?.IdTelemetry is null)
|
||||
return DateTimeOffset.MinValue;
|
||||
@ -154,7 +155,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
|
||||
public async Task<string> GetWellCaptionByIdAsync(int idWell, CancellationToken token)
|
||||
{
|
||||
var entity = await GetAsync(idWell, token).ConfigureAwait(false);
|
||||
var entity = await GetOrDefaultAsync(idWell, token).ConfigureAwait(false);
|
||||
var dto = Convert(entity);
|
||||
return dto.Caption;
|
||||
}
|
||||
@ -186,7 +187,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
|
||||
public async Task<IEnumerable<int>> GetClusterWellsIdsAsync(int idWell, CancellationToken token)
|
||||
{
|
||||
var well = await GetAsync(idWell, token);
|
||||
var well = await GetOrDefaultAsync(idWell, token);
|
||||
|
||||
if (well is null)
|
||||
return null;
|
||||
@ -239,7 +240,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
{
|
||||
var dto = entity.Adapt<CompanyDto>();
|
||||
dto.CompanyTypeCaption = entity.CompanyType?.Caption
|
||||
?? companyTypesService.Get(entity.IdCompanyType).Caption;
|
||||
?? companyTypesService.GetOrDefault(entity.IdCompanyType).Caption;
|
||||
return dto;
|
||||
}
|
||||
|
||||
@ -265,7 +266,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
|
||||
public SimpleTimezoneDto GetTimezone(int idWell)
|
||||
{
|
||||
var well = Get(idWell);
|
||||
var well = GetOrDefault(idWell);
|
||||
if (well == null)
|
||||
throw new ArgumentInvalidException($"idWell: {idWell} does not exist.", nameof(idWell));
|
||||
return GetTimezone(well);
|
||||
@ -334,7 +335,7 @@ namespace AsbCloudInfrastructure.Services
|
||||
|
||||
public DatesRangeDto GetDatesRange(int idWell)
|
||||
{
|
||||
var well = Get(idWell);
|
||||
var well = GetOrDefault(idWell);
|
||||
if (well is null)
|
||||
throw new Exception($"Well id: {idWell} does not exist.");
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb;
|
||||
using AsbCloudDb.Model;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@ -71,8 +72,9 @@ namespace AsbCloudInfrastructure.Services
|
||||
return Task.CompletedTask;
|
||||
|
||||
var timezoneHours = telemetryService.GetTimezone(idTelemetry).Hours;
|
||||
var entities = dtos.Select(dto => Convert(dto, idTelemetry, timezoneHours));
|
||||
|
||||
var entities = dtos
|
||||
.DistinctBy(d => d.DateTime)
|
||||
.Select(dto => Convert(dto, idTelemetry, timezoneHours));
|
||||
dbset.AddRange(entities);
|
||||
return db.SaveChangesAsync(token);
|
||||
}
|
||||
|
@ -7,6 +7,9 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.6" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
||||
<PackageReference Include="Moq" Version="4.18.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
|
@ -43,7 +43,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
public async Task GetById()
|
||||
{
|
||||
var id = await Insert();
|
||||
var gotItem = await service.GetAsync(id, CancellationToken.None);
|
||||
var gotItem = await service.GetOrDefaultAsync(id, CancellationToken.None);
|
||||
Assert.True(id > 0);
|
||||
Assert.Equal(id, gotItem.Id);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.Services;
|
||||
using AsbCloudInfrastructure.Repository;
|
||||
|
||||
namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Requests;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.Services;
|
||||
@ -6,6 +7,8 @@ using AsbCloudInfrastructure.Services.Cache;
|
||||
using AsbCloudInfrastructure.Services.DetectOperations;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
@ -17,9 +20,17 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
private readonly AsbCloudDbContext context;
|
||||
private readonly CacheDb cacheDb;
|
||||
private readonly DetectedOperationService service;
|
||||
#region Задача данных
|
||||
private readonly DetectedOperationRequest request;
|
||||
private Deposit deposit = new Deposit { Id = 1, Caption = "Депозит 1" };
|
||||
private Cluster cluster = new Cluster { Id = 1, Caption = "Кластер 1", IdDeposit = 1, Timezone = new SimpleTimezone() };
|
||||
private WellDto wellDto = new WellDto
|
||||
{
|
||||
Id = 1,
|
||||
Caption = "Test well 1",
|
||||
IdTelemetry = 1,
|
||||
IdCluster = 1,
|
||||
Timezone = new SimpleTimezoneDto { Hours = 5 }
|
||||
};
|
||||
private Well well = new Well
|
||||
{
|
||||
Id = 1,
|
||||
@ -35,7 +46,8 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
Patronymic = "Тест",
|
||||
Surname = "Тестович"
|
||||
};
|
||||
private DetectedOperation do1 = new DetectedOperation
|
||||
private List<DetectedOperation> do1 = new List<DetectedOperation> {
|
||||
new DetectedOperation
|
||||
{
|
||||
Id = 1,
|
||||
IdCategory = 1,
|
||||
@ -43,14 +55,54 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
DateStart = DateTimeOffset.Parse("2022-05-16T10:00:00.286Z"),
|
||||
DateEnd = DateTimeOffset.Parse("2022-05-16T18:00:00.286Z"),
|
||||
DepthStart = 100,
|
||||
Value = 50,
|
||||
DepthEnd = 1000
|
||||
};
|
||||
},
|
||||
new DetectedOperation
|
||||
{
|
||||
Id = 2,
|
||||
IdCategory = 1,
|
||||
IdTelemetry = 1,
|
||||
DateStart = DateTimeOffset.Parse("2022-05-16T10:00:00.286Z"),
|
||||
DateEnd = DateTimeOffset.Parse("2022-05-16T18:00:00.286Z"),
|
||||
DepthStart = 100,
|
||||
Value = 10,
|
||||
DepthEnd = 1000
|
||||
}};
|
||||
private Telemetry telemetry = new Telemetry
|
||||
{
|
||||
Id = 1,
|
||||
RemoteUid = Guid.NewGuid().ToString()
|
||||
};
|
||||
#endregion
|
||||
private OperationValue ovd = new OperationValue
|
||||
{
|
||||
Id = 1,
|
||||
StandardValue = 200,
|
||||
TargetValue = 100,
|
||||
DepthEnd = 300,
|
||||
DepthStart = 100,
|
||||
IdOperationCategory=1,
|
||||
IdWell = 1
|
||||
};
|
||||
private List<Schedule> sch = new List<Schedule> { new Schedule
|
||||
{
|
||||
Id = 1,
|
||||
IdDriller = 1,
|
||||
IdWell = 1,
|
||||
DrillStart = DateTimeOffset.Parse("2022-05-16T10:00:00.286Z"),
|
||||
DrillEnd = DateTimeOffset.Parse("2022-05-16T18:00:00.286Z"),
|
||||
ShiftStart = new TimeOnly(10, 00),
|
||||
ShiftEnd = new TimeOnly(18, 00)
|
||||
}, new Schedule
|
||||
{
|
||||
Id = 2,
|
||||
IdDriller = 1,
|
||||
IdWell = 1,
|
||||
DrillStart = DateTimeOffset.Parse("2022-05-17T10:00:00.286Z"),
|
||||
DrillEnd = DateTimeOffset.Parse("2022-05-17T18:00:00.286Z"),
|
||||
ShiftStart = new TimeOnly(10, 00),
|
||||
ShiftEnd = new TimeOnly(18, 00)
|
||||
} };
|
||||
|
||||
public DetectedOperationServiceTest()
|
||||
{
|
||||
@ -62,17 +114,25 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
context.Clusters.Add(cluster);
|
||||
context.Wells.Add(well);
|
||||
context.Drillers.Add(driller);
|
||||
context.DetectedOperations.Add(do1);
|
||||
context.DetectedOperations.AddRange(do1);
|
||||
context.OperationValues.Add(ovd);
|
||||
context.Schedule.AddRange(sch);
|
||||
|
||||
context.SaveChanges();
|
||||
|
||||
var timezone = new SimpleTimezoneDto { Hours = 5 };
|
||||
var wellServiceMock = new Mock<IWellService>();
|
||||
wellServiceMock.Setup(s => s.GetTimezone(It.IsAny<int>())).Returns(timezone);
|
||||
wellServiceMock.Setup(s => s.GetOrDefaultAsync(It.IsAny<int>(),CancellationToken.None)).Returns(Task.Run(() => wellDto));
|
||||
var operationValueService = new OperationValueService(context);
|
||||
var scheduleService = new ScheduleService(context, wellServiceMock.Object);
|
||||
|
||||
service = new DetectedOperationService(context, wellServiceMock.Object, operationValueService, scheduleService);
|
||||
request = new DetectedOperationRequest
|
||||
{
|
||||
IdWell = 1,
|
||||
IdCategory = 1
|
||||
};
|
||||
AsbCloudInfrastructure.DependencyInjection.MapsterSetup();
|
||||
}
|
||||
|
||||
@ -84,9 +144,40 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
[Fact]
|
||||
public async Task Count_grouping_by_driller()
|
||||
{
|
||||
var count = 10;
|
||||
var list = await service.GetAsync(1, null, CancellationToken.None);
|
||||
Assert.Equal(3, count);
|
||||
var list = await service.GetAsync(request, CancellationToken.None);
|
||||
Assert.Equal(2, list.Stats.First().Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AvgVal_grouping_by_driller()
|
||||
{
|
||||
var list = await service.GetAsync(request, CancellationToken.None);
|
||||
Assert.Equal(30, list.Stats.First().AverageValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AvgTargetVal_grouping_by_driller()
|
||||
{
|
||||
var list = await service.GetAsync(request, CancellationToken.None);
|
||||
Assert.Equal(100, list.Stats.First().AverageTargetValue);
|
||||
}
|
||||
[Fact]
|
||||
public async Task Loss_grouping_by_driller()
|
||||
{
|
||||
var list = await service.GetAsync(request, CancellationToken.None);
|
||||
Assert.Equal(0, list.Stats.First().Loss);
|
||||
}
|
||||
[Fact]
|
||||
public async Task Efficiency_grouping_by_driller()
|
||||
{
|
||||
var list = await service.GetAsync(request, CancellationToken.None);
|
||||
Assert.Equal(100, list.Stats.First().Efficiency);
|
||||
}
|
||||
[Fact]
|
||||
public async Task GroupCount_grouping_by_driller()
|
||||
{
|
||||
var list = await service.GetAsync(request, CancellationToken.None);
|
||||
Assert.Equal(1, list.Stats.Count());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -162,7 +162,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
db.DrillingProgramParts.Add(new DrillingProgramPart { IdFileCategory = 1001, IdWell = idWell });
|
||||
db.SaveChanges();
|
||||
|
||||
userServiceMock.Setup((s) => s.GetAsync(It.IsAny<int>(), It.IsAny<CancellationToken>()))
|
||||
userServiceMock.Setup((s) => s.GetOrDefaultAsync(It.IsAny<int>(), It.IsAny<CancellationToken>()))
|
||||
.Returns(Task.FromResult(publisher1.Adapt<UserExtendedDto>()));
|
||||
|
||||
var service = new DrillingProgramService(
|
||||
@ -197,7 +197,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
IdUserRole = idUserRole
|
||||
});
|
||||
db.SaveChanges();
|
||||
userServiceMock.Setup((s) => s.GetAsync(It.IsAny<int>(), It.IsAny<CancellationToken>()))
|
||||
userServiceMock.Setup((s) => s.GetOrDefaultAsync(It.IsAny<int>(), It.IsAny<CancellationToken>()))
|
||||
.Returns(Task.FromResult(publisher1.Adapt<UserExtendedDto>()));
|
||||
|
||||
var service = new DrillingProgramService(
|
||||
@ -346,7 +346,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
wellServiceMock.Setup(s => s.GetAsync(It.IsAny<int>(), It.IsAny<CancellationToken>()))
|
||||
wellServiceMock.Setup(s => s.GetOrDefaultAsync(It.IsAny<int>(), It.IsAny<CancellationToken>()))
|
||||
.Returns(Task.FromResult(new WellDto { Caption = "test well", Cluster = "test cluster" }));
|
||||
|
||||
var service = new DrillingProgramService(
|
||||
@ -376,7 +376,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
wellServiceMock.Setup(s => s.GetAsync(It.IsAny<int>(), It.IsAny<CancellationToken>()))
|
||||
wellServiceMock.Setup(s => s.GetOrDefaultAsync(It.IsAny<int>(), It.IsAny<CancellationToken>()))
|
||||
.Returns(Task.FromResult(new WellDto { Caption = "test well", Cluster = "test cluster" }));
|
||||
|
||||
var service = new DrillingProgramService(
|
||||
|
@ -119,7 +119,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
Permissions = new[] { new PermissionDto { Id = 2_000_001 } },
|
||||
};
|
||||
var id = await service.InsertAsync(newRole, CancellationToken.None);
|
||||
var entity = await service.GetAsync(id);
|
||||
var entity = await service.GetOrDefaultAsync(id);
|
||||
Assert.Equal(newRole.Permissions.Count(), entity.Permissions.Count());
|
||||
}
|
||||
|
||||
@ -134,7 +134,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
Roles = new[] { new UserRoleDto { Id = 1_000_001 } }
|
||||
};
|
||||
var id = await service.InsertAsync(newRole, CancellationToken.None);
|
||||
var entity = await service.GetAsync(id);
|
||||
var entity = await service.GetOrDefaultAsync(id);
|
||||
Assert.Equal(newRole.Roles.Count, entity.Roles.Count);
|
||||
}
|
||||
|
||||
@ -164,7 +164,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
Permissions = new[] { new PermissionDto { Id = 2_000_001 } },
|
||||
};
|
||||
var id = await service.UpdateAsync(modRole, CancellationToken.None);
|
||||
var entity = await service.GetAsync(id);
|
||||
var entity = await service.GetOrDefaultAsync(id);
|
||||
Assert.Equal(modRole.Permissions.Count(), entity.Permissions.Count());
|
||||
}
|
||||
|
||||
@ -180,7 +180,7 @@ namespace AsbCloudWebApi.Tests.ServicesTests
|
||||
Roles = new[] { new UserRoleDto { Id = 1_000_001 } }
|
||||
};
|
||||
var id = await service.UpdateAsync(modRole, CancellationToken.None);
|
||||
var entity = await service.GetAsync(id);
|
||||
var entity = await service.GetOrDefaultAsync(id);
|
||||
Assert.Equal(modRole.Roles.Count(), entity.Roles.Count());
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,23 @@
|
||||
using AsbCloudDb.Model;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||
|
||||
namespace AsbCloudWebApi.Tests
|
||||
{
|
||||
internal static class TestHelpter
|
||||
{
|
||||
// Попробовать когда-нибудь https://github.com/MichalJankowskii/Moq.EntityFrameworkCore
|
||||
|
||||
public static AsbCloudDbContext MakeTestContext()
|
||||
{
|
||||
var options = new DbContextOptionsBuilder<AsbCloudDbContext>()
|
||||
//.UseInMemoryDatabase(System.Guid.NewGuid().ToString())
|
||||
//.ConfigureWarnings(configBuilder =>
|
||||
// configBuilder.Ignore(InMemoryEventId.TransactionIgnoredWarning))
|
||||
.UseNpgsql("Host=localhost;Database=tests;Username=postgres;Password=q;Persist Security Info=True;Include Error Detail=True")
|
||||
.Options;
|
||||
var context = new AsbCloudDbContext(options);
|
||||
context.Database.EnsureDeleted();
|
||||
//context.Database.EnsureDeleted();
|
||||
context.Database.EnsureCreated();
|
||||
return context;
|
||||
}
|
||||
|
@ -9,8 +9,8 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.6" />
|
||||
<PackageReference Include="protobuf-net" Version="3.1.4" />
|
||||
<PackageReference Include="protobuf-net.AspNetCore" Version="3.0.101" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.1" />
|
||||
|
@ -5,6 +5,9 @@ using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace AsbCloudWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Редактор кустов для админки
|
||||
/// </summary>
|
||||
[Route("api/admin/cluster")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
|
@ -5,6 +5,9 @@ using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace AsbCloudWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Редактор компаний для админки
|
||||
/// </summary>
|
||||
[Route("api/admin/company")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
|
@ -5,6 +5,9 @@ using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace AsbCloudWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Редактор типов компаний для админки
|
||||
/// </summary>
|
||||
[Route("api/admin/companyType")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
|
@ -5,6 +5,9 @@ using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace AsbCloudWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Редактор месторождений для админки
|
||||
/// </summary>
|
||||
[Route("api/admin/deposit")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
|
@ -9,6 +9,9 @@ using System.Reflection;
|
||||
|
||||
namespace AsbCloudWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Редактор разрешений пользователей для админки
|
||||
/// </summary>
|
||||
[Route("api/admin/permission")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
|
@ -7,6 +7,9 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Редактор телеметрий для админки
|
||||
/// </summary>
|
||||
[Route("api/admin/telemetry")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
|
@ -5,6 +5,9 @@ using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace AsbCloudWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Редактор пользователей для админки
|
||||
/// </summary>
|
||||
[Route("api/admin/user")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
|
@ -6,6 +6,9 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Редактор ролей пользователей для админки
|
||||
/// </summary>
|
||||
[Route("api/admin/role")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
@ -16,8 +19,8 @@ namespace AsbCloudWebApi.Controllers
|
||||
{
|
||||
UpdateForbidAsync = async (dto, token) =>
|
||||
{
|
||||
var role = await service.GetAsync(dto.Id, token);
|
||||
return role?.IdType != 1;
|
||||
var role = await service.GetOrDefaultAsync(dto.Id, token);
|
||||
return role?.Id == 1;
|
||||
};
|
||||
|
||||
DeleteForbidAsync = (id, token) =>
|
||||
|
@ -7,6 +7,9 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Редактор скважин для админки
|
||||
/// </summary>
|
||||
[Route("api/admin/well")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
@ -18,7 +21,7 @@ namespace AsbCloudWebApi.Controllers
|
||||
|
||||
[HttpPost("EnshureTimezonesIsSet")]
|
||||
[Permission]
|
||||
public async Task<IActionResult> EnsureTimestamps(CancellationToken token)
|
||||
public async Task<IActionResult> EnshureTimezonesIsSet(CancellationToken token)
|
||||
{
|
||||
await ((IWellService)service).EnshureTimezonesIsSetAsync(token);
|
||||
return Ok();
|
||||
|
@ -8,6 +8,9 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Авторизация
|
||||
/// </summary>
|
||||
[Route("/auth")]
|
||||
[ApiController]
|
||||
public class AuthController : ControllerBase
|
||||
|
@ -9,7 +9,7 @@ using System.Threading.Tasks;
|
||||
namespace AsbCloudWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Контроллер кустов
|
||||
/// Инфо о кустах
|
||||
/// </summary>
|
||||
[Route("api/cluster")]
|
||||
[ApiController]
|
||||
|
@ -57,7 +57,7 @@ namespace AsbCloudWebApi.Controllers
|
||||
[Permission]
|
||||
public virtual async Task<ActionResult<T>> GetAsync(int id, CancellationToken token)
|
||||
{
|
||||
var result = await service.GetAsync(id, token).ConfigureAwait(false);
|
||||
var result = await service.GetOrDefaultAsync(id, token).ConfigureAwait(false);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ using System.Threading.Tasks;
|
||||
namespace AsbCloudWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// CRUD контроллер для админки.
|
||||
/// CRUD контроллер dto связных со скважиной для админки.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TService"></typeparam>
|
||||
@ -68,7 +68,12 @@ namespace AsbCloudWebApi.Controllers
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <summary>
|
||||
/// Получить одну запись по Id
|
||||
/// </summary>
|
||||
/// <param name="id">id записи</param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns>запись</returns>
|
||||
[HttpGet("{id}")]
|
||||
public override async Task<ActionResult<T>> GetAsync(int id, CancellationToken token)
|
||||
{
|
||||
@ -79,7 +84,12 @@ namespace AsbCloudWebApi.Controllers
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <summary>
|
||||
/// Добавить запись
|
||||
/// </summary>
|
||||
/// <param name="value">запись</param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns>id</returns>
|
||||
[HttpPost]
|
||||
public override async Task<ActionResult<int>> InsertAsync([FromBody] T value, CancellationToken token)
|
||||
{
|
||||
@ -88,7 +98,13 @@ namespace AsbCloudWebApi.Controllers
|
||||
return await base.InsertAsync(value, token);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <summary>
|
||||
/// Добавить несколько записей<br/>
|
||||
/// При невозможности добавить любую из записей, все не будут добавлены.
|
||||
/// </summary>
|
||||
/// <param name="values">записи</param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns>id</returns>
|
||||
[HttpPost("range")]
|
||||
public override async Task<ActionResult<int>> InsertRangeAsync([FromBody] IEnumerable<T> values, CancellationToken token)
|
||||
{
|
||||
@ -99,7 +115,12 @@ namespace AsbCloudWebApi.Controllers
|
||||
return await base.InsertRangeAsync(values, token);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <summary>
|
||||
/// Редактировать запись по id
|
||||
/// </summary>
|
||||
/// <param name="value">запись</param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns>1 - успешно отредактировано, 0 - нет</returns>
|
||||
[HttpPut]
|
||||
public override async Task<ActionResult<int>> UpdateAsync([FromBody] T value, CancellationToken token)
|
||||
{
|
||||
@ -108,11 +129,16 @@ namespace AsbCloudWebApi.Controllers
|
||||
return await base.UpdateAsync(value, token);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <summary>
|
||||
/// Удалить запись по id
|
||||
/// </summary>
|
||||
/// <param name="id">id записи</param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns>1 - успешно удалено, 0 - нет</returns>
|
||||
[HttpDelete("{id}")]
|
||||
public override async Task<ActionResult<int>> DeleteAsync(int id, CancellationToken token)
|
||||
{
|
||||
var item = await service.GetAsync(id, token);
|
||||
var item = await service.GetOrDefaultAsync(id, token);
|
||||
if (item is null)
|
||||
return NoContent();
|
||||
if (!await UserHasAccesToWellAsync(item.IdWell, token))
|
||||
|
@ -10,6 +10,9 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace AsbCloudWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Суточный рапорт
|
||||
/// </summary>
|
||||
[Route("api/well/{idWell}/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
@ -94,6 +97,7 @@ namespace AsbCloudWebApi.Controllers
|
||||
/// Сформировать и скачать рапорт в формате excel
|
||||
/// </summary>
|
||||
/// <param name="idWell"></param>
|
||||
/// <param name="date"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("{date}/excel")]
|
||||
@ -101,7 +105,7 @@ namespace AsbCloudWebApi.Controllers
|
||||
[ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK)]
|
||||
public async Task<IActionResult> DownloadAsync(int idWell, DateTime date, CancellationToken token = default)
|
||||
{
|
||||
var well = await wellService.GetAsync(idWell, token);
|
||||
var well = await wellService.GetOrDefaultAsync(idWell, token);
|
||||
var stream = await dailyReportService.MakeReportAsync(idWell, date, token);
|
||||
if (stream != null)
|
||||
{
|
||||
|
@ -9,7 +9,7 @@ using System.Threading.Tasks;
|
||||
namespace AsbCloudWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Контроллер для месторождений
|
||||
/// Инфо о месторождениях
|
||||
/// </summary>
|
||||
[Route("api/deposit")]
|
||||
[ApiController]
|
||||
|
@ -10,7 +10,7 @@ using System.Threading.Tasks;
|
||||
namespace AsbCloudWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Контроллер для коридоров бурения на панели
|
||||
/// Коридоры бурения для панели бурильщика
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
@ -18,14 +18,12 @@ namespace AsbCloudWebApi.Controllers
|
||||
public class DrillFlowChartController : CrudWellRelatedController<DrillFlowChartDto, IDrillFlowChartService>
|
||||
{
|
||||
private readonly ITelemetryService telemetryService;
|
||||
private readonly IWellService wellService;
|
||||
|
||||
public DrillFlowChartController(IWellService wellService, IDrillFlowChartService service,
|
||||
ITelemetryService telemetryService)
|
||||
: base(wellService, service)
|
||||
{
|
||||
this.telemetryService = telemetryService;
|
||||
this.wellService = wellService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -8,7 +8,7 @@ using System.Threading.Tasks;
|
||||
namespace AsbCloudWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Контроллер для режимов бурения
|
||||
/// Режимы бурения
|
||||
/// </summary>
|
||||
[Route("api/well/{idWell}/drillParams/")]
|
||||
[ApiController]
|
||||
|
@ -5,6 +5,9 @@ using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace AsbCloudWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Справочник бурильщиков
|
||||
/// </summary>
|
||||
[Route("api/driller")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user