移除历史状态归一化及相关遗留逻辑

- 移除 LegacyStatusNormalizationMigrator,仅保留 AreaLayoutModeDefaultMigrator
- 删除 WmsDispatchStatus 枚举、常量和全局 using
- 统一所有 DbContext 注入为 MiGuDbContext,移除 PlatformDbContext
- 服务实体操作统一用 IEditableRepository<T>,移除本地实现
- 移除 WmsService 的 MigrateLegacyAsync 方法
- 精简接口模型,移除部分字段和请求体
- 前端保存容器时 status 字段取自已有数据,移除写死默认值
- 更新文档,去除旧说明,统一数据库初始化流程
This commit is contained in:
2026-08-03 09:41:03 +08:00
parent 1f72488a8d
commit 125372b157
26 changed files with 63 additions and 183 deletions
+1 -6
View File
@@ -20,7 +20,7 @@ public sealed record ContainerMaterialSnapshot(
public abstract record CommonRequest(Guid? Id, long? Version, bool IsLock, string Remark, string Extend);
public sealed record MasterDataRequest(
Guid? Id, long? Version, string Code, string Name, string Type, string Status, bool Enabled, int SortOrder,
Guid? Id, long? Version, string Code, string Name, string Type, bool Enabled, int SortOrder,
bool IsLock, string Remark, string Extend) : CommonRequest(Id, Version, IsLock, Remark, Extend);
public sealed record AreaRequest(
@@ -57,8 +57,3 @@ public sealed record ContainerLocationRequest(
public sealed record BindMaterialRequest(
Guid? Id, long? Version, Guid ContainerId, Guid MaterialId, string Source, string Reason,
bool IsLock, string Remark, string Extend) : CommonRequest(Id, Version, IsLock, Remark, Extend);
public sealed record ContainerMaterialRequest(
Guid? Id, long? Version, Guid ContainerId, Guid MaterialId, decimal Quantity, string BatchNo, string SerialNo,
string Status, DateTimeOffset? LoadedAt, DateTimeOffset? UnloadedAt, string Source, string Reason,
bool IsLock, string Remark, string Extend) : CommonRequest(Id, Version, IsLock, Remark, Extend);
+2 -2
View File
@@ -5,9 +5,9 @@ namespace MiGu.Server.Wms;
public sealed class WmsReferenceValidator
{
private readonly PlatformDbContext _db;
private readonly MiGuDbContext _db;
public WmsReferenceValidator(PlatformDbContext db)
public WmsReferenceValidator(MiGuDbContext db)
{
_db = db;
}
+24 -87
View File
@@ -10,14 +10,14 @@ namespace MiGu.Server.Wms;
public sealed class WmsService
{
private readonly PlatformDbContext _db;
private readonly MiGuDbContext _db;
private readonly IUnitOfWork _uow;
private readonly IServiceProvider _services;
private readonly WmsReferenceValidator _refs;
private readonly JsonSerializerOptions _json = new(JsonSerializerDefaults.Web);
public WmsService(
PlatformDbContext db,
MiGuDbContext db,
IUnitOfWork uow,
IServiceProvider services,
WmsReferenceValidator refs)
@@ -158,7 +158,7 @@ public sealed class WmsService
StampCreate(entity, actor);
_db.Warehouses.Add(entity);
}
await EnsureUnique(_db.Warehouses, x => x.Code == req.Code && x.Id != entity.Id, "仓库编码已存在");
await Repo<Warehouse>().EnsureUniqueAsync(x => x.Code == req.Code && x.Id != entity.Id, "仓库编码已存在");
entity.Code = req.Code.Trim();
entity.Name = req.Name.Trim();
entity.Type = req.Type.TrimOr("Default");
@@ -185,7 +185,7 @@ public sealed class WmsService
StampCreate(entity, actor);
_db.WarehouseAreas.Add(entity);
}
await EnsureUnique(_db.WarehouseAreas, x => x.Code == req.Code && x.Id != entity.Id, "库区编码已存在");
await Repo<WarehouseArea>().EnsureUniqueAsync(x => x.Code == req.Code && x.Id != entity.Id, "库区编码已存在");
entity.WarehouseId = warehouseId;
entity.Code = req.Code.Trim();
entity.Name = req.Name.Trim();
@@ -214,7 +214,7 @@ public sealed class WmsService
StampCreate(entity, actor);
_db.Storages.Add(entity);
}
await EnsureUnique(_db.Storages, x => x.Code == req.Code && x.Id != entity.Id, "库位编码已存在");
await Repo<Storage>().EnsureUniqueAsync(x => x.Code == req.Code && x.Id != entity.Id, "库位编码已存在");
entity.AreaId = req.AreaId;
entity.Code = req.Code.Trim();
entity.Name = req.Name.Trim();
@@ -227,7 +227,7 @@ public sealed class WmsService
entity.SiteCode = req.SiteCode.TrimOr(entity.SiteId);
entity.Barcode = req.Barcode.TrimOr("");
entity.Capacity = 1;
var status = StorageStatuses.Normalize(req.Status);
var status = StorageStatuses.ParseOr(req.Status);
if (status == StorageStatuses.Disabled || req.Enabled == false)
entity.Status = req.Enabled ? status : StorageStatuses.Disabled;
else if (!string.IsNullOrWhiteSpace(req.Status) && StorageStatuses.All.Contains(status))
@@ -326,7 +326,7 @@ public sealed class WmsService
StampCreate(entity, actor);
_db.Containers.Add(entity);
}
await EnsureUnique(_db.Containers, x => x.Code == req.Code && x.Id != entity.Id, "容器编码已存在");
await Repo<Container>().EnsureUniqueAsync(x => x.Code == req.Code && x.Id != entity.Id, "容器编码已存在");
entity.AreaId = req.AreaId;
entity.Code = req.Code.Trim();
entity.Name = req.Name.Trim();
@@ -353,7 +353,7 @@ public sealed class WmsService
StampCreate(entity, actor);
_db.MaterialTypes.Add(entity);
}
await EnsureUnique(_db.MaterialTypes, x => x.Code == req.Code && x.Id != entity.Id, "物料类型编码已存在");
await Repo<MaterialType>().EnsureUniqueAsync(x => x.Code == req.Code && x.Id != entity.Id, "物料类型编码已存在");
entity.Code = req.Code.Trim();
entity.Name = req.Name.Trim();
entity.Spec = req.Spec.TrimOr("");
@@ -378,9 +378,9 @@ public sealed class WmsService
StampCreate(entity, actor);
_db.Materials.Add(entity);
}
await EnsureUnique(_db.Materials, x => x.Code == req.Code && x.Id != entity.Id, "物料编码已存在");
await Repo<Material>().EnsureUniqueAsync(x => x.Code == req.Code && x.Id != entity.Id, "物料编码已存在");
if (!string.IsNullOrWhiteSpace(req.Barcode))
await EnsureUnique(_db.Materials, x => x.Barcode == req.Barcode && x.Id != entity.Id, "物料条码已存在");
await Repo<Material>().EnsureUniqueAsync(x => x.Barcode == req.Barcode && x.Id != entity.Id, "物料条码已存在");
entity.Code = req.Code.Trim();
entity.Name = req.Name.Trim();
entity.TypeCode = req.TypeCode.TrimOr("");
@@ -425,9 +425,9 @@ public sealed class WmsService
await _uow.SaveChangesAsync();
}
public async Task DeleteEntity<T>(Guid id, long? version, string actor) where T : EntityBase
public async Task DeleteEntity<T>(Guid id, long? version, string actor)
where T : class, IEntity<Guid>, ISoftDeletable, IVersioned, ILockable, IAuditable
{
var entity = await FindEditable<T>(id, version);
if (typeof(T) == typeof(WarehouseArea))
{
if (await _db.Storages.AnyAsync(x => x.AreaId == id))
@@ -444,10 +444,8 @@ public sealed class WmsService
if (await _db.ContainerMaterials.AnyAsync(x => x.MaterialId == id))
throw new InvalidOperationException("物料仍在绑定中,不能删除");
}
entity.IsDeleted = true;
entity.DeletedAt = DateTimeOffset.UtcNow;
entity.DeletedBy = actor;
entity.UpdatedBy = actor;
await Repo<T>().SoftDeleteAsync(id, version);
await _uow.SaveChangesAsync();
}
@@ -497,8 +495,7 @@ public sealed class WmsService
}
else
{
EnsureVersion(current, req.Version);
EnsureUnlocked(current);
await Repo<ContainerLocation>().GetEditableAsync(current.Id, req.Version);
}
current.LocationType = locationType;
@@ -540,7 +537,7 @@ public sealed class WmsService
{
var current = await _db.ContainerLocations.FirstOrDefaultAsync(x => x.ContainerId == containerId)
?? throw new InvalidOperationException("容器当前位置不存在");
EnsureUnlocked(current);
await Repo<ContainerLocation>().GetEditableAsync(current.Id, null);
Guid? fromStorageId = null;
if (current.LocationType == ContainerLocationTypes.Storage && Guid.TryParse(current.LocationId, out var fs))
fromStorageId = fs;
@@ -614,15 +611,9 @@ public sealed class WmsService
return current;
}
/// <summary>兼容旧接口:忽略数量,按实体绑定。</summary>
public Task<ContainerMaterial> SaveContainerMaterial(ContainerMaterialRequest req, string actor) =>
BindMaterial(new BindMaterialRequest(req.Id, req.Version, req.ContainerId, req.MaterialId, req.Source, req.Reason, req.IsLock, req.Remark, req.Extend), actor);
public async Task UnbindMaterial(Guid bindingId, string actor, string reason = "", bool archive = false)
{
var current = await _db.ContainerMaterials.FirstOrDefaultAsync(x => x.Id == bindingId)
?? throw new InvalidOperationException("绑定不存在");
EnsureUnlocked(current);
var current = await Repo<ContainerMaterial>().GetEditableAsync(bindingId, null);
var material = await _db.Materials.FirstOrDefaultAsync(x => x.Id == current.MaterialId);
var before = Snapshot(current);
var now = DateTimeOffset.UtcNow;
@@ -718,46 +709,6 @@ public sealed class WmsService
return wh;
}
public async Task MigrateLegacyAsync(string actor = "system")
{
var wh = await EnsureDefaultWarehouseAsync(actor);
var areas = await _db.WarehouseAreas.Where(x => x.WarehouseId == Guid.Empty).ToListAsync();
foreach (var a in areas)
a.WarehouseId = wh.Id;
var storages = await _db.Storages.ToListAsync();
foreach (var s in storages)
{
if (s.LevelNo <= 0) s.LevelNo = 1;
if (s.DepthNo <= 0) s.DepthNo = 1;
if (string.IsNullOrWhiteSpace(s.SiteCode)) s.SiteCode = s.SiteId;
if (!StorageStatuses.All.Contains(s.Status))
s.Status = StorageStatuses.Empty;
if (!s.Enabled) s.Status = StorageStatuses.Disabled;
}
var containers = await _db.Containers.ToListAsync();
foreach (var c in containers)
{
if (!ContainerStatuses.All.Contains(c.Status))
c.Status = ContainerStatuses.EmptyMaterial;
}
var binds = await _db.ContainerMaterials.ToListAsync();
foreach (var b in binds)
{
b.Quantity = 1;
if (b.BoundAt == default) b.BoundAt = b.LoadedAt == default ? DateTimeOffset.UtcNow : b.LoadedAt;
if (!ContainerMaterialStatuses.ActiveBind.Contains(b.Status))
b.Status = ContainerMaterialStatuses.Bound;
}
await _uow.SaveChangesAsync();
foreach (var s in storages.Where(x => x.Status != StorageStatuses.Disabled))
await SyncOccupancyStatus(storageId: s.Id);
}
public async Task<List<ContainerLocationHistory>> LocationHistory(Guid? containerId = null)
{
var rows = await (containerId.HasValue
@@ -857,16 +808,13 @@ public sealed class WmsService
});
}
private IEditableRepository<T> Repo<T>()
where T : class, IEntity<Guid>, ISoftDeletable, IVersioned, ILockable
=> _services.GetRequiredService<IEditableRepository<T>>();
private Task<T> FindEditable<T>(Guid id, long? version)
where T : class, IEntity<Guid>, ISoftDeletable, IVersioned, ILockable
=> _services.GetRequiredService<IEditableRepository<T>>().GetEditableAsync(id, version);
private static void EnsureVersion(EntityBase entity, long? version)
{
if (version.HasValue && entity.Version != version.Value)
throw new MiGu.DB.Abstractions.Exceptions.ConcurrencyConflictException(
entity.GetType().Name, entity.Id, version);
}
=> Repo<T>().GetEditableAsync(id, version);
private static bool IsUniqueConstraintViolation(DbUpdateException ex)
{
@@ -882,19 +830,13 @@ public sealed class WmsService
return false;
}
private static void EnsureUnlocked(EntityBase entity)
{
if (entity.IsLock)
throw new MiGu.DB.Abstractions.Exceptions.EntityLockedException(entity.GetType().Name, entity.Id);
}
private static void StampCreate(EntityBase entity, string actor)
private static void StampCreate(AggregateRoot entity, string actor)
{
entity.CreatedBy = actor;
entity.UpdatedBy = actor;
}
private void ApplyCommon(EntityBase entity, CommonRequest req, string actor)
private void ApplyCommon(AggregateRoot entity, CommonRequest req, string actor)
{
entity.IsLock = req.IsLock;
entity.Remark = req.Remark.TrimOr("");
@@ -902,11 +844,6 @@ public sealed class WmsService
entity.UpdatedBy = actor;
}
private static async Task EnsureUnique<T>(IQueryable<T> query, System.Linq.Expressions.Expression<Func<T, bool>> predicate, string message)
{
if (await query.AnyAsync(predicate)) throw new InvalidOperationException(message);
}
private string NormalizeExtend(string? extend)
{
if (string.IsNullOrWhiteSpace(extend)) return "{}";
-1
View File
@@ -16,4 +16,3 @@ global using WmsDefaults = MiGu.DB.Domains.Wms.WmsDefaults;
global using WmsTransportTaskStatuses = MiGu.DB.Domains.Transport.WmsTransportTaskStatuses;
global using WmsTransportTriggerTypes = MiGu.DB.Domains.Transport.WmsTransportTriggerTypes;
global using WmsReservationStatuses = MiGu.DB.Domains.Transport.WmsReservationStatuses;
global using WmsDispatchStatuses = MiGu.DB.Domains.Transport.WmsDispatchStatuses;
+2 -2
View File
@@ -6,10 +6,10 @@ namespace MiGu.Server.Wms;
public sealed class WmsTransportPlanner
{
private readonly PlatformDbContext _db;
private readonly MiGuDbContext _db;
private readonly JsonSerializerOptions _json = new(JsonSerializerDefaults.Web);
public WmsTransportPlanner(PlatformDbContext db) => _db = db;
public WmsTransportPlanner(MiGuDbContext db) => _db = db;
public async Task<TransportCandidatePreview> PreviewAsync(WmsTransportRequest request)
{
+4 -4
View File
@@ -7,12 +7,12 @@ namespace MiGu.Server.Wms;
public sealed class WmsTransportRuleService
{
private readonly PlatformDbContext _db;
private readonly MiGuDbContext _db;
private readonly IEditableRepository<WmsTransportRule> _rules;
private readonly IUnitOfWork _uow;
public WmsTransportRuleService(
PlatformDbContext db,
MiGuDbContext db,
IEditableRepository<WmsTransportRule> rules,
IUnitOfWork uow)
{
@@ -71,13 +71,13 @@ public sealed class WmsTransportRuleService
await _uow.SaveChangesAsync();
}
private static void StampCreate(EntityBase entity, string actor)
private static void StampCreate(AggregateRoot entity, string actor)
{
entity.CreatedBy = actor;
entity.UpdatedBy = actor;
}
private static void ApplyCommon(EntityBase entity, CommonRequest req, string actor)
private static void ApplyCommon(AggregateRoot entity, CommonRequest req, string actor)
{
entity.IsLock = req.IsLock;
entity.Remark = req.Remark.TrimOr("");
+3 -3
View File
@@ -6,14 +6,14 @@ namespace MiGu.Server.Wms;
public sealed class WmsTransportTaskService
{
private readonly PlatformDbContext _db;
private readonly MiGuDbContext _db;
private readonly WmsTransportPlanner _planner;
private readonly WmsService _wms;
private readonly IWmsDispatchAdapter _dispatch;
private readonly JsonSerializerOptions _json = new(JsonSerializerDefaults.Web);
public WmsTransportTaskService(
PlatformDbContext db,
MiGuDbContext db,
WmsTransportPlanner planner,
WmsService wms,
IWmsDispatchAdapter dispatch)
@@ -331,7 +331,7 @@ public sealed class WmsTransportTaskService
GeneratedAt = DateTimeOffset.UtcNow
};
private static void StampCreate(EntityBase entity, string actor)
private static void StampCreate(AggregateRoot entity, string actor)
{
entity.CreatedBy = actor;
entity.UpdatedBy = actor;