From 843cc2ea1b104ecdf9da61318a4136a5d4096411 Mon Sep 17 00:00:00 2001
From: huangxiaoqiang <huangxiaoqiang@hnkhzn.com>
Date: 星期五, 24 四月 2026 11:07:21 +0800
Subject: [PATCH] 集成Quartz定时任务,支持NG出库自动化及WMS/WCS接口扩展

---
 Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StorageTaskServices/Task/Dt_TaskService.cs |  177 ++++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 144 insertions(+), 33 deletions(-)

diff --git a/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StorageTaskServices/Task/Dt_TaskService.cs b/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StorageTaskServices/Task/Dt_TaskService.cs
index bce772b..19b4a94 100644
--- a/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StorageTaskServices/Task/Dt_TaskService.cs
+++ b/Code Management/WMS/WIDESEA_WMSServer/WIDESEA_StorageTaskServices/Task/Dt_TaskService.cs
@@ -160,6 +160,45 @@
         }
     }
 
+    public async Task<WebResponseContent> CompleteNgTaskAsync(Dt_Task task)
+    {
+        WebResponseContent content = new WebResponseContent();
+        try
+        {
+            var boxing = await _boxingInfoRepository.QueryFirstNavAsync(x => x.PalletCode == task.PalletCode);
+            if (boxing != null)
+            {
+                await _boxingInfoRepository.Db.DeleteNav<DtBoxingInfo>(x => x.Id == boxing.Id)
+                                            .Include(x => x.BoxingInfoDetails)
+                                            .ExecuteCommandAsync();
+            }
+            var loc = _locationRepository.QueryFirst(x => x.LocationCode == task.SourceAddress && x.RoadwayNo == task.Roadway);
+            var taskHty = task.Adapt<Dt_Task_Hty>();
+            taskHty.FinishTime = DateTime.Now;
+            taskHty.OperateType = App.User.UserName != null ? (int)OperateTypeEnum.浜哄伐瀹屾垚 : (int)OperateTypeEnum.鑷姩瀹屾垚;
+            taskHty.Creater = App.User.UserName != null ? App.User.UserName : "System";
+            int lastStatus = loc.LocationStatus;
+            loc.LocationStatus = (int)LocationEnum.Free;
+            task.TaskState = (int)TaskOutStatusEnum.OutFinish;
+            // 浜嬪姟澶勭悊
+            await _unitOfWorkManage.UseTranAsync(async () =>
+            {
+                await UpdateLocationAsync(loc);
+
+                await DeleteTaskAsync(task.TaskId);
+                await AddTaskHtyAsync(taskHty);
+            });
+
+            _locationStatusChangeRecordRepository.AddLocationStatusChangeRecord(loc, lastStatus, (int)StatusChangeTypeEnum.AutomaticDelivery, task.TaskNum);
+            return content.OK("浠诲姟瀹屾垚鎴愬姛", task.Remark);
+        }
+        catch (Exception err)
+        {
+            LogFactory.GetLog("浠诲姟瀹屾垚").Error(true, $"绯荤粺寮傚父锛屽紓甯镐俊鎭細{err.Message}");
+            return content.Error(err.Message);
+        }
+    }
+
     private AgingOutputDto MapToAgingOutputDto(DtStockInfo stock, ResponseEqptRunDto? info = null)
     {
         // TODO Value鍊兼牴鎹甅OM涓嬪彂鐨勯潤缃椂闂村埌褰撳墠鏃堕棿鐨勫垎閽熸暟
@@ -407,7 +446,15 @@
                 return content.OK("鍏ュ簱浠诲姟瀹屾垚鎴愬姛");
             }
             // 鏍规嵁鏄惁鏈夌粍鐩樹俊鎭垱寤哄簱瀛樺疄渚嬫ā鍨�
-            DtStockInfo stock = boxing == null ? CreateEmptyPalletStock(task, locationInf) : CreateFullPalletStock(task, locationInf, boxing);
+            DtStockInfo stock = null;
+            if (boxing == null && task.TaskType == (int)TaskInboundTypeEnum.InTray)
+            {
+                stock = CreateEmptyPalletStock(task, locationInf);
+            }
+            else
+            {
+                stock = CreateFullPalletStock(task, locationInf, boxing);
+            }
 
             // 鎵ц鏁版嵁搴撲簨鍔�
             bool isResult = await ExecuteTransaction(stock, taskHty, locationInf, task.TaskId, boxing);
@@ -638,11 +685,20 @@
 
             case (int)TaskOutboundTypeEnum.OutTray:
             case (int)TaskOutboundTypeEnum.Outbound:
-            case (int)TaskOutboundTypeEnum.OutNG:
 
                 LogFactory.GetLog("浠诲姟瀹屾垚").InfoFormat(true, "鍑哄簱浠诲姟", "");
                 return await CompleteStackTaskAsync(task, stock);
 
+            case (int)TaskOutboundTypeEnum.OutNG:
+                LogFactory.GetLog("浠诲姟瀹屾垚").InfoFormat(true, "鍑哄簱浠诲姟", "");
+                if(task.Roadway.Contains("FR"))
+                {
+                    return await CompleteStackTaskAsync(task, stock);
+                }
+                else
+                {
+                    return await CompleteNgTaskAsync(task);
+                }
             case (int)TaskOutboundTypeEnum.OutFireAlarm:
 
                 LogFactory.GetLog("浠诲姟瀹屾垚").InfoFormat(true, "鐏浠诲姟", "");
@@ -671,7 +727,7 @@
             {
                 return CreateAndReturnWMSTaskDTO(task);
             }
-            if(task != null && (task.TaskState != (int)TaskInStatusEnum.InNew || task.TaskState != (int)TaskOutStatusEnum.OutNew))
+            if (task != null && (task.TaskState != (int)TaskInStatusEnum.InNew || task.TaskState != (int)TaskOutStatusEnum.OutNew))
             {
                 return content.Error($"鎵樼洏{input.PalletCode}瀛樺湪浠诲姟");
             }
@@ -737,6 +793,14 @@
                 ConsoleHelper.WriteErrorLine($"鑾峰彇鐢佃姱鐘舵�佸け璐�:{result.MOMMessage}");
                 if (result.SerialNos.Count <= 0)
                 {
+                    var config = _configService.GetByConfigKey(CateGoryConst.CONFIG_SYS_InStacker, SysConfigConst.InboundIsEmpty);
+                    var strings = config.ConfigValue.Split(',').ToList();
+                    if (strings.Contains(input.Position))
+                    {
+                        // todo閫佽嚦NG鍙�
+                        ConsoleHelper.WriteErrorLine($"褰撳墠浣嶇疆銆恵input.Position}銆戜笉鑳藉叆绌烘墭鐩�");
+                        return content.Error($"褰撳墠浣嶇疆銆恵input.Position}銆戜笉鑳藉叆绌烘墭鐩�");
+                    }
                     // 绌烘墭鐩樺叆搴撻�昏緫
                     var staion = _stationManagerRepository.QueryFirst(x => x.stationChildCode == input.Position && x.stationType == 1 && x.remark == "IN");
                     if (staion != null)
@@ -759,8 +823,8 @@
                 if (strings.Contains(input.Position))
                 {
                     // todo閫佽嚦NG鍙�
-                    ConsoleHelper.WriteErrorLine($"褰撳墠浣嶇疆涓嶈兘鍏ョ┖鎵樼洏");
-                    return content.Error("褰撳墠浣嶇疆涓嶈兘鍏ョ┖鎵樼洏");
+                    ConsoleHelper.WriteErrorLine($"褰撳墠浣嶇疆銆恵input.Position}銆戜笉鑳藉叆绌烘墭鐩�");
+                    return content.Error($"褰撳墠浣嶇疆銆恵input.Position}銆戜笉鑳藉叆绌烘墭鐩�");
                 }
                 else
                     return await RequestTrayInTaskAsync(input);
@@ -1060,17 +1124,17 @@
             }
 
             //var outBoundMateriel = AppSettings.app<OutBoundMateriel>("OutBoundMateriel");
-            var outBoundMateriel = _dt_ChangeoversRepository.QueryData(x => x.Status == "1").ToList();
+            //var outBoundMateriel = _dt_ChangeoversRepository.QueryData(x => x.Status == "1").ToList();
 
-            List<string>? materielCodes = outBoundMateriel.Count != 0
-                ? outBoundMateriel.Where(x => x.ProductionLine == productionLine && x.ProcessCode == area.AreaCode)
-                                  .Select(x => x.MaterielCode)
-                                  .ToList()
-                : null;
+            //List<string>? materielCodes = outBoundMateriel.Count != 0
+            //    ? outBoundMateriel.Where(x => x.ProductionLine == productionLine && x.ProcessCode == area.AreaCode)
+            //                      .Select(x => x.MaterielCode)
+            //                      .ToList()
+            //    : null;
 
-            var result = new DtStockInfo();
+            //DtStockInfo result = null;
 
-            var stockInfoList = await _stockInfoRepository.Db.Queryable<DtStockInfo>()
+            var result = await _stockInfoRepository.Db.Queryable<DtStockInfo>()
                             .Includes(x => x.LocationInfo)
                             //.Includes(x => x.StockInfoDetails)
                             .Where(x => x.AreaCode == areaCode && x.OutboundTime < DateTime.Now && x.IsFull)
@@ -1079,19 +1143,19 @@
                             .Where(x => x.LocationInfo.LocationStatus == (int)LocationEnum.InStock && x.LocationInfo.AreaId == area.AreaID && x.LocationInfo.EnalbeStatus == (int)EnableEnum.Enable)
                             //.WhereIF(!materielCodes.IsNullOrEmpty(), x => x.StockInfoDetails.Any(y => materielCodes.Contains(y.MaterielCode)))
                             .OrderBy(x => x.OutboundTime)
-                            .ToListAsync();
-            foreach (var stock in stockInfoList)
-            {
-                var hasMatchingDetail = await _stockInfoRepository.Db.Queryable<DtStockInfoDetail>()
-                    .Where(d => d.StockId == stock.Id && materielCodes.Contains(d.MaterielCode))
-                    .AnyAsync();
+                            .FirstAsync();
+            //foreach (var stock in stockInfoList)
+            //{
+            //    var hasMatchingDetail = await _stockInfoRepository.Db.Queryable<DtStockInfoDetail>()
+            //        .Where(d => d.StockId == stock.Id && materielCodes.Contains(d.MaterielCode))
+            //        .AnyAsync();
 
-                if (hasMatchingDetail)
-                {
-                    result = stock;
-                    break;
-                }
-            }
+            //    if (hasMatchingDetail)
+            //    {
+            //        result = stock;
+            //        break;
+            //    }
+            //}
 
             if (result.IsNullOrEmpty())
                 ConsoleHelper.WriteErrorLine($"{area.AreaName}-{productionLine}鏌ヨ瀹炵洏搴撳瓨淇℃伅澶辫触:鏈壘鍒扮鍚堟潯浠剁殑鏁版嵁");
@@ -1597,6 +1661,13 @@
                 ConsoleHelper.WriteErrorLine(content.ToJsonString());
                 var result = JsonConvert.DeserializeObject<ResultTrayCellsStatus>(content.Data.ToString());
                 if (result == null || !result.Success) return content.Error(result?.MOMMessage ?? "Deserialization error");
+
+                List<string> strings = station.productLine.Split(",").ToList();
+                if (!result.ProductionLine.Contains(strings))
+                {
+                    ConsoleHelper.WriteErrorLine($"鎵樼洏鍙枫�恵palletCode}銆戣姹備骇绾裤�恵result.ProductionLine}銆戜笉鍏佽鍏ャ�恵station.Roadway}銆�");
+                    return content.Error($"鎵樼洏鍙枫�恵palletCode}銆戣姹備骇绾裤�恵result.ProductionLine}銆戜笉鍏佽鍏ャ�恵station.Roadway}銆�");
+                }
 
                 if (result.SerialNos.Count > 0)
                 {
@@ -2203,13 +2274,19 @@
     {
         WebResponseContent content = new WebResponseContent();
 
-        // 鑾峰彇鐩爣鍦板潃
-        //string ToAddress = await GetRoadWayAsync(process);
         string ToAddress = string.Empty;
-        if (flag < 2)
+        if (input.Position == "1039")
+        {
+            ToAddress = await GetGWRoadWayAsync(process);
+        }
+        else if (flag < 2)
+        {
             ToAddress = await GetRoadWayAsync(process);
+        }
         else
+        {
             ToAddress = process[0];
+        }
         if (string.IsNullOrEmpty(ToAddress))
         {
             return content.Error("鏃犳硶鑾峰彇鐩爣鍦板潃");
@@ -2242,10 +2319,6 @@
         {
             task.TaskId = taskId;
             isResult = await _taskExecuteDetailRepository.AddDetailAsync(task, false, TaskDescription.GetTaskUpdateDescription(input.PalletCode, input.Position, ToAddress, TaskInStatusEnum.InNew.GetIntegralRuleTypeEnumDesc()));
-
-            //var location = _locationRepository.QueryFirst(x => x.RoadwayNo == task.Roadway && x.LocationCode == task.TargetAddress);
-            //location.LocationStatus = (int)LocationEnum.Lock;
-            //var isLocation = _locationRepository.UpdateData(location);
 
             if (isResult)
             {
@@ -2328,7 +2401,7 @@
              .Where(x => x.DeviceStatus == 1.ToString() && process.Contains(x.DeviceCode))
              .Select(x => x.DeviceCode).ToListAsync();
 
-        var minGroup = _locationRepository.QueryData(x => deviceCode.Contains(x.RoadwayNo) && x.LocationStatus == (int)LocationEnum.Free)
+        var minGroup = _locationRepository.QueryData(x => deviceCode.Contains(x.RoadwayNo) && x.LocationStatus == (int)LocationEnum.Free && x.EnalbeStatus == (int)EnableEnum.Enable)
              .GroupBy(x => x.RoadwayNo)
              .OrderByDescending(g => g.Count()) // 鏍规嵁姣忎釜缁勭殑鍏冪礌鏁伴噺鎺掑簭
              .ToList(); // 鍙栧嚭鏁伴噺鏈�澶氱殑缁�
@@ -2337,6 +2410,10 @@
         foreach (var item in minGroup)
         {
             var number = BaseDal.QueryData(x => x.TargetAddress == item.Key).Count();
+            if (item.Count() - number <= 0)
+            {
+                continue;
+            }
             result.Add(item.Key, item.Count() - number);
         }
 
@@ -2345,6 +2422,40 @@
         return minRoadwayNo;
     }
 
+
+    private static readonly object _lock = new object();
+    private static int _currentIndex = -1; // 璁板綍涓婁竴娆″垎閰嶇殑宸烽亾绱㈠紩
+    public async Task<string> GetGWRoadWayAsync(List<string> process)
+    {
+        var deviceCode = await SqlSugarHelper.DbWCS.Queryable<Dt_DeviceInfo>()
+             .Where(x => x.DeviceStatus == 1.ToString() && process.Contains(x.DeviceCode))
+             .Select(x => x.DeviceCode).ToListAsync();
+
+        var availableRoadways = _locationRepository.QueryData(x => deviceCode.Contains(x.RoadwayNo) && x.LocationStatus == (int)LocationEnum.Free && x.EnalbeStatus == (int)EnableEnum.Enable)
+                            .GroupBy(x => x.RoadwayNo)
+                            .Select(g => new
+                            {
+                                RoadwayNo = g.Key,
+                                Count = g.Count(),
+                                TargetCount = BaseDal.QueryData(t => t.TargetAddress == g.Key).Count()
+                            })
+                            .Where(x => x.Count - x.TargetCount > 0 && x.TargetCount < 2)
+                            .OrderByDescending(x => x.Count)
+                            .ToList();
+
+        if (!availableRoadways.Any())
+        {
+            return null; // 鎴栨姏鍑哄紓甯�
+        }
+
+        // 杞鍒嗛厤
+        lock (_lock)
+        {
+            _currentIndex = (_currentIndex + 1) % availableRoadways.Count;
+            return availableRoadways[_currentIndex].RoadwayNo;
+        }
+    }
+
     /// <summary>
     /// 鏍规嵁鍖哄煙鑾峰彇宸烽亾鎴栫珯鍙�
     /// </summary>

--
Gitblit v1.9.3