using NPOI.HSSF.UserModel; using NPOI.OpenXmlFormats.Dml.Chart; using NPOI.SS.UserModel; using NPOI.SS.UserModel.Charts; using NPOI.SS.Util; using NPOI.XSSF.UserModel; namespace YBEE.EQM.Application; /// /// EXCEL导出服务 /// public class ExportExcelService : IExportExcelService, ISingleton { /// /// 导出 Excel 文件 /// /// /// /// public byte[] ExportExcel(ExportExcelDto input) { IWorkbook wb; if (input.IsXlsx) { wb = new XSSFWorkbook(); } else { wb = new HSSFWorkbook(); } ISheet sheet = wb.CreateSheet(input.SheetName); sheet.DisplayGridlines = false; input.SetSheet?.Invoke(sheet); var cellStyle = GetCellStyle(wb, input.FontSize, input.TitleFontSize); // 行索引号 int rowNum = 0; int freezeRowCount = 0; #region 标题 if (!(string.IsNullOrEmpty(input.Title?.Trim()) || string.IsNullOrWhiteSpace(input.Title?.Trim()))) { IRow titleRow = sheet.CreateRow(rowNum++); titleRow.Height = input.TitleHeight ?? ExportExcelCellStyle.DefaultTitleHeight; AddCell(input.Title.Trim(), titleRow, 0, cellStyle.TitleStyle, sheet); sheet.AddMergedRegion(new CellRangeAddress(rowNum - 1, rowNum - 1, 0, input.Columns.Count - 1)); freezeRowCount++; } #endregion #region 摘要 if (input.BuildSummary == null) { string summary = ""; if (input.IncludeExportTime) { summary = $"导出时间:{DateTime.Now:yyyy-MM-dd HH:mm:ss} "; }; if (!(string.IsNullOrEmpty(input.Summary) || string.IsNullOrWhiteSpace(input.Summary))) { summary = $"{summary}{input.Summary}"; } if (summary != "") { IRow summaryRow = sheet.CreateRow(rowNum++); if (!input.NotSetRowHeight) { summaryRow.Height = ExportExcelCellStyle.DefaultRowHeight; } AddCell(summary, summaryRow, 0, cellStyle.SummaryStyle, sheet); sheet.AddMergedRegion(new CellRangeAddress(rowNum - 1, rowNum - 1, 0, input.Columns.Count - 1)); freezeRowCount++; } } else { int rc = input.BuildSummary(sheet, cellStyle, rowNum); freezeRowCount += rc; rowNum += rc; } #endregion #region 列头 IRow headerRow = sheet.CreateRow(rowNum++); if (!input.NotSetRowHeight) { headerRow.Height = input.HeaderHeight; } for (int i = 0; i < input.Columns.Count; i++) { var col = input.Columns[i]; AddCell(col.Name, headerRow, i, cellStyle.ColumnHeaderStyle, sheet, col.Width); } sheet.CreateFreezePane(0, ++freezeRowCount); #endregion #region 数据 foreach (var item in input.Items) { IRow row = sheet.CreateRow(rowNum++); if (!input.NotSetRowHeight) { row.Height = input.RowHeight ?? ExportExcelCellStyle.DefaultRowHeight; } for (int i = 0; i < input.Columns.Count; i++) { var col = input.Columns[i]; ICellStyle cstyle = col.WrapText ? cellStyle.CenterWrapCellStyle : cellStyle.CenterCellStyle; switch (col.Align) { case ExportExcelCellAlign.LEFT: cstyle = col.WrapText ? cellStyle.LeftWrapCellStyle : cellStyle.LeftCellStyle; break; case ExportExcelCellAlign.RIGHT: cstyle = col.WrapText ? cellStyle.RightWrapCellStyle : cellStyle.RightCellStyle; break; } AddCell(col.GetCellValue(item), row, i, cstyle, sheet, col.Width); } } #endregion MemoryStream ms = new(); wb.Write(ms, false); ms.Flush(); return ms.ToArray(); } #region EXCEL公共方法 /// /// 获取单元格表头和单元格样式 /// /// /// 正文字体大小 /// 标题字体大小 /// public ExportExcelCellStyle GetCellStyle(IWorkbook wb, double fontSize = 10, double titleFontSize = 16) { IDataFormat dataformat = wb.CreateDataFormat(); ExportExcelCellStyle cellStyle = new() { DataFormat = dataformat, TitleStyle = wb.CreateCellStyle(), SummaryStyle = wb.CreateCellStyle(), ColumnHeaderStyle = wb.CreateCellStyle(), ColumnFillHeaderStyle = wb.CreateCellStyle(), CenterCellStyle = wb.CreateCellStyle(), LeftCellStyle = wb.CreateCellStyle(), RightCellStyle = wb.CreateCellStyle(), CenterWrapCellStyle = wb.CreateCellStyle(), LeftWrapCellStyle = wb.CreateCellStyle(), RightWrapCellStyle = wb.CreateCellStyle(), FillCellStyle = wb.CreateCellStyle(), PercentCellStyleP2 = wb.CreateCellStyle(), NumberCellStyleP2 = wb.CreateCellStyle(), NumberCellStyleP4 = wb.CreateCellStyle(), }; // 标题样式 cellStyle.TitleStyle.WrapText = true; cellStyle.TitleStyle.Alignment = HorizontalAlignment.Center; cellStyle.TitleStyle.VerticalAlignment = VerticalAlignment.Center; IFont titleFont = wb.CreateFont(); titleFont.IsBold = true; titleFont.FontName = cellStyle.TitleFontName; titleFont.FontHeightInPoints = titleFontSize; cellStyle.TitleStyle.SetFont(titleFont); // 摘要样式 cellStyle.SummaryStyle.Alignment = HorizontalAlignment.Left; cellStyle.SummaryStyle.VerticalAlignment = VerticalAlignment.Center; IFont summaryFont = wb.CreateFont(); summaryFont.FontName = cellStyle.FontName; summaryFont.FontHeightInPoints = fontSize; cellStyle.SummaryStyle.SetFont(summaryFont); // 列头样式 cellStyle.ColumnHeaderStyle.Alignment = HorizontalAlignment.Center; cellStyle.ColumnHeaderStyle.VerticalAlignment = VerticalAlignment.Center; cellStyle.ColumnHeaderStyle.BorderTop = BorderStyle.Thin; cellStyle.ColumnHeaderStyle.BorderLeft = BorderStyle.Thin; cellStyle.ColumnHeaderStyle.BorderRight = BorderStyle.Thin; cellStyle.ColumnHeaderStyle.BorderBottom = BorderStyle.Thin; cellStyle.ColumnHeaderStyle.WrapText = true; IFont headerFont = wb.CreateFont(); headerFont.IsBold = true; headerFont.FontName = cellStyle.TitleFontName; headerFont.FontHeightInPoints = fontSize; cellStyle.ColumnHeaderStyle.SetFont(headerFont); // 带背景列头样式 cellStyle.ColumnFillHeaderStyle.CloneStyleFrom(cellStyle.ColumnHeaderStyle); if (wb.SpreadsheetVersion.DefaultExtension == "xls") { HSSFPalette palette = ((HSSFWorkbook)wb).GetCustomPalette(); palette.SetColorAtIndex(48, 237, 237, 237); cellStyle.ColumnFillHeaderStyle.FillForegroundColor = palette.FindColor(237, 237, 237).Indexed; } else { cellStyle.ColumnFillHeaderStyle.FillForegroundColor = 0; cellStyle.ColumnFillHeaderStyle.FillPattern = FillPattern.SolidForeground; ((XSSFColor)cellStyle.ColumnFillHeaderStyle.FillForegroundColorColor).SetRgb(new byte[] { 237, 237, 237 }); } #region 内容样式 // 居中样式 cellStyle.CenterCellStyle.Alignment = HorizontalAlignment.Center; cellStyle.CenterCellStyle.VerticalAlignment = VerticalAlignment.Center; cellStyle.CenterCellStyle.BorderTop = BorderStyle.Thin; cellStyle.CenterCellStyle.BorderLeft = BorderStyle.Thin; cellStyle.CenterCellStyle.BorderRight = BorderStyle.Thin; cellStyle.CenterCellStyle.BorderBottom = BorderStyle.Thin; IFont cellFont = wb.CreateFont(); cellFont.FontName = cellStyle.FontName; cellFont.FontHeightInPoints = fontSize; cellStyle.CenterCellStyle.SetFont(cellFont); // 居左样式 cellStyle.LeftCellStyle.CloneStyleFrom(cellStyle.CenterCellStyle); cellStyle.LeftCellStyle.Alignment = HorizontalAlignment.Left; // 居右样式 cellStyle.RightCellStyle.CloneStyleFrom(cellStyle.CenterCellStyle); cellStyle.RightCellStyle.Alignment = HorizontalAlignment.Right; #endregion #region 自动换行 // 居中样式(自动换行) cellStyle.CenterWrapCellStyle.CloneStyleFrom(cellStyle.CenterCellStyle); cellStyle.CenterWrapCellStyle.WrapText = true; // 居左样式(自动换行) cellStyle.LeftWrapCellStyle.CloneStyleFrom(cellStyle.LeftCellStyle); cellStyle.LeftWrapCellStyle.WrapText = true; // 居右样式(自动换行) cellStyle.RightWrapCellStyle.CloneStyleFrom(cellStyle.RightCellStyle); cellStyle.RightWrapCellStyle.WrapText = true; #endregion // 背景样式 cellStyle.FillCellStyle.CloneStyleFrom(cellStyle.CenterCellStyle); if (wb.SpreadsheetVersion.DefaultExtension == "xls") { HSSFPalette palette = ((HSSFWorkbook)wb).GetCustomPalette(); palette.SetColorAtIndex(48, 245, 245, 245); cellStyle.FillCellStyle.FillForegroundColor = palette.FindColor(245, 245, 245).Indexed; } else { cellStyle.FillCellStyle.FillForegroundColor = 0; cellStyle.FillCellStyle.FillPattern = FillPattern.SolidForeground; ((XSSFColor)cellStyle.FillCellStyle.FillForegroundColorColor).SetRgb(new byte[] { 245, 245, 245 }); } cellStyle.PercentCellStyleP2.CloneStyleFrom(cellStyle.CenterCellStyle); cellStyle.PercentCellStyleP2.DataFormat = HSSFDataFormat.GetBuiltinFormat("0.00%"); cellStyle.NumberCellStyleP2.CloneStyleFrom(cellStyle.CenterCellStyle); cellStyle.NumberCellStyleP2.DataFormat = dataformat.GetFormat("0.00"); cellStyle.NumberCellStyleP4.CloneStyleFrom(cellStyle.CenterCellStyle); cellStyle.NumberCellStyleP4.DataFormat = dataformat.GetFormat("0.0000"); return cellStyle; } /// /// 添加单元格 /// /// /// /// /// /// /// /// 0转为空白 /// public ICell AddCell(object value, IRow row, int columnIndex, ICellStyle cellStyle, ISheet sheet = null, int? width = null, bool? zeroToBlank = false, CellType? cellType = null) { bool isSetBlank = false; if (zeroToBlank == true) { if (double.TryParse(value.ToString(), out double v)) { isSetBlank = v == 0; } } ICell cell = row.CreateCell(columnIndex); cell.CellStyle = cellStyle; if (value != null && isSetBlank == false) { var valueTypeName = value.GetType().Name; if (cellType.HasValue) { cell.SetCellType(cellType.Value); } if (cellType.HasValue && cellType == CellType.Formula) { cell.CellFormula = value.ToString(); } else if (valueTypeName.Contains("Int") || valueTypeName == "Double" || valueTypeName == "Decimal") { cell.SetCellValue(Convert.ToDouble(value)); } else if (valueTypeName == "String") { cell.SetCellValue(value.ToString()); } else if (valueTypeName == "Boolean") { cell.SetCellValue((bool)value); } } if (sheet != null && width.HasValue) { sheet.SetColumnWidth(columnIndex, width.Value * 256); } return cell; } #endregion #region 图表 /// /// 导出柱状图 /// /// /// /// /// /// /// /// /// /// /// public void CreateBarChart(ISheet sheet, IDrawing drawing, IClientAnchor anchor, int startDataRow, int endDataRow, int columnIndex, string title = null, string serieTitle = null, string catalogTitle = null, string valueTile = null) { XSSFChart chart = (XSSFChart)drawing.CreateChart(anchor); if (!string.IsNullOrEmpty(title)) { chart.SetTitle(title); chart.GetCTChart().title.tx.rich.p[0].pPr = new NPOI.OpenXmlFormats.Dml.CT_TextParagraphProperties { defRPr = new NPOI.OpenXmlFormats.Dml.CT_TextCharacterProperties() { sz = 1400 } }; } IBarChartData barChartData = chart.ChartDataFactory.CreateBarChartData(); IChartLegend legend = chart.GetOrCreateLegend(); legend.Position = LegendPosition.TopRight; legend.IsOverlay = true; IChartAxis bottomAxis = chart.ChartAxisFactory.CreateCategoryAxis(AxisPosition.Bottom); bottomAxis.MajorTickMark = AxisTickMark.None; IValueAxis leftAxis = chart.ChartAxisFactory.CreateValueAxis(AxisPosition.Left); leftAxis.Crosses = AxisCrosses.AutoZero; leftAxis.SetCrossBetween(AxisCrossBetween.Between); IChartDataSource categoryAxis = DataSources.FromStringCellRange(sheet, new CellRangeAddress(startDataRow, endDataRow, 0, 0)); IChartDataSource valueAxis = DataSources.FromNumericCellRange(sheet, new CellRangeAddress(startDataRow, endDataRow, columnIndex, columnIndex)); var serie = barChartData.AddSeries(categoryAxis, valueAxis); if (!string.IsNullOrEmpty(serieTitle)) { serie.SetTitle(serieTitle); } chart.Plot(barChartData, bottomAxis, leftAxis); var plotArea = chart.GetCTChart().plotArea; plotArea.catAx[0].txPr = new CT_TextBody(); plotArea.catAx[0].txPr.AddNewP().pPr = new NPOI.OpenXmlFormats.Dml.CT_TextParagraphProperties() { defRPr = new NPOI.OpenXmlFormats.Dml.CT_TextCharacterProperties() { sz = 900 } }; plotArea.catAx[0].majorTickMark = new CT_TickMark() { val = ST_TickMark.@out }; plotArea.valAx[0].txPr = new CT_TextBody(); plotArea.valAx[0].txPr.AddNewP().pPr = new NPOI.OpenXmlFormats.Dml.CT_TextParagraphProperties() { defRPr = new NPOI.OpenXmlFormats.Dml.CT_TextCharacterProperties() { sz = 900 } }; plotArea.valAx[0].majorTickMark = new CT_TickMark() { val = ST_TickMark.@out }; var barChart = plotArea.barChart.First(); barChart.barDir = new CT_BarDir { val = ST_BarDir.col }; if (!string.IsNullOrEmpty(catalogTitle)) { var aTitle = new CT_Title { tx = new CT_Tx() }; aTitle.tx.rich = new CT_TextBody(); aTitle.tx.rich.AddNewP().AddNewR().t = catalogTitle; plotArea.valAx[0].title = aTitle; } if (!string.IsNullOrEmpty(valueTile)) { var aTitle = new CT_Title { tx = new CT_Tx() }; aTitle.tx.rich = new CT_TextBody(); aTitle.tx.rich.AddNewP().AddNewR().t = valueTile; plotArea.catAx[0].title = aTitle; } } #endregion }