20261008-ide1.0发布 #1
@ -11,6 +11,9 @@ namespace Oms.Application.Shared;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class KpiAreaInfoImportHelper
|
public static class KpiAreaInfoImportHelper
|
||||||
{
|
{
|
||||||
|
public const string TemplateSheetName = "导入模板";
|
||||||
|
public const string EnumSheetName = "枚举值";
|
||||||
|
|
||||||
private static readonly Regex ChinesePattern = new(@"[\u4E00-\u9FA5]", RegexOptions.Compiled);
|
private static readonly Regex ChinesePattern = new(@"[\u4E00-\u9FA5]", RegexOptions.Compiled);
|
||||||
|
|
||||||
private static readonly Dictionary<string, string> HeaderAliases = new(StringComparer.OrdinalIgnoreCase)
|
private static readonly Dictionary<string, string> HeaderAliases = new(StringComparer.OrdinalIgnoreCase)
|
||||||
@ -48,12 +51,11 @@ public static class KpiAreaInfoImportHelper
|
|||||||
|
|
||||||
public static async Task<byte[]> BuildTemplateBytesAsync()
|
public static async Task<byte[]> BuildTemplateBytesAsync()
|
||||||
{
|
{
|
||||||
var rows = new List<Dictionary<string, object?>>
|
var templateRows = new List<Dictionary<string, object?>>
|
||||||
{
|
{
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
["国家代码"] = "US",
|
["国家代码"] = "US",
|
||||||
["国家名称"] = "美国",
|
|
||||||
["匹配维度"] = "zip",
|
["匹配维度"] = "zip",
|
||||||
["匹配方式"] = "range",
|
["匹配方式"] = "range",
|
||||||
["州/省"] = "",
|
["州/省"] = "",
|
||||||
@ -64,7 +66,6 @@ public static class KpiAreaInfoImportHelper
|
|||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
["国家代码"] = "US",
|
["国家代码"] = "US",
|
||||||
["国家名称"] = "美国",
|
|
||||||
["匹配维度"] = "zip",
|
["匹配维度"] = "zip",
|
||||||
["匹配方式"] = "prefix",
|
["匹配方式"] = "prefix",
|
||||||
["州/省"] = "",
|
["州/省"] = "",
|
||||||
@ -75,7 +76,6 @@ public static class KpiAreaInfoImportHelper
|
|||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
["国家代码"] = "US",
|
["国家代码"] = "US",
|
||||||
["国家名称"] = "美国",
|
|
||||||
["匹配维度"] = "state",
|
["匹配维度"] = "state",
|
||||||
["匹配方式"] = "exact",
|
["匹配方式"] = "exact",
|
||||||
["州/省"] = "CA",
|
["州/省"] = "CA",
|
||||||
@ -85,11 +85,44 @@ public static class KpiAreaInfoImportHelper
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var enumRows = new List<Dictionary<string, object?>>
|
||||||
|
{
|
||||||
|
new() { ["枚举类型"] = "匹配维度", ["编码"] = "country", ["名称"] = "仅国家" },
|
||||||
|
new() { ["枚举类型"] = "匹配维度", ["编码"] = "zip", ["名称"] = "邮编" },
|
||||||
|
new() { ["枚举类型"] = "匹配维度", ["编码"] = "state", ["名称"] = "州/省" },
|
||||||
|
new() { ["枚举类型"] = "匹配维度", ["编码"] = "city", ["名称"] = "城市" },
|
||||||
|
new() { ["枚举类型"] = "匹配方式", ["编码"] = "prefix", ["名称"] = "前缀" },
|
||||||
|
new() { ["枚举类型"] = "匹配方式", ["编码"] = "exact", ["名称"] = "精确" },
|
||||||
|
new() { ["枚举类型"] = "匹配方式", ["编码"] = "range", ["名称"] = "区间" },
|
||||||
|
new() { ["枚举类型"] = "匹配方式", ["编码"] = "all", ["名称"] = "不限" }
|
||||||
|
};
|
||||||
|
|
||||||
|
var sheets = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
[TemplateSheetName] = templateRows,
|
||||||
|
[EnumSheetName] = enumRows
|
||||||
|
};
|
||||||
|
|
||||||
await using var stream = new MemoryStream();
|
await using var stream = new MemoryStream();
|
||||||
await MiniExcel.SaveAsAsync(stream, rows);
|
await MiniExcel.SaveAsAsync(stream, sheets);
|
||||||
return stream.ToArray();
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static string? ResolveImportSheetName(IEnumerable<string> sheetNames)
|
||||||
|
{
|
||||||
|
var names = sheetNames.Where(x => !string.IsNullOrWhiteSpace(x)).ToList();
|
||||||
|
if (names.Count == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return names.FirstOrDefault(x =>
|
||||||
|
string.Equals(x, TemplateSheetName, StringComparison.OrdinalIgnoreCase))
|
||||||
|
?? names.FirstOrDefault(x =>
|
||||||
|
!string.Equals(x, EnumSheetName, StringComparison.OrdinalIgnoreCase))
|
||||||
|
?? names[0];
|
||||||
|
}
|
||||||
|
|
||||||
public static string ResolveTemplateFileName(string? areaType) =>
|
public static string ResolveTemplateFileName(string? areaType) =>
|
||||||
areaType?.Trim().ToLowerInvariant() switch
|
areaType?.Trim().ToLowerInvariant() switch
|
||||||
{
|
{
|
||||||
@ -101,7 +134,20 @@ public static class KpiAreaInfoImportHelper
|
|||||||
|
|
||||||
public static async Task<List<(int RowNumber, KpiAreaInfo Entity)>> ParseImportRowsAsync(Stream fileStream)
|
public static async Task<List<(int RowNumber, KpiAreaInfo Entity)>> ParseImportRowsAsync(Stream fileStream)
|
||||||
{
|
{
|
||||||
var rows = await MiniExcel.QueryAsync(fileStream, useHeaderRow: true);
|
if (fileStream.CanSeek)
|
||||||
|
{
|
||||||
|
fileStream.Position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sheetNames = MiniExcel.GetSheetNames(fileStream);
|
||||||
|
var sheetName = ResolveImportSheetName(sheetNames);
|
||||||
|
|
||||||
|
if (fileStream.CanSeek)
|
||||||
|
{
|
||||||
|
fileStream.Position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rows = await MiniExcel.QueryAsync(fileStream, useHeaderRow: true, sheetName: sheetName);
|
||||||
var result = new List<(int RowNumber, KpiAreaInfo Entity)>();
|
var result = new List<(int RowNumber, KpiAreaInfo Entity)>();
|
||||||
var rowNumber = 1;
|
var rowNumber = 1;
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
|
using MiniExcelLibs;
|
||||||
using Oms.Application.Shared;
|
using Oms.Application.Shared;
|
||||||
using Oms.Domain.ChannelsAggregate.Entities;
|
using Oms.Domain.ChannelsAggregate.Entities;
|
||||||
using Oms.Domain.SystemAggregate.Entities;
|
using Oms.Domain.SystemAggregate.Entities;
|
||||||
@ -7,6 +8,63 @@ namespace Oms.Tests;
|
|||||||
|
|
||||||
public class KpiAreaInfoImportHelperTests
|
public class KpiAreaInfoImportHelperTests
|
||||||
{
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task BuildTemplateBytesAsync_ShouldUseNamedSheetsWithoutCountryName()
|
||||||
|
{
|
||||||
|
var bytes = await KpiAreaInfoImportHelper.BuildTemplateBytesAsync();
|
||||||
|
await using var stream = new MemoryStream(bytes);
|
||||||
|
|
||||||
|
var sheetNames = MiniExcel.GetSheetNames(stream);
|
||||||
|
sheetNames.Should().Equal(
|
||||||
|
KpiAreaInfoImportHelper.TemplateSheetName,
|
||||||
|
KpiAreaInfoImportHelper.EnumSheetName);
|
||||||
|
|
||||||
|
stream.Position = 0;
|
||||||
|
var templateRows = (await MiniExcel.QueryAsync(
|
||||||
|
stream,
|
||||||
|
useHeaderRow: true,
|
||||||
|
sheetName: KpiAreaInfoImportHelper.TemplateSheetName))
|
||||||
|
.Cast<IDictionary<string, object>>()
|
||||||
|
.ToList();
|
||||||
|
templateRows.Should().NotBeEmpty();
|
||||||
|
templateRows[0].Keys.Should().NotContain(key => key.Contains("国家名称"));
|
||||||
|
templateRows[0].Should().ContainKey("国家代码");
|
||||||
|
templateRows[0].Should().ContainKey("匹配维度");
|
||||||
|
templateRows[0].Should().ContainKey("匹配方式");
|
||||||
|
|
||||||
|
stream.Position = 0;
|
||||||
|
var enumRows = (await MiniExcel.QueryAsync(
|
||||||
|
stream,
|
||||||
|
useHeaderRow: true,
|
||||||
|
sheetName: KpiAreaInfoImportHelper.EnumSheetName))
|
||||||
|
.Cast<IDictionary<string, object>>()
|
||||||
|
.ToList();
|
||||||
|
enumRows.Should().HaveCount(8);
|
||||||
|
enumRows.Should().Contain(row =>
|
||||||
|
Convert.ToString(row["枚举类型"]) == "匹配维度"
|
||||||
|
&& Convert.ToString(row["编码"]) == "zip"
|
||||||
|
&& Convert.ToString(row["名称"]) == "邮编");
|
||||||
|
enumRows.Should().Contain(row =>
|
||||||
|
Convert.ToString(row["枚举类型"]) == "匹配方式"
|
||||||
|
&& Convert.ToString(row["编码"]) == "range"
|
||||||
|
&& Convert.ToString(row["名称"]) == "区间");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ParseImportRowsAsync_ShouldReadTemplateSheetOnly()
|
||||||
|
{
|
||||||
|
var bytes = await KpiAreaInfoImportHelper.BuildTemplateBytesAsync();
|
||||||
|
await using var stream = new MemoryStream(bytes);
|
||||||
|
|
||||||
|
var rows = await KpiAreaInfoImportHelper.ParseImportRowsAsync(stream);
|
||||||
|
|
||||||
|
rows.Should().HaveCount(3);
|
||||||
|
rows[0].Entity.CountryCode.Should().Be("US");
|
||||||
|
rows[0].Entity.CountryName.Should().BeNull();
|
||||||
|
rows[0].Entity.MatchDim.Should().Be("zip");
|
||||||
|
rows[0].Entity.MatchMode.Should().Be("range");
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void PrepareEntityForImport_ValidRow_ShouldFillCountryName()
|
public void PrepareEntityForImport_ValidRow_ShouldFillCountryName()
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user