This commit is contained in:
user 2024-12-09 14:52:14 +04:00
parent 8ef203ae66
commit 4d0f7d2693
2 changed files with 400 additions and 0 deletions

View File

@ -0,0 +1,319 @@
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ProjectHotel.Reports;
internal class ExcelBuilder
{
private readonly string _filePath;
private readonly SheetData _sheetData;
private readonly MergeCells _mergeCells;
private readonly Columns _columns;
private uint _rowIndex = 0;
public ExcelBuilder(string filePath)
{
if (string.IsNullOrWhiteSpace(filePath)) throw new ArgumentNullException(nameof(filePath));
if (File.Exists(filePath)) File.Delete(filePath);
_filePath = filePath;
_sheetData = new SheetData();
_mergeCells = new MergeCells();
_columns = new Columns();
_rowIndex = 1;
}
public ExcelBuilder AddHeader(string header, int startIndex, int count)
{
CreateCell(startIndex, _rowIndex, header, StyleIndex.BoldTextWithoutBorder);
for (int i = startIndex + 1; i < startIndex + count; ++i)
CreateCell(i, _rowIndex, "", StyleIndex.SimpleTextWithoutBorder);
_mergeCells.Append(new MergeCell()
{
Reference = new StringValue($"{GetExcelColumnName(startIndex)}{_rowIndex}:" +
$"{GetExcelColumnName(startIndex + count - 1)}{_rowIndex}")
});
_rowIndex++;
return this;
}
public ExcelBuilder AddParagraph(string text, int columnIndex)
{
CreateCell(columnIndex, _rowIndex++, text, StyleIndex.SimpleTextWithoutBorder);
return this;
}
public ExcelBuilder AddTable(int[] columnsWidths, List<string[]> data)
{
if (columnsWidths == null || columnsWidths.Length == 0)
throw new ArgumentNullException(nameof(columnsWidths));
if (data == null || data.Count == 0)
throw new ArgumentNullException(nameof(data));
if (data.Any(x => x.Length != columnsWidths.Length))
throw new InvalidOperationException("widths.Length != data.Length");
uint counter = 1;
int coef = 2;
_columns.Append(columnsWidths.Select(x => new Column
{
Min = counter,
Max = counter++,
Width = x * coef,
CustomWidth = true
}));
for (var j = 0; j < data.First().Length; ++j)
CreateCell(j, _rowIndex, data.First()[j], StyleIndex.BoldTextWithBorder);
_rowIndex++;
for (var i = 1; i < data.Count - 1; ++i)
{
for (var j = 0; j < data[i].Length; ++j)
CreateCell(j, _rowIndex, data[i][j], StyleIndex.SimpleTextWithBorder);
_rowIndex++;
}
for (var j = 0; j < data.Last().Length; ++j)
CreateCell(j, _rowIndex, data.Last()[j], StyleIndex.BoldTextWithBorder);
_rowIndex++;
return this;
}
public void Build()
{
using var spreadsheetDocument = SpreadsheetDocument.Create(_filePath,
SpreadsheetDocumentType.Workbook);
var workbookpart = spreadsheetDocument.AddWorkbookPart();
GenerateStyle(workbookpart);
workbookpart.Workbook = new Workbook();
var worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet();
if (_columns.HasChildren)
worksheetPart.Worksheet.Append(_columns);
worksheetPart.Worksheet.Append(_sheetData);
var sheets = spreadsheetDocument.WorkbookPart!.Workbook
.AppendChild(new Sheets());
var sheet = new Sheet()
{
Id = spreadsheetDocument.WorkbookPart
.GetIdOfPart(worksheetPart),
SheetId = 1,
Name = "Лист 1"
};
sheets.Append(sheet);
if (_mergeCells.HasChildren)
worksheetPart.Worksheet.InsertAfter(_mergeCells,
worksheetPart.Worksheet.Elements<SheetData>().First());
}
private static void GenerateStyle(WorkbookPart workbookPart)
{
var workbookStylesPart = workbookPart.AddNewPart<WorkbookStylesPart>();
workbookStylesPart.Stylesheet = new Stylesheet();
var fonts = new Fonts()
{
Count = 2,
KnownFonts = BooleanValue.FromBoolean(true)
};
fonts.Append(new DocumentFormat.OpenXml.Spreadsheet.Font
{
FontSize = new FontSize() { Val = 11 },
FontName = new FontName() { Val = "Calibri" },
FontFamilyNumbering = new FontFamilyNumbering() { Val = 2 },
FontScheme = new FontScheme()
{
Val = new EnumValue<FontSchemeValues>(FontSchemeValues.Minor)
}
});
fonts.Append(new DocumentFormat.OpenXml.Spreadsheet.Font
{
FontSize = new FontSize() { Val = 11 },
FontName = new FontName() { Val = "Calibri" },
FontFamilyNumbering = new FontFamilyNumbering() { Val = 2 },
FontScheme = new FontScheme()
{
Val = new EnumValue<FontSchemeValues>(FontSchemeValues.Minor)
},
Bold = new Bold() { Val = true }
});
workbookStylesPart.Stylesheet.Append(fonts);
// Default Fill
var fills = new Fills() { Count = 1 };
fills.Append(new Fill
{
PatternFill = new PatternFill()
{
PatternType = new EnumValue<PatternValues>(PatternValues.None)
}
});
workbookStylesPart.Stylesheet.Append(fills);
// Default Border
var borders = new Borders() { Count = 2 };
borders.Append(new Border
{
LeftBorder = new LeftBorder(),
RightBorder = new RightBorder(),
TopBorder = new TopBorder(),
BottomBorder = new BottomBorder(),
DiagonalBorder = new DiagonalBorder()
});
borders.Append(new Border
{
LeftBorder = new LeftBorder() { Style = BorderStyleValues.Thin },
RightBorder = new RightBorder() { Style = BorderStyleValues.Thin },
TopBorder = new TopBorder() { Style = BorderStyleValues.Thin },
BottomBorder = new BottomBorder() { Style = BorderStyleValues.Thin },
DiagonalBorder = new DiagonalBorder()
});
workbookStylesPart.Stylesheet.Append(borders);
// Default cell format and a date cell format
var cellFormats = new CellFormats() { Count = 4 };
cellFormats.Append(new CellFormat
{
NumberFormatId = 0,
FormatId = 0,
FontId = 0,
BorderId = 0,
FillId = 0,
Alignment = new Alignment()
{
Horizontal = HorizontalAlignmentValues.Left,
Vertical = VerticalAlignmentValues.Center,
WrapText = true
}
});
cellFormats.Append(new CellFormat
{
NumberFormatId = 0,
FormatId = 0,
FontId = 1,
BorderId = 0,
FillId = 0,
Alignment = new Alignment()
{
Horizontal = HorizontalAlignmentValues.Left,
Vertical = VerticalAlignmentValues.Center,
WrapText = true
}
});
cellFormats.Append(new CellFormat
{
NumberFormatId = 0,
FormatId = 0,
FontId = 0,
BorderId = 1,
FillId = 0,
Alignment = new Alignment()
{
Horizontal = HorizontalAlignmentValues.Left,
Vertical = VerticalAlignmentValues.Center,
WrapText = true
}
});
cellFormats.Append(new CellFormat
{
NumberFormatId = 0,
FormatId = 0,
FontId = 1,
BorderId = 1,
FillId = 0,
Alignment = new Alignment()
{
Horizontal = HorizontalAlignmentValues.Left,
Vertical = VerticalAlignmentValues.Center,
WrapText = true
}
});
workbookStylesPart.Stylesheet.Append(cellFormats);
}
private enum StyleIndex
{
SimpleTextWithoutBorder = 0,
BoldTextWithoutBorder = 1,
SimpleTextWithBorder = 2,
BoldTextWithBorder = 3,
}
private void CreateCell(int columnIndex, uint rowIndex, string text, StyleIndex styleIndex)
{
var columnName = GetExcelColumnName(columnIndex);
var cellReference = columnName + rowIndex;
var row = _sheetData.Elements<Row>()
.FirstOrDefault(r => r.RowIndex! == rowIndex);
if (row == null)
{
row = new Row() { RowIndex = rowIndex };
_sheetData.Append(row);
}
var newCell = row.Elements<Cell>()
.FirstOrDefault(c => c.CellReference != null &&
c.CellReference.Value == columnName + rowIndex);
if (newCell == null)
{
Cell? refCell = null;
foreach (Cell cell in row.Elements<Cell>())
{
if (cell.CellReference?.Value != null &&
cell.CellReference.Value.Length == cellReference.Length)
{
if (string.Compare(
cell.CellReference.Value, cellReference, true) > 0)
{
refCell = cell;
break;
}
}
}
newCell = new Cell() { CellReference = cellReference };
row.InsertBefore(newCell, refCell);
}
newCell.CellValue = new CellValue(text);
newCell.DataType = CellValues.String;
newCell.StyleIndex = (uint)styleIndex;
}
private static string GetExcelColumnName(int columnNumber)
{
columnNumber += 1;
int dividend = columnNumber;
string columnName = string.Empty;
int modulo;
while (dividend > 0)
{
modulo = (dividend - 1) % 26;
columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
dividend = (dividend - modulo) / 26;
}
return columnName;
}
}

View File

@ -0,0 +1,81 @@
using Microsoft.Extensions.Logging;
using ProjectHotel.Repositories;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ProjectHotel.Reports;
internal class TableReport
{
private readonly IPlacingAthleteRepository _placingAthleteRepository;
private readonly IRoomRepository _roomRepository;
private readonly ILogger<TableReport> _logger;
internal static readonly string[] item = ["Комната", "Дата", "Проживает сейчас", "Проживало за период"];
public TableReport(IPlacingAthleteRepository placingAthleteRepository, IRoomRepository roomRepository, ILogger<TableReport> logger)
{
_placingAthleteRepository = placingAthleteRepository ?? throw new ArgumentNullException(nameof(placingAthleteRepository));
_roomRepository = roomRepository ?? throw new ArgumentNullException(nameof(roomRepository));
_logger = logger ??
throw new ArgumentNullException(nameof(logger));
}
public bool CreateTable(string filePath, int roomId, DateTime startDate, DateTime endDate)
{
try
{
new ExcelBuilder(filePath)
.AddHeader("Сводка о количестве жильцов в комнате", 0, 4)
.AddParagraph("за период", 0)
.AddTable([10, 10, 15, 15], GetData(roomId, startDate, endDate))
.Build();
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка при формировании документа");
return false;
}
}
private List<string[]> GetData(int athleteId, DateTime startDate, DateTime endDate)
{
var data = _placingAthleteRepository
.ReadPlacingAthlete()
.Where(x => x.PlacingDate >= startDate && x.AthletePlacingAthletes.Any(y => new DateTime(x.PlacingDate.Year, x.PlacingDate.Month, y.LengthOfStay + x.PlacingDate.Day) <= endDate))
.Select(x => new
{
x.RoomId,
Date = x.PlacingDate,
CountIn = x.AthletePlacingAthletes.FirstOrDefault(y => y.AthleteId == athleteId).Count,
CountOut = (int?)null
})
.Union(
_feedingAnimalRepository
.ReadFeedingAnimals()
.Where(x => x.FeedingDate >= startDate &&
x.FeedingDate <= endDate && x.FeedId == feedId)
.Select(x => new
{
x.EmployeeId,
Date =
x.FeedingDate,
CountIn = (int?)null,
CountOut = (int?)x.Ration
}))
.OrderBy(x => x.Date);
return
new List<string[]>() { item }
.Union(
data
.Select(x => new string[] {
x.EmployeeId.ToString(), x.Date.ToString(), x.CountIn?.ToString() ??
string.Empty, x.CountOut?.ToString() ?? string.Empty}))
.Union(
[["Всего", "", data.Sum(x => x.CountIn ?? 0).ToString(),
data.Sum(x => x.CountOut ?? 0).ToString()]])
.ToList();
}
}