wanshenmean
2026-03-30 0005d58f6888dd3e4524784d1b6f103f9b1c588e
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
@@ -1,30 +1,24 @@
#region << 版 本 注 释 >>
/*----------------------------------------------------------------
 * 命名空间:WIDESEA_TaskInfoService
 * 创建者:胡童庆
 * 创建时间:2024/8/2 16:13:36
 * 版本:V1.0.0
 * 描述:
 *
 * ----------------------------------------------------------------
 * 修改人:
 * 修改时间:
 * 版本:V1.0.1
 * 修改说明:
 *
 *----------------------------------------------------------------*/
#endregion << 版 本 注 释 >>
using AutoMapper;
using Mapster;
using MapsterMapper;
using Microsoft.Extensions.Configuration;
using SqlSugar;
using System.DirectoryServices.Protocols;
using System.Text.Json;
using WIDESEA_Common.LocationEnum;
using WIDESEA_Common.StockEnum;
using WIDESEA_Common.TaskEnum;
using WIDESEA_Common.WareHouseEnum;
using WIDESEA_Core;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.BaseServices;
using WIDESEA_Core.Core;
using WIDESEA_Core.Enums;
using WIDESEA_Core.Helper;
using WIDESEA_DTO.GradingMachine;
using WIDESEA_DTO.MES;
using WIDESEA_DTO.Stock;
using WIDESEA_DTO.Task;
using WIDESEA_IBasicService;
using WIDESEA_IInboundService;
using WIDESEA_IOutboundService;
using WIDESEA_IRecordService;
using WIDESEA_IStockService;
using WIDESEA_ITaskInfoService;
using WIDESEA_Model.Models;
@@ -34,68 +28,1496 @@
    public partial class TaskService : ServiceBase<Dt_Task, IRepository<Dt_Task>>, ITaskService
    {
        private readonly IMapper _mapper;
        private readonly IStockInfoService _stockInfoService;
        private readonly ILocationInfoService _locationInfoService;
        private readonly HttpClientHelper _httpClientHelper;
        private readonly IConfiguration _configuration;
        private readonly RoundRobinService _roundRobinService;
        private readonly IMesService _mesService;
        private readonly ITask_HtyService _task_HtyService;
        private readonly IStockInfo_HtyService _stockInfo_HtyService;
        private readonly IUnitOfWorkManage _unitOfWorkManage;
        public IRepository<Dt_Task> Repository => BaseDal;
        private Dictionary<string, OrderByType> _taskOrderBy = new()
            {
                {nameof(Dt_Task.Grade),OrderByType.Desc },
                {nameof(Dt_Task.CreateDate),OrderByType.Asc},
            };
        private readonly Dictionary<string, OrderByType> _taskOrderBy = new()
        {
            { nameof(Dt_Task.Grade), OrderByType.Desc },
            { nameof(Dt_Task.CreateDate), OrderByType.Asc },
        };
        public List<int> TaskTypes => typeof(TaskTypeEnum).GetEnumIndexList();
        public List<int> TaskOutboundTypes => typeof(TaskTypeEnum).GetEnumIndexList();
        public TaskService(IRepository<Dt_Task> BaseDal, IMapper mapper, IUnitOfWorkManage unitOfWorkManage) : base(BaseDal)
        public TaskService(
            IRepository<Dt_Task> BaseDal,
            IMapper mapper,
            IStockInfoService stockInfoService,
            ILocationInfoService locationInfoService,
            HttpClientHelper httpClientHelper,
            IConfiguration configuration,
            RoundRobinService roundRobinService,
            IMesService mesService,
            ITask_HtyService task_HtyService,
            IStockInfo_HtyService stockInfo_HtyService,
            IUnitOfWorkManage unitOfWorkManage) : base(BaseDal)
        {
            _mapper = mapper;
            _stockInfoService = stockInfoService;
            _locationInfoService = locationInfoService;
            _httpClientHelper = httpClientHelper;
            _configuration = configuration;
            _roundRobinService = roundRobinService;
            _mesService = mesService;
            _task_HtyService = task_HtyService;
            _stockInfo_HtyService = stockInfo_HtyService;
            _unitOfWorkManage = unitOfWorkManage;
        }
        #region WCS逻辑处理
        /// <summary>
        /// 创建任务(组盘入库任务、空托盘回库任务)
        /// </summary>
        /// <param name="palletCode">托盘号</param>
        /// <param name="sourceAddress">起始地址</param>
        /// <param name="targetAddress">目标地址</param>
        /// <param name="roadway">巷道号</param>
        /// <param name="warehouseId">仓库主键</param>
        /// <param name="palletType">托盘类型</param>
        /// <param name="taskType">任务类型</param>
        /// <returns>是否成功</returns>
        public async Task<Dt_Task?> CreateTaskInboundAsync(CreateTaskDto taskDto)
        public async Task<WebResponseContent> CreateTaskInboundAsync(CreateTaskDto taskDto)
        {
            if (string.IsNullOrWhiteSpace(taskDto.PalletCode) || string.IsNullOrWhiteSpace(taskDto.SourceAddress) || string.IsNullOrWhiteSpace(taskDto.TargetAddress) || string.IsNullOrWhiteSpace(taskDto.Roadway))
            try
            {
                return null;
                WebResponseContent content = await GetTaskByPalletCodeAsync(taskDto.PalletCode);
                if (content.Status)
                {
                    return content;
                }
                if (string.IsNullOrWhiteSpace(taskDto.PalletCode) ||
                    string.IsNullOrWhiteSpace(taskDto.Roadway))
                {
                    return WebResponseContent.Instance.Error("无效的任务详情");
                }
                if (taskDto.TaskType != TaskTypeEnum.Inbound && taskDto.TaskType != TaskTypeEnum.InEmpty)
                {
                    return WebResponseContent.Instance.Error("无效的任务详情");
                }
                // 使用 switch 表达式映射任务类型
                int taskInboundType = taskDto.TaskType switch
                {
                    TaskTypeEnum.Inbound => TaskInboundTypeEnum.Inbound.GetHashCode(),
                    TaskTypeEnum.InEmpty => TaskInboundTypeEnum.InEmpty.GetHashCode(),
                    _ => 0 // 理论上不会走到这里,因为已经验证过了
                };
                var task = new Dt_Task
                {
                    TaskNum = await BaseDal.GetTaskNo(),
                    PalletCode = taskDto.PalletCode,
                    PalletType = taskDto.PalletType,
                    Roadway = taskDto.Roadway,
                    TaskType = taskInboundType,
                    TaskStatus = TaskInStatusEnum.InNew.GetHashCode(),
                    SourceAddress = taskDto.SourceAddress,
                    TargetAddress = taskDto.TargetAddress,
                    CurrentAddress = taskDto.SourceAddress,
                    NextAddress = taskDto.TargetAddress,
                    WarehouseId = taskDto.WarehouseId,
                    Grade = 1,
                    Creater = "system"
                };
                var result = await Repository.AddDataAsync(task) > 0;
                if (!result) return WebResponseContent.Instance.Error("任务创建失败");
                var wmstaskDto = _mapper.Map<WMSTaskDTO>(task);
                return WebResponseContent.Instance.OK("任务创建成功", wmstaskDto);
            }
            if (taskDto.TaskType != TaskTypeEnum.Inbound || taskDto.TaskType != TaskTypeEnum.InEmpty)
            catch (Exception ex)
            {
                return null;
                return WebResponseContent.Instance.Error($"任务创建失败: {ex.Message}");
            }
            var task = new Dt_Task
            {
                TaskNum = 0,
                PalletCode = taskDto.PalletCode,
                PalletType = taskDto.PalletType,
                Roadway = taskDto.Roadway,
                TaskType = taskDto.TaskType.GetHashCode(),
                TaskStatus = TaskStatusEnum.New.GetHashCode(),
                SourceAddress = taskDto.SourceAddress,
                TargetAddress = taskDto.TargetAddress,
                CurrentAddress = taskDto.SourceAddress,
                NextAddress = taskDto.TargetAddress,
                WarehouseId = taskDto.WarehouseId,
                Grade = 1,
                Creater = "system"
            };
            return await Repository.AddDataAsync(task) > 0 ? task : null;
        }
        /// <summary>
        /// 根据指定的任务详情异步创建新的出库任务
        /// </summary>
        public async Task<WebResponseContent> CreateTaskOutboundAsync(CreateTaskDto taskDto)
        {
            try
            {
                var stockResult = await _stockInfoService.GetStockInfoAsync(taskDto.WarehouseId);
                if (stockResult == null || !stockResult.Any())
                    return WebResponseContent.Instance.Error("未找到库存信息");
                var taskList = stockResult.Select(item => new Dt_Task
                {
                    WarehouseId = item.WarehouseId,
                    PalletCode = item.PalletCode,
                    PalletType = item.PalletType,
                    SourceAddress = item.LocationCode,
                    TargetAddress = taskDto.TargetAddress,
                    Roadway = item.LocationDetails.RoadwayNo,
                    TaskType = TaskTypeEnum.Outbound.GetHashCode(),
                    TaskStatus = TaskStatusEnum.New.GetHashCode(),
                    Grade = 1,
                    TaskNum = 0,
                    CurrentAddress = item.LocationCode,
                    NextAddress = taskDto.TargetAddress,
                    Creater = "system",
                }).ToList();
                var result = await BaseDal.AddDataAsync(taskList) > 0;
                var wmstaskDto = result ? _mapper.Map<WMSTaskDTO>(taskList) : null;
                return WebResponseContent.Instance.OK(result ? "任务创建成功" : "任务创建失败", wmstaskDto ?? new object());
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"任务创建失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 获取可入库货位
        /// </summary>
        public async Task<WebResponseContent> GetTasksLocationAsync(CreateTaskDto taskDto)
        {
            try
            {
                var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode);
                if (task == null) return WebResponseContent.Instance.Error("未找到对应的任务");
                var locationInfo = await _locationInfoService.GetLocationInfo(task.Roadway);
                if (locationInfo == null) return WebResponseContent.Instance.Error("未找到对应的货位");
                return await ExecuteWithinTransactionAsync(async () =>
                {
                    locationInfo.LocationStatus = LocationStatusEnum.FreeLock.GetHashCode();
                    task.CurrentAddress = task.SourceAddress;
                    task.NextAddress = locationInfo.LocationCode;
                    task.TargetAddress = locationInfo.LocationCode;
                    task.TaskStatus = TaskInStatusEnum.Line_InFinish.GetHashCode();
                    var updateTaskResult = await BaseDal.UpdateDataAsync(task);
                    var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(locationInfo);
                    if (!updateTaskResult || !updateLocationResult)
                    {
                        return WebResponseContent.Instance.Error("任务更新失败");
                    }
                    return WebResponseContent.Instance.OK("任务更新成功", locationInfo.LocationCode);
                });
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"获取任务失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 入库任务完成:添加库存,修改货位状态,删除任务数据,添加历史任务数据
        /// </summary>
        public async Task<WebResponseContent> InboundFinishTaskAsync(CreateTaskDto taskDto)
        {
            try
            {
                var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode);
                if (task == null) return WebResponseContent.Instance.Error("未找到对应的任务");
                var location = await _locationInfoService.GetLocationInfo(task.Roadway, task.TargetAddress);
                if (location == null) return WebResponseContent.Instance.Error("未找到对应的货位");
                var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode);
                if (stockInfo == null) return WebResponseContent.Instance.Error("未找到对应库存信息");
                // 判断是不是极卷库任务
                //if (taskDto.WarehouseId == (int)WarehouseEnum.FJ1 || taskDto.WarehouseId == (int)WarehouseEnum.ZJ1)
                //{
                //    return WebResponseContent.Instance.OK();
                //}
                return await ExecuteWithinTransactionAsync(async () =>
                {
                    WebResponseContent content = new WebResponseContent();
                    stockInfo.LocationCode = location.LocationCode;
                    stockInfo.LocationId = location.Id;
                    stockInfo.OutboundDate = task.Roadway switch
                    {
                        var r when r.Contains("GW") => DateTime.Now.AddHours(2),
                        var r when r.Contains("CW") => DateTime.Now.AddHours(1),
                        _ => DateTime.Now
                    };
                    stockInfo.StockStatus = StockStatusEmun.入库完成.GetHashCode();
                    location.LocationStatus = LocationStatusEnum.InStock.GetHashCode();
                    var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location);
                    var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo);
                    if (!updateLocationResult || !updateStockResult)
                        return WebResponseContent.Instance.Error("任务完成失败");
                    // 调用MES托盘进站
                    var inboundRequest = new InboundInContainerRequest
                    {
                        EquipmentCode = "STK-GROUP-001",
                        ResourceCode = "STK-GROUP-001",
                        LocalTime = DateTime.Now,
                        ContainerCode = taskDto.PalletCode
                    };
                    var inboundResult = _mesService.InboundInContainer(inboundRequest);
                    if (inboundResult == null || inboundResult.Data == null || !inboundResult.Data.IsSuccess)
                    {
                        return content.Error($"任务完成失败:MES进站失败: {inboundResult?.Data?.Msg ?? inboundResult?.ErrorMessage ?? "未知错误"}");
                    }
                    return await CompleteTaskAsync(task, "入库完成");
                });
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"完成任务失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 出库任务完成 :修改库存,修改货位状态,删除任务数据,添加历史任务数据
        /// </summary>
        public async Task<WebResponseContent> OutboundFinishTaskAsync(CreateTaskDto taskDto)
        {
            try
            {
                var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode);
                if (task == null) return WebResponseContent.Instance.Error("未找到对应的任务");
                var location = await _locationInfoService.GetLocationInfo(task.Roadway, task.SourceAddress);
                if (location == null) return WebResponseContent.Instance.Error("未找到对应的货位");
                var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode);
                if (stockInfo == null) return WebResponseContent.Instance.Error("未找到对应库存信息");
                // 判断是不是极卷库任务
                if (taskDto.WarehouseId == (int)WarehouseEnum.FJ1 || taskDto.WarehouseId == (int)WarehouseEnum.ZJ1)
                {
                    OutTaskCompleteDto outTaskCompleteDto = new OutTaskCompleteDto()
                    {
                        TaskId = task.OrderNo,
                        DevId = task.TargetAddress,
                        ReqTime = DateTime.Now.ToString()
                    };
                    return await OutTaskComplete(outTaskCompleteDto);
                }
                WebResponseContent content = new WebResponseContent();
                return await ExecuteWithinTransactionAsync(async () =>
                {
                    stockInfo.LocationId = 0;
                    stockInfo.LocationCode = null;
                    stockInfo.OutboundDate = DateTime.Now;
                    location.LocationStatus = LocationStatusEnum.Free.GetHashCode();
                    var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location);
                    var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo);
                    if (!updateLocationResult || !updateStockResult)
                        return WebResponseContent.Instance.Error("任务完成失败");
                    // 调用MES托盘出站
                    var outboundRequest = new OutboundInContainerRequest
                    {
                        EquipmentCode = "STK-GROUP-001",
                        ResourceCode = "STK-GROUP-001",
                        LocalTime = DateTime.Now,
                        ContainerCode = taskDto.PalletCode,
                        ParamList = new List<ParamItem>()
                    };
                    var outboundResult = _mesService.OutboundInContainer(outboundRequest);
                    if (outboundResult == null || outboundResult.Data == null || !outboundResult.Data.IsSuccess)
                    {
                        return content.Error($"任务完成失败:MES出站失败: {outboundResult?.Data?.Msg ?? outboundResult?.ErrorMessage ?? "未知错误"}");
                    }
                    return await CompleteTaskAsync(task, "出库完成");
                });
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"完成任务失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 移库任务完成:修改库存位置与状态,修改源/目标货位状态,删除任务数据
        /// </summary>
        public async Task<WebResponseContent> RelocationFinishTaskAsync(CreateTaskDto taskDto)
        {
            try
            {
                var task = await BaseDal.QueryFirstAsync(s =>
                    s.PalletCode == taskDto.PalletCode &&
                    s.TaskType == TaskRelocationTypeEnum.Relocation.GetHashCode());
                if (task == null) return WebResponseContent.Instance.Error("未找到对应的移库任务");
                var sourceLocation = await _locationInfoService.GetLocationInfo(task.Roadway, task.SourceAddress);
                if (sourceLocation == null) return WebResponseContent.Instance.Error("未找到移库源货位");
                var targetLocation = await _locationInfoService.GetLocationInfo(task.Roadway, task.TargetAddress);
                if (targetLocation == null) return WebResponseContent.Instance.Error("未找到移库目标货位");
                var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode);
                if (stockInfo == null) return WebResponseContent.Instance.Error("未找到对应库存信息");
                return await ExecuteWithinTransactionAsync(async () =>
                {
                    stockInfo.LocationCode = targetLocation.LocationCode;
                    stockInfo.LocationId = targetLocation.Id;
                    stockInfo.StockStatus = StockStatusEmun.入库完成.GetHashCode();
                    sourceLocation.LocationStatus = LocationStatusEnum.Free.GetHashCode();
                    targetLocation.LocationStatus = LocationStatusEnum.InStock.GetHashCode();
                    var updateSourceResult = await _locationInfoService.UpdateLocationInfoAsync(sourceLocation);
                    var updateTargetResult = await _locationInfoService.UpdateLocationInfoAsync(targetLocation);
                    var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo);
                    if (!updateSourceResult || !updateTargetResult || !updateStockResult)
                        return WebResponseContent.Instance.Error("移库任务完成失败");
                    return await CompleteTaskAsync(task, "移库完成");
                });
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"完成任务失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 创建空托盘入库任务
        /// </summary>
        /// <param name="taskDto"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> CreateTaskInboundTrayAsync(CreateTaskDto taskDto)
        {
            try
            {
                WebResponseContent content = await GetTaskByPalletCodeAsync(taskDto.PalletCode);
                if (content.Status)
                {
                    return content;
                }
                //var tasks = await BaseDal.QueryAsync(s => s.PalletCode == palletCode);
                //if (tasks == null || !tasks.Any())
                //    return WebResponseContent.Instance.Error("未找到对应的任务");
                //var taskDtos = _mapper.Map<List<WMSTaskDTO>>(tasks);
                return WebResponseContent.Instance.OK("查询成功"/*, taskDtos*/);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"查询任务失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 空托盘入库完成
        /// </summary>
        public async Task<WebResponseContent> InboundFinishTaskTrayAsync(CreateTaskDto taskDto)
        {
            try
            {
                var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode);
                if (task == null) return WebResponseContent.Instance.Error("未找到对应的任务");
                var location = await _locationInfoService.GetLocationInfo(task.Roadway, task.TargetAddress);
                if (location == null) return WebResponseContent.Instance.Error("未找到对应的货位");
                var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode);
                if (stockInfo == null) return WebResponseContent.Instance.Error("未找到对应库存信息");
                return await ExecuteWithinTransactionAsync(async () =>
                {
                    stockInfo.LocationCode = location.LocationCode;
                    stockInfo.LocationId = location.Id;
                    stockInfo.StockStatus = StockStatusEmun.空托盘库存.GetHashCode();
                    location.LocationStatus = LocationStatusEnum.InStock.GetHashCode();
                    var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location);
                    var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo);
                    if (!updateLocationResult || !updateStockResult)
                        return WebResponseContent.Instance.Error("任务完成失败");
                    // 保存任务历史
                    var historyTask = _mapper.Map<Dt_Task_Hty>(task);
                    historyTask.InsertTime = DateTime.Now;
                    historyTask.OperateType = "空托盘入库完成";
                    if (await _task_HtyService.Repository.AddDataAsync(historyTask) <= 0)
                        return WebResponseContent.Instance.Error("任务历史保存失败");
                    // 保存库存历史
                    var historyStock = _mapper.Map<Dt_StockInfo_Hty>(stockInfo);
                    historyStock.InsertTime = DateTime.Now;
                    historyStock.OperateType = "空托盘入库完成";
                    if (await _stockInfo_HtyService.Repository.AddDataAsync(historyStock) <= 0)
                        return WebResponseContent.Instance.Error("库存历史保存失败");
                    var deleteResult = await BaseDal.DeleteDataAsync(task);
                    if (!deleteResult) return WebResponseContent.Instance.Error("任务完成失败");
                    return WebResponseContent.Instance.OK("任务完成");
                });
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"完成任务失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 创建空托盘出库任务
        /// </summary>
        /// <param name="taskDto"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> GetOutBoundTrayTaskAsync(CreateTaskDto taskDto)
        {
            try
            {
                var stockInfo = await _stockInfoService.Repository.QueryDataNavFirstAsync(x => x.LocationDetails.WarehouseId == taskDto.WarehouseId && x.LocationDetails.LocationStatus == LocationStatusEnum.InStock.GetHashCode() && x.StockStatus == StockStatusEmun.空托盘库存.GetHashCode());
                if (stockInfo == null)
                    return WebResponseContent.Instance.Error("未找到对应的库存信息");
                var task = new Dt_Task()
                {
                    WarehouseId = stockInfo.LocationDetails.WarehouseId,
                    PalletCode = stockInfo.PalletCode,
                    PalletType = stockInfo.PalletType,
                    SourceAddress = stockInfo.LocationCode,
                    CurrentAddress = stockInfo.LocationCode,
                    NextAddress = taskDto.TargetAddress,
                    TargetAddress = taskDto.TargetAddress,
                    Roadway = stockInfo.LocationDetails.RoadwayNo,
                    TaskType = TaskOutboundTypeEnum.OutEmpty.GetHashCode(),
                    TaskStatus = TaskStatusEnum.New.GetHashCode(),
                    Grade = 1,
                    TaskNum = await BaseDal.GetTaskNo(),
                    Creater = "system",
                };
                var taskDtos = task.Adapt<WMSTaskDTO>();
                var addResult = await BaseDal.AddDataAsync(task) > 0;
                if (!addResult)
                    return WebResponseContent.Instance.Error("任务创建失败");
                return WebResponseContent.Instance.OK("任务创建成功", taskDtos);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"查询任务失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 空托盘出库完成
        /// </summary>
        public async Task<WebResponseContent> OutboundFinishTaskTrayAsync(CreateTaskDto taskDto)
        {
            try
            {
                var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode);
                if (task == null) return WebResponseContent.Instance.Error("未找到对应的任务");
                var location = await _locationInfoService.GetLocationInfo(task.Roadway, task.SourceAddress);
                if (location == null) return WebResponseContent.Instance.Error("未找到对应的货位");
                var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode);
                if (stockInfo == null) return WebResponseContent.Instance.Error("未找到对应库存信息");
                return await ExecuteWithinTransactionAsync(async () =>
                {
                    stockInfo.LocationId = 0;
                    stockInfo.LocationCode = null;
                    stockInfo.StockStatus = StockStatusEmun.出库完成.GetHashCode();
                    location.LocationStatus = LocationStatusEnum.Free.GetHashCode();
                    var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location);
                    var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo);
                    if (!updateLocationResult || !updateStockResult)
                        return WebResponseContent.Instance.Error("任务完成失败");
                    // 保存任务历史
                    var historyTask = _mapper.Map<Dt_Task_Hty>(task);
                    historyTask.InsertTime = DateTime.Now;
                    historyTask.OperateType = "空托盘出库完成";
                    if (await _task_HtyService.Repository.AddDataAsync(historyTask) <= 0)
                        return WebResponseContent.Instance.Error("任务历史保存失败");
                    // 保存库存历史
                    var historyStock = _mapper.Map<Dt_StockInfo_Hty>(stockInfo);
                    historyStock.InsertTime = DateTime.Now;
                    historyStock.OperateType = "空托盘出库完成";
                    if (await _stockInfo_HtyService.Repository.AddDataAsync(historyStock) <= 0)
                        return WebResponseContent.Instance.Error("库存历史保存失败");
                    var deleteResult = await BaseDal.DeleteDataAsync(task);
                    if (!deleteResult) return WebResponseContent.Instance.Error("任务完成失败");
                    return WebResponseContent.Instance.OK("任务完成");
                });
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"完成任务失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 修改任务状态(根据任务ID修改为指定状态)
        /// </summary>
        /// <param name="taskId"></param>
        /// <param name="newStatus"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> UpdateTaskByStatusAsync(int taskId, int newStatus)
        {
            try
            {
                var tasks = await BaseDal.QueryFirstAsync(s => s.TaskNum == taskId);
                if (tasks == null)
                    return WebResponseContent.Instance.Error("未找到对应的任务");
                tasks.TaskStatus = newStatus;
                await BaseDal.UpdateDataAsync(tasks);
                return WebResponseContent.Instance.OK("修改成功", tasks);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"修改失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 查找托盘是否有任务
        /// </summary>
        /// <param name="palletCode"></param>
        /// <returns></returns>
        private async Task<WebResponseContent> GetTaskByPalletCodeAsync(string palletCode)
        {
            try
            {
                var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == palletCode);
                if (task == null)
                    return WebResponseContent.Instance.Error("未找到对应的任务");
                var taskDto = _mapper.Map<WMSTaskDTO>(task);
                return WebResponseContent.Instance.OK("查询成功", taskDto);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"查询任务失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 完成任务后统一处理(删除任务数据)
        /// </summary>
        private async Task<WebResponseContent> CompleteTaskAsync(Dt_Task task, string operateType = "")
        {
            var deleteTaskResult = await BaseDal.DeleteDataAsync(task);
            if (!deleteTaskResult) return WebResponseContent.Instance.Error("任务完成失败");
            var historyTask = _mapper.Map<Dt_Task_Hty>(task);
            historyTask.InsertTime = DateTime.Now;
            historyTask.OperateType = operateType;
            var saveResult = await _task_HtyService.Repository.AddDataAsync(historyTask) > 0;
            if (!saveResult) return WebResponseContent.Instance.Error("任务历史保存失败");
            return WebResponseContent.Instance.OK("任务完成");
        }
        /// <summary>
        /// 根据巷道确定目标地址(支持多出库口轮询)
        /// </summary>
        private string DetermineTargetAddress(string roadway, Dictionary<string, List<string>> addressMap)
        {
            if (string.IsNullOrWhiteSpace(roadway))
                return "10080";
            // 查找匹配的巷道前缀
            string matchedPrefix = null;
            foreach (var kvp in addressMap)
            {
                if (roadway.Contains(kvp.Key))
                {
                    matchedPrefix = kvp.Key;
                    break;
                }
            }
            if (matchedPrefix == null)
                return "10080";
            var addresses = addressMap[matchedPrefix];
            if (addresses == null || addresses.Count == 0)
                return "10080";
            // 单个地址,直接返回
            if (addresses.Count == 1)
                return addresses[0];
            // 多个地址,使用轮询服务
            return _roundRobinService.GetNextAddress(matchedPrefix, addresses);
        }
        /// <summary>
        /// 自动创建出库任务 - 查询到期库存并创建任务
        /// </summary>
        public async Task<WebResponseContent> CreateAutoOutboundTasksAsync()
        {
            try
            {
                // 1. 查询到期库存
                var expiredStocks = await _stockInfoService.Repository
                    .QueryDataNavAsync(s => s.OutboundDate <= DateTime.Now
                        && s.StockStatus == StockStatusEmun.入库完成.GetHashCode());
                if (expiredStocks == null || !expiredStocks.Any())
                {
                    return WebResponseContent.Instance.OK("无到期库存需要处理");
                }
                // 过滤有位置且位置有库存的记录
                expiredStocks = expiredStocks
                    .Where(s => s.LocationDetails != null
                        && s.LocationDetails.LocationStatus == LocationStatusEnum.InStock.GetHashCode())
                    .ToList();
                if (!expiredStocks.Any())
                {
                    return WebResponseContent.Instance.OK("无符合条件的到期库存");
                }
                // 2. 检查已存在的任务
                var palletCodes = expiredStocks.Select(s => s.PalletCode).ToList();
                var existingTasks = await Repository.QueryDataAsync(t =>
                    palletCodes.Contains(t.PalletCode)
                    && (t.TaskStatus == TaskStatusEnum.New.GetHashCode()
                        || t.TaskStatus == TaskStatusEnum.SC_Executing.GetHashCode()
                        || t.TaskStatus == TaskInStatusEnum.InNew.GetHashCode()));
                var processedPallets = existingTasks.Select(t => t.PalletCode).ToHashSet();
                // 3. 筛选需要处理的库存
                var stocksToProcess = expiredStocks
                    .Where(s => !processedPallets.Contains(s.PalletCode))
                    .ToList();
                if (!stocksToProcess.Any())
                {
                    return WebResponseContent.Instance.OK("所有到期库存已存在任务");
                }
                // 4. 获取配置的目标地址映射
                var targetAddressMap = _configuration.GetSection("AutoOutboundTask:TargetAddresses")
                    .Get<Dictionary<string, List<string>>>()
                    ?? new Dictionary<string, List<string>>();
                // 5. 批量创建任务
                var taskList = new List<Dt_Task>();
                foreach (var stock in stocksToProcess)
                {
                    // 根据巷道确定目标地址
                    var targetAddress = DetermineTargetAddress(
                        stock.LocationDetails?.RoadwayNo ?? "",
                        targetAddressMap);
                    var task = new Dt_Task
                    {
                        WarehouseId = stock.WarehouseId,
                        PalletCode = stock.PalletCode,
                        PalletType = stock.PalletType,
                        SourceAddress = stock.LocationCode,
                        CurrentAddress = stock.LocationCode,
                        NextAddress = targetAddress,
                        TargetAddress = targetAddress,
                        Roadway = stock.LocationDetails?.RoadwayNo ?? "",
                        TaskType = TaskTypeEnum.Outbound.GetHashCode(),
                        TaskStatus = TaskStatusEnum.New.GetHashCode(),
                        Grade = 1,
                        TaskNum = await BaseDal.GetTaskNo(),
                        Creater = "system_auto"
                    };
                    taskList.Add(task);
                }
                var transactionResult = await ExecuteWithinTransactionAsync(async () =>
                {
                    var addResult = await BaseDal.AddDataAsync(taskList) > 0;
                    if (!addResult)
                    {
                        return WebResponseContent.Instance.Error($"批量创建任务失败,共 {taskList.Count} 个任务");
                    }
                    // 任务创建成功后,同步锁定库存和货位状态,避免重复分配
                    var stocksToUpdate = stocksToProcess
                        .Select(s =>
                        {
                            s.StockStatus = StockStatusEmun.出库锁定.GetHashCode();
                            return s;
                        })
                        .ToList();
                    var updateStockResult = await _stockInfoService.Repository.UpdateDataAsync(stocksToUpdate);
                    if (!updateStockResult)
                    {
                        return WebResponseContent.Instance.Error($"任务创建成功,但库存状态更新失败,共 {stocksToUpdate.Count} 条");
                    }
                    var locationsToUpdate = stocksToProcess
                        .Where(s => s.LocationDetails != null)
                        .GroupBy(s => s.LocationDetails.Id)
                        .Select(g =>
                        {
                            var location = g.First().LocationDetails;
                            location.LocationStatus = LocationStatusEnum.InStockLock.GetHashCode();
                            return location;
                        })
                        .ToList();
                    if (locationsToUpdate.Any())
                    {
                        var updateLocationResult = await _locationInfoService.Repository.UpdateDataAsync(locationsToUpdate);
                        if (!updateLocationResult)
                        {
                            return WebResponseContent.Instance.Error($"任务创建成功,但货位状态更新失败,共 {locationsToUpdate.Count} 条");
                        }
                    }
                    return WebResponseContent.Instance.OK();
                });
                if (!transactionResult.Status)
                {
                    return transactionResult;
                }
                // 6. 通知 WCS(异步,不影响主流程)
                _ = Task.Run(() =>
                {
                    try
                    {
                        var wmstaskDtos = _mapper.Map<List<WMSTaskDTO>>(taskList);
                        _httpClientHelper.Post<WebResponseContent>(
                            "http://localhost:9292/api/Task/ReceiveTask",
                            wmstaskDtos.ToJson());
                    }
                    catch (Exception ex)
                    {
                        // WCS 通知失败不影响任务创建,记录日志即可
                        Console.WriteLine($"WCS 批量通知失败,任务数量: {taskList.Count}, 错误: {ex.Message}");
                    }
                });
                return WebResponseContent.Instance.OK($"成功创建 {taskList.Count} 个出库任务", taskList.Count);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"自动创建出库任务失败: {ex.Message}");
            }
        }
        /// <summary>
        /// 创建机械手组盘任务
        /// </summary>
        public async Task<WebResponseContent> CreateRobotGroupPalletTaskAsync(StockDTO stock)
        {
            return await CreateRobotPalletTaskAsync(
                stock,
                "组盘",
                RobotTaskTypeEnum.GroupPallet,
                s => string.IsNullOrWhiteSpace(s.TargetPalletNo) ? s.SourcePalletNo : s.TargetPalletNo,
                requireStockWithoutLocation: false);
        }
        /// <summary>
        /// 创建机械手换盘任务
        /// </summary>
        public async Task<WebResponseContent> CreateRobotChangePalletTaskAsync(StockDTO stock)
        {
            return await CreateRobotPalletTaskAsync(
                stock,
                "换盘",
                RobotTaskTypeEnum.ChangePallet,
                s => s.SourcePalletNo,
                requireStockWithoutLocation: true,
                stockPalletCodeSelector: s => s.SourcePalletNo);
        }
        /// <summary>
        /// 创建机械手拆盘任务
        /// </summary>
        public async Task<WebResponseContent> CreateRobotSplitPalletTaskAsync(StockDTO stock)
        {
            return await CreateRobotPalletTaskAsync(
                stock,
                "拆盘",
                RobotTaskTypeEnum.SplitPallet,
                s => s.SourcePalletNo,
                requireStockWithoutLocation: true,
                stockPalletCodeSelector: s => s.SourcePalletNo);
        }
        private async Task<WebResponseContent> CreateRobotPalletTaskAsync(
            StockDTO stock,
            string taskName,
            RobotTaskTypeEnum taskType,
            Func<StockDTO, string?> palletCodeSelector,
            bool requireStockWithoutLocation,
            Func<StockDTO, string?>? stockPalletCodeSelector = null)
        {
            try
            {
                if (stock == null)
                    return WebResponseContent.Instance.Error("任务参数不能为空");
                var palletCode = palletCodeSelector(stock)?.Trim();
                if (string.IsNullOrWhiteSpace(palletCode))
                    return WebResponseContent.Instance.Error("托盘号不能为空");
                var sourceLineNo = stock.SourceLineNo?.Trim();
                var targetLineNo = stock.TargetLineNo?.Trim();
                if (string.IsNullOrWhiteSpace(sourceLineNo) || string.IsNullOrWhiteSpace(targetLineNo))
                    return WebResponseContent.Instance.Error("来源线体编号和目标线体编号不能为空");
                var existingTask = await BaseDal.QueryFirstAsync(t =>
                    t.PalletCode == palletCode &&
                    (t.TaskStatus == TaskRobotStatusEnum.RobotNew.GetHashCode()
                     || t.TaskStatus == TaskRobotStatusEnum.RobotExecuting.GetHashCode()
                     || t.TaskStatus == TaskRobotStatusEnum.RobotPickFinish.GetHashCode()
                     || t.TaskStatus == TaskRobotStatusEnum.RobotPutFinish.GetHashCode()
                     || t.TaskStatus == TaskRobotStatusEnum.RobotPending.GetHashCode()));
                if (existingTask != null)
                    return WebResponseContent.Instance.Error($"托盘[{palletCode}]已存在未完成任务");
                Dt_StockInfo? stockInfo = null;
                if (requireStockWithoutLocation)
                {
                    var stockPalletCode = (stockPalletCodeSelector ?? palletCodeSelector).Invoke(stock)?.Trim();
                    if (string.IsNullOrWhiteSpace(stockPalletCode))
                        return WebResponseContent.Instance.Error("源托盘号不能为空");
                    stockInfo = await _stockInfoService.GetStockInfoAsync(stockPalletCode);
                    if (stockInfo == null)
                        return WebResponseContent.Instance.Error($"托盘[{stockPalletCode}]库存不存在");
                    if (stockInfo.LocationId > 0 || !string.IsNullOrWhiteSpace(stockInfo.LocationCode))
                        return WebResponseContent.Instance.Error($"托盘[{stockPalletCode}]库存已绑定货位,不能创建机械手{taskName}任务");
                }
                var task = new Dt_Task
                {
                    TaskNum = await BaseDal.GetTaskNo(),
                    PalletCode = palletCode,
                    PalletType = stockInfo?.PalletType ?? 0,
                    Roadway = stock.Roadway,
                    TaskType = taskType.GetHashCode(),
                    TaskStatus = TaskRobotStatusEnum.RobotNew.GetHashCode(),
                    SourceAddress = sourceLineNo,
                    TargetAddress = targetLineNo,
                    CurrentAddress = sourceLineNo,
                    NextAddress = targetLineNo,
                    WarehouseId = stockInfo?.WarehouseId ?? 1,
                    Grade = 1,
                    Remark = $"机械手{taskName}",
                    Creater = "system"
                };
                var result = await Repository.AddDataAsync(task) > 0;
                if (!result)
                    return WebResponseContent.Instance.Error($"机械手{taskName}任务创建失败");
                var wmstaskDto = _mapper.Map<WMSTaskDTO>(task);
                return WebResponseContent.Instance.OK($"机械手{taskName}任务创建成功", wmstaskDto);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"机械手{taskName}任务创建失败: {ex.Message}");
            }
        }
        #endregion WCS逻辑处理
        #region 分容柜接口
        /// <summary>
        /// 堆垛机取放货完成后物流通知化成分容柜完成信号
        /// </summary>
        public async Task<WebResponseContent> InOrOutCompletedAsync(GradingMachineInputDto input)
        {
            WebResponseContent content = new WebResponseContent();
            if (string.IsNullOrWhiteSpace(input.PalletCode) || string.IsNullOrWhiteSpace(input.LocationCode))
            {
                return content.Error($"托盘号或者货位编号不能为空");
            }
            try
            {
                var stockInfo = await _stockInfoService.GetStockInfoAsync(input.PalletCode, input.LocationCode);
                int locationStatus;
                if (stockInfo == null)
                {
                    var location = await _locationInfoService.GetLocationInfoAsync(input.LocationCode);
                    locationStatus = location?.LocationStatus ?? 0;
                }
                else
                {
                    locationStatus = stockInfo.LocationDetails?.LocationStatus ?? 0;
                }
                OutputDto outPutDto = new OutputDto()
                {
                    LocationCode = input.LocationCode,
                    PalletCode = input.PalletCode,
                    IsNormalProcedure = 1,
                    LocationStatus = locationStatus
                };
                return content.OK(data: outPutDto);
            }
            catch (Exception ex)
            {
                content.Error(ex.Message);
            }
            return content;
        }
        /// <summary>
        /// 化成分容柜定时向物流更新分容柜状态信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> SendLocationStatusAsync(GradingMachineInputDto input)
        {
            WebResponseContent content = new WebResponseContent();
            if (string.IsNullOrWhiteSpace(input.LocationCode))
            {
                return content.Error($"货位编号不能为空");
            }
            try
            {
                var result = await _locationInfoService.Db.Updateable<Dt_LocationInfo>()
                    .SetColumns(s => new Dt_LocationInfo
                    {
                        LocationStatus = input.LocationStatus
                    }).Where(s => s.LocationCode == input.LocationCode).ExecuteCommandAsync() > 0;
                if (result)
                {
                    content.OK("更新成功");
                }
                else
                {
                    content.Error("更新失败");
                }
            }
            catch (Exception ex)
            {
                content.Error(ex.Message);
            }
            return content;
        }
        /// <summary>
        /// 分容柜工作完成后调用此接口通知物流出库
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> RequestOutboundAsync(GradingMachineInputDto input)
        {
            WebResponseContent content = new WebResponseContent();
            if (string.IsNullOrWhiteSpace(input.LocationCode) || string.IsNullOrWhiteSpace(input.PalletCode))
            {
                return content.Error($"托盘号或者货位编号不能为空");
            }
            try
            {
                var stock = await _stockInfoService.GetStockInfoAsync(input.PalletCode, input.LocationCode);
                if (stock == null)
                {
                    content.Error("未找到对应的托盘");
                }
                else
                {
                    var taskList = new Dt_Task
                    {
                        WarehouseId = stock.WarehouseId,
                        PalletCode = stock.PalletCode,
                        PalletType = stock.PalletType,
                        SourceAddress = stock.LocationCode,
                        CurrentAddress = stock.LocationCode,
                        NextAddress = "10080",
                        TargetAddress = "10081",
                        Roadway = stock.LocationDetails.RoadwayNo,
                        TaskType = TaskTypeEnum.Outbound.GetHashCode(),
                        TaskStatus = TaskStatusEnum.New.GetHashCode(),
                        Grade = 1,
                        TaskNum = await BaseDal.GetTaskNo(),
                        Creater = "system",
                    };
                    var result = await BaseDal.AddDataAsync(taskList) > 0;
                    var wmstaskDto = result ? _mapper.Map<WMSTaskDTO>(taskList) : null;
                    var httpResponse = _httpClientHelper.Post<WebResponseContent>("http://logistics-service/api/logistics/notifyoutbound", JsonSerializer.Serialize(wmstaskDto)).Data;
                    if (result && httpResponse != null)
                    {
                        content.OK("出库请求成功");
                    }
                    else
                    {
                        content.Error("出库请求失败");
                    }
                }
            }
            catch (Exception ex)
            {
                content.Error(ex.Message);
            }
            return content;
        }
        /// <summary>
        /// 入库完成分容调用获取托盘上每个通道电芯
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> GetPalletCodeCellAsync(GradingMachineInputDto input)
        {
            WebResponseContent content = new WebResponseContent();
            if (string.IsNullOrWhiteSpace(input.PalletCode) || string.IsNullOrWhiteSpace(input.LocationCode))
            {
                return content.Error($"托盘号或者货位编号不能为空");
            }
            try
            {
                var stockInfo = await _stockInfoService.GetStockInfoAsync(input.PalletCode, input.LocationCode);
                if (stockInfo == null)
                {
                    return content.Error("未找到对应的托盘");
                }
                var outPutDtos = stockInfo.Details.Select(x => new OutputDto()
                {
                    LocationCode = input.LocationCode,
                    PalletCode = input.PalletCode,
                    IsNormalProcedure = 1,
                    LocationStatus = stockInfo.LocationDetails.LocationStatus,
                    CellCode = x.SerialNumber,
                    Channel = x.InboundOrderRowNo.ToString()
                }).ToList();
                return content.OK(data: outPutDtos);
            }
            catch (Exception ex)
            {
                return content.Error(ex.Message);
            }
        }
        #endregion 分容柜接口
        #region 极卷库任务模块
        public string AGV_OutTaskComplete = WIDESEA_Core.Helper.AppSettings.Configuration["AGV_OutTaskComplete"]; // 上报AGV出库输送线完成
        public string WCS_ReceiveTask = WIDESEA_Core.Helper.AppSettings.Configuration["WCS_ReceiveTask"]; // WMS输送线任务下发
        /// <summary>
        /// 出入库申请
        /// </summary>
        /// <param name="applyInOutDto">请求参数</param>
        /// <returns></returns>
        public async Task<AGVResponse> ApplyInOutAsync(ApplyInOutDto applyInOutDto)
        {
            AGVResponse aGVResponse = new AGVResponse();
            try
            {
                // 参数验证
                if (applyInOutDto == null) return aGVResponse.Error("请求参数不能为空");
                if (string.IsNullOrWhiteSpace(applyInOutDto.TrayNumber)) return aGVResponse.Error("托盘号不能为空");
                if (string.IsNullOrWhiteSpace(applyInOutDto.TaskId)) return aGVResponse.Error("任务号不能为空");
                if (string.IsNullOrWhiteSpace(applyInOutDto.MaterialType)) return aGVResponse.Error("物料类型不能为空");
                if (string.IsNullOrWhiteSpace(applyInOutDto.MaterialName)) return aGVResponse.Error("物料描述不能为空");
                if (string.IsNullOrWhiteSpace(applyInOutDto.ReqTime)) return aGVResponse.Error("请求时间不能为空");
                if (applyInOutDto.Floor != 1 && applyInOutDto.Floor != 2) return aGVResponse.Error($"楼层段错误,必须为1(模切段)或2(卷绕段),当前值:{applyInOutDto.Floor}");
                if (applyInOutDto.YinYang != 1 && applyInOutDto.YinYang != 2) return aGVResponse.Error($"阴阳极错误,必须为1(阴极)或2(阳极),当前值:{applyInOutDto.YinYang}");
                if (applyInOutDto.InOut != 1 && applyInOutDto.InOut != 2) return aGVResponse.Error($"出入库类型错误,必须为1(入库)或2(出库),当前值:{applyInOutDto.InOut}");
                if (applyInOutDto.InOut == 1) // 入库
                {
                    if (applyInOutDto.Width == null || applyInOutDto.Width <= 0) return aGVResponse.Error("入库时宽度不能为空且必须大于0");
                    if (string.IsNullOrWhiteSpace(applyInOutDto.Group)) return aGVResponse.Error("入库时整托组别不能为空");
                }
                // 检查任务是否已存在
                var existingTask = await BaseDal.QueryFirstAsync(x => x.PalletCode == applyInOutDto.TrayNumber);
                if (existingTask != null) return aGVResponse.Error($"WMS已有当前任务,不可重复下发,任务号:{applyInOutDto.TaskId}");
                // 创建任务
                Dt_Task task = new Dt_Task
                {
                    OrderNo = applyInOutDto.TaskId, // 使用AGV的任务号
                    PalletCode = applyInOutDto.TrayNumber,
                    PalletType = applyInOutDto.Floor,
                    //WarehouseId = applyInOutDto.YinYang,
                    Grade = 1,
                    Creater = "AGV",
                    CreateDate = DateTime.Now,
                    Remark = $"物料类型:{applyInOutDto.MaterialType},物料描述:{applyInOutDto.MaterialName}"
                };
                // 根据阴极/阳极设置巷道和站台
                if (applyInOutDto.YinYang == 1) // 阴极
                {
                    // 货物到达后分配货物位
                    task.Roadway = WarehouseEnum.FJ1.ToString();
                    task.WarehouseId = (int)WarehouseEnum.FJ1;
                    task.SourceAddress = applyInOutDto.InOut == 1 ? "D10010" : "D10020"; // 入库口/出库口
                    task.NextAddress = "D10080"; // 阴极公共出库口
                    task.TargetAddress = "阴极卷库";
                }
                else if (applyInOutDto.YinYang == 2) // 阳极
                {
                    task.Roadway = WarehouseEnum.ZJ1.ToString();
                    task.WarehouseId = (int)WarehouseEnum.ZJ1;
                    task.SourceAddress = applyInOutDto.InOut == 1 ? "D10100" : "D10090"; // 入库口/出库口
                    task.NextAddress = "D10160"; // 阳极公共出库口
                    task.TargetAddress = "正极卷库";
                }
                // 根据出入库类型设置目标地址
                if (applyInOutDto.InOut == 1) // 入库
                {
                    var stockInfo = await _stockInfoService.GetStockInfoAsync(applyInOutDto.TrayNumber);
                    if (stockInfo != null) return aGVResponse.Error($"当前托盘{applyInOutDto.TrayNumber}已经入库了");
                    task.TaskType = (int)TaskInboundTypeEnum.Inbound;
                    task.TaskStatus = (int)TaskInStatusEnum.InNew;
                    task.CurrentAddress = task.SourceAddress; // 当前在入库口
                    // 保存任务
                    var result = await BaseDal.AddDataAsync(task);
                }
                else // 出库
                {
                    // 判断是否移库
                    task.TaskType = (int)TaskOutboundTypeEnum.Outbound;
                    task.TaskStatus = (int)TaskOutStatusEnum.OutNew;
                    task.CurrentAddress = task.SourceAddress; // 当前在入库口
                    // 查找库存
                    var stockInfo = await _stockInfoService.GetStockInfoAsync(applyInOutDto.TrayNumber);
                    if (stockInfo == null) return aGVResponse.Error($"未找到托盘{applyInOutDto.TrayNumber}的库存信息");
                    // 验证库存所属是否正确
                    if (stockInfo.WarehouseId != applyInOutDto.YinYang) return aGVResponse.Error($"托盘{applyInOutDto.TrayNumber}不属于当前{(applyInOutDto.YinYang == 1 ? "阴极" : "阳极")}");
                    if (stockInfo.StockStatus != (int)StockStatusEmun.入库完成) return aGVResponse.Error($"托盘{applyInOutDto.TrayNumber}正在移动中,请稍后!");
                    task.SourceAddress = stockInfo.LocationCode; // 源地址为货位
                    task.CurrentAddress = stockInfo.LocationCode; // 当前位置在货位
                    task.TargetAddress = applyInOutDto.YinYang == 1 ? "D10020" : "D10090"; // 目标地址为出库口
                    // 保存任务
                    var result = await BaseDal.AddDataAsync(task);
                    // 判断是否移库
                    //var transferTask = await _locationInfoService.TransferCheckAsync(result);
                }
                // 构建响应数据
                AGVDataDto aGVDataDto = new AGVDataDto
                {
                    DevId = applyInOutDto.InOut == 1 ? task.SourceAddress : task.TargetAddress,
                    TrayNumber = task.PalletCode,
                    Group = applyInOutDto.Group,
                    Width = applyInOutDto.Width ?? 0,
                    LabelNumber = applyInOutDto.LabelNumber,
                    ProductNo = applyInOutDto.ProductNo,
                    ProductName = applyInOutDto.ProductName,
                    Quantity = applyInOutDto.Quantity,
                    UomCode = applyInOutDto.UomCode,
                    ProductType = applyInOutDto.ProductType,
                    Equipment = applyInOutDto.Equipment,
                    ProductionDate = applyInOutDto.ProductionDate,
                    LowerLimitTime = applyInOutDto.LowerLimitTime,
                    WarningTime = applyInOutDto.WarningTime,
                    OverdueTime = applyInOutDto.OverdueTime
                };
                return aGVResponse.OK(aGVDataDto);
            }
            catch (Exception ex)
            {
                return aGVResponse.Error($"WMS任务创建接口错误: {ex.Message}");
            }
        }
        /// <summary>
        /// 手动出库完成反馈给AGV
        /// </summary>
        /// <param name="outTaskCompleteDto">请求参数</param>
        /// <returns></returns>
        public async Task<WebResponseContent> OutTaskComplete(OutTaskCompleteDto outTaskCompleteDto)
        {
            WebResponseContent webResponse = new WebResponseContent();
            try
            {
                if (outTaskCompleteDto == null) return webResponse.Error("请求参数不能为空");
                if (string.IsNullOrWhiteSpace(outTaskCompleteDto.TaskId)) return webResponse.Error("任务号不能为空");
                if (string.IsNullOrWhiteSpace(outTaskCompleteDto.DevId)) return webResponse.Error("出库口编号不能为空");
                var task = await BaseDal.QueryFirstAsync(x => x.OrderNo == outTaskCompleteDto.TaskId);
                if (task == null) return webResponse.Error("未找到任务信息");
                outTaskCompleteDto.ReqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                var httpResponse = _httpClientHelper.Post<AGVResponse>(AGV_OutTaskComplete, outTaskCompleteDto.ToJson()).Data;
                // 判断远程接口返回是否成功
                if (httpResponse != null && httpResponse.Data != null)
                {
                    AGVResponse agvResponse = httpResponse;
                    // 根据code字段判断,code为true表示成功
                    if (agvResponse.Code == true)
                    {
                        var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode);
                        if (stockInfo == null) return webResponse.Error($"未找到托盘{task.PalletCode}的库存信息");
                        var locationInfo = await _locationInfoService.GetLocationInfoAsync(stockInfo.LocationCode);
                        if (locationInfo == null) return webResponse.Error($"未找到托盘{stockInfo.LocationCode}的货位信息");
                        if (stockInfo.StockStatus != (int)StockStatusEmun.出库锁定 || locationInfo.LocationStatus != (int)LocationStatusEnum.InStockLock)
                        {
                            return webResponse.Error($"当前库存{stockInfo.StockStatus}或者货位{locationInfo.LocationStatus}状态信息错误");
                        }
                        locationInfo.LocationStatus = (int)LocationStatusEnum.Free;
                        _unitOfWorkManage.BeginTran();
                        BaseDal.DeleteData(task);
                        _locationInfoService.UpdateData(locationInfo);
                        _stockInfoService.DeleteData(stockInfo);
                        _unitOfWorkManage.CommitTran();
                        return webResponse.OK(agvResponse.Msg);
                    }
                    else
                    {
                        // 失败:返回AGV返回的错误信息
                        return webResponse.Error(string.IsNullOrWhiteSpace(agvResponse.Msg)
                            ? "AGV接口调用失败"
                            : agvResponse.Msg);
                    }
                }
                else
                {
                    // HTTP请求本身失败
                    return webResponse.Error(httpResponse?.Msg ?? "AGV接口调用异常");
                }
            }
            catch (Exception ex)
            {
                _unitOfWorkManage.RollbackTran();
                return webResponse.Error($"WMS任务完成接口错误:{ex.Message}");
            }
        }
        ///// <summary>
        ///// 任务完成接口
        ///// </summary>
        ///// <param name="wCSTask"></param>
        ///// <returns></returns>
        //public async Task<WebResponseContent> TaskCompleted(WCSTaskDTO wCSTask)
        //{
        //    WebResponseContent webResponse = new WebResponseContent();
        //    try
        //    {
        //        Dt_Task task = await BaseDal.QueryFirstAsync(x => x.TaskId == wCSTask.TaskNum && x.PalletCode == wCSTask.PalletCode);
        //        if (task == null) return webResponse.Error("未找到任务信息");
        //        // 出库完成反馈
        //        OutTaskCompleteDto outTaskCompleteDto = new OutTaskCompleteDto()
        //        {
        //            TaskId = task.OrderNo,
        //            DevId = task.TargetAddress,
        //            ReqTime = DateTime.Now.ToString()
        //        };
        //        return await OutTaskComplete(outTaskCompleteDto);
        //    }
        //    catch (Exception ex)
        //    {
        //        return webResponse.Error($"WMS任务完成接口错误:{ex.Message}");
        //    }
        //}
        /// <summary>
        /// 输送线申请进入
        /// </summary>
        /// <param name="applyEnterDto">请求参数</param>
        /// <returns></returns>
        public async Task<AGVResponse> ApplyEnterAsync(ApplyEnterDto applyEnterDto)
        {
            AGVResponse aGVResponse = new AGVResponse();
            try
            {
                // 参数验证
                if (applyEnterDto == null) return aGVResponse.Error("请求参数不能为空");
                if (string.IsNullOrWhiteSpace(applyEnterDto.DevId)) return aGVResponse.Error("设备编号不能为空");
                if (string.IsNullOrWhiteSpace(applyEnterDto.TaskId)) return aGVResponse.Error("任务号不能为空");
                if (applyEnterDto.InOut != 1 && applyEnterDto.InOut != 2) return aGVResponse.Error($"出入库类型错误,必须为1(入库)或2(出库),当前值:{applyEnterDto.InOut}");
                // 查询任务是否存在
                var task = await BaseDal.QueryFirstAsync(x => x.OrderNo == applyEnterDto.TaskId);
                if (task == null) return aGVResponse.Error($"未找到任务信息,任务号:{applyEnterDto.TaskId}");
                if (applyEnterDto.InOut == 1 && task.TaskType == (int)TaskInboundTypeEnum.Inbound && task.TaskStatus == (int)TaskInStatusEnum.InNew)
                {
                    aGVResponse.OK();
                }
                else if (applyEnterDto.InOut == 2 && task.TaskType == (int)TaskOutboundTypeEnum.Outbound && task.TaskStatus == (int)TaskStatusEnum.Line_Finish)
                {
                    aGVResponse.OK();
                }
                return aGVResponse.Error($"输送线{applyEnterDto.DevId}当前繁忙,请稍后重试");
                // Dt_Task.SourceAddress询问wcs站台1-阴极入口叫D10010和D10020;2-阳极D10090和D10100是否有货物
                //var httpResponse = _httpClientHelper.Post<WebResponseContent>("http://127.0.0.1:9999/api/Task/ApplyInOut", JsonSerializer.Serialize(task)).Data;
                //if (httpResponse != null && httpResponse.Status == true)
                //{
                //    _unitOfWorkManage.BeginTran();
                //    task.TaskStatus = (int)TaskStatusEnum.AGV_Executing;
                //    await BaseDal.UpdateDataAsync(task);
                //    _unitOfWorkManage.CommitTran();
                //    return aGVResponse.OK();
                //}
                //else
                //{
                //    return aGVResponse.Error($"站台{task.SourceAddress}已经载货");
                //}
            }
            catch (Exception ex)
            {
                //_unitOfWorkManage.RollbackTran();
                return aGVResponse.Error($"WMS输送线申请接口错误:{ex.Message}");
            }
        }
        /// <summary>
        /// 取放货完成
        /// </summary>
        /// <param name="taskCompleteDto">请求参数</param>
        /// <returns></returns>
        public async Task<AGVResponse> TaskCompleteAsync(TaskCompleteDto taskCompleteDto)
        {
            AGVResponse aGVResponse = new AGVResponse();
            try
            {
                if (taskCompleteDto == null) return aGVResponse.Error("请求参数不能为空");
                if (string.IsNullOrWhiteSpace(taskCompleteDto.TaskId)) return aGVResponse.Error("任务号不能为空");
                if (string.IsNullOrWhiteSpace(taskCompleteDto.DevId)) return aGVResponse.Error("设备编号不能为空");
                if (taskCompleteDto.InOut != 1 && taskCompleteDto.InOut != 2) return aGVResponse.Error($"出入库类型错误,必须为1(入库)或2(出库),当前值:{taskCompleteDto.InOut}");
                var task = await BaseDal.QueryFirstAsync(x => x.OrderNo == taskCompleteDto.TaskId);
                if (task == null) return aGVResponse.Error($"未找到任务信息,任务号:{taskCompleteDto.TaskId}");
                if (taskCompleteDto.InOut == 2)
                {
                    var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode);
                    if (stockInfo == null) return aGVResponse.Error($"未找到托盘{task.PalletCode}的库存信息");
                    var locationInfo = await _locationInfoService.GetLocationInfoAsync(stockInfo.LocationCode);
                    if (locationInfo == null) return aGVResponse.Error($"未找到托盘{stockInfo.LocationCode}的货位信息");
                    if (stockInfo.StockStatus != (int)StockStatusEmun.出库锁定 || locationInfo.LocationStatus != (int)LocationStatusEnum.InStockLock)
                    {
                        return aGVResponse.Error($"当前库存{stockInfo.StockStatus}或者货位{locationInfo.LocationStatus}状态信息错误");
                    }
                    locationInfo.LocationStatus = (int)LocationStatusEnum.Free;
                    task.TaskStatus = (int)TaskOutStatusEnum.OutFinish;
                    _unitOfWorkManage.BeginTran();
                    _stockInfoService.DeleteData(stockInfo);
                    await _locationInfoService.UpdateLocationInfoAsync(locationInfo);
                    BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成);
                    _unitOfWorkManage.CommitTran();
                }
                else
                {
                    //查找可用货位
                    var availableLocation = await _locationInfoService.GetLocationInfo(task.Roadway);
                    if (availableLocation == null) return aGVResponse.Error("无可用的入库货位");
                    task.TargetAddress = availableLocation.LocationCode;
                    // 通知WCS入库
                    var wcsTaskDto = _mapper.Map<WCSTaskDTO>(task);
                    var httpResponse = _httpClientHelper.Post<WebResponseContent>(WCS_ReceiveTask, JsonSerializer.Serialize(wcsTaskDto));
                    if (httpResponse == null) return aGVResponse.Error("下发WCS失败");
                    task.TaskStatus = (int)TaskStatusEnum.Line_Executing;
                    task.Dispatchertime = DateTime.Now;
                    var locationInfo = await _locationInfoService.GetLocationInfoAsync(task.TargetAddress);
                    if (locationInfo == null) return aGVResponse.Error($"未找到托盘{task.TargetAddress}的货位信息");
                    if (locationInfo.LocationStatus != (int)LocationStatusEnum.InStock)
                    {
                        return aGVResponse.Error($"当前货位{locationInfo.LocationStatus}状态信息错误");
                    }
                    Dt_StockInfo dt_Stock = new Dt_StockInfo()
                    {
                        PalletCode = task.PalletCode,
                        StockStatus = (int)StockStatusEmun.入库确认,
                        LocationCode = locationInfo.LocationCode,
                        WarehouseId = task.WarehouseId,
                        Creater = "AGV",
                        CreateDate = DateTime.Now
                    };
                    locationInfo.LocationStatus = (int)LocationStatusEnum.FreeLock;
                    _unitOfWorkManage.BeginTran();
                    BaseDal.UpdateData(task);
                    _locationInfoService.UpdateData(locationInfo);
                    _stockInfoService.AddData(dt_Stock);
                    _unitOfWorkManage.CommitTran();
                }
                return aGVResponse.OK();
            }
            catch (Exception ex)
            {
                _unitOfWorkManage.RollbackTran();
                return aGVResponse.Error($"WMS取放货完成接口错误:{ex.Message}");
            }
        }
        /// <summary>
        /// 任务取消
        /// </summary>
        /// <param name="taskCancelDto">请求参数</param>
        /// <returns></returns>
        public async Task<AGVResponse> TaskCancelAsync(TaskCancelDto taskCancelDto)
        {
            AGVResponse aGVResponse = new AGVResponse();
            try
            {
                if (taskCancelDto == null) return aGVResponse.Error("请求参数不能为空");
                if (string.IsNullOrWhiteSpace(taskCancelDto.TaskId)) return aGVResponse.Error("任务号不能为空");
                var task = await BaseDal.QueryFirstAsync(x => x.OrderNo == taskCancelDto.TaskId);
                // 没有任务强制取消
                if (task == null) return aGVResponse.OK();
                if (task.TaskStatus == (int)TaskInStatusEnum.InNew)
                {
                    task.TaskStatus = (int)TaskInStatusEnum.InCancel;
                    // 入库任务直接删除
                    _unitOfWorkManage.BeginTran();
                    BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成);
                    _unitOfWorkManage.CommitTran();
                    return aGVResponse.OK();
                }
                else if (task.TaskStatus == (int)TaskOutStatusEnum.OutNew)
                {
                    // 出库任务恢复库存
                    var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode);
                    if (stockInfo == null) return aGVResponse.Error($"未找到托盘{task.PalletCode}的库存信息");
                    var locationInfo = await _locationInfoService.GetLocationInfoAsync(stockInfo.LocationCode);
                    if (locationInfo == null) return aGVResponse.Error($"未找到托盘{stockInfo.LocationCode}的货位信息");
                    if (stockInfo.StockStatus != (int)StockStatusEmun.出库锁定 || locationInfo.LocationStatus != (int)LocationStatusEnum.InStockLock)
                    {
                        return aGVResponse.Error($"当前库存{stockInfo.StockStatus}或者货位{locationInfo.LocationStatus}状态信息错误");
                    }
                    stockInfo.StockStatus = (int)StockStatusEmun.入库完成;
                    locationInfo.LocationStatus = (int)LocationStatusEnum.InStock;
                    task.TaskStatus = (int)TaskOutStatusEnum.OutCancel;
                    _unitOfWorkManage.BeginTran();
                    _locationInfoService.UpdateData(locationInfo);
                    _stockInfoService.UpdateData(stockInfo);
                    BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成);
                    _unitOfWorkManage.CommitTran();
                    return aGVResponse.OK();
                }
                return aGVResponse.Error("任务已经在执行中,不可取消");
            }
            catch (Exception ex)
            {
                _unitOfWorkManage.RollbackTran();
                return aGVResponse.Error($"WMS任务取消接口错误:{ex.Message}");
            }
        }
        #endregion 极卷库任务模块
    }
}
}