diff --git a/WcsMain/ApiClient/DataEntity/AGVEntity/AGVResponseLayout.cs b/WcsMain/ApiClient/DataEntity/AGVEntity/AGVResponseLayout.cs index 39dcb41..0d4d673 100644 --- a/WcsMain/ApiClient/DataEntity/AGVEntity/AGVResponseLayout.cs +++ b/WcsMain/ApiClient/DataEntity/AGVEntity/AGVResponseLayout.cs @@ -1,4 +1,5 @@ -using Newtonsoft.Json; +using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace WcsMain.ApiClient.DataEntity.AGVEntity; @@ -13,12 +14,14 @@ public class AGVResponseLayout where T : class, new() /// 头部 /// [JsonProperty("header")] + [JsonPropertyName("header")] public AGVResponseHeader? Header { get; set; } /// /// 数据 /// [JsonProperty("body")] + [JsonPropertyName("body")] public AGVResponseBody? Body { get; set; } @@ -34,19 +37,22 @@ public class AGVResponseHeader /// 请求ID /// [JsonProperty("requestId")] + [JsonPropertyName("requestId")] public string? RequestId { get; set; } /// /// 时间戳 /// [JsonProperty("timestamp")] + [JsonPropertyName("timestamp")] public string? TimeStamp { get; set; } /// /// 版本号 /// [JsonProperty("version")] - public string? version { get; set; } + [JsonPropertyName("version")] + public string? Version { get; set; } @@ -62,24 +68,28 @@ public class AGVResponseBody where T : class, new() /// 是否成功 /// [JsonProperty("success")] + [JsonPropertyName("success")] public bool? Success { get; set; } /// /// 条码 /// [JsonProperty("code")] + [JsonPropertyName("code")] public string? Code { get; set; } /// /// 响应信息 /// [JsonProperty("message")] + [JsonPropertyName("message")] public string? Message { get; set; } /// /// 响应数据 /// [JsonProperty("data")] + [JsonPropertyName ("data")] public T? Data { get; set; } diff --git a/WcsMain/ApiServe/Controllers/AGVController/AGVController.cs b/WcsMain/ApiServe/Controllers/AGVController/AGVController.cs index c586891..c853d60 100644 --- a/WcsMain/ApiServe/Controllers/AGVController/AGVController.cs +++ b/WcsMain/ApiServe/Controllers/AGVController/AGVController.cs @@ -1,5 +1,8 @@ using Microsoft.AspNetCore.Mvc; +using WcsMain.ApiClient.DataEntity.AGVEntity; using WcsMain.ApiServe.ControllerFilter; +using WcsMain.ApiServe.Controllers.Dto.AGV; +using WcsMain.ApiServe.Service.AGVService; namespace WcsMain.ApiServe.Controllers.AGVController; @@ -9,9 +12,15 @@ namespace WcsMain.ApiServe.Controllers.AGVController; [Route("api/agv")] [ApiController] [ServiceFilter] -public class AGVController : ControllerBase +public class AGVController(AGVService agvService) : ControllerBase { - + /// + /// AGV 任务的回告 + /// + /// + /// + [HttpPost("taskCallBack")] + public AGVResponseLayout> TaskCallBack(Dto.AGV.AGVRequestLayout> request) => agvService.TaskCallBack(request); diff --git a/WcsMain/ApiServe/Controllers/Dto/AGV/AGVNoVeBuckMoveRequest.cs b/WcsMain/ApiServe/Controllers/Dto/AGV/AGVNoVeBuckMoveRequest.cs new file mode 100644 index 0000000..267ffec --- /dev/null +++ b/WcsMain/ApiServe/Controllers/Dto/AGV/AGVNoVeBuckMoveRequest.cs @@ -0,0 +1,63 @@ +using System.Text.Json.Serialization; + +namespace WcsMain.ApiServe.Controllers.Dto.AGV; + +public class AGVNoVeBuckMoveRequest +{ + /// + /// 机器人编号 + /// + [JsonPropertyName("agvCode")] + public string? AGVCode { get; set; } + + /// + /// 起始点 + /// + [JsonPropertyName("startPoint")] + public string? StartPoint { get; set; } + + /// + /// 起始点简码 + /// + [JsonPropertyName("startPointName")] + public string? StartPointName { get; set; } + + /// + /// 目标区域 + /// + [JsonPropertyName("endArea")] + public string? EndArea { get; set; } + + /// + /// 目标点位 + /// + [JsonPropertyName("endPoint")] + public string? EndPoint { get; set; } + + /// + /// 目标点简码 + /// + [JsonPropertyName("endPointName")] + public string? EndPointName { get; set;} + + /// + /// 货架作业面 + /// + [JsonPropertyName("workFaces")] + public string? WorkFaces { get; set; } + + /// + /// 货架编码 + /// + [JsonPropertyName("bucketCode")] + public string? BucketCode { get; set; } + + /// + /// 货架简码 + /// + [JsonPropertyName("alias")] + public string? Alias { get; set; } + + + +} diff --git a/WcsMain/ApiServe/Controllers/Dto/AGV/AGVRequestBodyLayout.cs b/WcsMain/ApiServe/Controllers/Dto/AGV/AGVRequestBodyLayout.cs new file mode 100644 index 0000000..eda1212 --- /dev/null +++ b/WcsMain/ApiServe/Controllers/Dto/AGV/AGVRequestBodyLayout.cs @@ -0,0 +1,49 @@ +using System.Text.Json.Serialization; + +namespace WcsMain.ApiServe.Controllers.Dto.AGV; + +/// +/// AGV 回告任务状态的模板 +/// +public class AGVRequestBodyLayout +{ + + /// + /// 上游任务号 + /// + [JsonPropertyName("robotJobId")] + public string? RobotJobId { get; set; } + + /// + /// 仓库编号 + /// + [JsonPropertyName("warehouseId")] + public string? WarehouseId { get; set; } + + /// + /// 快仓系统内部任务号 + /// + [JsonPropertyName("jobId")] + public string? JobId { get; set; } + + /// + /// 任务状态 + /// + [JsonPropertyName("state")] + public string? State { get; set; } + + /// + /// 内部任务类型 + /// + [JsonPropertyName("jobType")] + public string? JobType { get; set; } + + /// + /// 数据 + /// + [JsonPropertyName("jobData")] + public T? JobData { get; set; } + + + +} diff --git a/WcsMain/ApiServe/Controllers/Dto/AGV/AGVRequestLayout.cs b/WcsMain/ApiServe/Controllers/Dto/AGV/AGVRequestLayout.cs new file mode 100644 index 0000000..ca0726b --- /dev/null +++ b/WcsMain/ApiServe/Controllers/Dto/AGV/AGVRequestLayout.cs @@ -0,0 +1,63 @@ +using Newtonsoft.Json; +using System.Text.Json.Serialization; + +namespace WcsMain.ApiServe.Controllers.Dto.AGV; + +/// +/// 接收AGV请求的实体 +/// +public class AGVRequestLayout +{ + /// + /// 头部 + /// + [JsonPropertyName("header")] + public AGVRequestHeader? Header { get; set; } + + /// + /// 数据 + /// + [JsonPropertyName("body")] + public T? Body { get; set; } +} + + +/// +/// AGV 报文请求头 +/// +public class AGVRequestHeader +{ + /// + /// 快仓唯一标识 + /// + [JsonPropertyName("appKey")] + public string? AppKey { get; set; } + + /// + /// 应用密钥 + /// + [JsonPropertyName("appSecret")] + public string? AppSecret { get; set; } + + /// + /// 请求ID + /// + [JsonPropertyName("requestId")] + public string? RequestId { get; set; } + + /// + /// 时间戳 + /// + [JsonPropertyName("timestamp")] + public string? TimeStamp { get; set; } + + /// + /// 版本号 + /// + [JsonPropertyName("version")] + public string? version { get; set; } + + + +} + diff --git a/WcsMain/ApiServe/Service/AGVService/AGVService.cs b/WcsMain/ApiServe/Service/AGVService/AGVService.cs new file mode 100644 index 0000000..28a41d6 --- /dev/null +++ b/WcsMain/ApiServe/Service/AGVService/AGVService.cs @@ -0,0 +1,149 @@ +using Humanizer; +using WcsMain.ApiClient.DataEntity.AGVEntity; +using WcsMain.ApiServe.Controllers.Dto.AGV; +using WcsMain.Business.CommonAction; +using WcsMain.DataBase.Dao; +using WcsMain.DataBase.TableEntity; +using WcsMain.Enum.Stacker; +using WcsMain.WcsAttribute.AutoFacAttribute; +namespace WcsMain.ApiServe.Service.AGVService; + +[Service] +public class AGVService(AppWmsTaskDao wmsTaskDao, WCSTaskExecuteEvent taskExecuteEvent) +{ + /// + /// AGV 任务回告 + /// + /// + /// + public AGVResponseLayout> TaskCallBack(Controllers.Dto.AGV.AGVRequestLayout> request) + { + var bodyData = request.Body; + if(bodyData == default) + { + return new() + { + Header = new() { RequestId = request.Header?.RequestId, Version = request.Header?.version, TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }, + Body = new() { Code = "ERROR", Success = false, Message = "Body 未能正确解析" } + }; + } + string? wmsTaskId = bodyData.RobotJobId; // 任务号 + string? status = bodyData.State; // 状态 + if(status == default || wmsTaskId == default) + { + return new() + { + Header = new() { RequestId = request.Header?.RequestId, Version = request.Header?.version, TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }, + Body = new() { Code = "ERROR", Success = false, Message = "任务号和状态未能正确解析" } + }; + } + /* 实际业务处理 */ + // 找到此任务 + List? wmsTasks = wmsTaskDao.Select(new() { TaskId = wmsTaskId }); + if(wmsTasks == default) + { + return new() + { + Header = new() { RequestId = request.Header?.RequestId, Version = request.Header?.version, TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }, + Body = new() { Code = "ERROR", Success = false, Message = "数据连接异常" } + }; + } + if (wmsTasks.Count < 1) + { + return new() + { + Header = new() { RequestId = request.Header?.RequestId, Version = request.Header?.version, TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }, + Body = new() { Code = "ERROR", Success = false, Message = "该任务号不存在任务" } + }; + } + AppWmsTask wmsTask = wmsTasks.First(); + // 若是入库任务或者移库任务则在开始移动时上报WMS货物离开起始位置 + if (status == "MOVE_BEGIN" && (wmsTask.TaskType == (int)WmsTaskTypeEnum.inTask || wmsTask.TaskType == (int)WmsTaskTypeEnum.agv)) + { + // 上报WMS任务已经开始 + string? errText = taskExecuteEvent.LeaveStart(wmsTask); + if (string.IsNullOrEmpty(errText)) + { + return new() + { + Header = new() { RequestId = request.Header?.RequestId, Version = request.Header?.version, TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }, + Body = new() { Code = "SUCCESS", Success = true, Message = "操作成功" } + }; + } + return new() + { + Header = new() { RequestId = request.Header?.RequestId, Version = request.Header?.version, TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }, + Body = new() { Code = "ERROR", Success = false, Message = $"操作异常:{errText}" } + }; + } + // 若是出库位置则在上报任务完成时上报WMS任务完成 + if (status == "DONE" || status == "ABNORMAL_COMPLETED") + { + if(wmsTask.TaskType == (int)WmsTaskTypeEnum.outTask || wmsTask.TaskType == (int)WmsTaskTypeEnum.agv) + { + string? errText = taskExecuteEvent.CompleteTaskEvent(wmsTask, "AGV上报完成", wmsTask.Destination); + if (string.IsNullOrEmpty(errText)) + { + return new() + { + Header = new() { RequestId = request.Header?.RequestId, Version = request.Header?.version, TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }, + Body = new() { Code = "SUCCESS", Success = true, Message = "操作成功" } + }; + } + return new() + { + Header = new() { RequestId = request.Header?.RequestId, Version = request.Header?.version, TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }, + Body = new() { Code = "ERROR", Success = false, Message = $"操作异常:{errText}" } + }; + } + if(wmsTask.TaskType == (int)WmsTaskTypeEnum.inTask) + { + var updateResult = wmsTaskDao.Update(new() { TaskId = wmsTask.TaskId, TaskStatus = (int)WmsTaskStatusEnum.arriveMid, ModifyTime = DateTime.Now }); + if(updateResult > 0) + { + return new() + { + Header = new() { RequestId = request.Header?.RequestId, Version = request.Header?.version, TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }, + Body = new() { Code = "SUCCESS", Success = true, Message = "操作成功" } + }; + } + return new() + { + Header = new() { RequestId = request.Header?.RequestId, Version = request.Header?.version, TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }, + Body = new() { Code = "ERROR", Success = false, Message = $"操作异常,数据更新失败" } + }; + } + } + if(status == "CANCEL" || status == "ABNORMAL_CANCEL") + { + var updateResult = wmsTaskDao.Update(new() { TaskId = wmsTask.TaskId, TaskStatus = (int)WmsTaskStatusEnum.err, TaskMsg = status, ModifyTime = DateTime.Now }); + if (updateResult > 0) + { + return new() + { + Header = new() { RequestId = request.Header?.RequestId, Version = request.Header?.version, TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }, + Body = new() { Code = "SUCCESS", Success = true, Message = "操作成功" } + }; + } + return new() + { + Header = new() { RequestId = request.Header?.RequestId, Version = request.Header?.version, TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }, + Body = new() { Code = "ERROR", Success = false, Message = $"操作异常数据更新失败" } + }; + } + var updateAllResult = wmsTaskDao.Update(new() { TaskId = wmsTask.TaskId, TaskMsg = status, ModifyTime = DateTime.Now }); + if (updateAllResult > 0) + { + return new() + { + Header = new() { RequestId = request.Header?.RequestId, Version = request.Header?.version, TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }, + Body = new() { Code = "SUCCESS", Success = true, Message = "操作成功" } + }; + } + return new() + { + Header = new() { RequestId = request.Header?.RequestId, Version = request.Header?.version, TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }, + Body = new() { Code = "ERROR", Success = false, Message = $"操作异常数据更新失败" } + }; + } +} diff --git a/WcsMain/Business/CommonAction/SendWmsTaskStatus.cs b/WcsMain/Business/CommonAction/SendWmsTaskStatus.cs index 88e64b6..4cbbac9 100644 --- a/WcsMain/Business/CommonAction/SendWmsTaskStatus.cs +++ b/WcsMain/Business/CommonAction/SendWmsTaskStatus.cs @@ -308,4 +308,44 @@ public class SendWmsTaskStatus(AppWmsTaskDao wmsTaskDao, WmsWebApiPost wmsWebApi } }); } + + /// + /// 发送任务离开起始位置 + /// + /// + /// + public void SendTaskLeaveStart(AppWmsTask wmsTask, int count = 5) + { + Task.Factory.StartNew(() => { + if (wmsTask == default) { return; } + SendWmsTaskStatusRequest request = new() + { + TaskId = wmsTask.TaskId, + TaskStatus = (int)SendWmsTaskStatusEnum.leaveOrigin, + VehicleNo = wmsTask.VehicleNo, + Message = "任务离开起始位置" + }; + for (int i = 1; i <= count; i++) + { + var response = wmsWebApiPost.HttpPost(request, CommonData.AppApiBaseInfos.GetAddress("SendWmsTaskStatusApiAddress") ?? ""); + if (!response.IsSend) + { + ConsoleLog.Error($"【异常】发送WMS[任务离开起始位置]失败,发送次数:{i},任务号:{wmsTask.TaskId},参考信息:{response.RequestException?.Message}"); + continue; + } + var responseObj = response.ResponseEntity; + if (responseObj == default) + { + ConsoleLog.Error($"【异常】发送WMS[任务离开起始位置]失败,解析WMS返回数据失败,发送次数:{i},任务号:{wmsTask.TaskId}"); + return; + } + if (responseObj.Code == 0) + { + ConsoleLog.Tip($"发送WMS[任务离开起始位置]成功任务号:{wmsTask.TaskId},载具号:{wmsTask.VehicleNo},{wmsTask.Origin} => {wmsTask.Destination}"); + return; + } + ConsoleLog.Error($"【异常】发送WMS[任务离开起始位置]失败,WMS返回异常,任务号:{wmsTask.TaskId},载具号:{wmsTask.VehicleNo},参考信息:{responseObj.Message}"); + } + }); + } } \ No newline at end of file diff --git a/WcsMain/Business/CommonAction/WCSTaskExecuteEvent.cs b/WcsMain/Business/CommonAction/WCSTaskExecuteEvent.cs index 089e8f9..bbf4876 100644 --- a/WcsMain/Business/CommonAction/WCSTaskExecuteEvent.cs +++ b/WcsMain/Business/CommonAction/WCSTaskExecuteEvent.cs @@ -5,6 +5,7 @@ using WcsMain.DataBase.MixDao; using WcsMain.Enum.TaskEnum; using WcsMain.WcsAttribute.AutoFacAttribute; using WcsMain.StaticData; +using WcsMain.Enum.Stacker; namespace WcsMain.Business.CommonAction; @@ -12,7 +13,7 @@ namespace WcsMain.Business.CommonAction; /// WCS 任务 触发的事件 /// [Component] -public class WCSTaskExecuteEvent(TaskDao taskDao, SendWmsTaskStatus sendWmsTaskStatus, AppLocationDao locationDao) +public class WCSTaskExecuteEvent(TaskDao taskDao, SendWmsTaskStatus sendWmsTaskStatus, AppLocationDao locationDao, AppWmsTaskDao wmsTaskDao) { /// /// 任务执行异常触发事件 @@ -162,11 +163,34 @@ public class WCSTaskExecuteEvent(TaskDao taskDao, SendWmsTaskStatus sendWmsTaskS { ConsoleLog.Warning($"【异常】任务完成更新WMS任务状态失败,异常信息:{errText}"); } - /* 上报WMS */ - sendWmsTaskStatus.SendTaskComplete(task.TaskId, destination: destination); + if(task.CreatePerson == StaticData.StaticString.WMS) + { + /* 上报WMS */ + sendWmsTaskStatus.SendTaskComplete(task.TaskId, destination: destination); + } return errText; } + /// + /// 发送任务离开起始位置 + /// + /// + /// + public string? LeaveStart(AppWmsTask task) + { + int updateResult = wmsTaskDao.Update(new() { TaskId = task.TaskId, TaskStatus = task.TaskType == (int)WmsTaskTypeEnum.moveTask ? (int)WmsTaskStatusEnum.toDestination : (int)WmsTaskStatusEnum.toMid, ModifyTime = DateTime.Now }); + if (updateResult < 1) + { + ConsoleLog.Warning($"【异常】任务完成更新WMS任务状态失败"); + } + if (task.CreatePerson == StaticData.StaticString.WMS) + { + /* 上报WMS */ + sendWmsTaskStatus.SendTaskLeaveStart(task); + } + return "更新信息失败"; + } + #endregion diff --git a/WcsMain/WcsMain.csproj b/WcsMain/WcsMain.csproj index 4715051..38bfafe 100644 --- a/WcsMain/WcsMain.csproj +++ b/WcsMain/WcsMain.csproj @@ -38,7 +38,6 @@ -