feat(uns): equipment CSV import folded into the tree toolbar
This commit is contained in:
@@ -504,6 +504,81 @@ public sealed class UnsTreeService(IDbContextFactory<OtOpcUaConfigDbContext> dbF
|
||||
return new UnsMutationResult(true, null);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<EquipmentImportResult> ImportEquipmentAsync(
|
||||
IReadOnlyList<EquipmentInput> rows,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
await using var db = await dbFactory.CreateDbContextAsync(ct);
|
||||
|
||||
// Known lines and the MachineCodes already in the fleet, read once up front. The seen-set
|
||||
// tracks MachineCodes inserted earlier in this same batch so two CSV rows that share a
|
||||
// MachineCode skip the duplicate the same way the original ImportEquipment.razor did.
|
||||
var lineSet = (await db.UnsLines.AsNoTracking().Select(l => l.UnsLineId).ToListAsync(ct))
|
||||
.ToHashSet(StringComparer.Ordinal);
|
||||
var existing = (await db.Equipment.AsNoTracking().Select(e => e.MachineCode).ToListAsync(ct))
|
||||
.ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var inserted = 0;
|
||||
var skipped = 0;
|
||||
var errors = new List<string>();
|
||||
|
||||
foreach (var row in rows)
|
||||
{
|
||||
// Existing MachineCode (in DB or earlier in this batch) → skip, never an error.
|
||||
if (existing.Contains(row.MachineCode))
|
||||
{
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!lineSet.Contains(row.UnsLineId))
|
||||
{
|
||||
errors.Add($"Row '{row.MachineCode}': UNS line '{row.UnsLineId}' not found.");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Reuse the #122 guard: it reports an unknown DriverInstanceId and a driver/line cluster
|
||||
// mismatch, and is a no-op for driver-less rows.
|
||||
var guard = await CheckDriverClusterGuardAsync(db, row, ct);
|
||||
if (guard is not null)
|
||||
{
|
||||
errors.Add($"Row '{row.MachineCode}': {guard.Value.Error}");
|
||||
continue;
|
||||
}
|
||||
|
||||
var uuid = Guid.NewGuid();
|
||||
var equipmentId = $"EQ-{uuid.ToString("N")[..12]}";
|
||||
|
||||
db.Equipment.Add(new Equipment
|
||||
{
|
||||
EquipmentId = equipmentId,
|
||||
EquipmentUuid = uuid,
|
||||
DriverInstanceId = string.IsNullOrWhiteSpace(row.DriverInstanceId) ? null : row.DriverInstanceId,
|
||||
UnsLineId = row.UnsLineId,
|
||||
Name = row.Name,
|
||||
MachineCode = row.MachineCode,
|
||||
ZTag = string.IsNullOrWhiteSpace(row.ZTag) ? null : row.ZTag,
|
||||
SAPID = string.IsNullOrWhiteSpace(row.SAPID) ? null : row.SAPID,
|
||||
Manufacturer = row.Manufacturer,
|
||||
Model = row.Model,
|
||||
SerialNumber = row.SerialNumber,
|
||||
HardwareRevision = row.HardwareRevision,
|
||||
SoftwareRevision = row.SoftwareRevision,
|
||||
YearOfConstruction = row.YearOfConstruction,
|
||||
AssetLocation = row.AssetLocation,
|
||||
ManufacturerUri = row.ManufacturerUri,
|
||||
DeviceManualUri = row.DeviceManualUri,
|
||||
Enabled = row.Enabled,
|
||||
});
|
||||
existing.Add(row.MachineCode);
|
||||
inserted++;
|
||||
}
|
||||
|
||||
await db.SaveChangesAsync(ct);
|
||||
return new EquipmentImportResult(inserted, skipped, errors);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<UnsMutationResult> UpdateEquipmentAsync(
|
||||
string equipmentId,
|
||||
|
||||
Reference in New Issue
Block a user