wanshenmean
10 小时以前 ba9c1994b95624b88ef606ec00394990d8f2009f
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs
@@ -1,24 +1,4 @@
#region << 版 本 注 释 >>
/*----------------------------------------------------------------
 * 命名空间:WIDESEAWCS_TaskInfoService
 * 创建者:胡童庆
 * 创建时间:2024/8/2 16:13:36
 * 版本:V1.0.0
 * 描述:
 *
 * ----------------------------------------------------------------
 * 修改人:
 * 修改时间:
 * 版本:V1.0.1
 * 修改说明:
 *
 *----------------------------------------------------------------*/
#endregion << 版 本 注 释 >>
using MapsterMapper;
using Microsoft.IdentityModel.Tokens;
using SqlSugar;
using System.Diagnostics.CodeAnalysis;
using WIDESEA_Core;
@@ -26,7 +6,6 @@
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_Core.Enums;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_DTO;
using WIDESEAWCS_DTO.Stock;
using WIDESEAWCS_DTO.TaskInfo;
@@ -39,733 +18,57 @@
using WIDESEAWCS_QuartzJob.Models;
using WIDESEAWCS_QuartzJob.Service;
namespace WIDESEAWCS_TaskInfoService
namespace WIDESEAWCS_TaskInfoService;
/// <summary>
/// 任务服务 - 核心业务逻辑
/// </summary>
public partial class TaskService : ServiceBase<Dt_Task, ITaskRepository>, ITaskService
{
    public class TaskService : ServiceBase<Dt_Task, ITaskRepository>, ITaskService
    private readonly IRouterService _routerService;
    private readonly ITaskExecuteDetailService _taskExecuteDetailService;
    private readonly ITaskExecuteDetailRepository _taskExecuteDetailRepository;
    private readonly IMapper _mapper;
    private readonly IOutboundTaskFlowService _outboundTaskFlowService;
    private readonly IInboundTaskFlowService _inboundTaskFlowService;
    private readonly IRelocationTaskFlowService _relocationTaskFlowService;
    private readonly IRobotTaskFlowService _robotTaskFlowService;
    private Dictionary<string, OrderByType> _taskOrderBy = new()
    {
        private readonly IRouterService _routerService;
        private readonly ITaskExecuteDetailService _taskExecuteDetailService;
        private readonly ITaskExecuteDetailRepository _taskExecuteDetailRepository;
        private readonly IMapper _mapper;
        private readonly IOutboundTaskFlowService _outboundTaskFlowService;
        private readonly IInboundTaskFlowService _inboundTaskFlowService;
        private readonly IRelocationTaskFlowService _relocationTaskFlowService;
        private readonly IRobotTaskFlowService _robotTaskFlowService;
        {nameof(Dt_Task.Grade),OrderByType.Desc },
        {nameof(Dt_Task.CreateDate),OrderByType.Asc},
    };
        private Dictionary<string, OrderByType> _taskOrderBy = new()
            {
                {nameof(Dt_Task.Grade),OrderByType.Desc },
                {nameof(Dt_Task.CreateDate),OrderByType.Asc},
            };
    public Dictionary<string, OrderByType> TaskOrderBy
    { get { return _taskOrderBy; } set { _taskOrderBy = value; } }
        public Dictionary<string, OrderByType> TaskOrderBy
        { get { return _taskOrderBy; } set { _taskOrderBy = value; } }
    public List<int> TaskInboundTypes => typeof(TaskInboundTypeEnum).GetEnumIndexList();
        public List<int> TaskInboundTypes => typeof(TaskInboundTypeEnum).GetEnumIndexList();
    public List<int> TaskOutboundTypes => typeof(TaskOutboundTypeEnum).GetEnumIndexList();
        public List<int> TaskOutboundTypes => typeof(TaskOutboundTypeEnum).GetEnumIndexList();
    public List<int> TaskRelocationTypes => typeof(TaskRelocationTypeEnum).GetEnumIndexList();
        public List<int> TaskRelocationTypes => typeof(TaskRelocationTypeEnum).GetEnumIndexList();
    public List<int> TaskRobotTypes => typeof(TaskOtherTypeEnum).GetEnumIndexList();
        public List<int> TaskRobotTypes => typeof(TaskOtherTypeEnum).GetEnumIndexList();
        public TaskService(
            ITaskRepository BaseDal,
            IRouterService routerService,
            ITaskExecuteDetailService taskExecuteDetailService,
            ITaskExecuteDetailRepository taskExecuteDetailRepository,
            IMapper mapper,
            IOutboundTaskFlowService outboundTaskFlowService,
            IInboundTaskFlowService inboundTaskFlowService,
            IRelocationTaskFlowService relocationTaskFlowService,
            IRobotTaskFlowService robotTaskFlowService) : base(BaseDal)
        {
            _routerService = routerService;
            _taskExecuteDetailService = taskExecuteDetailService;
            _taskExecuteDetailRepository = taskExecuteDetailRepository;
            _mapper = mapper;
            _outboundTaskFlowService = outboundTaskFlowService;
            _inboundTaskFlowService = inboundTaskFlowService;
            _relocationTaskFlowService = relocationTaskFlowService;
            _robotTaskFlowService = robotTaskFlowService;
        }
        /// <summary>
        /// 接收WMS任务信息
        /// </summary>
        /// <param name="taskDTOs">WMS任务对象集合</param>
        /// <returns>返回处理结果</returns>
        public WebResponseContent ReceiveWMSTask([NotNull] List<WMSTaskDTO> taskDTOs)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                List<Dt_Task> tasks = new List<Dt_Task>();
                List<Dt_Task> duplicates = new List<Dt_Task>();
                foreach (var item in taskDTOs)
                {
                    Dt_Task existingTask = BaseDal.QueryFirst(x => x.TaskNum == item.TaskNum || x.PalletCode == item.PalletCode);
                    if (existingTask != null)
                    {
                        duplicates.Add(existingTask);
                        continue;
                    }
                    Dt_Task task = _mapper.Map<Dt_Task>(item);
                    task.Creater = "WMS";
                    InitializeTaskOnReceive(task, item);
                    tasks.Add(task);
                }
                // TOOD: 这里注意添加错误要返回错误
                BaseDal.AddData(tasks);
                _taskExecuteDetailService.AddTaskExecuteDetail(tasks.Select(x => x.TaskNum).ToList(), "接收WMS任务");
                // 将重复任务信息也一并返回
                tasks.AddRange(duplicates);
                var result = tasks;
                content = WebResponseContent.Instance.OK("成功", result);
            }
            catch (Exception ex)
            {
                content = WebResponseContent.Instance.Error($"任务接收错误,错误信息:{ex.Message}");
            }
            return content;
        }
        /// <summary>
        /// 根据托盘号、起始地址向WMS请求任务
        /// </summary>
        /// <param name="palletCode">托盘号</param>
        /// <param name="sourceAddress">起始地址</param>
        /// <returns></returns>
        public WebResponseContent RequestWMSTask(string palletCode, string sourceAddress)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                WMSTaskDTO taskDTO = new WMSTaskDTO()
                {
                    TaskNum = Convert.ToInt32(DateTime.Now.ToString("HHmmss")),
                    Grade = 1,
                    PalletCode = palletCode,
                    Roadway = "SC01",
                    SourceAddress = sourceAddress,
                    TargetAddress = "SC01",
                    TaskStatus = (int)TaskInStatusEnum.InNew,
                    Id = 0,
                    TaskType = (int)TaskInboundTypeEnum.Inbound
                };
                content = ReceiveWMSTask(new List<WMSTaskDTO> { taskDTO });
            }
            catch (Exception ex)
            {
                content = WebResponseContent.Instance.Error(ex.Message);
            }
            return content;
        }
        /// <summary>
        /// 按任务分组初始化任务接收信息。
        /// </summary>
        /// <param name="task">任务实体。</param>
        /// <param name="source">WMS原始任务对象。</param>
        private void InitializeTaskOnReceive(Dt_Task task, WMSTaskDTO source)
        {
            switch (task.TaskType.GetTaskTypeGroup())
            {
                case TaskTypeGroup.OutbondGroup:
                    _outboundTaskFlowService.InitializeOnReceive(task, source);
                    break;
                case TaskTypeGroup.InboundGroup:
                    _inboundTaskFlowService.InitializeOnReceive(task, source);
                    break;
                case TaskTypeGroup.RelocationGroup:
                    _relocationTaskFlowService.InitializeOnReceive(task, source);
                    break;
                case TaskTypeGroup.OtherGroup:
                    _robotTaskFlowService.InitializeOnReceive(task, source);
                    break;
                default:
                    break;
            }
        }
        /// <summary>
        /// 根据设备编号、当前地址查询输送线未执行的任务
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="currentAddress">当前地址</param>
        /// <returns></returns>
        public Dt_Task QueryConveyorLineTask(string deviceNo, string currentAddress)
        {
            return BaseDal.QueryFirst(x => (TaskInboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskInStatusEnum.InNew || TaskOutboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskOutStatusEnum.SC_OutFinish) && x.CurrentAddress == currentAddress, TaskOrderBy);
        }
        /// <summary>
        /// 根据任务号、下一地址查询输送线执行中的任务
        /// </summary>
        /// <param name="taskNum">任务号</param>
        /// <param name="nextAddress">下一地址</param>
        /// <returns></returns>
        public Dt_Task QueryExecutingConveyorLineTask(int taskNum, string nextAddress)
        {
            if (string.IsNullOrEmpty(nextAddress))
                throw new ArgumentNullException(nameof(nextAddress), "下一地址不能为空");
            return BaseDal.QueryFirst(x => x.TaskNum == taskNum && x.NextAddress == nextAddress && (x.TaskStatus == (int)TaskInStatusEnum.Line_InExecuting || x.TaskStatus == (int)TaskOutStatusEnum.Line_OutExecuting), TaskOrderBy);
        }
        /// <summary>
        /// 根据任务号、当前地址查询输送线完成的任务
        /// </summary>
        /// <param name="taskNum">任务号</param>
        /// <param name="currentAddress">当前地址</param>
        /// <returns></returns>
        public Dt_Task QueryCompletedConveyorLineTask(int taskNum, string currentAddress)
        {
            if (string.IsNullOrEmpty(currentAddress))
                throw new ArgumentNullException(nameof(currentAddress), "当前地址不能为空");
            return BaseDal.QueryFirst(x => x.TaskNum == taskNum && x.CurrentAddress == currentAddress && (x.TaskStatus == (int)TaskInStatusEnum.Line_InFinish || x.TaskStatus == (int)TaskOutStatusEnum.Line_OutFinish), TaskOrderBy);
        }
        /// <summary>
        /// 根据设备编号、任务类型分组(可选)按照优先级以及创建时间排序查询任务池新增的任务
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="taskTypeGroup">任务类型分组(可选)</param>
        /// <returns></returns>
        public Dt_Task? QuertStackerCraneTask(string deviceNo, TaskTypeGroup? taskTypeGroup = null)
        {
            if (taskTypeGroup == null)
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && (TaskInboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskInStatusEnum.Line_InFinish || TaskOutboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskOutStatusEnum.OutNew), TaskOrderBy);
            if (taskTypeGroup.Value == TaskTypeGroup.InboundGroup)
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskInboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskInStatusEnum.Line_InFinish, TaskOrderBy);
            if (taskTypeGroup.Value == TaskTypeGroup.OutbondGroup)
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskOutboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskOutStatusEnum.OutNew, TaskOrderBy);
            return null;
        }
        /// <summary>
        /// 根据设备编号、当前地址按照优先级以及创建时间排序查询任务池新增的任务
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="currentAddress">当前地址</param>
        /// <returns>返回任务实体对象,可能为null</returns>
        public Dt_Task QueryStackerCraneTask(string deviceNo, string currentAddress = "")
        {
            if (string.IsNullOrEmpty(currentAddress))
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && (TaskInboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskInStatusEnum.Line_InFinish || TaskOutboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskOutStatusEnum.OutNew || TaskRelocationTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskRelocationStatusEnum.RelocationNew), TaskOrderBy);
            else
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && x.CurrentAddress == currentAddress && (TaskInboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskInStatusEnum.Line_InFinish || TaskOutboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskOutStatusEnum.OutNew || TaskRelocationTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskRelocationStatusEnum.RelocationNew), TaskOrderBy);
        }
        /// <summary>
        /// 根据设备编号、当前地址按照优先级以及创建时间排序查询任务池入库类型的新增的任务
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="currentAddress">当前地址</param>
        /// <returns>返回任务实体对象,可能为null</returns>
        public Dt_Task QueryStackerCraneInTask(string deviceNo, string currentAddress = "")
        {
            if (string.IsNullOrEmpty(currentAddress))
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskInboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskInStatusEnum.Line_InFinish, TaskOrderBy);
            else
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskInboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskInStatusEnum.Line_InFinish && x.CurrentAddress == currentAddress, TaskOrderBy);
        }
        /// <summary>
        /// 根据设备编号、当前地址按照优先级以及创建时间排序查询任务池出库类型的新增的任务
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="currentAddress">当前地址</param>
        /// <returns>返回任务实体对象,可能为null</returns>
        public Dt_Task QueryStackerCraneOutTask(string deviceNo, string currentAddress = "")
        {
            if (string.IsNullOrEmpty(currentAddress))
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskOutboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskOutStatusEnum.OutNew, TaskOrderBy);
            else
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskOutboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskOutStatusEnum.OutNew && x.CurrentAddress == currentAddress, TaskOrderBy);
        }
        /// <summary>
        /// 根据设备编号、当前地址按照优先级以及创建时间排序查询任务池出库类型的新增的任务
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="currentAddress">当前地址</param>
        /// <returns>返回任务实体对象集合,可能为null</returns>
        public List<Dt_Task> QueryStackerCraneOutTasks(string deviceNo, List<string> outStationCodes)
        {
            return BaseDal.QueryData(x => x.Roadway == deviceNo && TaskOutboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskOutStatusEnum.OutNew && outStationCodes.Contains(x.CurrentAddress), TaskOrderBy);
        }
        /// <summary>
        /// 更新任务异常信息显示
        /// </summary>
        /// <param name="taskNum">任务号</param>
        /// <param name="message">异常信息</param>
        public WebResponseContent UpdateTaskExceptionMessage(int taskNum, string message)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                if (string.IsNullOrEmpty(message))
                    throw new ArgumentNullException(nameof(message), "异常信息不能为空");
                Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum);
                if (task == null) return WebResponseContent.Instance.Error($"未找到该任务信息,任务号:【{taskNum}】");
                if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup)
                {
                    task.TaskStatus = (int)TaskOutStatusEnum.OutPending;
                }
                else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup)
                {
                    task.TaskStatus = (int)TaskInStatusEnum.InPending;
                }
                task.ExceptionMessage = message;
                task.ModifyDate = DateTime.Now;
                BaseDal.UpdateData(task);
                _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, task.ExceptionMessage);
                content = WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
            {
                content = WebResponseContent.Instance.Error(ex.Message);
            }
            return content;
        }
        /// <summary>
        /// 更新任务状态信息,并同步至WMS
        /// </summary>
        /// <param name="taskNum">任务号</param>
        /// <param name="status">任务状态</param>
        public void UpdateTaskStatus(int taskNum, int status)
        {
            Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum);
            if (task == null) return;
            task.TaskStatus = status;
            task.ModifyDate = DateTime.Now;
            BaseDal.UpdateData(task);
        }
        /// <summary>
        /// 将任务状态修改为下一个状态
        /// </summary>
        /// <param name="taskNum">任务号</param>
        public WebResponseContent UpdateTaskStatusToNext(int taskNum)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum);
                if (task == null) return WebResponseContent.Instance.Error($"未找到该任务信息,任务号:【{taskNum}】");
                return UpdateTaskStatusToNext(task);
            }
            catch (Exception ex)
            {
                content = WebResponseContent.Instance.Error(ex.Message);
            }
            return content;
        }
        /// <summary>
        /// 将任务状态修改为下一个状态
        /// </summary>
        /// <param name="task">任务实体对象</param>
        /// <returns></returns>
        public WebResponseContent UpdateTaskStatusToNext([NotNull] Dt_Task task)
        {
            int oldState = task.TaskStatus;
            var result = task.TaskType.GetTaskTypeGroup() switch
            {
                TaskTypeGroup.OutbondGroup => _outboundTaskFlowService.MoveToNextStatus(task),
                TaskTypeGroup.InboundGroup => _inboundTaskFlowService.MoveToNextStatus(task),
                TaskTypeGroup.RelocationGroup => _relocationTaskFlowService.MoveToNextStatus(task),
                TaskTypeGroup.OtherGroup => _robotTaskFlowService.MoveToNextStatus(task),
                _ => WebResponseContent.Instance.Error($"任务类型错误,未找到该任务类型,任务号:【{task.TaskNum}】,任务类型:【{task.TaskType}】")
            };
            if (!result.Status)
                return result;
            // 出库完成线体节点时,可能需要接收入库新任务。
            if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup
                && result.Data is List<WMSTaskDTO> wmsTasks
                && wmsTasks.Count > 0)
            {
                return ReceiveWMSTask(wmsTasks);
            }
            // 更新任务数据
            task.ModifyDate = DateTime.Now;
            task.Modifier = "System";
            if (task.TaskStatus == (int)TaskOutStatusEnum.Line_OutFinish)
            {
                BaseDal.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动完成);
            }
            else
            {
                BaseDal.UpdateData(task);
            }
            // 记录任务执行详情
            string logMessage = App.User.UserId > 0
                ? $"人工手动将任务状态从【{oldState}】跳转到【{task.TaskStatus}】"
                : $"系统自动流程,任务状态从【{oldState}】转到【{task.TaskStatus}】";
            _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, logMessage);
            return WebResponseContent.Instance.OK();
        }
        /// <summary>
        /// 根据任务号、当前地址更新任务位置信息
        /// </summary>
        /// <param name="taskNum">任务号</param>
        /// <param name="currentAddress">当前地址</param>
        /// <returns></returns>
        public Dt_Task? UpdatePosition(int taskNum, string currentAddress)
        {
            try
            {
                if (string.IsNullOrEmpty(currentAddress))
                    throw new ArgumentNullException(nameof(currentAddress), "当前地址不能为空");
                Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum && x.CurrentAddress == currentAddress);
                if (task == null) throw new Exception($"未找到该任务信息,任务号:【{taskNum}】");
                string oldCurrentPos = task.CurrentAddress;
                string oldNextPos = task.NextAddress;
                Dt_Router routers = _routerService.QueryNextRoute(oldNextPos, task.TargetAddress);
                if (routers == null) throw new Exception($"未找到设备路由信息");
                task.CurrentAddress = task.NextAddress;
                task.NextAddress = routers.ChildPosi;
                task.ModifyDate = DateTime.Now;
                task.Modifier = "System";
                BaseDal.UpdateData(task);
                _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"系统自动流程,更新当前位置【{oldCurrentPos} ----> {task.CurrentAddress}】和下一位置【{oldNextPos} ----> {task.NextAddress}】");
                return task;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"UpdatePosition 更新任务位置失败,任务号:【{taskNum}】,错误信息:【{ex.Message}】");
            }
            return null;
        }
        /// <summary>
        /// 任务完成
        /// </summary>
        /// <param name="taskNum">任务编号</param>
        /// <returns>返回处理结果</returns>
        public WebResponseContent StackCraneTaskCompleted(int taskNum)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum);
                if (task == null) return WebResponseContent.Instance.Error($"未找到该任务信息,任务号:【{taskNum}】");
                TaskTypeGroup taskTypeGroup = task.TaskType.GetTaskTypeGroup();
                content = taskTypeGroup switch
                {
                    TaskTypeGroup.OutbondGroup => _outboundTaskFlowService.CompleteStackerTask(task),
                    TaskTypeGroup.InboundGroup => _inboundTaskFlowService.CompleteStackerTask(task),
                    TaskTypeGroup.RelocationGroup => _relocationTaskFlowService.CompleteStackerTask(task),
                    TaskTypeGroup.OtherGroup => _robotTaskFlowService.CompleteStackerTask(task),
                    _ => throw new Exception($"任务类型错误,未找到该任务类型,任务号:【{taskNum}】,任务类型:【{task.TaskType}】")
                };
                if (!content.Status)
                {
                    return content;
                }
                if (taskTypeGroup == TaskTypeGroup.OutbondGroup && task.TaskStatus == (int)TaskOutStatusEnum.SC_OutFinish)
                {
                    BaseDal.UpdateData(task);
                    _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, "堆垛机出库完成");
                    return content;
                }
                if (taskTypeGroup == TaskTypeGroup.InboundGroup && task.TaskStatus == (int)TaskInStatusEnum.SC_InFinish)
                {
                    BaseDal.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动完成);
                    _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, "堆垛机入库完成");
                    return content;
                }
                if (taskTypeGroup == TaskTypeGroup.RelocationGroup && task.TaskStatus == (int)TaskRelocationStatusEnum.RelocationFinish)
                {
                    BaseDal.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动完成);
                    _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, "堆垛机移库完成");
                    return content;
                }
                content = WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
            {
                content = WebResponseContent.Instance.Error($"任务完成异常,任务号:【{taskNum}】");
            }
            return content;
        }
        /// <summary>
        /// 恢复挂起任务
        /// </summary>
        /// <param name="taskNum">任务号</param>
        /// <returns>返回处理结果</returns>
        public WebResponseContent TaskStatusRecovery(int taskNum)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum);
                if (task == null) return WebResponseContent.Instance.Error($"未找到该任务信息,任务号:【{taskNum}】");
                if (task.TaskStatus != (int)TaskInStatusEnum.InPending && task.TaskStatus != (int)TaskOutStatusEnum.OutPending)
                {
                    return content = WebResponseContent.Instance.Error($"该任务状态不可恢复,任务号:【{taskNum}】,任务状态:【{task.TaskStatus}】");
                }
                Dt_TaskExecuteDetail taskExecuteDetail = _taskExecuteDetailRepository.QueryFirst(x => x.TaskId == task.TaskId && x.IsNormal, new Dictionary<string, OrderByType> { { nameof(Dt_TaskExecuteDetail.TaskDetailId), OrderByType.Desc } });
                if (taskExecuteDetail != null)
                {
                    task.TaskStatus = taskExecuteDetail.TaskState;
                }
                else
                {
                    if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup)
                    {
                        task.TaskStatus = (int)TaskOutStatusEnum.OutNew;
                    }
                    else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup)
                    {
                        task.TaskStatus = (int)TaskInStatusEnum.InNew;
                    }
                    //todo
                }
                task.ExceptionMessage = string.Empty;
                BaseDal.UpdateData(task);
                _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"人工恢复挂起任务,恢复挂起时任务状态【{task.TaskStatus}】");
                content = WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
            {
                content = WebResponseContent.Instance.Error(ex.Message);
            }
            return content;
        }
        /// <summary>
        /// 回滚任务状态
        /// </summary>
        /// <param name="taskNum">任务号</param>
        /// <returns>返回处理结果</returns>
        public WebResponseContent RollbackTaskStatusToLast(int taskNum)
        {
            WebResponseContent content = new();
            try
            {
                Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum);
                if (task == null) return WebResponseContent.Instance.Error($"未找到该任务信息,任务号:【{taskNum}】");
                int oldState = task.TaskStatus;
                Dt_TaskExecuteDetail taskExecuteDetail = _taskExecuteDetailRepository.QueryFirst(x => x.TaskId == task.TaskId && x.TaskState < task.TaskStatus && x.TaskState > 0, new Dictionary<string, OrderByType> { { nameof(Dt_TaskExecuteDetail.TaskDetailId), OrderByType.Desc } });
                if (taskExecuteDetail != null)
                {
                    task.TaskStatus = taskExecuteDetail.TaskState;
                    task.CurrentAddress = taskExecuteDetail.CurrentAddress;
                    task.NextAddress = taskExecuteDetail.NextAddress;
                }
                else
                {
                    return content = WebResponseContent.Instance.Error($"未找到任务明细信息,该任务状态不可回滚到上一步,任务号:【{taskNum}】,任务状态:【{task.TaskStatus}】");
                }
                task.ExceptionMessage = string.Empty;
                BaseDal.UpdateData(task);
                _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"人工将任务状态从【{oldState}】回滚到【{task.TaskStatus}】");
                content = WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
            {
                content = WebResponseContent.Instance.Error(ex.Message);
            }
            return content;
        }
        public override WebResponseContent DeleteData(object[] keys)
        {
            List<int> taskKeys = new List<int>();
            for (int i = 0; i < keys.Length; i++)
            {
                taskKeys.Add(Convert.ToInt32(keys[i]));
            }
            List<Dt_Task> tasks = BaseDal.QueryData(x => taskKeys.Contains(x.TaskId));
            BaseDal.DeleteAndMoveIntoHty(tasks, OperateTypeEnum.人工删除);
            return WebResponseContent.Instance.OK($"成功删除{tasks.Count}条数据");
        }
        /// <summary>
        /// 根据设备编号、当前地址按照优先级以及创建时间排序查询任务池新增的任务
        /// </summary>
        /// <param name="deviceNo">设备编号</param>
        /// <param name="currentAddress">当前地址</param>
        /// <returns>返回任务实体对象,可能为null</returns>
        public Dt_Task QueryRobotCraneTask(string deviceNo, string currentAddress = "")
        {
            if (string.IsNullOrEmpty(currentAddress))
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && (TaskRobotTypes.Contains(x.TaskType) && x.TaskStatus <= (int)TaskRobotStatusEnum.RobotExecuting), TaskOrderBy);
            else
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskRobotTypes.Contains(x.TaskType) && x.CurrentAddress == currentAddress && x.TaskStatus <= (int)TaskRobotStatusEnum.RobotExecuting, TaskOrderBy);
        }
        /// <summary>
        /// 获取与指定任务编号关联的任务。
        /// </summary>
        /// <param name="taskNum">要获取的任务的唯一标识符。</param>
        /// <returns>表示指定编号任务的<see cref="Dt_Task"/>对象,如果不存在该任务则返回<c>null</c>。</returns>
        public Dt_Task QueryByTaskNum(int taskNum)
        {
            return BaseDal.QueryFirst(x => x.TaskNum == taskNum);
        }
        /// <summary>
        /// 接收WMS手动创建的任务,创建WCS任务
        /// </summary>
        /// <param name="taskDTOs">WMS任务对象集合</param>
        /// <returns>返回处理结果</returns>
        public WebResponseContent ReceiveManualTask([NotNull] List<WMSTaskDTO> taskDTOs)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                // 调用 ReceiveWMSTask 创建 WCS 任务
                content = ReceiveWMSTask(taskDTOs);
                return content;
            }
            catch (Exception ex)
            {
                content = WebResponseContent.Instance.Error($"手动任务接收错误,错误信息:{ex.Message}");
                return content;
            }
        }
        /// <summary>
        /// 查询指定起点地址的新建手动入库任务
        /// </summary>
        /// <param name="sourceAddress">起点地址</param>
        /// <returns>任务实体</returns>
        public Dt_Task QueryManualInboundTask(string sourceAddress)
        {
            return BaseDal.QueryFirst(x =>
                x.TaskType == (int)TaskInboundTypeEnum.Inbound &&
                x.TaskStatus == (int)TaskInStatusEnum.InNew &&
                x.SourceAddress == sourceAddress &&
                x.Creater == "WMS");
        }
    }
    public enum ConveyorLineDBNameNew
    public TaskService(
        ITaskRepository BaseDal,
        IRouterService routerService,
        ITaskExecuteDetailService taskExecuteDetailService,
        ITaskExecuteDetailRepository taskExecuteDetailRepository,
        IMapper mapper,
        IOutboundTaskFlowService outboundTaskFlowService,
        IInboundTaskFlowService inboundTaskFlowService,
        IRelocationTaskFlowService relocationTaskFlowService,
        IRobotTaskFlowService robotTaskFlowService) : base(BaseDal)
    {
        Barcode
    }
    public class ConveyorLineTaskCommandNew : DeviceCommand
    {
        /// <summary>
        /// 任务号
        /// </summary>
        public short TaskNo { get; set; }
        /// <summary>
        /// 源位置 开始地址
        /// </summary>
        public short Source { get; set; }
        /// <summary>
        /// 目标位置
        /// </summary>
        public short Target { get; set; }
        /// <summary>
        /// 箱型
        /// </summary>
        public byte BoxType { get; set; }
        /// <summary>
        /// 输送线状态 设备空闲状态
        /// </summary>
        public byte CV_State { get; set; }
        /// <summary>
        /// 输送线错误代码
        /// </summary>
        public byte CV_ERRCode { get; set; }
        /// <summary>
        /// WCS就绪标志 WCS下发完成时,触发为1
        /// </summary>
        public byte WCS_STB { get; set; }
        /// <summary>
        /// WCS应答标志 WCS收到完成时,触发为1
        /// </summary>
        public byte WCS_ACK { get; set; }
        /// <summary>
        /// PLC就绪标志 完成任务时,触发为1
        /// </summary>
        public byte PLC_STB { get; set; }
        /// <summary>
        /// PLC应答标志 收到任务时,触发为1
        /// </summary>
        public byte PLC_ACK { get; set; }
        /// <summary>
        /// PLC请求标志 入库站台,到位写1
        /// </summary>
        public byte PLC_REQ { get; set; }
        /// <summary>
        /// WCS错误代码
        /// </summary>
        public byte WCS_ERRCode { get; set; }
        /// <summary>
        /// WCS特殊标志 (旋转标识、强制放行、循环、特殊申请、是否叠盘、是否堵塞)
        /// </summary>
        public byte WCS_Special { get; set; }
        /// <summary>
        /// 设备自动模式 手动1,自动2
        /// </summary>
        public byte Equ_Auto { get; set; }
        /// <summary>
        /// 尾板标志
        /// </summary>
        public byte Last_pallet { get; set; }
        /// <summary>
        /// 条码(22个字符)
        /// </summary>
        [DataLength(22)]
        public string Barcode { get; set; }
        _routerService = routerService;
        _taskExecuteDetailService = taskExecuteDetailService;
        _taskExecuteDetailRepository = taskExecuteDetailRepository;
        _mapper = mapper;
        _outboundTaskFlowService = outboundTaskFlowService;
        _inboundTaskFlowService = inboundTaskFlowService;
        _relocationTaskFlowService = relocationTaskFlowService;
        _robotTaskFlowService = robotTaskFlowService;
    }
}