wanshenmean
6 小时以前 ba9c1994b95624b88ef606ec00394990d8f2009f
refactor(TaskService): 重构任务服务代码结构,拆分文件并优化逻辑

将TaskService.cs拆分为多个部分类文件,按功能模块组织代码
更新机器人任务总数计算逻辑,修复状态更新问题
添加新的输送线任务命令模型和枚举类型
优化任务接收、状态更新和查询方法的实现
已添加5个文件
已修改4个文件
1616 ■■■■ 文件已修改
Code/.omc/state/idle-notif-cooldown.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/RobotTaskService.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs 816 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService/TaskService.Complete.cs 180 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService/TaskService.Models.cs 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService/TaskService.Query.cs 156 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService/TaskService.Receive.cs 172 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService/TaskService.Status.cs 188 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotPrefixCommandHandler.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Code/.omc/state/idle-notif-cooldown.json
@@ -1,3 +1,3 @@
{
  "lastSentAt": "2026-04-15T06:28:49.381Z"
  "lastSentAt": "2026-04-15T11:40:34.475Z"
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/RobotTaskService.cs
@@ -90,7 +90,7 @@
                    RobotTaskState = taskDTO.TaskStatus,
                    RobotGrade = taskDTO.Grade,
                    Creater = "WMS",
                    RobotTaskTotalNum = 0,
                    RobotTaskTotalNum = 48,
                };
                BaseDal.AddData(task);
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,766 +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";
                    content = InitializeTaskOnReceive(task, item);
                    if (!content.Status)
                        return content;
                    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 WebResponseContent InitializeTaskOnReceive(Dt_Task task, WMSTaskDTO source)
        {
            switch (task.TaskType.GetTaskTypeGroup())
            {
                case TaskTypeGroup.OutbondGroup:
                    return _outboundTaskFlowService.InitializeOnReceive(task, source);
                case TaskTypeGroup.InboundGroup:
                    return _inboundTaskFlowService.InitializeOnReceive(task, source);
                case TaskTypeGroup.RelocationGroup:
                    return _relocationTaskFlowService.InitializeOnReceive(task, source);
                case TaskTypeGroup.OtherGroup:
                    return _robotTaskFlowService.InitializeOnReceive(task, source);
                default:
                    return WebResponseContent.Instance.Error("WCS不存在当前任务的任务类型");
            }
        }
        /// <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)
            {
                WebResponseContent content = ReceiveWMSTask(wmsTasks);
                if (!content.Status)
                    return content;
            }
            // æ›´æ–°ä»»åŠ¡æ•°æ®
            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
            {
                // æ”¶é›†é‡å¤ä»»åŠ¡çš„ä¿¡æ¯
                var duplicateTasks = new List<DuplicateTaskDto>();
                // å€’序遍历,安全删除并收集被移除的项
                for (int i = taskDTOs.Count - 1; i >= 0; i--)
                {
                    var item = taskDTOs[i];
                    var exists = BaseDal.QueryFirst(x => x.TaskNum == item.TaskNum || x.PalletCode == item.PalletCode);
                    if (exists != null)
                    {
                        duplicateTasks.Add(new DuplicateTaskDto
                        {
                            TaskNum = exists.TaskNum,
                            PalletCode = exists.PalletCode,
                            TaskType = exists.TaskType,
                            TaskStatus = exists.TaskStatus
                        });
                        taskDTOs.RemoveAt(i);
                    }
                }
                // è°ƒç”¨ ReceiveWMSTask åˆ›å»º WCS ä»»åŠ¡
                content = ReceiveWMSTask(taskDTOs);
                // å¦‚果有重复任务,修改返回结果
                if (duplicateTasks.Count > 0 && content.Status)
                {
                    var result = new ReceiveTaskResultDto
                    {
                        Success = true,
                        Message = content.Message + $",其中{duplicateTasks.Count}个任务在WCS中已存在",
                        CreatedCount = taskDTOs.Count,
                        DuplicateTasks = duplicateTasks
                    };
                    content.Data = result;
                }
                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);
        }
    }
    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;
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService/TaskService.Complete.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,180 @@
using MapsterMapper;
using SqlSugar;
using System.Diagnostics.CodeAnalysis;
using WIDESEA_Core;
using WIDESEAWCS_Common.TaskEnum;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_Core.Enums;
using WIDESEAWCS_DTO;
using WIDESEAWCS_DTO.TaskInfo;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob.Models;
using WIDESEAWCS_QuartzJob.Service;
namespace WIDESEAWCS_TaskInfoService;
/// <summary>
/// TaskService ä»»åŠ¡å®Œæˆä¸Žæ¢å¤ç›¸å…³æ–¹æ³•
/// </summary>
public partial class TaskService
{
    /// <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}条数据");
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService/TaskService.Models.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,98 @@
using WIDESEAWCS_QuartzJob.DeviceBase;
namespace WIDESEAWCS_TaskInfoService;
/// <summary>
/// è¾“送线PLC命令相关枚举与命令对象
/// </summary>
public enum ConveyorLineDBNameNew
{
    Barcode
}
/// <summary>
/// è¾“送线任务命令(新版本)
/// </summary>
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; }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService/TaskService.Query.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,156 @@
using WIDESEAWCS_Common.TaskEnum;
using WIDESEAWCS_Model.Models;
namespace WIDESEAWCS_TaskInfoService;
/// <summary>
/// TaskService æŸ¥è¯¢ç›¸å…³æ–¹æ³•
/// </summary>
public partial class TaskService
{
    /// <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="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>
    /// æŸ¥è¯¢æŒ‡å®šèµ·ç‚¹åœ°å€çš„æ–°å»ºæ‰‹åŠ¨å…¥åº“ä»»åŠ¡
    /// </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);
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService/TaskService.Receive.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,172 @@
using MapsterMapper;
using System.Diagnostics.CodeAnalysis;
using WIDESEA_Core;
using WIDESEAWCS_Common.TaskEnum;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.Enums;
using WIDESEAWCS_DTO.TaskInfo;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
using WIDESEAWCS_QuartzJob.Models;
namespace WIDESEAWCS_TaskInfoService;
/// <summary>
/// TaskService ä»»åŠ¡æŽ¥æ”¶ç›¸å…³æ–¹æ³•
/// </summary>
public partial class TaskService
{
    /// <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";
                content = InitializeTaskOnReceive(task, item);
                if (!content.Status)
                    return content;
                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 WebResponseContent InitializeTaskOnReceive(Dt_Task task, WMSTaskDTO source)
    {
        switch (task.TaskType.GetTaskTypeGroup())
        {
            case TaskTypeGroup.OutbondGroup:
                return _outboundTaskFlowService.InitializeOnReceive(task, source);
            case TaskTypeGroup.InboundGroup:
                return _inboundTaskFlowService.InitializeOnReceive(task, source);
            case TaskTypeGroup.RelocationGroup:
                return _relocationTaskFlowService.InitializeOnReceive(task, source);
            case TaskTypeGroup.OtherGroup:
                return _robotTaskFlowService.InitializeOnReceive(task, source);
            default:
                return WebResponseContent.Instance.Error("WCS不存在当前任务的任务类型");
        }
    }
    /// <summary>
    /// æŽ¥æ”¶WMS手动创建的任务,创建WCS任务
    /// </summary>
    /// <param name="taskDTOs">WMS任务对象集合</param>
    /// <returns>返回处理结果</returns>
    public WebResponseContent ReceiveManualTask([NotNull] List<WMSTaskDTO> taskDTOs)
    {
        WebResponseContent content = new WebResponseContent();
        try
        {
            // æ”¶é›†é‡å¤ä»»åŠ¡çš„ä¿¡æ¯
            var duplicateTasks = new List<DuplicateTaskDto>();
            // å€’序遍历,安全删除并收集被移除的项
            for (int i = taskDTOs.Count - 1; i >= 0; i--)
            {
                var item = taskDTOs[i];
                var exists = BaseDal.QueryFirst(x => x.TaskNum == item.TaskNum || x.PalletCode == item.PalletCode);
                if (exists != null)
                {
                    duplicateTasks.Add(new DuplicateTaskDto
                    {
                        TaskNum = exists.TaskNum,
                        PalletCode = exists.PalletCode,
                        TaskType = exists.TaskType,
                        TaskStatus = exists.TaskStatus
                    });
                    taskDTOs.RemoveAt(i);
                }
            }
            // è°ƒç”¨ ReceiveWMSTask åˆ›å»º WCS ä»»åŠ¡
            content = ReceiveWMSTask(taskDTOs);
            // å¦‚果有重复任务,修改返回结果
            if (duplicateTasks.Count > 0 && content.Status)
            {
                var result = new ReceiveTaskResultDto
                {
                    Success = true,
                    Message = content.Message + $",其中{duplicateTasks.Count}个任务在WCS中已存在",
                    CreatedCount = taskDTOs.Count,
                    DuplicateTasks = duplicateTasks
                };
                content.Data = result;
            }
            return content;
        }
        catch (Exception ex)
        {
            content = WebResponseContent.Instance.Error($"手动任务接收错误,错误信息:{ex.Message}");
            return content;
        }
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService/TaskService.Status.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,188 @@
using System.Diagnostics.CodeAnalysis;
using WIDESEAWCS_Common.TaskEnum;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.Enums;
using WIDESEAWCS_DTO;
using WIDESEAWCS_DTO.TaskInfo;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
using WIDESEAWCS_QuartzJob.Models;
using WIDESEAWCS_QuartzJob.Service;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.Enums;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
using WIDESEAWCS_QuartzJob.Models;
using WIDESEAWCS_QuartzJob.Service;
namespace WIDESEAWCS_TaskInfoService;
/// <summary>
/// TaskService ä»»åŠ¡çŠ¶æ€æ›´æ–°ç›¸å…³æ–¹æ³•
/// </summary>
public partial class TaskService
{
    /// <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)
        {
            WebResponseContent content = ReceiveWMSTask(wmsTasks);
            if (!content.Status)
                return content;
        }
        // æ›´æ–°ä»»åŠ¡æ•°æ®
        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;
    }
}
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotPrefixCommandHandler.cs
@@ -267,7 +267,7 @@
                // å¦‚果任务存在,同步更新任务的计数
                if (task != null)
                {
                    task.RobotTaskTotalNum += positions.Length;
                    task.RobotTaskTotalNum -= positions.Length;
                }
            }