399 lines
18 KiB
C#
399 lines
18 KiB
C#
using ClosedXML.Excel;
|
|
using CloudBuilder.Core.DatabaseAccessor.Entity;
|
|
using CloudBuilder.Core.Extensions;
|
|
using CloudBuilder.Core.Service;
|
|
using DocumentFormat.OpenXml.Spreadsheet;
|
|
using DocumentFormat.OpenXml;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel.DataAnnotations.Schema;
|
|
using System.Data.SqlTypes;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Diagnostics;
|
|
|
|
namespace CloudBuilder.Core.Report
|
|
{
|
|
public class DataToExcelHelper<T>
|
|
{
|
|
private readonly IApplicationService service;
|
|
public delegate object DataValueFormatOperation(string functionName, object value);
|
|
public delegate void CellTypeFormatOperation(IXLWorksheet xLWorksheet, string functionName, object cellValue, int rowIndex, int ColIndex, T[] datas);
|
|
public delegate void XLWorksheetOperation(IXLWorksheet xLWorksheet, T[] datas);
|
|
public DataToExcelHelper(IApplicationService service)
|
|
{
|
|
this.service = service;
|
|
}
|
|
|
|
public IActionResult ToExcel(T[] datas)
|
|
{
|
|
using (var excel = new XLWorkbook())
|
|
{
|
|
IXLWorksheet worksheet = GetExcelWorksheet(excel, datas);
|
|
|
|
using (MemoryStream stream = new MemoryStream())
|
|
{
|
|
excel.SaveAs(stream);
|
|
return new FileStreamResult(stream,
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
public IXLWorksheet GetExcelWorksheet(XLWorkbook excel, T[] datas)
|
|
{
|
|
string tableName = typeof(T).GetCustomAttributeValue<TableAttribute, string>(x => x.Name);
|
|
|
|
List<TemplateHeader> headers = new List<TemplateHeader>();
|
|
PropertyInfo[] pArray = typeof(T).GetProperties();
|
|
|
|
string format = null;
|
|
foreach (PropertyInfo p in pArray)
|
|
{
|
|
object value = p.GetType();
|
|
format = string.Empty;
|
|
if (value is DateTime || p.PropertyType.FullName.ToLower().Contains("datetime"))
|
|
{
|
|
format = TemplateHeader.DateTimeFormat1;
|
|
}
|
|
else if (value is int || p.PropertyType.FullName.ToLower().Contains("int"))
|
|
{
|
|
format = TemplateHeader.IntFormat1;
|
|
}
|
|
else if (value is decimal || p.PropertyType.FullName.ToLower().Contains("decimal"))
|
|
{
|
|
format = TemplateHeader.DecimalFormat1;
|
|
}
|
|
|
|
//DatabaseGeneratedOption option = typeof(StockOrderEntity).GetCustomAttributeValue<DatabaseGeneratedAttribute, DatabaseGeneratedOption>(x => x.DatabaseGeneratedOption, p.Name);
|
|
//if (option == DatabaseGeneratedOption.Identity)
|
|
//{
|
|
// continue;
|
|
//}
|
|
|
|
string displayName = typeof(T).GetCustomAttributeValue<ColumnAttribute, string>(x => x.Name, p.Name);
|
|
if (string.IsNullOrEmpty(displayName)) continue;
|
|
|
|
headers.Add(new TemplateHeader
|
|
{
|
|
DisplayName = displayName,
|
|
BindingName = p.Name,
|
|
Format = format,
|
|
Width = TemplateHeader.WidthAutoFit
|
|
});
|
|
}
|
|
|
|
return PackWorksheet(excel, tableName, tableName, null, headers.ToArray(), datas, null);
|
|
}
|
|
|
|
public IActionResult ToExcel(string worksheetName, string title, TemplateHeader[] headers, T[] datas)
|
|
{
|
|
return ToExcel(worksheetName, title, null, headers, datas, null);
|
|
}
|
|
|
|
public IActionResult ToExcel(string worksheetName, string title, List<string> subTitle, TemplateHeader[] headers, T[] datas)
|
|
{
|
|
return ToExcel(worksheetName, title, subTitle, headers, datas, null);
|
|
}
|
|
|
|
public IActionResult ToExcel(string worksheetName, string title, TemplateHeader[] headers, T[] datas, Dictionary<string, Dictionary<string, object>> mappings)
|
|
{
|
|
return ToExcel(worksheetName, title, null, headers, datas, mappings);
|
|
}
|
|
|
|
public IActionResult ToExcel(string worksheetName, string title, List<string> subTitle, TemplateHeader[] headers, T[] datas, Dictionary<string, Dictionary<string, object>> mappings)
|
|
{
|
|
return ToExcel(worksheetName, title, subTitle, headers, datas, mappings, null!, null!, null!);
|
|
}
|
|
public IActionResult ToExcel(string worksheetName, string title, List<string> subTitle, TemplateHeader[] headers, T[] datas, Dictionary<string, Dictionary<string, object>> mappings, DataValueFormatOperation dataValueOperation)
|
|
{
|
|
return ToExcel(worksheetName, title, subTitle, headers, datas, mappings, dataValueOperation, null!, null!);
|
|
}
|
|
|
|
public IActionResult ToExcel(string worksheetName, string title, List<string> subTitle, TemplateHeader[] headers, T[] datas, Dictionary<string, Dictionary<string, object>> mappings, DataValueFormatOperation dataValueOperation,
|
|
CellTypeFormatOperation cellOperation)
|
|
{
|
|
return ToExcel(worksheetName, title, subTitle, headers, datas, mappings, dataValueOperation, cellOperation, null!);
|
|
}
|
|
|
|
public IActionResult ToExcel(string worksheetName, string title, List<string> subTitle, TemplateHeader[] headers, T[] datas, Dictionary<string, Dictionary<string, object>> mappings, DataValueFormatOperation dataValueOperation,
|
|
CellTypeFormatOperation cellOperation, XLWorksheetOperation xLWorksheetOperation)
|
|
{
|
|
string path = ToExcelFile(worksheetName, title, subTitle, headers, datas, mappings, dataValueOperation, cellOperation, xLWorksheetOperation);
|
|
|
|
var stream = System.IO.File.OpenRead(path);
|
|
|
|
return new FileStreamResult(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
|
}
|
|
|
|
public void PrintExcel(string worksheetName, string title, TemplateHeader[] headers, T[] datas)
|
|
{
|
|
PrintExcel(worksheetName, title, null!, headers, datas, null!, null!, null!, null!);
|
|
}
|
|
|
|
public void PrintExcel(string worksheetName, string title, List<string> subTitle, TemplateHeader[] headers, T[] datas)
|
|
{
|
|
PrintExcel(worksheetName, title, subTitle, headers, datas, null!, null!, null!, null!);
|
|
}
|
|
|
|
public void PrintExcel(string worksheetName, string title, List<string> subTitle, TemplateHeader[] headers, T[] datas, Dictionary<string, Dictionary<string, object>> mappings)
|
|
{
|
|
PrintExcel(worksheetName, title, subTitle, headers, datas, mappings, null!, null!, null!);
|
|
}
|
|
public void PrintExcel(string worksheetName, string title, List<string> subTitle, TemplateHeader[] headers, T[] datas, Dictionary<string, Dictionary<string, object>> mappings, DataValueFormatOperation dataValueOperation)
|
|
{
|
|
PrintExcel(worksheetName, title, subTitle, headers, datas, mappings, dataValueOperation, null!, null!);
|
|
}
|
|
|
|
public void PrintExcel(string worksheetName, string title, List<string> subTitle, TemplateHeader[] headers, T[] datas, Dictionary<string, Dictionary<string, object>> mappings, DataValueFormatOperation dataValueOperation,
|
|
CellTypeFormatOperation cellOperation)
|
|
{
|
|
PrintExcel(worksheetName, title, subTitle, headers, datas, mappings, dataValueOperation, cellOperation, null!);
|
|
}
|
|
|
|
public void PrintExcel(string worksheetName, string title, List<string> subTitle, TemplateHeader[] headers, T[] datas, Dictionary<string, Dictionary<string, object>> mappings, DataValueFormatOperation dataValueOperation,
|
|
CellTypeFormatOperation cellOperation, XLWorksheetOperation xLWorksheetOperation)
|
|
{
|
|
string fileFullname = ToExcelFile(worksheetName, title, subTitle, headers, datas, mappings, dataValueOperation, cellOperation, xLWorksheetOperation);
|
|
|
|
Process.Start(new ProcessStartInfo
|
|
{
|
|
FileName = fileFullname,
|
|
UseShellExecute = true // 使用Windows Shell执行
|
|
});
|
|
}
|
|
|
|
public string ToExcelFile(string worksheetName, string title, List<string> subTitle, TemplateHeader[] headers, T[] datas, Dictionary<string, Dictionary<string, object>> mappings, DataValueFormatOperation dataValueOperation,
|
|
CellTypeFormatOperation cellOperation, XLWorksheetOperation xLWorksheetOperation)
|
|
{
|
|
string tempPath = Path.GetTempPath() + $"{DateTime.Now.ToString("yyyyMMdd")}";
|
|
|
|
if (!Directory.Exists(tempPath)) Directory.CreateDirectory(tempPath);
|
|
|
|
string fileFullname = Path.Combine(tempPath, worksheetName.Replace(" ", "") + $"{DateTime.Now.ToString("yyyyMMddHHmmssffff")}.xlsx");
|
|
|
|
if (service != null)
|
|
{
|
|
fileFullname = Path.Combine(service.Configuration["FileServiceSettings:ExcelOutputDirectory"], $"{DateTime.Now.ToString("yyyyMMdd")}", typeof(T).Name + $"{DateTime.Now.ToString("yyyyMMddHHmmssffff")}.xlsx");
|
|
}
|
|
|
|
using (var excel = new XLWorkbook())
|
|
{
|
|
if (string.IsNullOrEmpty(worksheetName)) worksheetName = "Report";
|
|
|
|
PackWorksheet(excel, worksheetName, title, subTitle, headers, datas, mappings, dataValueOperation, cellOperation, xLWorksheetOperation);
|
|
excel.SaveAs(fileFullname);
|
|
}
|
|
|
|
return fileFullname;
|
|
}
|
|
|
|
public IXLWorksheet PackWorksheet(XLWorkbook excel, string worksheetName, string title, List<string> subTitle, TemplateHeader[] headers, T[] datas, Dictionary<string, Dictionary<string, object>> mappings)
|
|
{
|
|
return PackWorksheet(excel, worksheetName, title, subTitle, headers, datas, mappings, null!, null!, null!);
|
|
}
|
|
|
|
public IXLWorksheet PackWorksheet(XLWorkbook excel, string worksheetName, string title, List<string> subTitle, TemplateHeader[] headers, T[] datas, Dictionary<string, Dictionary<string, object>> mappings, DataValueFormatOperation dataValueOperation)
|
|
{
|
|
return PackWorksheet(excel, worksheetName, title, subTitle, headers, datas, mappings, dataValueOperation, null!, null!);
|
|
}
|
|
|
|
public IXLWorksheet PackWorksheet(XLWorkbook excel, string worksheetName, string title, List<string> subTitle, TemplateHeader[] headers, T[] datas, Dictionary<string, Dictionary<string, object>> mappings, DataValueFormatOperation dataValueOperation,
|
|
CellTypeFormatOperation cellOperation)
|
|
{
|
|
return PackWorksheet(excel, worksheetName, title, subTitle, headers, datas, mappings, dataValueOperation, cellOperation, null!);
|
|
}
|
|
|
|
public IXLWorksheet PackWorksheet(XLWorkbook excel, string worksheetName, string title, List<string> subTitle, TemplateHeader[] headers, T[] datas, Dictionary<string, Dictionary<string, object>> mappings, DataValueFormatOperation dataValueOperation,
|
|
CellTypeFormatOperation cellOperation, XLWorksheetOperation xLWorksheetOperation)
|
|
{
|
|
List<ExportRow> ExportDatas = new List<ExportRow>();
|
|
int rowIndex = 1;
|
|
var worksheet = excel.Worksheets.Add(worksheetName);
|
|
|
|
List<string> headerNames = new List<string>();
|
|
int i = 1;
|
|
foreach (TemplateHeader header in headers)
|
|
{
|
|
if (!string.IsNullOrEmpty(header.Format))
|
|
worksheet.Column(i).Style.NumberFormat.Format = header.Format;
|
|
worksheet.Column(i).Width = header.DisplayName.Length * 1.5;
|
|
if (header.Width > 0)
|
|
worksheet.Column(i).Width = header.Width;
|
|
|
|
headerNames.Add(header.DisplayName);
|
|
i++;
|
|
}
|
|
|
|
worksheet.Row(rowIndex).Style.Font.FontSize = 20;
|
|
worksheet.Row(rowIndex).Height = 30;
|
|
worksheet.Range(rowIndex, 1, rowIndex, headers.Length).Merge();
|
|
worksheet.Cell(rowIndex++, 1).Value = title;
|
|
|
|
//空行
|
|
rowIndex++;
|
|
worksheet.Row(rowIndex).Height = 20;
|
|
|
|
if (subTitle != null && subTitle.Count > 0)
|
|
{
|
|
|
|
foreach (string st in subTitle)
|
|
{
|
|
worksheet.Range(rowIndex, 1, rowIndex, headers.Length).Merge();
|
|
worksheet.Cell(rowIndex++, 1).Value = st;
|
|
}
|
|
|
|
//空行
|
|
rowIndex++;
|
|
}
|
|
|
|
//設置列名
|
|
var listOfList = new List<List<string>>();
|
|
listOfList.Add(headerNames);
|
|
worksheet.Cell(rowIndex++, 1).InsertData(listOfList);
|
|
object[] rowData;
|
|
|
|
int dataIndex = rowIndex;
|
|
|
|
//Handle on empty dataset
|
|
var listOfArr = new List<object[]>();
|
|
if (datas != null && datas.Length > 0)
|
|
{
|
|
//綁定明細
|
|
var t = datas[0].GetType();
|
|
//里面是所有公共属性
|
|
PropertyInfo[] pArray = t.GetProperties();
|
|
|
|
foreach (T d in datas)
|
|
{
|
|
rowData = new object[headers.Length];
|
|
i = 0;
|
|
foreach (TemplateHeader header in headers)
|
|
{
|
|
rowData[i] = null;
|
|
Array.ForEach<PropertyInfo>(pArray, p =>
|
|
{
|
|
if (header.BindingName == p.Name)
|
|
{
|
|
object value = p.GetValue(d);
|
|
if (value == null || value == DBNull.Value)
|
|
{
|
|
rowData[i] = null;
|
|
}
|
|
else if (header.DataValueFormatName != null && dataValueOperation != null)
|
|
{
|
|
rowData[i] = dataValueOperation(header.DataValueFormatName, value);
|
|
}
|
|
else if (value is DateTime)
|
|
{
|
|
if (value == DBNull.Value)
|
|
{
|
|
rowData[i] = null;
|
|
}
|
|
else if (((DateTime)value).Year > 1900)
|
|
rowData[i] = (DateTime)value;
|
|
}
|
|
else if (value is SqlDateTime)
|
|
{
|
|
if (!((SqlDateTime)value).IsNull)
|
|
{
|
|
if (((SqlDateTime)value).Value.Year > 1900)
|
|
rowData[i] = ((SqlDateTime)value).Value;
|
|
}
|
|
else
|
|
{
|
|
rowData[i] = null;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (mappings != null && mappings.ContainsKey(header.BindingName))
|
|
{
|
|
if (mappings[header.BindingName].ContainsKey((string)value))
|
|
rowData[i] = mappings[header.BindingName][(string)value];
|
|
else
|
|
rowData[i] = value;
|
|
}
|
|
else
|
|
rowData[i] = value;
|
|
}
|
|
}
|
|
});
|
|
|
|
i++;
|
|
}
|
|
|
|
listOfArr.Add(rowData);
|
|
|
|
}
|
|
}
|
|
|
|
worksheet.Cell(rowIndex++, 1).InsertData(listOfArr);
|
|
|
|
if (datas != null && datas.Length > 0)
|
|
{
|
|
foreach (T d in datas)
|
|
{
|
|
i = 1;
|
|
foreach (TemplateHeader header in headers)
|
|
{
|
|
if (header.CellTypeFormatName != null)
|
|
cellOperation(worksheet, header.CellTypeFormatName, d, dataIndex, i, datas);
|
|
|
|
i++;
|
|
}
|
|
|
|
dataIndex++;
|
|
}
|
|
}
|
|
|
|
rowIndex = rowIndex + listOfArr.Count();
|
|
|
|
// 3 is title line + space line + header line
|
|
int headerRow = 3 + (subTitle == null || subTitle.Count == 0 ? 0 : subTitle.Count + 1);
|
|
|
|
worksheet.Range(headerRow, 1, headerRow, headers.Length).Style.Fill.PatternType = XLFillPatternValues.Solid;
|
|
worksheet.Range(headerRow, 1, headerRow, headers.Length).Style.Fill.SetBackgroundColor(XLColor.Silver);
|
|
var range = worksheet.Range(headerRow, 1, headerRow + datas.Length, headers.Length);
|
|
|
|
range.Style.Border.TopBorder = XLBorderStyleValues.Thin;
|
|
range.Style.Border.BottomBorder = XLBorderStyleValues.Thin;
|
|
range.Style.Border.LeftBorder = XLBorderStyleValues.Thin;
|
|
range.Style.Border.RightBorder = XLBorderStyleValues.Thin;
|
|
range.Style.Alignment.WrapText = true;
|
|
range.Style.Alignment.Vertical = XLAlignmentVerticalValues.Top;
|
|
|
|
|
|
i = 1;
|
|
foreach (TemplateHeader header in headers)
|
|
{
|
|
if (header.Width == TemplateHeader.WidthAutoFit)
|
|
worksheet.Column(i).AdjustToContents(headerRow, headerRow + datas.Length, 10, 100);
|
|
i++;
|
|
}
|
|
|
|
if (xLWorksheetOperation != null)
|
|
xLWorksheetOperation(worksheet, datas);
|
|
|
|
return worksheet;
|
|
}
|
|
|
|
private enum ExportDisplayStyle { Header, Subtotal, Detail, Total };
|
|
private class ExportRow
|
|
{
|
|
public object[] values;
|
|
public ExportDisplayStyle displayStyle;
|
|
public ExportRow(object[] values, ExportDisplayStyle displayStyle)
|
|
{
|
|
this.values = values;
|
|
this.displayStyle = displayStyle;
|
|
}
|
|
}
|
|
}
|
|
}
|