using SimpleLite.RCS; using SimpleCore.PropType; using StandardScene.CarTypes; using System; using System.Globalization; using SimpleLite.RCS.CarTypes; namespace StandardScene.Scheduler.FassEvent { /// /// 将 StandardScene 车辆对象转换为 FASS 事件系统可识别的快照字段。 /// 负责编号、地标、状态、电量等与 EventCarService.TriggerHandler 对齐的映射。 /// internal static class FassEventCarSnapshotFactory { /// /// 获取车辆“下一地标”编码。 /// 优先级:status.enums["NextNode"] → tags["NextNode"] → pendingLocks 首站(TagValue 或站点 ID)。 /// public static string GetNextNodeCode(Car car) { if (car.status?.enums != null && car.status.enums.TryGetValue("NextNode", out var node) && !string.IsNullOrWhiteSpace(node)) { return node; } if (car.tags != null && car.tags.TryGetValue("NextNode", out var tagNode) && !string.IsNullOrWhiteSpace(tagNode)) { return tagNode; } // 调度 pendingLocks 通常表示车辆即将前往的站点,可近似为 FASS NextNodeCode。 if (car.status?.pendingLocks != null && car.status.pendingLocks.Length > 0) { var pendingSiteId = car.status.pendingLocks[0]; var site = SimpleCore.SimpleLib.GetSite(pendingSiteId); if (site?.fields != null && site.fields.TryGetValue("TagValue", out var tagValue) && !string.IsNullOrWhiteSpace(tagValue)) { return tagValue; } return pendingSiteId.ToString(CultureInfo.InvariantCulture); } return string.Empty; } /// /// 根据车辆与上一周期地标构建完整快照。 /// /// 场景车辆。 /// 上一周期 CurrentNode,由 EventCarMission 维护。 /// 下一地标;为空时自动调用 。 public static FassEventCarSnapshot Create(Car car, string prevNodeCode, string nextNodeCode) { return new FassEventCarSnapshot { CarId = car.id, Code = GetCarCode(car), CarModel = GetCarModel(car), PrevNodeCode = prevNodeCode, CurrentNodeCode = GetCurrentNodeCode(car), NextNodeCode = string.IsNullOrWhiteSpace(nextNodeCode) ? GetNextNodeCode(car) : nextNodeCode, State = GetFassState(car), Angle = (int)Math.Round(car.th), Charge = GetCharge(car) }; } /// /// 获取 FASS 车辆编号。MagCar 优先使用 VehicleCode,否则 fields["Code"],最后回退 name。 /// public static string GetCarCode(Car car) { if (car is MagCar magCar && magCar.VehicleCode > 0) { return magCar.VehicleCode.ToString(CultureInfo.InvariantCulture); } if (car.fields != null && car.fields.TryGetValue("Code", out var code) && !string.IsNullOrWhiteSpace(code)) { return code; } return car.name; } /// 获取车型。下料站 InplaceStaion 根据 CarModel 在 ME11 / 放行车型间切换。 public static string GetCarModel(Car car) { if (car.fields != null && car.fields.TryGetValue("CarModel", out var model) && !string.IsNullOrWhiteSpace(model)) { return model; } return car.GetType().Name; } /// /// 获取当前地标号。MagCar 上报后写入 status.enums["CurrentNode"]; /// 其他车型可回退到 siteID。 /// public static string GetCurrentNodeCode(Car car) { if (car.status?.enums != null && car.status.enums.TryGetValue("CurrentNode", out var node) && !string.IsNullOrWhiteSpace(node)) { return node; } return car.siteID > 0 ? car.siteID.ToString(CultureInfo.InvariantCulture) : string.Empty; } /// /// 将 StandardScene 车辆状态映射为 FASS 英文字符串。 /// /// 可手动覆盖:tags["FassState"] 或 enums["FassState"]。 /// WaitPass 需在停止中且 tags 含 WaitPass(FASS 中“等待放行”态)。 /// /// public static string GetFassState(Car car) { if (car.tags != null && car.tags.TryGetValue("FassState", out var tagState) && !string.IsNullOrWhiteSpace(tagState)) { return tagState; } if (car.status?.enums != null && car.status.enums.TryGetValue("FassState", out var enumState) && !string.IsNullOrWhiteSpace(enumState)) { return enumState; } if (car.status?.enums != null && car.status.enums.TryGetValue("State", out var state)) { switch (state) { case "运行中": return "Running"; case "停止中": return car.tags != null && car.tags.ContainsKey("WaitPass") ? "WaitPass" : "Stopping"; case "未准备": return "NotReady"; case "充电中": return "Charging"; default: return state; } } return string.Empty; } /// 从 status.enums["Soc"] 解析电量百分比。 private static double GetCharge(Car car) { if (car.status?.enums != null && car.status.enums.TryGetValue("Soc", out var soc) && double.TryParse(soc, NumberStyles.Float, CultureInfo.InvariantCulture, out var value)) { return value; } return 0; } } }