wanshenmean
2026-03-11 5af11cc200dd5ebe474b9c0475883b0e6d1e3759
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs
@@ -8,7 +8,8 @@
using WIDESEA_Core;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.BaseServices;
using WIDESEA_DTO;
using WIDESEA_Core.Core;
using WIDESEA_DTO.GradingMachine;
using WIDESEA_DTO.Task;
using WIDESEA_IBasicService;
using WIDESEA_IStockService;
@@ -24,6 +25,7 @@
        private readonly ILocationInfoService _locationInfoService;
        private readonly HttpClientHelper _httpClientHelper;
        private readonly IConfiguration _configuration;
        private readonly RoundRobinService _roundRobinService;
        public IRepository<Dt_Task> Repository => BaseDal;
@@ -42,13 +44,15 @@
            IStockInfoService stockInfoService,
            ILocationInfoService locationInfoService,
            HttpClientHelper httpClientHelper,
            IConfiguration configuration) : base(BaseDal)
            IConfiguration configuration,
            RoundRobinService roundRobinService) : base(BaseDal)
        {
            _mapper = mapper;
            _stockInfoService = stockInfoService;
            _locationInfoService = locationInfoService;
            _httpClientHelper = httpClientHelper;
            _configuration = configuration;
            _roundRobinService = roundRobinService;
        }
        #region WCS逻辑处理
@@ -206,6 +210,7 @@
                    var r when r.Contains("CW") => DateTime.Now.AddHours(1),
                    _ => DateTime.Now
                };
                stockInfo.StockStatus = StockStatusEmun.入库完成.GetHashCode();
                location.LocationStatus = LocationStatusEnum.InStock.GetHashCode();
@@ -380,20 +385,37 @@
        }
        /// <summary>
        /// 根据巷道确定目标地址
        /// 根据巷道确定目标地址(支持多出库口轮询)
        /// </summary>
        private string DetermineTargetAddress(string roadway, Dictionary<string, string> addressMap)
        private string DetermineTargetAddress(string roadway, Dictionary<string, List<string>> addressMap)
        {
            if (string.IsNullOrWhiteSpace(roadway))
                return "10080"; // 默认地址
                return "10080";
            // 查找匹配的巷道前缀
            string matchedPrefix = null;
            foreach (var kvp in addressMap)
            {
                if (roadway.Contains(kvp.Key))
                    return kvp.Value;
                {
                    matchedPrefix = kvp.Key;
                    break;
                }
            }
            return "10080"; // 默认地址
            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>
@@ -405,7 +427,7 @@
            {
                // 1. 查询到期库存
                var expiredStocks = await _stockInfoService.Repository
                    .QueryAsync(s => s.OutboundDate <= DateTime.Now
                    .QueryDataAsync(s => s.OutboundDate <= DateTime.Now
                        && s.StockStatus == StockStatusEmun.入库完成.GetHashCode());
                if (expiredStocks == null || !expiredStocks.Any())
@@ -413,13 +435,29 @@
                    return WebResponseContent.Instance.OK("无到期库存需要处理");
                }
                // 加载位置详情
                foreach (var stock in expiredStocks)
                // 批量加载位置详情(优化 N+1 查询问题)
                var locationIds = expiredStocks
                    .Where(s => s.LocationId > 0)
                    .Select(s => s.LocationId)
                    .Distinct()
                    .Cast<object>()
                    .ToList();
                if (locationIds.Any())
                {
                    if (stock.LocationId > 0)
                    var locations = await _locationInfoService.Repository
                        .QureyDataByIdsAsync(locationIds);
                    // 创建位置字典以便快速查找
                    var locationDict = locations.ToDictionary(l => l.Id, l => l);
                    // 为每个库存关联位置详情
                    foreach (var stock in expiredStocks)
                    {
                        stock.LocationDetails = await _locationInfoService.Repository
                            .GetFirstAsync(s => s.Id == stock.LocationId);
                        if (stock.LocationId > 0 && locationDict.ContainsKey(stock.LocationId))
                        {
                            stock.LocationDetails = locationDict[stock.LocationId];
                        }
                    }
                }
@@ -436,11 +474,11 @@
                // 2. 检查已存在的任务
                var palletCodes = expiredStocks.Select(s => s.PalletCode).ToList();
                var existingTasks = await Repository.QueryAsync(t =>
                var existingTasks = await Repository.QueryDataAsync(t =>
                    palletCodes.Contains(t.PalletCode)
                    && (t.TaskStatus == TaskStatusEnum.New.GetHashCode()
                        || t.TaskStatus == TaskStatusEnum.Executing.GetHashCode()
                        || t.TaskInStatus == TaskInStatusEnum.InNew.GetHashCode()));
                        || t.TaskStatus == TaskStatusEnum.SC_Executing.GetHashCode()
                        || t.TaskStatus == TaskInStatusEnum.InNew.GetHashCode()));
                var processedPallets = existingTasks.Select(t => t.PalletCode).ToHashSet();
@@ -456,8 +494,8 @@
                // 4. 获取配置的目标地址映射
                var targetAddressMap = _configuration.GetSection("AutoOutboundTask:TargetAddresses")
                    .Get<Dictionary<string, string>>()
                    ?? new Dictionary<string, string>();
                    .Get<Dictionary<string, List<string>>>()
                    ?? new Dictionary<string, List<string>>();
                // 5. 批量创建任务
                var taskList = new List<Dt_Task>();
@@ -481,7 +519,7 @@
                        TaskType = TaskTypeEnum.Outbound.GetHashCode(),
                        TaskStatus = TaskStatusEnum.New.GetHashCode(),
                        Grade = 1,
                        TaskNum = await Repository.GetTaskNo(),
                        TaskNum = await BaseDal.GetTaskNo(),
                        Creater = "system_auto"
                    };
                    taskList.Add(task);
@@ -494,15 +532,15 @@
                }
                // 6. 通知 WCS(异步,不影响主流程)
                _ = Task.Run(async () =>
                _ = Task.Run(() =>
                {
                    foreach (var task in taskList)
                    {
                        try
                        {
                            var wmstaskDto = _mapper.Map<WMSTaskDTO>(task);
                            await _httpClientHelper.Post<WebResponseContent>(
                                "http://logistics-service/api/logistics/notifyoutbound",
                            _httpClientHelper.Post<WebResponseContent>(
                                "http://localhost:9292/api/Task/ReceiveTask",
                                JsonSerializer.Serialize(wmstaskDto));
                        }
                        catch (Exception ex)
@@ -528,7 +566,7 @@
        /// <summary>
        /// 堆垛机取放货完成后物流通知化成分容柜完成信号
        /// </summary>
        public async Task<WebResponseContent> InOrOutCompletedAsync(InputDto input)
        public async Task<WebResponseContent> InOrOutCompletedAsync(GradingMachineInputDto input)
        {
            WebResponseContent content = new WebResponseContent();
            if (string.IsNullOrWhiteSpace(input.PalletCode) || string.IsNullOrWhiteSpace(input.LocationCode))
@@ -543,7 +581,7 @@
                {
                    var location = await _locationInfoService.GetLocationInfoAsync(input.LocationCode);
                    OutPutDto outPutDto = new OutPutDto()
                    OutputDto outPutDto = new OutputDto()
                    {
                        LocationCode = input.LocationCode,
                        PalletCode = input.PalletCode,
@@ -554,7 +592,7 @@
                }
                else
                {
                    OutPutDto outPutDto = new OutPutDto()
                    OutputDto outPutDto = new OutputDto()
                    {
                        LocationCode = input.LocationCode,
                        PalletCode = input.PalletCode,
@@ -577,7 +615,7 @@
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> SendLocationStatusAsync(InputDto input)
        public async Task<WebResponseContent> SendLocationStatusAsync(GradingMachineInputDto input)
        {
            WebResponseContent content = new WebResponseContent();
            if (string.IsNullOrWhiteSpace(input.LocationCode))
@@ -614,7 +652,7 @@
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> RequestOutboundAsync(InputDto input)
        public async Task<WebResponseContent> RequestOutboundAsync(GradingMachineInputDto input)
        {
            WebResponseContent content = new WebResponseContent();
            if (string.IsNullOrWhiteSpace(input.LocationCode) || string.IsNullOrWhiteSpace(input.PalletCode))
@@ -673,7 +711,7 @@
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<WebResponseContent> GetPalletCodeCellAsync(InputDto input)
        public async Task<WebResponseContent> GetPalletCodeCellAsync(GradingMachineInputDto input)
        {
            WebResponseContent content = new WebResponseContent();
            if (string.IsNullOrWhiteSpace(input.PalletCode) || string.IsNullOrWhiteSpace(input.LocationCode))
@@ -687,7 +725,7 @@
                {
                    return content.Error("未找到对应的托盘");
                }
                var outPutDtos = stockInfo.Details.Select(x => new OutPutDto()
                var outPutDtos = stockInfo.Details.Select(x => new OutputDto()
                {
                    LocationCode = input.LocationCode,
                    PalletCode = input.PalletCode,