forked from ddrilling/AsbCloudServer
Merge pull request 'feature/import_and_export_process_map' (#80) from feature/import_and_export_process_map into dev
Reviewed-on: http://test.digitaldrilling.ru:8080/DDrilling/AsbCloudServer/pulls/80
This commit is contained in:
commit
f02346a24a
@ -87,5 +87,10 @@ namespace AsbCloudApp.Data.ProcessMap
|
|||||||
/// Плановый процент использования spin master
|
/// Плановый процент использования spin master
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double UsageSpin { get; set; }
|
public double UsageSpin { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DTO типа секции
|
||||||
|
/// </summary>
|
||||||
|
public WellSectionTypeDto WellSectionType { get; set; } = null!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
17
AsbCloudApp/Data/WellSectionTypeDto.cs
Normal file
17
AsbCloudApp/Data/WellSectionTypeDto.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace AsbCloudApp.Data;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Тип секции
|
||||||
|
/// </summary>
|
||||||
|
public class WellSectionTypeDto : IId
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Id секции
|
||||||
|
/// </summary>
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Название типа секции
|
||||||
|
/// </summary>
|
||||||
|
public string Caption { get; set; } = null!;
|
||||||
|
}
|
35
AsbCloudApp/Services/IProcessMapPlanImportService.cs
Normal file
35
AsbCloudApp/Services/IProcessMapPlanImportService.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Services;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Сервис импорта/экспорта для РТК вводимых вручную
|
||||||
|
/// </summary>
|
||||||
|
public interface IProcessMapPlanImportService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Загрузить данные из файла
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idWell"></param>
|
||||||
|
/// <param name="idUser"></param>
|
||||||
|
/// <param name="stream"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task ImportAsync(int idWell, int idUser, Stream stream, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Сформировать файл с данными
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idWell"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<Stream> ExportAsync(int idWell, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение шаблона для заполнения
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<Stream> GetExcelTemplateStreamAsync(CancellationToken cancellationToken);
|
||||||
|
}
|
@ -35,6 +35,7 @@
|
|||||||
<EmbeddedResource Include="Services\ProcessMap\ProcessMapReportTemplate.xlsx" />
|
<EmbeddedResource Include="Services\ProcessMap\ProcessMapReportTemplate.xlsx" />
|
||||||
<EmbeddedResource Include="Services\WellOperationService\ScheduleReportTemplate.xlsx" />
|
<EmbeddedResource Include="Services\WellOperationService\ScheduleReportTemplate.xlsx" />
|
||||||
<EmbeddedResource Include="Services\WellOperationService\WellOperationImportTemplate.xlsx" />
|
<EmbeddedResource Include="Services\WellOperationService\WellOperationImportTemplate.xlsx" />
|
||||||
|
<EmbeddedResource Include="Services\ProcessMap\ProcessMapPlanTemplate.xlsx" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -128,6 +128,7 @@ namespace AsbCloudInfrastructure
|
|||||||
services.AddTransient<ITimezoneService, TimezoneService>();
|
services.AddTransient<ITimezoneService, TimezoneService>();
|
||||||
services.AddTransient<IWellService, WellService>();
|
services.AddTransient<IWellService, WellService>();
|
||||||
services.AddTransient<IWellOperationImportService, WellOperationImportService>();
|
services.AddTransient<IWellOperationImportService, WellOperationImportService>();
|
||||||
|
services.AddTransient<IProcessMapPlanImportService, ProcessMapPlanImportService>();
|
||||||
services.AddTransient<IPlannedTrajectoryImportService, PlannedTrajectoryImportService>();
|
services.AddTransient<IPlannedTrajectoryImportService, PlannedTrajectoryImportService>();
|
||||||
services.AddTransient<IWellOperationRepository, WellOperationRepository>();
|
services.AddTransient<IWellOperationRepository, WellOperationRepository>();
|
||||||
services.AddTransient<IScheduleReportService, ScheduleReportService>();
|
services.AddTransient<IScheduleReportService, ScheduleReportService>();
|
||||||
@ -195,6 +196,8 @@ namespace AsbCloudInfrastructure
|
|||||||
services.AddTransient<ITrajectoryFactRepository, TrajectoryFactRepository>();
|
services.AddTransient<ITrajectoryFactRepository, TrajectoryFactRepository>();
|
||||||
services.AddTransient<IFaqRepository, FaqRepository>();
|
services.AddTransient<IFaqRepository, FaqRepository>();
|
||||||
services.AddTransient<IWellContactService, WellContactService>();
|
services.AddTransient<IWellContactService, WellContactService>();
|
||||||
|
services.AddTransient<ICrudRepository<WellSectionTypeDto>, CrudCacheRepositoryBase<WellSectionTypeDto,
|
||||||
|
WellSectionType>>();
|
||||||
|
|
||||||
// Subsystem service
|
// Subsystem service
|
||||||
services.AddTransient<ICrudRepository<SubsystemDto>, CrudCacheRepositoryBase<SubsystemDto, Subsystem>>();
|
services.AddTransient<ICrudRepository<SubsystemDto>, CrudCacheRepositoryBase<SubsystemDto, Subsystem>>();
|
||||||
|
@ -0,0 +1,352 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.Data.ProcessMap;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
|
using AsbCloudApp.Services;
|
||||||
|
using ClosedXML.Excel;
|
||||||
|
using System;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services.ProcessMap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* password for ProcessMapImportTemplate.xlsx is ASB2020!
|
||||||
|
*/
|
||||||
|
public class ProcessMapPlanImportService : IProcessMapPlanImportService
|
||||||
|
{
|
||||||
|
private readonly IProcessMapPlanRepository processMapPlanRepository;
|
||||||
|
private readonly ICrudRepository<WellSectionTypeDto> wellSectionTypeRepository;
|
||||||
|
|
||||||
|
private const string sheetNamePlan = "План";
|
||||||
|
|
||||||
|
private const int headerRowsCount = 2;
|
||||||
|
|
||||||
|
private const int columnWellSectionType = 1;
|
||||||
|
private const int columnMode = 2;
|
||||||
|
private const int columnDepthStart = 3;
|
||||||
|
private const int columnDepthEnd = 4;
|
||||||
|
private const int columnPressurePlan = 5;
|
||||||
|
private const int columnPressureLimitMax = 6;
|
||||||
|
private const int columnAxialLoadPlan = 7;
|
||||||
|
private const int columnAxialLoadLimitMax = 8;
|
||||||
|
private const int columnTopDriveTorquePlan = 9;
|
||||||
|
private const int columnTopDriveTorqueLimitMax = 10;
|
||||||
|
private const int columnTopDriveSpeedPlan = 11;
|
||||||
|
private const int columnTopDriveSpeedLimitMax = 12;
|
||||||
|
private const int columnFlowPlan = 13;
|
||||||
|
private const int columnFlowLimitMax = 14;
|
||||||
|
private const int columnRopPlan = 15;
|
||||||
|
private const int columnUsageSaub = 16;
|
||||||
|
private const int columnUsageSpin = 17;
|
||||||
|
|
||||||
|
private WellSectionTypeDto[] sections = null!;
|
||||||
|
|
||||||
|
public ProcessMapPlanImportService(IProcessMapPlanRepository processMapPlanRepository,
|
||||||
|
ICrudRepository<WellSectionTypeDto> wellSectionTypeRepository)
|
||||||
|
{
|
||||||
|
this.processMapPlanRepository = processMapPlanRepository;
|
||||||
|
this.wellSectionTypeRepository = wellSectionTypeRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ImportAsync(int idWell, int idUser, Stream stream, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
sections = (await wellSectionTypeRepository.GetAllAsync(cancellationToken)).ToArray();
|
||||||
|
|
||||||
|
using var workBook = new XLWorkbook(stream);
|
||||||
|
|
||||||
|
var processPlanMaps = ParseWorkBook(workBook);
|
||||||
|
|
||||||
|
foreach (var processPlanMap in processPlanMaps)
|
||||||
|
{
|
||||||
|
processPlanMap.IdWell = idWell;
|
||||||
|
processPlanMap.IdUser = idUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
await processMapPlanRepository.InsertRangeAsync(processPlanMaps, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Stream> ExportAsync(int idWell, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var processMapPlans = (await processMapPlanRepository.GetByIdWellAsync(idWell,
|
||||||
|
cancellationToken)).ToArray();
|
||||||
|
|
||||||
|
return await GenerateExcelFileStreamAsync(processMapPlans,
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Stream> GetExcelTemplateStreamAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var resourceName = Assembly.GetExecutingAssembly()
|
||||||
|
.GetManifestResourceNames()
|
||||||
|
.FirstOrDefault(n => n.EndsWith("ProcessMapPlanTemplate.xlsx"))!;
|
||||||
|
|
||||||
|
using var stream = Assembly.GetExecutingAssembly()
|
||||||
|
.GetManifestResourceStream(resourceName)!;
|
||||||
|
|
||||||
|
var memoryStream = new MemoryStream();
|
||||||
|
await stream.CopyToAsync(memoryStream, cancellationToken);
|
||||||
|
memoryStream.Position = 0;
|
||||||
|
|
||||||
|
return memoryStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddToWorkbook(XLWorkbook workbook, ProcessMapPlanDto[] processMapPlans)
|
||||||
|
{
|
||||||
|
if (!processMapPlans.Any())
|
||||||
|
return;
|
||||||
|
|
||||||
|
var sheet = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetNamePlan)
|
||||||
|
?? throw new FileFormatException($"Книга excel не содержит листа {sheetNamePlan}.");
|
||||||
|
|
||||||
|
AddToSheet(sheet, processMapPlans);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddToSheet(IXLWorksheet sheet, ProcessMapPlanDto[] processMapPlans)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < processMapPlans.Length; i++)
|
||||||
|
{
|
||||||
|
var row = sheet.Row(1 + i + headerRowsCount);
|
||||||
|
AddToRow(row, processMapPlans[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddToRow(IXLRow row, ProcessMapPlanDto processMap)
|
||||||
|
{
|
||||||
|
row.Cell(columnWellSectionType).Value = processMap.WellSectionType.Caption;
|
||||||
|
row.Cell(columnMode).Value = GetModeCaption(processMap.IdMode);
|
||||||
|
row.Cell(columnDepthStart).Value = processMap.DepthStart;
|
||||||
|
row.Cell(columnDepthEnd).Value = processMap.DepthEnd;
|
||||||
|
row.Cell(columnPressurePlan).Value = processMap.Pressure.Plan;
|
||||||
|
row.Cell(columnPressureLimitMax).Value = processMap.Pressure.LimitMax;
|
||||||
|
row.Cell(columnAxialLoadPlan).Value = processMap.AxialLoad.Plan;
|
||||||
|
row.Cell(columnAxialLoadLimitMax).Value = processMap.AxialLoad.LimitMax;
|
||||||
|
row.Cell(columnTopDriveTorquePlan).Value = processMap.TopDriveTorque.Plan;
|
||||||
|
row.Cell(columnTopDriveTorqueLimitMax).Value = processMap.TopDriveTorque.LimitMax;
|
||||||
|
row.Cell(columnTopDriveSpeedPlan).Value = processMap.TopDriveSpeed.Plan;
|
||||||
|
row.Cell(columnTopDriveSpeedLimitMax).Value = processMap.TopDriveSpeed.LimitMax;
|
||||||
|
row.Cell(columnFlowPlan).Value = processMap.Flow.Plan;
|
||||||
|
row.Cell(columnFlowLimitMax).Value = processMap.Flow.LimitMax;
|
||||||
|
row.Cell(columnRopPlan).Value = processMap.RopPlan;
|
||||||
|
row.Cell(columnUsageSaub).Value = processMap.UsageSaub;
|
||||||
|
row.Cell(columnUsageSpin).Value = processMap.UsageSpin;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProcessMapPlanDto[] ParseWorkBook(IXLWorkbook workbook)
|
||||||
|
{
|
||||||
|
var sheet = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetNamePlan)
|
||||||
|
?? throw new FileFormatException($"Книга excel не содержит листа {sheetNamePlan}.");
|
||||||
|
|
||||||
|
return ParseSheet(sheet);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProcessMapPlanDto[] ParseSheet(IXLWorksheet sheet)
|
||||||
|
{
|
||||||
|
const int columnsCount = 17;
|
||||||
|
|
||||||
|
if (sheet.RangeUsed().RangeAddress.LastAddress.ColumnNumber < columnsCount)
|
||||||
|
throw new FileFormatException($"Лист {sheet.Name} содержит меньшее количество столбцов.");
|
||||||
|
|
||||||
|
var rowsCount = sheet.RowsUsed().Count() - headerRowsCount;
|
||||||
|
|
||||||
|
if (rowsCount <= 0)
|
||||||
|
return Array.Empty<ProcessMapPlanDto>();
|
||||||
|
|
||||||
|
var processMapPlans = new ProcessMapPlanDto[rowsCount];
|
||||||
|
|
||||||
|
var parseErrors = new List<string>();
|
||||||
|
|
||||||
|
for (int i = 0; i < processMapPlans.Length; i++)
|
||||||
|
{
|
||||||
|
var row = sheet.Row(1 + i + headerRowsCount);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
processMapPlans[i] = ParseRow(row);
|
||||||
|
}
|
||||||
|
catch (FileFormatException ex)
|
||||||
|
{
|
||||||
|
parseErrors.Add(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parseErrors.Any())
|
||||||
|
throw new FileFormatException(string.Join("\r\n", parseErrors));
|
||||||
|
|
||||||
|
return processMapPlans;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProcessMapPlanDto ParseRow(IXLRow row)
|
||||||
|
{
|
||||||
|
var wellSectionTypeCaption = GetCellValue<string>(row, columnWellSectionType).Trim().ToLower();
|
||||||
|
var modeName = GetCellValue<string>(row, columnMode).Trim().ToLower();
|
||||||
|
var depthStart = GetCellValue<double>(row, columnDepthStart);
|
||||||
|
var depthEnd = GetCellValue<double>(row, columnDepthEnd);
|
||||||
|
var pressurePlan = GetCellValue<double>(row, columnPressurePlan);
|
||||||
|
var pressureLimitMax = GetCellValue<double>(row, columnPressureLimitMax);
|
||||||
|
var axialLoadPlan = GetCellValue<double>(row, columnAxialLoadPlan);
|
||||||
|
var axialLoadLimitMax = GetCellValue<double>(row, columnAxialLoadLimitMax);
|
||||||
|
var topDriveTorquePlan = GetCellValue<double>(row, columnTopDriveTorquePlan);
|
||||||
|
var topDriveTorqueLimitMax = GetCellValue<double>(row, columnTopDriveTorqueLimitMax);
|
||||||
|
var topDriveSpeedPlan = GetCellValue<double>(row, columnTopDriveSpeedPlan);
|
||||||
|
var topDriveSpeedLimitMax = GetCellValue<double>(row, columnTopDriveSpeedLimitMax);
|
||||||
|
var flowPlan = GetCellValue<double>(row, columnFlowPlan);
|
||||||
|
var flowLimitMax = GetCellValue<double>(row, columnFlowLimitMax);
|
||||||
|
var ropPlan = GetCellValue<double>(row, columnRopPlan);
|
||||||
|
var usageSaub = GetCellValue<double>(row, columnUsageSaub);
|
||||||
|
var usageSpin = GetCellValue<double>(row, columnUsageSpin);
|
||||||
|
|
||||||
|
var wellSection = sections.FirstOrDefault(s => s.Caption.Trim().ToLower() == wellSectionTypeCaption)
|
||||||
|
?? throw new FileFormatException(
|
||||||
|
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указана некорректная секция");
|
||||||
|
|
||||||
|
var idMode = GetIdMode(modeName)
|
||||||
|
?? throw new FileFormatException(
|
||||||
|
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указан некорректный режим");
|
||||||
|
|
||||||
|
if (depthStart is < 0 or > 50000)
|
||||||
|
throw new FileFormatException(
|
||||||
|
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указана некорректная стартовая глубина");
|
||||||
|
|
||||||
|
if (depthEnd is < 0 or > 50000)
|
||||||
|
throw new FileFormatException(
|
||||||
|
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указана некорректная конечная глубина");
|
||||||
|
|
||||||
|
if (pressurePlan is < 0 or > 50000)
|
||||||
|
throw new FileFormatException(
|
||||||
|
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное плановое значение перепада давления");
|
||||||
|
|
||||||
|
if (pressureLimitMax is < 0 or > 50000)
|
||||||
|
throw new FileFormatException(
|
||||||
|
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное ограничение перепада давления");
|
||||||
|
|
||||||
|
if (axialLoadPlan is < 0 or > 50000)
|
||||||
|
throw new FileFormatException(
|
||||||
|
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное плановое значение нагрузки");
|
||||||
|
|
||||||
|
if (axialLoadLimitMax is < 0 or > 50000)
|
||||||
|
throw new FileFormatException(
|
||||||
|
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное ограничение нагрузки");
|
||||||
|
|
||||||
|
if (topDriveTorquePlan is < 0 or > 50000)
|
||||||
|
throw new FileFormatException(
|
||||||
|
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное плановое значение момента на ВСП");
|
||||||
|
|
||||||
|
if (topDriveTorqueLimitMax is < 0 or > 50000)
|
||||||
|
throw new FileFormatException(
|
||||||
|
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное ограничение момента на ВСП");
|
||||||
|
|
||||||
|
if (topDriveSpeedPlan is < 0 or > 50000)
|
||||||
|
throw new FileFormatException(
|
||||||
|
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное плановое значение оборотов на ВСП");
|
||||||
|
|
||||||
|
if (topDriveSpeedLimitMax is < 0 or > 50000)
|
||||||
|
throw new FileFormatException(
|
||||||
|
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное ограничения оборота на ВСП");
|
||||||
|
|
||||||
|
if (flowPlan is < 0 or > 50000)
|
||||||
|
throw new FileFormatException(
|
||||||
|
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное плановое значение расхода");
|
||||||
|
|
||||||
|
if (flowLimitMax is < 0 or > 50000)
|
||||||
|
throw new FileFormatException(
|
||||||
|
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное ограничение расхода");
|
||||||
|
|
||||||
|
if (ropPlan is < 0 or > 50000)
|
||||||
|
throw new FileFormatException(
|
||||||
|
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указано некорректное плановое значение механической скорости");
|
||||||
|
|
||||||
|
if (usageSaub is < 0 or > 100)
|
||||||
|
throw new FileFormatException(
|
||||||
|
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указан некорректный плановый процент использования АКБ");
|
||||||
|
|
||||||
|
if (usageSpin is < 0 or > 100)
|
||||||
|
throw new FileFormatException(
|
||||||
|
$"Лист {row.Worksheet.Name}. В строке {row.RowNumber()} указан некорректные плановый процент использования spin master");
|
||||||
|
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
IdWellSectionType = wellSection.Id,
|
||||||
|
IdMode = idMode,
|
||||||
|
DepthStart = depthStart,
|
||||||
|
LastUpdate = DateTime.UtcNow,
|
||||||
|
DepthEnd = depthEnd,
|
||||||
|
Pressure = new()
|
||||||
|
{
|
||||||
|
Plan = pressurePlan,
|
||||||
|
LimitMax = pressureLimitMax
|
||||||
|
},
|
||||||
|
AxialLoad = new()
|
||||||
|
{
|
||||||
|
Plan = axialLoadPlan,
|
||||||
|
LimitMax = axialLoadLimitMax
|
||||||
|
},
|
||||||
|
TopDriveTorque = new()
|
||||||
|
{
|
||||||
|
Plan = topDriveTorquePlan,
|
||||||
|
LimitMax = topDriveTorqueLimitMax
|
||||||
|
},
|
||||||
|
TopDriveSpeed = new()
|
||||||
|
{
|
||||||
|
Plan = topDriveSpeedPlan,
|
||||||
|
LimitMax = topDriveSpeedLimitMax
|
||||||
|
},
|
||||||
|
Flow = new()
|
||||||
|
{
|
||||||
|
Plan = flowPlan,
|
||||||
|
LimitMax = flowLimitMax
|
||||||
|
},
|
||||||
|
RopPlan = ropPlan,
|
||||||
|
UsageSaub = usageSaub,
|
||||||
|
UsageSpin = usageSpin
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Stream> GenerateExcelFileStreamAsync(ProcessMapPlanDto[] processMapPlans,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
using var excelTemplateStream = await GetExcelTemplateStreamAsync(cancellationToken);
|
||||||
|
|
||||||
|
using var workbook = new XLWorkbook(excelTemplateStream, XLEventTracking.Disabled);
|
||||||
|
|
||||||
|
AddToWorkbook(workbook, processMapPlans);
|
||||||
|
|
||||||
|
MemoryStream memoryStream = new MemoryStream();
|
||||||
|
workbook.SaveAs(memoryStream, new SaveOptions { });
|
||||||
|
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
return memoryStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int? GetIdMode(string modeName) =>
|
||||||
|
modeName switch
|
||||||
|
{
|
||||||
|
"ручной" => 0,
|
||||||
|
"ротор" => 1,
|
||||||
|
"слайд" => 2,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
|
||||||
|
private static string GetModeCaption(int idMode)
|
||||||
|
=> idMode switch
|
||||||
|
{
|
||||||
|
1 => "Ротор",
|
||||||
|
2 => "Слайд",
|
||||||
|
_ => "Ручной",
|
||||||
|
};
|
||||||
|
|
||||||
|
private static T GetCellValue<T>(IXLRow row, int columnNumber)
|
||||||
|
{
|
||||||
|
var cell = row.Cell(columnNumber);
|
||||||
|
|
||||||
|
if (cell.Value is T cellValue)
|
||||||
|
{
|
||||||
|
return cellValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FileFormatException(
|
||||||
|
$"Лист {row.Worksheet.Name}. Ячейка:{columnNumber},{row.RowNumber()} содержит некорректное значение");
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
@ -7,9 +7,12 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace AsbCloudWebApi.Controllers
|
namespace AsbCloudWebApi.Controllers
|
||||||
{
|
{
|
||||||
@ -25,6 +28,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
private readonly IHubContext<TelemetryHub> telemetryHubContext;
|
private readonly IHubContext<TelemetryHub> telemetryHubContext;
|
||||||
private readonly IProcessMapReportMakerService processMapReportService;
|
private readonly IProcessMapReportMakerService processMapReportService;
|
||||||
private readonly IProcessMapReportService processMapService;
|
private readonly IProcessMapReportService processMapService;
|
||||||
|
private readonly IProcessMapPlanImportService processMapPlanImportService;
|
||||||
|
|
||||||
private const string SirnalRMethodGetDataName = "UpdateProcessMap";
|
private const string SirnalRMethodGetDataName = "UpdateProcessMap";
|
||||||
|
|
||||||
@ -34,13 +38,15 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
IProcessMapReportMakerService processMapReportService,
|
IProcessMapReportMakerService processMapReportService,
|
||||||
IProcessMapReportService processMapService,
|
IProcessMapReportService processMapService,
|
||||||
ITelemetryService telemetryService,
|
ITelemetryService telemetryService,
|
||||||
IHubContext<TelemetryHub> telemetryHubContext)
|
IHubContext<TelemetryHub> telemetryHubContext,
|
||||||
|
IProcessMapPlanImportService processMapPlanImportService)
|
||||||
: base(wellService, repository)
|
: base(wellService, repository)
|
||||||
{
|
{
|
||||||
this.telemetryService = telemetryService;
|
this.telemetryService = telemetryService;
|
||||||
this.telemetryHubContext = telemetryHubContext;
|
this.telemetryHubContext = telemetryHubContext;
|
||||||
this.processMapReportService = processMapReportService;
|
this.processMapReportService = processMapReportService;
|
||||||
this.processMapService = processMapService;
|
this.processMapService = processMapService;
|
||||||
|
this.processMapPlanImportService = processMapPlanImportService;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +67,6 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
var idWell = telemetryService.GetIdWellByTelemetryUid(uid);
|
var idWell = telemetryService.GetIdWellByTelemetryUid(uid);
|
||||||
if (idWell is null)
|
if (idWell is null)
|
||||||
return BadRequest($"Wrong uid {uid}");
|
return BadRequest($"Wrong uid {uid}");
|
||||||
#warning implement Process map get method
|
|
||||||
return Ok(Enumerable.Empty<ProcessMapPlanDto>());
|
return Ok(Enumerable.Empty<ProcessMapPlanDto>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +99,6 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
/// <param name="wellId"></param>
|
/// <param name="wellId"></param>
|
||||||
/// /// <param name="token"></param>
|
/// /// <param name="token"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="NotImplementedException"></exception>
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("getReportFile/{wellId}")]
|
[Route("getReportFile/{wellId}")]
|
||||||
[ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK)]
|
[ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK)]
|
||||||
@ -132,7 +136,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Добавить запись
|
/// Добавить запись плановой РТК
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value"></param>
|
/// <param name="value"></param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
@ -147,7 +151,7 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Редактировать запись по id
|
/// Редактировать запись по id плановой РТК
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">запись</param>
|
/// <param name="value">запись</param>
|
||||||
/// <param name="token"></param>
|
/// <param name="token"></param>
|
||||||
@ -161,6 +165,77 @@ namespace AsbCloudWebApi.Controllers
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Возвращает шаблон файла импорта плановой РТК
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Запрашиваемый файл</returns>
|
||||||
|
[HttpGet]
|
||||||
|
[Route("template")]
|
||||||
|
[ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK)]
|
||||||
|
public async Task<IActionResult> GetTemplateAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var stream = await processMapPlanImportService.GetExcelTemplateStreamAsync(cancellationToken);
|
||||||
|
var fileName = "ЕЦП_шаблон_файла_РТК.xlsx";
|
||||||
|
return File(stream, "application/octet-stream", fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Импортирует плановой РТК из excel (xlsx) файла
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idWell">Id скважины</param>
|
||||||
|
/// <param name="file">Загружаемый файл</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost]
|
||||||
|
[Route("import")]
|
||||||
|
public async Task<IActionResult> ImportAsync(int idWell,
|
||||||
|
[Required] IFormFile file,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
int? idUser = User.GetUserId();
|
||||||
|
|
||||||
|
if (idUser is null)
|
||||||
|
return Forbid();
|
||||||
|
|
||||||
|
if (Path.GetExtension(file.FileName).ToLower() != ".xlsx")
|
||||||
|
return BadRequest("Требуется xlsx файл.");
|
||||||
|
|
||||||
|
using Stream stream = file.OpenReadStream();
|
||||||
|
|
||||||
|
await processMapPlanImportService.ImportAsync(idWell,
|
||||||
|
idUser.Value,
|
||||||
|
stream,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Экспорт плановой РТК в excel
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idWell">Id скважины</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet]
|
||||||
|
[Route("export")]
|
||||||
|
[ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK)]
|
||||||
|
public async Task<IActionResult> ExportAsync([FromQuery] int idWell, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
int? idUser = User.GetUserId();
|
||||||
|
|
||||||
|
if (idUser is null)
|
||||||
|
return Forbid();
|
||||||
|
|
||||||
|
var well = await wellService.GetOrDefaultAsync(idWell, cancellationToken);
|
||||||
|
|
||||||
|
if (well is null)
|
||||||
|
return NoContent();
|
||||||
|
|
||||||
|
var stream = await processMapPlanImportService.ExportAsync(idWell, cancellationToken);
|
||||||
|
var fileName = $"РТК-план по скважине {well.Caption} куст {well.Cluster}.xlsx";
|
||||||
|
return File(stream, "application/octet-stream", fileName);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task NotifyUsersBySignalR(int idWell, CancellationToken token)
|
private async Task NotifyUsersBySignalR(int idWell, CancellationToken token)
|
||||||
{
|
{
|
||||||
var dtos = await service.GetAllAsync(idWell, null, token);
|
var dtos = await service.GetAllAsync(idWell, null, token);
|
||||||
|
Loading…
Reference in New Issue
Block a user