C# .Net6 使用Epplus库作Excel导出,处理一对多数据,合并单元格——2024年04月

一对多导出方法可大致处理以下需求:

1. 标题行别名设定(如在属性上标注[Display(Name = “编号”)]),存在集合属性(集合属性适配了集合普通类型属性和集合对象类型属性)时自动将标题行设为占据两行
2. 布尔转为是与否,导出时设为下拉
3. 枚举转为Display中的Name名称,可实现将枚举从英文转为中文,导出时设为下拉
4. 导出可处理一对多的数据结果,其中可合并单元格,但不知道性能行不行,自己使用看看
5. 基础样式已经设置好了,自己可根据需求修改适配
6. 检测Display属性是否存在,不存在则忽略该列(属性)的导出
7. 检测导出类模型是否有[Display(Name = “…”, Description = “…”)]特性,Name为表名,Description 为文档说明
8. 兼容普通导出以及一对一对象属性导出

注:工具使用了Magicodes.IE(版本时2.7)内置的低版本Epplus,另外5.0以上的高版本Epplus是需要授权的。大家也可以使用Magicodes.IE封装好的导入导出方法,需注意它的导入操作会需要将Excel文件上传存储到服务器本地作解析。

  • [一对多导入 ] 导入暂时还没有一对多导入,后续补充~~~~~~~~

ExcelHelper工具分享:

using OfficeOpenXml.DataValidation;
using OfficeOpenXml.Style;
using OfficeOpenXml;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
using System.DirectoryServices.ActiveDirectory;
using SixLabors.ImageSharp;

namespace DMS.Common.Helper
{
    public class ExcelTool
    {
        /// <summary>
        /// 导出Excel,采用流导出文件,单sheet,一对一类型数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="sheetName"></param>
        /// <param name="fileName"></param>
        /// <param name="customPath">自定义路径</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static string ExportExcel<T>(List<T> list, Stream stream, string fileName, List<string> values = null)
        {
            try
            {
                if (list == null || list.Count == 0)
                {
                    list = new List<T>();
                    return DownloadImportTemplate(list, stream, fileName, values);
                }
                List<string> titleName = new();
                Dictionary<string, Dictionary<object, string>> enumColInfo = new();
                string sFileName = $"{fileName}-{DateTime.Now.ToString("yyyyMMdd")}.xlsx";
                using (ExcelPackage package = new(new FileInfo(sFileName)))
                {
                    ExcelWorksheet worksheet = package.Workbook.Worksheets.Add(fileName);

                    #region 设置导出格式

                    //设置导出格式
                    var properties = typeof(T).GetProperties();
                    foreach (var prop in properties)
                    {
                        //标题行处理
                        DisplayAttribute displayAttribute = prop.GetCustomAttribute<DisplayAttribute>();
                        if (displayAttribute != null)
                        {
                            titleName.Add(displayAttribute.Name ?? prop.Name);
                        }
                        else
                        {
                            titleName.Add(prop.Name);
                        }
                        //时间类型处理
                        if (prop.PropertyType == typeof(DateTime) || prop.PropertyType == typeof(DateTime?))
                        {
                            var columnIndex = Array.IndexOf(typeof(T).GetProperties(), prop) + 1;
                            var address = $"{worksheet.Cells[2, columnIndex].Address}:{worksheet.Cells[list.Count + 1, columnIndex].Address}";
                            worksheet.Cells[address].Style.Numberformat.Format = "yyyy-MM-dd";
                        }
                        //枚举类型处理
                        if (prop.PropertyType.IsEnum)
                        {
                            Dictionary<object, string> valueMapping = new Dictionary<object, string>();
                            var enumType = prop.PropertyType;
                            var enumValues = Enum.GetValues(prop.PropertyType);
                            var columnIndex = Array.IndexOf(typeof(T).GetProperties(), prop) + 1;
                            //下拉选择
                            var dd = worksheet.Cells[2, columnIndex, 20000, columnIndex].DataValidation.AddListDataValidation() as ExcelDataValidationList;
                            dd.AllowBlank = true;
                            foreach (var enumValue in enumValues)
                            {
                                if (enumValue != null)
                                {
                                    var memberInfo = enumType.GetMember(enumValue.ToString());
                                    var enumDisplayAttribute = memberInfo[0].GetCustomAttribute<DisplayAttribute>();
                                    if (enumDisplayAttribute != null)
                                    {
                                        var displayName = enumDisplayAttribute.Name;
                                        valueMapping.Add(enumValue, displayName);
                                        dd.Formula.Values.Add($"{displayName}");
                                    }
                                    else
                                    {
                                        valueMapping.Add(enumValue, enumValue.ToString());
                                        dd.Formula.Values.Add($"{enumValue.ToString()}");
                                    }
                                }
                            }
                            var attributes = prop.GetCustomAttributes(true);
                            var propDisplayAttribute = attributes.FirstOrDefault(a => a is DisplayAttribute) as DisplayAttribute;
                            string propertyDisplayName = propDisplayAttribute?.Name ?? prop.Name;
                            enumColInfo.Add(propertyDisplayName, valueMapping);
                        }
                        //布尔类型
                        if (prop.PropertyType == typeof(bool) || prop.PropertyType == typeof(bool?))
                        {
                            var columnIndex = Array.IndexOf(typeof(T).GetProperties(), prop) + 1;
                            //下拉选择
                            var dd = worksheet.Cells[2, columnIndex, 20000, columnIndex].DataValidation.AddListDataValidation() as ExcelDataValidationList;
                            dd.AllowBlank = true;
                            dd.Formula.Values.Add("是");
                            dd.Formula.Values.Add("否");
                        }
                    }

                    #endregion 设置导出格式

                    #region 样式设置

                    //单元格自动适应大小
                    worksheet.Cells.Style.ShrinkToFit = true;
                    //单元格自动换行
                    worksheet.Cells.Style.WrapText = true;
                    //全部字段导出
                    worksheet.Cells.LoadFromCollection(list, true, OfficeOpenXml.Table.TableStyles.Light13);
                    //获取最后的行数
                    var endCellRow = worksheet.Dimension.End.Row;
                    //获取最后的列数
                    var endCellColumn = worksheet.Dimension.End.Column;

                    //获得第一行有数据的最后一个单元格
                    string rowCell = "null";
                    var lastRowCell = worksheet.Cells.LastOrDefault(c => c.Start.Row == 1);
                    if (lastRowCell != null) rowCell = lastRowCell.Address;

                    #region 设置全局样式

                    for (int i = 1; i <= endCellColumn; i++)
                    {
                        worksheet.Column(i).Width = 25;//列宽
                    }
                    // 设置样式范围
                    var globalRange = worksheet.Cells[$"A1:{worksheet.Cells[endCellRow, endCellColumn].Address}"];
                    // 设置字体大小
                    globalRange.Style.Font.Size = 12;
                    // 设置字体粗细
                    globalRange.Style.Font.Bold = false;
                    //字体颜色
                    globalRange.Style.Font.Color.SetColor(SixLabors.ImageSharp.Color.Black);
                    // 设置水平对齐
                    globalRange.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
                    // 设置垂直对齐
                    globalRange.Style.VerticalAlignment = ExcelVerticalAlignment.Center;

                    #endregion 设置全局样式

                    #region 设置标题行样式

                    var firstTitle = "A1" + ":" + rowCell;
                    //字体大小
                    worksheet.Cells[firstTitle].Style.Font.Size = 14;
                    //字体粗细
                    worksheet.Cells[firstTitle].Style.Font.Bold = true;
                    //字体颜色
                    worksheet.Cells[firstTitle].Style.Font.Color.SetColor(SixLabors.ImageSharp.Color.White);
                    //左右居中
                    worksheet.Cells[firstTitle].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
                    //上下居中
                    worksheet.Cells[firstTitle].Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center;
                    //设置第一行行高
                    worksheet.Row(1).Height = 20;

                    #endregion 设置标题行样式

                    #endregion 样式设置

                    #region 标题行别名设置

                    //导出标题行别名设置
                    if (values != null && values.Count > 0)
                    {
                        for (int i = 0; i < values.Count; i++)
                        {
                            //导出标题行别名设置
                            worksheet.Cells[1, i + 1].Value = values[i];
                            //枚举处理
                            for (int j = 0; j < list.Count; j++)
                            {
                                if (enumColInfo.ContainsKey(values[i]))
                                {
                                    var valueMappings = enumColInfo[values[i]];
                                    worksheet.Cells[2 + j, i + 1].Value = valueMappings[worksheet.Cells[2 + j, i + 1].Value];
                                }
                            }
                        }
                    }
                    else
                    {
                        if (titleName != null && titleName.Count > 0)
                        {
                            for (int i = 0; i < titleName.Count; i++)
                            {
                                worksheet.Cells[1, i + 1].Value = titleName[i];
                                //枚举处理
                                for (int j = 0; j < list.Count; j++)
                                {
                                    if (enumColInfo.ContainsKey(titleName[i]))
                                    {
                                        var valueMappings = enumColInfo[titleName[i]];
                                        worksheet.Cells[2 + j, i + 1].Value = valueMappings[worksheet.Cells[2 + j, i + 1].Value];
                                    }
                                }
                            }
                        }
                    }

                    #endregion 标题行别名设置

                    package.SaveAs(stream);
                }
                return sFileName;
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to export:", ex);
            }
        }

        /// <summary>
        /// 导出Excel,采用流导出文件,单sheet,一对多类型数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="stream"></param>
        /// <param name="fileName"></param>
        /// <param name="description"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static string ExportExcel<T>(List<T> list, Stream stream, string fileName = null, string description = null)
        {
            try
            {
                if (list == null || list.Count == 0)
                {
                    list = new List<T>();
                }
                bool hasListProperty = false;
                if (fileName == null || description == null)
                {
                    // 获取泛型类型T的类型信息
                    Type type = typeof(T);
                    // 获取类级别的Display特性
                    var typeDisplayAttribute = type.GetCustomAttribute<DisplayAttribute>();
                    if (typeDisplayAttribute != null)
                    {
                        fileName = fileName != null ? fileName : typeDisplayAttribute.Name ?? "未命名";
                        description = description != null ? description : typeDisplayAttribute.Description ?? "";
                    }
                }
                List<string> titleName = new();
                Dictionary<string, Dictionary<object, string>> enumColInfo = new();
                string sFileName = $"{fileName}-{DateTime.Now.ToString("yyyyMMdd")}.xlsx";
                using (ExcelPackage package = new(new FileInfo(sFileName)))
                {
                    ExcelWorksheet worksheet = package.Workbook.Worksheets.Add(fileName);

                    #region 数据赋值

                    if (description == null || description == "")
                    {
                        //标题行设置
                        TitleRowSet<T>(worksheet, ref hasListProperty, 1, 1);
                        if (hasListProperty)
                        {
                            //数据行设置
                            DataRowSet(worksheet, list, 3);
                        }
                        else
                        {
                            //数据行设置
                            DataRowSet(worksheet, list, 2);
                        }
                    }
                    else
                    {
                        //描述行
                        DescriptionRowSet<T>(worksheet, description);
                        //标题行设置
                        TitleRowSet<T>(worksheet, ref hasListProperty, 2, 1);
                        if (hasListProperty)
                        {
                            //数据行设置
                            DataRowSet(worksheet, list, 4);
                        }
                        else
                        {
                            //数据行设置
                            DataRowSet(worksheet, list, 3);
                        }
                    }

                    #endregion 数据赋值

                    #region 全局样式设定

                    //单元格自动适应大小
                    worksheet.Cells.Style.ShrinkToFit = true;
                    //单元格自动换行
                    worksheet.Cells.Style.WrapText = true;
                    //获取最后的行数
                    var endCellRow = worksheet.Dimension.End.Row;
                    //获取最后的列数
                    var endCellColumn = worksheet.Dimension.End.Column;
                    //设置列宽
                    for (int i = 1; i <= endCellColumn; i++)
                    {
                        worksheet.Column(i).Width = 25;
                    }

                    #endregion 全局样式设定

                    #region 设置枚举与布尔类型为下拉

                    //设置枚举与布尔类型为下拉
                    if (description == null || description == "")
                    {
                        if (hasListProperty)
                        {
                            AddDropDownListsForBooleanAndEnum<T>(worksheet, 3, 1, endCellRow);
                        }
                        else
                        {
                            AddDropDownListsForBooleanAndEnum<T>(worksheet, 2, 1, endCellRow);
                        }
                    }
                    else
                    {
                        if (hasListProperty)
                        {
                            AddDropDownListsForBooleanAndEnum<T>(worksheet, 4, 1, endCellRow);
                        }
                        else
                        {
                            AddDropDownListsForBooleanAndEnum<T>(worksheet, 3, 1, endCellRow);
                        }
                    }

                    #endregion 设置枚举与布尔类型为下拉

                    package.SaveAs(stream);
                }
                return sFileName;
            }
            catch (Exception ex)
            {
                throw new Exception("导出失败");
            }
        }

        /// <summary>
        /// 下载导入模板-用于单行数据,全字段导出
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list">示例数据</param>
        /// <param name="stream"></param>
        /// <param name="fileName">下载文件名</param>
        /// <param name="values">导出标题行</param>
        /// <returns></returns>
        public static string DownloadImportTemplate<T>(List<T> list, Stream stream, string fileName, List<string> values = null)
        {
            try
            {
                List<string> titleName = new();
                Dictionary<string, Dictionary<object, string>> enumColInfo = new();
                string sFileName = $"{fileName}-{DateTime.Now.ToString("yyyyMMdd")}.xlsx";
                using (ExcelPackage package = new(new FileInfo(sFileName)))
                {
                    //判断该文件是否存在
                    if (package.File.Exists)
                    {
                        package.SaveAs(stream);
                        return sFileName;
                    }
                    // 添加worksheet
                    ExcelWorksheet worksheet = package.Workbook.Worksheets.Add(fileName);

                    //设置导出格式
                    var properties = typeof(T).GetProperties();
                    foreach (var prop in properties)
                    {
                        //标题行处理
                        DisplayAttribute displayAttribute = prop.GetCustomAttribute<DisplayAttribute>();
                        if (displayAttribute != null)
                        {
                            titleName.Add(displayAttribute.Name ?? prop.Name);
                        }
                        else
                        {
                            titleName.Add(prop.Name);
                        }

                        if (prop.PropertyType == typeof(DateTime) || prop.PropertyType == typeof(DateTime?))
                        {
                            var columnIndex = Array.IndexOf(typeof(T).GetProperties(), prop) + 1;
                            var address = $"{worksheet.Cells[2, columnIndex].Address}:{worksheet.Cells[1 + 1, columnIndex].Address}";
                            worksheet.Cells[address].Style.Numberformat.Format = "yyyy-MM-dd";
                        }
                        //枚举类型处理
                        if (prop.PropertyType.IsEnum)
                        {
                            Dictionary<object, string> valueMapping = new Dictionary<object, string>();
                            var enumType = prop.PropertyType;
                            var enumValues = Enum.GetValues(prop.PropertyType);
                            var columnIndex = Array.IndexOf(typeof(T).GetProperties(), prop) + 1;
                            //下拉选择
                            var dd = worksheet.Cells[2, columnIndex, 20000, columnIndex].DataValidation.AddListDataValidation() as ExcelDataValidationList;
                            dd.AllowBlank = true;
                            foreach (var enumValue in enumValues)
                            {
                                if (enumValue != null)
                                {
                                    var memberInfo = enumType.GetMember(enumValue.ToString());
                                    var enumDisplayAttribute = memberInfo[0].GetCustomAttribute<DisplayAttribute>();
                                    if (enumDisplayAttribute != null)
                                    {
                                        var displayName = enumDisplayAttribute.Name;
                                        valueMapping.Add(enumValue, displayName);
                                        dd.Formula.Values.Add($"{displayName}");
                                    }
                                    else
                                    {
                                        valueMapping.Add(enumValue, enumValue.ToString());
                                        dd.Formula.Values.Add($"{enumValue.ToString()}");
                                    }
                                }
                            }
                            var attributes = prop.GetCustomAttributes(true);
                            var propDisplayAttribute = attributes.FirstOrDefault(a => a is DisplayAttribute) as DisplayAttribute;
                            string propertyDisplayName = propDisplayAttribute?.Name ?? prop.Name;
                            enumColInfo.Add(propertyDisplayName, valueMapping);
                        }
                        //布尔类型
                        if (prop.PropertyType == typeof(bool) && prop.PropertyType == typeof(bool?))
                        {
                            var columnIndex = Array.IndexOf(typeof(T).GetProperties(), prop) + 1;
                            //下拉选择
                            var dd = worksheet.Cells[2, columnIndex, 20000, columnIndex].DataValidation.AddListDataValidation() as ExcelDataValidationList;
                            dd.AllowBlank = true;
                            dd.Formula.Values.Add("是");
                            dd.Formula.Values.Add("否");
                        }
                    }

                    //单元格自动适应大小
                    worksheet.Cells.Style.ShrinkToFit = true;
                    //单元格自动换行
                    worksheet.Cells.Style.WrapText = true;
                    //全部字段导出
                    worksheet.Cells.LoadFromCollection(list, true, OfficeOpenXml.Table.TableStyles.Light13);

                    #region 样式设置

                    //获取最后的行数
                    var endCellRow = worksheet.Dimension.End.Row;
                    //获取最后的列数
                    var endCellColumn = worksheet.Dimension.End.Column;

                    //获得第一行有数据的最后一个单元格
                    string rowCell = "null";
                    var lastRowCell = worksheet.Cells.LastOrDefault(c => c.Start.Row == 1);
                    if (lastRowCell != null) rowCell = lastRowCell.Address;

                    #region 设置全局样式

                    for (int i = 1; i <= endCellColumn; i++)
                    {
                        //列宽
                        worksheet.Column(i).Width = 20;
                    }
                    // 设置样式范围
                    var globalRange = worksheet.Cells["A1:Z10000"];
                    // 设置字体大小
                    globalRange.Style.Font.Size = 12;
                    // 设置字体粗细
                    globalRange.Style.Font.Bold = false;
                    // 字体颜色
                    globalRange.Style.Font.Color.SetColor(SixLabors.ImageSharp.Color.Black);
                    // 设置水平对齐
                    globalRange.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
                    // 设置垂直对齐
                    globalRange.Style.VerticalAlignment = ExcelVerticalAlignment.Center;

                    #endregion 设置全局样式

                    #region 设置标题行样式

                    var firstTitle = "A1" + ":" + rowCell;
                    //字体大小
                    worksheet.Cells[firstTitle].Style.Font.Size = 14;
                    //字体粗细
                    worksheet.Cells[firstTitle].Style.Font.Bold = true;
                    //字体颜色
                    worksheet.Cells[firstTitle].Style.Font.Color.SetColor(SixLabors.ImageSharp.Color.White);
                    //左右居中
                    worksheet.Cells[firstTitle].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
                    //上下居中
                    worksheet.Cells[firstTitle].Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center;
                    //设置第一行行高
                    worksheet.Row(1).Height = 20;

                    #endregion 设置标题行样式

                    #endregion 样式设置

                    //导出标题行别名设置
                    if (values != null && values.Count > 0)
                    {
                        for (int i = 0; i < values.Count; i++)
                        {
                            //导出标题行别名设置
                            worksheet.Cells[1, i + 1].Value = values[i];
                            //枚举处理
                            for (int j = 0; j < list.Count; j++)
                            {
                                if (enumColInfo.ContainsKey(values[i]))
                                {
                                    var valueMappings = enumColInfo[values[i]];
                                    worksheet.Cells[2 + j, i + 1].Value = valueMappings[worksheet.Cells[2 + j, i + 1].Value];
                                }
                            }
                        }
                    }
                    else
                    {
                        if (titleName != null && titleName.Count > 0)
                        {
                            for (int i = 0; i < titleName.Count; i++)
                            {
                                worksheet.Cells[1, i + 1].Value = titleName[i];
                                //枚举处理
                                for (int j = 0; j < list.Count; j++)
                                {
                                    if (enumColInfo.ContainsKey(titleName[i]))
                                    {
                                        var valueMappings = enumColInfo[titleName[i]];
                                        worksheet.Cells[2 + j, i + 1].Value = valueMappings[worksheet.Cells[2 + j, i + 1].Value];
                                    }
                                }
                            }
                        }
                    }
                    package.SaveAs(stream);
                }
                return sFileName;
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to export");
            }
        }

        /// <summary>
        /// 导入数据-适用于只有一个sheet
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static IEnumerable<T> ImportData<T>(Stream stream, T entity) where T : new()
        {
            try
            {
                using ExcelPackage package = new(stream);
                ExcelWorksheet worksheet = package.Workbook.Worksheets[0];//读取第1个sheet

                //获取表格的列数和行数
                int colStart = worksheet.Dimension.Start.Column;
                int colEnd = worksheet.Dimension.End.Column;
                int rowStart = worksheet.Dimension.Start.Row;
                int rowEnd = worksheet.Dimension.End.Row;

                List<T> resultList = new();
                List<PropertyInfo> propertyInfoList = new List<PropertyInfo>(typeof(T).GetProperties());
                Dictionary<string, int> dictHeader = new();
                for (int i = colStart; i <= colEnd; i++)
                {
                    dictHeader[worksheet.Cells[rowStart, i].Value.ToString()] = i;
                }

                for (int row = rowStart + 1; row <= rowEnd; row++)
                {
                    T result = new();
                    foreach (PropertyInfo p in propertyInfoList)
                    {
                        try
                        {
                            //判断标题行是否正确
                            var attributes = p.GetCustomAttributes(true);
                            var displayAttribute = attributes.FirstOrDefault(a => a is DisplayAttribute) as DisplayAttribute;
                            string propertyName = displayAttribute?.Name ?? p.Name;
                            if (!dictHeader.ContainsKey(propertyName))
                            {
                                throw new Exception($"The imported template is incorrect. The column '{propertyName}' is missing.");
                            }
                            ExcelRange cell = worksheet.Cells[row, dictHeader[propertyName]]; //与属性名对应的单元格

                            if (cell.Value == null)
                                continue;
                            //时间类型处理
                            if (p.PropertyType.Equals(typeof(DateTime)))
                            {
                                p.SetValue(result, cell.GetValue<DateTime>());
                            }
                            else if (p.PropertyType.Equals(typeof(DateTime?)))
                            {
                                p.SetValue(result, cell.GetValue<DateTime?>());
                            }
                            //枚举值处理
                            if (p.PropertyType.IsEnum)
                            {
                                string enumDisplayName = cell.GetValue<string>();
                                var enumType = p.PropertyType;
                                var enumValues = Enum.GetValues(p.PropertyType);
                                foreach (var enumValue in enumValues)
                                {
                                    if (enumValue != null)
                                    {
                                        var memberInfo = enumType.GetMember(enumValue.ToString());
                                        var enumDisplayAttribute = memberInfo[0].GetCustomAttribute<DisplayAttribute>();
                                        if (enumDisplayAttribute != null)
                                        {
                                            var displayName = enumDisplayAttribute.Name;
                                            if (displayName == enumDisplayName)
                                            {
                                                p.SetValue(result, enumValue);
                                            }
                                        }
                                        else
                                        {
                                            p.SetValue(result, enumValue);
                                        }
                                    }
                                }
                            }

                            //布尔类型
                            if (p.PropertyType == typeof(bool) || p.PropertyType == typeof(bool?))
                            {
                                string boolStr = cell.GetValue<string>();
                                if (boolStr == "是")
                                {
                                    p.SetValue(result, 1);
                                }
                                else
                                {
                                    p.SetValue(result, 0);
                                }
                            }
                            switch (p.PropertyType.Name.ToLower())
                            {
                                case "string":
                                    p.SetValue(result, cell.GetValue<string>());
                                    break;

                                case "int16":
                                    p.SetValue(result, cell.GetValue<short>());
                                    break;

                                case "int32":
                                    p.SetValue(result, cell.GetValue<int>());
                                    break;

                                case "int64":
                                    p.SetValue(result, cell.GetValue<long>());
                                    break;

                                case "decimal":
                                    p.SetValue(result, cell.GetValue<decimal>());
                                    break;

                                case "double":
                                    p.SetValue(result, cell.GetValue<double>());
                                    break;

                                //case "boolean":
                                //    p.SetValue(result, cell.GetValue<bool>());
                                //    break;

                                case "byte":
                                    p.SetValue(result, cell.GetValue<byte>());
                                    break;

                                case "char":
                                    p.SetValue(result, cell.GetValue<char>());
                                    break;

                                case "single":
                                    p.SetValue(result, cell.GetValue<float>());
                                    break;

                                default:
                                    break;
                            }
                        }
                        catch (KeyNotFoundException ex)
                        {
                            throw new Exception("Data import failed");
                        }
                    }

                    resultList.Add(result);
                }
                return resultList;
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to import");
            }
        }

        /// <summary>
        /// 导入数据-适用于多sheet
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="stream"></param>
        /// <param name="entityDictionary"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static Dictionary<string, List<T>> ImportData<T>(Stream stream, Dictionary<string, T> entityDictionary)
        {
            try
            {
                using ExcelPackage package = new(stream);
                Dictionary<string, List<T>> resultListDictionary = new Dictionary<string, List<T>>();

                foreach (KeyValuePair<string, T> entityPair in entityDictionary)
                {
                    string sheetName = entityPair.Key;
                    T entity = entityPair.Value;

                    ExcelWorksheet worksheet = package.Workbook.Worksheets[sheetName];
                    if (worksheet == null)
                    {
                        throw new Exception($"Sheet '{sheetName}' not found in the Excel file");
                    }

                    int colStart = worksheet.Dimension.Start.Column;
                    int colEnd = worksheet.Dimension.End.Column;
                    int rowStart = worksheet.Dimension.Start.Row;
                    int rowEnd = worksheet.Dimension.End.Row;

                    List<T> resultList = new List<T>();
                    List<PropertyInfo> propertyInfoList = new List<PropertyInfo>(typeof(T).GetProperties());
                    Dictionary<string, int> dictHeader = new Dictionary<string, int>();
                    for (int i = colStart; i <= colEnd; i++)
                    {
                        dictHeader[worksheet.Cells[rowStart, i].Value.ToString()] = i;
                    }

                    for (int row = rowStart + 1; row <= rowEnd; row++)
                    {
                        T result = Activator.CreateInstance<T>();

                        foreach (PropertyInfo p in propertyInfoList)
                        {
                            try
                            {
                                var attributes = p.GetCustomAttributes(true);
                                var displayAttribute = attributes.FirstOrDefault(a => a is DisplayAttribute) as DisplayAttribute;
                                string propertyName = displayAttribute?.Name ?? p.Name;

                                if (!dictHeader.Any(x => x.Key.Equals(propertyName, StringComparison.OrdinalIgnoreCase)))
                                {
                                    continue; // 如果标题行不匹配则跳过
                                }
                                var columnHeader = dictHeader.First(x => x.Key.Equals(propertyName, StringComparison.OrdinalIgnoreCase)).Value;
                                ExcelRange cell = worksheet.Cells[row, columnHeader];

                                if (cell.Value == null)
                                    continue;

                                switch (p.PropertyType.Name.ToLower())
                                {
                                    case "string":
                                        p.SetValue(result, cell.GetValue<string>());
                                        break;

                                    case "int16":
                                        p.SetValue(result, cell.GetValue<short>());
                                        break;

                                    case "int32":
                                        p.SetValue(result, cell.GetValue<int>());
                                        break;

                                    case "int64":
                                        p.SetValue(result, cell.GetValue<long>());
                                        break;

                                    case "decimal":
                                        p.SetValue(result, cell.GetValue<decimal>());
                                        break;

                                    case "double":
                                        p.SetValue(result, cell.GetValue<double>());
                                        break;

                                    case "datetime":
                                        p.SetValue(result, cell.GetValue<DateTime>());
                                        break;

                                    case "boolean":
                                        p.SetValue(result, cell.GetValue<bool>());
                                        break;

                                    case "byte":
                                        p.SetValue(result, cell.GetValue<byte>());
                                        break;

                                    case "char":
                                        p.SetValue(result, cell.GetValue<char>());
                                        break;

                                    case "single":
                                        p.SetValue(result, cell.GetValue<float>());
                                        break;

                                    default:
                                        break;
                                }
                            }
                            catch (KeyNotFoundException ex)
                            {
                                throw new Exception("Data import failed");
                            }
                        }
                        resultList.Add(result);
                    }
                    resultListDictionary.Add(sheetName, resultList);
                }
                return resultListDictionary;
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to import");
            }
        }

        /// <summary>
        /// 合并单元格
        /// </summary>
        /// <param name="worksheet"></param>
        /// <param name="startRow"></param>
        /// <param name="endRow"></param>
        /// <param name="startColumn"></param>
        /// <param name="endColumn"></param>
        /// <param name="ignoreColumns"></param>
        public void MergeRows(ExcelWorksheet worksheet, int startRow, int endRow, int startColumn, int endColumn, List<int> ignoreColumns = null)
        {
            // 如果ignoreColumns为null,将其转换为一个空列表
            ignoreColumns ??= new List<int>();

            // 首先,确定需要合并的区域
            var mergeAreas = new List<(int StartCol, int EndCol)>();
            int currentStartCol = startColumn;

            for (int col = startColumn; col <= endColumn; col++)
            {
                if (ignoreColumns.Contains(col))
                {
                    if (col > currentStartCol)
                    {
                        mergeAreas.Add((currentStartCol, col - 1));
                    }
                    currentStartCol = col + 1;
                }
            }

            // 如果最后一个合并区域没有被添加,现在添加它
            if (endColumn > currentStartCol)
            {
                mergeAreas.Add((currentStartCol, endColumn));
            }

            // 遍历所有行,对每个合并区域进行合并操作
            for (int row = startRow; row <= endRow; row++)
            {
                foreach (var (startCol, endCol) in mergeAreas)
                {
                    // 清除合并区域中的所有单元格,除了起始单元格
                    for (int clearCol = startCol + 1; clearCol <= endCol; clearCol++)
                    {
                        worksheet.Cells[row, clearCol].Value = null;
                    }

                    // 合并单元格
                    worksheet.Cells[row, startCol, row, endCol].Merge = true;
                }
            }
        }

        /// <summary>
        /// 描述行设置
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="worksheet"></param>
        /// <param name="startRow"></param>
        public static void DescriptionRowSet<T>(ExcelWorksheet worksheet, string description = "测试描述")
        {
            try
            {
                int startColumn = 2;
                int startRow = 1;
                worksheet.Cells[startRow, 1].Value = "文档说明";
                var properties = typeof(T).GetProperties();
                int currentColumn = startColumn;
                foreach (var property in properties)
                {
                    string displayName = GetDisplayName(property);
                    var propertyType = property.PropertyType;
                    if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(List<>))
                    {
                        if (propertyType.IsGenericType &&
                                  propertyType.GetGenericTypeDefinition() == typeof(List<>) &&
                                  !propertyType.GetGenericArguments()[0].IsPrimitive &&
                                  propertyType.GetGenericArguments()[0] != typeof(string))
                        {
                            // 集合类型,需要展开子属性
                            var subProperties = property.PropertyType.GetGenericArguments().First().GetProperties();
                            foreach (var subProperty in subProperties)
                            {
                                string subDisplayName = GetDisplayName(subProperty);
                                if (subDisplayName != null)
                                    currentColumn++;
                            }
                        }
                        else
                        {
                            currentColumn++;
                        }
                    }
                    else if (displayName != null)
                    {
                        // 检测是否为对象类型 ,是则获取该属性对象的属性个数
                        if (propertyType.IsClass && !property.PropertyType.Equals(typeof(string)))
                        {
                            currentColumn = currentColumn + propertyType.GetProperties().Length;
                        }
                        else
                        {
                            currentColumn++;
                        }
                    }
                }

                #region 样式设置

                //设置行高
                worksheet.Row(startRow).Height = 50;
                var descriptionTitileRange = worksheet.Cells[startRow, 1, startRow, 1];
                //字体大小
                descriptionTitileRange.Style.Font.Size = 14;
                //字体粗细
                descriptionTitileRange.Style.Font.Bold = true;
                //字体颜色
                descriptionTitileRange.Style.Font.Color.SetColor(Color.Black);
                //左右居中
                descriptionTitileRange.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
                //上下居中
                descriptionTitileRange.Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center;

                //获得第一行有数据的最后一个单元格
                var descriptionRange = worksheet.Cells[startRow, startColumn, startRow, currentColumn - 2];
                //合并单元格
                descriptionRange.Merge = true;
                //赋值
                descriptionRange.Value = description;
                //字体大小
                descriptionRange.Style.Font.Size = 12;
                //字体粗细
                descriptionRange.Style.Font.Bold = false;
                //字体颜色
                descriptionRange.Style.Font.Color.SetColor(Color.Black);
                //左右居中
                descriptionRange.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Left;
                //上下居中
                descriptionRange.Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center;

                #endregion 样式设置
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// 标题行设置
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="worksheet"></param>
        public static void TitleRowSet<T>(ExcelWorksheet worksheet, ref bool hasListProperty, int startRow = 1, int startCol = 1)
        {
            try
            {
                int endRow = startRow;
                int currentColumn = startCol;
                hasListProperty = false;
                var properties = typeof(T).GetProperties();
                // 判断属性是否存在集合类型
                foreach (var property in properties)
                {
                    Type propertyType = property.PropertyType;
                    if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(List<>))
                        hasListProperty = true;
                }

                foreach (var property in properties)
                {
                    endRow = hasListProperty ? startRow + 1 : startRow;
                    string displayName = GetDisplayName(property);
                    if (displayName != null)
                    {
                        var propertyType = property.PropertyType;
                        if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(List<>))
                        {
                            // 检查该类型是否为复杂类型,是则需要展开子属性
                            if (propertyType.IsGenericType &&
                                  propertyType.GetGenericTypeDefinition() == typeof(List<>) &&
                                  !propertyType.GetGenericArguments()[0].IsPrimitive &&
                                  propertyType.GetGenericArguments()[0] != typeof(string))
                            {
                                var subProperties = property.PropertyType.GetGenericArguments().First().GetProperties();
                                worksheet.Cells[startRow, currentColumn].Value = displayName; // 主标题
                                foreach (var subProperty in subProperties)
                                {
                                    string subDisplayName = GetDisplayName(subProperty);
                                    worksheet.Cells[endRow, currentColumn].Value = subDisplayName; // 子标题
                                    currentColumn++;
                                }
                                // 合并主标题行
                                worksheet.Cells[startRow, currentColumn - subProperties.Length, startRow, currentColumn - 1].Merge = true;
                            }
                            else
                            {
                                worksheet.Cells[startRow, currentColumn].Value = displayName;
                                worksheet.Cells[startRow, currentColumn, endRow, currentColumn].Merge = true;
                                currentColumn++;
                            }
                        }
                        else
                        {
                            // 检查是否为对象类型,是则展开其对象的属性,将属性写入标题
                            if (propertyType.IsClass && !property.PropertyType.Equals(typeof(string)))
                            {
                                // 展开对象的属性
                                var nestedProperties = propertyType.GetProperties();
                                foreach (var nestedProperty in nestedProperties)
                                {
                                    string nestedDisplayName = GetDisplayName(nestedProperty);
                                    worksheet.Cells[startRow, currentColumn].Value = nestedDisplayName;
                                    worksheet.Cells[startRow, currentColumn, endRow, currentColumn].Merge = true;
                                    currentColumn++;
                                }
                            }
                            else
                            {
                                // 检查是否为非对象类型,是则直接写入标题
                                worksheet.Cells[startRow, currentColumn].Value = displayName;
                                worksheet.Cells[startRow, currentColumn, endRow, currentColumn].Merge = true;
                                currentColumn++;
                            }
                        }
                    }
                }

                #region 样式设置

                if (startRow == endRow)
                    worksheet.Row(startRow).Height = 30;
                //获得标题行范围
                var titleRange = worksheet.Cells[startRow, startCol, endRow, currentColumn - 1];
                //字体大小
                titleRange.Style.Font.Size = 14;
                //字体粗细
                titleRange.Style.Font.Bold = true;
                //字体颜色
                titleRange.Style.Font.Color.SetColor(Color.Black);
                //背景
                titleRange.Style.Fill.PatternType = ExcelFillStyle.Solid;
                titleRange.Style.Fill.BackgroundColor.SetColor(Color.WhiteSmoke);
                //左右居中
                titleRange.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
                //上下居中
                titleRange.Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center;

                // 设置边框样式
                titleRange.Style.Border.Top.Style = ExcelBorderStyle.Thin;
                titleRange.Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
                titleRange.Style.Border.Left.Style = ExcelBorderStyle.Thin;
                titleRange.Style.Border.Right.Style = ExcelBorderStyle.Thin;

                // 设置边框颜色
                titleRange.Style.Border.Top.Color.SetColor(Color.LightGray);
                titleRange.Style.Border.Bottom.Color.SetColor(Color.LightGray);
                titleRange.Style.Border.Left.Color.SetColor(Color.LightGray);
                titleRange.Style.Border.Right.Color.SetColor(Color.LightGray);

                #endregion 样式设置
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// 数据行设置
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="worksheet"></param>
        /// <param name="datas"></param>
        /// <param name="startRow"></param>
        /// <param name="startColumn"></param>
        /// <exception cref="Exception"></exception>
        public static void DataRowSet<T>(ExcelWorksheet worksheet, List<T> datas, int startRow, int startColumn = 1)
        {
            try
            {
                var properties = typeof(T).GetProperties();
                Dictionary<PropertyInfo, bool> isCollectionProperties = new Dictionary<PropertyInfo, bool>();

                // 判断属性是否为集合类型
                foreach (var property in properties)
                {
                    Type propertyType = property.PropertyType;
                    bool isList = false;

                    if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(List<>))
                        isList = true;
                    isCollectionProperties[property] = isList;
                }

                int currentRow = startRow;
                int currentColumn = startColumn;

                foreach (var item in datas)
                {
                    currentColumn = startColumn;
                    // 计算集合属性的最大行数
                    int maxCollectionRowCount = 1;
                    if (isCollectionProperties.Values.Any())
                    {
                        foreach (var property in properties)
                        {
                            string displayName = GetDisplayName(property);
                            if (displayName != null)
                            {
                                if (isCollectionProperties[property])
                                {
                                    IList collection = (IList)property.GetValue(item);
                                    if (collection != null)
                                    {
                                        int collectionCount = collection.Cast<object>().Count();
                                        if (collectionCount > maxCollectionRowCount)
                                            maxCollectionRowCount = collectionCount;
                                    }
                                }
                            }
                        }
                    }

                    // 写入属性值
                    foreach (var property in properties)
                    {
                        string displayName = GetDisplayName(property);
                        if (displayName != null)
                        {
                            if (!isCollectionProperties[property])
                            {
                                // 检查是否为对象类型
                                bool isObjectProperty = property.PropertyType.IsClass && !property.PropertyType.IsPrimitive && property.PropertyType != typeof(string);

                                if (isObjectProperty)
                                {
                                    // 获取对象的实例
                                    object value = property.GetValue(item);
                                    if (value != null)
                                    {
                                        // 获取对象类型
                                        Type objectType = property.PropertyType;
                                        // 获取对象的所有属性
                                        var objectProperties = objectType.GetProperties();

                                        // 对象属性的每个属性都写入到Excel的不同列
                                        foreach (var objectProperty in objectProperties)
                                        {
                                            // 获取子属性的显示名称
                                            string objectDisplayName = GetDisplayName(objectProperty);
                                            if (objectDisplayName != null)
                                            {
                                                // 获取子属性的值
                                                object objectPropertyValue = objectProperty.GetValue(value);
                                                if (objectPropertyValue != null)
                                                    // 如果需要,转换数据类型
                                                    objectPropertyValue = DataConvert(objectPropertyValue, objectProperty.PropertyType);
                                                // 写入子属性的值到单元格
                                                worksheet.Cells[currentRow, currentColumn].Value = objectPropertyValue;
                                                // 计算非集合属性的合并单元格范围
                                                int mergeStartRow = currentRow;
                                                int mergeEndRow = currentRow + maxCollectionRowCount - 1;
                                                worksheet.Cells[mergeStartRow, currentColumn, mergeEndRow, currentColumn].Merge = true;
                                                // 移动到下一列
                                                currentColumn++;
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    // 检查是否为非对象类型
                                    object value = property.GetValue(item);
                                    if (value != null)
                                        value = DataConvert(value, property.PropertyType);
                                    worksheet.Cells[currentRow, currentColumn].Value = value;

                                    // 计算非集合属性的合并单元格范围
                                    int mergeStartRow = currentRow;
                                    int mergeEndRow = currentRow + maxCollectionRowCount - 1;
                                    worksheet.Cells[mergeStartRow, currentColumn, mergeEndRow, currentColumn].Merge = true;

                                    // 移动到下一列
                                    currentColumn++;
                                }
                            }
                            else
                            {
                                // 获取集合属性的类型参数,即集合中对象的类型
                                Type subItemType = property.PropertyType.GetGenericArguments()[0];
                                // 获取对象的属性个数
                                int subItemPropertyCount = 1;
                                // 检查该类型是否为复杂类型,则获取该类型的属性个数
                                if (!subItemType.IsPrimitive && subItemType != typeof(string))
                                {
                                    subItemPropertyCount = subItemType.GetProperties().Length;
                                    IList collection = (IList)property.GetValue(item);
                                    if (collection == null)
                                        throw new Exception("导出失败");
                                    int subItemRowOffset = 0;
                                    if (collection.Count == 0)
                                    {
                                        // 如果集合为空,写入空值或占位符
                                        for (int i = 0; i < subItemPropertyCount; i++)
                                        {
                                            // 使用空字符串作为占位符
                                            worksheet.Cells[currentRow, currentColumn + i].Value = "";
                                        }
                                    }
                                    else
                                    {
                                        foreach (var subItem in collection)
                                        {
                                            int subItemColumn = currentColumn;
                                            foreach (var subItemProperty in subItem.GetType().GetProperties())
                                            {
                                                var subValue = subItemProperty.GetValue(subItem);
                                                if (subValue != null)
                                                    subValue = DataConvert(subValue, subItemProperty.PropertyType);
                                                worksheet.Cells[currentRow + subItemRowOffset, subItemColumn].Value = subValue;
                                                subItemColumn++;
                                            }
                                            subItemRowOffset++;
                                            subItemPropertyCount = subItem.GetType().GetProperties().Length;
                                        }
                                    }
                                }
                                else
                                {
                                    subItemPropertyCount = 1;

                                    // 如果是基本类型,可以直接将集合转换为字符串并写入单元格
                                    var collection = (IList)property.GetValue(item);
                                    if (collection == null)
                                        throw new Exception("导出失败");
                                    int subItemRowOffset = 0;
                                    if (collection.Count == 0)
                                    {
                                        // 如果集合为空,写入空值或占位符
                                        for (int i = 0; i < subItemPropertyCount; i++)
                                        {
                                            // 使用空字符串作为占位符
                                            worksheet.Cells[currentRow, currentColumn + i].Value = "";
                                        }
                                    }
                                    else
                                    {
                                        foreach (var subItem in collection)
                                        {
                                            int subItemColumn = currentColumn;
                                            worksheet.Cells[currentRow + subItemRowOffset, subItemColumn].Value = subItem;
                                            subItemRowOffset++;
                                        }
                                    }
                                }
                                currentColumn += subItemPropertyCount;
                            }
                        }
                    }

                    // 重置行和列的索引,准备下一条数据
                    currentRow += maxCollectionRowCount;
                }

                #region 样式设定

                // 设置样式范围
                var dataRange = worksheet.Cells[startRow, startColumn, currentRow, currentColumn];
                // 设置字体大小
                dataRange.Style.Font.Size = 12;
                // 设置字体粗细
                dataRange.Style.Font.Bold = false;
                //字体颜色
                dataRange.Style.Font.Color.SetColor(SixLabors.ImageSharp.Color.Black);
                // 设置水平对齐
                dataRange.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
                // 设置垂直对齐
                dataRange.Style.VerticalAlignment = ExcelVerticalAlignment.Center;

                #endregion 样式设定
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// 数据转换
        /// </summary>
        /// <param name="value"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        private static object DataConvert(object value, Type type)
        {
            try
            {
                if (value == null) return value;

                // 检查是否为时间类型
                if (type == typeof(DateTime) || type == typeof(DateTime?))
                {
                    // 转换为字符串
                    return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");
                }

                // 检查是否为布尔类型
                if (type == typeof(bool) || type == typeof(bool?))
                {
                    // 转换为"是"或"否"
                    return (bool)value ? "是" : "否";
                }

                // 检查是否为枚举类型
                if (type.IsEnum)
                {
                    var enumValue = (Enum)value;
                    var memberInfo = type.GetMember(enumValue.ToString());
                    if (memberInfo.Length > 0)
                    {
                        var enumDisplayAttribute = memberInfo[0].GetCustomAttribute<DisplayAttribute>();
                        if (enumDisplayAttribute != null)
                        {
                            // 转换为Display特性中的name值
                            return enumDisplayAttribute.Name ?? enumValue.ToString();
                        }
                    }
                    // 默认情况下使用枚举的名称
                    return enumValue.ToString();
                }
                return value;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// 添加下拉框
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="worksheet"></param>
        /// <param name="startRow"></param>
        /// <param name="startCol"></param>
        /// <param name="endRow"></param>
        /// <exception cref="Exception"></exception>
        private static void AddDropDownListsForBooleanAndEnum<T>(ExcelWorksheet worksheet, int startRow, int startCol, int endRow)
        {
            try
            {
                //用于记录集合对象属性造成的列偏移
                int colOffset = 0;
                var properties = typeof(T).GetProperties();

                for (int i = 0; i < properties.Length; i++)
                {
                    var prop = properties[i];
                    string displayName = GetDisplayName(prop);

                    if (displayName != null)
                    {
                        int columnIndex = i + startCol + colOffset;

                        // 检查是否为布尔类型
                        if (prop.PropertyType == typeof(bool) || prop.PropertyType == typeof(bool?))
                        {
                            //添加下拉选择
                            var dd = worksheet.Cells[startRow, columnIndex, endRow, columnIndex].DataValidation.AddListDataValidation() as ExcelDataValidationList;
                            if (dd != null)
                            {
                                dd.AllowBlank = true;
                                dd.Formula.Values.Add("是");
                                dd.Formula.Values.Add("否");
                            }
                        }

                        // 检查是否为枚举类型
                        if (prop.PropertyType.IsEnum)
                        {
                            Dictionary<object, string> valueMapping = new Dictionary<object, string>();
                            var enumType = prop.PropertyType;
                            var enumValues = Enum.GetValues(prop.PropertyType);
                            //下拉选择
                            var dd = worksheet.Cells[startRow, columnIndex, endRow, columnIndex].DataValidation.AddListDataValidation() as ExcelDataValidationList;
                            dd.AllowBlank = true;
                            foreach (var enumValue in enumValues)
                            {
                                if (enumValue != null)
                                {
                                    var memberInfo = enumType.GetMember(enumValue.ToString());
                                    var enumDisplayAttribute = memberInfo[0].GetCustomAttribute<DisplayAttribute>();
                                    if (enumDisplayAttribute != null)
                                    {
                                        var enumDisplayName = enumDisplayAttribute.Name;
                                        valueMapping.Add(enumValue, enumDisplayName);
                                        dd.Formula.Values.Add($"{enumDisplayName}");
                                    }
                                    else
                                    {
                                        valueMapping.Add(enumValue, enumValue.ToString());
                                        dd.Formula.Values.Add($"{enumValue.ToString()}");
                                    }
                                }
                            }
                        }

                        // 检查是否为对象类型
                        if (prop.PropertyType.IsClass && !prop.PropertyType.IsPrimitive
    && !prop.PropertyType.IsEnum && prop.PropertyType != typeof(string)
    && !prop.PropertyType.IsGenericType && !typeof(System.Collections.IEnumerable).IsAssignableFrom(prop.PropertyType))
                        {
                            // 对象类型,需要遍历其公共属性
                            var objectProperties = prop.PropertyType.GetProperties();

                            // 遍历对象的所有属性
                            foreach (var objectProp in objectProperties)
                            {
                                string subDisplayName = GetDisplayName(objectProp);
                                if (subDisplayName != null)
                                {
                                    int subColumnIndex = i + startCol + colOffset;

                                    // 检查对象的属性是否为布尔类型
                                    if (objectProp.PropertyType == typeof(bool) || objectProp.PropertyType == typeof(bool?))
                                    {
                                        // 添加下拉选择
                                        var dd = worksheet.Cells[startRow, subColumnIndex, endRow, subColumnIndex].DataValidation.AddListDataValidation() as ExcelDataValidationList;
                                        if (dd != null)
                                        {
                                            dd.AllowBlank = true;
                                            dd.Formula.Values.Add("是");
                                            dd.Formula.Values.Add("否");
                                        }
                                    }

                                    // 检查对象的属性是否为枚举类型
                                    else if (objectProp.PropertyType.IsEnum)
                                    {
                                        var enumValues = Enum.GetValues(objectProp.PropertyType);
                                        var dd = worksheet.Cells[startRow, subColumnIndex, endRow, subColumnIndex].DataValidation.AddListDataValidation() as ExcelDataValidationList;
                                        dd.AllowBlank = true;
                                        foreach (var enumValue in enumValues)
                                        {
                                            var enumDisplayName = enumValue.ToString(); // 假设没有DisplayAttribute,或者使用默认的枚举名称
                                            dd.Formula.Values.Add(enumDisplayName);
                                        }
                                    }

                                    colOffset++;
                                }
                            }
                            colOffset--;
                        }

                        // 检查是否为集合类型
                        if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(List<>))
                        {
                            // 获取集合的元素类型
                            var elementType = prop.PropertyType.GetGenericArguments()[0];

                            // 检查集合中元素是否为复杂对象类型
                            if (elementType.IsClass && !elementType.IsPrimitive && !elementType.IsEnum && elementType != typeof(string))
                            {
                                // 获取对象类型属性
                                var elementProperties = elementType.GetProperties();
                                // 遍历对象的属性
                                foreach (var elementProp in elementProperties)
                                {
                                    string subDisplayName = GetDisplayName(elementProp);
                                    if (subDisplayName != null)
                                    {
                                        // 检查属性是否为布尔类型
                                        if (elementProp.PropertyType == typeof(bool) || elementProp.PropertyType == typeof(bool?))
                                        {
                                            // 添加下拉选择
                                            var dd = worksheet.Cells[startRow, columnIndex, endRow, columnIndex].DataValidation.AddListDataValidation() as ExcelDataValidationList;
                                            if (dd != null)
                                            {
                                                dd.AllowBlank = true;
                                                dd.Formula.Values.Add("是");
                                                dd.Formula.Values.Add("否");
                                            }
                                        }

                                        // 检查属性是否为枚举类型
                                        if (elementProp.PropertyType.IsEnum)
                                        {
                                            Dictionary<object, string> valueMapping = new Dictionary<object, string>();
                                            var enumType = elementType;
                                            var enumValues = Enum.GetValues(enumType);
                                            var dd = worksheet.Cells[startRow, columnIndex, endRow, columnIndex].DataValidation.AddListDataValidation() as ExcelDataValidationList;
                                            dd.AllowBlank = true;
                                            foreach (var enumValue in enumValues)
                                            {
                                                var memberInfo = enumType.GetMember(enumValue.ToString());
                                                var enumDisplayAttribute = memberInfo.Length > 0 ? memberInfo[0].GetCustomAttribute<DisplayAttribute>() : null;
                                                if (enumDisplayAttribute != null)
                                                {
                                                    var enumDisplayName = enumDisplayAttribute.Name;
                                                    valueMapping.Add(enumValue, enumDisplayName);
                                                    dd.Formula.Values.Add($"{enumDisplayName}");
                                                }
                                                else
                                                {
                                                    valueMapping.Add(enumValue, enumValue.ToString());
                                                    dd.Formula.Values.Add($"{enumValue.ToString()}");
                                                }
                                            }
                                        }
                                        colOffset++;
                                        columnIndex++;
                                    }
                                }
                            }
                            else if (elementType != typeof(bool) || elementType != typeof(bool?) || !elementType.IsEnum)
                            {
                                colOffset++;
                            }

                            // 检查集合的元素类型是否为布尔
                            if (elementType == typeof(bool) || elementType == typeof(bool?))
                            {
                                // 添加下拉选择
                                var dd = worksheet.Cells[startRow, columnIndex, endRow, columnIndex].DataValidation.AddListDataValidation() as ExcelDataValidationList;
                                if (dd != null)
                                {
                                    dd.AllowBlank = true;
                                    dd.Formula.Values.Add("是");
                                    dd.Formula.Values.Add("否");
                                }
                            }

                            // 检查集合的元素类型是否为枚举
                            if (elementType.IsEnum)
                            {
                                Dictionary<object, string> valueMapping = new Dictionary<object, string>();
                                var enumType = elementType;
                                var enumValues = Enum.GetValues(enumType);
                                var dd = worksheet.Cells[startRow, columnIndex, endRow, columnIndex].DataValidation.AddListDataValidation() as ExcelDataValidationList;
                                dd.AllowBlank = true;
                                foreach (var enumValue in enumValues)
                                {
                                    var memberInfo = enumType.GetMember(enumValue.ToString());
                                    var enumDisplayAttribute = memberInfo.Length > 0 ? memberInfo[0].GetCustomAttribute<DisplayAttribute>() : null;
                                    if (enumDisplayAttribute != null)
                                    {
                                        var enumDisplayName = enumDisplayAttribute.Name;
                                        valueMapping.Add(enumValue, enumDisplayName);
                                        dd.Formula.Values.Add($"{enumDisplayName}");
                                    }
                                    else
                                    {
                                        valueMapping.Add(enumValue, enumValue.ToString());
                                        dd.Formula.Values.Add($"{enumValue.ToString()}");
                                    }
                                }
                            }
                            colOffset--;
                        }
                    }
                    else
                    {
                        colOffset--;
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// 获取属性的注释
        /// </summary>
        /// <param name="property"></param>
        /// <returns></returns>
        private static string GetDisplayName(PropertyInfo property)
        {
            var displayAttribute = property.GetCustomAttribute<DisplayAttribute>();
            return displayAttribute != null ? displayAttribute.Name : null;
        }
    }
}

部分方法未被调用验证过,可能不能用,那就自己调一下吧

以下为效果图:

这是全貌(已将数据清空)

在这里插入图片描述

模型样例

    [Display(Name = "导出测试", Description = "暂无")]
    public class ExportModel
    {
        /// <summary>
        /// 字符串属性
        /// </summary>
        [Display(Name = "字符串属性")]
        public string AT { get; set; }

        /// <summary>
        /// 布尔属性
        /// </summary>
        [Display(Name = "布尔属性")]
        public bool BT { get; set; }

        /// <summary>
        /// 整型属性
        /// </summary>
        [Display(Name = "整型属性")]
        public int CT { get; set; }

        /// <summary>
        /// 周期单位
        /// </summary>
        [Display(Name = "枚举属性")]
        public PeriodUnit DT { get; set; }

        /// <summary>
        /// 集合普通属性
        /// </summary>
        [Display(Name = "集合普通属性")]
        public List<string> List1 { get; set; }

        /// <summary>
        /// 集合对象属性
        /// </summary>
        [Display(Name = "集合对象属性")]
        public List<SpotCheckRecordDetailTemplate> List2 { get; set; }
    }

导出样例

string sFileName = ExcelTool.ExportExcel(new List<ExportModel>(), stream);
if (string.IsNullOrEmpty(sFileName))
    return BadRequest(ReturnResult.ResError("Failed to export spare parts library"));
return File(stream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", $"{sFileName}");

在这里插入图片描述

如有问题,加QQ:1991241337

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Epplus 简介:Epplus是一个使用Open Office XML(Xlsx)文件格式,能读写Excel 2007/2010文件的开源组件 功效:支持对excel文档的汇入汇出,图表(excel自带的图表基本都可以实现)的列印 使用:首先应该下载Epplus的dll文件 1> 添加dll文件至工程bin文件中 2>在程式中添加引用 using OfficeOpenXml; using OfficeOpenXml.Drawing; using OfficeOpenXml.Drawing.Chart; using OfficeOpenXml.Style; 3>所有的操作语句需要放置在下面的using中 using (ExcelPackage package = new ExcelPackage()) { } 4.添加新的sheet var worksheet = package.Workbook.Worksheets.Add(“sheet1"); 5.单元格赋值,这里多说一句,NPOI必须先创建单元格,然后再给单元格赋值,而Epplus不需要,直接找到单元格进行赋值就可以了. worksheet.Cells[int row, int col].Value = “”; 或者 worksheet.Cells["A1"].Value = “”; 6.合并单元格 worksheet.Cells[int fromRow, fromCol, int toRow,int toCol].Merge = true; 7.获取某一个区域 var rangeData= worksheet.Cells[fromRow, fromCol, toRow, toCol]; 8.设置字体 worksheet.Cells.Style.Font.Name= “正楷”; worksheet.Cells.Style.Font.Color worksheet.Cells.Style.Font.Size 9.设置边框的属性 worksheet.Cells.Style.Border.Left.Style= ExcelBorderStyle.Thin ; worksheet.Cells.Style.Border.Right.Style= ExcelBorderStyle.Thin; worksheet.Cells.Style.Border.Top.Style= ExcelBorderStyle.Thin; worksheet.Cells.Style.Border.Bottom.Style= ExcelBorderStyle.Thin; 10.对齐方式 worksheet.Cells.Style.HorizontalAlignment=ExcelHorizontalAlignment.Center; worksheet.Cells.Style.VerticalAlignment = ExcelVerticalAlignment.Bottom; 11. 设置整个sheet的背景色 worksheet.Cells.Style.Fill.PatternType= ExcelFillStyle.Solid; worksheet.Cells.Style.Fill.BackgroundColor.SetColor(Color.LightBlue); 12.折行显示 worksheet.Cells.Style.WrapText= true; 13.单元格自动适应大小 worksheet.Cells.Style.ShrinkToFit= true; 14.格式化单元格value值 worksheet.Cells.Style.Numberformat.Format= "0.00"; 15.锁定 worksheet.Cells["A1"].Style.Locked= true; 注:此处锁定某一个单元格的时候,只有在整个sheet被锁定的情况下才可以被锁定,不然加上锁定属性也是不起作用的~~ 二.Epplus另一个出色的地方就是支持图表的列印.功能的實現很簡單,難點在于需求比較細的點上,epplus可能不好實現,但是總的來說是比較好的一個列印圖表的工具 1.简单介绍一下可以实现的图表类型: 直條圖、折綫圖、圓形圖、橫條圖、散佈圖、區域圖 等類型的圖表 2.使用:分为三步, 第一步是将需要显示在图表中的 数据列印到excel中. 第二步是创建所需要的图表类型(折线图为例) var chart = (worksheet.Drawings.AddChart("LineChart", eChartType.Line) as ExcelLineChart); 第三步为图表添加第一步列印的数据区间就可以了 chart.Series.Add(Y軸顯示的數據源,X軸顯示的數據源) 3.图表的功能就这样实现了,很简单吧
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值