diff --git a/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj b/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj index cdb57ae5..05875bb8 100644 --- a/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj +++ b/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj @@ -14,6 +14,7 @@ + @@ -36,6 +37,7 @@ + diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs index 5e1ea903..f1e3c84d 100644 --- a/AsbCloudInfrastructure/DependencyInjection.cs +++ b/AsbCloudInfrastructure/DependencyInjection.cs @@ -202,6 +202,7 @@ namespace AsbCloudInfrastructure services.AddScoped(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); diff --git a/AsbCloudInfrastructure/Services/ProcessMaps/Report/ProcessMapReportDataSaubStatExportService.cs b/AsbCloudInfrastructure/Services/ProcessMaps/Report/ProcessMapReportDataSaubStatExportService.cs new file mode 100644 index 00000000..1bee0843 --- /dev/null +++ b/AsbCloudInfrastructure/Services/ProcessMaps/Report/ProcessMapReportDataSaubStatExportService.cs @@ -0,0 +1,260 @@ +using AsbCloudApp.Data.ProcessMaps.Report; +using AsbCloudApp.Requests; +using AsbCloudApp.Services; +using AsbCloudApp.Services.ProcessMaps.WellDrilling; +using ClosedXML.Excel; +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; + +namespace AsbCloudInfrastructure.Services.ProcessMaps.Report +{ + public class ProcessMapReportDataSaubStatExportService : IProcessMapReportWellDrillingExportService + { + const int firstColumn = 2; + const int lastColumn = 35; + + const int headerRowsCount = 5; + + private readonly IWellService wellService; + private readonly IProcessMapReportDataSaubStatService processMapReportDataSaubStatService; + private readonly string TemplateName = "ProcessMapReportDataSaubStatTemplate.xlsx"; + + public ProcessMapReportDataSaubStatExportService(IWellService wellService, + IProcessMapReportDataSaubStatService processMapReportDataSaubStatService) + { + this.wellService = wellService; + this.processMapReportDataSaubStatService = processMapReportDataSaubStatService; + } + + public async Task<(string Name, Stream File)?> ExportAsync(int idWell, CancellationToken cancellationToken) + { + var well = await wellService.GetOrDefaultAsync(idWell, cancellationToken); + + if (well is null) + return null; + + var stream = Assembly.GetExecutingAssembly().GetTemplateCopyStream(TemplateName); + using var workbook = new XLWorkbook(stream); + + var request = new DataSaubStatRequest(); + var data = await processMapReportDataSaubStatService.GetAsync(idWell, request, cancellationToken); + + FillProcessMapToWorkbook(workbook, data); + + MemoryStream memoryStream = new(); + workbook.SaveAs(memoryStream, new SaveOptions { }); + memoryStream.Seek(0, SeekOrigin.Begin); + + var name = $"РТК бурение. Отчёт по скважине {well.Caption} куст {well.Cluster}.xlsx"; + + return (name, memoryStream); + } + + private static void FillProcessMapToWorkbook(XLWorkbook workbook, + IEnumerable data) + { + const string sheetName = "Отчёт"; + + var sheet = workbook.GetWorksheet(sheetName); + + var startRow = headerRowsCount + 1; + foreach (var item in data) + { + startRow = FillRow(sheet, item, startRow); + } + } + + + private static int FillRow(IXLWorksheet sheet, ProcessMapReportDataSaubStatDto item, + int startRow) + { + var endRow = FillIntervalData(sheet, item, startRow); + + var sectionStyle = sheet.Range(startRow, firstColumn, endRow - 1, lastColumn).Style; + SetStyle(sectionStyle); + return endRow; + } + + private static int FillIntervalData(IXLWorksheet sheet, ProcessMapReportDataSaubStatDto interval, int row) + { + const int columnSection = firstColumn + 1; + const int columnDepthStart = firstColumn + 2; + const int columnDepthEnd = firstColumn + 3; + const int columnDeltaDepth = firstColumn + 4; + const int columnDrilledTime = firstColumn + 5; + const int columnMode = firstColumn + 6; + + double? deltaDepth = interval.DeltaDepth.HasValue + ? Math.Round(interval.DeltaDepth.Value, 1) + : null; + + sheet.Cell(row, firstColumn).SetCellValue(interval.DateStart, "DD.MM.YYYY HH:MM"); + sheet.Cell(row, columnSection).SetCellValue(interval.WellSectionTypeName); + sheet.Cell(row, columnDepthStart).SetCellValue(Math.Round(interval.DepthStart, 2)); + sheet.Cell(row, columnDepthEnd).SetCellValue(Math.Round(interval.DepthEnd, 2)); + sheet.Cell(row, columnDeltaDepth).SetCellValue(deltaDepth); + sheet.Cell(row, columnDrilledTime).SetCellValue(Math.Round(interval.DrilledTime, 2)); + sheet.Cell(row, columnMode).SetCellValue(interval.DrillingMode); + + row = FillIntervalModeData(sheet, interval, columnMode, row); + + return row; + } + + private static int FillIntervalModeData(IXLWorksheet sheet, ProcessMapReportDataSaubStatDto modeData, + int column, int row) + { + int columnPressure = column + 1; + int columnLoad = columnPressure + 5; + int columnTorque = columnLoad + 5; + int columnSpeed = columnTorque + 5; + int columnTopDriveSpeed = columnSpeed + 4; + int columnFlow = columnTopDriveSpeed + 2; + int columnRopPlan = columnFlow + 3; + int columnRopFact = columnRopPlan + 1; + + FillIntervalModeDataParam(sheet, modeData.PressureDiff, columnPressure, row); + FillIntervalModeDataParam(sheet, modeData.AxialLoad, columnLoad, row); + FillIntervalModeDataParam(sheet, modeData.TopDriveTorque, columnTorque, row); + FillIntervalModeDataSpeed(sheet, modeData.SpeedLimit, columnSpeed, row); + FillIntervalModeTopDriveSpeed(sheet, modeData.TopDriveSpeed, columnTopDriveSpeed, row); + FillIntervalModeFlow(sheet, modeData.Flow, columnFlow, row); + + double? ropPlan = modeData.Rop.Plan.HasValue + ? Math.Round(modeData.Rop.Plan.Value, 1) + : null; + + double? ropFact = modeData.Rop.Fact.HasValue + ? Math.Round(modeData.Rop.Fact.Value, 1) + : null; + + sheet.Cell(row, columnRopPlan).SetCellValue(ropPlan); + sheet.Cell(row, columnRopFact).SetCellValue(ropFact); + + return row + 1; + } + + private static void FillIntervalModeDataParam(IXLWorksheet sheet, + ProcessMapReportDataSaubStatParamsDto dataParam, int column, int row) + { + const int columnOffsetSpPlan = 0; + const int columnOffsetSpFact = 1; + const int columnOffsetFact = 2; + const int columnOffsetLimit = 3; + const int columnOffsetPercent = 4; + + double? setpointPlan = dataParam.SetpointPlan.HasValue + ? Math.Round(dataParam.SetpointPlan.Value) + : null; + + double? setpointFact = dataParam.SetpointFact.HasValue + ? Math.Round(dataParam.SetpointFact.Value, 1) + : null; + + double? factWavg = dataParam.FactWavg.HasValue + ? Math.Round(dataParam.FactWavg.Value, 1) + : null; + + double? limit = dataParam.Limit.HasValue + ? Math.Round(dataParam.Limit.Value, 1) + : null; + + double? setpointUsage = dataParam.SetpointUsage.HasValue + ? Math.Round(dataParam.SetpointUsage.Value, 1) + : null; + + sheet.Cell(row, column + columnOffsetSpPlan).SetCellValue(setpointPlan); + sheet.Cell(row, column + columnOffsetSpFact).SetCellValue(setpointFact); + sheet.Cell(row, column + columnOffsetFact).SetCellValue(factWavg); + sheet.Cell(row, column + columnOffsetLimit).SetCellValue(limit); + sheet.Cell(row, column + columnOffsetPercent).SetCellValue(setpointUsage); + } + + private static void FillIntervalModeDataSpeed(IXLWorksheet sheet, + ProcessMapReportDataSaubStatParamsDto dataParam, int column, int row) + { + const int columnOffsetSpPlan = 0; + const int columnOffsetSpFact = 1; + const int columnOffsetFact = 2; + const int columnOffsetPercent = 3; + + double? setpointPlan = dataParam.SetpointPlan.HasValue + ? Math.Round(dataParam.SetpointPlan.Value) + : null; + + double? setpointFact = dataParam.SetpointFact.HasValue + ? Math.Round(dataParam.SetpointFact.Value, 1) + : null; + + double? factWavg = dataParam.FactWavg.HasValue + ? Math.Round(dataParam.FactWavg.Value, 1) + : null; + + double? setpointUsage = dataParam.SetpointUsage.HasValue + ? Math.Round(dataParam.SetpointUsage.Value, 1) + : null; + + sheet.Cell(row, column + columnOffsetSpPlan).SetCellValue(setpointPlan); + sheet.Cell(row, column + columnOffsetSpFact).SetCellValue(setpointFact); + sheet.Cell(row, column + columnOffsetFact).SetCellValue(factWavg); + sheet.Cell(row, column + columnOffsetPercent).SetCellValue(setpointUsage); + } + + private static void FillIntervalModeTopDriveSpeed(IXLWorksheet sheet, + ProcessMapReportDataSaubStatParamsDto dataParam, int column, int row) + { + const int columnOffsetSpPlan = 0; + const int columnOffsetFact = 1; + + double? setpointPlan = dataParam.SetpointPlan.HasValue + ? Math.Round(dataParam.SetpointPlan.Value) + : null; + + double? factWavg = dataParam.FactWavg.HasValue + ? Math.Round(dataParam.FactWavg.Value, 1) + : null; + + sheet.Cell(row, column + columnOffsetSpPlan).SetCellValue(setpointPlan); + sheet.Cell(row, column + columnOffsetFact).SetCellValue(factWavg); + } + + private static void FillIntervalModeFlow(IXLWorksheet sheet, + ProcessMapReportDataSaubStatParamsDto dataParam, int column, int row) + { + const int columnOffsetSpPlan = 0; + const int columnOffsetFact = 1; + const int columnOffsetLimit = 2; + + double? setpointPlan = dataParam.SetpointPlan.HasValue + ? Math.Round(dataParam.SetpointPlan.Value) + : null; + + double? factWavg = dataParam.FactWavg.HasValue + ? Math.Round(dataParam.FactWavg.Value, 1) + : null; + + double? limit = dataParam.Limit.HasValue + ? Math.Round(dataParam.Limit.Value, 1) + : null; + + sheet.Cell(row, column + columnOffsetSpPlan).SetCellValue(setpointPlan); + sheet.Cell(row, column + columnOffsetFact).SetCellValue(factWavg); + sheet.Cell(row, column + columnOffsetLimit).SetCellValue(limit); + } + + private static void SetStyle(IXLStyle style) + { + style.Border.RightBorder = XLBorderStyleValues.Thin; + style.Border.LeftBorder = XLBorderStyleValues.Thin; + style.Border.TopBorder = XLBorderStyleValues.Thin; + style.Border.BottomBorder = XLBorderStyleValues.Thin; + style.Border.InsideBorder = XLBorderStyleValues.Thin; + + style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; + } + } +} diff --git a/AsbCloudInfrastructure/Services/ProcessMaps/Report/ProcessMapReportDataSaubStatTemplate.xlsx b/AsbCloudInfrastructure/Services/ProcessMaps/Report/ProcessMapReportDataSaubStatTemplate.xlsx new file mode 100644 index 00000000..063659a8 Binary files /dev/null and b/AsbCloudInfrastructure/Services/ProcessMaps/Report/ProcessMapReportDataSaubStatTemplate.xlsx differ diff --git a/AsbCloudInfrastructure/XLExtentions.cs b/AsbCloudInfrastructure/XLExtentions.cs index 0aeeca00..5b9517e4 100644 --- a/AsbCloudInfrastructure/XLExtentions.cs +++ b/AsbCloudInfrastructure/XLExtentions.cs @@ -21,7 +21,17 @@ public static class XLExtentions return cell; } - public static IXLCell SetHyperlink(this IXLCell cell, string link) + public static IXLCell SetCellValue(this IXLCell cell, T value, string format) + { + if (typeof(T) == typeof(DateTime)) + cell.Style.DateFormat.Format = format; + + cell.Value = XLCellValue.FromObject(value); + + return cell; + } + + public static IXLCell SetHyperlink(this IXLCell cell, string link) { cell.SetHyperlink(new XLHyperlink(link)); diff --git a/AsbCloudWebApi/Controllers/ProcessMaps/ProcessMapWellDrillingController.cs b/AsbCloudWebApi/Controllers/ProcessMaps/ProcessMapWellDrillingController.cs index 857e4a68..9b189e87 100644 --- a/AsbCloudWebApi/Controllers/ProcessMaps/ProcessMapWellDrillingController.cs +++ b/AsbCloudWebApi/Controllers/ProcessMaps/ProcessMapWellDrillingController.cs @@ -24,9 +24,8 @@ namespace AsbCloudWebApi.Controllers.ProcessMaps; /// public class ProcessMapWellDrillingController : ProcessMapBaseController { - private readonly IProcessMapReportWellDrillingService processMapReportWellDrillingService; private readonly IProcessMapReportDataSaubStatService processMapReportDataSaubStatService; - private readonly IProcessMapReportWellDrillingExportService processMapReportWellDrillingExportService; + private readonly IProcessMapReportWellDrillingExportService processMapReportDataSaubStatExportService; private readonly IProcessMapPlanImportService processMapPlanImportService; protected override string SignalRGroup => "ProcessMapWellDrilling"; @@ -34,7 +33,7 @@ public class ProcessMapWellDrillingController : ProcessMapBaseController repository, IUserRepository userRepository, - IProcessMapReportWellDrillingExportService processMapReportWellDrillingExportService, + IProcessMapReportWellDrillingExportService processMapReportDataSaubStatExportService, IProcessMapPlanImportService processMapPlanImportService, IProcessMapReportWellDrillingService processMapReportWellDrillingService, IProcessMapReportDataSaubStatService processMapReportDataSaubStatService, @@ -44,10 +43,9 @@ public class ProcessMapWellDrillingController : ProcessMapBaseController service) : base(wellService, repository, userRepository, wellSectionRepository, telemetryHubContext, telemetryService, service) { - this.processMapReportWellDrillingExportService = processMapReportWellDrillingExportService; + this.processMapReportDataSaubStatExportService = processMapReportDataSaubStatExportService; this.processMapPlanImportService = processMapPlanImportService; this.processMapReportDataSaubStatService = processMapReportDataSaubStatService; - this.processMapReportWellDrillingService = processMapReportWellDrillingService; } /// @@ -77,7 +75,7 @@ public class ProcessMapWellDrillingController : ProcessMapBaseController ExportReportAsync(int idWell, CancellationToken cancellationToken) { - var report = await processMapReportWellDrillingExportService.ExportAsync(idWell, cancellationToken); + var report = await processMapReportDataSaubStatExportService.ExportAsync(idWell, cancellationToken); if (report is null) return NoContent();