118 lines
3.9 KiB
C#
118 lines
3.9 KiB
C#
using DongfangHydro.Dashboard.Api.Data;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
namespace DongfangHydro.Dashboard.Api.Importing;
|
|
|
|
public sealed record BomImportCommand(string FilePath, bool PurgeDemo, bool ValidateOnly, bool Force)
|
|
{
|
|
public static BomImportCommand? Parse(string[] args)
|
|
{
|
|
if (args.Length == 0 || !string.Equals(args[0], "import-bom", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
string? filePath = null;
|
|
var purgeDemo = false;
|
|
var validateOnly = false;
|
|
var force = false;
|
|
for (var index = 1; index < args.Length; index++)
|
|
{
|
|
switch (args[index])
|
|
{
|
|
case "--file":
|
|
if (index + 1 >= args.Length || args[index + 1].StartsWith("--", StringComparison.Ordinal))
|
|
{
|
|
throw new BomImportException("import-bom 的 --file 参数必须提供 Excel 路径。");
|
|
}
|
|
|
|
filePath = args[++index];
|
|
break;
|
|
case "--purge-demo":
|
|
purgeDemo = true;
|
|
break;
|
|
case "--validate-only":
|
|
validateOnly = true;
|
|
break;
|
|
case "--force":
|
|
force = true;
|
|
break;
|
|
default:
|
|
throw new BomImportException($"不支持的 import-bom 参数:{args[index]}。");
|
|
}
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(filePath))
|
|
{
|
|
throw new BomImportException("import-bom 必须提供 --file <xlsx路径>。");
|
|
}
|
|
|
|
return new BomImportCommand(filePath, purgeDemo, validateOnly, force);
|
|
}
|
|
}
|
|
|
|
public static class BomImportCommandRunner
|
|
{
|
|
public static async Task<object> RunAsync(
|
|
IServiceProvider services,
|
|
BomImportCommand command,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var fullPath = Path.GetFullPath(command.FilePath);
|
|
if (!File.Exists(fullPath))
|
|
{
|
|
throw new BomImportException($"Excel 文件不存在:{fullPath}");
|
|
}
|
|
|
|
BomImportDocument document;
|
|
await using (var stream = File.OpenRead(fullPath))
|
|
{
|
|
document = BomWorkbookParser.Parse(stream, Path.GetFileName(fullPath));
|
|
}
|
|
|
|
var levelCounts = document.BomNodes
|
|
.GroupBy(node => node.Level)
|
|
.OrderBy(group => group.Key)
|
|
.ToDictionary(group => group.Key, group => group.Count());
|
|
if (command.ValidateOnly)
|
|
{
|
|
return new BomValidationReport(
|
|
fullPath,
|
|
document.Metadata.SourceDocumentCode,
|
|
document.Metadata.WorkOrderCode,
|
|
document.Metadata.SourceFileHash,
|
|
document.BlockCount,
|
|
document.BomNodes.Count,
|
|
document.MaterialQuotas.Count,
|
|
levelCounts,
|
|
document.Warnings);
|
|
}
|
|
|
|
await using var scope = services.CreateAsyncScope();
|
|
var dbContext = scope.ServiceProvider.GetRequiredService<DashboardDbContext>();
|
|
if (dbContext.Database.IsRelational())
|
|
{
|
|
await dbContext.Database.MigrateAsync(cancellationToken);
|
|
}
|
|
else
|
|
{
|
|
await dbContext.Database.EnsureCreatedAsync(cancellationToken);
|
|
}
|
|
|
|
return await scope.ServiceProvider.GetRequiredService<BomImportService>()
|
|
.ImportAsync(document, command.PurgeDemo, cancellationToken, command.Force);
|
|
}
|
|
}
|
|
|
|
public sealed record BomValidationReport(
|
|
string FilePath,
|
|
string SourceDocumentCode,
|
|
string WorkOrderCode,
|
|
string SourceFileHash,
|
|
int Blocks,
|
|
int BomNodes,
|
|
int MaterialQuotas,
|
|
IReadOnlyDictionary<int, int> LevelCounts,
|
|
IReadOnlyList<string> Warnings);
|