diff --git a/AsbCloudApp/Data/ProcessMap/ProcessMapReportDto.cs b/AsbCloudApp/Data/ProcessMap/ProcessMapReportDto.cs index 6bc8ace1..514de0f9 100644 --- a/AsbCloudApp/Data/ProcessMap/ProcessMapReportDto.cs +++ b/AsbCloudApp/Data/ProcessMap/ProcessMapReportDto.cs @@ -27,7 +27,7 @@ namespace AsbCloudApp.Data.ProcessMap /// на начало интервала /// /// - public DateTimeOffset DateStart { get; set; } + public DateTime DateStart { get; set; } /// /// Время мех бурения, ч diff --git a/AsbCloudApp/Repositories/ILimitingParameterRepository.cs b/AsbCloudApp/Repositories/ILimitingParameterRepository.cs index fcce0759..a9b61823 100644 --- a/AsbCloudApp/Repositories/ILimitingParameterRepository.cs +++ b/AsbCloudApp/Repositories/ILimitingParameterRepository.cs @@ -20,6 +20,15 @@ namespace AsbCloudApp.Repositories /// /// Task> GetLimitingParametersAsync(LimitingParameterRequest request, WellDto wellDto, CancellationToken token); + + /// + /// Получение списка ограничивающих параметров по идентификатору скважины + /// + /// + /// + /// + /// + /// Task> GetLimitingParametersAsync(LimitingParameterRequest request, int idTelemetry, double timezoneHours, CancellationToken token); } #nullable disable diff --git a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportService.cs b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportService.cs index c8357a2a..db5c306e 100644 --- a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportService.cs +++ b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportService.cs @@ -1,7 +1,5 @@ using AsbCloudApp.Data.ProcessMap; using AsbCloudApp.Services; -using AsbCloudDb.Model; -using AsbCloudInfrastructure.Services.DailyReport; using ClosedXML.Excel; using System.Collections.Generic; using System.IO; @@ -14,14 +12,13 @@ namespace AsbCloudInfrastructure.Services.ProcessMap #nullable enable public class ProcessMapReportService : IProcessMapReportService { - private readonly IAsbCloudDbContext context; - private readonly IProcessMapRepository processMapRepository; + const int firstColumn = 2; + const int headerRowsCount = 3; + private readonly IProcessMapService processMapService; - public ProcessMapReportService(IAsbCloudDbContext context, IProcessMapRepository processMapRepository, IProcessMapService processMapService) + public ProcessMapReportService(IProcessMapService processMapService) { - this.context = context; - this.processMapRepository = processMapRepository; this.processMapService = processMapService; } @@ -40,42 +37,164 @@ namespace AsbCloudInfrastructure.Services.ProcessMap return memoryStream; } - private static void FillProcessMapToWorkbook(XLWorkbook workbook, IEnumerable dto) + private static void FillProcessMapToWorkbook(XLWorkbook workbook, IEnumerable data) { - var rowsCount = 4; - var columnCount = 2; - var countMerge = 27; - var sheet = workbook.Worksheets.FirstOrDefault(); if (sheet is null) return; - - - sheet.Row(rowsCount).Cell(columnCount).Value = "saddadasdasdasds"; - sheet.Range(rowsCount, columnCount, rowsCount, countMerge).Row(1).Merge(); - SetBorder(sheet.Row(rowsCount).Cell(columnCount).Style); - - rowsCount++; - sheet.Row(rowsCount).Cell(columnCount).Value = 2; - sheet.Row(rowsCount).Cell(columnCount).Value = 3; - columnCount++; - sheet.Row(rowsCount).Cell(columnCount).Value = 4; + var dataBySections = data.GroupBy(p => p.IdWellSectionType); + FillSheet(sheet, dataBySections); } - private Stream GetExcelTemplateStream() + private static void FillSheet(IXLWorksheet sheet, IEnumerable> dataBySections) + { + var startRow = headerRowsCount + 1; + foreach (var sectionData in dataBySections) + { + if(sectionData.Any()) + startRow = FillSection(sheet, sectionData, startRow); + } + } + + private static int FillSection(IXLWorksheet sheet, IGrouping sectionData, int row) + { + var rowStart = row; + const int lastHeaderColumn = 27; + + var sectionName = sectionData.FirstOrDefault()?.WellSectionTypeName + ?? sectionData.Key.ToString(); + + sheet.Range(row, firstColumn, row, lastHeaderColumn) + .Merge() + .FirstCell() + .SetVal(sectionName); + + row++; + + foreach (var interval in sectionData) + row = FillIntervalData(sheet, interval, row); + + var sectionStyle = sheet.Range(rowStart, firstColumn, row - 1, lastHeaderColumn).Style; + SetBorders(sectionStyle); + return row; + } + + private static int FillIntervalData(IXLWorksheet sheet, ProcessMapReportDto interval, int row) + { + const int columnDepth = firstColumn; + const int columnDate = firstColumn + 1; + const int columnRopTime = firstColumn + 2; + const int columnMode = firstColumn + 3; + + int rowRotor = row; + int rowSlide = row + 1; + + sheet.Range(rowRotor, columnDepth, rowSlide, columnDepth) + .Merge().FirstCell() + .SetVal(interval.DepthStart, "0.0"); + + sheet.Range(rowRotor, columnDate, rowSlide, columnDate) + .Merge().FirstCell() + .SetVal(interval.DateStart); + + sheet.Range(rowRotor, columnRopTime, rowSlide, columnRopTime) + .Merge().FirstCell() + .SetVal(interval.MechDrillingHours); + + row = FillIntervalModeData(sheet, "Ротор", interval.Rotor, columnMode, row); + row = FillIntervalModeData(sheet, "Слайд", interval.Rotor, columnMode, row); + + return row; + } + + private static int FillIntervalModeData(IXLWorksheet sheet, string modeName, ProcessMapReportRowDto modeData, int column, int row) + { + int columnDeltaDepth = column + 1; + int columnPressure = columnDeltaDepth + 1; + int columnLoad = columnPressure + 5; + int columnTorque = columnLoad + 5; + int columnSpeed = columnTorque + 5; + int columnUsage = columnSpeed + 4; + int columnRop = columnUsage + 1; + + sheet.Cell(row, column) + .SetVal(modeName); + + sheet.Cell(row, columnDeltaDepth) + .SetVal(modeData.DeltaDepth); + + FillIntervalModeDataParam(sheet, modeData.PressureDiff, columnPressure, row); + FillIntervalModeDataParam(sheet, modeData.AxialLoad, columnLoad, row); + FillIntervalModeDataParam(sheet, modeData.TopDriveTorque, columnTorque, row); + FillIntervalModeDataSpeed(sheet, modeData.SpeedLimit, columnSpeed, row); + + sheet.Cell(row, columnUsage) + .SetVal(modeData.Usage); + + sheet.Cell(row, columnRop) + .SetVal(modeData.Rop); + + return row + 1; + } + + private static void FillIntervalModeDataParam(IXLWorksheet sheet, ProcessMapReportParamsDto dataParam, int column, int row) + { + const int columnOffsetSpPlan = 0; + const int columnOffsetSpFact = 1; + const int columnOffsetFact = 2; + const int columnOffsetLimit = 3; + const int columnOffsetPercent = 4; + + sheet.Cell(row, column + columnOffsetSpPlan) + .SetVal(dataParam.SetpointPlan); + + sheet.Cell(row, column + columnOffsetSpFact) + .SetVal(dataParam.SetpointFact); + + sheet.Cell(row, column + columnOffsetFact) + .SetVal(dataParam.Fact); + + sheet.Cell(row, column + columnOffsetLimit) + .SetVal(dataParam.Limit); + + sheet.Cell(row, column + columnOffsetPercent) + .SetVal(dataParam.PercDrillingSetpoint); + } + + private static void FillIntervalModeDataSpeed(IXLWorksheet sheet, ProcessMapReportParamsDto dataParam, int column, int row) + { + const int columnOffsetSpPlan = 0; + const int columnOffsetSpFact = 1; + const int columnOffsetFact = 2; + const int columnOffsetPercent = 3; + + sheet.Cell(row, column + columnOffsetSpPlan) + .SetVal(dataParam.SetpointPlan); + + sheet.Cell(row, column + columnOffsetSpFact) + .SetVal(dataParam.SetpointFact); + + sheet.Cell(row, column + columnOffsetFact) + .SetVal(dataParam.Fact); + + sheet.Cell(row, column + columnOffsetPercent) + .SetVal(dataParam.PercDrillingSetpoint); + } + + private static Stream GetExcelTemplateStream() { var stream = System.Reflection.Assembly.GetExecutingAssembly() .GetManifestResourceStream("AsbCloudInfrastructure.Services.ProcessMap.ProcessMapReportTemplate.xlsx"); return stream!; } - private static IXLStyle SetBorder(IXLStyle style) + private static IXLStyle SetBorders(IXLStyle style) { - style.Border.RightBorder = XLBorderStyleValues.Medium; - style.Border.LeftBorder = XLBorderStyleValues.Medium; - style.Border.TopBorder = XLBorderStyleValues.Medium; - style.Border.BottomBorder = XLBorderStyleValues.Medium; - style.Border.InsideBorder = XLBorderStyleValues.Medium; + style.Border.RightBorder = XLBorderStyleValues.Thin ; + style.Border.LeftBorder = XLBorderStyleValues.Thin; + style.Border.TopBorder = XLBorderStyleValues.Thin ; + style.Border.BottomBorder = XLBorderStyleValues.Thin ; + style.Border.InsideBorder = XLBorderStyleValues.Thin ; return style; } } diff --git a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportTemplate.xlsx b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportTemplate.xlsx index 52e91ccc..64b328cd 100644 Binary files a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportTemplate.xlsx and b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapReportTemplate.xlsx differ diff --git a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapService.cs b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapService.cs index c29ffd8e..3342b24c 100644 --- a/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapService.cs +++ b/AsbCloudInfrastructure/Services/ProcessMap/ProcessMapService.cs @@ -1,77 +1,106 @@ using AsbCloudApp.Data; using AsbCloudApp.Data.ProcessMap; using AsbCloudApp.Data.SAUB; +using AsbCloudApp.Exceptions; using AsbCloudApp.Repositories; using AsbCloudApp.Requests; using AsbCloudApp.Services; +using AsbCloudApp.Services.Subsystems; using AsbCloudDb.Model; +using AsbCloudApp.Data.Subsystems; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using AsbCloudDb.Model.Subsystems; +using System.Reflection.Metadata.Ecma335; +using AsbCloudInfrastructure.Services.Subsystems; namespace AsbCloudInfrastructure.Services.ProcessMap { #nullable enable public partial class ProcessMapService : IProcessMapService { - private readonly IAsbCloudDbContext db; + private readonly IWellService wellService; private readonly IWellOperationRepository wellOperationRepository; private readonly IProcessMapRepository processMapRepository; - private readonly ITelemetryService telemetryService; private readonly ITelemetryDataSaubService telemetryDataSaubService; private readonly ILimitingParameterRepository limitingParameterRepository; + private readonly ISubsystemOperationTimeService subsystemOperationTimeService; public ProcessMapService( - IAsbCloudDbContext db, + IWellService wellService, IWellOperationRepository wellOperationService, IProcessMapRepository processMapRepository, - ITelemetryService telemetryService, ITelemetryDataSaubService telemetryDataSaubService, - ILimitingParameterRepository limitingParameterRepository) + ILimitingParameterRepository limitingParameterRepository, + ISubsystemOperationTimeService subsystemOperationTimeService) { - this.db = db; + this.wellService = wellService; this.wellOperationRepository = wellOperationService; this.processMapRepository = processMapRepository; - this.telemetryService = telemetryService; this.telemetryDataSaubService = telemetryDataSaubService; this.limitingParameterRepository = limitingParameterRepository; + this.subsystemOperationTimeService = subsystemOperationTimeService; } public async Task> GetProcessMapAsync(int idWell, CancellationToken token) { - var operationsRequest = new WellOperationRequest - { - IdWell = idWell, - OperationCategoryIds = WellOperationCategory.MechanicalDrillingSubIds, - OperationType = WellOperation.IdOperationTypeFact, - SortFields = new[]{ nameof(WellOperation.DateStart) } - }; - var allFactDrillingOperations = (await wellOperationRepository.GetAsync(operationsRequest, token)) - .Where(o => o.DepthEnd > o.DepthStart); - - var processMapDtos = (await processMapRepository.GetByIdWellAsync(idWell, token))!; + var well = wellService.GetOrDefault(idWell) + ?? throw new ArgumentInvalidException("idWell not found", nameof(idWell)); + var idTelemetry = well.IdTelemetry + ?? throw new ArgumentInvalidException("telemetry by well not found", nameof(idWell)); - var idTelemetry = telemetryService.GetOrDefaultIdTelemetryByIdWell(idWell)!.Value; - IEnumerable telemetryDataStat = await telemetryDataSaubService.GetTelemetryDataStatAsync(idTelemetry, token); - - var result = allFactDrillingOperations + var processMap = (await processMapRepository.GetByIdWellAsync(idWell, token))!; + var factDrillingOperations = await GetFactDrillingOperationsAsync(idWell, token); + var telemetryDataStat = await telemetryDataSaubService.GetTelemetryDataStatAsync(idTelemetry, token); + var limitingParameters = await limitingParameterRepository.GetLimitingParametersAsync(new(), well, token); + var subsystemsOperationTime = await GetOperationTimeAsync(idWell, token); + + var result = factDrillingOperations .GroupBy(o => o.IdWellSectionType) .SelectMany(sectionOperations => { - var sectionProcessMap = processMapDtos.Where(p => p.IdWellSectionType == sectionOperations.Key); - return HandleSections(sectionOperations, sectionProcessMap, telemetryDataStat); + var sectionProcessMap = processMap.Where(p => p.IdWellSectionType == sectionOperations.Key); + return HandleSection(sectionOperations, sectionProcessMap, telemetryDataStat, limitingParameters, subsystemsOperationTime!); }) .ToList(); return result; } - private static IEnumerable HandleSections( + private Task?> GetOperationTimeAsync(int idWell, CancellationToken token) + { + var request = new SubsystemOperationTimeRequest + { + IdWell = idWell, + IdsSubsystems = new int[] { SubsystemOperationTimeService.IdSubsystemAKB, SubsystemOperationTimeService.IdSubsystemSpin }, + }; + return subsystemOperationTimeService.GetOperationTimeAsync(request, token); + } + + private async Task> GetFactDrillingOperationsAsync(int idWell, CancellationToken token) + { + var operationsRequest = new WellOperationRequest + { + IdWell = idWell, + OperationCategoryIds = WellOperationCategory.MechanicalDrillingSubIds, + OperationType = WellOperation.IdOperationTypeFact, + SortFields = new[] { nameof(WellOperation.DateStart) } + }; + + var allFactDrillingOperations = await wellOperationRepository.GetAsync(operationsRequest, token); + var factDrillingOperations = allFactDrillingOperations.Where(o => o.DepthEnd > o.DepthStart); + return factDrillingOperations; + } + + private static IEnumerable HandleSection( IEnumerable sectionOperations, IEnumerable sectionProcessMap, - IEnumerable telemetryDataStat) + IEnumerable telemetryDataStat, + IEnumerable limitingParameters, + IEnumerable subsystemsOperationTime) { var minDepth = sectionOperations.Min(o => o.DepthStart); var maxDepth = sectionOperations.Max(o => o.DepthEnd); @@ -80,7 +109,7 @@ namespace AsbCloudInfrastructure.Services.ProcessMap var result = new ProcessMapReportDto[depthIntervals.Length]; for (var i = 0; i < depthIntervals.Length; i++ ) - result[i] = MakeProcessMapReportDto(depthIntervals[i], sectionOperations, sectionProcessMap, telemetryDataStat); + result[i] = MakeProcessMapReportDto(depthIntervals[i], sectionOperations, sectionProcessMap, telemetryDataStat, limitingParameters, subsystemsOperationTime); return result; } @@ -89,7 +118,9 @@ namespace AsbCloudInfrastructure.Services.ProcessMap (double min, double max) depthInterval, IEnumerable sectionOperations, IEnumerable sectionProcessMap, - IEnumerable telemetryDataStat) + IEnumerable telemetryDataStat, + IEnumerable limitingParameters, + IEnumerable subsystemsOperationTime) { var dto = new ProcessMapReportDto{ DepthStart = depthInterval.min @@ -98,22 +129,25 @@ namespace AsbCloudInfrastructure.Services.ProcessMap var intervalOperations = sectionOperations.Where(o => o.DepthEnd >= depthInterval.min && o.DepthStart <= depthInterval.max); var intervalProcessMap = sectionProcessMap.Where(map => map.DepthEnd >= depthInterval.min && map.DepthStart <= depthInterval.max); var intervalTelemetryDataStat = CalcIntervalTelemetryDataStat(depthInterval, telemetryDataStat); + var intervalLimitingParametrs = limitingParameters.Where(l => l.DepthEnd >= depthInterval.min && l.DepthStart <= depthInterval.max); + var intervalSubsystemsOperationTime = subsystemsOperationTime.Where(o => o.DepthEnd >= depthInterval.min && o.DepthStart <= depthInterval.max); - if (intervalOperations.Any()) + var firstIntervalOperation = intervalOperations.FirstOrDefault(); + if (firstIntervalOperation is not null) { - var firstIntervalOperation = intervalOperations.First(); - var slideOperations = intervalOperations.Where(o => o.IdCategory == WellOperationCategory.IdSlide); - var rotorOperations = intervalOperations.Where(o => o.IdCategory == WellOperationCategory.IdRotor); - - dto.DepthStart = depthInterval.min; dto.DateStart = GetInterpolatedDate(firstIntervalOperation, depthInterval.min); dto.IdWell = firstIntervalOperation.IdWell; dto.IdWellSectionType = firstIntervalOperation.IdWellSectionType; dto.WellSectionTypeName = firstIntervalOperation.WellSectionTypeName; - dto.MechDrillingHours = CalcHours(depthInterval, sectionOperations); - dto.Slide = CalcDrillModeStat(depthInterval, slideOperations, intervalProcessMap, intervalTelemetryDataStat); - dto.Rotor = CalcDrillModeStat(depthInterval, rotorOperations, intervalProcessMap, intervalTelemetryDataStat); - } + dto.MechDrillingHours = CalcHours(depthInterval, intervalOperations); + } + + var slideOperations = intervalOperations.Where(o => o.IdCategory == WellOperationCategory.IdSlide); + var rotorOperations = intervalOperations.Where(o => o.IdCategory == WellOperationCategory.IdRotor); + + dto.Slide = CalcDrillModeStat(depthInterval, slideOperations, intervalProcessMap, intervalTelemetryDataStat, intervalLimitingParametrs, intervalSubsystemsOperationTime); + dto.Rotor = CalcDrillModeStat(depthInterval, rotorOperations, intervalProcessMap, intervalTelemetryDataStat, intervalLimitingParametrs, intervalSubsystemsOperationTime); + return dto; } @@ -169,22 +203,26 @@ namespace AsbCloudInfrastructure.Services.ProcessMap (double min, double max) depthInterval, IEnumerable intervalModeOperations, IEnumerable intervalProcessMap, - TelemetryDataSaubStatDto? telemetryDataStat) + TelemetryDataSaubStatDto? telemetryDataStat, + IEnumerable intervalLimitingParametrs, + IEnumerable intervalSubsystemsOperationTime) { var dto = new ProcessMapReportRowDto(); if (intervalModeOperations.Any()) { var deltaDepth = CalcDeltaDepth(depthInterval, intervalModeOperations); dto.DeltaDepth = deltaDepth; - dto.Rop = deltaDepth / CalcHours(depthInterval, intervalModeOperations); + dto.Rop = deltaDepth / CalcHours(depthInterval, intervalModeOperations); + }; + if (intervalProcessMap.Any()) + { var processMapFirst = intervalProcessMap.First(); - dto.PressureDiff.SetpointPlan = processMapFirst.Pressure.Plan; dto.AxialLoad.SetpointPlan = processMapFirst.AxialLoad.Plan; dto.TopDriveTorque.SetpointPlan = processMapFirst.TopDriveTorque.Plan; - dto.SpeedLimit.SetpointPlan = double.NaN; - }; + //dto.SpeedLimit.SetpointPlan = null; + } if (telemetryDataStat is not null) { @@ -199,6 +237,46 @@ namespace AsbCloudInfrastructure.Services.ProcessMap dto.TopDriveTorque.SetpointFact = telemetryDataStat.RotorTorqueSp; dto.TopDriveTorque.Fact = telemetryDataStat.RotorTorque; dto.TopDriveTorque.Limit = telemetryDataStat.RotorTorqueLimitMax; + + dto.SpeedLimit.SetpointFact = telemetryDataStat.BlockSpeedSp; + dto.SpeedLimit.Fact = telemetryDataStat.BlockSpeed; + //dto.SpeedLimit.Limit = mull; + } + + if(intervalLimitingParametrs.Any()) + { + const int idLimParamRop = 1; + const int idLimParamPressure = 2; + const int idLimParamAxialLoad = 3; + const int idLimParamTorque = 4; + + var intervalLimitingParametrsStat = intervalLimitingParametrs + .GroupBy(p => p.IdFeedRegulator) + .Select(g => new + { + IdLimParam = g.Key, + SumDepth = g.Sum(p => p.DepthEnd - p.DepthStart), + }); + + var totalDepth = intervalLimitingParametrsStat + .Sum(s => s.SumDepth); + + dto.AxialLoad.PercDrillingSetpoint = intervalLimitingParametrsStat + .FirstOrDefault(s => s.IdLimParam == idLimParamAxialLoad)?.SumDepth / totalDepth; + + dto.PressureDiff.PercDrillingSetpoint = intervalLimitingParametrsStat + .FirstOrDefault(s => s.IdLimParam == idLimParamPressure)?.SumDepth / totalDepth; + + dto.TopDriveTorque.PercDrillingSetpoint = intervalLimitingParametrsStat + .FirstOrDefault(s => s.IdLimParam == idLimParamTorque)?.SumDepth / totalDepth; + + dto.SpeedLimit.PercDrillingSetpoint = intervalLimitingParametrsStat + .FirstOrDefault(s => s.IdLimParam == idLimParamRop)?.SumDepth / totalDepth; + } + + if (intervalSubsystemsOperationTime.Any() && dto.DeltaDepth > 0) + { + dto.Usage = intervalSubsystemsOperationTime.Sum(t => t.DepthEnd - t.DepthStart) / dto.DeltaDepth.Value; } return dto; @@ -242,9 +320,6 @@ namespace AsbCloudInfrastructure.Services.ProcessMap private static DateTime GetInterpolatedDate(WellOperationDto operation, double depth) { - if (operation.DepthStart > depth) - throw new ArgumentOutOfRangeException(nameof(depth)); - var ratio = (depth - operation.DepthStart) / (operation.DepthEnd - operation.DepthStart); var deltaHours = operation.DurationHours * ratio; var interpolatedDate = operation.DateStart + TimeSpan.FromHours(deltaHours); diff --git a/AsbCloudInfrastructure/Services/ProcessMap/XLExtentions.cs b/AsbCloudInfrastructure/Services/ProcessMap/XLExtentions.cs new file mode 100644 index 00000000..7117e1cf --- /dev/null +++ b/AsbCloudInfrastructure/Services/ProcessMap/XLExtentions.cs @@ -0,0 +1,63 @@ +using ClosedXML.Excel; +using System; + +namespace AsbCloudInfrastructure.Services.ProcessMap; + +internal static class XLExtentions +{ + public static IXLCell SetVal(this IXLCell cell, object value) + { + switch (value) + { + case DateTime dateTime: + cell.SetVal(dateTime); + break; + case IFormattable formattable: + cell.SetVal(formattable); + break; + case string valueString: + cell.SetVal(valueString); + break; + default: + cell.Value = value; + break; + } + + return cell; + } + + public static IXLCell SetVal(this IXLCell cell, string value, bool adaptRowHeight = false) + { + cell.Value = value; + if (adaptRowHeight) + { + var colWidth = cell.WorksheetColumn().Width; + var maxCharsToWrap = colWidth / (0.1d * cell.Style.Font.FontSize); + if (value.Length > maxCharsToWrap) + { + var row = cell.WorksheetRow(); + var baseHeight = row.Height; + row.Height = 0.5d * baseHeight * Math.Ceiling(1d + value.Length / maxCharsToWrap); + } + } + + return cell; + } + + public static IXLCell SetVal(this IXLCell cell, DateTime value, string dateFormat = "DD.MM.YYYY HH:MM:SS") + { + cell.Value = value; + cell.DataType = XLDataType.DateTime; + cell.Style.DateFormat.Format = dateFormat; + + return cell; + } + + public static IXLCell SetVal(this IXLCell cell, IFormattable value, string format = "0.00") + { + cell.Value = value; + cell.DataType = XLDataType.Number; + cell.Style.NumberFormat.Format = format; + return cell; + } +} diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs index 7839b83b..8ec8cb10 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataSaubService.cs @@ -41,8 +41,8 @@ namespace AsbCloudInfrastructure.Services.SAUB { Count = g.Count(), - DateMin = g.Min(t => t.DateTime.UtcDateTime), - DateMax = g.Max(t => t.DateTime.UtcDateTime), + DateMin = DateTime.SpecifyKind(g.Min(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified), + DateMax = DateTime.SpecifyKind(g.Max(t => t.DateTime.UtcDateTime) + timezoneOffset, DateTimeKind.Unspecified), WellDepthMin = g.Min(t => t.WellDepth!.Value), WellDepthMax = g.Max(t => t.WellDepth!.Value),