wanshenmean
2026-03-18 2ef99428f9be29ec299029782edb97baef88e126
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
@@ -1,14 +1,18 @@
using AutoMapper;
using Microsoft.AspNetCore.Components.Forms;
using Mapster;
using MapsterMapper;
using Microsoft.Extensions.Configuration;
using SqlSugar;
using System.Text.Json;
using WIDESEA_Common.LocationEnum;
using WIDESEA_Common.StockEnum;
using WIDESEA_Common.TaskEnum;
using WIDESEA_Core;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.BaseServices;
using WIDESEA_Core.Core;
using WIDESEA_Core.Helper;
using WIDESEA_DTO;
using WIDESEA_DTO.GradingMachine;
using WIDESEA_DTO.Stock;
using WIDESEA_DTO.Task;
using WIDESEA_IBasicService;
using WIDESEA_IStockService;
@@ -23,6 +27,8 @@
        private readonly IStockInfoService _stockInfoService;
        private readonly ILocationInfoService _locationInfoService;
        private readonly HttpClientHelper _httpClientHelper;
        private readonly IConfiguration _configuration;
        private readonly RoundRobinService _roundRobinService;
        public IRepository<Dt_Task> Repository => BaseDal;
@@ -40,13 +46,19 @@
            IMapper mapper,
            IStockInfoService stockInfoService,
            ILocationInfoService locationInfoService,
            HttpClientHelper httpClientHelper) : base(BaseDal)
            HttpClientHelper httpClientHelper,
            IConfiguration configuration,
            RoundRobinService roundRobinService) : base(BaseDal)
        {
            _mapper = mapper;
            _stockInfoService = stockInfoService;
            _locationInfoService = locationInfoService;
            _httpClientHelper = httpClientHelper;
            _configuration = configuration;
            _roundRobinService = roundRobinService;
        }
        #region WCS逻辑处理
        /// <summary>
        /// 创建任务(组盘入库任务、空托盘回库任务)
@@ -55,27 +67,39 @@
        {
            try
            {
                WebResponseContent content = await GetTasksByPalletCodeAsync(taskDto.PalletCode);
                if (content.Status)
                {
                    return content;
                }
                if (string.IsNullOrWhiteSpace(taskDto.PalletCode) ||
                    string.IsNullOrWhiteSpace(taskDto.SourceAddress) ||
                    string.IsNullOrWhiteSpace(taskDto.TargetAddress) ||
                    string.IsNullOrWhiteSpace(taskDto.Roadway))
                {
                    return WebResponseContent.Instance.Error("Invalid task details.");
                    return WebResponseContent.Instance.Error("无效的任务详情");
                }
                if (taskDto.TaskType != TaskTypeEnum.Inbound && taskDto.TaskType != TaskTypeEnum.InEmpty)
                {
                    return WebResponseContent.Instance.Error("Invalid task details.");
                    return WebResponseContent.Instance.Error("无效的任务详情");
                }
                // 使用 switch 表达式映射任务类型
                int taskInboundType = taskDto.TaskType switch
                {
                    TaskTypeEnum.Inbound => TaskInboundTypeEnum.Inbound.GetHashCode(),
                    TaskTypeEnum.InEmpty => TaskInboundTypeEnum.InEmpty.GetHashCode(),
                    _ => 0 // 理论上不会走到这里,因为已经验证过了
                };
                var task = new Dt_Task
                {
                    TaskNum = 0,
                    TaskNum = await BaseDal.GetTaskNo(),
                    PalletCode = taskDto.PalletCode,
                    PalletType = taskDto.PalletType,
                    Roadway = taskDto.Roadway,
                    TaskType = taskDto.TaskType.GetHashCode(),
                    TaskStatus = TaskStatusEnum.New.GetHashCode(),
                    TaskType = taskInboundType,
                    TaskStatus = TaskInStatusEnum.InNew.GetHashCode(),
                    SourceAddress = taskDto.SourceAddress,
                    TargetAddress = taskDto.TargetAddress,
                    CurrentAddress = taskDto.SourceAddress,
@@ -96,7 +120,6 @@
                return WebResponseContent.Instance.Error($"任务创建失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 根据指定的任务详情异步创建新的出库任务
@@ -128,14 +151,13 @@
                var result = await BaseDal.AddDataAsync(taskList) > 0;
                var wmstaskDto = result ? _mapper.Map<WMSTaskDTO>(taskList) : null;
                return WebResponseContent.Instance.OK(result ? "任务创建成功" : "任务创建失败", wmstaskDto);
                return WebResponseContent.Instance.OK(result ? "任务创建成功" : "任务创建失败", wmstaskDto ?? new object());
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"任务创建失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 获取可入库货位
@@ -151,10 +173,10 @@
                if (locationInfo == null) return WebResponseContent.Instance.Error("未找到对应的货位");
                locationInfo.LocationStatus = LocationStatusEnum.FreeLock.GetHashCode();
                task.CurrentAddress = taskDto.SourceAddress;
                task.CurrentAddress = task.SourceAddress;
                task.NextAddress = locationInfo.LocationCode;
                task.TargetAddress = taskDto.TargetAddress;
                task.TaskStatus = TaskStatusEnum.Line_Finish.GetHashCode();
                task.TargetAddress = locationInfo.LocationCode;
                task.TaskStatus = TaskInStatusEnum.Line_InFinish.GetHashCode();
                var updateResult = await BaseDal.UpdateDataAsync(task);
                var locationResult = await _locationInfoService.UpdateLocationInfoAsync(locationInfo);
@@ -191,6 +213,7 @@
                    var r when r.Contains("CW") => DateTime.Now.AddHours(1),
                    _ => DateTime.Now
                };
                stockInfo.StockStatus = StockStatusEmun.入库完成.GetHashCode();
                location.LocationStatus = LocationStatusEnum.InStock.GetHashCode();
@@ -198,14 +221,7 @@
                var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo);
                if (!updateLocationResult || !updateStockResult)
                    return WebResponseContent.Instance.Error("任务完成失败");
                var deleteTaskResult = await BaseDal.DeleteDataAsync(task);
                if (!deleteTaskResult) return WebResponseContent.Instance.Error("任务完成失败");
                var historyTask = _mapper.Map<Dt_Task_Hty>(task);
                historyTask.InsertTime = DateTime.Now;
                return WebResponseContent.Instance.OK("任务完成");
                return await CompleteTaskAsync(task);
            }
            catch (Exception ex)
            {
@@ -226,8 +242,9 @@
                var location = await _locationInfoService.GetLocationInfo(task.Roadway, task.SourceAddress);
                if (location == null) return WebResponseContent.Instance.Error("未找到对应的货位");
                var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode); stockInfo.LocationCode = location.LocationCode;
                stockInfo.LocationId = location.Id;
                var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode);
                stockInfo.LocationId = 0;
                stockInfo.LocationCode = null;
                stockInfo.OutboundDate = DateTime.Now;
                location.LocationStatus = LocationStatusEnum.Free.GetHashCode();
@@ -236,14 +253,7 @@
                var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo);
                if (!updateLocationResult || !updateStockResult)
                    return WebResponseContent.Instance.Error("任务完成失败");
                var deleteTaskResult = await BaseDal.DeleteDataAsync(task);
                if (!deleteTaskResult) return WebResponseContent.Instance.Error("任务完成失败");
                var historyTask = _mapper.Map<Dt_Task_Hty>(task);
                historyTask.InsertTime = DateTime.Now;
                return WebResponseContent.Instance.OK("任务完成");
                return await CompleteTaskAsync(task);
            }
            catch (Exception ex)
            {
@@ -251,12 +261,487 @@
            }
        }
        /// <summary>
        /// 移库任务完成:修改库存位置与状态,修改源/目标货位状态,删除任务数据
        /// </summary>
        public async Task<WebResponseContent> RelocationFinishTaskAsync(CreateTaskDto taskDto)
        {
            try
            {
                var task = await BaseDal.QueryFirstAsync(s =>
                    s.PalletCode == taskDto.PalletCode &&
                    s.TaskType == TaskRelocationTypeEnum.Relocation.GetHashCode());
                if (task == null) return WebResponseContent.Instance.Error("未找到对应的移库任务");
                var sourceLocation = await _locationInfoService.GetLocationInfo(task.Roadway, task.SourceAddress);
                if (sourceLocation == null) return WebResponseContent.Instance.Error("未找到移库源货位");
                var targetLocation = await _locationInfoService.GetLocationInfo(task.Roadway, task.TargetAddress);
                if (targetLocation == null) return WebResponseContent.Instance.Error("未找到移库目标货位");
                var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode);
                if (stockInfo == null) return WebResponseContent.Instance.Error("未找到对应库存信息");
                stockInfo.LocationCode = targetLocation.LocationCode;
                stockInfo.LocationId = targetLocation.Id;
                stockInfo.StockStatus = StockStatusEmun.入库完成.GetHashCode();
                sourceLocation.LocationStatus = LocationStatusEnum.Free.GetHashCode();
                targetLocation.LocationStatus = LocationStatusEnum.InStock.GetHashCode();
                var updateSourceResult = await _locationInfoService.UpdateLocationInfoAsync(sourceLocation);
                var updateTargetResult = await _locationInfoService.UpdateLocationInfoAsync(targetLocation);
                var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo);
                if (!updateSourceResult || !updateTargetResult || !updateStockResult)
                    return WebResponseContent.Instance.Error("移库任务完成失败");
                return await CompleteTaskAsync(task);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"完成任务失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 创建空托盘入库任务
        /// </summary>
        /// <param name="taskDto"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> CreateTaskInboundTrayAsync(CreateTaskDto taskDto)
        {
            try
            {
                WebResponseContent content = await GetTasksByPalletCodeAsync(taskDto.PalletCode);
                if (content.Status)
                {
                    return content;
                }
                //var tasks = await BaseDal.QueryAsync(s => s.PalletCode == palletCode);
                //if (tasks == null || !tasks.Any())
                //    return WebResponseContent.Instance.Error("未找到对应的任务");
                //var taskDtos = _mapper.Map<List<WMSTaskDTO>>(tasks);
                return WebResponseContent.Instance.OK("查询成功"/*, taskDtos*/);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"查询任务失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 创建空托盘出库任务
        /// </summary>
        /// <param name="taskDto"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> GetOutBoundTrayTaskAsync(CreateTaskDto taskDto)
        {
            try
            {
                var stockInfo = await _stockInfoService.Repository.QueryDataNavFirstAsync(x => x.LocationDetails.WarehouseId == taskDto.WarehouseId && x.LocationDetails.LocationStatus == LocationStatusEnum.InStock.GetHashCode() && x.StockStatus == StockStatusEmun.空托盘库存.GetHashCode());
                if (stockInfo == null)
                    return WebResponseContent.Instance.Error("未找到对应的库存信息");
                var task = new Dt_Task()
                {
                    WarehouseId = stockInfo.LocationDetails.WarehouseId,
                    PalletCode = stockInfo.PalletCode,
                    PalletType = stockInfo.PalletType,
                    SourceAddress = stockInfo.LocationCode,
                    CurrentAddress = stockInfo.LocationCode,
                    NextAddress = taskDto.TargetAddress,
                    TargetAddress = taskDto.TargetAddress,
                    Roadway = stockInfo.LocationDetails.RoadwayNo,
                    TaskType = TaskOutboundTypeEnum.OutEmpty.GetHashCode(),
                    TaskStatus = TaskStatusEnum.New.GetHashCode(),
                    Grade = 1,
                    TaskNum = await BaseDal.GetTaskNo(),
                    Creater = "system",
                };
                var taskDtos = task.Adapt<WMSTaskDTO>();
                BaseDal.AddData(task);
                return WebResponseContent.Instance.OK("查询成功", taskDtos);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"查询任务失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 修改任务状态(根据任务ID修改为指定状态)
        /// </summary>
        /// <param name="taskId"></param>
        /// <param name="newStatus"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> UpdateTaskByStatusAsync(int taskId, int newStatus)
        {
            try
            {
                var tasks = await BaseDal.QueryFirstAsync(s => s.TaskNum == taskId);
                if (tasks == null)
                    return WebResponseContent.Instance.Error("未找到对应的任务");
                tasks.TaskStatus = newStatus;
                await BaseDal.UpdateDataAsync(tasks);
                return WebResponseContent.Instance.OK("修改成功", tasks);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"修改失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 查找托盘是否有任务
        /// </summary>
        /// <param name="palletCode"></param>
        /// <returns></returns>
        private async Task<WebResponseContent> GetTasksByPalletCodeAsync(string palletCode)
        {
            try
            {
                var tasks = await BaseDal.QueryFirstAsync(s => s.PalletCode == palletCode);
                if (tasks == null)
                    return WebResponseContent.Instance.Error("未找到对应的任务");
                var taskDtos = _mapper.Map<List<WMSTaskDTO>>(tasks);
                return WebResponseContent.Instance.OK("查询成功", taskDtos);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"查询任务失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 完成任务后统一处理(删除任务数据)
        /// </summary>
        private async Task<WebResponseContent> CompleteTaskAsync(Dt_Task task)
        {
            var deleteTaskResult = await BaseDal.DeleteDataAsync(task);
            if (!deleteTaskResult) return WebResponseContent.Instance.Error("任务完成失败");
            // 保留历史对象构建逻辑,后续可接入历史表落库
            var historyTask = _mapper.Map<Dt_Task_Hty>(task);
            historyTask.InsertTime = DateTime.Now;
            return WebResponseContent.Instance.OK("任务完成");
        }
        /// <summary>
        /// 根据巷道确定目标地址(支持多出库口轮询)
        /// </summary>
        private string DetermineTargetAddress(string roadway, Dictionary<string, List<string>> addressMap)
        {
            if (string.IsNullOrWhiteSpace(roadway))
                return "10080";
            // 查找匹配的巷道前缀
            string matchedPrefix = null;
            foreach (var kvp in addressMap)
            {
                if (roadway.Contains(kvp.Key))
                {
                    matchedPrefix = kvp.Key;
                    break;
                }
            }
            if (matchedPrefix == null)
                return "10080";
            var addresses = addressMap[matchedPrefix];
            if (addresses == null || addresses.Count == 0)
                return "10080";
            // 单个地址,直接返回
            if (addresses.Count == 1)
                return addresses[0];
            // 多个地址,使用轮询服务
            return _roundRobinService.GetNextAddress(matchedPrefix, addresses);
        }
        /// <summary>
        /// 自动创建出库任务 - 查询到期库存并创建任务
        /// </summary>
        public async Task<WebResponseContent> CreateAutoOutboundTasksAsync()
        {
            try
            {
                // 1. 查询到期库存
                var expiredStocks = await _stockInfoService.Repository
                    .QueryDataNavAsync(s => s.OutboundDate <= DateTime.Now
                        && s.StockStatus == StockStatusEmun.入库完成.GetHashCode());
                if (expiredStocks == null || !expiredStocks.Any())
                {
                    return WebResponseContent.Instance.OK("无到期库存需要处理");
                }
                // 过滤有位置且位置有库存的记录
                expiredStocks = expiredStocks
                    .Where(s => s.LocationDetails != null
                        && s.LocationDetails.LocationStatus == LocationStatusEnum.InStock.GetHashCode())
                    .ToList();
                if (!expiredStocks.Any())
                {
                    return WebResponseContent.Instance.OK("无符合条件的到期库存");
                }
                // 2. 检查已存在的任务
                var palletCodes = expiredStocks.Select(s => s.PalletCode).ToList();
                var existingTasks = await Repository.QueryDataAsync(t =>
                    palletCodes.Contains(t.PalletCode)
                    && (t.TaskStatus == TaskStatusEnum.New.GetHashCode()
                        || t.TaskStatus == TaskStatusEnum.SC_Executing.GetHashCode()
                        || t.TaskStatus == TaskInStatusEnum.InNew.GetHashCode()));
                var processedPallets = existingTasks.Select(t => t.PalletCode).ToHashSet();
                // 3. 筛选需要处理的库存
                var stocksToProcess = expiredStocks
                    .Where(s => !processedPallets.Contains(s.PalletCode))
                    .ToList();
                if (!stocksToProcess.Any())
                {
                    return WebResponseContent.Instance.OK("所有到期库存已存在任务");
                }
                // 4. 获取配置的目标地址映射
                var targetAddressMap = _configuration.GetSection("AutoOutboundTask:TargetAddresses")
                    .Get<Dictionary<string, List<string>>>()
                    ?? new Dictionary<string, List<string>>();
                // 5. 批量创建任务
                var taskList = new List<Dt_Task>();
                foreach (var stock in stocksToProcess)
                {
                    // 根据巷道确定目标地址
                    var targetAddress = DetermineTargetAddress(
                        stock.LocationDetails?.RoadwayNo ?? "",
                        targetAddressMap);
                    var task = new Dt_Task
                    {
                        WarehouseId = stock.WarehouseId,
                        PalletCode = stock.PalletCode,
                        PalletType = stock.PalletType,
                        SourceAddress = stock.LocationCode,
                        CurrentAddress = stock.LocationCode,
                        NextAddress = targetAddress,
                        TargetAddress = targetAddress,
                        Roadway = stock.LocationDetails?.RoadwayNo ?? "",
                        TaskType = TaskTypeEnum.Outbound.GetHashCode(),
                        TaskStatus = TaskStatusEnum.New.GetHashCode(),
                        Grade = 1,
                        TaskNum = await BaseDal.GetTaskNo(),
                        Creater = "system_auto"
                    };
                    taskList.Add(task);
                }
                var addResult = await BaseDal.AddDataAsync(taskList) > 0;
                if (!addResult)
                {
                    return WebResponseContent.Instance.Error($"批量创建任务失败,共 {taskList.Count} 个任务");
                }
                // 任务创建成功后,同步锁定库存和货位状态,避免重复分配
                var stocksToUpdate = stocksToProcess
                    .Select(s =>
                    {
                        s.StockStatus = StockStatusEmun.出库锁定.GetHashCode();
                        return s;
                    })
                    .ToList();
                var updateStockResult = await _stockInfoService.Repository.UpdateDataAsync(stocksToUpdate);
                if (!updateStockResult)
                {
                    return WebResponseContent.Instance.Error($"任务创建成功,但库存状态更新失败,共 {stocksToUpdate.Count} 条");
                }
                var locationsToUpdate = stocksToProcess
                    .Where(s => s.LocationDetails != null)
                    .GroupBy(s => s.LocationDetails.Id)
                    .Select(g =>
                    {
                        var location = g.First().LocationDetails;
                        location.LocationStatus = LocationStatusEnum.InStockLock.GetHashCode();
                        return location;
                    })
                    .ToList();
                if (locationsToUpdate.Any())
                {
                    var updateLocationResult = await _locationInfoService.Repository.UpdateDataAsync(locationsToUpdate);
                    if (!updateLocationResult)
                    {
                        return WebResponseContent.Instance.Error($"任务创建成功,但货位状态更新失败,共 {locationsToUpdate.Count} 条");
                    }
                }
                // 6. 通知 WCS(异步,不影响主流程)
                _ = Task.Run(() =>
                {
                    try
                    {
                        var wmstaskDtos = _mapper.Map<List<WMSTaskDTO>>(taskList);
                        _httpClientHelper.Post<WebResponseContent>(
                            "http://localhost:9292/api/Task/ReceiveTask",
                            wmstaskDtos.ToJson());
                    }
                    catch (Exception ex)
                    {
                        // WCS 通知失败不影响任务创建,记录日志即可
                        Console.WriteLine($"WCS 批量通知失败,任务数量: {taskList.Count}, 错误: {ex.Message}");
                    }
                });
                return WebResponseContent.Instance.OK($"成功创建 {taskList.Count} 个出库任务", taskList.Count);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"自动创建出库任务失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 创建机械手组盘任务
        /// </summary>
        public async Task<WebResponseContent> CreateRobotGroupPalletTaskAsync(StockDTO stock)
        {
            return await CreateRobotPalletTaskAsync(
                stock,
                "组盘",
                RobotTaskTypeEnum.GroupPallet,
                s => string.IsNullOrWhiteSpace(s.TargetPalletNo) ? s.SourcePalletNo : s.TargetPalletNo,
                requireStockWithoutLocation: false);
        }
        /// <summary>
        /// 创建机械手换盘任务
        /// </summary>
        public async Task<WebResponseContent> CreateRobotChangePalletTaskAsync(StockDTO stock)
        {
            return await CreateRobotPalletTaskAsync(
                stock,
                "换盘",
                RobotTaskTypeEnum.ChangePallet,
                s => s.SourcePalletNo,
                requireStockWithoutLocation: true,
                stockPalletCodeSelector: s => s.SourcePalletNo);
        }
        /// <summary>
        /// 创建机械手拆盘任务
        /// </summary>
        public async Task<WebResponseContent> CreateRobotSplitPalletTaskAsync(StockDTO stock)
        {
            return await CreateRobotPalletTaskAsync(
                stock,
                "拆盘",
                RobotTaskTypeEnum.SplitPallet,
                s => s.SourcePalletNo,
                requireStockWithoutLocation: true,
                stockPalletCodeSelector: s => s.SourcePalletNo);
        }
        private async Task<WebResponseContent> CreateRobotPalletTaskAsync(
            StockDTO stock,
            string taskName,
            RobotTaskTypeEnum taskType,
            Func<StockDTO, string?> palletCodeSelector,
            bool requireStockWithoutLocation,
            Func<StockDTO, string?>? stockPalletCodeSelector = null)
        {
            try
            {
                if (stock == null)
                    return WebResponseContent.Instance.Error("任务参数不能为空");
                var palletCode = palletCodeSelector(stock)?.Trim();
                if (string.IsNullOrWhiteSpace(palletCode))
                    return WebResponseContent.Instance.Error("托盘号不能为空");
                var sourceLineNo = stock.SourceLineNo?.Trim();
                var targetLineNo = stock.TargetLineNo?.Trim();
                if (string.IsNullOrWhiteSpace(sourceLineNo) || string.IsNullOrWhiteSpace(targetLineNo))
                    return WebResponseContent.Instance.Error("来源线体编号和目标线体编号不能为空");
                var existingTask = await BaseDal.QueryFirstAsync(t =>
                    t.PalletCode == palletCode &&
                    (t.TaskStatus == TaskRobotStatusEnum.RobotNew.GetHashCode()
                     || t.TaskStatus == TaskRobotStatusEnum.RobotExecuting.GetHashCode()
                     || t.TaskStatus == TaskRobotStatusEnum.RobotPickFinish.GetHashCode()
                     || t.TaskStatus == TaskRobotStatusEnum.RobotPutFinish.GetHashCode()
                     || t.TaskStatus == TaskRobotStatusEnum.RobotPending.GetHashCode()));
                if (existingTask != null)
                    return WebResponseContent.Instance.Error($"托盘[{palletCode}]已存在未完成任务");
                Dt_StockInfo? stockInfo = null;
                if (requireStockWithoutLocation)
                {
                    var stockPalletCode = (stockPalletCodeSelector ?? palletCodeSelector).Invoke(stock)?.Trim();
                    if (string.IsNullOrWhiteSpace(stockPalletCode))
                        return WebResponseContent.Instance.Error("源托盘号不能为空");
                    stockInfo = await _stockInfoService.GetStockInfoAsync(stockPalletCode);
                    if (stockInfo == null)
                        return WebResponseContent.Instance.Error($"托盘[{stockPalletCode}]库存不存在");
                    if (stockInfo.LocationId > 0 || !string.IsNullOrWhiteSpace(stockInfo.LocationCode))
                        return WebResponseContent.Instance.Error($"托盘[{stockPalletCode}]库存已绑定货位,不能创建机械手{taskName}任务");
                }
                var task = new Dt_Task
                {
                    TaskNum = await BaseDal.GetTaskNo(),
                    PalletCode = palletCode,
                    PalletType = stockInfo?.PalletType ?? 0,
                    Roadway = stock.Roadway,
                    TaskType = taskType.GetHashCode(),
                    TaskStatus = TaskRobotStatusEnum.RobotNew.GetHashCode(),
                    SourceAddress = sourceLineNo,
                    TargetAddress = targetLineNo,
                    CurrentAddress = sourceLineNo,
                    NextAddress = targetLineNo,
                    WarehouseId = stockInfo?.WarehouseId ?? 1,
                    Grade = 1,
                    Remark = $"机械手{taskName}",
                    Creater = "system"
                };
                var result = await Repository.AddDataAsync(task) > 0;
                if (!result)
                    return WebResponseContent.Instance.Error($"机械手{taskName}任务创建失败");
                var wmstaskDto = _mapper.Map<WMSTaskDTO>(task);
                return WebResponseContent.Instance.OK($"机械手{taskName}任务创建成功", wmstaskDto);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"机械手{taskName}任务创建失败: {ex.Message}");
            }
        }
        #endregion WCS逻辑处理
        #region 分容柜接口
        /// <summary>
        /// 堆垛机取放货完成后物流通知化成分容柜完成信号
        /// </summary>
        public async Task<WebResponseContent> InOrOutCompletedAsync(InputDto input)
        public async Task<WebResponseContent> InOrOutCompletedAsync(GradingMachineInputDto input)
        {
            WebResponseContent content = new WebResponseContent();
            if (string.IsNullOrWhiteSpace(input.PalletCode) || string.IsNullOrWhiteSpace(input.LocationCode))
@@ -271,7 +756,7 @@
                {
                    var location = await _locationInfoService.GetLocationInfoAsync(input.LocationCode);
                    OutPutDto outPutDto = new OutPutDto()
                    OutputDto outPutDto = new OutputDto()
                    {
                        LocationCode = input.LocationCode,
                        PalletCode = input.PalletCode,
@@ -282,7 +767,7 @@
                }
                else
                {
                    OutPutDto outPutDto = new OutPutDto()
                    OutputDto outPutDto = new OutputDto()
                    {
                        LocationCode = input.LocationCode,
                        PalletCode = input.PalletCode,
@@ -305,7 +790,7 @@
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> SendLocationStatusAsync(InputDto input)
        public async Task<WebResponseContent> SendLocationStatusAsync(GradingMachineInputDto input)
        {
            WebResponseContent content = new WebResponseContent();
            if (string.IsNullOrWhiteSpace(input.LocationCode))
@@ -342,7 +827,7 @@
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> RequestOutboundAsync(InputDto input)
        public async Task<WebResponseContent> RequestOutboundAsync(GradingMachineInputDto input)
        {
            WebResponseContent content = new WebResponseContent();
            if (string.IsNullOrWhiteSpace(input.LocationCode) || string.IsNullOrWhiteSpace(input.PalletCode))
@@ -378,7 +863,6 @@
                    var result = await BaseDal.AddDataAsync(taskList) > 0;
                    var wmstaskDto = result ? _mapper.Map<WMSTaskDTO>(taskList) : null;
                    var httpResponse = _httpClientHelper.Post<WebResponseContent>("http://logistics-service/api/logistics/notifyoutbound", JsonSerializer.Serialize(wmstaskDto)).Data;
                    if (result && httpResponse != null)
                    {
@@ -402,7 +886,7 @@
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> GetPalletCodeCellAsync(InputDto input)
        public async Task<WebResponseContent> GetPalletCodeCellAsync(GradingMachineInputDto input)
        {
            WebResponseContent content = new WebResponseContent();
            if (string.IsNullOrWhiteSpace(input.PalletCode) || string.IsNullOrWhiteSpace(input.LocationCode))
@@ -416,7 +900,7 @@
                {
                    return content.Error("未找到对应的托盘");
                }
                var outPutDtos = stockInfo.Details.Select(x => new OutPutDto()
                var outPutDtos = stockInfo.Details.Select(x => new OutputDto()
                {
                    LocationCode = input.LocationCode,
                    PalletCode = input.PalletCode,
@@ -433,6 +917,6 @@
            }
        }
        #endregion
        #endregion 分容柜接口
    }
}