diff --git a/src/Magicodes.ExporterAndImporter.Excel/ExcelImporter.cs b/src/Magicodes.ExporterAndImporter.Excel/ExcelImporter.cs index d9049c61..fd10c792 100644 --- a/src/Magicodes.ExporterAndImporter.Excel/ExcelImporter.cs +++ b/src/Magicodes.ExporterAndImporter.Excel/ExcelImporter.cs @@ -15,6 +15,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Reflection; using System.Threading.Tasks; using Magicodes.ExporterAndImporter.Core; using Magicodes.ExporterAndImporter.Core.Models; @@ -36,9 +37,39 @@ public class ExcelImporter : IExcelImporter /// 文件名必须填写! - fileName public Task GenerateTemplate(string fileName) where T : class, new() { - using (var importer = new ImportHelper()) + var isMultipleSheetType = false; + var tableType = typeof(T); + List sheetPropertyList = new List(); + var sheetProperties = tableType.GetProperties(); + + for (var i = 0; i < sheetProperties.Length; i++) { - return importer.GenerateTemplate(fileName); + var sheetProperty = sheetProperties[i]; + var importerAttribute = + (sheetProperty.GetCustomAttributes(typeof(ExcelImporterAttribute), true) as ExcelImporterAttribute[])?.FirstOrDefault(); + if (importerAttribute == null) + { + continue; + } + if (!string.IsNullOrEmpty(importerAttribute.SheetName)) + { + isMultipleSheetType = true; + sheetPropertyList.Add(sheetProperty); + } + } + + if (isMultipleSheetType) + { + using (var importer = new ImportMultipleSheetHelper(sheetPropertyList)) + { + return importer.GenerateTemplate(fileName); + } + } + { + using (var importer = new ImportHelper()) + { + return importer.GenerateTemplate(fileName); + } } } @@ -49,9 +80,40 @@ public class ExcelImporter : IExcelImporter /// 二进制字节 public Task GenerateTemplateBytes() where T : class, new() { - using (var importer = new ImportHelper()) + var isMultipleSheetType = false; + var tableType = typeof(T); + List sheetPropertyList = new List(); + var sheetProperties = tableType.GetProperties(); + + for (var i = 0; i < sheetProperties.Length; i++) + { + var sheetProperty = sheetProperties[i]; + var importerAttribute = + (sheetProperty.GetCustomAttributes(typeof(ExcelImporterAttribute), true) as ExcelImporterAttribute[])?.FirstOrDefault(); + if (importerAttribute == null) + { + continue; + } + if (!string.IsNullOrEmpty(importerAttribute.SheetName)) + { + isMultipleSheetType = true; + sheetPropertyList.Add(sheetProperty); + } + } + + if (isMultipleSheetType) { - return importer.GenerateTemplateByte(); + using (var importer = new ImportMultipleSheetHelper(sheetPropertyList)) + { + return importer.GenerateTemplateByte(); + } + } + else + { + using (var importer = new ImportHelper()) + { + return importer.GenerateTemplateByte(); + } } } @@ -216,5 +278,33 @@ public async Task>> ImportSameSheets + /// 判断Dto类型是否为多Sheet类 + /// + /// Dto类型 + /// + private bool DtoTypeIsMultipleSheet() + { + var tableType = typeof(T); + var sheetProperties = tableType.GetProperties(); + + for (var i = 0; i < sheetProperties.Length; i++) + { + var sheetProperty = sheetProperties[i]; + var importerAttribute = + (sheetProperty.GetCustomAttributes(typeof(ExcelImporterAttribute), true) as ExcelImporterAttribute[])?.FirstOrDefault(); + if (importerAttribute == null) + { + continue; + } + if (!string.IsNullOrEmpty(importerAttribute.SheetName)) + { + return true; + } + } + return false; + } } } \ No newline at end of file diff --git a/src/Magicodes.ExporterAndImporter.Excel/Utility/ImportMultipleSheetHelper.cs b/src/Magicodes.ExporterAndImporter.Excel/Utility/ImportMultipleSheetHelper.cs index e1cf1405..f5fe1a09 100644 --- a/src/Magicodes.ExporterAndImporter.Excel/Utility/ImportMultipleSheetHelper.cs +++ b/src/Magicodes.ExporterAndImporter.Excel/Utility/ImportMultipleSheetHelper.cs @@ -29,6 +29,9 @@ public class ImportMultipleSheetHelper : IDisposable private ExcelPackage _excelPackage; + private List _sheetPropertyList; + + private ImportMultipleSheetHelper() { @@ -45,6 +48,15 @@ public ImportMultipleSheetHelper(string filePath) _excelStream = new FileStream(FilePath, FileMode.Open); } + /// + /// Sheet属性信息列表 + /// + /// + public ImportMultipleSheetHelper(List sheetPropertyList) + { + _sheetPropertyList = sheetPropertyList; + } + /// /// 导入全局设置 /// @@ -464,53 +476,137 @@ protected virtual bool ParseImporterHeader() } /// - /// 构建Excel模板 + /// 解析头部 /// - protected virtual void StructureExcel(ExcelPackage excelPackage) + /// + /// 导入实体没有定义ImporterHeader属性 + protected virtual bool ParseImporterHeader(Type sheetType) { - var worksheet = - excelPackage.Workbook.Worksheets.Add(_importDataType.GetDisplayName() ?? - ExcelImporterSettings.SheetName ?? "导入数据"); - if (!ParseImporterHeader()) return; + ImporterHeaderInfos = new List(); + var objProperties = sheetType.GetProperties(); + if (objProperties.Length == 0) return false; - //设置列头 - for (var i = 0; i < ImporterHeaderInfos.Count; i++) + foreach (var propertyInfo in objProperties) { - //忽略 - if (ImporterHeaderInfos[i].Header.IsIgnore) continue; - - worksheet.Cells[ExcelImporterSettings.HeaderRowIndex, i + 1].Value = - ImporterHeaderInfos[i].Header.Name; - if (!string.IsNullOrWhiteSpace(ImporterHeaderInfos[i].Header.Description)) - worksheet.Cells[ExcelImporterSettings.HeaderRowIndex, i + 1].AddComment( - ImporterHeaderInfos[i].Header.Description, - ImporterHeaderInfos[i].Header.Author); - //如果必填,则列头标红sd - if (ImporterHeaderInfos[i].IsRequired) - worksheet.Cells[ExcelImporterSettings.HeaderRowIndex, i + 1].Style.Font.Color.SetColor(Color.Red); - - if (ImporterHeaderInfos[i].MappingValues.Count > 0) + //TODO:简化并重构 + //如果不设置,则自动使用默认定义 + var importerHeaderAttribute = + (propertyInfo.GetCustomAttributes(typeof(ImporterHeaderAttribute), true) as + ImporterHeaderAttribute[])?.FirstOrDefault() ?? new ImporterHeaderAttribute + { + Name = propertyInfo.GetDisplayName() ?? propertyInfo.Name + }; + + if (string.IsNullOrWhiteSpace(importerHeaderAttribute.Name)) + importerHeaderAttribute.Name = propertyInfo.GetDisplayName() ?? propertyInfo.Name; + + //忽略字段处理 + if (importerHeaderAttribute.IsIgnore) continue; + + var colHeader = new ImporterHeaderInfo + { + IsRequired = propertyInfo.IsRequired(), + PropertyName = propertyInfo.Name, + Header = importerHeaderAttribute + }; + ImporterHeaderInfos.Add(colHeader); + + #region 处理值映射 + + var mappings = propertyInfo.GetAttributes().ToList(); + foreach (var mappingAttribute in mappings.Where(mappingAttribute => + !colHeader.MappingValues.ContainsKey(mappingAttribute.Text))) + colHeader.MappingValues.Add(mappingAttribute.Text, mappingAttribute.Value); + + //如果存在自定义映射,则不会生成默认映射 + if (mappings.Any()) continue; + + //为bool类型生成默认映射 + switch (propertyInfo.PropertyType.GetCSharpTypeName()) { - //针对枚举类型和Bool类型添加数据约束 - var range = ExcelCellBase.GetAddress(ExcelImporterSettings.HeaderRowIndex + 1, i + 1, - ExcelPackage.MaxRows, i + 1); - var dataValidations = worksheet.DataValidations.AddListValidation(range); - foreach (var mappingValue in ImporterHeaderInfos[i].MappingValues) - dataValidations.Formula.Values.Add(mappingValue.Key); + case "Boolean": + case "Nullable": + { + if (!colHeader.MappingValues.ContainsKey("是")) colHeader.MappingValues.Add("是", true); + if (!colHeader.MappingValues.ContainsKey("否")) colHeader.MappingValues.Add("否", false); + break; + } } + + var type = propertyInfo.PropertyType; + var isNullable = type.IsNullable(); + if (isNullable) type = type.GetNullableUnderlyingType(); + //为枚举类型生成默认映射 + if (type.IsEnum) + { + var values = type.GetEnumTextAndValues(); + foreach (var value in values.Where(value => !colHeader.MappingValues.ContainsKey(value.Key))) + colHeader.MappingValues.Add(value.Key, value.Value); + + if (isNullable) + if (!colHeader.MappingValues.ContainsKey(string.Empty)) + colHeader.MappingValues.Add(string.Empty, null); + } + + #endregion } - worksheet.Cells.AutoFitColumns(); - worksheet.Cells.Style.WrapText = true; - worksheet.Cells[worksheet.Dimension.Address].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; - worksheet.Cells[worksheet.Dimension.Address].Style.VerticalAlignment = ExcelVerticalAlignment.Center; - - worksheet.Cells[worksheet.Dimension.Address].Style.Border.Left.Style = ExcelBorderStyle.Thin; - worksheet.Cells[worksheet.Dimension.Address].Style.Border.Right.Style = ExcelBorderStyle.Thin; - worksheet.Cells[worksheet.Dimension.Address].Style.Border.Top.Style = ExcelBorderStyle.Thin; - worksheet.Cells[worksheet.Dimension.Address].Style.Border.Bottom.Style = ExcelBorderStyle.Thin; - worksheet.Cells[worksheet.Dimension.Address].Style.Fill.PatternType = ExcelFillStyle.Solid; - worksheet.Cells[worksheet.Dimension.Address].Style.Fill.BackgroundColor.SetColor(Color.DarkSeaGreen); + return true; + } + /// + /// 构建Excel模板 + /// + protected virtual void StructureExcel(ExcelPackage excelPackage) + { + foreach (var sheetProperty in _sheetPropertyList) + { + var sheetType= sheetProperty.PropertyType; + var importerAttribute = + (sheetProperty.GetCustomAttributes(typeof(ExcelImporterAttribute), true) as ExcelImporterAttribute[])?.FirstOrDefault(); + + var worksheet = + excelPackage.Workbook.Worksheets.Add(importerAttribute.SheetName); + if (!ParseImporterHeader(sheetType)) return; + + //设置列头 + for (var i = 0; i < ImporterHeaderInfos.Count; i++) + { + //忽略 + if (ImporterHeaderInfos[i].Header.IsIgnore) continue; + + worksheet.Cells[importerAttribute.HeaderRowIndex, i + 1].Value = + ImporterHeaderInfos[i].Header.Name; + if (!string.IsNullOrWhiteSpace(ImporterHeaderInfos[i].Header.Description)) + worksheet.Cells[importerAttribute.HeaderRowIndex, i + 1].AddComment( + ImporterHeaderInfos[i].Header.Description, + ImporterHeaderInfos[i].Header.Author); + //如果必填,则列头标红 + if (ImporterHeaderInfos[i].IsRequired) + worksheet.Cells[importerAttribute.HeaderRowIndex, i + 1].Style.Font.Color.SetColor(Color.Red); + + if (ImporterHeaderInfos[i].MappingValues.Count > 0) + { + //针对枚举类型和Bool类型添加数据约束 + var range = ExcelCellBase.GetAddress(importerAttribute.HeaderRowIndex + 1, i + 1, + ExcelPackage.MaxRows, i + 1); + var dataValidations = worksheet.DataValidations.AddListValidation(range); + foreach (var mappingValue in ImporterHeaderInfos[i].MappingValues) + dataValidations.Formula.Values.Add(mappingValue.Key); + } + } + + worksheet.Cells.AutoFitColumns(); + worksheet.Cells.Style.WrapText = true; + worksheet.Cells[worksheet.Dimension.Address].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; + worksheet.Cells[worksheet.Dimension.Address].Style.VerticalAlignment = ExcelVerticalAlignment.Center; + + worksheet.Cells[worksheet.Dimension.Address].Style.Border.Left.Style = ExcelBorderStyle.Thin; + worksheet.Cells[worksheet.Dimension.Address].Style.Border.Right.Style = ExcelBorderStyle.Thin; + worksheet.Cells[worksheet.Dimension.Address].Style.Border.Top.Style = ExcelBorderStyle.Thin; + worksheet.Cells[worksheet.Dimension.Address].Style.Border.Bottom.Style = ExcelBorderStyle.Thin; + worksheet.Cells[worksheet.Dimension.Address].Style.Fill.PatternType = ExcelFillStyle.Solid; + worksheet.Cells[worksheet.Dimension.Address].Style.Fill.BackgroundColor.SetColor(Color.DarkSeaGreen); + } } /// diff --git a/src/Magicodes.ExporterAndImporter.Tests/ExcelImporterMultipleSheet_Tests.cs b/src/Magicodes.ExporterAndImporter.Tests/ExcelImporterMultipleSheet_Tests.cs index 10679b8d..ab0f5282 100644 --- a/src/Magicodes.ExporterAndImporter.Tests/ExcelImporterMultipleSheet_Tests.cs +++ b/src/Magicodes.ExporterAndImporter.Tests/ExcelImporterMultipleSheet_Tests.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -110,5 +111,26 @@ public async Task ClassStudentInfoImporter_SaveLabelingError_Test() _testOutputHelper.WriteLine($"保存标注错误Excel文件已生成,路径:{labelingErrorExcelPath}"); } } + + + [Fact(DisplayName = "多Sheet导出模板")] + public async Task MultipleSheetGenerateTemplate_Test() + { + var Importer = new ExcelImporter(); + var bytes1 = await Importer.GenerateTemplateBytes(); + var str1 = Convert.ToBase64String(bytes1); + _testOutputHelper.WriteLine($"已导出多Sheet的Excel模板,Base64:{str1}"); + var tempaltePath2 = Path.Combine(Directory.GetCurrentDirectory(), "TestFiles", "Import", "学生基础数据及缴费流水号模板导出.xlsx"); + await Importer.GenerateTemplate(tempaltePath2); + + if (File.Exists(tempaltePath2)) + { + _testOutputHelper.WriteLine($"已导出Excel模板,路径:{tempaltePath2}"); + } + //一个Sheet导出 + var bytes3 = await Importer.GenerateTemplateBytes(); + var str3 = Convert.ToBase64String(bytes3); + _testOutputHelper.WriteLine($"已导出单个Sheet的Excel模板,Base64:{str3}"); + } } }