- Added t_daily_report table and related migrations;

- Added request processing service for DailyReportController. Implemented all methods except DownloadAsync.
This commit is contained in:
zikan 2022-04-26 16:45:52 +05:00
parent c31cb55d2b
commit 019c6a4db1
14 changed files with 6829 additions and 0 deletions

View File

@ -0,0 +1,216 @@
using System;
using System.Collections.Generic;
namespace AsbCloudApp.Data
{
/// <summary>
///
/// </summary>
public class DailyReportDto
{
/// <summary>
///название скважины
/// <summary>
public string WellName { get; set; }
///<summary>
///название куста
///<summary>
public string ClusterName { get; set; }
/// <summary>
///заказчик
///<summary>
public string Customer { get; set; }
/// <summary>
///подрядчик
///<summary>
public string Contractor { get; set; }
/// <summary>
///дата рапорта
///<summary>
public DateTime ReportDate { get; set; }
/// <summary>
///глубина забоя на дату начала интервала
///<summary>
public double? WellDepthIntervalStartDate { get; set; }
/// <summary>
///глубина забоя на дату окончания интервала
///<summary>
public double? WellDepthIntervalFinishDate { get; set; }
/// <summary>
///Глубина забоя по стволу на окончание отчетного периода
///<summary>
public double? BottomholeDepth { get; set; }
/// <summary>
///Глубина забоя по вертикали на дату окончания отчетного периода
///<summary>
public double? VerticalDepth { get; set; }
/// <summary>
///Зeнитный угол на дату окончания отчетного периода
///<summary>
public double? ZenithAngle { get; set; }
/// <summary>
///Азимутальный угол на дату окончания отчетного периода
///<summary>
public double? AzimuthAngle { get; set; }
/// <summary>
///ФИО бурильщиков
///<summary>
public string FirstDriller { get; set; }
/// <summary>
///ФИО бурильщиков
///<summary>
public string SecondDriller { get; set; }
/// <summary>
///Время работы АПД
///<summary>
public double? WorkTimeSAUB { get; set; }
/// <summary>
///Время работы спин мастер
///<summary>
public double? WorkTimeSpinMaster { get; set; }
/// <summary>
///Время работы торк мастер
///<summary>
public double? WorkTimeTorkMaster { get; set; }
/// <summary>
///количество метров пробуренных с включенным АПД
///<summary>
public double? PenetrationSAUB { get; set; }
/// <summary>
///количество метров пробуренных с включенным Спин мастер
///<summary>
public double? PenetrationSpinMaster { get; set; }
/// <summary>
///количество метров пробуренных с включенным торк мастер
///<summary>
public double? PenetrationTorkMaster { get; set; }
/// <summary>
///Количество запусков МСЕ
///<summary>
public int CountLaunchesMSE { get; set; }
/// <summary>
///КНБК описание
///<summary>
public string BHADescription { get; set; }
/// <summary>
///Нормативное время на одну операцию по подготовке ствола скважины к наращиванию
///<summary>
public double? StandardTimeBarrelPreparation { get; set; }
/// <summary>
///Нормативное время на одну операцию по наращиванию
///<summary>
public double? StandardTimeExtension { get; set; }
/// <summary>
///Фактическое время проработок при подготовке ствола скважины к наращиванию.
///<summary>
public double? ActualTimeBarrelPreparation { get; set; }
/// <summary>
///Фактическое время наращиваний
///<summary>
public double? ActualTimeExtension { get; set; }
/// <summary>
///Режимы бурения в роторе
///<summary>
public IEnumerable<string> RotorDrillingModes { get; set; }
/// <summary>
///режимы бурения в слайде
///<summary>
public IEnumerable<string> SlideDrillingModes { get; set; }
/// <summary>
///Количество метров пробуренных в роторе за отчетный период
///<summary>
public double? PenetrationInRotor { get; set; }
/// <summary>
///Количество часов бурения в роторе за отчетный период
///<summary>
public double? NumberDrillingHours { get; set; }
/// <summary>
///средний диф перепад в роторе за отчетный период
///<summary>
public double? AVGDiffDropRotor { get; set; }
/// <summary>
///количество метров пробуренных в слайде за отчетный период
///<summary>
public double? PenetrationInSlide { get; set; }
/// <summary>
///время бурения в роторе за отчетный период
///<summary>
public double? DrillingTimeInRotor { get; set; }
/// <summary>
///средний диф перепад в слайде за отчетный период
///<summary>
public double? AVGDiffPressureSlide { get; set; }
/// <summary>
///Плановая МСП за секцию
///<summary>
public double? SectionROPPlan { get; set; }
/// <summary>
///Общее время бурения за секцию
///<summary>
public double? SectionDrillingTimeTotal { get; set; }
/// <summary>
///Общая проходка за секцию
///<summary>
public double? SectionPenetrationTotal { get; set; }
/// <summary>
///Количество наращиваний за отчетный период
///<summary>
public int ExtensionsCount { get; set; }
/// <summary>
///Отклонение относительно ГГД
///<summary>
public double? DeviationFromTVD { get; set; }
/// <summary>
///указываются все причины, которые влияют на снижение МСП.
///<summary>
public string DeclinesReasonsROP { get; set; }
/// <summary>
///ФИО Мастера буровой
///<summary>
public string DrillingMaster { get; set; }
/// <summary>
///ФИО супервайзера
///<summary>
public string Supervisor { get; set; }
}
}

View File

@ -0,0 +1,20 @@
using AsbCloudApp.Data;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudApp.Services
{
public interface IDailyReportService
{
Task<IEnumerable<DailyReportDto>> GetListAsync(int idWell, DateTime? v1, DateTime? v2, CancellationToken cancellationToken);
Task<IEnumerable<DailyReportDto>> GetOrGenerateAsync(int idWell, DateTime date, CancellationToken token);
Task<int> AddAsync(int idWell, DailyReportDto dto, CancellationToken token = default);
Task<int> UpdateAsync(int idWell, DateTime date, DailyReportDto dto, CancellationToken token = default);
Task<Stream> MakeReportAsync(int idWell, DateTime date, CancellationToken token = default);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
using System;
using AsbCloudDb.Model;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace AsbCloudDb.Migrations
{
public partial class Add_DailyReport_Table : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "t_daily_report",
columns: table => new
{
id_well = table.Column<int>(type: "integer", nullable: false, comment: "ID скважины"),
start_date = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, comment: "Дата отчёта"),
info = table.Column<DailyReportInfo>(type: "jsonb", nullable: true, comment: "Список параметров для отчёта")
},
constraints: table =>
{
table.PrimaryKey("t_id_well_date_start_pk", x => new { x.id_well, x.start_date });
table.ForeignKey(
name: "FK_t_daily_report_t_well_id_well",
column: x => x.id_well,
principalTable: "t_well",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
},
comment: "Ежедневные отчёты");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "t_daily_report");
}
}
}

View File

@ -137,6 +137,31 @@ namespace AsbCloudDb.Migrations
});
});
modelBuilder.Entity("AsbCloudDb.Model.DailyReport", b =>
{
b.Property<int>("IdWell")
.HasColumnType("integer")
.HasColumnName("id_well")
.HasComment("ID скважины");
b.Property<DateTimeOffset>("StartDate")
.HasColumnType("timestamp with time zone")
.HasColumnName("start_date")
.HasComment("Дата отчёта");
b.Property<DailyReportInfo>("Info")
.HasColumnType("jsonb")
.HasColumnName("info")
.HasComment("Список параметров для отчёта");
b.HasKey("IdWell", "StartDate")
.HasName("t_id_well_date_start_pk");
b.ToTable("t_daily_report");
b.HasComment("Ежедневные отчёты");
});
modelBuilder.Entity("AsbCloudDb.Model.Deposit", b =>
{
b.Property<int>("Id")
@ -5142,6 +5167,17 @@ namespace AsbCloudDb.Migrations
b.Navigation("CompanyType");
});
modelBuilder.Entity("AsbCloudDb.Model.DailyReport", b =>
{
b.HasOne("AsbCloudDb.Model.Well", "Well")
.WithMany()
.HasForeignKey("IdWell")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Well");
});
modelBuilder.Entity("AsbCloudDb.Model.DrillFlowChart", b =>
{
b.HasOne("AsbCloudDb.Model.Well", "Well")

View File

@ -43,6 +43,7 @@ namespace AsbCloudDb.Model
public virtual DbSet<RelationUserRolePermission> RelationUserRolePermissions { get; set; }
public virtual DbSet<RelationUserRoleUserRole> RelationUserRoleUserRoles { get; set; }
public virtual DbSet<RelationUserDrillingProgramPart> RelationDrillingProgramPartUsers { get; set; }
public virtual DbSet<DailyReport> DailyReport { get; set; }
// WITS
public DbSet<WITS.Record1> Record1 { get; set; }
@ -299,6 +300,12 @@ namespace AsbCloudDb.Model
.IsRequired();
});
modelBuilder.Entity<DailyReport>(entity =>
{
entity.HasKey(e => new { e.IdWell, e.StartDate })
.HasName("t_id_well_date_start_pk");
});
FillData(modelBuilder);
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
namespace AsbCloudDb.Model
{
[Table("t_daily_report"), Comment("Ежедневные отчёты")]
public class DailyReport
{
[Column("id_well"), Comment("ID скважины")]
public int IdWell { get; set; }
[Column("start_date", TypeName = "timestamp with time zone"), Comment("Дата отчёта")]
public DateTimeOffset StartDate { get; set; }
[Column("info", TypeName = "jsonb"), Comment("Список параметров для отчёта")]
public DailyReportInfo Info { get; set; }
[ForeignKey(nameof(IdWell))]
public virtual Well Well { get; set; }
}
}

View File

@ -0,0 +1,216 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AsbCloudDb.Model
{
public class DailyReportInfo
{
/// <summary>
///название скважины
/// <summary>
public string WellName { get; set; }
///<summary>
///название куста
///<summary>
public string ClusterName { get; set; }
/// <summary>
///заказчик
///<summary>
public string Customer { get; set; }
/// <summary>
///подрядчик
///<summary>
public string Contractor { get; set; }
/// <summary>
///дата рапорта
///<summary>
public DateTime ReportDate { get; set; }
/// <summary>
///глубина забоя на дату начала интервала
///<summary>
public double? WellDepthIntervalStartDate { get; set; }
/// <summary>
///глубина забоя на дату окончания интервала
///<summary>
public double? WellDepthIntervalFinishDate { get; set; }
/// <summary>
///Глубина забоя по стволу на окончание отчетного периода
///<summary>
public double? BottomholeDepth { get; set; }
/// <summary>
///Глубина забоя по вертикали на дату окончания отчетного периода
///<summary>
public double? VerticalDepth { get; set; }
/// <summary>
///Зeнитный угол на дату окончания отчетного периода
///<summary>
public double? ZenithAngle { get; set; }
/// <summary>
///Азимутальный угол на дату окончания отчетного периода
///<summary>
public double? AzimuthAngle { get; set; }
/// <summary>
///ФИО бурильщиков
///<summary>
public string FirstDriller { get; set; }
/// <summary>
///ФИО бурильщиков
///<summary>
public string SecondDriller { get; set; }
/// <summary>
///Время работы АПД
///<summary>
public double? WorkTimeSAUB { get; set; }
/// <summary>
///Время работы спин мастер
///<summary>
public double? WorkTimeSpinMaster { get; set; }
/// <summary>
///Время работы торк мастер
///<summary>
public double? WorkTimeTorkMaster { get; set; }
/// <summary>
///количество метров пробуренных с включенным АПД
///<summary>
public double? PenetrationSAUB { get; set; }
/// <summary>
///количество метров пробуренных с включенным Спин мастер
///<summary>
public double? PenetrationSpinMaster { get; set; }
/// <summary>
///количество метров пробуренных с включенным торк мастер
///<summary>
public double? PenetrationTorkMaster { get; set; }
/// <summary>
///Количество запусков МСЕ
///<summary>
public int CountLaunchesMSE { get; set; }
/// <summary>
///КНБК описание
///<summary>
public string BHADescription { get; set; }
/// <summary>
///Нормативное время на одну операцию по подготовке ствола скважины к наращиванию
///<summary>
public double? StandardTimeBarrelPreparation { get; set; }
/// <summary>
///Нормативное время на одну операцию по наращиванию
///<summary>
public double? StandardTimeExtension { get; set; }
/// <summary>
///Фактическое время проработок при подготовке ствола скважины к наращиванию.
///<summary>
public double? ActualTimeBarrelPreparation { get; set; }
/// <summary>
///Фактическое время наращиваний
///<summary>
public double? ActualTimeExtension { get; set; }
/// <summary>
///Режимы бурения в роторе
///<summary>
public IEnumerable<string> RotorDrillingModes { get; set; }
/// <summary>
///режимы бурения в слайде
///<summary>
public IEnumerable<string> SlideDrillingModes { get; set; }
/// <summary>
///Количество метров пробуренных в роторе за отчетный период
///<summary>
public double? PenetrationInRotor { get; set; }
/// <summary>
///Количество часов бурения в роторе за отчетный период
///<summary>
public double? NumberDrillingHours { get; set; }
/// <summary>
///средний диф перепад в роторе за отчетный период
///<summary>
public double? AVGDiffDropRotor { get; set; }
/// <summary>
///количество метров пробуренных в слайде за отчетный период
///<summary>
public double? PenetrationInSlide { get; set; }
/// <summary>
///время бурения в роторе за отчетный период
///<summary>
public double? DrillingTimeInRotor { get; set; }
/// <summary>
///средний диф перепад в слайде за отчетный период
///<summary>
public double? AVGDiffPressureSlide { get; set; }
/// <summary>
///Плановая МСП за секцию
///<summary>
public double? SectionROPPlan { get; set; }
/// <summary>
///Общее время бурения за секцию
///<summary>
public double? SectionDrillingTimeTotal { get; set; }
/// <summary>
///Общая проходка за секцию
///<summary>
public double? SectionPenetrationTotal { get; set; }
/// <summary>
///Количество наращиваний за отчетный период
///<summary>
public int ExtensionsCount { get; set; }
/// <summary>
///Отклонение относительно ГГД
///<summary>
public double? DeviationFromTVD { get; set; }
/// <summary>
///указываются все причины, которые влияют на снижение МСП.
///<summary>
public string DeclinesReasonsROP { get; set; }
/// <summary>
///ФИО Мастера буровой
///<summary>
public string DrillingMaster { get; set; }
/// <summary>
///ФИО супервайзера
///<summary>
public string Supervisor { get; set; }
}
}

View File

@ -42,6 +42,7 @@ namespace AsbCloudDb.Model
DbSet<DrillingProgramPart> DrillingProgramParts { get; set; }
DbSet<RelationUserDrillingProgramPart> RelationDrillingProgramPartUsers { get; set; }
DbSet<RelationCompanyWell> RelationCompaniesWells { get; set; }
DbSet<DailyReport> DailyReport { get; set; }
int SaveChanges();
int SaveChanges(bool acceptAllChangesOnSuccess);

View File

@ -85,6 +85,7 @@ namespace AsbCloudInfrastructure
services.AddTransient<IWellOperationImportService, WellOperationImportService>();
services.AddTransient<IWellOperationService, WellOperationService>();
services.AddTransient<IScheduleReportService, ScheduleReportService>();
services.AddTransient<IDailyReportService, DailyReportService>();
// admin crud services:
services.AddTransient<ICrudService<TelemetryDto>, CrudServiceBase<TelemetryDto, Telemetry>>(); // может быть включен в сервис TelemetryService

View File

@ -0,0 +1,8 @@
namespace AsbCloudInfrastructure
{
/// <summary>
/// Тип для поиска этой сборки
/// </summary>
public interface IInfrastructureMarker
{}
}

View File

@ -0,0 +1,337 @@
using AsbCloudApp.Data;
using AsbCloudApp.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services.Cache;
using AsbCloudApp.Exceptions;
using Mapster;
using Microsoft.EntityFrameworkCore;
using System.Collections;
using System.IO;
using ClosedXML.Excel;
namespace AsbCloudInfrastructure.Services
{
public class DailyReportService : IDailyReportService
{
private readonly IAsbCloudDbContext db;
private readonly IWellService wellService;
private readonly IOperationsStatService operationsStatService;
const string sheetNameSchedule = "Дневной отчёт";
private static readonly int[,] ParamsCellsIndexes = new int[42, 2] {
{0,0},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1},
{1,1}
};
public DailyReportService(IAsbCloudDbContext db, IWellService wellService)
{
this.db = db;
this.wellService = wellService;
}
private DateTimeOffset Convert(DateTime date, int idWell)
{
var hours = wellService.GetTimezone(idWell).Hours;
var dateOffset = DateTimeExtentions.ToUtcDateTimeOffset((DateTime)date, hours);
return dateOffset;
}
private DailyReportDto Convert(DailyReport data, int idWell)
{
var hours = wellService.GetTimezone(idWell).Hours;
var dto = data.Adapt<DailyReportDto>();
dto.ReportDate = data.StartDate.ToRemoteDateTime(hours);
return dto;
}
private static Stream GetExcelTemplateStream()
{
var assembly = System.Reflection.Assembly.GetAssembly(typeof(AsbCloudInfrastructure.IInfrastructureMarker));
var stream = assembly.GetManifestResourceStream("AsbCloudInfrastructure.Services.DailyReport.DailyReportTemplate.xlsx");
return stream;
}
public async Task<IEnumerable<DailyReportDto>> GetListAsync(int idWell, DateTime? begin, DateTime? end, CancellationToken token)
{
var hours = wellService.GetTimezone(idWell).Hours;
var query = db.DailyReport.Where(r => r.IdWell == idWell);
if (begin is not null)
query = query.Where(d => d.StartDate >= Convert((DateTime)begin, idWell));
if (end is not null)
query = query.Where(d => d.StartDate <= Convert((DateTime)end, idWell));
var data = await query.ToListAsync(token);
return data.Select(d=>Convert(d, idWell));
}
public IEnumerable<DailyReportDto> GetDefaultDailyReportDto()
{
var dto = new DailyReportDto()
{
ReportDate = DateTime.Now,
};
IEnumerable<DailyReportDto> result = new List<DailyReportDto> { dto };
return result;
}
public async Task<IEnumerable<DailyReportDto>> GetOrGenerateAsync(int idWell, DateTime date, CancellationToken token)
{
var query = db.DailyReport.Where(r => r.IdWell == idWell);
query = query.Where(d => d.StartDate == Convert(date, idWell));
var data = await query.ToListAsync(token);
if (data.Count == 0)
return GetDefaultDailyReportDto();
else
return data.Select(d => Convert(d, idWell));
}
public async Task<int> AddAsync(int idWell, DailyReportDto dto, CancellationToken token = default)
{
var entity = dto.Adapt<DailyReport>();
entity.StartDate = Convert(dto.ReportDate, idWell);
db.DailyReport.Add(entity);
var result = await db.SaveChangesAsync(token);
return result;
}
public async Task<int> UpdateAsync(int idWell, DateTime date, DailyReportDto dto, CancellationToken token)
{
var entity = dto.Adapt<DailyReport>();
entity.StartDate = Convert(dto.ReportDate, idWell);
db.DailyReport.Update(entity);
var result = await db.SaveChangesAsync(token);
return result;
}
public async Task<Stream> MakeReportAsync(int idWell, DateTime date, CancellationToken token = default)
{
var tvd = await operationsStatService.GetTvdAsync(idWell, token);
if (!tvd.Any())
return null;
var well = await wellService.GetAsync(idWell, token);
var ecxelTemplateStream = GetExcelTemplateStream();
using var workbook = new XLWorkbook(ecxelTemplateStream, XLEventTracking.Disabled);
FillScheduleSheetToWorkbook(workbook, tvd, well);
FillTvdSheetToWorkbook(workbook, tvd, well);
MemoryStream memoryStream = new MemoryStream();
workbook.SaveAs(memoryStream, new SaveOptions { });
memoryStream.Seek(0, SeekOrigin.Begin);
return memoryStream;
}
private static void FillScheduleSheetToWorkbook(XLWorkbook workbook, IEnumerable<PlanFactPredictBase<WellOperationDto>> tvd, WellDto well)
{
var sheet = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetNameSchedule);
if (sheet is null)
return;
const int headerRowsCount = 6;
const int rowTitle = 3;
const int columnRowNumber = 2;
const int columnCaption = 3;
const int columnWellDepthStartPlan = 4;
const int columnWellDepthStartFact = 5;
const int columnWellDepthStartPredict = 6;
const int columnWellDepthEndPlan = 7;
const int columnWellDepthEndFact = 8;
const int columnWellDepthEndPredict = 9;
const int columnDeltaWellDepthPerDay = 10;
const int columnDurationPlan = 11;
const int columnDurationFact = 12;
const int columnDurationPredict = 13;
const int columnDateStartPlan = 14;
const int columnDateStartFact = 15;
const int columnDateStartPredict = 16;
const int columnDateEndPlan = 17;
const int columnDateEndFact = 18;
const int columnDateEndPredict = 19;
const int columnGuilty = 20;
const int columnNpt = 21;
var subTitle = $"на строительство скважины №{well.Caption}, куст: {well.Cluster}, м/р: {well.Deposit}";
sheet.Row(rowTitle).Cell(3).Value = subTitle;
var tvdList = tvd.ToList();
}
private static void FillTvdSheetToWorkbook(XLWorkbook workbook, IEnumerable<PlanFactPredictBase<WellOperationDto>> tvd, WellDto well)
{
var sheet = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetNameTvd);
if (sheet is null)
return;
const int rowTitle = 2;
const int rowSubtitle = 3;
const int colTitle = 5;
const int rowTopStatTitle = 2;
const int colTopStatvalue = 10;
const int colBottomStatvalue = 3;
const int rowStartDateFact = 43;
const int rowEndDatePlan = 44;
const int rowEndDateFact = 45;
sheet.Row(rowSubtitle).Cell(colTitle).Value
= $"скважины №{well.Caption}, куст: {well.Cluster}, м/р: {well.Deposit}";
SetCell(sheet.Row(rowTitle), colTopStatvalue, DateTime.Now);
var Plan = tvd.Where(t => t.Plan is not null)
.Select(t => t.Plan);
var Fact = tvd.Where(t => t.Fact is not null)
.Select(t => t.Fact);
var Predict = tvd.Where(t => t.Predict is not null)
.Select(t => t.Predict);
var startDateFact = Fact.FirstOrDefault()?.DateStart;
var planLast = Plan.LastOrDefault();
var factLast = Fact.LastOrDefault();
var predictLast = Predict.LastOrDefault();
static DateTime GetEndDate(WellOperationDto operation)
=> operation is not null
? operation.DateStart.AddHours(operation.DurationHours)
: default;
var endDatePlan = GetEndDate(planLast);
var endDateFact = GetEndDate(factLast);
var endDatePredict = GetEndDate(predictLast);
var endDate = endDatePredict > endDateFact
? endDatePredict
: endDateFact;
if (startDateFact is not null)
{
SetCell(sheet.Row(rowStartDateFact), colBottomStatvalue, startDateFact);
SetCell(sheet.Row(rowEndDatePlan), colBottomStatvalue, endDatePlan);
SetCell(sheet.Row(rowEndDateFact), colBottomStatvalue, endDate);
if (endDate != default)
{
var deltaEndDate = (endDatePlan - endDate).TotalDays;
SetCell(sheet.Row(rowTopStatTitle + 1), colTopStatvalue, Math.Abs(deltaEndDate));
if (deltaEndDate >= 0)
SetCell(sheet.Row(rowTopStatTitle + 1), colTopStatvalue - 1, "+")
.Style.Font.SetFontColor(XLColor.Green);
else
SetCell(sheet.Row(rowTopStatTitle + 1), colTopStatvalue - 1, "—")
.Style.Font.SetFontColor(XLColor.Red);
}
}
}
private static string GetColunmLetter(int columnNumber)
{
string letter = "";
while (columnNumber > 0)
{
int modulo = (columnNumber - 1) % 26;
letter = Convert.ToChar('A' + modulo) + letter;
columnNumber = (columnNumber - modulo) / 26;
}
return letter;
}
private static IXLStyle SetBorder(IXLStyle style)
{
style.Border.RightBorder = XLBorderStyleValues.Thin;
style.Border.LeftBorder = XLBorderStyleValues.Thin;
style.Border.TopBorder = XLBorderStyleValues.Thin;
style.Border.BottomBorder = XLBorderStyleValues.Thin;
style.Border.InsideBorder = XLBorderStyleValues.Thin;
return style;
}
private static IXLCell SetDateTime(IXLCell cell)
{
cell.DataType = XLDataType.DateTime;
cell.Style.DateFormat.Format = "DD.MM.YYYY HH:MM:SS";
return cell;
}
private static IXLCell SetNumber(IXLCell cell)
{
cell.DataType = XLDataType.Number;
cell.Style.NumberFormat.Format = "0.00";
return cell;
}
private static IXLCell SetCell(IXLRow row, int colunm, object value)
{
var cell = row.Cell(colunm);
cell.Value = value;
SetBorder(cell.Style);
cell.Style.Alignment.WrapText = true;
if (value is string valueString && valueString.Length > maxChartsToWrap)
{
var baseHeight = row.Height;
row.Height = 0.82d * baseHeight * Math.Ceiling(1d + valueString.Length / maxChartsToWrap);
}
if (value is DateTime)
{
SetDateTime(cell);
}
else if (value is IFormattable)
{
SetNumber(cell);
}
return cell;
}
}
}

View File

@ -0,0 +1,112 @@
using AsbCloudApp.Data;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Services;
using AsbCloudInfrastructure.Services;
namespace AsbCloudWebApi.Controllers
{
[Route("api/well/{idWell}/[controller]")]
[ApiController]
[Authorize]
public class DailyReportController : ControllerBase
{
private readonly IDailyReportService dailyReportService;
public DailyReportController(IDailyReportService dailyReportService)
{
this.dailyReportService = dailyReportService;
}
/// <summary>
/// Список наборов данных для формирования рапорта
/// </summary>
/// <param name="idWell"></param>
/// <param name="begin"></param>
/// <param name="end"></param>
/// <param name="token"></param>
/// <returns></returns>
[HttpGet]
//[Permission]
[ProducesResponseType(typeof(IEnumerable<DailyReportDto>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetListAsync(int idWell, DateTime? begin = null, DateTime? end = null, CancellationToken token = default)
{
var result = await dailyReportService.GetListAsync(idWell, begin, end, token);
return Ok(result);
}
/// <summary>
/// новый набор данных для формирования рапорта (на новую дату). Если в архиве на эту дату уже есть данные то вернуться они.
/// </summary>
/// <param name="idWell"></param>
/// <param name="date"></param>
/// <param name="token"></param>
/// <returns></returns>
[HttpGet("{date}")]
//[Permission]
[ProducesResponseType(typeof(DailyReportDto), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetOrGenerateAsync(int idWell, [Required] DateTime date, CancellationToken token = default)
{
var dto = await dailyReportService.GetOrGenerateAsync(idWell, date, token);
return Ok(dto);
}
/// <summary>
/// Сохранение нового набора данных для формирования рапорта
/// </summary>
/// <param name="idWell"></param>
/// <param name="dto"></param>
/// <param name="token"></param>
/// <returns></returns>
[HttpPost]
//[Permission]
[ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> AddAsync(int idWell, [Required] DailyReportDto dto, CancellationToken token = default)
{
var result = await dailyReportService.AddAsync(idWell, dto, token);
return Ok(result);
}
/// <summary>
/// Сохранение изменений набора данных для формирования рапорта
/// </summary>
/// <param name="idWell"></param>
/// <param name="date"></param>
/// <param name="dto"></param>
/// <param name="token"></param>
/// <returns></returns>
[HttpPut("{date}")]
//[Permission]
[ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> UpdateAsync(int idWell, [Required] DateTime date, [Required] DailyReportDto dto, CancellationToken token = default)
{
var result = await dailyReportService.UpdateAsync(idWell, date, dto, token);
return Ok(result);
}
/// <summary>
/// Сформировать и скачать рапорт в формате excel
/// </summary>
/// <param name="idWell"></param>
/// <param name="token"></param>
/// <returns></returns>
[HttpGet("{date}/excel")]
//[Permission]
[ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> DownloadAsync(int idWell, DateTime date, CancellationToken token = default)
{
await Task.Delay(1);
var stream = dailyReportService.MakeReportAsync();
var fileName = "CP.xlsx";
return File(stream, "application/octet-stream", fileName);
}
}
}