wanshenmean
2026-03-17 94ad631d316da04c46266ddb1fc6e63e6f8f2fae
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs
@@ -17,10 +17,11 @@
#endregion << 版 本 注 释 >>
using AutoMapper;
using MapsterMapper;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using SqlSugar;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using WIDESEA_Core;
using WIDESEAWCS_Common.HttpEnum;
using WIDESEAWCS_Common.TaskEnum;
@@ -28,12 +29,13 @@
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_Core.Enums;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.Http;
using WIDESEAWCS_DTO;
using WIDESEAWCS_DTO.Stock;
using WIDESEAWCS_DTO.TaskInfo;
using WIDESEAWCS_ITaskInfoRepository;
using WIDESEAWCS_ITaskInfoService;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
using WIDESEAWCS_QuartzJob.Models;
using WIDESEAWCS_QuartzJob.Service;
@@ -59,6 +61,8 @@
        public List<int> TaskInboundTypes => typeof(TaskInboundTypeEnum).GetEnumIndexList();
        public List<int> TaskOutboundTypes => typeof(TaskOutboundTypeEnum).GetEnumIndexList();
        public List<int> TaskRelocationTypes => typeof(TaskRelocationTypeEnum).GetEnumIndexList();
        public List<int> TaskRobotTypes => typeof(TaskOtherTypeEnum).GetEnumIndexList();
@@ -92,24 +96,25 @@
                    task.Creater = "WMS";
                    if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup)
                    {
                        List<Dt_Router> routers = _routerService.QueryNextRoutes(item.RoadWay, item.TargetAddress);
                        var taskType = 100;
                        Dt_Router router = _routerService.QueryNextRoute(item.Roadway, item.TargetAddress, taskType);
                        //暂不考虑多路径
                        if (routers.Count > 0)
                        if (router != null)
                        {
                            task.TaskState = (int)TaskOutStatusEnum.OutNew;
                            task.TaskStatus = (int)TaskOutStatusEnum.OutNew;
                            task.CurrentAddress = item.SourceAddress;
                            task.NextAddress = routers.FirstOrDefault().ChildPosi;
                            task.NextAddress = router.ChildPosi;
                        }
                    }
                    else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup)
                    {
                        List<Dt_Router> routers = _routerService.QueryNextRoutes(item.SourceAddress, item.TargetAddress);
                        Dt_Router routers = _routerService.QueryNextRoute(item.SourceAddress);
                        //暂不考虑多路径
                        if (routers.Count > 0)
                        if (!routers.IsNullOrEmpty())
                        {
                            task.TaskState = (int)TaskInStatusEnum.InNew;
                            task.TaskStatus = (int)TaskInStatusEnum.InNew;
                            task.CurrentAddress = item.SourceAddress;
                            task.NextAddress = routers.FirstOrDefault().ChildPosi;
                            task.NextAddress = routers.ChildPosi;
                        }
                    }
                    tasks.Add(task);
@@ -118,7 +123,7 @@
                _taskExecuteDetailService.AddTaskExecuteDetail(tasks.Select(x => x.TaskNum).ToList(), "接收WMS任务");
                content = WebResponseContent.Instance.OK("成功");
                content = WebResponseContent.Instance.OK("成功", tasks);
            }
            catch (Exception ex)
            {
@@ -143,7 +148,7 @@
                    TaskNum = Convert.ToInt32(DateTime.Now.ToString("HHmmss")),
                    Grade = 1,
                    PalletCode = palletCode,
                    RoadWay = "SC01",
                    Roadway = "SC01",
                    SourceAddress = sourceAddress,
                    TargetAddress = "SC01",
                    TaskState = (int)TaskInStatusEnum.InNew,
@@ -168,7 +173,7 @@
        /// <returns></returns>
        public Dt_Task QueryConveyorLineTask(string deviceNo, string currentAddress)
        {
            return BaseDal.QueryFirst(x => (TaskInboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskInStatusEnum.InNew || TaskOutboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskOutStatusEnum.SC_OutFinish) && x.CurrentAddress == currentAddress, TaskOrderBy);
            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>
@@ -179,7 +184,10 @@
        /// <returns></returns>
        public Dt_Task QueryExecutingConveyorLineTask(int taskNum, string nextAddress)
        {
            return BaseDal.QueryFirst(x => x.TaskNum == taskNum && x.NextAddress == nextAddress && (x.TaskState == (int)TaskInStatusEnum.Line_InExecuting || x.TaskState == (int)TaskOutStatusEnum.Line_OutExecuting), TaskOrderBy);
            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>
@@ -190,7 +198,10 @@
        /// <returns></returns>
        public Dt_Task QueryCompletedConveyorLineTask(int taskNum, string currentAddress)
        {
            return BaseDal.QueryFirst(x => x.TaskNum == taskNum && x.CurrentAddress == currentAddress && (x.TaskState == (int)TaskInStatusEnum.Line_InFinish || x.TaskState == (int)TaskOutStatusEnum.Line_OutFinish), TaskOrderBy);
            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>
@@ -202,11 +213,11 @@
        public Dt_Task? QuertStackerCraneTask(string deviceNo, TaskTypeGroup? taskTypeGroup = null)
        {
            if (taskTypeGroup == null)
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && (TaskInboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskInStatusEnum.Line_InFinish || TaskOutboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskOutStatusEnum.OutNew), TaskOrderBy);
                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.TaskState == (int)TaskInStatusEnum.Line_InFinish, TaskOrderBy);
                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.TaskState == (int)TaskOutStatusEnum.OutNew, TaskOrderBy);
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskOutboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskOutStatusEnum.OutNew, TaskOrderBy);
            return null;
        }
@@ -219,9 +230,9 @@
        public Dt_Task QueryStackerCraneTask(string deviceNo, string currentAddress = "")
        {
            if (string.IsNullOrEmpty(currentAddress))
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && (TaskInboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskInStatusEnum.Line_InFinish || TaskOutboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskOutStatusEnum.OutNew), TaskOrderBy);
                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.TaskState == (int)TaskInStatusEnum.Line_InFinish || TaskOutboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskOutStatusEnum.OutNew), TaskOrderBy);
                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>
@@ -233,9 +244,9 @@
        public Dt_Task QueryStackerCraneInTask(string deviceNo, string currentAddress = "")
        {
            if (string.IsNullOrEmpty(currentAddress))
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskInboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskInStatusEnum.Line_InFinish, TaskOrderBy);
                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.TaskState == (int)TaskInStatusEnum.Line_InFinish && x.CurrentAddress == currentAddress, TaskOrderBy);
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskInboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskInStatusEnum.Line_InFinish && x.CurrentAddress == currentAddress, TaskOrderBy);
        }
        /// <summary>
@@ -247,9 +258,9 @@
        public Dt_Task QueryStackerCraneOutTask(string deviceNo, string currentAddress = "")
        {
            if (string.IsNullOrEmpty(currentAddress))
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskOutboundTypes.Contains(x.TaskType) && x.TaskState == (int)TaskOutStatusEnum.OutNew, TaskOrderBy);
                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.TaskState == (int)TaskOutStatusEnum.OutNew && x.CurrentAddress == currentAddress, TaskOrderBy);
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskOutboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskOutStatusEnum.OutNew && x.CurrentAddress == currentAddress, TaskOrderBy);
        }
        /// <summary>
@@ -260,7 +271,7 @@
        /// <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.TaskState == (int)TaskOutStatusEnum.OutNew && outStationCodes.Contains(x.CurrentAddress), TaskOrderBy);
            return BaseDal.QueryData(x => x.Roadway == deviceNo && TaskOutboundTypes.Contains(x.TaskType) && x.TaskStatus == (int)TaskOutStatusEnum.OutNew && outStationCodes.Contains(x.CurrentAddress), TaskOrderBy);
        }
        /// <summary>
@@ -273,15 +284,18 @@
            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.TaskState = (int)TaskOutStatusEnum.OutPending;
                    task.TaskStatus = (int)TaskOutStatusEnum.OutPending;
                }
                else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup)
                {
                    task.TaskState = (int)TaskInStatusEnum.InPending;
                    task.TaskStatus = (int)TaskInStatusEnum.InPending;
                }
                task.ExceptionMessage = message;
                task.ModifyDate = DateTime.Now;
@@ -307,7 +321,7 @@
        {
            Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum);
            if (task == null) return;
            task.TaskState = status;
            task.TaskStatus = status;
            task.ModifyDate = DateTime.Now;
            BaseDal.UpdateData(task);
        }
@@ -339,89 +353,376 @@
        /// <returns></returns>
        public WebResponseContent UpdateTaskStatusToNext([NotNull] Dt_Task task)
        {
            WebResponseContent content = new WebResponseContent();
            try
            int oldState = task.TaskStatus;
            var result = task.TaskType.GetTaskTypeGroup() switch
            {
                int oldState = task.TaskState;
                if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup)
                {
                    if (task.TaskState >= (int)TaskOutStatusEnum.OutFinish)
                    {
                        return content = WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskState}】");
                    }
                TaskTypeGroup.OutbondGroup => ProcessOutboundTaskStatus(task),
                TaskTypeGroup.InboundGroup => ProcessInboundTaskStatus(task),
                TaskTypeGroup.RelocationGroup => ProcessRelocationTaskStatus(task),
                TaskTypeGroup.OtherGroup => ProcessRobotTaskStatus(task),
                _ => WebResponseContent.Instance.Error($"任务类型错误,未找到该任务类型,任务号:【{task.TaskNum}】,任务类型:【{task.TaskType}】")
            };
                    int nextStatus = task.TaskState.GetNextNotCompletedStatus<TaskOutStatusEnum>();
            if (!result.Status)
                return result;
                    task.TaskState = nextStatus;
                }
                else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup)
                {
                    if (task.TaskState >= (int)TaskInStatusEnum.InFinish)
                    {
                        return content = WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskState}】");
                    }
                    int nextStatus = task.TaskState.GetNextNotCompletedStatus<TaskInStatusEnum>();
                    task.TaskState = nextStatus;
                    if (task.TaskState == (int)TaskInStatusEnum.Line_InFinish)
                    {
                        // 调用WMS系统接口,获取最终目标地址
                        CreateTaskDto taskDto = new CreateTaskDto()
                        {
                            PalletCode = task.PalletCode,
                        };
                        var result = _httpClientHelper.Post<WebResponseContent>("WMS", taskDto.ToJson(), nameof(ConfigKey.GetTasksLocation));
                        if (!result.IsSuccess && !result.Data.Status)
                        {
                            return WebResponseContent.Instance.Error($"调用WMS接口获取任务目标地址失败,任务号:【{task.TaskNum}】,错误信息:【{content.Message}】");
                        }
                        string wmsTargetAddress = result.Data.Data?.ToString() ?? string.Empty;
                        if (string.IsNullOrEmpty(wmsTargetAddress))
                        {
                            return WebResponseContent.Instance.Error($"调用WMS接口获取任务目标地址失败,任务号:【{task.TaskNum}】,错误信息:【未获取到有效的目标地址】");
                        }
                        task.NextAddress = wmsTargetAddress;
                        task.TargetAddress = wmsTargetAddress;
                        task.CurrentAddress = task.NextAddress;
                    }
                }
                else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OtherGroup)
                {
                    if (task.TaskState >= (int)TaskRobotStatusEnum.RobotNew)
                    {
                        return content = WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskState}】");
                    }
                    int nextStatus = task.TaskState.GetNextNotCompletedStatus<TaskRobotStatusEnum>();
                    task.TaskState = nextStatus;
                }
                else
                {
                    throw new Exception($"任务类型错误,未找到该任务类型,任务号:【{task.TaskNum}】,任务类型:【{task.TaskType}】");
                }
                if (task.TaskState <= 0)
                {
                    return content = WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskState}】");
                }
                task.ModifyDate = DateTime.Now;
                task.Modifier = "System";
            // 更新任务数据
            task.ModifyDate = DateTime.Now;
            task.Modifier = "System";
            if(task.TaskStatus == (int)TaskOutStatusEnum.Line_OutFinish)
            {
                BaseDal.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动删除);
            }
            else
            {
                BaseDal.UpdateData(task);
                _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, App.User.UserId > 0 ? $"人工手动将任务状态从【{oldState}】跳转到【{task.TaskState}】" : $"系统自动流程,任务状态从【{oldState}】转到【{task.TaskState}】");
                content = WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
            // 记录任务执行详情
            string logMessage = App.User.UserId > 0
                ? $"人工手动将任务状态从【{oldState}】跳转到【{task.TaskStatus}】"
                : $"系统自动流程,任务状态从【{oldState}】转到【{task.TaskStatus}】";
            _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, logMessage);
            return WebResponseContent.Instance.OK();
        }
        /// <summary>
        /// 处理出库任务状态转换
        /// </summary>
        private WebResponseContent ProcessOutboundTaskStatus(Dt_Task task)
        {
            if (task.TaskStatus >= (int)TaskOutStatusEnum.OutFinish)
                return WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskStatus}】");
            task.TaskStatus = task.TaskStatus.GetNextNotCompletedStatus<TaskOutStatusEnum>();
            if (task.TaskStatus <= 0)
                return WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskStatus}】");
            // 根据状态调用不同的WMS接口
            if (task.TaskStatus == (int)TaskOutStatusEnum.Line_OutFinish && task.TaskType == (int)TaskOutboundTypeEnum.Outbound)
            {
                content = WebResponseContent.Instance.Error(ex.Message);
                return GetWMSOutboundTrayTask(task);
            }
            return content;
            else if (task.TaskStatus == (int)TaskOutStatusEnum.Line_OutFinish && task.TaskType == (int)TaskOutboundTypeEnum.OutEmpty)
            {
                return GetWMSRobotTask(task);
            }
            else
            {
                // return UpdateWMSTaskStatus(task);
                return WebResponseContent.Instance.OK();
            }
        }
        /// <summary>
        /// 处理入库任务状态转换
        /// </summary>
        private WebResponseContent ProcessInboundTaskStatus(Dt_Task task)
        {
            if (task.TaskStatus >= (int)TaskInStatusEnum.InFinish)
                return WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskStatus}】");
            task.TaskStatus = task.TaskStatus.GetNextNotCompletedStatus<TaskInStatusEnum>();
            if (task.TaskStatus <= 0)
                return WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskStatus}】");
            // 根据状态调用不同的WMS接口
            if (task.TaskStatus == (int)TaskInStatusEnum.Line_InFinish)
            {
                return GetWMSInboundLocation(task);
            }
            else
            {
                return UpdateWMSTaskStatus(task);
            }
        }
        /// <summary>
        /// 处理机械手任务状态转换
        /// </summary>
        private WebResponseContent ProcessRobotTaskStatus(Dt_Task task)
        {
            if (task.TaskStatus >= (int)TaskRobotStatusEnum.RobotFinish)
                return WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskStatus}】");
            task.TaskStatus = task.TaskStatus.GetNextNotCompletedStatus<TaskRobotStatusEnum>();
            if (task.TaskStatus <= 0)
                return WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskStatus}】");
            return WebResponseContent.Instance.OK();
        }
        /// <summary>
        /// 处理移库任务状态转换
        /// </summary>
        private WebResponseContent ProcessRelocationTaskStatus(Dt_Task task)
        {
            if (task.TaskStatus >= (int)TaskRelocationStatusEnum.RelocationFinish)
                return WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskStatus}】");
            task.TaskStatus = task.TaskStatus.GetNextNotCompletedStatus<TaskRelocationStatusEnum>();
            if (task.TaskStatus <= 0)
                return WebResponseContent.Instance.Error($"该任务状态不可跳转到下一步,任务号:【{task.TaskNum}】,任务状态:【{task.TaskStatus}】");
            // 移库任务开始时,同步WMS任务状态
            if (task.TaskStatus == (int)TaskRelocationStatusEnum.SC_RelocationExecuting)
            {
                return UpdateWMSTaskStatus(task);
            }
            // 移库任务完成时,调用WMS移库完成接口
            if (task.TaskStatus == (int)TaskRelocationStatusEnum.RelocationFinish)
            {
                return NotifyWMSRelocationFinish(task);
            }
            return WebResponseContent.Instance.OK();
        }
        /// <summary>
        /// 通知WMS系统出库完成
        /// </summary>
        private WebResponseContent NotifyWMSOutboundFinish(Dt_Task task)
        {
            var result = _httpClientHelper.Post<WebResponseContent>(
                nameof(ConfigKey.OutboundFinishTaskAsync),
                new StockInfoDTO { PalletCode = task.PalletCode, TaskNum = task.TaskNum }.ToJson());
            if (!result.IsSuccess || !result.Data.Status)
                return WebResponseContent.Instance.Error($"通知WMS系统堆垛机出库完成失败,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】,错误信息:【{result.Data?.Message}】");
            return WebResponseContent.Instance.OK();
        }
        /// <summary>
        /// 获取空托出库任务
        /// </summary>
        private WebResponseContent GetWMSOutboundTrayTask(Dt_Task task)
        {
            var targetAddress = task.TargetAddress;
            var warehouseId = MapWarehouseIdConfigKey(task.TargetAddress);
            string sourceLineNo = ResolveRobotRuleValue(targetAddress, "AddressSourceLineNoMap", task.TargetAddress);
            var result = _httpClientHelper.Post<WebResponseContent>(
                nameof(ConfigKey.GetOutBoundTrayTaskAsync),
                new CreateTaskDto { WarehouseId = warehouseId, TargetAddress = sourceLineNo }.ToJson());
            if (!result.IsSuccess || !result.Data.Status)
                return WebResponseContent.Instance.Error($"获取WMS系统空托盘出库任务失败,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】,错误信息:【{result.Data?.Message}】");
            var wMSTask = JsonConvert.DeserializeObject<WMSTaskDTO>(result.Data.Data.ToString());
            var tasks = new List<WMSTaskDTO>();
            tasks.Add(wMSTask);
            return ReceiveWMSTask(tasks);
        }
        /// <summary>
        /// 获取WMS系统机械手任务
        /// </summary>
        /// <param name="task"></param>
        /// <returns></returns>
        private WebResponseContent GetWMSRobotTask(Dt_Task task)
        {
            string configKey = ResolveRobotTaskConfigKey(task.TargetAddress);
            StockDTO stock = BuildRobotTaskStock(task, configKey);
            var result = _httpClientHelper.Post<WebResponseContent>(configKey, stock.ToJson());
            if (!result.IsSuccess || !result.Data.Status)
                return WebResponseContent.Instance.Error($"获取WMS系统机械手任务失败,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】,目标地址:【{task.TargetAddress}】,接口:【{configKey}】,错误信息:【{result.Data?.Message}】");
            var tasks = JsonConvert.DeserializeObject<List<WMSTaskDTO>>(result.Data.Data?.ToString() ?? string.Empty);
            if (tasks == null || tasks.Count == 0)
                return WebResponseContent.Instance.Error($"获取WMS系统机械手任务失败,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】,错误信息:【WMS未返回有效任务数据】");
            return ReceiveWMSTask(tasks);
        }
        /// <summary>
        /// 根据输送线目标地址解析机械手任务接口。
        /// 规则:
        /// 1. 从配置读取精确地址映射(AddressMap)
        /// 2. 未命中时默认换盘
        /// </summary>
        private string ResolveRobotTaskConfigKey(string? targetAddress)
        {
            string address = (targetAddress ?? string.Empty).Trim();
            if (string.IsNullOrWhiteSpace(address))
                return nameof(ConfigKey.CreateRobotChangePalletTask);
            var section = App.Configuration.GetSection("RobotTaskAddressRules");
            var addressMap = ReadRobotRuleMap(section.GetSection("AddressMap"));
            if (addressMap.TryGetValue(address, out string? exactTaskType))
                return MapRobotTaskTypeToConfigKey(exactTaskType);
            return nameof(ConfigKey.CreateRobotChangePalletTask);
        }
        private int MapWarehouseIdConfigKey(string? targetAddress)
        {
            return targetAddress switch
            {
                "11068" => 1,
                "11001" => 3,
                "11010" => 3,
                "10010" => 1,
                "10030" => 1,
                _ => 1
            };
        }
        /// <summary>
        /// 将配置任务类型转换为接口配置键。
        /// 支持值:Split/Group/Change(大小写不敏感)
        /// </summary>
        private string MapRobotTaskTypeToConfigKey(string? taskType)
        {
            string type = (taskType ?? string.Empty).Trim().ToLowerInvariant();
            return type switch
            {
                "split" => nameof(ConfigKey.CreateRobotSplitPalletTask),
                "group" => nameof(ConfigKey.CreateRobotGroupPalletTask),
                _ => nameof(ConfigKey.CreateRobotChangePalletTask)
            };
        }
        /// <summary>
        /// 根据接口类型构建机械手任务入参。
        /// </summary>
        private StockDTO BuildRobotTaskStock(Dt_Task task, string configKey)
        {
            string targetAddress = task.TargetAddress ?? string.Empty;
            string roadway = ResolveRobotRuleValue(targetAddress, "AddressRoadwayMap", task.Roadway);
            string sourceLineNo = ResolveRobotRuleValue(targetAddress, "AddressSourceLineNoMap", task.SourceAddress);
            var stock = new StockDTO
            {
                Roadway = roadway,
                SourceLineNo = sourceLineNo,
                TargetLineNo = task.TargetAddress,
                SourcePalletNo = task.PalletCode,
                TargetPalletNo = task.PalletCode
            };
            if (configKey == nameof(ConfigKey.CreateRobotSplitPalletTask))
            {
                stock.TargetPalletNo = string.Empty;
            }
            else if (configKey == nameof(ConfigKey.CreateRobotGroupPalletTask))
            {
                stock.SourcePalletNo = string.Empty;
            }
            else if (configKey == nameof(ConfigKey.CreateRobotChangePalletTask))
            {
                IDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceProDTOs.Any(d => d.DeviceChildCode == sourceLineNo));
                if (device != null)
                {
                    CommonConveyorLine conveyorLine = (CommonConveyorLine)device;
                    var barcode = conveyorLine.GetValue<ConveyorLineDBNameNew, string>(ConveyorLineDBNameNew.Barcode, sourceLineNo);
                    stock.SourcePalletNo = string.IsNullOrEmpty(barcode) ? string.Empty : barcode;
                }
            }
            return stock;
        }
        /// <summary>
        /// 根据目标地址按「精确 > 回退值」解析规则值。
        /// </summary>
        private string ResolveRobotRuleValue(string? targetAddress, string addressSectionName, string? fallback)
        {
            string address = (targetAddress ?? string.Empty).Trim();
            string defaultValue = fallback ?? string.Empty;
            if (string.IsNullOrWhiteSpace(address))
                return defaultValue;
            var section = App.Configuration.GetSection("RobotTaskAddressRules");
            var addressMap = ReadRobotRuleMap(section.GetSection(addressSectionName));
            if (addressMap.TryGetValue(address, out string? value))
                return value;
            return defaultValue;
        }
        /// <summary>
        /// 读取规则映射段。
        /// </summary>
        private Dictionary<string, string> ReadRobotRuleMap(IConfigurationSection section)
        {
            return section
                .GetChildren()
                .Where(x => !string.IsNullOrWhiteSpace(x.Key) && !string.IsNullOrWhiteSpace(x.Value))
                .ToDictionary(x => x.Key.Trim(), x => x.Value!.Trim());
        }
        /// <summary>
        /// 从WMS系统获取入库目标地址
        /// </summary>
        private WebResponseContent GetWMSInboundLocation(Dt_Task task)
        {
            var result = _httpClientHelper.Post<WebResponseContent>(
                nameof(ConfigKey.GetTasksLocation),
                new CreateTaskDto { PalletCode = task.PalletCode }.ToJson());
            if (!result.IsSuccess || !result.Data.Status)
                return WebResponseContent.Instance.Error($"调用WMS接口获取任务目标地址失败,任务号:【{task.TaskNum}】,错误信息:【{result.Data?.Message}】");
            var nextAddress = result.Data.Data?.ToString();
            if (string.IsNullOrEmpty(nextAddress))
                return WebResponseContent.Instance.Error($"调用WMS接口获取任务目标地址失败,任务号:【{task.TaskNum}】,错误信息:【未获取到有效的目标地址】");
            task.CurrentAddress = task.NextAddress;
            task.NextAddress = nextAddress;
            task.TargetAddress = nextAddress;
            return WebResponseContent.Instance.OK();
        }
        /// <summary>
        /// 更新WMS系统任务状态
        /// </summary>
        private WebResponseContent UpdateWMSTaskStatus(Dt_Task task)
        {
            var result = _httpClientHelper.Post<WebResponseContent>(
                nameof(ConfigKey.UpdateTaskByStatus),
                new UpdateTaskDto { Id = task.TaskNum, NewStatus = task.TaskStatus }.ToJson());
            if (!result.IsSuccess || !result.Data.Status)
                return WebResponseContent.Instance.Error($"调用WMS接口更新任务状态失败,任务号:【{task.TaskNum}】,错误信息:【{result.Data?.Message}】");
            return WebResponseContent.Instance.OK();
        }
        /// <summary>
        /// 通知WMS系统移库任务完成
        /// </summary>
        private WebResponseContent NotifyWMSRelocationFinish(Dt_Task task)
        {
            var result = _httpClientHelper.Post<WebResponseContent>(
                nameof(ConfigKey.RelocationFinishTask),
                new CreateTaskDto
                {
                    PalletCode = task.PalletCode,
                    SourceAddress = task.CurrentAddress,
                    TargetAddress = task.TargetAddress,
                    Roadway = task.Roadway,
                    TaskType = task.TaskType
                }.ToJson());
            if (!result.IsSuccess || !result.Data.Status)
                return WebResponseContent.Instance.Error($"通知WMS系统移库完成失败,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】,错误信息:【{result.Data?.Message}】");
            return WebResponseContent.Instance.OK();
        }
        /// <summary>
@@ -434,6 +735,9 @@
        {
            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}】");
@@ -455,6 +759,7 @@
            }
            catch (Exception ex)
            {
                Console.WriteLine($"UpdatePosition 更新任务位置失败,任务号:【{taskNum}】,错误信息:【{ex.Message}】");
            }
            return null;
        }
@@ -472,49 +777,57 @@
                Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum);
                if (task == null) return WebResponseContent.Instance.Error($"未找到该任务信息,任务号:【{taskNum}】");
                if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup && task.TaskState == (int)TaskOutStatusEnum.SC_OutExecuting)
                if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup && task.TaskStatus == (int)TaskOutStatusEnum.SC_OutExecuting)
                {
                    List<Dt_Router> routers = _routerService.QueryNextRoutes(task.NextAddress, task.TargetAddress);
                    if (!routers.Any()) return WebResponseContent.Instance.Error($"未找到设备路由信息");
                    int nextStatus = task.TaskState.GetNextNotCompletedStatus<TaskOutStatusEnum>();
                    task.TaskState = nextStatus;
                    int nextStatus = task.TaskStatus.GetNextNotCompletedStatus<TaskOutStatusEnum>();
                    task.TaskStatus = nextStatus;
                    task.CurrentAddress = task.NextAddress;
                    task.NextAddress = routers.FirstOrDefault().ChildPosi;
                    task.ModifyDate = DateTime.Now;
                    task.Modifier = "System";
                    BaseDal.UpdateData(task);
                    _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"堆垛机出库完成");
                    var result = _httpClientHelper.Post<WebResponseContent>("WMS", (new StockInfoDTO() { PalletCode = task.PalletCode, TaskNum = task.TaskNum }).ToJson());
                    if (result.IsSuccess && result.Data.Status)
                    content = NotifyWMSOutboundFinish(task);
                    if (content.Status)
                    {
                        BaseDal.UpdateData(task);
                        _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"堆垛机出库完成");
                        return content.Error($"通知WMS系统堆垛机出库完成成功,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】");
                    }
                    }
                    else
                    {
                        return content.Error($"通知WMS系统堆垛机出库完成失败,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】,错误信息:【{result.Data.Message}】");
                    }
                    //var result = _httpClientHelper.Post<WebResponseContent>(nameof(ConfigKey.OutboundFinishTaskAsync), (new StockInfoDTO() { PalletCode = task.PalletCode, TaskNum = task.TaskNum }).ToJson());
                    //if (result.IsSuccess && result.Data.Status)
                    //{
                    //    BaseDal.UpdateData(task);
                    //    _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"堆垛机出库完成");
                    //    return content.Error($"通知WMS系统堆垛机出库完成成功,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】");
                    //}
                    //else
                    //{
                    //    return content.Error($"通知WMS系统堆垛机出库完成失败,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】,错误信息:【{result.Data.Message}】");
                    //}
                }
                else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup && task.TaskState == (int)TaskInStatusEnum.SC_InExecuting)
                else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup && task.TaskStatus == (int)TaskInStatusEnum.SC_InExecuting)
                {
                    int nextStatus = task.TaskState.GetNextNotCompletedStatus<TaskInStatusEnum>();
                    task.TaskState = nextStatus;
                    int nextStatus = task.TaskStatus.GetNextNotCompletedStatus<TaskInStatusEnum>();
                    task.TaskStatus = nextStatus;
                    task.ModifyDate = DateTime.Now;
                    task.Modifier = "System";
                    BaseDal.UpdateData(task);
                    _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"堆垛机入库完成");
                    var result = _httpClientHelper.Post<WebResponseContent>("WMS", (new CreateTaskDto()
                    var result = _httpClientHelper.Post<WebResponseContent>(nameof(ConfigKey.InboundFinishTaskAsync), (new CreateTaskDto()
                    {
                        PalletCode = task.PalletCode,
                    }).ToJson());
                    if (result.IsSuccess && result.Data.Status)
                    {
                        BaseDal.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动完成);
                        _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"堆垛机入库完成");
                        return content.Error($"通知WMS系统堆垛机入库完成成功,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】");
                    }
                    else
@@ -524,7 +837,25 @@
                }
                else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.RelocationGroup)
                {
                    //todo 调用WMS移库完成
                    if (task.TaskStatus == (int)TaskRelocationStatusEnum.SC_RelocationExecuting)
                    {
                        int nextStatus = task.TaskStatus.GetNextNotCompletedStatus<TaskRelocationStatusEnum>();
                        task.TaskStatus = nextStatus;
                        task.ModifyDate = DateTime.Now;
                        task.Modifier = "System";
                        WebResponseContent result = NotifyWMSRelocationFinish(task);
                        if (result.Status)
                        {
                            BaseDal.DeleteAndMoveIntoHty(task, OperateTypeEnum.自动完成);
                            _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"堆垛机移库完成");
                            return content.Error($"通知WMS系统堆垛机移库完成成功,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】");
                        }
                        else
                        {
                            return content.Error($"通知WMS系统堆垛机移库完成失败,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】,错误信息:【{result.Message}】");
                        }
                    }
                }
                else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OtherGroup)
                {
@@ -554,25 +885,25 @@
            {
                Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum);
                if (task == null) return WebResponseContent.Instance.Error($"未找到该任务信息,任务号:【{taskNum}】");
                if (task.TaskState != (int)TaskInStatusEnum.InPending && task.TaskState != (int)TaskOutStatusEnum.OutPending)
                if (task.TaskStatus != (int)TaskInStatusEnum.InPending && task.TaskStatus != (int)TaskOutStatusEnum.OutPending)
                {
                    return content = WebResponseContent.Instance.Error($"该任务状态不可恢复,任务号:【{taskNum}】,任务状态:【{task.TaskState}】");
                    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.TaskState = taskExecuteDetail.TaskState;
                    task.TaskStatus = taskExecuteDetail.TaskState;
                }
                else
                {
                    if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup)
                    {
                        task.TaskState = (int)TaskOutStatusEnum.OutNew;
                        task.TaskStatus = (int)TaskOutStatusEnum.OutNew;
                    }
                    else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup)
                    {
                        task.TaskState = (int)TaskInStatusEnum.InNew;
                        task.TaskStatus = (int)TaskInStatusEnum.InNew;
                    }
                    //todo
                }
@@ -581,7 +912,7 @@
                BaseDal.UpdateData(task);
                _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"人工恢复挂起任务,恢复挂起时任务状态【{task.TaskState}】");
                _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"人工恢复挂起任务,恢复挂起时任务状态【{task.TaskStatus}】");
                content = WebResponseContent.Instance.OK();
            }
@@ -605,24 +936,24 @@
                Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum);
                if (task == null) return WebResponseContent.Instance.Error($"未找到该任务信息,任务号:【{taskNum}】");
                int oldState = task.TaskState;
                Dt_TaskExecuteDetail taskExecuteDetail = _taskExecuteDetailRepository.QueryFirst(x => x.TaskId == task.TaskId && x.TaskState < task.TaskState && x.TaskState > 0, new Dictionary<string, OrderByType> { { nameof(Dt_TaskExecuteDetail.TaskDetailId), OrderByType.Desc } });
                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.TaskState = taskExecuteDetail.TaskState;
                    task.TaskStatus = taskExecuteDetail.TaskState;
                    task.CurrentAddress = taskExecuteDetail.CurrentAddress;
                    task.NextAddress = taskExecuteDetail.NextAddress;
                }
                else
                {
                    return content = WebResponseContent.Instance.Error($"未找到任务明细信息,该任务状态不可回滚到上一步,任务号:【{taskNum}】,任务状态:【{task.TaskState}】");
                    return content = WebResponseContent.Instance.Error($"未找到任务明细信息,该任务状态不可回滚到上一步,任务号:【{taskNum}】,任务状态:【{task.TaskStatus}】");
                }
                task.ExceptionMessage = string.Empty;
                BaseDal.UpdateData(task);
                _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"人工将任务状态从【{oldState}】回滚到【{task.TaskState}】");
                _taskExecuteDetailService.AddTaskExecuteDetail(task.TaskId, $"人工将任务状态从【{oldState}】回滚到【{task.TaskStatus}】");
                content = WebResponseContent.Instance.OK();
            }
@@ -654,9 +985,9 @@
        public Dt_Task QueryRobotCraneTask(string deviceNo, string currentAddress = "")
        {
            if (string.IsNullOrEmpty(currentAddress))
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && (TaskRobotTypes.Contains(x.TaskType) && x.TaskState <= (int)TaskRobotStatusEnum.RobotExecuting), TaskOrderBy);
                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.TaskState <= (int)TaskRobotStatusEnum.RobotExecuting, TaskOrderBy);
                return BaseDal.QueryFirst(x => x.Roadway == deviceNo && TaskRobotTypes.Contains(x.TaskType) && x.CurrentAddress == currentAddress && x.TaskStatus <= (int)TaskRobotStatusEnum.RobotExecuting, TaskOrderBy);
        }
        /// <summary>
@@ -669,4 +1000,9 @@
            return BaseDal.QueryFirst(x => x.TaskNum == taskNum);
        }
    }
}
    public enum ConveyorLineDBNameNew
    {
        Barcode
    }
}