feat(机器人任务): 实现本地创建机器人任务功能
refactor(任务选择器): 优化堆垛机任务选择逻辑并增加日志
fix(库存服务): 完善拆盘和换盘操作后的库存清理逻辑
style(前端): 调整机器人任务表格列显示和字段命名
perf(堆垛机作业): 增加关键步骤日志输出提升可观测性
docs: 添加本地创建机器人任务设计文档
chore: 更新子代理追踪和任务状态文件
| | |
| | | { |
| | | "updatedAt": "2026-04-22T08:00:38.578Z", |
| | | "updatedAt": "2026-04-23T06:52:14.501Z", |
| | | "missions": [ |
| | | { |
| | | "id": "session:9007b9ea-1eb6-4d24-8fe7-2c3a949eac88:none", |
| | |
| | | "sourceKey": "session-stop:a70a5d0efcc81d263" |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | "id": "session:97f7871e-58c9-49b8-b7b1-d67ca866e495:none", |
| | | "source": "session", |
| | | "name": "none", |
| | | "objective": "Session mission", |
| | | "createdAt": "2026-04-23T02:51:49.771Z", |
| | | "updatedAt": "2026-04-23T02:55:09.431Z", |
| | | "status": "done", |
| | | "workerCount": 1, |
| | | "taskCounts": { |
| | | "total": 1, |
| | | "pending": 0, |
| | | "blocked": 0, |
| | | "inProgress": 0, |
| | | "completed": 1, |
| | | "failed": 0 |
| | | }, |
| | | "agents": [ |
| | | { |
| | | "name": "Explore:a90c490", |
| | | "role": "Explore", |
| | | "ownership": "a90c490b825a81654", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-23T02:55:09.431Z" |
| | | } |
| | | ], |
| | | "timeline": [ |
| | | { |
| | | "id": "session-start:a90c490b825a81654:2026-04-23T02:51:49.771Z", |
| | | "at": "2026-04-23T02:51:49.771Z", |
| | | "kind": "update", |
| | | "agent": "Explore:a90c490", |
| | | "detail": "started Explore:a90c490", |
| | | "sourceKey": "session-start:a90c490b825a81654" |
| | | }, |
| | | { |
| | | "id": "session-stop:a90c490b825a81654:2026-04-23T02:55:09.431Z", |
| | | "at": "2026-04-23T02:55:09.431Z", |
| | | "kind": "completion", |
| | | "agent": "Explore:a90c490", |
| | | "detail": "completed", |
| | | "sourceKey": "session-stop:a90c490b825a81654" |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | "id": "session:7faab803-bef5-44c3-a296-6a6757237fd7:none", |
| | | "source": "session", |
| | | "name": "none", |
| | | "objective": "Session mission", |
| | | "createdAt": "2026-04-23T06:52:14.501Z", |
| | | "updatedAt": "2026-04-23T06:52:14.501Z", |
| | | "status": "running", |
| | | "workerCount": 1, |
| | | "taskCounts": { |
| | | "total": 1, |
| | | "pending": 0, |
| | | "blocked": 0, |
| | | "inProgress": 1, |
| | | "completed": 0, |
| | | "failed": 0 |
| | | }, |
| | | "agents": [ |
| | | { |
| | | "name": "Explore:a20f390", |
| | | "role": "Explore", |
| | | "ownership": "a20f390d480b5890b", |
| | | "status": "running", |
| | | "currentStep": null, |
| | | "latestUpdate": null, |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-23T06:52:14.501Z" |
| | | } |
| | | ], |
| | | "timeline": [ |
| | | { |
| | | "id": "session-start:a20f390d480b5890b:2026-04-23T06:52:14.501Z", |
| | | "at": "2026-04-23T06:52:14.501Z", |
| | | "kind": "update", |
| | | "agent": "Explore:a20f390", |
| | | "detail": "started Explore:a20f390", |
| | | "sourceKey": "session-start:a20f390d480b5890b" |
| | | } |
| | | ] |
| | | } |
| | | ] |
| | | } |
| | |
| | | "status": "completed", |
| | | "completed_at": "2026-04-22T08:00:38.576Z", |
| | | "duration_ms": 191600 |
| | | }, |
| | | { |
| | | "agent_id": "a90c490b825a81654", |
| | | "agent_type": "Explore", |
| | | "started_at": "2026-04-23T02:51:49.771Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-23T02:55:09.429Z", |
| | | "duration_ms": 199658 |
| | | }, |
| | | { |
| | | "agent_id": "a20f390d480b5890b", |
| | | "agent_type": "Explore", |
| | | "started_at": "2026-04-23T06:52:14.501Z", |
| | | "parent_mode": "none", |
| | | "status": "running" |
| | | } |
| | | ], |
| | | "total_spawned": 147, |
| | | "total_completed": 170, |
| | | "total_spawned": 149, |
| | | "total_completed": 171, |
| | | "total_failed": 0, |
| | | "last_updated": "2026-04-22T08:00:38.695Z" |
| | | "last_updated": "2026-04-23T06:52:14.616Z" |
| | | } |
| | |
| | | { |
| | | title: "æ¯å¦æç", |
| | | field: "isSplitPallet", |
| | | type: "checkbox", |
| | | type: "select", |
| | | dataKey: "isTrue", |
| | | data: [], |
| | | }, |
| | | { |
| | | title: "æ¯å¦ç»ç", |
| | | field: "isGroupPallet", |
| | | type: "checkbox", |
| | | type: "select", |
| | | dataKey: "isTrue", |
| | | data: [], |
| | | }, |
| | | { |
| | | title: "åçµè¯æ¨¡å¼", |
| | | field: "isInFakeBatteryMode", |
| | | type: "checkbox", |
| | | type: "select", |
| | | dataKey: "isTrue", |
| | | data: [], |
| | | }, |
| | | ], |
| | | [ |
| | | { |
| | | title: "æ¯å¦æ«ç NG", |
| | | field: "isScanNG", |
| | | type: "checkbox", |
| | | type: "select", |
| | | dataKey: "isTrue", |
| | | data: [], |
| | | }, |
| | | { |
| | | title: "çµè¯æ¯å¦å°ä½", |
| | | field: "batteryArrived", |
| | | type: "checkbox", |
| | | type: "select", |
| | | dataKey: "isTrue", |
| | | data: [], |
| | | }, |
| | | { |
| | | title: "æ¶æ¯å·²è®¢é
", |
| | | field: "isEventSubscribed", |
| | | type: "checkbox", |
| | | type: "select", |
| | | dataKey: "isTrue", |
| | | data: [], |
| | | }, |
| | | ], |
| | | ]); |
| | |
| | | type: "string", |
| | | width: 120, |
| | | align: "left", |
| | | hidden: true, |
| | | }, |
| | | { |
| | | field: "robotTargetAddress", |
| | |
| | | type: "string", |
| | | width: 120, |
| | | align: "left", |
| | | hidden: true, |
| | | }, |
| | | { |
| | | field: "robotSourceAddressLineCode", |
| | | title: "æ¥æºçº¿ä»£ç ", |
| | | title: "æ¥æºçº¿ä½å°å", |
| | | type: "string", |
| | | width: 130, |
| | | align: "left", |
| | | }, |
| | | { |
| | | field: "robotTargetAddressLineCode", |
| | | title: "ç®æ 线代ç ", |
| | | title: "ç®æ 线ä½å°å", |
| | | type: "string", |
| | | width: 130, |
| | | align: "left", |
| | | hidden: true, |
| | | }, |
| | | { |
| | | field: "robotSourceAddressPalletCode", |
| | | title: "æ¥æºæç代ç ", |
| | | title: "æ¥æºæç", |
| | | type: "string", |
| | | width: 130, |
| | | align: "left", |
| | | hidden: true, |
| | | }, |
| | | { |
| | | field: "robotTargetAddressPalletCode", |
| | | title: "ç®æ æç代ç ", |
| | | title: "ç®æ æç", |
| | | type: "string", |
| | | width: 130, |
| | | align: "left", |
| | | hidden: true, |
| | | }, |
| | | { |
| | | field: "robotExceptionMessage", |
| | |
| | | type: "datetime", |
| | | width: 160, |
| | | align: "left", |
| | | hidden: true, |
| | | }, |
| | | { |
| | | field: "robotremark", |
| | |
| | | type: "string", |
| | | width: 100, |
| | | align: "left", |
| | | hidden: true, |
| | | }, |
| | | { |
| | | field: "createDate", |
| | |
| | | width: 160, |
| | | align: "left", |
| | | sortable: true, |
| | | hidden: true, |
| | | }, |
| | | { |
| | | field: "modifier", |
| | |
| | | type: "string", |
| | | width: 100, |
| | | align: "left", |
| | | hidden: true, |
| | | }, |
| | | { |
| | | field: "modifyDate", |
| | |
| | | type: "datetime", |
| | | width: 160, |
| | | align: "left", |
| | | hidden: true, |
| | | }, |
| | | ]); |
| | | |
| | |
| | | WebResponseContent ReceiveWMSTask([NotNull] WMSTaskDTO taskDTO, StockDTO stockDTO); |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// è°ç¨WMSæ¥å£è·åæºæ¢°æä»»å¡ |
| | | /// </summary> |
| | | /// <param name="task"></param> |
| | | /// <returns></returns> |
| | | /// <param name="task">åºåºä»»å¡</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | WebResponseContent GetWMSRobotTask(Dt_Task task); |
| | | |
| | | /// <summary> |
| | | /// 卿¬å°ç´æ¥åå»ºæºæ¢°æä»»å¡ï¼ä¸è°ç¨WMSæ¥å£ |
| | | /// </summary> |
| | | /// <param name="task">åºåºä»»å¡</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | WebResponseContent CreateLocalRobotTask(Dt_Task task); |
| | | |
| | | int MapWarehouseIdConfigKey(string? targetAddress); |
| | | string ResolveRobotRuleValue(string? targetAddress, string addressSectionName, string? fallback); |
| | | } |
| | |
| | | }, |
| | | "Logging": { |
| | | "LogLevel": { |
| | | "Default": "Debug", |
| | | "Default": "Warning", |
| | | "Microsoft.AspNetCore": "Warning", |
| | | "Quartz": "Debug" |
| | | } |
| | |
| | | "10030": "11010" |
| | | } |
| | | }, |
| | | "RobotAddressRules": { |
| | | "11068": [ "1", "2" ], |
| | | "11001": [ "3", "1" ], |
| | | "11010": [ "4", "2" ], |
| | | "2101": [ "1", "3" ], |
| | | "2103": [ "2", "4" ] |
| | | }, |
| | | "RedisConfig": { |
| | | "Enabled": true, //æ¯å¦å¯ç¨Redisï¼falseæ¶ä»
使ç¨å
åç¼å |
| | | "ConnectionString": "127.0.0.1:6379,password=P@ssw0rd,defaultDatabase=0,connectTimeout=5000,abortConnect=false", //Redisè¿æ¥å符串 |
| | |
| | | |
| | | if (task.TaskStatus == (int)TaskOutStatusEnum.Line_OutFinish && task.TaskType == (int)TaskOutboundTypeEnum.OutEmpty) |
| | | { |
| | | _robotTaskService.GetWMSRobotTask(task); |
| | | _robotTaskService.CreateLocalRobotTask(task); |
| | | //if (!content.Status) |
| | | //{ |
| | | // return content; |
| | |
| | | task.Modifier = "System"; |
| | | |
| | | // éç¥WMSåºåºå®æå¹¶è·åè¿åç»æ |
| | | return NotifyWMSOutboundFinish(task); |
| | | return NotifyWMSOutboundFinish(task); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | if (wMSTask == null) |
| | | return WebResponseContent.Instance.Error($"è·åWMSç³»ç»ç©ºæçåºåºä»»å¡å¤±è´¥,ä»»å¡å·:ã{task.TaskNum}ã,æçå·:ã{task.PalletCode}ã,é误信æ¯:ãWMSæªè¿åææä»»å¡æ°æ®ã"); |
| | | |
| | | return WebResponseContent.Instance.OK("æå", new List<WMSTaskDTO> { wMSTask }); |
| | | if (TaskService.ReceiveWMSTask(new List<WMSTaskDTO> { wMSTask }).Status) |
| | | return WebResponseContent.Instance.OK("æå"); |
| | | |
| | | return WebResponseContent.Instance.Error("æ¥æ¶WMSä»»å¡å¤±è´¥"); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 卿¬å°ç´æ¥åå»ºæºæ¢°æä»»å¡ï¼ä¸è°ç¨WMSæ¥å£ã |
| | | /// æ ¹æ®ç®æ å°åè§£æä»»å¡ç±»åï¼æå»ºä»»å¡æ°æ®å¹¶åå
¥æ°æ®åºã |
| | | /// </summary> |
| | | /// <param name="task">åºåºä»»å¡å®ä½</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | public WebResponseContent CreateLocalRobotTask(Dt_Task task) |
| | | { |
| | | WebResponseContent content = new(); |
| | | try |
| | | { |
| | | // æ ¹æ®ç®æ å°åè§£æä»»å¡ç±»åé
ç½®é® |
| | | string configKey = ResolveRobotTaskConfigKey(task.TargetAddress); |
| | | |
| | | // æå»ºStockæ°æ® |
| | | StockDTO stock = BuildRobotTaskStock(task, configKey); |
| | | |
| | | // è·åæååæ¾ç½®å°åç线ä½é
ç½®ï¼å¦ææï¼ |
| | | var section = App.Configuration.GetSection("RobotTaskAddressRules").GetSection(stock?.TargetLineNo ?? string.Empty).GetChildren().Select(c => c.Value).ToArray(); |
| | | if (section.Length < 2) |
| | | return WebResponseContent.Instance.Error($"æªæ¾å°çº¿ä½[{stock?.TargetLineNo}]çå°åé
ç½®"); |
| | | |
| | | // å建æ¬å°æºå¨äººä»»å¡ |
| | | Dt_RobotTask robotTask = new() |
| | | { |
| | | RobotTaskNum = Random.Shared.Next(), |
| | | RobotSourceAddress = section[0]!, |
| | | RobotTargetAddress = section[1]!, |
| | | RobotSourceAddressLineCode = stock?.SourceLineNo ?? string.Empty, |
| | | RobotTargetAddressLineCode = stock?.TargetLineNo ?? string.Empty, |
| | | RobotRoadway = stock?.Roadway ?? string.Empty, |
| | | RobotSourceAddressPalletCode = stock?.SourcePalletNo ?? string.Empty, |
| | | RobotTargetAddressPalletCode = stock?.TargetPalletNo ?? string.Empty, |
| | | RobotTaskType = MapConfigKeyToRobotTaskType(configKey), |
| | | RobotTaskState = (int)TaskRobotStatusEnum.RobotNew, |
| | | RobotGrade = task.Grade, |
| | | Creater = "WCS_Local", |
| | | RobotTaskTotalNum = 1, |
| | | CreateDate = DateTime.Now |
| | | }; |
| | | |
| | | BaseDal.AddData(robotTask); |
| | | |
| | | _taskExecuteDetailService.AddTaskExecuteDetail(new List<int> { robotTask.RobotTaskNum }, "æ¬å°å建æºå¨äººä»»å¡"); |
| | | |
| | | QuartzLogHelper.LogInfo(_logger, $"æ¬å°å建æºå¨äººä»»å¡æå,ä»»å¡å·:ã{robotTask.RobotTaskNum}ã,æºå°å:ã{robotTask.RobotSourceAddress}ã,ç®æ å°å:ã{robotTask.RobotTargetAddress}ã,ä»»å¡ç±»å:ã{configKey}ã", "RobotTaskService"); |
| | | |
| | | content = WebResponseContent.Instance.OK("æ¬å°å建æºå¨äººä»»å¡æå", robotTask); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | QuartzLogHelper.LogError(_logger, $"æ¬å°å建æºå¨äººä»»å¡å¤±è´¥,ä»»å¡å·:ã{task.TaskNum}ã,é误信æ¯:{ex.Message}", "RobotTaskService"); |
| | | content = WebResponseContent.Instance.Error($"æ¬å°å建æºå¨äººä»»å¡å¤±è´¥,é误信æ¯:{ex.Message}"); |
| | | } |
| | | return content; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å°é
ç½®é®æ å°å°æºæ¢°æä»»å¡ç±»åæä¸¾å¼ã |
| | | /// </summary> |
| | | /// <param name="configKey">é
ç½®é®åç§°</param> |
| | | /// <returns>ä»»å¡ç±»åæä¸¾å¼</returns> |
| | | public int MapConfigKeyToRobotTaskType(string? configKey) |
| | | { |
| | | return configKey switch |
| | | { |
| | | nameof(ConfigKey.CreateRobotGroupPalletTask) => (int)RobotTaskTypeEnum.GroupPallet, |
| | | nameof(ConfigKey.CreateRobotSplitPalletTask) => (int)RobotTaskTypeEnum.SplitPallet, |
| | | _ => (int)RobotTaskTypeEnum.ChangePallet |
| | | }; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ ¹æ®è¾éçº¿ç®æ å°åè§£ææºæ¢°æä»»å¡æ¥å£ã |
| | | /// è§åï¼ |
| | | /// 1. ä»é
置读å精确å°åæ å°ï¼AddressMapï¼ |
| | |
| | | // - æèä¸æç©æï¼RobotArmObject == 1ï¼ |
| | | // - ä»»å¡ç¶æä¸º RobotPickFinishï¼å·²è®°å½åè´§å®æï¼ |
| | | if ((latestState.CurrentAction == "PickFinished" || latestState.CurrentAction == "AllPickFinished") |
| | | && (latestState.RobotArmObject.IsNullOrEmpty() || latestState.RobotArmObject == 1) |
| | | //&& (latestState.RobotArmObject.IsNullOrEmpty() || latestState.RobotArmObject == 1) |
| | | && task.RobotTaskState == TaskRobotStatusEnum.RobotPickFinish.GetHashCode()) |
| | | { |
| | | QuartzLogHelper.LogInfo(_logger, $"ExecuteAsyncï¼æ»¡è¶³æ¾è´§æ¡ä»¶ï¼å¼å§ä¸åæ¾è´§ä»»å¡,ä»»å¡å·: {task.RobotTaskNum}", latestState.RobotCrane?.DeviceName ?? ipAddress); |
| | |
| | | // - æè䏿 ç©æï¼RobotArmObject == 0ï¼ |
| | | // - ä»»å¡ç¶æä¸º RobotPutFinish æä¸æ¯ RobotExecuting |
| | | else if ((latestState.CurrentAction == "PutFinished" || latestState.CurrentAction == "AllPutFinished" || latestState.CurrentAction.IsNullOrEmpty()) |
| | | && (latestState.RobotArmObject.IsNullOrEmpty() || latestState.RobotArmObject == 0) |
| | | //&& (latestState.RobotArmObject.IsNullOrEmpty() || latestState.RobotArmObject == 0) |
| | | && (task.RobotTaskState == TaskRobotStatusEnum.RobotPutFinish.GetHashCode() || task.RobotTaskState != TaskRobotStatusEnum.RobotExecuting.GetHashCode())) |
| | | { |
| | | QuartzLogHelper.LogInfo(_logger, $"ExecuteAsyncï¼æ»¡è¶³åè´§æ¡ä»¶ï¼å¼å§ä¸ååè´§ä»»å¡ï¼ä»»å¡å·: {task.RobotTaskNum}", latestState.RobotCrane?.DeviceName ?? ipAddress); |
| | |
| | | { |
| | | if (stateForUpdate.CellBarcode.Contains(trayBarcode1) || stateForUpdate.CellBarcode.Contains(trayBarcode2)) |
| | | { |
| | | QuartzLogHelper.LogInfo(_logger, $"HandlePutFinishedStateAsyncï¼è¯»åçæçæ¡ç å·²åå¨ï¼å¯è½åå¨éå¤ï¼ä»»å¡å·: {task.RobotTaskNum}", stateForUpdate?.RobotCrane?.DeviceName ?? ipAddress); |
| | | QuartzLogHelper.LogInfo(_logger, $"HandlePutFinishedStateAsyncï¼è¯»åççµè¯æ¡ç å·²åå¨ï¼å¯è½åå¨éå¤ï¼ä»»å¡å·: {task.RobotTaskNum}", stateForUpdate?.RobotCrane?.DeviceName ?? ipAddress); |
| | | |
| | | // åéåè´§æä»¤ æ è®°æ«ç NGï¼æ¾è´§æ¶ä¸ä½¿ç¨è¿äºæ¡ç ï¼å¹¶æ¾å
¥NGå£ |
| | | //await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate, true); |
| | |
| | | } |
| | | else |
| | | { |
| | | QuartzLogHelper.LogInfo(_logger, $"HandlePutFinishedStateAsyncï¼è¯»åçæçæ¡ç å¯ä¸ï¼ç»§ç»æ§è¡ï¼ä»»å¡å·: {task.RobotTaskNum}", stateForUpdate?.RobotCrane?.DeviceName ?? ipAddress); |
| | | if (trayBarcode1.Length < 13 || trayBarcode2.Length < 13) |
| | | { |
| | | QuartzLogHelper.LogError(_logger, $"HandlePutFinishedStateAsyncï¼çµè¯æ¡ç é¿åº¦ä¸è¾¾æ ï¼ä»»å¡å·: {task.RobotTaskNum}ï¼è¯»åçµè¯æ¡ç æå: ã{trayBarcode1}ã-----ã{trayBarcode2}ã", stateForUpdate?.RobotCrane?.DeviceName ?? ipAddress); |
| | | return; |
| | | } |
| | | |
| | | QuartzLogHelper.LogInfo(_logger, $"HandlePutFinishedStateAsyncï¼è¯»åççµè¯æ¡ç å¯ä¸ï¼ç»§ç»æ§è¡ï¼ä»»å¡å·: {task.RobotTaskNum}", stateForUpdate?.RobotCrane?.DeviceName ?? ipAddress); |
| | | |
| | | // å°æ¡ç æ·»å å°ç¶æä¸ï¼ä¾åç»æ¾è´§æ¶ä½¿ç¨ |
| | | stateForUpdate.CellBarcode = new List<string>() |
| | |
| | | } |
| | | |
| | | // è®°å½æ¥å¿ï¼è¯»åæçæ¡ç æå |
| | | QuartzLogHelper.LogInfo(_logger, $"HandlePutFinishedStateAsyncï¼è¯»åæçæ¡ç æå: ã{trayBarcode1}ã-----ã{trayBarcode2}ãï¼ä»»å¡å·: {task.RobotTaskNum}", stateForUpdate?.RobotCrane?.DeviceName ?? ipAddress); |
| | | QuartzLogHelper.LogInfo(_logger, $"HandlePutFinishedStateAsyncï¼è¯»åçµè¯æ¡ç æå: ã{trayBarcode1}ã-----ã{trayBarcode2}ãï¼ä»»å¡å·: {task.RobotTaskNum}", stateForUpdate?.RobotCrane?.DeviceName ?? ipAddress); |
| | | |
| | | // åéåè´§æä»¤ |
| | | await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate); |
| | |
| | | QuartzLogHelper.LogInfo(_logger, "Executeï¼è®¢é
ä»»å¡å®æäºä»¶ï¼è®¾å¤: {DeviceCode}", "订é
ä»»å¡å®æäºä»¶", _deviceCode, _deviceCode); |
| | | } |
| | | |
| | | QuartzLogHelper.LogInfo(_logger, $"å¼å§æ£æ¥å åæºå®æç¶æï¼ã{_deviceCode}ã", _deviceCode); |
| | | // ========== æ£æ¥å åæºä»»å¡å®æç¶æ ========== |
| | | commonStackerCrane.CheckStackerCraneTaskCompleted(); |
| | | |
| | | QuartzLogHelper.LogInfo(_logger, $"æ£æ¥å®æï¼æ£å¨çå¬å åæºä»»å¡å®æï¼ã{_deviceCode}ã", _deviceCode); |
| | | |
| | | // ========== æ£æ¥æ¯å¦å¯ä»¥åéæ°ä»»å¡ ========== |
| | | //if (!commonStackerCrane.IsCanSendTask(commonStackerCrane.Communicator, commonStackerCrane.DeviceProDTOs, commonStackerCrane.DeviceProtocolDetailDTOs)) |
| | |
| | | // å åæºä¸å¯ç¨ï¼å¦æ£å¨æ§è¡ä¸ä¸ä»»å¡ï¼ï¼ç´æ¥è¿å |
| | | return Task.CompletedTask; |
| | | } |
| | | |
| | | QuartzLogHelper.LogInfo(_logger, $"å åæºå¯ä¸åä»»å¡ï¼ã{_deviceCode}ã", _deviceCode); |
| | | |
| | | // ========== éæ©ä»»å¡ ========== |
| | | // ä»»å¡éæ©ä¸æ²å°ä¸ç¨éæ©å¨ |
| | |
| | | return Task.CompletedTask; |
| | | } |
| | | |
| | | |
| | | QuartzLogHelper.LogInfo(_logger, $"è·åå°ä»»å¡ï¼å¼å§æå»ºä»»å¡ä¸åå½ä»¤ï¼ã{_deviceCode}ã", _deviceCode); |
| | | |
| | | // ========== æå»ºå½ä»¤ ========== |
| | | // å½ä»¤æå»ºä¸æ²å°ä¸ç¨æå»ºå¨ |
| | |
| | | return Task.CompletedTask; |
| | | } |
| | | |
| | | |
| | | QuartzLogHelper.LogInfo(_logger, $"å½ä»¤æå»ºå®æï¼å¼å§ä¸åä»»å¡ï¼ã{_deviceCode}ã", _deviceCode); |
| | | |
| | | // ========== åéå½ä»¤ ========== |
| | | bool sendFlag = SendStackerCraneCommand(commonStackerCrane, stackerCraneTaskCommand); |
| | | if (sendFlag) |
| | |
| | | Dt_Task? candidateTask; |
| | | var deviceCode = commonStackerCrane.DeviceCode; |
| | | |
| | | QuartzLogHelper.LogDebug(_logger, $"å¼å§éæ©ä»»å¡ï¼è®¾å¤: {deviceCode}ï¼ä¸ä¸ä»»å¡ç±»å: {commonStackerCrane.LastTaskType}",commonStackerCrane.DeviceName); |
| | | QuartzLogHelper.LogInfo(_logger, $"å¼å§éæ©ä»»å¡ï¼è®¾å¤: {deviceCode}ï¼ä¸ä¸ä»»å¡ç±»å: {commonStackerCrane.LastTaskType}", commonStackerCrane.DeviceName); |
| | | |
| | | // æ ¹æ®ä¸ä¸ä»»å¡ç±»åå³å®æ¥è¯¢çç¥ |
| | | if (commonStackerCrane.LastTaskType == null || commonStackerCrane.LastTaskType == TaskRelocationTypeEnum.Relocation.GetHashCode()) |
| | | { |
| | | // 没æä¸ä¸ä»»å¡ç±»åï¼æ¥è¯¢æ®éä»»å¡ |
| | | candidateTask = _taskService.QueryStackerCraneTask(deviceCode); |
| | | QuartzLogHelper.LogDebug(_logger, $"æ¥è¯¢æ®éä»»å¡ï¼è®¾å¤: {deviceCode}ï¼ç»æ: {candidateTask?.TaskNum}", commonStackerCrane.DeviceName); |
| | | QuartzLogHelper.LogInfo(_logger, $"æ¥è¯¢æ®éä»»å¡ï¼è®¾å¤: {deviceCode}ï¼ç»æ: {candidateTask?.TaskNum}", commonStackerCrane.DeviceName); |
| | | } |
| | | else if (commonStackerCrane.LastTaskType.GetValueOrDefault().GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup) |
| | | { |
| | |
| | | candidateTask = _taskService.QueryStackerCraneInTask(deviceCode); |
| | | // å¦ææ²¡æå
¥åºä»»å¡ï¼åæ¥ä¸ä¸åºåºä»»å¡ |
| | | candidateTask ??= _taskService.QueryStackerCraneOutTask(deviceCode); |
| | | QuartzLogHelper.LogDebug(_logger, $"åºåºåä¼å
æ¥å
¥åºï¼è®¾å¤: {deviceCode}ï¼ç»æ: {candidateTask?.TaskNum}", commonStackerCrane.DeviceName); |
| | | QuartzLogHelper.LogInfo(_logger, $"åºåºåä¼å
æ¥å
¥åºï¼è®¾å¤: {deviceCode}ï¼ç»æ: {candidateTask?.TaskNum}", commonStackerCrane.DeviceName); |
| | | } |
| | | else |
| | | { |
| | | // ä¸ä¸ä»»å¡æ¯å
¥åºï¼éåºåºï¼ï¼ä¼å
æ¥åºåºä»»å¡ |
| | | candidateTask = _taskService.QueryStackerCraneOutTask(deviceCode); |
| | | QuartzLogHelper.LogDebug(_logger, $"å
¥åºåä¼å
æ¥åºåºï¼è®¾å¤: {deviceCode}ï¼ç»æ: {candidateTask?.TaskNum}", commonStackerCrane.DeviceName); |
| | | |
| | | // å¦ææ²¡æåºåºä»»å¡ï¼åæ¥ä¸ä¸å
¥åºä»»å¡ |
| | | candidateTask ??= _taskService.QueryStackerCraneInTask(deviceCode); |
| | | QuartzLogHelper.LogInfo(_logger, $"å
¥åºåä¼å
æ¥åºåºï¼è®¾å¤: {deviceCode}ï¼ç»æ: {candidateTask?.TaskNum}", commonStackerCrane.DeviceName); |
| | | } |
| | | |
| | | // å¦ææ²¡æåéä»»å¡ï¼è¿å null |
| | | if (candidateTask == null) |
| | | { |
| | | QuartzLogHelper.LogDebug(_logger, $"没æåéä»»å¡ï¼è®¾å¤: {deviceCode}", commonStackerCrane.DeviceName); |
| | | QuartzLogHelper.LogInfo(_logger, $"没æåéä»»å¡ï¼è®¾å¤: {deviceCode}", commonStackerCrane.DeviceName); |
| | | return null; |
| | | } |
| | | |
| | | // 妿䏿¯åºåºä»»å¡ï¼ç´æ¥è¿å |
| | | if (candidateTask.TaskType.GetTaskTypeGroup() != TaskTypeGroup.OutbondGroup) |
| | | { |
| | | QuartzLogHelper.LogDebug(_logger, $"éä¸éåºåºä»»å¡ï¼ä»»å¡å·: {candidateTask.TaskNum}ï¼ä»»å¡ç±»å: {candidateTask.TaskType}", commonStackerCrane.DeviceName); |
| | | QuartzLogHelper.LogInfo(_logger, $"éä¸éåºåºä»»å¡ï¼ä»»å¡å·: {candidateTask.TaskNum}ï¼ä»»å¡ç±»å: {candidateTask.TaskType}", commonStackerCrane.DeviceName); |
| | | return candidateTask; |
| | | } |
| | | |
| | |
| | | Dt_Task? selectedTask = TrySelectOutboundTask(candidateTask); |
| | | if (selectedTask != null) |
| | | { |
| | | QuartzLogHelper.LogDebug(_logger, $"éä¸åºåºä»»å¡ï¼ä»»å¡å·: {selectedTask.TaskNum}", commonStackerCrane.DeviceName); |
| | | QuartzLogHelper.LogInfo(_logger, $"éä¸åºåºä»»å¡ï¼ä»»å¡å·: {selectedTask.TaskNum}", commonStackerCrane.DeviceName); |
| | | return selectedTask; |
| | | } |
| | | |
| | |
| | | selectedTask = TrySelectOutboundTask(sameStationTask); |
| | | if (selectedTask != null) |
| | | { |
| | | QuartzLogHelper.LogDebug(_logger, $"éä¸åç«å°å¤éåºåºä»»å¡ï¼ä»»å¡å·: {selectedTask.TaskNum}", commonStackerCrane.DeviceName); |
| | | QuartzLogHelper.LogInfo(_logger, $"éä¸åç«å°å¤éåºåºä»»å¡ï¼ä»»å¡å·: {selectedTask.TaskNum}", commonStackerCrane.DeviceName); |
| | | return selectedTask; |
| | | } |
| | | } |
| | |
| | | selectedTask = TrySelectOutboundTask(alternativeTask); |
| | | if (selectedTask != null) |
| | | { |
| | | QuartzLogHelper.LogDebug(_logger, $"éä¸å¤éåºåºä»»å¡ï¼ä»»å¡å·: {selectedTask.TaskNum}", commonStackerCrane.DeviceName); |
| | | QuartzLogHelper.LogInfo(_logger, $"éä¸å¤éåºåºä»»å¡ï¼ä»»å¡å·: {selectedTask.TaskNum}", commonStackerCrane.DeviceName); |
| | | return selectedTask; |
| | | } |
| | | } |
| | | |
| | | // 没æå¯ç¨åºåºä»»å¡ï¼å°è¯è¿åå
¥åºä»»å¡ |
| | | var inboundTask = _taskService.QueryStackerCraneInTask(deviceCode); |
| | | QuartzLogHelper.LogDebug(_logger, $"è¿åå
¥åºä»»å¡ï¼ä»»å¡å·: {inboundTask?.TaskNum}", commonStackerCrane.DeviceName); |
| | | QuartzLogHelper.LogInfo(_logger, $"è¿åå
¥åºä»»å¡ï¼ä»»å¡å·: {inboundTask?.TaskNum}", commonStackerCrane.DeviceName); |
| | | return inboundTask; |
| | | } |
| | | |
| | |
| | | /// <summary> |
| | | /// 髿¸©1å·åºåºå°åå表ï¼è½®è¯¢ï¼ |
| | | /// </summary> |
| | | public static readonly string[] GW1_ADDRESSES = { "11001", "11010" }; |
| | | public static readonly string[] GW1_ADDRESSES = { "11001" }; |
| | | |
| | | /// <summary> |
| | | /// 髿¸©2å·åºåºå°å |
| | |
| | | /// <returns>åºåä¿¡æ¯</returns> |
| | | public async Task<Dt_StockInfo> GetStockInfoAsync(string palletCode, string locationCode) |
| | | { |
| | | return await BaseDal.QueryFirstAsync(x => x.PalletCode == palletCode && x.LocationCode == locationCode); |
| | | return await BaseDal.QueryDataNavFirstAsync(x => x.PalletCode == palletCode && x.LocationCode == locationCode); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | var result = await StockInfoDetailService.Repository.UpdateDataAsync(detailEntities); |
| | | if (!result) return content.Error("æ¢ç失败"); |
| | | |
| | | // æ£æ¥æºæçæ¯å¦è¿æå©ä½åºåæç»ï¼è¥æ åå 餿ºæçåºå头 |
| | | var remainingSourceDetails = StockInfoDetailService.Repository.QueryData(d => d.StockId == sourceStock.Id); |
| | | if (!remainingSourceDetails.Any()) |
| | | { |
| | | if (await StockInfoService.Repository.Db.Deleteable<Dt_StockInfo>().Where(s => s.Id == sourceStock.Id).ExecuteCommandAsync() <= 0) |
| | | return content.Error("å 餿ºæçåºå失败"); |
| | | } |
| | | |
| | | return content.OK("æ¢çæå"); |
| | | }); |
| | | } |
| | |
| | | if (await StockInfo_HtyService.Repository.AddDataAsync(CreateStockHistory(new[] { sourceStock }, "æç")) <= 0) |
| | | return content.Error("æçåå²è®°å½ä¿å失败"); |
| | | |
| | | // å é¤å·²æåºçåºåæç» |
| | | var detailIds = detailEntities.Select(d => d.Id).ToList(); |
| | | if (await StockInfoDetailService.Repository.Db.Deleteable<Dt_StockInfoDetail>().In(detailIds).ExecuteCommandAsync() <= 0) |
| | | return content.Error("å é¤åºåæç»å¤±è´¥"); |
| | | |
| | | // æ£æ¥æºæçæ¯å¦è¿æå©ä½åºåæç»ï¼è¥æ åå 餿ºæçåºå头 |
| | | var remainingSourceDetails = StockInfoDetailService.Repository.QueryData(d => d.StockId == sourceStock.Id); |
| | | if (!remainingSourceDetails.Any()) |
| | | { |
| | | if (await StockInfoService.Repository.Db.Deleteable<Dt_StockInfo>().Where(s => s.Id == sourceStock.Id).ExecuteCommandAsync() <= 0) |
| | | return content.Error("å 餿ºæçåºå失败"); |
| | | } |
| | | |
| | | return content.OK("æçæå"); |
| | | }); |
| | | } |
| | |
| | | "BaseUrl": "http://192.168.98.11:20033", |
| | | "Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjMwMTcyNzM5Mzk5NzYxOTIwIiwibmFtZSI6IlBBQ0voo4XphY3lt6XkvY0wMSIsIkZhY3RvcnlJZCI6IjEyMzQ1NiIsIlNpdGVJZCI6IjEyMzQ1NiIsIkNvZGUiOiJYWExQQUNLMDRBRTAzMiIsIm5iZiI6MTcwNDE4NzY5MCwiZXhwIjoyMTQ1NjkxNjkwLCJpc3MiOiJodHRwczovL3d3dy5oeW1zb24uY29tIiwiYXVkIjoiaHR0cHM6Ly93d3cuaHltc29uLmNvbSJ9.An1BE7UgfcSP--LtTOmmmWVE2RQFPDahLkDg1xy5KqY" |
| | | }, |
| | | "RobotTaskAddressRules": { |
| | | "11068": [ "1", "2" ], |
| | | "11001": [ "3", "1" ], |
| | | "11010": [ "4", "2" ], |
| | | "2101": [ "1", "3" ], |
| | | "2103": [ "2", "4" ] |
| | | }, |
| | | |
| | | |
| | | "A0GV_OutTaskComplete": "http://localhost:9999/OutTaskComplete", // 䏿¥AGVåºåºè¾éçº¿å®æ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # æ¬å°å建æºå¨äººä»»å¡è®¾è®¡ |
| | | |
| | | ## èæ¯ |
| | | |
| | | `RobotTaskService.GetWMSRobotTask` å½åéè¿ HTTP è°ç¨ WMS è·åæºå¨äººä»»å¡æ°æ®ï¼ååå
¥æ¬å°æ°æ®åºãéæ±æ¯è·³è¿ WMS è°ç¨ï¼ç´æ¥å¨æ¬å°å建 `Dt_RobotTask`ã |
| | | |
| | | ## æ¹æ¡ |
| | | |
| | | æ°å¢ `CreateLocalRobotTask(Dt_Task task)` æ¹æ³ï¼ä¿çå `GetWMSRobotTask` ä¸å é¤ã |
| | | |
| | | ### æ¹å¨æä»¶ |
| | | |
| | | 1. **RobotTaskService.cs** â æ°å¢ `CreateLocalRobotTask` åè¾
婿¹æ³ `MapConfigKeyToRobotTaskType` |
| | | 2. **IRobotTaskService.cs** â æ¥å£æ°å¢æ¹æ³å£°æ |
| | | 3. **OutboundTaskFlowService.cs** â è°ç¨ç¹ä» `GetWMSRobotTask` æ¹ä¸º `CreateLocalRobotTask` |
| | | |
| | | ### æ¹æ³é»è¾ |
| | | |
| | | 1. å¤ç¨ `ResolveRobotTaskConfigKey` è§£æä»»å¡ç±»åé
ç½®é® |
| | | 2. å¤ç¨ `BuildRobotTaskStock` æå»º StockDTO |
| | | 3. æ°å¢ `MapConfigKeyToRobotTaskType` æ å°é
ç½®é®å° `RobotTaskTypeEnum`ï¼ |
| | | - `CreateRobotChangePalletTask` â `ChangePallet` (510) |
| | | - `CreateRobotGroupPalletTask` â `GroupPallet` (500) |
| | | - `CreateRobotSplitPalletTask` â `SplitPallet` (520) |
| | | 4. æå»º `Dt_RobotTask`ï¼ |
| | | - `RobotTaskNum` = `Random.Shared.Next()` |
| | | - `RobotSourceAddress` / `RobotTargetAddress` = `task.SourceAddress` / `task.TargetAddress` |
| | | - `RobotSourceAddressLineCode` / `RobotTargetAddressLineCode` = stock 对åºå段 |
| | | - `RobotRoadway` = `stock.Roadway` |
| | | - `RobotSourceAddressPalletCode` / `RobotTargetAddressPalletCode` = stock 对åºå段 |
| | | - `RobotTaskType` = æ å°åçæä¸¾å¼ |
| | | - `RobotTaskState` = `RobotNew` (300) |
| | | - `RobotGrade` = `task.Grade` |
| | | - `Creater` = `"WCS_Local"` |
| | | - `RobotTaskTotalNum` = 1 |
| | | 5. `BaseDal.AddData` æå
¥æ°æ®åº |
| | | 6. `_taskExecuteDetailService.AddTaskExecuteDetail` è®°å½æ§è¡æç» |
| | | |
| | | ### ä¸å¨çé¨å |
| | | |
| | | - `GetWMSRobotTask` å `ReceiveWMSTask` ä¿æåæ · |
| | | - `ResolveRobotTaskConfigKey`ã`BuildRobotTaskStock` çç°ææ¹æ³å¤ç¨ï¼ä¸ä¿®æ¹ |
| | | - é
ç½®æä»¶ `appsettings.json` 䏿¹ |