VdaSegmentedPathCache.cs 7.12 KB
using Rcs.Domain.Enums;

namespace Rcs.Application.Services.PathFind.Models;

/// <summary>
/// VDA5050分段路径缓存
/// @author zzy
/// 2026-02-05 更新:支持两层切割结构
/// 2026-02-06 更新:支持网络动作执行状态跟踪
/// 2026-03-03 更新:添加姿态信息
/// </summary>
public class VdaSegmentedPathCache
{
    public Guid TaskId { get; set; }
    public string TaskCode { get; set; } = string.Empty;
    public Guid RobotId { get; set; }
    public Guid MapId { get; set; }
    public string MapCode { get; set; } = string.Empty;
    public DateTime CreatedAt { get; set; }
    /// <summary>
    /// 当前路口段索引(第一层)
    /// </summary>
    public int CurrentJunctionIndex { get; set; }
    /// <summary>
    /// 当前资源段索引(第二层)
    /// </summary>
    public int CurrentResourceIndex { get; set; }
    /// <summary>
    /// 路口切割后的段落列表
    /// </summary>
    public List<VdaJunctionSegmentCache> JunctionSegments { get; set; } = new();

    /// <summary>
    /// 上一次发送的最大 SequenceId,用于后续段延续编号
    /// @author zzy
    /// 2026-02-25 新增:解决分段发送时 sequenceId 从0重新开始的问题
    /// </summary>
    public int LastSentSequenceId { get; set; }

    /// <summary>
    /// 当前活跃的网络动作上下文ID(用于跟踪正在执行的网络动作)
    /// @author zzy
    /// </summary>
    public string? ActiveNetActionContextId { get; set; }

    /// <summary>
    /// 网络动作执行状态
    /// @author zzy
    /// </summary>
    public NetActionExecutionStatus? NetActionStatus { get; set; }

    /// <summary>
    /// 是否正在等待网络动作完成
    /// @author zzy
    /// </summary>
    public bool IsWaitingForNetAction =>
        NetActionStatus == NetActionExecutionStatus.Executing ||
        NetActionStatus == NetActionExecutionStatus.WaitingAsyncResponse;

    /// <summary>
    /// 姿态信息
    /// @author zzy
    /// 2026-03-03 新增:存储终点姿态信息
    /// </summary>
    public VdaPoseInfo? PoseInfo { get; set; }

    /// <summary>
    /// 路径版本号(用于并发更新对齐)
    /// 作者:codex
    /// </summary>
    public long PlanVersion { get; set; } = 1;

    /// <summary>
    /// 路由模式(示例值:Normal/HoldingAtWaitNode/QueueingForJunction/Detouring/Rejoining...)
    /// 作者:codex
    /// </summary>
    public string RouteMode { get; set; } = "Normal";

    /// <summary>
    /// 原始目标节点编码(用于避让后回归)
    /// 作者:codex
    /// </summary>
    public string? OriginalGoalNodeCode { get; set; }

    /// <summary>
    /// 当前活动补丁ID
    /// 作者:codex
    /// </summary>
    public Guid? ActivePatchId { get; set; }

    /// <summary>
    /// 等待截止时间(UTC)
    /// 作者:codex
    /// </summary>
    public DateTime? HoldUntilUtc { get; set; }

    /// <summary>
    /// 等待节点编码
    /// 作者:codex
    /// </summary>
    public string? HoldNodeCode { get; set; }

    /// <summary>
    /// 连续通过次数(用于防抖)
    /// 作者:codex
    /// </summary>
    public int StablePassCount { get; set; } = 0;

    /// <summary>
    /// 上一次决策编码
    /// 作者:codex
    /// </summary>
    public string? LastDecisionCode { get; set; }

    /// <summary>
    /// 连续冲突失败计数(用于进入阻塞保护态 Blocked)
    /// </summary>
    public int ConsecutiveConflictFailCount { get; set; } = 0;

    /// <summary>
    /// 阻塞模式原因(Blocked)
    /// </summary>
    public string? BlockedReason { get; set; }
}

/// <summary>
/// 路口切割段缓存(第一层)
/// @author zzy
/// </summary>
public class VdaJunctionSegmentCache
{
    /// <summary>
    /// 资源/模板切割后的子段列表
    /// </summary>
    public List<VdaSegmentCacheItem> ResourceSegments { get; set; } = new();
}

/// <summary>
/// VDA5050分段缓存项(第二层)
/// @author zzy
/// 2026-02-06 更新:添加网络动作相关字段
/// </summary>
public class VdaSegmentCacheItem
{
    public bool IsSent { get; set; } = false;
    public List<PathSegmentWithCode> Segments { get; set; } = new();

    /// <summary>
    /// 段来源编码(Base/Avoidance/Merged)
    /// 作者:codex
    /// </summary>
    public string SegmentOrigin { get; set; } = "Base";

    /// <summary>
    /// 终点网络动作上下文ID列表(用于关联网络动作执行状态)
    /// @author zzy
    /// </summary>
    public List<string> EndNodeNetActionContextIds { get; set; } = new();

    /// <summary>
    /// 起点网络动作上下文ID列表(用于关联网络动作执行状态)
    /// @author zzy
    /// </summary>
    public List<string> StartNodeNetActionContextIds { get; set; } = new();

    /// <summary>
    /// 是否已执行终点网络动作
    /// @author zzy
    /// </summary>
    public bool IsEndNodeNetActionExecuted { get; set; } = false;

    /// <summary>
    /// 是否已执行起点网络动作
    /// @author zzy
    /// </summary>
    public bool IsStartNodeNetActionExecuted { get; set; } = false;

    /// <summary>
    /// 获取该段的终点网络动作ID列表(仅返回动作申请类型的网络动作)
    /// @author zzy
    /// 2026-02-06 更新:从字典Keys获取,过滤只返回ActionType为Apply的网络动作
    /// </summary>
    public List<Guid> GetEndNodeNetActionIds()
    {
        if (Segments.Count == 0)
        {
            return new List<Guid>();
        }

        var lastSegment = Segments.Last();
        if (lastSegment.EndNodeNetActionTypes == null || lastSegment.EndNodeNetActionTypes.Count == 0)
        {
            return new List<Guid>();
        }

        // 从字典Keys中获取ActionType为Apply的网络动作ID
        return lastSegment.EndNodeNetActionTypes
            .Where(kv => kv.Value == ActionType.Apply)
            .Select(kv => kv.Key)
            .ToList();
    }

    /// <summary>
    /// 获取该段的起点网络动作ID列表(仅返回动作申请类型的网络动作)
    /// @author zzy
    /// 2026-02-06 更新:从字典Keys获取,过滤只返回ActionType为Apply的网络动作
    /// </summary>
    public List<Guid> GetStartNodeNetActionIds()
    {
        if (Segments.Count == 0)
        {
            return new List<Guid>();
        }

        var firstSegment = Segments.First();
        if (firstSegment.StartNodeNetActionTypes == null || firstSegment.StartNodeNetActionTypes.Count == 0)
        {
            return new List<Guid>();
        }

        // 从字典Keys中获取ActionType为Apply的网络动作ID
        return firstSegment.StartNodeNetActionTypes
            .Where(kv => kv.Value == ActionType.Apply)
            .Select(kv => kv.Key)
            .ToList();
    }
}

/// <summary>
/// VDA5050姿态信息
/// @author zzy
/// 2026-03-03 创建:存储路径终点的姿态信息
/// </summary>
public class VdaPoseInfo
{
    /// <summary>
    /// 终点货叉与车头的夹角(弧度)
    /// 0表示货叉在车头方向,π表示货叉在车尾方向
    /// @author zzy
    /// </summary>
    public double EndForkAngleOffset { get; set; }
}