Files
SQLVision/SQLVision.Services/Exporters/ExcelExporter.cs
2026-01-05 00:37:54 +03:00

140 lines
4.2 KiB
C#

using ClosedXML.Excel;
using Microsoft.Extensions.Logging;
using SQLVision.Core.Models;
using System.Data;
namespace SQLVision.Services.Exporters;
public class ExcelExporter : IExportHandler
{
private readonly ILogger<ExcelExporter> _logger;
public string FormatName => "Excel";
public ExcelExporter(ILogger<ExcelExporter> logger)
{
_logger = logger;
}
public async Task ExportAsync(DataTable data, string filePath, ExportOptions options)
{
using var workbook = new XLWorkbook();
var worksheet = workbook.Worksheets.Add("Data");
WriteDataToWorksheet(worksheet, data, options);
if (options.IncludeCharts && data.Rows.Count > 0)
{
AddCharts(worksheet, data, options);
}
await Task.Run(() => workbook.SaveAs(filePath));
_logger.LogInformation("Exported {Rows} rows to Excel: {FilePath}", data.Rows.Count, filePath);
}
public async Task<byte[]> ExportToMemoryAsync(DataTable data, ExportOptions options)
{
using var workbook = new XLWorkbook();
var worksheet = workbook.Worksheets.Add("Data");
WriteDataToWorksheet(worksheet, data, options);
using var stream = new MemoryStream();
await Task.Run(() => workbook.SaveAs(stream));
return stream.ToArray();
}
private void WriteDataToWorksheet(IXLWorksheet worksheet, DataTable data, ExportOptions options)
{
if (options.IncludeHeaders)
{
for (int col = 0; col < data.Columns.Count; col++)
{
worksheet.Cell(1, col + 1).Value = data.Columns[col].ColumnName;
worksheet.Cell(1, col + 1).Style.Font.Bold = true;
}
}
int startRow = options.IncludeHeaders ? 2 : 1;
for (int row = 0; row < data.Rows.Count; row++)
{
for (int col = 0; col < data.Columns.Count; col++)
{
var value = data.Rows[row][col];
worksheet.Cell(startRow + row, col + 1).Value = ConvertValue(value);
ApplyFormatting(worksheet.Cell(startRow + row, col + 1), value);
}
}
if (options.AutoFilter)
{
var endRow = startRow + data.Rows.Count - 1;
worksheet.Range(1, 1, endRow, data.Columns.Count).SetAutoFilter();
}
worksheet.Columns().AdjustToContents();
}
private XLCellValue ConvertValue(object value)
{
if (value == null || value == DBNull.Value) return Blank.Value;
if (value is DateTime dateTime)
return dateTime;
if (value is decimal || value is double || value is float)
return Convert.ToDouble(value);
if (value is bool b)
return b;
return value.ToString();
}
private void ApplyFormatting(IXLCell cell, object value)
{
if (value is DateTime)
{
cell.Style.DateFormat.Format = "dd.MM.yyyy HH:mm:ss";
}
else if (value is decimal || value is double || value is float)
{
cell.Style.NumberFormat.Format = "#,##0.00";
}
}
private void AddCharts(IXLWorksheet worksheet, DataTable data, ExportOptions options)
{
if (data.Columns.Count < 2) return;
//TODO: chart
/*var chartType = GetChartType(options.ChartType);
var chart = worksheet.CreateChart(0, data.Columns.Count + 2, 20, data.Columns.Count + 10);
chart.ChartType = chartType;
// Добавление серий на основе данных
for (int col = 1; col < Math.Min(5, data.Columns.Count); col++)
{
var series = chart.AddSeries(
worksheet.Range(2, col + 1, data.Rows.Count + 1, col + 1),
worksheet.Range(2, 1, data.Rows.Count + 1, 1));
series.ChartType = chartType;
}
*/
}
private XLChartType GetChartType(string? chartType) => chartType?.ToLower() switch
{
"line" => XLChartType.Line,
"column" => XLChartType.ColumnClustered,
"bar" => XLChartType.BarClustered,
"pie" => XLChartType.Pie,
"area" => XLChartType.Area,
_ => XLChartType.Line
};
}