1
z8018
2025-06-10 e46aa927d231af83724683c7286d9db503e24cf7
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/ContainerService.cs
@@ -4,157 +4,100 @@
using System.Text;
using System.Threading.Tasks;
using AutoMapper;
using HslCommunication.WebSocket;
using WIDESEAWCS_BasicInfoRepository;
using WIDESEAWCS_BasicInfoService;
using WIDESEAWCS_Common;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.BaseRepository;
using WIDESEAWCS_Core.BaseServices;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_DTO.BasicInfo;
using WIDESEAWCS_DTO.PlacedBlockDTO;
using WIDESEAWCS_DTO.TaskInfo;
using WIDESEAWCS_IBasicInfoRepository;
using WIDESEAWCS_IBasicInfoService;
using WIDESEAWCS_ITaskInfoRepository;
using WIDESEAWCS_Model.Models;
namespace WIDESEAWCS_BasicInfoService
{
    /// <summary>
    /// å®¹å™¨æœåŠ¡ç±»ï¼Œæä¾›å®¹å™¨ç›¸å…³çš„ä¸šåŠ¡é€»è¾‘æ“ä½œ
    /// </summary>
    /// <remarks>
    /// ä¸»è¦åŠŸèƒ½åŒ…æ‹¬ï¼š <br/>
    /// 1. èŽ·å–ç‰©å“åœ¨å®¹å™¨ä¸­çš„æ”¾ç½®ä½ç½® <br/>
    /// 2. å¤„理异常工位的位置分配 <br/>
    /// 3. æ ¹æ®è®¢å•或尺寸获取合适的位置 <br/>
    /// 4. é‡Šæ”¾å®¹å™¨èµ„源 <br/>
    /// ä½¿ç”¨ä¾èµ–注入方式获取仓储接口和工作单元管理
    /// </remarks>
    public class ContainerService : ServiceBase<Dt_Container, IContainerRepository>, IContainerService
    {
        /// <summary>
        /// ç”¨äºŽå¯¹è±¡æ˜ å°„的映射器实例
        /// </summary>
        private readonly IMapper _mapper;
        int lengthThreshold = AppSettings.Get("LengthThreshold").ObjToInt();
        /// <summary>
        /// å·¥ä½œå•元管理接口实例,用于管理数据库事务和工作单元
        /// </summary>
        private readonly IUnitOfWorkManage _unitOfWorkManage;
        /// <summary>
        /// å®¹å™¨ç‰©å“ä»“储接口实例
        /// </summary>
        private readonly IContainerItemRepository _containerItemRepository;
        /// <summary>
        /// è®¢å•容器仓储接口实例
        /// </summary>
        private readonly IOrderContainerRepository _orderContainerRepository;
        /// <summary>
        /// ä»»åŠ¡ä»“å‚¨æŽ¥å£å®žä¾‹ï¼Œç”¨äºŽæ“ä½œä»»åŠ¡æ•°æ®
        /// </summary>
        private readonly ITaskRepository _taskRepository;
        /// <summary>
        /// WebSocket服务器实例,用于处理实时通信
        /// </summary>
        private readonly WebSocketServer _webSocketServer;
        public ContainerService(IContainerRepository BaseDal, IMapper mapper) : base(BaseDal)
        /// <summary>
        /// å®¹å™¨æœåŠ¡æž„é€ å‡½æ•°
        /// </summary>
        /// <param name="BaseDal">容器仓储接口</param>
        /// <param name="mapper">对象映射器</param>
        /// <param name="unitOfWorkManage">工作单元管理器</param>
        /// <param name="containerItemRepository">容器项仓储接口</param>
        /// <param name="orderContainerRepository">订单容器仓储接口</param>
        /// <param name="taskRepository">任务仓储接口</param>
        /// <param name="webSocketServer">WebSocket服务实例</param>
        public ContainerService(IContainerRepository BaseDal, IMapper mapper, IUnitOfWorkManage unitOfWorkManage, IContainerItemRepository containerItemRepository, IOrderContainerRepository orderContainerRepository, ITaskRepository taskRepository, WebSocketServer webSocketServer) : base(BaseDal)
        {
            _mapper = mapper;
            _unitOfWorkManage = unitOfWorkManage;
            _containerItemRepository = containerItemRepository;
            _orderContainerRepository = orderContainerRepository;
            _taskRepository = taskRepository;
            _webSocketServer = webSocketServer;
        }
        public TaskPosition? GetTaskPosition(int length, int width, int height, ContainerSize containerSize, List<PlacedBlock> placedBlocks)
        /// <summary>
        /// èŽ·å–ä»»åŠ¡ä½ç½®ä¿¡æ¯
        /// </summary>
        /// <param name="length">物品长度</param>
        /// <param name="width">物品宽度</param>
        /// <param name="height">物品高度</param>
        /// <param name="containerSize">容器尺寸</param>
        /// <param name="placedBlocks">已放置块列表</param>
        /// <param name="edge">边缘参数</param>
        /// <returns>返回任务位置信息,若放置失败则返回null</returns>
        /// <exception cref="Exception">当放置过程中发生错误时抛出异常</exception>
        public TaskPosition? GetTaskPosition(int length, int width, int height, ContainerSize containerSize, List<PlacedBlock> placedBlocks, int edge)
        {
            try
            {
                PlaceBlockService placeBlockService = new PlaceBlockService(containerSize, placedBlocks);
                Point3D? point3D = placeBlockService.PlaceBlock(length, width, height);
                if (point3D == null)
                {
                    return null;
                }
                //放货位置板材中心点
                Point3D putCenter = new Point3D(point3D.Value.X + length / 2, point3D.Value.Y + width / 2, point3D.Value.Z + height / 2);
                //取货位置板材中心点
                Point3D takeCenter = new Point3D(length / 2, width / 2, height / 2);
                //吸盘长530 é—´éš”660  æœ€å¤§920 å¸ç›˜å®½130
                int positionR = 1;
                int takePositionX = 0;
                int takePositionY = 0;
                int takePositionZ = 0;
                int putPositionX = 0;
                int putPositionY = 0;
                int putPositionZ = 0;
                //1.如果长度大于920,宽度大于等于300,则可以使用双吸盘横向吸取
                if (length > 920 && width >= 100)
                {
                    //
                    Point3D deviceCenter = new Point3D(530 / 2, 920 / 2, 0);
                    positionR = 1;
                    takePositionX = (takeCenter.Y - deviceCenter.X);
                    takePositionY = (takeCenter.X - deviceCenter.Y);
                    takePositionZ = 10;
                    putPositionX = (putCenter.Y - deviceCenter.X);
                    putPositionY = (putCenter.X - deviceCenter.Y);
                    putPositionZ = point3D.Value.Z; // putCenter.Z /*+ 10*/;
                }
                else if (length < 450)
                {
                    Point3D deviceCenter = new Point3D(530 / 2, 130 / 2, 0);
                    positionR = 1;
                    takePositionX = (takeCenter.Y - deviceCenter.X);
                    takePositionY = (takeCenter.X - deviceCenter.Y);
                    takePositionZ = 10;
                    putPositionX = (putCenter.Y - deviceCenter.X);
                    putPositionY = (putCenter.X - deviceCenter.Y);
                    putPositionZ = point3D.Value.Z; // putCenter.Z /*+ 10*/;
                }
                else
                {
                    positionR = 0;
                    Point3D deviceCenter = new Point3D(130 / 2, 530 / 2, 0);
                    takePositionX = (takeCenter.Y - deviceCenter.X);
                    takePositionY = (takeCenter.X - deviceCenter.Y);
                    takePositionZ = 10;
                    putPositionX = (putCenter.Y - deviceCenter.X);
                    putPositionY = (putCenter.X - deviceCenter.Y);
                    putPositionZ = point3D.Value.Z; //putCenter.Z /*+ 10*/;
                }
                if (positionR == 1 && takePositionY < 155)
                {
                    takePositionY = 0;
                    putPositionY = point3D.Value.X + 155;
                }
                else if (positionR == 1 && takePositionY >= 880)
                {
                    takePositionY = 880 - 155;
                    putPositionY = 880;
                }
                else
                {
                    takePositionY -= 155;
                }
                if (positionR == 0 && takePositionY < 350)
                {
                    takePositionY = 0;
                    putPositionY = point3D.Value.X + 350;
                }
                else if (positionR == 0 && takePositionY >= 350 && takePositionY <= 880)
                {
                    takePositionY -= 350;
                }
                else if (positionR == 0 && takePositionY >= 880)
                {
                    takePositionY = 880 - 350;
                    putPositionY = 880;
                }
                if (putPositionX < -20)
                {
                    takePositionX = -40;
                    //point3D.X += -20;
                    putPositionX = point3D.Value.Y - 40;
                }
                TaskPosition taskPosition = new TaskPosition()
                {
                    PositionR = positionR,
                    TakePositionX = takePositionX,
                    TakePositionY = takePositionY,
                    TakePositionZ = takePositionZ,
                    PutPositionX = putPositionX,
                    PutPositionY = putPositionY,
                    PutPositionZ = putPositionZ,
                    TakeCenterPositionX = takeCenter.X,
                    TakeCenterPositionY = takeCenter.Y,
                    TakeCenterPositionZ = takeCenter.Z,
                    PutCenterPositionX = putCenter.X,
                    PutCenterPositionY = putCenter.Y,
                    PutCenterPositionZ = putCenter.Z,
                    PositionX = point3D.Value.X,
                    PositionY = point3D.Value.Y,
                    PositionZ = point3D.Value.Z
                };
                TaskPosition? taskPosition = placeBlockService.PlaceBlock(length, width, height, edge);
                return taskPosition;
            }
            catch (Exception ex)
@@ -163,156 +106,196 @@
            }
        }
        //public TaskPosition? GetPosition(string orderNo, int length, int width, int height)
        //{
        //    List<Dt_OrderContainer> containerInfos = new List<Dt_OrderContainer>();
        //    List<Dt_OrderContainer> orderContainers = Db.Queryable<Dt_OrderContainer>().Where(it => it.OrderNo == orderNo).ToList();
        //    if (orderContainers != null && orderContainers.Count > 0)
        //    {
        //        containerInfos = orderContainers;
        //        if (containerInfos.Count == 1)
        //        {
        //            Dt_Container container = Db.Queryable<Dt_Container>().OrderBy(x => x.ContainerSort).First(x => x.ContainerStatus == ContainerStatusEnum.Empty.ObjToInt() && x.ContainerType == ContainerTypeEnum.PutContainer.ObjToInt() && x.ContainerEnable);
        //            if (container != null)
        //            {
        //                Dt_OrderContainer containerInfo = _mapper.Map<Dt_OrderContainer>(container);
        //                containerInfos.Add(containerInfo);
        //            }
        //            else
        //            {
        //                Dt_Container containerItem = Db.Queryable<Dt_Container>().Where(x => x.ContainerStatus == ContainerStatusEnum.NonEmpty.ObjToInt() && x.ContainerType == ContainerTypeEnum.PutContainer.ObjToInt() && x.ContainerEnable).Includes(x => x.Items).OrderByDescending(x => x.Items.Count).First();
        //                if (containerItem != null)
        //                {
        //                    if (LightStatusStorage.LightStatusDic.TryGetValue(containerItem.ContainerCode, out LightStatusEnum lightStatus))
        //                    {
        //                        if (lightStatus != LightStatusEnum.ReadyRelease)
        //                        {
        //                            LightStatusStorage.LightStatusDic[containerItem.ContainerCode] = LightStatusEnum.ReadyRelease;
        //                            Dt_OrderContainer containerInfo = _mapper.Map<Dt_OrderContainer>(containerItem);
        //                            containerInfos.Add(containerInfo);
        //                        }
        //                    }
        //                }
        //                else
        //                {
        //                    throw new Exception($"未找到可放货位置,请检查数据是否已添加或者工位被禁用");
        //                }
        //            }
        //        }
        //    }
        //    else
        //    {
        //        Dt_Container container = Db.Queryable<Dt_Container>().OrderBy(x => x.ContainerSort).First(x => x.ContainerStatus == ContainerStatusEnum.Empty.ObjToInt() && x.ContainerType == ContainerTypeEnum.PutContainer.ObjToInt() && x.ContainerEnable);
        //        if (container != null)
        //        {
        //            containerInfos.Add(_mapper.Map<Dt_OrderContainer>(container));
        //        }
        //        else
        //        {
        //            Dt_Container containerItem = Db.Queryable<Dt_Container>().Where(x => x.ContainerStatus == ContainerStatusEnum.NonEmpty.ObjToInt() && x.ContainerType == ContainerTypeEnum.PutContainer.ObjToInt() && x.ContainerEnable).Includes(x => x.Items).OrderByDescending(x => x.Items.Count()).First();
        //            if (containerItem != null)
        //            {
        //                if (LightStatusStorage.LightStatusDic.TryGetValue(containerItem.ContainerCode, out LightStatusEnum lightStatus))
        //                {
        //                    if (lightStatus != LightStatusEnum.ReadyRelease)
        //                    {
        //                        LightStatusStorage.LightStatusDic[containerItem.ContainerCode] = LightStatusEnum.ReadyRelease;
        //                        Dt_OrderContainer containerInfo = _mapper.Map<Dt_OrderContainer>(containerItem);
        //                        containerInfos.Add(containerInfo);
        //                    }
        //                }
        //            }
        //            else
        //            {
        //                throw new Exception($"未找到可放货位置,请检查数据是否已添加或者工位被禁用");
        //            }
        //        }
        //    }
        //    {
        //        List<Dt_Container> containers = Db.Queryable<Dt_Container>().Where(it => containerInfos.Any(x => x.ContainerId == it.Id && x.ContainerCode == it.ContainerCode) && it.ContainerEnable).Includes(x => x.Items).ToList().OrderBy(x => x.ContainerSort).ToList();
        //        foreach (var container in containers)
        //        {
        //            List<PlacedBlock> placedBlocks = new List<PlacedBlock>();
        //            foreach (var item in container.Items)
        //            {
        //                Point3D point3D = new Point3D(item.ItemRelaPositionX, item.ItemRelaPositionY, item.ItemRelaPositionZ);
        //                placedBlocks.Add(new PlacedBlock(point3D, item.ItemLength, item.ItemWidth, item.ItemHeight));
        //            }
        //            Dt_OrderContainer? orderContainer = containerInfos.FirstOrDefault(x => x.ContainerId == x.Id && x.ContainerCode == x.ContainerCode);
        //            int containerLength = container.ContainerLength;
        //            if (length < lengthThreshold)
        //            {
        //                containerLength = lengthThreshold;
        //            }
        //            ContainerSize containerSize = new ContainerSize(containerLength, container.ContainerWidth, container.ContainerHeight);
        //            TaskPosition? taskPosition = GetTaskPosition(length, width, height, containerSize, placedBlocks);
        //            if (taskPosition != null)
        //            {
        //                taskPosition.PutPosition = container.ContainerCode;
        //                return taskPosition;
        //            }
        //            throw new Exception("10001");
        //        }
        //    }
        //    return null;
        //}
        public TaskPosition? GetPosition(string orderNo, int length, int width, int height)
        /// <summary>
        /// èŽ·å–å¼‚å¸¸å·¥ä½ä½ç½®
        /// </summary>
        /// <param name="length">物品长度</param>
        /// <param name="width">物品宽度</param>
        /// <param name="height">物品高度</param>
        /// <returns>元组包含三个值:是否成功获取、任务位置对象(失败时为null)、错误信息(成功时为空)</returns>
        /// <remarks>
        /// å½“异常容器中物品数量≥5时,使用固定Z轴位置99;否则根据当前物品数量计算位置
        /// </remarks>
        public (bool, TaskPosition?, string) GetExceptionPosition(int length, int width, int height)
        {
            TaskPosition? taskPosition = GetPositionByOrder(orderNo, length, width, height);
            Dt_Container? container = Db.Queryable<Dt_Container>().Where(x => x.ContainerType == ContainerTypeEnum.ExceptionContainer.ObjToInt()).Includes(x => x.Items).First();
            if (container == null)
            {
                return (false, null, "请配置异常工位");
            }
            if (container.Items.Count >= 5)
            {
                ContainerSize containerSize = new ContainerSize(container.ContainerLength, container.ContainerWidth, container.ContainerHeight);
                ExceptionPlaceBlockService exceptionPlaceBlockService = new ExceptionPlaceBlockService(containerSize);
                TaskPosition taskPosition = exceptionPlaceBlockService.ExceptionPlaceBlock(length, width, height, 0);
                taskPosition.TakeCenterPositionZ = 99;
                taskPosition.PutPosition = container.ContainerCode;
                if (LightStatusStorage.LightStatusDic.ContainsKey(container.ContainerCode))
                {
                    LightStatusStorage.LightStatusDic[container.ContainerCode] = LightStatusEnum.LightError;
                }
                return (true, taskPosition, "");
            }
            else
            {
                ContainerSize containerSize = new ContainerSize(container.ContainerLength, container.ContainerWidth, container.ContainerHeight);
                ExceptionPlaceBlockService exceptionPlaceBlockService = new ExceptionPlaceBlockService(containerSize);
                TaskPosition taskPosition = exceptionPlaceBlockService.ExceptionPlaceBlock(length, width, height, container.Items.Count);
                taskPosition.PutPosition = container.ContainerCode;
                return (true, taskPosition, "");
            }
        }
        /// <summary>
        /// æ ¹æ®è®¢å•信息或尺寸获取任务位置
        /// </summary>
        /// <param name="orderId">订单ID</param>
        /// <param name="orderNo">订单编号</param>
        /// <param name="length">长度</param>
        /// <param name="width">宽度</param>
        /// <param name="height">高度</param>
        /// <returns>
        /// è¿”回元组包含三个值: <br/>
        /// Item1 - æ˜¯å¦æˆåŠŸèŽ·å–ä½ç½® <br/>
        /// Item2 - èŽ·å–åˆ°çš„ä»»åŠ¡ä½ç½®å¯¹è±¡ï¼Œå¯èƒ½ä¸ºnull <br/>
        /// Item3 - é”™è¯¯ä»£ç ï¼ŒæˆåŠŸæ—¶è¿”å›žç©ºå­—ç¬¦ä¸²
        /// </returns>
        public (bool, TaskPosition?, string) GetPosition(int orderId, string orderNo, int length, int width, int height)
        {
            TaskPosition? taskPosition = GetPositionByOrder(orderId, orderNo, length, width, height);
            if (taskPosition != null)
            {
                return taskPosition;
                return (true, taskPosition, "");
            }
            taskPosition = GetPosition(length, width, height);
            if (taskPosition != null)
            {
                return taskPosition;
                return (true, taskPosition, "");
            }
            throw new Exception("10001");
            return (false, null, "10001");
        }
        /// <summary>
        /// æ ¹æ®ç‰©å“å°ºå¯¸èŽ·å–åˆé€‚çš„å®¹å™¨ä½ç½®
        /// </summary>
        /// <param name="length">物品长度</param>
        /// <param name="width">物品宽度</param>
        /// <param name="height">物品高度</param>
        /// <returns>返回找到的任务位置信息,包含容器编码;若未找到合适位置则返回null</returns>
        /// <remarks>
        /// è¯¥æ–¹æ³•会查询所有可用空容器,并根据物品尺寸和容器状态判断是否适合放置。 <br/>
        /// å¯¹äºŽè¶…大物品(长或宽超过1600)或有特殊要求的容器会进行特殊处理。
        /// </remarks>
        public TaskPosition? GetPosition(int length, int width, int height)
        {
            Dt_Container container = Db.Queryable<Dt_Container>().OrderBy(x => x.ContainerSort).First(x => x.ContainerStatus == ContainerStatusEnum.Empty.ObjToInt() && x.ContainerType == ContainerTypeEnum.PutContainer.ObjToInt() && x.ContainerEnable);
            List<PlacedBlock> placedBlocks = new List<PlacedBlock>();
            List<Dt_Container> containers = Db.Queryable<Dt_Container>().Where(x => x.ContainerType == ContainerTypeEnum.PutContainer.ObjToInt()).Includes(x => x.Items).ToList();
            if (container.Items != null && container.Items.Count > 0)
            Dt_Container? container = containers.OrderBy(x => x.ContainerSort).FirstOrDefault(x => x.ContainerStatus == ContainerStatusEnum.Empty.ObjToInt() && x.ContainerEnable);
            List<PlacedBlock> placedBlocks = new List<PlacedBlock>();
            if (container != null)
            {
                foreach (var item in container.Items)
                int edge = 0;
                if (container.ContainerNo == containers.Where(x => x.DeviceCode == container.DeviceCode && x.ContainerType == ContainerTypeEnum.PutContainer.ObjToInt()).Min(x => x.ContainerNo))
                {
                    Point3D point3D = new Point3D(item.ItemRelaPositionX, item.ItemRelaPositionY, item.ItemRelaPositionZ);
                    placedBlocks.Add(new PlacedBlock(point3D, item.ItemLength, item.ItemWidth, item.ItemHeight));
                    edge = 1;
                }
                int containerLength = container.ContainerLength;
                int containerWidth = container.ContainerWidth;
                int maxValue = Math.Max(length, width);
                int minValue = Math.Min(length, width);
                if (minValue > container.ContainerWidth)
                {
                    containerLength = maxValue;
                    containerWidth = minValue;
                }
                ContainerSize containerSize = new ContainerSize(containerLength, containerWidth, container.ContainerHeight);
                TaskPosition? taskPosition = GetTaskPosition(length, width, height, containerSize, placedBlocks, edge);
                if (taskPosition != null)
                {
                    taskPosition.PutPosition = container.ContainerCode;
                    return taskPosition;
                }
            }
            int containerLength = container.ContainerLength;
            if (length < lengthThreshold)
            {
                containerLength = lengthThreshold;
            }
            ContainerSize containerSize = new ContainerSize(containerLength, container.ContainerWidth, container.ContainerHeight);
            TaskPosition? taskPosition = GetTaskPosition(length, width, height, containerSize, placedBlocks);
            if (taskPosition != null)
            {
                taskPosition.PutPosition = container.ContainerCode;
                return taskPosition;
            }
            return null;
        }
        public TaskPosition? GetPositionByOrder(string orderNo, int length, int width, int height)
        /// <summary>
        /// èŽ·å–æŒ‡å®šå®¹å™¨ä¸­çš„å¯ç”¨ä½ç½®
        /// </summary>
        /// <param name="container">目标容器对象</param>
        /// <param name="length">待放置物品长度</param>
        /// <param name="width">待放置物品宽度</param>
        /// <param name="height">待放置物品高度</param>
        /// <returns>元组包含: <br/>
        ///   - bool: æ˜¯å¦æ‰¾åˆ°åˆé€‚位置 <br/>
        ///   - TaskPosition?: æ‰¾åˆ°çš„任务位置信息(可为null) <br/>
        ///   - string: é”™è¯¯ä»£ç (成功时返回空字符串)
        /// </returns>
        /// <remarks>
        /// æ–¹æ³•会检查容器尺寸是否满足物品放置要求, <br/>
        /// å¹¶è€ƒè™‘容器边缘情况计算最佳放置位置
        /// </remarks>
        public (bool, TaskPosition?, string) GetPosition(Dt_Container container, int length, int width, int height)
        {
            List<Dt_OrderContainer> orderContainers = Db.Queryable<Dt_OrderContainer>().Where(it => it.OrderNo == orderNo).ToList();
            List<Dt_Container> containers = Db.Queryable<Dt_Container>().Where(x => x.ContainerType == ContainerTypeEnum.PutContainer.ObjToInt()).Includes(x => x.Items).ToList();
            List<PlacedBlock> placedBlocks = new List<PlacedBlock>();
            if (container != null)
            {
                int edge = 0;
                if (container.ContainerNo == containers.Where(x => x.DeviceCode == container.DeviceCode && x.ContainerType == ContainerTypeEnum.PutContainer.ObjToInt()).Min(x => x.ContainerNo))
                {
                    edge = 1;
                }
                int containerLength = container.ContainerLength;
                int containerWidth = container.ContainerWidth;
                int maxValue = Math.Max(length, width);
                int minValue = Math.Min(length, width);
                if (minValue > container.ContainerWidth)
                {
                    containerLength = maxValue;
                    containerWidth = minValue;
                }
                ContainerSize containerSize = new ContainerSize(containerLength, containerWidth, container.ContainerHeight);
                TaskPosition? taskPosition = GetTaskPosition(length, width, height, containerSize, placedBlocks, edge);
                if (taskPosition != null)
                {
                    taskPosition.PutPosition = container.ContainerCode;
                    return (true, taskPosition, "");
                }
            }
            return (false, null, "10002");
        }
        /// <summary>
        /// æ ¹æ®è®¢å•信息获取可用货位位置
        /// </summary>
        /// <param name="orderId">订单ID</param>
        /// <param name="orderNo">订单编号</param>
        /// <param name="length">物品长度</param>
        /// <param name="width">物品宽度</param>
        /// <param name="height">物品高度</param>
        /// <returns>返回符合条件的任务位置信息,若找不到则返回null</returns>
        /// <remarks>
        /// è¯¥æ–¹æ³•会查询订单关联的容器,并检查每个容器中已放置物品的布局, <br/>
        /// é€šè¿‡ç®—法计算新物品在容器中的最佳放置位置
        /// </remarks>
        public TaskPosition? GetPositionByOrder(int orderId, string orderNo, int length, int width, int height)
        {
            List<Dt_OrderContainer> orderContainers = Db.Queryable<Dt_OrderContainer>().Where(it => it.OrderNo == orderNo && it.OrderId == orderId).ToList();
            if (orderContainers != null && orderContainers.Count > 0)
            {
                List<Dt_Container> containers = Db.Queryable<Dt_Container>().Where(it => orderContainers.Any(x => x.ContainerId == it.Id && x.ContainerCode == it.ContainerCode) && it.ContainerEnable).Includes(x => x.Items).ToList().OrderBy(x => x.ContainerSort).ToList(); ;
                List<Dt_Container> dt_Containers = Db.Queryable<Dt_Container>().ToList();
                List<Dt_Container> containers = dt_Containers.Where(it => orderContainers.Any(x => x.ContainerId == it.Id && x.ContainerCode == it.ContainerCode) && it.ContainerEnable && it.ContainerStatus != ContainerStatusEnum.ReadyRelease.ObjToInt()).ToList().OrderBy(x => x.ContainerSort).ToList();
                for (int i = 0; i < containers.Count; i++)
                {
                    containers[i].Items = Db.Queryable<Dt_ContainerItem>().Where(x => x.ContainerId == containers[i].Id).ToList();
                }
                foreach (var container in containers)
                {
@@ -320,22 +303,32 @@
                    foreach (var item in container.Items)
                    {
                        Point3D point3D = new Point3D(item.ItemRelaPositionX, item.ItemRelaPositionY, item.ItemRelaPositionZ);
                        placedBlocks.Add(new PlacedBlock(point3D, item.ItemLength, item.ItemWidth, item.ItemHeight));
                        int tempLength = item.ItemLength;
                        int tempWidth = item.ItemWidth;
                        if (item.ItemLength < item.ItemWidth)
                        {
                            tempLength = item.ItemWidth;
                            tempWidth = item.ItemLength;
                        }
                        Point3D point3D = new Point3D(item.ItemPositionX, item.ItemPositionY, item.ItemPositionZ);
                        placedBlocks.Add(new PlacedBlock(point3D, tempLength, tempWidth, item.ItemHeight));
                    }
                    Dt_OrderContainer? orderContainer = orderContainers.FirstOrDefault(x => x.ContainerId == x.Id && x.ContainerCode == x.ContainerCode);
                    int containerLength = container.ContainerLength;
                    if (length < lengthThreshold)
                    Dt_OrderContainer? orderContainer = orderContainers.FirstOrDefault(x => x.ContainerId == container.Id && x.ContainerCode == container.ContainerCode);
                    if (orderContainer == null)
                    {
                        containerLength = lengthThreshold;
                        continue;
                    }
                    else
                    int edge = 0;
                    if (container.ContainerNo == dt_Containers.Where(x => x.DeviceCode == container.DeviceCode && x.ContainerType == ContainerTypeEnum.PutContainer.ObjToInt()).Min(x => x.ContainerNo))
                    {
                        if (orderContainer != null)
                            containerLength = orderContainer.MaxLength;
                        edge = 1;
                    }
                    ContainerSize containerSize = new ContainerSize(containerLength, container.ContainerWidth, container.ContainerHeight);
                    TaskPosition? taskPosition = GetTaskPosition(length, width, height, containerSize, placedBlocks);
                    ContainerSize containerSize = new ContainerSize(orderContainer.MaxLength, orderContainer.MaxWidth, container.ContainerHeight);
                    TaskPosition? taskPosition = GetTaskPosition(length, width, height, containerSize, placedBlocks, edge);
                    if (taskPosition != null)
                    {
                        taskPosition.PutPosition = container.ContainerCode;
@@ -345,7 +338,179 @@
            }
            return null;
        }
        /// <summary>
        /// é‡Šæ”¾æŒ‡å®šå®¹å™¨åŠå…¶å…³è”项
        /// </summary>
        /// <param name="keys">容器ID数组</param>
        /// <returns>操作结果响应</returns>
        /// <remarks>
        /// 1. æŸ¥è¯¢å¹¶èŽ·å–æŒ‡å®šå®¹å™¨åŠå…¶å…³è”é¡¹ <br/>
        /// 2. æ›´æ–°å®¹å™¨çŠ¶æ€ä¸ºç©ºé—² <br/>
        /// 3. åœ¨äº‹åŠ¡ä¸­æ‰§è¡Œä»¥ä¸‹æ“ä½œï¼š <br/>
        ///    - åˆ é™¤å®¹å™¨é¡¹å¹¶ç§»å…¥åŽ†å²è¡¨ <br/>
        ///    - åˆ é™¤è®¢å•容器关联并移入历史表 <br/>
        ///    - æ›´æ–°å®¹å™¨çŠ¶æ€ <br/>
        /// 4. æ“ä½œæˆåŠŸè¿”å›žOK,失败回滚事务并返回错误信息
        /// </remarks>
        public WebResponseContent ReleaseContainer(int[] keys)
        {
            try
            {
                List<Dt_Container> containers = Db.Queryable<Dt_Container>().Where(x => keys.Contains(x.Id)).Includes(x => x.Items).ToList();
                List<Dt_ContainerItem> containerItems = new List<Dt_ContainerItem>();
                List<Dt_OrderContainer> orderContainers = Db.Queryable<Dt_OrderContainer>().Where(x => containers.Select(x => x.Id).ToList().Contains(x.ContainerId)).ToList();
                for (int i = 0; i < containers.Count; i++)
                {
                    containers[i].ContainerStatus = ContainerStatusEnum.Empty.ObjToInt();
                    containerItems.AddRange(containers[i].Items);
                }
                _unitOfWorkManage.BeginTran();
                _containerItemRepository.DeleteAndMoveIntoHty(containerItems, App.User?.UserId > 0 ? WIDESEAWCS_Core.Enums.OperateTypeEnum.人工删除 : WIDESEAWCS_Core.Enums.OperateTypeEnum.自动删除);
                _orderContainerRepository.DeleteAndMoveIntoHty(orderContainers, App.User?.UserId > 0 ? WIDESEAWCS_Core.Enums.OperateTypeEnum.人工删除 : WIDESEAWCS_Core.Enums.OperateTypeEnum.自动删除);
                Db.Updateable(containers).ExecuteCommand();
                _unitOfWorkManage.CommitTran();
                return WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
            {
                _unitOfWorkManage.RollbackTran();
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        public WebResponseContent AutoReleaseContainer(int[] keys)
        {
            try
            {
                List<Dt_Container> containers = Db.Queryable<Dt_Container>().Where(x => keys.Contains(x.Id)).Includes(x => x.Items).ToList();
                for (int i = 0; i < containers.Count; i++)
                {
                    AutoReleaseContainer(containers[i].ContainerCode);
                }
                return WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
        /// <summary>
        /// è‡ªåŠ¨é‡Šæ”¾å®¹å™¨
        /// </summary>
        /// <param name="containerCode">容器编号</param>
        /// <returns>Web响应结果</returns>
        /// <remarks>
        /// 1. æ ¹æ®å®¹å™¨ç¼–号查询容器信息 <br/>
        /// 2. æ£€æŸ¥å®¹å™¨æ˜¯å¦å­˜åœ¨å…³è”任务 <br/>
        /// 3. è‹¥æ— ä»»åŠ¡åˆ™æ¸…ç©ºå®¹å™¨çŠ¶æ€å¹¶åˆ é™¤è®¢å•å®¹å™¨è®°å½• <br/>
        /// 4. è‹¥æœ‰ä»»åŠ¡åˆ™æ›´æ–°ä»»åŠ¡çŠ¶æ€ä¸º"龙门架重新分配" <br/>
        /// 5. äº‹åŠ¡å¤„ç†æ‰€æœ‰æ•°æ®åº“æ“ä½œ
        /// </remarks>
        public WebResponseContent AutoReleaseContainer(string containerCode)
        {
            try
            {
                Dt_Container container = BaseDal.QueryFirst(x => x.ContainerCode == containerCode);
                if (container == null)
                {
                    return WebResponseContent.Instance.Error("容器不存在");
                }
                if (container.ContainerStatus == ContainerStatusEnum.Empty.ObjToInt())
                {
                    return WebResponseContent.Instance.Error("容器已处于空闲状态");
                }
                if (container.ContainerType == ContainerTypeEnum.ExceptionContainer.ObjToInt())
                {
                    if (container.Items != null && container.Items.Count > 0)
                    {
                        _containerItemRepository.DeleteAndMoveIntoHty(container.Items, App.User?.UserId > 0 ? WIDESEAWCS_Core.Enums.OperateTypeEnum.人工删除 : WIDESEAWCS_Core.Enums.OperateTypeEnum.自动删除);
                    }
                    return WebResponseContent.Instance.OK("异常工位已释放");
                }
                List<Dt_Task> tasks = _taskRepository.QueryData(x => x.NextAddress.Contains(container.ContainerCode));
                Dt_OrderContainer orderContainer = _orderContainerRepository.QueryFirst(x => x.ContainerCode == container.ContainerCode && x.ContainerId == container.Id);
                if (tasks != null && tasks.Count > 0)
                {
                    List<string> codes = tasks.Select(x => x.PalletCode).ToList();
                    container.Items = _containerItemRepository.QueryData(x => x.ContainerId == container.Id && !codes.Contains(x.ItemCode));
                    if (container.ContainerType == ContainerTypeEnum.ExceptionContainer.ObjToInt())
                    {
                        tasks.ForEach(x =>
                        {
                            if (x.TaskState == TaskStatusEnum.Gantry_BeRelease.ObjToInt())
                            {
                                x.TaskState = TaskStatusEnum.Gantry_New.ObjToInt();
                            }
                        });
                    }
                    else
                    {
                        tasks.ForEach(x =>
                        {
                            if (x.TaskState == TaskStatusEnum.Gantry_Wait.ObjToInt())
                            {
                                x.TaskState = TaskStatusEnum.Gantry_BeReassign.ObjToInt();
                            }
                        });
                    }
                }
                else
                {
                    container.Items = _containerItemRepository.QueryData(x => x.ContainerId == container.Id);
                }
                _unitOfWorkManage.BeginTran();
                if (container.Items != null && container.Items.Count > 0)
                {
                    _containerItemRepository.DeleteAndMoveIntoHty(container.Items, App.User?.UserId > 0 ? WIDESEAWCS_Core.Enums.OperateTypeEnum.人工删除 : WIDESEAWCS_Core.Enums.OperateTypeEnum.自动删除);
                }
                if (tasks == null || tasks.Count == 0)
                {
                    container.ContainerStatus = ContainerStatusEnum.Empty.ObjToInt();
                    BaseDal.UpdateData(container);
                    if (orderContainer != null)
                    {
                        _orderContainerRepository.DeleteAndMoveIntoHty(orderContainer, App.User?.UserId > 0 ? WIDESEAWCS_Core.Enums.OperateTypeEnum.人工删除 : WIDESEAWCS_Core.Enums.OperateTypeEnum.自动删除);
                    }
                }
                else
                {
                    orderContainer.MaxLength = container.ContainerLength;
                    orderContainer.MaxWidth = container.ContainerWidth;
                    _orderContainerRepository.UpdateData(orderContainer);
                    _taskRepository.UpdateData(tasks);
                }
                _unitOfWorkManage.CommitTran();
                //_webSocketServer发送数据
                _webSocketServer.PublishAllClientPayload(new
                {
                    stationCode = container.ContainerCode,
                    release = 1,
                }.Serialize());
                return WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
            {
                _unitOfWorkManage.RollbackTran();
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
    }
}