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);
}
}
}
}