RobotTask.cs 9.08 KB
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Rcs.Domain.Attributes;
using Rcs.Domain.Entities.DomainEvents.RobotTask;

namespace Rcs.Domain.Entities
{
    /// <summary>
    /// 任务实体类
    /// @author zzy
    /// </summary>
    [Table("robot_tasks")]
    public class RobotTask : Entity
    {
        /// <summary>
        /// 系统ID
        /// </summary>
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        [Column("task_id")]
        public Guid TaskId { get; set; }

        /// <summary>
        /// 任务编码
        /// </summary>
        [Required]
        [Column("task_code")]
        [MaxLength(50)]
        public string TaskCode { get; set; }

        /// <summary>
        /// 任务名称
        /// </summary>
        [Required]
        [Column("task_name")]
        [MaxLength(100)]
        public string? TaskName { get; set; }

        /// <summary>
        /// 机器人ID(外键)
        /// </summary>
        [Column("robot_id")]
        public Guid? RobotId { get; set; }

        /// <summary>
        /// 任务模板ID(可空)
        /// @author zzy
        /// </summary>
        [Column("task_Template_id")]
        public Guid? TaskTemplateId { get; set; }

        /// <summary>
        /// 起点库位ID
        /// @author zzy
        /// </summary>
        [Column("begin_location_id")]
        public Guid? BeginLocationId { get; set; }

        /// <summary>
        /// 终点库位ID
        /// @author zzy
        /// </summary>
        [Column("end_location_id")]
        public Guid? EndLocationId { get; set; }

        /// <summary>
        /// 任务状态
        /// </summary>
        [Column("status")]
        public TaskStatus Status { get; set; }
        /// <summary>
        /// 任暂停
        /// </summary>
        [Column("pause")]
        public bool Pause { get; set; }

        /// <summary>
        /// 优先级
        /// </summary>
        [Column("priority")]
        public int Priority { get; set; } = 99;
        /// <summary>
        /// 单据来源
        /// </summary>
        [Column("source")]
        public string? Source { get; set; }
        /// <summary>
        /// 关联单据
        /// </summary>
        [Column("relation")]
        public string? Relation { get; set; }
        
        /// <summary>
        /// 货架编码
        /// @author zzy
        /// </summary>
        [Column("shelf_code")]
        [MaxLength(50)]
        public string? ShelfCode { get; set; }

        /// <summary>
        /// 故障信息
        /// </summary>
        [Column("error_info", TypeName = "text")]
        public string? ErrorInfo { get; set; }

        /// <summary>
        /// 创建时间
        /// </summary>
        [Column("created_at", TypeName = "timestamp")]
        public DateTime CreatedAt { get; set; }

        /// <summary>
        /// 更新时间
        /// </summary>
        [Column("updated_at", TypeName = "timestamp")]
        public DateTime? UpdatedAt { get; set; }

        #region 外键 => 导航属性,ManyToOne/OneToOne

        /// <summary>
        /// 机器人导航属性
        /// </summary>
        [ForeignKey(nameof(RobotId))]
        public virtual Robot? Robot { get; set; }

        /// <summary>
        /// 起点库位导航属性
        /// @author zzy
        /// </summary>
        [ForeignKey(nameof(BeginLocationId))]
        public virtual StorageLocation? BeginLocation { get; set; }

        /// <summary>
        /// 终点库位导航属性
        /// @author zzy
        /// </summary>
        [ForeignKey(nameof(EndLocationId))]
        public virtual StorageLocation? EndLocation { get; set; }

        /// <summary>
        /// 任务模板导航属性
        /// @author zzy
        /// </summary>
        [ForeignKey(nameof(TaskTemplateId))]
        public virtual TaskTemplate? TaskTemplate { get; set; }

        #endregion

        #region 领域方法

        /// <summary>
        /// 创建任务
        /// @author zzy
        /// </summary>
        /// <param name="taskCode">任务编码</param>
        /// <param name="taskName">任务名称</param>
        /// <param name="beginLocationId">起点库位ID</param>
        /// <param name="endLocationId">终点库位ID</param>
        /// <param name="priority">优先级(默认99)</param>
        /// <param name="taskTemplateId">任务模板ID</param>
        /// <param name="shelfCode">货架编码</param>
        /// <param name="robotId">机器人ID</param>
        /// <param name="status">任务状态</param>
        public void Create(string taskCode, string? taskName, Guid? beginLocationId, Guid? endLocationId,
            int priority = 99, Guid? taskTemplateId = null, string? shelfCode = null,
            Guid? robotId = null, TaskStatus status = TaskStatus.Pending)
        {
            TaskId = Guid.NewGuid();
            TaskCode = taskCode;
            TaskName = taskName;
            RobotId = robotId;
            BeginLocationId = beginLocationId;
            EndLocationId = endLocationId;
            Priority = priority;
            TaskTemplateId = taskTemplateId;
            ShelfCode = shelfCode;
            Status = status;
            CreatedAt = DateTime.Now;
            AddDomainEvent(new TaskCreatedDomainEvent(TaskId));
        }

        /// <summary>
        /// 挂起任务
        /// @author zzy
        /// </summary>
        public void Suspend()
        {
            Status = TaskStatus.WaitingForResource;
            UpdatedAt = DateTime.Now;
            AddDomainEvent(new TaskSuspendedDomainEvent(TaskId));
        }
        /// <summary>
        /// 挂起任务
        /// @author zzy
        /// </summary>
        public void Completed(Guid? robotId = null)
        {
            if (robotId.HasValue) robotId = RobotId;
            Status = TaskStatus.Completed;
            UpdatedAt = DateTime.Now;
            AddDomainEvent(new TaskCompletedDomainEvent(TaskId));
        }

        /// <summary>
        /// 暂停任务
        /// @author zzy
        /// </summary>
        public void Paused()
        {
            Pause =  true;
            UpdatedAt = DateTime.Now;
            AddDomainEvent(new TaskPausedDomainEvent(TaskId));
        }

        /// <summary>
        /// 继续任务
        /// @author zzy
        /// </summary>
        public void Resume()
        {
            Pause = false;
            UpdatedAt = DateTime.Now;
            AddDomainEvent(new TaskResumedDomainEvent(TaskId));
        }
        /// <summary>
        /// 任务已分配
        /// @author zzy
        /// </summary>
        public void Assign(Guid robotId)
        {
            RobotId = robotId;
            Status = TaskStatus.Assigned;
            UpdatedAt = DateTime.Now;
            AddDomainEvent(new TaskAssignedDomainEvent(TaskId));
        }

        /// <summary>
        /// 取消任务
        /// @author zzy
        /// </summary>
        public void Cancel()
        {
            Status = TaskStatus.Cancelled;
            UpdatedAt = DateTime.Now;
            AddDomainEvent(new TaskCancelledDomainEvent(TaskId));
        }

        /// <summary>
        /// 任务失败
        /// @author zzy
        /// </summary>
        /// <param name="errorInfo">错误信息</param>
        public void Fail(string? errorInfo = null)
        {
            Status = TaskStatus.Failed;
            ErrorInfo = errorInfo;
            UpdatedAt = DateTime.Now;
            AddDomainEvent(new TaskFailedDomainEvent(TaskId, errorInfo));
        }

        /// <summary>
        /// 判断任务是否为执行中状态
        /// 等待中、已分配、已完成、已取消为非执行中状态,其他为执行中状态
        /// @author zzy
        /// </summary>
        /// <returns>是否为执行中状态</returns>
        public bool IsInProgress()
        {
            return Status != TaskStatus.Pending
                && Status != TaskStatus.Assigned
                && Status != TaskStatus.Completed
                && Status != TaskStatus.Cancelled;
        }
        /// <summary>
        /// 开始执行任务
        /// @author zzy
        /// </summary>
        public void StartExecution()
        {
            Status = TaskStatus.InProgress;
            UpdatedAt = DateTime.Now;
        }

        #endregion
    }

    /// <summary>
    /// 任务状态枚举 - RCS调度任务状态
    /// @author zzy
    /// </summary>
    public enum TaskStatus
    {
        [EnumDescription("等待中", "Pending")]
        Pending = 1,

        [EnumDescription("已分配", "Assigned")]
        Assigned = 2,

        [EnumDescription("执行中", "Pick In Progress")]
        InProgress = 3,

        [EnumDescription("等待资源", "Waiting for Resource")]
        WaitingForResource,

        [EnumDescription("已完成", "Completed")]
        Completed,

        [EnumDescription("已取消", "Cancelled")]
        Cancelled,

        [EnumDescription("执行失败", "Failed")]
        Failed,

        [EnumDescription("超时", "Timeout")]
        Timeout,

        [EnumDescription("重新分配", "Reassigned")]
        Reassigned
    }
}