using System; using System.Collections.Generic; using System.Linq; 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 { /// /// 容器服务类,提供容器相关的业务逻辑操作 /// /// /// 主要功能包括:
/// 1. 获取物品在容器中的放置位置
/// 2. 处理异常工位的位置分配
/// 3. 根据订单或尺寸获取合适的位置
/// 4. 释放容器资源
/// 使用依赖注入方式获取仓储接口和工作单元管理 ///
public class ContainerService : ServiceBase, IContainerService { /// /// 用于对象映射的映射器实例 /// private readonly IMapper _mapper; /// /// 工作单元管理接口实例,用于管理数据库事务和工作单元 /// private readonly IUnitOfWorkManage _unitOfWorkManage; /// /// 容器物品仓储接口实例 /// private readonly IContainerItemRepository _containerItemRepository; /// /// 订单容器仓储接口实例 /// private readonly IOrderContainerRepository _orderContainerRepository; /// /// 任务仓储接口实例,用于操作任务数据 /// private readonly ITaskRepository _taskRepository; /// /// WebSocket服务器实例,用于处理实时通信 /// private readonly WebSocketServer _webSocketServer; /// /// 容器服务构造函数 /// /// 容器仓储接口 /// 对象映射器 /// 工作单元管理器 /// 容器项仓储接口 /// 订单容器仓储接口 /// 任务仓储接口 /// WebSocket服务实例 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; } /// /// 获取任务位置信息 /// /// 物品长度 /// 物品宽度 /// 物品高度 /// 容器尺寸 /// 已放置块列表 /// 边缘参数 /// 返回任务位置信息,若放置失败则返回null /// 当放置过程中发生错误时抛出异常 public TaskPosition? GetTaskPosition(int length, int width, int height, ContainerSize containerSize, List placedBlocks, int edge) { try { PlaceBlockService placeBlockService = new PlaceBlockService(containerSize, placedBlocks); TaskPosition? taskPosition = placeBlockService.PlaceBlock(length, width, height, edge); return taskPosition; } catch (Exception ex) { throw new Exception(ex.Message); } } /// /// 获取异常工位位置 /// /// 物品长度 /// 物品宽度 /// 物品高度 /// 元组包含三个值:是否成功获取、任务位置对象(失败时为null)、错误信息(成功时为空) /// /// 当异常容器中物品数量≥5时,使用固定Z轴位置99;否则根据当前物品数量计算位置 /// public (bool, TaskPosition?, string) GetExceptionPosition(int length, int width, int height) { Dt_Container? container = Db.Queryable().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, ""); } } /// /// 根据订单信息或尺寸获取任务位置 /// /// 订单ID /// 订单编号 /// 长度 /// 宽度 /// 高度 /// /// 返回元组包含三个值:
/// Item1 - 是否成功获取位置
/// Item2 - 获取到的任务位置对象,可能为null
/// Item3 - 错误代码,成功时返回空字符串 ///
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 (true, taskPosition, ""); } taskPosition = GetPosition(length, width, height); if (taskPosition != null) { return (true, taskPosition, ""); } return (false, null, "10001"); } /// /// 根据物品尺寸获取合适的容器位置 /// /// 物品长度 /// 物品宽度 /// 物品高度 /// 返回找到的任务位置信息,包含容器编码;若未找到合适位置则返回null /// /// 该方法会查询所有可用空容器,并根据物品尺寸和容器状态判断是否适合放置。
/// 对于超大物品(长或宽超过1600)或有特殊要求的容器会进行特殊处理。 ///
public TaskPosition? GetPosition(int length, int width, int height) { List containers = Db.Queryable().Where(x => x.ContainerType == ContainerTypeEnum.PutContainer.ObjToInt()).Includes(x => x.Items).ToList(); Dt_Container? container = containers.OrderBy(x => x.ContainerSort).FirstOrDefault(x => x.ContainerStatus == ContainerStatusEnum.Empty.ObjToInt() && x.ContainerEnable); List placedBlocks = new List(); 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 taskPosition; } } return null; } /// /// 获取指定容器中的可用位置 /// /// 目标容器对象 /// 待放置物品长度 /// 待放置物品宽度 /// 待放置物品高度 /// 元组包含:
/// - bool: 是否找到合适位置
/// - TaskPosition?: 找到的任务位置信息(可为null)
/// - string: 错误代码(成功时返回空字符串) ///
/// /// 方法会检查容器尺寸是否满足物品放置要求,
/// 并考虑容器边缘情况计算最佳放置位置 ///
public (bool, TaskPosition?, string) GetPosition(Dt_Container container, int length, int width, int height) { List containers = Db.Queryable().Where(x => x.ContainerType == ContainerTypeEnum.PutContainer.ObjToInt()).Includes(x => x.Items).ToList(); List placedBlocks = new List(); 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"); } /// /// 根据订单信息获取可用货位位置 /// /// 订单ID /// 订单编号 /// 物品长度 /// 物品宽度 /// 物品高度 /// 返回符合条件的任务位置信息,若找不到则返回null /// /// 该方法会查询订单关联的容器,并检查每个容器中已放置物品的布局,
/// 通过算法计算新物品在容器中的最佳放置位置 ///
public TaskPosition? GetPositionByOrder(int orderId, string orderNo, int length, int width, int height) { List orderContainers = Db.Queryable().Where(it => it.OrderNo == orderNo && it.OrderId == orderId).ToList(); if (orderContainers != null && orderContainers.Count > 0) { List dt_Containers = Db.Queryable().ToList(); List 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().Where(x => x.ContainerId == containers[i].Id).ToList(); } foreach (var container in containers) { List placedBlocks = new List(); foreach (var item in container.Items) { 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 == container.Id && x.ContainerCode == container.ContainerCode); if (orderContainer == null) { continue; } int edge = 0; if (container.ContainerNo == dt_Containers.Where(x => x.DeviceCode == container.DeviceCode && x.ContainerType == ContainerTypeEnum.PutContainer.ObjToInt()).Min(x => x.ContainerNo)) { edge = 1; } 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; return taskPosition; } } } return null; } /// /// 释放指定容器及其关联项 /// /// 容器ID数组 /// 操作结果响应 /// /// 1. 查询并获取指定容器及其关联项
/// 2. 更新容器状态为空闲
/// 3. 在事务中执行以下操作:
/// - 删除容器项并移入历史表
/// - 删除订单容器关联并移入历史表
/// - 更新容器状态
/// 4. 操作成功返回OK,失败回滚事务并返回错误信息 ///
public WebResponseContent ReleaseContainer(int[] keys) { try { List containers = Db.Queryable().Where(x => keys.Contains(x.Id)).Includes(x => x.Items).ToList(); List containerItems = new List(); List orderContainers = Db.Queryable().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 containers = Db.Queryable().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); } } /// /// 自动释放容器 /// /// 容器编号 /// Web响应结果 /// /// 1. 根据容器编号查询容器信息
/// 2. 检查容器是否存在关联任务
/// 3. 若无任务则清空容器状态并删除订单容器记录
/// 4. 若有任务则更新任务状态为"龙门架重新分配"
/// 5. 事务处理所有数据库操作 ///
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 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 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); } } } }