xiazhengtongxue
2026-04-01 a9edf162ac5dd98719c2f93ab0800c98673fd220
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_AGV.cs
@@ -14,13 +14,12 @@
{
    public partial class TaskService
    {
        #region 极卷库任务模块
        public string AGV_OutTaskComplete = WIDESEA_Core.Helper.AppSettings.Configuration["AGV_OutTaskComplete"];
        public string WCS_ReceiveTask = WIDESEA_Core.Helper.AppSettings.Configuration["WCS_ReceiveTask"];
        /// <summary>
        /// 出入库申请。
        /// 极卷库出入库申请
        /// </summary>
        public async Task<AGVResponse> ApplyInOutAsync(ApplyInOutDto applyInOutDto)
        {
@@ -32,7 +31,7 @@
                if (validationMessage != null)
                    return response.Error(validationMessage);
                var existingTask = await BaseDal.QueryFirstAsync(x => x.PalletCode == applyInOutDto.TrayNumber);
                var existingTask = await BaseDal.QueryFirstAsync(x => x.PalletCode == applyInOutDto.TrayNumber || x.OrderNo == applyInOutDto.TaskId);
                if (existingTask != null)
                    return response.Error($"WMS已有当前任务,不可重复下发,任务号:{applyInOutDto.TaskId}");
@@ -61,7 +60,7 @@
        }
        /// <summary>
        /// 手动出库完成反馈给AGV。
        /// 手动出库完成反馈给AGV
        /// </summary>
        public async Task<WebResponseContent> OutTaskComplete(OutTaskCompleteDto outTaskCompleteDto)
        {
@@ -83,7 +82,7 @@
                    return response.Error(httpResponse?.Msg ?? "AGV接口调用异常");
                if (!httpResponse.Code)
                    return response.Error(string.IsNullOrWhiteSpace(httpResponse.Msg) ? "AGV接口调用失败" : httpResponse.Msg);
                        return response.Error(string.IsNullOrWhiteSpace(httpResponse.Msg) ? "AGV接口调用失败" : httpResponse.Msg);
                var syncResult = await CompleteLocalOutboundAfterAgvAckAsync(task);
                return syncResult.Status ? response.OK(httpResponse.Msg) : syncResult;
@@ -96,7 +95,7 @@
        }
        /// <summary>
        /// 输送线申请进入。
        /// 输送线申请进入
        /// </summary>
        public async Task<AGVResponse> ApplyEnterAsync(ApplyEnterDto applyEnterDto)
        {
@@ -124,7 +123,7 @@
        }
        /// <summary>
        /// 取放货完成。
        /// 取放货完成
        /// </summary>
        public async Task<AGVResponse> TaskCompleteAsync(TaskCompleteDto taskCompleteDto)
        {
@@ -152,7 +151,7 @@
        }
        /// <summary>
        /// 任务取消。
        /// 任务取消
        /// </summary>
        public async Task<AGVResponse> TaskCancelAsync(TaskCancelDto taskCancelDto)
        {
@@ -183,6 +182,7 @@
            }
        }
        #region 参数验证
        private static string? ValidateApplyInOutRequest(ApplyInOutDto dto)
        {
            if (dto == null) return "请求参数不能为空";
@@ -231,7 +231,10 @@
            if (string.IsNullOrWhiteSpace(dto.TaskId)) return "任务号不能为空";
            return null;
        }
        #endregion 参数验证
        #region 具体实现
        // 出入库共用创建任务
        private Dt_Task BuildAgvTask(ApplyInOutDto dto)
        {
            var task = new Dt_Task
@@ -265,6 +268,7 @@
            return task;
        }
        // 构建返回AGV出入库请求体
        private AGVDataDto BuildAgvDataDto(Dt_Task task, ApplyInOutDto dto)
        {
            return new AGVDataDto
@@ -287,6 +291,7 @@
            };
        }
        // 入库创建
        private async Task<AGVResponse?> CreateAgvInboundTaskAsync(Dt_Task task, ApplyInOutDto dto)
        {
            AGVResponse response = new AGVResponse();
@@ -302,6 +307,7 @@
            return addResult ? null : response.Error("入库任务创建失败");
        }
        // 出库创建
        private async Task<AGVResponse?> CreateAgvOutboundTaskAsync(Dt_Task task, ApplyInOutDto dto)
        {
            AGVResponse response = new AGVResponse();
@@ -309,13 +315,13 @@
            if (stockInfo == null)
                return response.Error($"未找到托盘{dto.TrayNumber}的库存信息");
            if (stockInfo.WarehouseId != dto.YinYang)
                return response.Error($"托盘{dto.TrayNumber}不属于当前{(dto.YinYang == 1 ? "阴极" : "阳极")}");
            //if (stockInfo.WarehouseId != dto.YinYang)
            //    return response.Error($"托盘{dto.TrayNumber}不属于当前{(dto.YinYang == 1 ? "阴极" : "阳极")}");
            if (stockInfo.StockStatus != (int)StockStatusEmun.入库完成)
                return response.Error($"托盘{dto.TrayNumber}正在移动中,请稍后!");
            var locationInfo = await _locationInfoService.GetLocationInfoAsync(stockInfo.LocationCode);
            var locationInfo = await _locationInfoService.GetLocationInfo(stockInfo.LocationCode);
            if (locationInfo == null)
                return response.Error($"未找到托盘{stockInfo.LocationCode}的货位信息");
@@ -327,6 +333,14 @@
            task.SourceAddress = stockInfo.LocationCode;
            task.CurrentAddress = stockInfo.LocationCode;
            task.TargetAddress = dto.YinYang == 1 ? "D10020" : "D10090";
            var wmsTaskDto = _mapper.Map<WMSTaskDTO>(task);
            var taskList = new List<WMSTaskDTO> { wmsTaskDto };
            var requestBody = JsonSerializer.Serialize(taskList);
            var httpResponse = _httpClientHelper.Post<WebResponseContent>(WCS_ReceiveTask, requestBody);
            if (httpResponse == null || httpResponse.Data == null || !httpResponse.Data.Status)
                return response.Error(httpResponse?.Data?.Message ?? "下发WCS失败");
            stockInfo.StockStatus = (int)StockStatusEmun.出库锁定;
            locationInfo.LocationStatus = (int)LocationStatusEnum.InStockLock;
@@ -340,34 +354,22 @@
                _unitOfWorkManage.RollbackTran();
                return response.Error("出库任务创建失败");
            }
            _unitOfWorkManage.CommitTran();
            return null;
        }
        private async Task<WebResponseContent> CompleteLocalOutboundAfterAgvAckAsync(Dt_Task task)
        {
            var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode);
            if (stockInfo == null)
                return WebResponseContent.Instance.Error($"未找到托盘{task.PalletCode}的库存信息");
            var locationInfo = await _locationInfoService.GetLocationInfoAsync(stockInfo.LocationCode);
            if (locationInfo == null)
                return WebResponseContent.Instance.Error($"未找到托盘{stockInfo.LocationCode}的货位信息");
            if (stockInfo.StockStatus != (int)StockStatusEmun.出库锁定 || locationInfo.LocationStatus != (int)LocationStatusEnum.InStockLock)
                return WebResponseContent.Instance.Error($"当前库存{stockInfo.StockStatus}或者货位{locationInfo.LocationStatus}状态信息错误");
            locationInfo.LocationStatus = (int)LocationStatusEnum.Free;
            task.TaskStatus = (int)TaskOutStatusEnum.Line_OutFinish;
            _unitOfWorkManage.BeginTran();
            var deleteTaskResult = BaseDal.DeleteData(task);
            var updateLocationResult = _locationInfoService.UpdateData(locationInfo);
            var deleteStockResult = _stockInfoService.DeleteData(stockInfo);
            if (!deleteTaskResult || !updateLocationResult.Status || !deleteStockResult.Status)
            var updateResult = BaseDal.UpdateData(task);
            if (!updateResult)
            {
                _unitOfWorkManage.RollbackTran();
                return WebResponseContent.Instance.Error("AGV完成回传后,本地任务/库存/货位更新失败");
                return WebResponseContent.Instance.Error("AGV完成回传后,任务更新失败");
            }
            _unitOfWorkManage.CommitTran();
@@ -376,11 +378,62 @@
        private bool CanApplyEnter(Dt_Task task, ApplyEnterDto dto)
        {
            return dto.InOut == 1
                ? task.TaskType == (int)TaskInboundTypeEnum.Inbound && task.TaskStatus == (int)TaskInStatusEnum.InNew
                : task.TaskType == (int)TaskOutboundTypeEnum.Outbound && task.TaskStatus == (int)TaskStatusEnum.Line_Finish;
            if (dto.InOut == 1)
            {
                var hasExecutingOutTask = BaseDal.QueryFirst(x => x.TaskType == (int)TaskOutboundTypeEnum.Outbound
                    && x.TargetAddress == task.SourceAddress
                    && (x.TaskStatus == (int)TaskOutStatusEnum.SC_OutExecuting
                        || x.TaskStatus == (int)TaskOutStatusEnum.Line_OutExecuting));
                // 如果没有正在执行的出库任务,则允许入库
                return hasExecutingOutTask == null;
            }
            else
            {
                return task.TaskType == (int)TaskOutboundTypeEnum.Outbound
                    && task.TaskStatus == (int)TaskStatusEnum.Line_Finish;
            }
        }
        // WCS入库完成
        private async Task<WebResponseContent> CompleteAgvInboundTaskAsync(CreateTaskDto taskDto)
        {
            WebResponseContent response = new WebResponseContent();
            var task = await BaseDal.QueryFirstAsync(x => x.PalletType == taskDto.PalletType);
            if (task == null)
                return response.Error($"没有当前托盘{taskDto.PalletType}入库任务");
            var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode);
            if (stockInfo == null)
                return response.Error($"未找到托盘{task.PalletCode}的库存信息");
            var locationInfo = await _locationInfoService.GetLocationInfoAsync(task.TargetAddress);
            if (locationInfo == null)
                return response.Error($"未找到货位{task.TargetAddress}的信息");
            if (locationInfo.LocationStatus == (int)LocationStatusEnum.InStock)
                return response.Error($"当前货位{locationInfo.LocationStatus}状态不是空闲状态,无法入库");
            // 更新货位状态为占用
            locationInfo.LocationStatus = (int)LocationStatusEnum.InStock;
            task.TaskStatus = (int)TaskInStatusEnum.InFinish;
            stockInfo.StockStatus = (int)StockStatusEmun.入库完成;
            _unitOfWorkManage.BeginTran();
            var addStockResult = _stockInfoService.UpdateData(stockInfo);
            var updateLocationResult = _locationInfoService.UpdateData(locationInfo);
            BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成);
            if (!addStockResult.Status || !updateLocationResult.Status)
            {
                _unitOfWorkManage.RollbackTran();
                return response.Error("入库完成后,添加库存或货位更新失败");
            }
            _unitOfWorkManage.CommitTran();
            return response.OK();
        }
        // AGV出库完成
        private async Task<AGVResponse> CompleteAgvOutboundTaskAsync(Dt_Task task)
        {
            AGVResponse response = new AGVResponse();
@@ -400,9 +453,9 @@
            _unitOfWorkManage.BeginTran();
            var deleteStockResult = _stockInfoService.DeleteData(stockInfo);
            var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(locationInfo);
            var updateLocationResult = _locationInfoService.UpdateData(locationInfo);
            BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成);
            if (!deleteStockResult.Status || !updateLocationResult)
            if (!deleteStockResult.Status || !updateLocationResult.Status)
            {
                _unitOfWorkManage.RollbackTran();
                return response.Error("出库完成后,本地库存或货位更新失败");
@@ -412,6 +465,7 @@
            return response.OK();
        }
        // AGV已放货,准备输送线入库
        private async Task<AGVResponse> CompleteAgvInboundTaskAsync(Dt_Task task)
        {
            AGVResponse response = new AGVResponse();
@@ -421,12 +475,15 @@
            task.TargetAddress = availableLocation.LocationCode;
            var wcsTaskDto = _mapper.Map<WCSTaskDTO>(task);
            var httpResponse = _httpClientHelper.Post<WebResponseContent>(WCS_ReceiveTask, JsonSerializer.Serialize(wcsTaskDto));
            var wmsTaskDto = _mapper.Map<WMSTaskDTO>(task);
            var taskList = new List<WMSTaskDTO> { wmsTaskDto };
            var requestBody = JsonSerializer.Serialize(taskList);
            var httpResponse = _httpClientHelper.Post<WebResponseContent>(WCS_ReceiveTask, requestBody);
            if (httpResponse == null || httpResponse.Data == null || !httpResponse.Data.Status)
                return response.Error(httpResponse?.Data?.Message ?? "下发WCS失败");
            task.TaskStatus = (int)TaskStatusEnum.Line_Executing;
            task.TaskStatus = (int)TaskInStatusEnum.Line_InExecuting;
            task.Dispatchertime = DateTime.Now;
            var locationInfo = await _locationInfoService.GetLocationInfoAsync(task.TargetAddress);
@@ -435,6 +492,10 @@
            if (locationInfo.LocationStatus != (int)LocationStatusEnum.Free)
                return response.Error($"当前货位{locationInfo.LocationStatus}状态信息错误");
            var existingStock = await _stockInfoService.GetStockInfoAsync(task.PalletCode);
            if (existingStock != null)
                return response.Error($"托盘{task.PalletCode}的库存信息已存在,请勿重复入库");
            Dt_StockInfo stockInfo = new Dt_StockInfo
            {
@@ -462,6 +523,7 @@
            return response.OK();
        }
        // AGV入库取消
        private AGVResponse CancelAgvInboundTask(Dt_Task task)
        {
            AGVResponse response = new AGVResponse();
@@ -473,6 +535,8 @@
            return response.OK();
        }
        // AGV出库取消
        private async Task<AGVResponse> CancelAgvOutboundTaskAsync(Dt_Task task)
        {
            AGVResponse response = new AGVResponse();
@@ -505,6 +569,6 @@
            return response.OK();
        }
        #endregion 极卷库任务模块
        #endregion 具体实现
    }
}
}