feat: 分区明细导入模板去掉国家名称,并增加枚举值 Sheet
All checks were successful
Build and Deploy / deploy (push) Successful in 1m0s
All checks were successful
Build and Deploy / deploy (push) Successful in 1m0s
导入模板只保留国家代码;Sheet2 列出匹配维度/方式的编码与名称,导入时按代码补国家名称。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
5bf81b5138
commit
04dc9ca1ff
@ -11,6 +11,9 @@ namespace Oms.Application.Shared;
|
||||
/// </summary>
|
||||
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 Dictionary<string, string> HeaderAliases = new(StringComparer.OrdinalIgnoreCase)
|
||||
@ -48,12 +51,11 @@ public static class KpiAreaInfoImportHelper
|
||||
|
||||
public static async Task<byte[]> BuildTemplateBytesAsync()
|
||||
{
|
||||
var rows = new List<Dictionary<string, object?>>
|
||||
var templateRows = new List<Dictionary<string, object?>>
|
||||
{
|
||||
new()
|
||||
{
|
||||
["国家代码"] = "US",
|
||||
["国家名称"] = "美国",
|
||||
["匹配维度"] = "zip",
|
||||
["匹配方式"] = "range",
|
||||
["州/省"] = "",
|
||||
@ -64,7 +66,6 @@ public static class KpiAreaInfoImportHelper
|
||||
new()
|
||||
{
|
||||
["国家代码"] = "US",
|
||||
["国家名称"] = "美国",
|
||||
["匹配维度"] = "zip",
|
||||
["匹配方式"] = "prefix",
|
||||
["州/省"] = "",
|
||||
@ -75,7 +76,6 @@ public static class KpiAreaInfoImportHelper
|
||||
new()
|
||||
{
|
||||
["国家代码"] = "US",
|
||||
["国家名称"] = "美国",
|
||||
["匹配维度"] = "state",
|
||||
["匹配方式"] = "exact",
|
||||
["州/省"] = "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 MiniExcel.SaveAsAsync(stream, rows);
|
||||
await MiniExcel.SaveAsAsync(stream, sheets);
|
||||
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) =>
|
||||
areaType?.Trim().ToLowerInvariant() switch
|
||||
{
|
||||
@ -101,7 +134,20 @@ public static class KpiAreaInfoImportHelper
|
||||
|
||||
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 rowNumber = 1;
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using FluentAssertions;
|
||||
using MiniExcelLibs;
|
||||
using Oms.Application.Shared;
|
||||
using Oms.Domain.ChannelsAggregate.Entities;
|
||||
using Oms.Domain.SystemAggregate.Entities;
|
||||
@ -7,6 +8,63 @@ namespace Oms.Tests;
|
||||
|
||||
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]
|
||||
public void PrepareEntityForImport_ValidRow_ShouldFillCountryName()
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user