feat(ExcelIO): add FluentTableWriter using map registry
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
using ClosedXML.Excel;
|
||||
using JdeScoping.ExcelIO.Formatting;
|
||||
using JdeScoping.ExcelIO.Mapping;
|
||||
|
||||
namespace JdeScoping.ExcelIO.Generators;
|
||||
|
||||
/// <summary>
|
||||
/// Writes Excel tables using fluent mapping configuration.
|
||||
/// </summary>
|
||||
public sealed class FluentTableWriter
|
||||
{
|
||||
private readonly ExcelMapRegistry _registry;
|
||||
|
||||
public FluentTableWriter(ExcelMapRegistry registry)
|
||||
{
|
||||
_registry = registry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a table to the worksheet using the registered map for type T.
|
||||
/// </summary>
|
||||
public IXLTable? WriteTable<T>(
|
||||
IXLWorksheet worksheet,
|
||||
int startRow,
|
||||
int startCol,
|
||||
IEnumerable<T> data,
|
||||
string? tableNameOverride = null,
|
||||
bool showHeader = false,
|
||||
string? headerText = null)
|
||||
{
|
||||
var map = _registry.GetMap<T>();
|
||||
var columns = map.Columns;
|
||||
var tableName = tableNameOverride ?? map.TableName ?? typeof(T).Name;
|
||||
var header = headerText ?? map.TabName ?? string.Empty;
|
||||
|
||||
if (columns.Count == 0)
|
||||
return null;
|
||||
|
||||
var dataList = data.ToList();
|
||||
var baseRow = startRow;
|
||||
|
||||
// Write merged header if requested
|
||||
if (showHeader && !string.IsNullOrEmpty(header))
|
||||
{
|
||||
var mergedHeaderRange = worksheet.Range(baseRow, startCol, baseRow, startCol + columns.Count - 1);
|
||||
HeaderFormatter.ApplyHeaderFormat(mergedHeaderRange, header, merge: true);
|
||||
baseRow++;
|
||||
}
|
||||
|
||||
// Write column headers
|
||||
var col = startCol;
|
||||
foreach (var column in columns)
|
||||
{
|
||||
var cell = worksheet.Cell(baseRow, col);
|
||||
HeaderFormatter.ApplyHeaderFormat(cell, column.HeaderText);
|
||||
|
||||
// Pre-set column formatting
|
||||
worksheet.Column(col).Style.Alignment.WrapText = column.WrapText;
|
||||
if (!column.AutoWidth)
|
||||
{
|
||||
worksheet.Column(col).Width = column.Width;
|
||||
}
|
||||
|
||||
col++;
|
||||
}
|
||||
|
||||
// Write data rows
|
||||
var row = baseRow + 1;
|
||||
foreach (var item in dataList)
|
||||
{
|
||||
col = startCol;
|
||||
foreach (var column in columns)
|
||||
{
|
||||
var value = column.ValueGetter(item!);
|
||||
worksheet.Cell(row, col).Value = ConvertToXlValue(value);
|
||||
col++;
|
||||
}
|
||||
row++;
|
||||
}
|
||||
|
||||
// Handle empty data case
|
||||
if (dataList.Count == 0)
|
||||
{
|
||||
row = baseRow + 1;
|
||||
}
|
||||
|
||||
// Create table range
|
||||
var dataRange = worksheet.Range(
|
||||
baseRow, startCol,
|
||||
baseRow + dataList.Count, startCol + columns.Count - 1);
|
||||
|
||||
// Create table
|
||||
var table = dataRange.CreateTable(tableName);
|
||||
table.Theme = XLTableTheme.TableStyleLight18;
|
||||
table.ShowTotalsRow = false;
|
||||
|
||||
// Apply column formatting
|
||||
col = startCol;
|
||||
var tableStartRow = table.RangeAddress.FirstAddress.RowNumber;
|
||||
var tableEndRow = table.RangeAddress.LastAddress.RowNumber;
|
||||
|
||||
foreach (var column in columns)
|
||||
{
|
||||
// Apply number format
|
||||
worksheet.Range(tableStartRow, col, tableEndRow, col)
|
||||
.Style.NumberFormat.Format = column.Format;
|
||||
|
||||
// Apply column width
|
||||
if (column.WrapText && !column.AutoWidth)
|
||||
{
|
||||
worksheet.Column(col).Width = column.Width;
|
||||
}
|
||||
else if (column.AutoWidth)
|
||||
{
|
||||
worksheet.Column(col).AdjustToContents();
|
||||
worksheet.Column(col).Width *= Formatting.ExcelFormats.DataPaddingFactor;
|
||||
}
|
||||
else
|
||||
{
|
||||
worksheet.Column(col).Width = column.Width;
|
||||
}
|
||||
|
||||
col++;
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
private static XLCellValue ConvertToXlValue(object? value)
|
||||
{
|
||||
return value switch
|
||||
{
|
||||
null => Blank.Value,
|
||||
string s => s,
|
||||
int i => i,
|
||||
long l => l,
|
||||
decimal d => d,
|
||||
double dbl => dbl,
|
||||
float f => f,
|
||||
DateTime dt => dt,
|
||||
bool b => b,
|
||||
_ => value.ToString() ?? string.Empty
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user