diff --git a/README.zh-CN.md b/README.zh-CN.md index c5e4d4c4..0ee706f4 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -228,6 +228,31 @@ public Genders Gender { get; set; } ``` +- **也可以继承“ValueMappingsBaseAttribute”特性基类实现值映射关系,目前仅可用于枚举和Bool类型,支持导入导出。** +```csharp + [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] + public class GenderLocalAttribute : ValueMappingsBaseAttribute + { + public override Dictionary GetMappings(PropertyInfo propertyInfo) + { + var res= new Dictionary(); + res.Add("男",0); + res.Add("女",1); + return res; + } + } + + + /// + /// 性别 + /// + [ImporterHeader(Name = "性别")] + [Required(ErrorMessage = "性别不能为空")] + [GenderLocal] + public Genders Gender { get; set; } +``` + + - **支持枚举和Bool类型的导入数据验证项的生成,以及相关数据转换** - **枚举默认情况下会自动获取枚举的描述、显示名、名称和值生成数据项** diff --git a/src/Magicodes.ExporterAndImporter.Core/Extension/Extension.cs b/src/Magicodes.ExporterAndImporter.Core/Extension/Extension.cs index 1bf9f1de..3180bc89 100644 --- a/src/Magicodes.ExporterAndImporter.Core/Extension/Extension.cs +++ b/src/Magicodes.ExporterAndImporter.Core/Extension/Extension.cs @@ -322,7 +322,18 @@ public static int GetLargestContinuous(this List numList) public static void ValueMapping(this PropertyInfo propertyInfo, ref Dictionary directory) { #region 处理值映射 + //ValueMappingsBaseAttribute + var valueMappings = propertyInfo.GetAttributes(true).FirstOrDefault()?.GetMappings(propertyInfo); + if(valueMappings != null ) + { + foreach (var valueMapping in valueMappings) + { + if (!directory.ContainsKey(valueMapping.Key)) directory.Add(valueMapping.Key, valueMapping.Value); + } + if (valueMappings.Count > 0) return; + } + //ValueMappingAttribute var mappings = propertyInfo.GetAttributes().ToList(); var objects = directory; foreach (var mappingAttribute in mappings.Where(mappingAttribute => @@ -363,4 +374,4 @@ public static void ValueMapping(this PropertyInfo propertyInfo, ref Dictionary /// /// - Task> Import(Stream stream,Stream labelingFileStream) where T : class, new(); + Task> Import(Stream stream, Stream labelingFileStream, Func, ImportResult> importResultCallback = null) where T : class, new(); } } \ No newline at end of file diff --git a/src/Magicodes.ExporterAndImporter.Core/ValueMappingsBaseAttribute.cs b/src/Magicodes.ExporterAndImporter.Core/ValueMappingsBaseAttribute.cs new file mode 100644 index 00000000..92943493 --- /dev/null +++ b/src/Magicodes.ExporterAndImporter.Core/ValueMappingsBaseAttribute.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; + +namespace Magicodes.IE.Core +{ + /// + /// 值映射 + /// + public abstract class ValueMappingsBaseAttribute : Attribute + { + /// + /// 根据字段信息获取映射 + /// + /// + /// + public abstract Dictionary GetMappings(PropertyInfo propertyInfo); + } +} diff --git a/src/Magicodes.ExporterAndImporter.Csv/CsvImporter.cs b/src/Magicodes.ExporterAndImporter.Csv/CsvImporter.cs index 22ce7bb2..cc8c5834 100644 --- a/src/Magicodes.ExporterAndImporter.Csv/CsvImporter.cs +++ b/src/Magicodes.ExporterAndImporter.Csv/CsvImporter.cs @@ -89,7 +89,7 @@ public class CsvImporter : ICsvImporter /// /// /// - public Task> Import(Stream stream, Stream labelingFileStream) where T : class, new() + public Task> Import(Stream stream, Stream labelingFileStream, Func, ImportResult> importResultCallback = null) where T : class, new() { using (var importer = new ImportHelper(stream)) { diff --git a/src/Magicodes.ExporterAndImporter.Excel/ExcelImporter.cs b/src/Magicodes.ExporterAndImporter.Excel/ExcelImporter.cs index 474d0942..2f2186e7 100644 --- a/src/Magicodes.ExporterAndImporter.Excel/ExcelImporter.cs +++ b/src/Magicodes.ExporterAndImporter.Excel/ExcelImporter.cs @@ -169,11 +169,11 @@ public class ExcelImporter : IExcelImporter /// /// /// - public Task> Import(Stream stream, Stream labelingFileStream) where T : class, new() + public Task> Import(Stream stream, Stream labelingFileStream, Func, ImportResult> importResultCallback = null) where T : class, new() { using (var importer = new ImportHelper(stream, labelingFileStream)) { - return importer.Import(); + return importer.Import(importResultCallback: importResultCallback); } } diff --git a/src/Magicodes.ExporterAndImporter.Tests/ExcelExporterWithXSSFWorkbook_Tests.cs b/src/Magicodes.ExporterAndImporter.Tests/ExcelExporterWithXSSFWorkbook_Tests.cs index 805b73e4..c8254c9b 100644 --- a/src/Magicodes.ExporterAndImporter.Tests/ExcelExporterWithXSSFWorkbook_Tests.cs +++ b/src/Magicodes.ExporterAndImporter.Tests/ExcelExporterWithXSSFWorkbook_Tests.cs @@ -958,8 +958,55 @@ public async Task ValueMapping_Test() } } - - + [Fact(DisplayName = "ValueMappingsBase测试#544")] + public async Task ValueMappingsBase_Test() + { + IExporter exporter = new ExcelExporter(); + var filePath = GetTestFilePath($"{nameof(ValueMappingsBase_Test)}.xlsx"); + DeleteFile(filePath); + var list = new List() + { + new Issue544() + { + Gender ="男", + IsAlumni = true, + Name ="张三", + IsAlumni2 = true, + }, + new Issue544() + { + Gender ="男", + IsAlumni = false, + Name ="张三", + IsAlumni2 = true, + }, + new Issue544() + { + Gender ="男", + IsAlumni = null, + Name ="张三", + IsAlumni2 = false, + }, + }; + var result = await exporter.ExportWithXSSFWorkbook(filePath, list); + result.ShouldNotBeNull(); + File.Exists(filePath).ShouldBeTrue(); + using (var pck = new ExcelPackage(new FileInfo(filePath))) + { + pck.Workbook.Worksheets.Count.ShouldBe(1); + var sheet = pck.Workbook.Worksheets.First(); + sheet.Cells["D2"].Text.ShouldBe("是"); + sheet.Cells["D3"].Text.ShouldBe("是"); + sheet.Cells["D4"].Text.ShouldBe("否"); + + sheet.Cells["C2"].Text.ShouldBe("是"); + sheet.Cells["C3"].Text.ShouldBe("否"); + sheet.Cells["C4"].Text.ShouldBe(""); + } + } + + + [Fact(DisplayName = "导出日期格式化#331")] public async Task DateTimeExport_Test() { diff --git a/src/Magicodes.ExporterAndImporter.Tests/ExcelExporter_Tests.cs b/src/Magicodes.ExporterAndImporter.Tests/ExcelExporter_Tests.cs index 220ecc0f..533df41e 100644 --- a/src/Magicodes.ExporterAndImporter.Tests/ExcelExporter_Tests.cs +++ b/src/Magicodes.ExporterAndImporter.Tests/ExcelExporter_Tests.cs @@ -964,6 +964,55 @@ public async Task ValueMapping_Test() } + [Fact(DisplayName = "ValueMappingsBase测试#544")] + public async Task ValueMappingsBase_Test() + { + IExporter exporter = new ExcelExporter(); + var filePath = GetTestFilePath($"{nameof(ValueMappingsBase_Test)}.xlsx"); + DeleteFile(filePath); + var list = new List() + { + new Issue544() + { + Gender ="男", + IsAlumni = true, + Name ="张三", + IsAlumni2 = true, + }, + new Issue544() + { + Gender ="男", + IsAlumni = false, + Name ="张三", + IsAlumni2 = true, + }, + new Issue544() + { + Gender ="男", + IsAlumni = null, + Name ="张三", + IsAlumni2 = false, + }, + }; + var result = await exporter.Export(filePath, list); + result.ShouldNotBeNull(); + File.Exists(filePath).ShouldBeTrue(); + using (var pck = new ExcelPackage(new FileInfo(filePath))) + { + pck.Workbook.Worksheets.Count.ShouldBe(1); + var sheet = pck.Workbook.Worksheets.First(); + sheet.Cells["D2"].Text.ShouldBe("是"); + sheet.Cells["D3"].Text.ShouldBe("是"); + sheet.Cells["D4"].Text.ShouldBe("否"); + + sheet.Cells["C2"].Text.ShouldBe("是"); + sheet.Cells["C3"].Text.ShouldBe("否"); + sheet.Cells["C4"].Text.ShouldBe(""); + } + } + + + [Fact(DisplayName = "导出日期格式化#331")] public async Task DateTimeExport_Test() diff --git a/src/Magicodes.ExporterAndImporter.Tests/Models/Export/ExporterHeaderFilterTestData.cs b/src/Magicodes.ExporterAndImporter.Tests/Models/Export/ExporterHeaderFilterTestData.cs index 09ded2bd..afaca293 100644 --- a/src/Magicodes.ExporterAndImporter.Tests/Models/Export/ExporterHeaderFilterTestData.cs +++ b/src/Magicodes.ExporterAndImporter.Tests/Models/Export/ExporterHeaderFilterTestData.cs @@ -59,7 +59,8 @@ public class ExporterHeaderFilterTestData1 [ExporterHeader(DisplayName = "加粗文本", IsBold = true)] public string Text { get; set; } - [ExporterHeader(DisplayName = "普通文本")] public string Text2 { get; set; } + [ExporterHeader(DisplayName = "普通文本")] + public string Text2 { get; set; } [ExporterHeader(DisplayName = "忽略", IsIgnore = true)] public string Text3 { get; set; } diff --git a/src/Magicodes.ExporterAndImporter.Tests/Models/Export/Issue544.cs b/src/Magicodes.ExporterAndImporter.Tests/Models/Export/Issue544.cs new file mode 100644 index 00000000..bf3603cb --- /dev/null +++ b/src/Magicodes.ExporterAndImporter.Tests/Models/Export/Issue544.cs @@ -0,0 +1,49 @@ +using Magicodes.ExporterAndImporter.Core; +using Magicodes.ExporterAndImporter.Excel; +using Magicodes.IE.Core; +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace Magicodes.ExporterAndImporter.Tests.Models.Export +{ + [ExcelExporter(Name = "导出结果", TableStyle = OfficeOpenXml.Table.TableStyles.None)] + public class Issue544 + { + /// + /// 名称 + /// + [ExporterHeader(DisplayName = "姓名")] + public string Name { get; set; } + + /// + /// 性别 + /// + [ExporterHeader(DisplayName = "性别")] + public string Gender { get; set; } + + /// + /// 是否校友 + /// + [ExporterHeader(DisplayName = "是否校友")] + [BoolLocal337] + public bool? IsAlumni { get; set; } + + [ExporterHeader(DisplayName = "是否校友2")] + [BoolLocal337] + public bool IsAlumni2 { get; set; } + } + + + [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] + public class BoolLocal337Attribute : ValueMappingsBaseAttribute + { + public override Dictionary GetMappings(PropertyInfo propertyInfo) + { + var res= new Dictionary(); + res.Add("是",true); + res.Add("否",false); + return res; + } + } +} diff --git a/src/Magicodes.ExporterAndImporter.Tests/Models/Import/ImportWithOnlyErrorRowsDto.cs b/src/Magicodes.ExporterAndImporter.Tests/Models/Import/ImportWithOnlyErrorRowsDto.cs index 268849af..a2282956 100644 --- a/src/Magicodes.ExporterAndImporter.Tests/Models/Import/ImportWithOnlyErrorRowsDto.cs +++ b/src/Magicodes.ExporterAndImporter.Tests/Models/Import/ImportWithOnlyErrorRowsDto.cs @@ -39,7 +39,7 @@ public class ImportWithOnlyErrorRowsDto /// [ImporterHeader(Name = "身份证号", IsAllowRepeat = false)] [Required(ErrorMessage = "身份证号不能为空")] - [MaxLength(18, ErrorMessage = "身份证字数超出最大限制,请修改!")] + [MaxLength(18, ErrorMessage = "身份证号字数超出最大限制,请修改!")] public string IdCard { get; set; } ///