新增 WMS 搬运规则与任务管理
支持搬运规则维护、候选预览、任务生成、预占、下发、取消和完成,并完善仓储管理前端交互。
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MiGu.Server.Wms;
|
||||
|
||||
public sealed class TransportSelector
|
||||
{
|
||||
public int SchemaVersion { get; set; } = 1;
|
||||
public StorageSelectorFilter? Storage { get; set; }
|
||||
public ContainerSelectorFilter? Container { get; set; }
|
||||
public MaterialSelectorFilter? Material { get; set; }
|
||||
public List<RankingRule> Ranking { get; set; } = [];
|
||||
}
|
||||
|
||||
public sealed class StorageSelectorFilter
|
||||
{
|
||||
public List<string> AreaIds { get; set; } = [];
|
||||
public List<string> StorageTypes { get; set; } = [];
|
||||
public List<string> ZoneCodes { get; set; } = [];
|
||||
public List<string> StatusIn { get; set; } = [];
|
||||
public List<string> SiteIds { get; set; } = [];
|
||||
public bool? AllowInbound { get; set; }
|
||||
public bool? AllowOutbound { get; set; }
|
||||
public bool RequireSiteId { get; set; }
|
||||
public bool RequireEmpty { get; set; }
|
||||
public bool RequireOccupied { get; set; }
|
||||
public List<string> ExcludeStorageIds { get; set; } = [];
|
||||
}
|
||||
|
||||
public sealed class ContainerSelectorFilter
|
||||
{
|
||||
public List<string> ContainerTypes { get; set; } = [];
|
||||
public List<string> StatusIn { get; set; } = [];
|
||||
public bool ExcludeReserved { get; set; } = true;
|
||||
}
|
||||
|
||||
public sealed class MaterialSelectorFilter
|
||||
{
|
||||
public List<string> MaterialIds { get; set; } = [];
|
||||
public List<string> Categories { get; set; } = [];
|
||||
public List<string> StatusIn { get; set; } = [];
|
||||
public decimal? MinQuantity { get; set; }
|
||||
public string BatchNoMode { get; set; } = "Any";
|
||||
}
|
||||
|
||||
public sealed class RankingRule
|
||||
{
|
||||
public string Field { get; set; } = "";
|
||||
public string Direction { get; set; } = "asc";
|
||||
}
|
||||
|
||||
public sealed class TransportTaskOptions
|
||||
{
|
||||
public bool AutoReserve { get; set; } = true;
|
||||
public bool RequireManualConfirm { get; set; }
|
||||
public bool AllowSameStorage { get; set; }
|
||||
public int ReservationTtlSeconds { get; set; } = 600;
|
||||
public string DispatchMode { get; set; } = "Manual";
|
||||
public int MaxCandidateCount { get; set; } = 20;
|
||||
}
|
||||
|
||||
public static class TransportSelectorParser
|
||||
{
|
||||
private static readonly JsonSerializerOptions Json = new(JsonSerializerDefaults.Web)
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
||||
};
|
||||
|
||||
public static TransportSelector ParseSelector(string? json)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(json) || json.Trim() == "{}")
|
||||
return new TransportSelector();
|
||||
try
|
||||
{
|
||||
return JsonSerializer.Deserialize<TransportSelector>(json, Json) ?? new TransportSelector();
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
throw new InvalidOperationException($"Selector JSON 无效: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public static TransportTaskOptions ParseTaskOptions(string? json)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(json) || json.Trim() == "{}")
|
||||
return new TransportTaskOptions();
|
||||
try
|
||||
{
|
||||
return JsonSerializer.Deserialize<TransportTaskOptions>(json, Json) ?? new TransportTaskOptions();
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
throw new InvalidOperationException($"TaskOptions JSON 无效: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public static string NormalizeSelectorJson(string? json) =>
|
||||
JsonSerializer.Serialize(ParseSelector(json), Json);
|
||||
|
||||
public static string NormalizeTaskOptionsJson(string? json) =>
|
||||
JsonSerializer.Serialize(ParseTaskOptions(json), Json);
|
||||
}
|
||||
|
||||
public sealed record WmsTransportRequest(
|
||||
string TriggerType,
|
||||
Guid? RuleId,
|
||||
string? RequestSiteId,
|
||||
Guid? MaterialId,
|
||||
decimal? Quantity,
|
||||
Guid? ContainerId,
|
||||
Guid? SourceStorageId,
|
||||
Guid? TargetStorageId,
|
||||
string? BatchNo,
|
||||
int Priority,
|
||||
string Reason,
|
||||
Dictionary<string, string>? Tags);
|
||||
|
||||
public sealed record TransportCandidatePair(
|
||||
Guid RuleId,
|
||||
string RuleCode,
|
||||
Guid SourceStorageId,
|
||||
string SourceStorageCode,
|
||||
Guid TargetStorageId,
|
||||
string TargetStorageCode,
|
||||
Guid ContainerId,
|
||||
string ContainerCode,
|
||||
Guid? MaterialId,
|
||||
string? MaterialCode,
|
||||
decimal? Quantity,
|
||||
int Score,
|
||||
List<string> RejectReasons);
|
||||
|
||||
public sealed record TransportCandidatePreview(
|
||||
WmsTransportRequest Request,
|
||||
List<TransportCandidatePair> Candidates,
|
||||
List<RulePreviewResult> RuleResults);
|
||||
|
||||
public sealed record RulePreviewResult(
|
||||
Guid RuleId,
|
||||
string RuleCode,
|
||||
string RuleName,
|
||||
int CandidateCount,
|
||||
List<string> RejectReasons);
|
||||
|
||||
public sealed record DispatchTransportCommand(
|
||||
Guid TaskId,
|
||||
string SourceSiteId,
|
||||
string TargetSiteId,
|
||||
string ContainerCode,
|
||||
int Priority,
|
||||
string BusinessType,
|
||||
string Reason);
|
||||
Reference in New Issue
Block a user