1
z8018
2025-06-10 e46aa927d231af83724683c7286d9db503e24cf7
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs
@@ -15,69 +15,300 @@
 *----------------------------------------------------------------*/
#endregion << ç‰ˆ æœ¬ æ³¨ é‡Š >>
using AutoMapper;
using Magicodes.ExporterAndImporter.Core;
using Microsoft.AspNetCore.Mvc.RazorPages;
using NetTaste;
using Newtonsoft.Json;
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Metadata;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using WIDESEA_Common.Log;
using AutoMapper;
using HslCommunication;
using HslCommunication.WebSocket;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
using SqlSugar;
using WIDESEAWCS_BasicInfoRepository;
using WIDESEAWCS_BasicInfoService;
using WIDESEAWCS_Common;
using WIDESEAWCS_Common.TaskEnum;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_Core.Enums;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.Utilities;
using WIDESEAWCS_DTO.Enum;
using WIDESEAWCS_DTO.BasicInfo;
using WIDESEAWCS_DTO.PlacedBlockDTO;
using WIDESEAWCS_DTO.TaskInfo;
using WIDESEAWCS_IBasicInfoRepository;
using WIDESEAWCS_IBasicInfoService;
using WIDESEAWCS_ITaskInfoRepository;
using WIDESEAWCS_ITaskInfoService;
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob.Models;
using WIDESEAWCS_QuartzJob.Repository;
using WIDESEAWCS_QuartzJob.Service;
using static Dm.net.buffer.ByteArrayBuffer;
namespace WIDESEAWCS_TaskInfoService
{
    /// <summary>
    /// ä»»åŠ¡æœåŠ¡ç±»ï¼Œæä¾›ä»»åŠ¡ç›¸å…³çš„ä¸šåŠ¡é€»è¾‘æ“ä½œ
    /// </summary>
    /// <remarks>
    /// ä¸»è¦åŠŸèƒ½åŒ…æ‹¬ï¼š <br/>
    /// 1. æŸ¥è¯¢é—¨æž¶è®¾å¤‡æœªæ‰§è¡Œä»»åŠ¡ <br/>
    /// 2. æ‰§è¡Œè®¢å•块放置测试 <br/>
    /// 3. åˆ›å»ºå’Œç®¡ç†ä»»åŠ¡ <br/>
    /// 4. ç”Ÿæˆå’Œé‡æ–°ç”Ÿæˆä»»åŠ¡ <br/>
    /// 5. å¤„理异常任务 <br/>
    /// 6. ä»»åŠ¡å®Œæˆå¤„ç† <br/>
    /// ä¾èµ–仓储层进行数据访问,通过工作单元管理事务 <br/>
    /// ä½¿ç”¨WebSocket进行实时通知,并包含完整的异常处理机制
    /// </remarks>
    public class TaskService : ServiceBase<Dt_Task, ITaskRepository>, ITaskService
    {
        private readonly IMapper _mapper;
        private readonly IContainerRepository _containerRepository;
        private readonly IContainerItemRepository _containerItemRepository;
        private readonly IDeviceInfoRepository _deviceInfoRepository;
        /// <summary>
        /// å·¥ä½œå•元管理接口实例,用于管理数据库事务和工作单元
        /// </summary>
        private readonly IUnitOfWorkManage _unitOfWorkManage;
        public TaskService(ITaskRepository BaseDal, IMapper mapper, IContainerRepository containerRepository, IContainerItemRepository containerItemRepository, IDeviceInfoRepository deviceInfoRepository) : base(BaseDal)
        /// <summary>
        /// ç”¨äºŽå¯¹è±¡æ˜ å°„的映射器实例
        /// </summary>
        private readonly IMapper _mapper;
        /// <summary>
        /// å®¹å™¨ä»“储接口实例,用于容器相关数据操作
        /// </summary>
        private readonly IContainerRepository _containerRepository;
        /// <summary>
        /// å®¹å™¨ç‰©å“ä»“储接口实例(只读)
        /// </summary>
        private readonly IContainerItemRepository _containerItemRepository;
        /// <summary>
        /// WebSocket服务器实例,用于处理WebSocket连接
        /// </summary>
        private readonly WebSocketServer _webSocketServer;
        /// <summary>
        /// è®¢å•详情仓储接口实例(只读)
        /// </summary>
        private readonly IOrderDetailsRepository _orderDetailsRepository;
        /// <summary>
        /// å®¹å™¨æœåŠ¡æŽ¥å£å®žä¾‹ï¼Œç”¨äºŽç®¡ç†ä¾èµ–æ³¨å…¥å®¹å™¨ç›¸å…³æ“ä½œ
        /// </summary>
        private readonly IContainerService _containerService;
        /// <summary>
        /// è®¢å•明细服务接口
        /// </summary>
        private readonly IOrderDetailsService _orderDetailsService;
        /// <summary>
        /// è®¢å•行仓储接口实例,用于操作订单行数据
        /// </summary>
        private readonly IOrderrowsRepository _orderrowsRepository;
        /// <summary>
        /// è®¢å•容器仓储接口实例,用于操作订单容器相关数据
        /// </summary>
        private readonly IOrderContainerRepository _orderContainerRepository;
        public TaskService(ITaskRepository BaseDal, IUnitOfWorkManage unitOfWorkManage, IMapper mapper, IContainerRepository containerRepository, IContainerItemRepository containerItemRepository, WebSocketServer webSocketServer, IOrderDetailsRepository orderDetailsRepository, IContainerService containerService, IOrderDetailsService orderDetailsService, IOrderrowsRepository orderrowsRepository, IOrderContainerRepository orderContainerRepository) : base(BaseDal)
        {
            _unitOfWorkManage = unitOfWorkManage;
            _mapper = mapper;
            _containerRepository = containerRepository;
            _containerItemRepository = containerItemRepository;
            _deviceInfoRepository = deviceInfoRepository;
            _webSocketServer = webSocketServer;
            _orderDetailsRepository = orderDetailsRepository;
            _containerService = containerService;
            _orderDetailsService = orderDetailsService;
            _orderrowsRepository = orderrowsRepository;
            _orderContainerRepository = orderContainerRepository;
        }
        /// <summary>
        /// æŸ¥è¯¢æŒ‡å®šé—¨æž¶è®¾å¤‡æœªæ‰§è¡Œçš„任务
        /// </summary>
        /// <param name="gantryDeviceNo">门架设备编号</param>
        /// <returns>未执行的任务数据,若不存在则返回null</returns>
        public Dt_Task? QueryAGantryUnExecuteTask(string gantryDeviceNo)
        {
            return BaseDal.QueryFirst(x => x.TaskState == (int)TaskStatusEnum.Gantry_New && x.DeviceCode == gantryDeviceNo);
        }
        /// <summary>
        /// æ‰§è¡Œè®¢å•块放置测试,根据订单行ID获取订单明细并计算放置位置
        /// </summary>
        /// <param name="orderRowId">订单行ID</param>
        /// <returns>包含放置块信息的Web响应内容。成功时返回放置块列表,失败时返回错误信息</returns>
        /// <remarks>
        /// 1. é€šè¿‡è®¢å•行ID查询订单明细数据 <br/>
        /// 2. å¯¹æ¯ä¸ªæœ‰æ•ˆè®¢å•明细计算合适的放置位置 <br/>
        /// 3. åˆ›å»ºå®¹å™¨é¡¹å’Œä»»åŠ¡è®°å½• <br/>
        /// 4. é€šè¿‡WebSocket发布放置位置信息 <br/>
        /// 5. è¿”回所有成功放置的块信息
        /// </remarks>
        public WebResponseContent PlaceBlockTest(int orderRowId)
        {
            try
            {
                List<OrderDetails> orderDetails = _orderDetailsRepository.QueryData(x => x.Orderrowsid == orderRowId);
                if (orderDetails == null || orderDetails.Count == 0)
                {
                    return WebResponseContent.Instance.Error("未找到订单明细信息");
                }
                List<PlacedBlock> placedBlocks = new List<PlacedBlock>();
                string putPosition = "";
                for (int i = 0; i < orderDetails.Count; i++)
                {
                    try
                    {
                        lock (placedBlocks)
                        {
                            int length = Convert.ToInt32(orderDetails[i].Orderdetails_length);
                            int width = Convert.ToInt32(orderDetails[i].Orderdetails_width);
                            int height = Convert.ToInt32(orderDetails[i].Orderdetails_thickness);
                            OrderInfo orderInfo = _orderDetailsService.GetOrderInfoByBarcode(orderDetails[i].Orderdetails_outid);
                            var (flag, taskPosition, message) = _containerService.GetPosition(orderInfo.OrderHeadId, orderInfo.OrderNo, length, width, height);
                            if (flag && taskPosition != null)
                            {
                                if (string.IsNullOrEmpty(putPosition))
                                {
                                    putPosition = taskPosition.PutPosition;
                                }
                                if (putPosition != taskPosition.PutPosition)
                                {
                                    continue;
                                }
                                Dt_OrderContainer orderContainer = _orderContainerRepository.QueryFirst(x => x.OrderNo == orderInfo.OrderNo && x.ContainerCode == taskPosition.PutPosition);
                                Dt_Container putContainer = _containerRepository.QueryFirst(x => x.ContainerCode == taskPosition.PutPosition);
                                if (putContainer == null)
                                {
                                    //todo
                                    throw new Exception("未找到放货位置");
                                }
                                bool isAdd = false;
                                if (orderContainer == null)
                                {
                                    orderContainer = new Dt_OrderContainer()
                                    {
                                        OrderId = orderInfo.OrderHeadId,
                                        ContainerCode = putContainer.ContainerCode,
                                        ContainerId = putContainer.Id,
                                        OrderNo = orderInfo.OrderNo,
                                    };
                                    int containerLength = putContainer.ContainerLength;
                                    int containerWidth = putContainer.ContainerWidth;
                                    int maxValue = Math.Max(length, width);
                                    int minValue = Math.Min(length, width);
                                    if (minValue > putContainer.ContainerWidth)
                                    {
                                        containerLength = maxValue;
                                        containerWidth = minValue;
                                    }
                                    orderContainer.MaxLength = containerLength;
                                    orderContainer.MaxWidth = containerWidth;
                                    isAdd = true;
                                }
                                if (taskPosition != null)
                                {
                                    Dt_ContainerItem dt_ContainerItem = new Dt_ContainerItem()
                                    {
                                        ContainerId = putContainer.Id,
                                        ItemCode = orderInfo.Barcode,
                                        ItemLength = length,
                                        ItemWidth = width,
                                        ItemHeight = height,
                                        ItemPositionX = taskPosition.PositionX,
                                        ItemPositionY = taskPosition.PositionY,
                                        ItemPositionZ = taskPosition.PositionZ,
                                        ItemRelaPositionX = taskPosition.PutPositionX,
                                        ItemRelaPositionY = taskPosition.PutPositionY,
                                        ItemRelaPositionZ = taskPosition.PutPositionZ,
                                        ItemStatus = (int)ItemStatusEnum.Assigned,
                                        ItemName = orderInfo.Barcode
                                    };
                                    Dt_Task dt_Task = new Dt_Task()
                                    {
                                        PalletCode = orderInfo.Barcode,
                                        DeviceCode = putContainer.DeviceCode,
                                        TaskState = (int)TaskStatusEnum.Gantry_Wait,
                                        TaskType = 0,
                                        SourceAddress = "",
                                        TargetAddress = $"F06",
                                        CurrentAddress = $"F06*{taskPosition.TakePositionX}*{taskPosition.TakePositionY}*{taskPosition.TakePositionZ}*{taskPosition.PositionR}",
                                        NextAddress = $"{putContainer.ContainerCode}*{taskPosition.PutPositionX}*{taskPosition.PutPositionY}*{taskPosition.PutPositionZ}*{taskPosition.PositionR}",
                                        ItemInfo = $"{length}*{width}*{height}",
                                        Grade = 0,
                                    };
                                    putContainer.ContainerStatus = ContainerStatusEnum.NonEmpty.ObjToInt();
                                    _unitOfWorkManage.BeginTran();
                                    BaseDal.AddData(dt_Task);
                                    _containerRepository.UpdateData(putContainer);
                                    _containerItemRepository.AddData(dt_ContainerItem);
                                    if (isAdd)
                                    {
                                        _orderContainerRepository.AddData(orderContainer);
                                    }
                                    _unitOfWorkManage.CommitTran();
                                    PlacedBlock placedBlock = new PlacedBlock(new Point3D(taskPosition.PositionX, taskPosition.PositionY, taskPosition.PositionZ), length > width ? length : width, width > length ? length : width, height);
                                    placedBlocks.Add(placedBlock);
                                    Thread.Sleep(1000);
                                    object obj = new
                                    {
                                        x = taskPosition.PutCenterPositionX - putContainer.ContainerLength / 2,
                                        y = taskPosition.PutCenterPositionY - putContainer.ContainerWidth / 2,
                                        z = taskPosition.PutPositionZ,
                                        length = length > width ? length : width,
                                        width = width > length ? length : width,
                                        height,
                                    };
                                    _webSocketServer.PublishAllClientPayload(obj.Serialize());
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                    }
                }
                return WebResponseContent.Instance.OK(data: placedBlocks);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        /// <summary>
        /// åˆ›å»ºä»»åŠ¡å¹¶è®¡ç®—ç‰©å“æ”¾ç½®ä½ç½®
        /// </summary>
        /// <param name="takePosition">取货位置编码</param>
        /// <param name="putPosition">放货位置编码</param>
        /// <param name="deviceCode">设备编码</param>
        /// <param name="length">物品长度</param>
        /// <param name="width">物品宽度</param>
        /// <param name="height">物品高度</param>
        /// <returns>包含操作结果的Web响应内容</returns>
        /// <remarks>
        /// 1. éªŒè¯å–è´§/放货位置是否存在 <br/>
        /// 2. è®¡ç®—物品在容器中的最佳放置位置 <br/>
        /// 3. åˆ›å»ºå®¹å™¨ç‰©å“è®°å½•和任务记录 <br/>
        /// 4. é€šè¿‡WebSocket通知客户端
        /// </remarks>
        public WebResponseContent CreateTask(string takePosition, string putPosition, string deviceCode, int length, int width, int height)
        {
            try
@@ -88,24 +319,44 @@
                    return WebResponseContent.Instance.Error("取货位置不存在");
                }
                List<Dt_Container> containers = _containerRepository.QueryData(x => x.DeviceCode == deviceCode && x.ContainerType == ContainerTypeEnum.PutContainer.ObjToInt());
                Dt_Container putContainer = _containerRepository.QueryFirst(x => x.ContainerCode == putPosition && x.ContainerType == ContainerTypeEnum.PutContainer.ObjToInt());
                if (putContainer == null)
                {
                    return WebResponseContent.Instance.Error("放货位置不存在");
                }
                int edge = 0;
                if (putContainer.ContainerNo == containers.Min(x => x.ContainerNo))
                {
                    edge = 1;
                }
                ContainerSize containerSize = new ContainerSize(putContainer.ContainerLength, putContainer.ContainerWidth, putContainer.ContainerHeight);
                List<Dt_ContainerItem> containerItems = _containerItemRepository.QueryData(x => x.ContainerId == putContainer.Id);
                List<PlacedBlock> placedBlocks = containerItems.Select(x => new PlacedBlock(new Point3D(x.ItemPositionX, x.ItemPositionY, x.ItemPositionZ), x.ItemLength, x.ItemWidth, x.ItemHeight)).ToList();
                List<PlacedBlock> placedBlocks = containerItems.Select(x => new PlacedBlock(new Point3D(x.ItemPositionX, x.ItemPositionY, x.ItemPositionZ), x.ItemLength > x.ItemLength ? x.ItemLength : x.ItemWidth, x.ItemLength > x.ItemLength ? x.ItemWidth : x.ItemLength, x.ItemHeight)).ToList();
                PlaceBlockService placeBlockService = new PlaceBlockService(containerSize, placedBlocks);
                Point3D? point3D = placeBlockService.PlaceBlock(length, width, height);
                if (point3D == null)
                TaskPosition? taskPosition = _containerService.GetTaskPosition(length, width, height, containerSize, placedBlocks, edge);
                if (taskPosition == null)
                {
                    return WebResponseContent.Instance.Error("放货位置已满");
                    return WebResponseContent.Instance.Error("未找到合适放置位置");
                }
                object obj = new
                {
                    x = taskPosition.PutCenterPositionX - putContainer.ContainerLength / 2,
                    y = taskPosition.PutCenterPositionY - putContainer.ContainerWidth / 2,
                    z = taskPosition.PutCenterPositionZ,
                    length,
                    width,
                    height,
                };
                _webSocketServer.PublishAllClientPayload(obj.Serialize());
                string code = DateTime.Now.ToString("yyyyMMddHHmmss");
                Dt_ContainerItem dt_ContainerItem = new Dt_ContainerItem()
@@ -115,134 +366,27 @@
                    ItemLength = length,
                    ItemWidth = width,
                    ItemHeight = height,
                    ItemPositionX = point3D.Value.X,
                    ItemPositionY = point3D.Value.Y,
                    ItemPositionZ = point3D.Value.Z,
                    ItemPositionX = taskPosition.PositionX,
                    ItemPositionY = taskPosition.PositionY,
                    ItemPositionZ = taskPosition.PositionZ,
                    ItemRelaPositionX = taskPosition.PutPositionX,
                    ItemRelaPositionY = taskPosition.PutPositionY,
                    ItemRelaPositionZ = taskPosition.PutPositionZ,
                    ItemStatus = (int)ItemStatusEnum.Assigned,
                    ItemName = code
                };
                int positionR = 1;
                int takePositionX = 0;
                int takePositionY = 0;
                int putPositionX = 0;
                int putPositionY = 0;
                int takeContainerPositionX = 0;
                int takeContainerPositionY = 0;
                int takeContainerPositionZ = 0;
                int putContainerPositionX = 0;
                int putContainerPositionY = 0;
                int putContainerPositionZ = 0;
                int deviceHalfLength = 0;
                int deviceHalfWidth = 0;
                if (length > 920 && width >= 300)
                {
                    positionR = 1;
                    if (OPositions.ZPositions.TryGetValue(takeContainer.ContainerCode, out Position? takeOPosition))
                    {
                        takeContainerPositionX = takeOPosition.PositionX;
                        takeContainerPositionY = takeOPosition.PositionY;
                        takeContainerPositionZ = takeOPosition.PositionZ;
                    }
                    if (OPositions.ZPositions.TryGetValue(putContainer.ContainerCode, out Position? putOPosition))
                    {
                        putContainerPositionX = putOPosition.PositionX;
                        putContainerPositionY = putOPosition.PositionY;
                        putContainerPositionZ = putOPosition.PositionZ;
                    }
                    deviceHalfLength = 460;
                    deviceHalfWidth = 265;
                }
                else
                {
                    positionR = 0;
                    if (OPositions.HPositions.TryGetValue(takeContainer.ContainerCode, out Position? takeOPosition))
                    {
                        takeContainerPositionX = takeOPosition.PositionX;
                        takeContainerPositionY = takeOPosition.PositionY;
                        takeContainerPositionZ = takeOPosition.PositionZ;
                    }
                    if (OPositions.HPositions.TryGetValue(putContainer.ContainerCode, out Position? putOPosition))
                    {
                        putContainerPositionX = putOPosition.PositionX;
                        putContainerPositionY = putOPosition.PositionY;
                        putContainerPositionZ = putOPosition.PositionZ;
                    }
                    deviceHalfLength = 265;
                    deviceHalfWidth = 460;
                }
                //吸盘长530 300 é—´éš”660  æœ€å¤§920 å¸ç›˜å®½130
                int sourceTakePositionX = 0;
                int sourceTakePositionY = 0;
                int sourcePutPositionX = 0;
                int sourceTPutPositionY = 0;
                if (length / 2 + point3D.Value.X > 1000)
                {
                    takePositionY = 1000;
                    putPositionY = putContainerPositionY + 1000;
                    sourceTakePositionY = 1000;
                    sourceTPutPositionY = 1000;
                }
                else
                {
                    takePositionY = takeContainerPositionY - length / 2 + deviceHalfLength;
                    putPositionY = putContainerPositionY + length / 2 + point3D.Value.X - deviceHalfLength;
                    sourceTakePositionY = length / 2 + point3D.Value.X + deviceHalfLength;
                    sourceTPutPositionY = length / 2 + point3D.Value.X - deviceHalfLength;
                }
                if (width >= 530)
                {
                    takePositionX = takeContainerPositionX + Math.Abs( width / 2 - deviceHalfWidth);
                    putPositionX = point3D.Value.Y + putContainerPositionX + Math.Abs(width / 2 - deviceHalfWidth);
                    sourceTakePositionX = Math.Abs(width / 2 - deviceHalfWidth);
                    sourcePutPositionX = point3D.Value.Y + Math.Abs(width / 2 - deviceHalfWidth);
                }
                else
                {
                    takePositionX = takeContainerPositionX;
                    putPositionX = point3D.Value.Y + takeContainerPositionX;
                    sourceTakePositionX = 0;
                    sourcePutPositionX = point3D.Value.Y;
                }
                int takePositionZ = takeContainerPositionZ - (height - (height - 10));
                int putPositionZ = (putContainerPositionZ - (height - (height - 10))) - point3D.Value.Z;
                int sourceTakePositionZ = height - (height - 10);
                int sourcePutPositionZ = height - (height - 10) + point3D.Value.Z;
                Dt_Task dt_Task = new Dt_Task()
                {
                    TaskNum = 1,
                    PalletCode = code,
                    DeviceCode = deviceCode,
                    DeviceCode = putContainer.DeviceCode,
                    TaskState = (int)TaskStatusEnum.Gantry_New,
                    TaskType = 0,
                    SourceAddress = $"{takePosition}-{sourceTakePositionX}-{sourceTakePositionY}-{sourceTakePositionZ}-{positionR}",
                    TargetAddress = $"{putPosition}-{sourcePutPositionX}-{sourceTPutPositionY}-{sourcePutPositionZ}-{positionR}",
                    CurrentAddress = $"{takePosition}-{takePositionX}-{takePositionY}-{takePositionZ}-{positionR}",
                    NextAddress = $"{putPosition}-{putPositionX}-{putPositionY}-{putPositionZ}-{positionR}",
                    SourceAddress = "",
                    TargetAddress = $"{takeContainer.ContainerNo}",
                    CurrentAddress = $"{takeContainer.ContainerCode}*{taskPosition.TakePositionX}*{taskPosition.TakePositionY}*{taskPosition.TakePositionZ}*{taskPosition.PositionR}",
                    NextAddress = $"{putContainer.ContainerCode}*{taskPosition.PutPositionX}*{taskPosition.PutPositionY}*{taskPosition.PutPositionZ}*{taskPosition.PositionR}",
                    ItemInfo = $"{length}*{width}*{height}",
                    Grade = 0,
                };
@@ -256,5 +400,533 @@
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        /// <summary>
        /// æ ¹æ®è®¢å•信息生成任务
        /// </summary>
        /// <param name="orderInfo">订单信息</param>
        /// <returns>包含三个值的元组: <br/>
        /// Item1 - æ“ä½œæ˜¯å¦æˆåŠŸ (bool) <br/>
        /// Item2 - ç”Ÿæˆçš„任务对象 (Dt_Task),失败时为null <br/>
        /// Item3 - é”™è¯¯æ¶ˆæ¯ (string),成功时为空字符串
        /// </returns>
        /// <remarks>
        /// è¯¥æ–¹æ³•会: <br/>
        /// 1. æ ¹æ®è®¢å•尺寸获取合适的货位 <br/>
        /// 2. åˆ›å»ºå®¹å™¨é¡¹å’Œä»»åŠ¡è®°å½• <br/>
        /// 3. æ›´æ–°ç›¸å…³å®¹å™¨çŠ¶æ€ <br/>
        /// 4. åœ¨äº‹åŠ¡ä¸­æ‰§è¡Œæ‰€æœ‰æ•°æ®åº“æ“ä½œ
        /// </remarks>
        public (bool, Dt_Task?, string) GenerateTask(OrderInfo orderInfo)
        {
            try
            {
                int length = Convert.ToInt32(orderInfo.Length);
                int width = Convert.ToInt32(orderInfo.Width);
                int height = Convert.ToInt32(orderInfo.Thickness);
                var (flag, taskPosition, message) = _containerService.GetPosition(orderInfo.OrderHeadId, orderInfo.OrderNo, length, width, height);
                if (flag && taskPosition != null)
                {
                    Dt_Container putContainer = _containerRepository.QueryFirst(x => x.ContainerCode == taskPosition.PutPosition);
                    if (putContainer == null)
                    {
                        return (false, null, "未找到放货位置");
                    }
                    Dt_Container? takeContainer = GetTakePosition(putContainer.DeviceCode);
                    if (takeContainer == null)
                    {
                        return (false, null, "未找到取货位置");
                    }
                    Dt_OrderContainer orderContainer = _orderContainerRepository.QueryFirst(x => x.OrderNo == orderInfo.OrderNo && x.ContainerCode == putContainer.ContainerCode);
                    bool isAdd = false;
                    bool isUpdate = false;
                    if (orderContainer == null)
                    {
                        orderContainer = new Dt_OrderContainer()
                        {
                            OrderId = orderInfo.OrderHeadId,
                            ContainerCode = putContainer.ContainerCode,
                            ContainerId = putContainer.Id,
                            OrderNo = orderInfo.OrderNo,
                        };
                        int containerLength = putContainer.ContainerLength;
                        int containerWidth = putContainer.ContainerWidth;
                        int maxValue = Math.Max(length, width);
                        int minValue = Math.Min(length, width);
                        if (minValue > putContainer.ContainerWidth)
                        {
                            containerLength = maxValue;
                            containerWidth = minValue;
                        }
                        orderContainer.MaxLength = containerLength;
                        orderContainer.MaxWidth = containerWidth;
                        isAdd = true;
                    }
                    Dt_ContainerItem dt_ContainerItem = new Dt_ContainerItem()
                    {
                        ContainerId = putContainer.Id,
                        ItemCode = orderInfo.Barcode,
                        ItemLength = length,
                        ItemWidth = width,
                        ItemHeight = height,
                        ItemPositionX = taskPosition.PositionX,
                        ItemPositionY = taskPosition.PositionY,
                        ItemPositionZ = taskPosition.PositionZ,
                        ItemRelaPositionX = taskPosition.PutPositionX,
                        ItemRelaPositionY = taskPosition.PutPositionY,
                        ItemRelaPositionZ = taskPosition.PutPositionZ,
                        ItemStatus = (int)ItemStatusEnum.Assigned,
                        ItemName = orderInfo.Barcode,
                        Remark = $"{takeContainer.ContainerCode}*{taskPosition.TakePositionX}*{taskPosition.TakePositionY}*{taskPosition.TakePositionZ}*{taskPosition.PositionR}"
                    };
                    Dt_Task dt_Task = new Dt_Task()
                    {
                        PalletCode = orderInfo.Barcode,
                        DeviceCode = putContainer.DeviceCode,
                        TaskState = (int)TaskStatusEnum.Gantry_Wait,
                        TaskType = 0,
                        SourceAddress = "",
                        TargetAddress = $"{takeContainer.ContainerNo}",
                        CurrentAddress = $"{takeContainer.ContainerCode}*{taskPosition.TakePositionX}*{taskPosition.TakePositionY}*{taskPosition.TakePositionZ}*{taskPosition.PositionR}",
                        NextAddress = $"{putContainer.ContainerCode}*{taskPosition.PutPositionX}*{taskPosition.PutPositionY}*{taskPosition.PutPositionZ}*{taskPosition.PositionR}",
                        ItemInfo = $"{length}*{width}*{height}",
                        Grade = 0,
                    };
                    putContainer.ContainerStatus = ContainerStatusEnum.NonEmpty.ObjToInt();
                    _unitOfWorkManage.BeginTran();
                    BaseDal.AddData(dt_Task);
                    _containerRepository.UpdateData(putContainer);
                    _containerItemRepository.AddData(dt_ContainerItem);
                    if (isAdd)
                    {
                        _orderContainerRepository.AddData(orderContainer);
                    }
                    else if (isUpdate)
                    {
                        _orderContainerRepository.UpdateData(orderContainer);
                    }
                    _unitOfWorkManage.CommitTran();
                    return (true, dt_Task, "");
                }
                else
                {
                    return (false, null, message);
                }
            }
            catch (Exception ex)
            {
                _unitOfWorkManage.RollbackTran();
                return (false, null, $"错误,{ex.ExceptionToString()}");
            }
        }
        /// <summary>
        /// é‡æ–°ç”Ÿæˆä»»åŠ¡
        /// </summary>
        /// <param name="task">原始任务对象</param>
        /// <param name="stationCode">工作站编码</param>
        /// <returns>
        /// åŒ…含三个值的元组: <br/>
        /// 1. bool - æ“ä½œæ˜¯å¦æˆåŠŸ <br/>
        /// 2. Dt_Task - æ›´æ–°åŽçš„任务对象(失败时为null) <br/>
        /// 3. string - é”™è¯¯æ¶ˆæ¯ï¼ˆæˆåŠŸæ—¶ä¸ºç©ºå­—ç¬¦ä¸²ï¼‰
        /// </returns>
        /// <remarks>
        /// è¯¥æ–¹æ³•用于重新生成任务信息,包括: <br/>
        /// 1. è§£æžæ¿å­å°ºå¯¸ä¿¡æ¯ <br/>
        /// 2. éªŒè¯å–è´§/放货位置 <br/>
        /// 3. è®¡ç®—物品放置位置 <br/>
        /// 4. æ›´æ–°ä»»åŠ¡çŠ¶æ€å’Œä½ç½®ä¿¡æ¯ <br/>
        /// 5. åœ¨äº‹åŠ¡ä¸­æ›´æ–°æ•°æ®åº“è®°å½•
        /// </remarks>
        public (bool, Dt_Task?, string) RegenerateTask(Dt_Task task, string stationCode)
        {
            try
            {
                int length = 0;
                int width = 0;
                int height = 0;
                Dt_ContainerItem containerItem = _containerItemRepository.QueryFirst(x => x.ItemCode == task.PalletCode);
                if (containerItem == null)
                {
                    List<string> itemInfos = task.ItemInfo.Split("*").ToList();
                    if (itemInfos.Count == 3)
                    {
                        length = Convert.ToInt32(itemInfos[0]);
                        width = Convert.ToInt32(itemInfos[1]);
                        height = Convert.ToInt32(itemInfos[2]);
                    }
                    else
                    {
                        return (false, null, "板子尺寸信息错误");
                    }
                }
                else
                {
                    length = containerItem.ItemLength;
                    width = containerItem.ItemWidth;
                    height = containerItem.ItemHeight;
                }
                string containerCode = task.NextAddress.Split("*")[0];
                Dt_Container putContainer = _containerRepository.QueryFirst(x => x.ContainerCode == containerCode);
                if (putContainer == null)
                {
                    return (false, null, "未找到放货位置");
                }
                Dt_Container? takeContainer = _containerRepository.QueryFirst(x => x.ContainerCode == stationCode);
                if (takeContainer == null)
                {
                    return (false, null, "未找到取货位置");
                }
                var (flag, taskPosition, message) = _containerService.GetPosition(putContainer, length, width, height);
                if (!flag || taskPosition == null)
                {
                    return (false, null, message);
                }
                Dt_OrderContainer orderContainer = _orderContainerRepository.QueryFirst(x => x.ContainerCode == putContainer.ContainerCode);
                bool isAdd = false;
                if (orderContainer == null)
                {
                    return (false, null, "未找到订单与容器绑定关系");
                }
                int containerLength = putContainer.ContainerLength;
                int containerWidth = putContainer.ContainerWidth;
                int maxValue = Math.Max(length, width);
                int minValue = Math.Min(length, width);
                if (minValue > putContainer.ContainerWidth)
                {
                    containerLength = maxValue;
                    containerWidth = minValue;
                }
                orderContainer.MaxLength = containerLength;
                orderContainer.MaxWidth = containerWidth;
                if (containerItem == null)
                {
                    containerItem = new Dt_ContainerItem()
                    {
                        ContainerId = putContainer.Id,
                        ItemCode = task.PalletCode,
                        ItemLength = length,
                        ItemWidth = width,
                        ItemHeight = height,
                        ItemPositionX = taskPosition.PositionX,
                        ItemPositionY = taskPosition.PositionY,
                        ItemPositionZ = taskPosition.PositionZ,
                        ItemRelaPositionX = taskPosition.PutPositionX,
                        ItemRelaPositionY = taskPosition.PutPositionY,
                        ItemRelaPositionZ = taskPosition.PutPositionZ,
                        ItemStatus = (int)ItemStatusEnum.Assigned,
                        ItemName = task.PalletCode,
                        Remark = $"{takeContainer.ContainerCode}*{taskPosition.TakePositionX}*{taskPosition.TakePositionY}*{taskPosition.TakePositionZ}*{taskPosition.PositionR}"
                    };
                    isAdd = true;
                }
                else
                {
                    containerItem.ItemLength = length;
                    containerItem.ItemWidth = width;
                    containerItem.ItemHeight = height;
                    containerItem.ItemPositionX = taskPosition.PositionX;
                    containerItem.ItemPositionY = taskPosition.PositionY;
                    containerItem.ItemPositionZ = taskPosition.PositionZ;
                    containerItem.ItemRelaPositionX = taskPosition.PutPositionX;
                    containerItem.ItemRelaPositionY = taskPosition.PutPositionY;
                    containerItem.ItemRelaPositionZ = taskPosition.PutPositionZ;
                    containerItem.ItemStatus = (int)ItemStatusEnum.Assigned;
                    containerItem.Remark = $"{takeContainer.ContainerCode}*{taskPosition.TakePositionX}*{taskPosition.TakePositionY}*{taskPosition.TakePositionZ}*{taskPosition.PositionR}";
                }
                task.TaskState = (int)TaskStatusEnum.Gantry_New;
                task.CurrentAddress = $"{takeContainer.ContainerCode}*{taskPosition.TakePositionX}*{taskPosition.TakePositionY}*{taskPosition.TakePositionZ}*{taskPosition.PositionR}";
                task.NextAddress = $"{putContainer.ContainerCode}*{taskPosition.PutPositionX}*{taskPosition.PutPositionY}*{taskPosition.PutPositionZ}*{taskPosition.PositionR}";
                task.ItemInfo = $"{length}*{width}*{height}";
                _unitOfWorkManage.BeginTran();
                BaseDal.UpdateData(task);
                _containerRepository.UpdateData(putContainer);
                _orderContainerRepository.UpdateData(orderContainer);
                if (isAdd)
                {
                    _containerItemRepository.AddData(containerItem);
                }
                else
                {
                    _containerItemRepository.UpdateData(containerItem);
                }
                _unitOfWorkManage.CommitTran();
                return (true, task, "");
            }
            catch (Exception ex)
            {
                _unitOfWorkManage.RollbackTran();
                return (false, null, $"错误,{ex.ExceptionToString()}");
            }
        }
        /// <summary>
        /// ç”Ÿæˆå¼‚常任务
        /// </summary>
        /// <param name="orderInfo">订单信息</param>
        /// <returns>元组包含三个值: <br/>
        /// Item1 - æ“ä½œæ˜¯å¦æˆåŠŸï¼ˆbool) <br/>
        /// Item2 - ç”Ÿæˆçš„任务对象(Dt_Task),失败时为null <br/>
        /// Item3 - é”™è¯¯æ¶ˆæ¯ï¼ˆstring),成功时为空字符串</returns>
        /// <remarks>
        /// è¯¥æ–¹æ³•会根据订单信息生成一个异常处理任务,包括: <br/>
        /// 1. èŽ·å–å¼‚å¸¸ä½ç½® <br/>
        /// 2. éªŒè¯æ”¾è´§/取货位置 <br/>
        /// 3. åˆ›å»ºå®¹å™¨é¡¹å’Œä»»åŠ¡è®°å½• <br/>
        /// 4. æäº¤äº‹åŠ¡
        /// </remarks>
        public (bool, Dt_Task?, string) GenerateExceptionTask(OrderInfo orderInfo)
        {
            int length = Convert.ToInt32(orderInfo.Length);
            int width = Convert.ToInt32(orderInfo.Width);
            int height = Convert.ToInt32(orderInfo.Thickness);
            var (flag, taskPosition, message) = _containerService.GetExceptionPosition(length, width, height);
            if (flag && taskPosition != null)
            {
                Dt_Container putContainer = _containerRepository.QueryFirst(x => x.ContainerCode == taskPosition.PutPosition);
                if (putContainer == null)
                {
                    return (false, null, "未找到放货位置");
                }
                Dt_Container? takeContainer = GetTakePosition(putContainer.DeviceCode);
                if (takeContainer == null)
                {
                    return (false, null, "未找到取货位置");
                }
                Dt_ContainerItem dt_ContainerItem = new Dt_ContainerItem()
                {
                    ContainerId = putContainer.Id,
                    ItemCode = orderInfo.Barcode,
                    ItemLength = length,
                    ItemWidth = width,
                    ItemHeight = height,
                    ItemPositionX = taskPosition.PositionX,
                    ItemPositionY = taskPosition.PositionY,
                    ItemPositionZ = taskPosition.PositionZ,
                    ItemRelaPositionX = taskPosition.PutPositionX,
                    ItemRelaPositionY = taskPosition.PutPositionY,
                    ItemRelaPositionZ = taskPosition.PutPositionZ,
                    ItemStatus = (int)ItemStatusEnum.Assigned,
                    ItemName = orderInfo.Barcode,
                    Remark = $"{takeContainer.ContainerCode}*{taskPosition.TakePositionX}*{taskPosition.TakePositionY}*{taskPosition.TakePositionZ}*{taskPosition.PositionR}"
                };
                Dt_Task dt_Task = new Dt_Task()
                {
                    PalletCode = orderInfo.Barcode,
                    DeviceCode = putContainer.DeviceCode,
                    TaskState = (int)TaskStatusEnum.Gantry_Wait,
                    TaskType = 0,
                    SourceAddress = "",
                    TargetAddress = $"{takeContainer.ContainerNo}",
                    CurrentAddress = $"{takeContainer.ContainerCode}*{taskPosition.TakePositionX}*{taskPosition.TakePositionY}*{taskPosition.TakePositionZ}*{taskPosition.PositionR}",
                    NextAddress = $"{putContainer.ContainerCode}*{taskPosition.PutPositionX}*{taskPosition.PutPositionY}*{taskPosition.PutPositionZ}*{taskPosition.PositionR}",
                    ItemInfo = $"{length}*{width}*{height}",
                    Grade = 0,
                };
                if (taskPosition.TakeCenterPositionZ == 99)
                {
                    dt_Task.TaskState = (int)TaskStatusEnum.Gantry_BeRelease;
                }
                _unitOfWorkManage.BeginTran();
                BaseDal.AddData(dt_Task);
                _containerItemRepository.AddData(dt_ContainerItem);
                _unitOfWorkManage.CommitTran();
                return (true, dt_Task, "");
            }
            else
            {
                return (false, null, message);
            }
        }
        /// <summary>
        /// æ ¹æ®è®¾å¤‡ç¼–号获取取货位置
        /// </summary>
        /// <param name="deviceCode">设备编号</param>
        /// <returns>符合条件的容器对象,若找不到则返回null</returns>
        /// <remarks>
        /// 1. é¦–先查询指定设备下所有可用的取货容器,并按ContainerSort升序排序 <br/>
        /// 2. æŸ¥æ‰¾è¯¥è®¾å¤‡æœ€è¿‘的任务记录 <br/>
        /// 3. å¦‚果找到任务记录,则根据任务源地址匹配容器,返回下一个容器(若已是最后一个则返回第一个) <br/>
        /// 4. å¦‚果出现异常或未找到匹配项,则返回第一个可用容器
        /// </remarks>
        public Dt_Container? GetTakePosition(string deviceCode)
        {
            Dictionary<string, OrderByType> orderby = new Dictionary<string, OrderByType>() { { nameof(Dt_Container.ContainerSort), OrderByType.Asc } };
            List<Dt_Container> containers = _containerRepository.QueryData(x => x.ContainerType == ContainerTypeEnum.TakeContainer.ObjToInt() && x.DeviceCode == deviceCode && x.ContainerEnable, orderby);
            try
            {
                if (containers == null || containers.Count == 0)
                {
                    throw new Exception($"未找到对应的取货位置,设备编号:{deviceCode}");
                }
                Dictionary<string, OrderByType> taskOrderby = new Dictionary<string, OrderByType>() { { nameof(Dt_Task.TaskNum), OrderByType.Desc } };
                Dt_Task task = BaseDal.QueryFirst(x => x.DeviceCode == deviceCode, taskOrderby);
                if (task != null)
                {
                    string? sourceCode = task.SourceAddress.Split("*").FirstOrDefault();
                    if (!string.IsNullOrEmpty(sourceCode))
                    {
                        Dt_Container? container = containers.FirstOrDefault(x => x.ContainerCode == sourceCode);
                        if (container != null)
                        {
                            int index = containers.IndexOf(container);
                            if (index + 1 < containers.Count)
                            {
                                return containers[index + 1];
                            }
                            else
                            {
                                return containers.FirstOrDefault();
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
            }
            return containers.FirstOrDefault();
        }
        /// <summary>
        /// ä»»åŠ¡å®Œæˆå¤„ç†æ–¹æ³•
        /// </summary>
        /// <param name="task">任务实体</param>
        /// <returns>Web响应内容</returns>
        /// <remarks>
        /// 1. æ›´æ–°ä»»åŠ¡çŠ¶æ€ä¸º"龙门架完成" <br/>
        /// 2. æ›´æ–°ç›¸å…³è®¢å•详情状态为"码垛成功" <br/>
        /// 3. æ›´æ–°è®¢å•行中的托盘数量 <br/>
        /// 4. æ ¹æ®ä»»åŠ¡å®Œæˆæƒ…å†µå‘é€WebSocket通知 <br/>
        /// 5. è®°å½•操作日志并提交事务 <br/>
        /// 6. å¼‚常时回滚事务并返回错误信息
        /// </remarks>
        public WebResponseContent TaskComplete(Dt_Task task)
        {
            try
            {
                task.TaskState = TaskStatusEnum.Gantry_Completed.ObjToInt();
                _unitOfWorkManage.BeginTran();
                OrderDetails orderDetails = _orderDetailsRepository.QueryFirst(x => x.Orderdetails_outid == task.PalletCode);
                if (orderDetails != null)
                {
                    orderDetails.Orderdetails_status = PalletingStatusEnmu.PalletingSuccess.ObjToInt();
                    Orderrows orderrows = _orderrowsRepository.QueryFirst(x => x.id == orderDetails.Orderrowsid);
                    if (orderrows != null)
                    {
                        orderrows.Orderrows_PalletNum = orderrows.Orderrows_PalletNum ?? 0 + 1;
                        Dt_Container container = _containerRepository.QueryFirst(x => task.NextAddress.Contains(x.ContainerCode));
                        _orderDetailsRepository.UpdateData(orderDetails);
                        _orderrowsRepository.UpdateData(orderrows);
                        if (container.ContainerType == ContainerTypeEnum.ExceptionContainer.ObjToInt())
                        {
                            int count = Db.Queryable<Dt_ContainerItem>().Count(x => x.ContainerId == container.Id);
                            if (count >= 5)
                            {
                                if (LightStatusStorage.LightStatusDic.ContainsKey(container.ContainerCode))
                                {
                                    LightStatusStorage.LightStatusDic[container.ContainerCode] = LightStatusEnum.LightError;
                                }
                            }
                        }
                        try
                        {
                            List<string> containerItemCodes = _containerItemRepository.QueryData(x => x.ContainerId == container.Id).Select(x => x.ItemCode).ToList();
                            List<OrderDetails> totalDetails = _orderDetailsRepository.QueryData(x => x.Orderrowsid == orderrows.id);
                            List<OrderDetails> details = totalDetails.Where(x => x.Orderrowsid == orderrows.id && x.Orderdetails_status == PalletingStatusEnmu.PalletingSuccess.ObjToInt() && containerItemCodes.Contains(x.Orderdetails_outid)).ToList();
                            int sortedNum = totalDetails.Where(x => x.Orderrowsid == orderrows.id && x.Orderdetails_status == PalletingStatusEnmu.PalletingSuccess.ObjToInt()).Count();
                            List<object> orderData = new List<object>();
                            foreach (var item in details)
                            {
                                object obj = new
                                {
                                    name = item.Orderdetails_name,
                                    baseName = item.Orderdetails_productName,
                                    size = $"{item.Orderdetails_length}*{item.Orderdetails_width}*{item.Orderdetails_thickness}",
                                    process = "",
                                };
                                orderData.Add(obj);
                            }
                            object data = new
                            {
                                orderCode = orderrows.Orderrows_orderid,
                                orderName = orderrows.Orderrows_name,
                                cusName = orderrows.Orderrows_customer,
                                stationCode = container.ContainerCode,
                                orderTotalNum = totalDetails.Count,
                                sortedNum = sortedNum,
                                unsortedNum = totalDetails.Count - sortedNum,
                                stationSortedNum = details.Count,
                                orderData = orderData,
                                orderId = orderrows.id,
                                release = 0
                            };
                            _webSocketServer.PublishAllClientPayload(data.Serialize());
                        }
                        catch (Exception ex)
                        {
                        }
                    }
                }
                BaseDal.DeleteAndMoveIntoHty(task, App.User?.UserId > 0 ? OperateTypeEnum.人工完成 : OperateTypeEnum.自动完成);
                _unitOfWorkManage.CommitTran();
                return WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
            {
                _unitOfWorkManage.RollbackTran();
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
    }
}