Files
Migu2.0/MiGu.Server/Wms/WmsTransportSelectors.cs
ArtoriasWu 15405ba114 新增 WMS 搬运规则与任务管理
支持搬运规则维护、候选预览、任务生成、预占、下发、取消和完成,并完善仓储管理前端交互。
2026-06-25 11:02:22 +08:00

154 lines
4.6 KiB
C#

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);