wanshenmean
3 天以前 ff006f77f6267fc0d2c4ee810d897a85165f5b8f
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/RobotTaskService.cs
@@ -22,10 +22,12 @@
using Masuit.Tools;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Serilog;
using SqlSugar;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using WIDESEA_Core;
using WIDESEAWCS_Common;
using WIDESEAWCS_Common.HttpEnum;
@@ -75,6 +77,7 @@
            _taskExecuteDetailService = taskExecuteDetailService;
            _logger = logger;
        }
        public override WebResponseContent DeleteData(object[] keys)
        {
            List<int> taskKeys = new List<int>();
@@ -85,8 +88,8 @@
            List<Dt_RobotTask> tasks = BaseDal.QueryData(x => taskKeys.Contains(x.RobotTaskId));
            BaseDal.DeleteAndMoveIntoHty(tasks, OperateTypeEnum.人工删除);
            return WebResponseContent.Instance.OK($"成功删除{tasks.Count}条数据");
        }
        public bool DeleteRobotTask(int id)
        {
            Dt_RobotTask task = BaseDal.QueryFirst(x => x.RobotTaskId == id);
@@ -135,7 +138,7 @@
        public Dt_RobotTask? QueryRobotCraneTask(string deviceCode)
        {
            return BaseDal.QueryFirst(x => x.RobotRoadway == deviceCode && x.RobotTaskState != (int)TaskRobotStatusEnum.RobotExecuting, TaskOrderBy);
            return BaseDal.QueryFirst(x => x.RobotRoadway == deviceCode, TaskOrderBy);
        }
        public Dt_RobotTask? QueryRobotCraneExecutingTask(string deviceCode)
@@ -242,10 +245,108 @@
        }
        /// <summary>
        /// 检查源线体是否有托盘号,并根据结果创建机械手任务。
        /// </summary>
        /// <param name="task">出库任务实体</param>
        /// <returns>
        /// 有托盘号时返回 CreateLocalRobotTask 结果;
        /// 无托盘号时返回 GetWMSOutboundTrayTask 结果。
        /// </returns>
        public WebResponseContent CheckSourceLineAndCreateRobotTask(Dt_Task task)
        {
            // 1. 获取源线体编号(复用已有逻辑)
            string configKey = ResolveRobotTaskConfigKey(task.TargetAddress);
            StockDTO stock = BuildRobotTaskStock(task, configKey);
            string sourceLineNo = stock.SourceLineNo;
            if (string.IsNullOrWhiteSpace(sourceLineNo))
            {
                return GetWMSOutboundTrayTaskFromWMS(task);
            }
            // 2. 通过设备通信读取线体托盘号
            string? palletCode = ReadLineBarcode(sourceLineNo);
            if (!string.IsNullOrWhiteSpace(palletCode))
            {
                // 有托盘号,本地创建机械手任务
                return CreateLocalRobotTask(task);
            }
            // 无托盘号,从 WMS 获取任务
            return GetWMSOutboundTrayTaskFromWMS(task);
        }
        /// <summary>
        /// 从WMS获取空托盘出库任务。
        /// </summary>
        /// <param name="task">任务实体。</param>
        /// <returns>调用结果。</returns>
        private WebResponseContent GetWMSOutboundTrayTaskFromWMS(Dt_Task task)
        {
            int warehouseId = MapWarehouseIdConfigKey(task.TargetAddress);
            string sourceLineNo = ResolveRobotRuleValue(task.TargetAddress, "AddressSourceLineNoMap", task.TargetAddress);
            string configKey = nameof(ConfigKey.GetOutBoundTrayTaskAsync);
            string requestParam = new CreateTaskDto { WarehouseId = warehouseId, TargetAddress = sourceLineNo }.ToJson();
            DateTime startTime = DateTime.Now;
            var result = _httpClientHelper.Post<WebResponseContent>(configKey, requestParam);
            if (!result.IsSuccess || !result.Data.Status)
            {
                QuartzLogHelper.LogError(_logger, $"调用WMS接口失败,接口:【{configKey}】,请求参数:【{requestParam}】,错误信息:【{result.Data?.Message}】", "RobotTaskService");
                return WebResponseContent.Instance.Error($"获取WMS系统空托盘出库任务失败,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】,错误信息:【{result.Data?.Message}】");
            }
            QuartzLogHelper.LogInfo(_logger, $"调用WMS接口成功,接口:【{configKey}】,响应数据:【{result.Data?.Data}】,耗时:{(DateTime.Now - startTime).TotalMilliseconds}ms", "RobotTaskService");
            WMSTaskDTO? wMSTask = JsonConvert.DeserializeObject<WMSTaskDTO>(result.Data.Data?.ToString() ?? string.Empty);
            if (wMSTask == null)
                return WebResponseContent.Instance.Error($"获取WMS系统空托盘出库任务失败,任务号:【{task.TaskNum}】,托盘号:【{task.PalletCode}】,错误信息:【WMS未返回有效任务数据】");
            // 构建StockDTO并调用ReceiveWMSTask创建本地入库任务
            var stockDto = new StockDTO
            {
                Roadway = task.Roadway,
                SourceLineNo = sourceLineNo,
                TargetLineNo = task.TargetAddress,
                SourcePalletNo = string.Empty,
                TargetPalletNo = string.Empty
            };
            return ReceiveWMSTask(wMSTask, stockDto);
        }
        /// <summary>
        /// 读取指定线体的托盘号。
        /// </summary>
        /// <param name="sourceLineNo">源线体编号</param>
        /// <returns>托盘号,如有异常返回 null</returns>
        private string? ReadLineBarcode(string sourceLineNo)
        {
            try
            {
                IDevice? device = Storage.Devices.FirstOrDefault(x =>
                    x.DeviceProDTOs.Any(d => d.DeviceChildCode == sourceLineNo));
                if (device == null)
                    return null;
                CommonConveyorLine conveyorLine = (CommonConveyorLine)device;
                return conveyorLine.GetValue<ConveyorLineDBNameNew, string>(
                    ConveyorLineDBNameNew.Barcode, sourceLineNo);
            }
            catch (Exception ex)
            {
                _logger.Error(ex, $"读取线体[{sourceLineNo}]托盘号异常");
                return null;
            }
        }
        /// <summary>
        /// 获取机械手任务总数量。
        /// 组盘任务固定48,换盘和拆盘任务通过托盘号查询WMS库存明细数量。
        /// </summary>
        private int GetRobotTaskTotalNum(int taskType, string? palletCode)
        public int GetRobotTaskTotalNum(int taskType, string? palletCode)
        {
            if (taskType == (int)RobotTaskTypeEnum.GroupPallet)
                return 48;
@@ -255,8 +356,10 @@
            try
            {
                QuartzLogHelper.LogInfo(_logger, $"开始调用WMS接口获取库存明细数量,托盘号:【{palletCode}】", "RobotTaskService");
                string url = $"{BaseAPI.WMSBaseUrl}Stock/GetStockDetailCount?palletCode={Uri.EscapeDataString(palletCode)}";
                var result = _httpClientHelper.Get(url);
                QuartzLogHelper.LogInfo(_logger, $"调用WMS获取库存明细数量接口,请求URL:【{url}】,响应数据:【{result.Content}】,耗时:{result.Duration}ms", "RobotTaskService");
                if (!result.IsSuccess || string.IsNullOrEmpty(result.Content))
                    return 1;
@@ -264,8 +367,8 @@
                if (response == null || !response.Status)
                    return 1;
                var detailCount = response.Data?.GetType().GetProperty("DetailCount")?.GetValue(response.Data);
                return detailCount is int count and > 0 ? count : 1;
                var detailCount = (response.Data as JObject)?["detailCount"]?.Value<int>();
                return detailCount.HasValue && detailCount.Value > 0 ? detailCount.Value : 1;
            }
            catch
            {
@@ -370,8 +473,10 @@
                    CommonConveyorLine conveyorLine = (CommonConveyorLine)device;
                    DeviceProDTO? devicePro = conveyorLine.DeviceProDTOs.FirstOrDefault(x => x.DeviceProParamName == nameof(ConveyorLineDBNameNew.Barcode) && x.DeviceChildCode == sourceLineNo);
                    //conveyorLine.Communicator.Read(devicePro.DeviceProAddress, 20);
                    //ConveyorLineTaskCommandNew command = conveyorLine.ReadCustomer<ConveyorLineTaskCommandNew>(sourceLineNo);  // 测试用
                    var barcode = conveyorLine.GetValue<ConveyorLineDBNameNew, string>(ConveyorLineDBNameNew.Barcode, sourceLineNo);
                    var bytes = conveyorLine.Communicator.Read(devicePro.DeviceProAddress, 20);
                    var barcode = Encoding.Default.GetString(bytes).Trim();
                    stock.SourcePalletNo = string.IsNullOrEmpty(barcode) ? string.Empty : barcode;
                }
            }