using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Configuration; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using ExternalDataSync; using MesServerWork; using MisDataSaveDate; using System.Net.Http; using System.Web.Http; using MisDataSaveDate.MOM; using System.Data.SqlClient; using static MisDataSaveDate.Helper.ApiLogHelper; using MisDataSaveDate.Helper; using WebApi; using System.Security.Policy; using System.Data; using MisDataFunDll; using System.Reflection.Emit; namespace MisDataSaveDate { /// /// AGV业务处理类 /// public class AGV_BusinessLogic { static string agvBaseUrl = ConfigurationManager.AppSettings["AGV_BaseUrl"]; /// /// 处理AGV进入请求业务逻辑 /// /// 接口URL /// AGV请求数据 /// 处理结果 public static string ProcessAGVEnterRequest(string url, [FromBody] JObject jobj) { var result = new AGV_Response(); result.code = "0"; result.message = ""; result.reqCode = ""; string errorMessage = ""; if (jobj == null) { result.code = "1"; result.message = "参数格式不正确!"; result.reqCode = ""; string retString1 = JsonConvert.SerializeObject(result); SaveMesLog("AGV进入请求", "参数格式不正确!", MesLogType.ERROR); MyLog4Net.MyLogHelper.Info("AGV请求进入接口res:", retString1); return retString1; } string str = jobj.ToString(); //存储请求日志 SaveLog_Interface_Request(url, 2, str, out int AID); try { // 解析AGV请求内容 AGV_EnterRequest enterRequest = JsonConvert.DeserializeObject(str); // 必填字段校验 if (string.IsNullOrWhiteSpace(enterRequest.reqCode)) { throw new Exception("请求编号(reqCode)不能为空"); } if (string.IsNullOrWhiteSpace(enterRequest.reqTime)) { throw new Exception("请求时间戳(reqTime)不能为空"); } if (string.IsNullOrWhiteSpace(enterRequest.currentPositionCode)) { throw new Exception("当前位置编号(currentPositionCode)不能为空"); } if (string.IsNullOrWhiteSpace(enterRequest.method)) { throw new Exception("方法名(method)不能为空"); } if (string.IsNullOrWhiteSpace(enterRequest.robotCode)) { throw new Exception("AGV编号(robotCode)不能为空"); } if (string.IsNullOrWhiteSpace(enterRequest.taskCode)) { throw new Exception("任务编号(taskCode)不能为空"); } string method = enterRequest.method.Trim().ToLower(); if (method != "apply" && method != "release" && method != "lower" && method != "raise") { throw new Exception($"不支持的method:{enterRequest.method}"); } //enterRequest.currentPositionCode = RemoveTrailingZero(enterRequest.currentPositionCode); // 调用存储过程保存AGV请求数据 var param = new SqlParameter[] { new SqlParameter("@reqCode", enterRequest.reqCode ?? ""), new SqlParameter("@reqTime", enterRequest.reqTime ?? ""), new SqlParameter("@cooX", enterRequest.cooX ?? ""), new SqlParameter("@cooY", enterRequest.cooY ?? ""), new SqlParameter("@currentPositionCode", enterRequest.currentPositionCode ?? ""), new SqlParameter("@data", ""),// enterRequest.data ?? new SqlParameter("@mapCode", enterRequest.mapCode ?? ""), new SqlParameter("@mapDataCode", enterRequest.mapDataCode ?? ""), new SqlParameter("@stgBinCode", enterRequest.stgBinCode ?? ""), new SqlParameter("@method", method), new SqlParameter("@podCode", enterRequest.podCode ?? ""), new SqlParameter("@podDir", enterRequest.podDir ?? ""), new SqlParameter("@materialLot", enterRequest.materialLot ?? ""), new SqlParameter("@robotCode", enterRequest.robotCode ?? ""), new SqlParameter("@taskCode", enterRequest.taskCode ?? ""), new SqlParameter("@wbCode", enterRequest.wbCode ?? ""), new SqlParameter("@ctnrCode", enterRequest.ctnrCode ?? ""), new SqlParameter("@ctnrType", enterRequest.ctnrType ?? ""), new SqlParameter("@roadWayCode", enterRequest.roadWayCode ?? ""), new SqlParameter("@seq", enterRequest.seq ?? ""), new SqlParameter("@eqpCode", enterRequest.eqpCode ?? "") }; // 这里定义AGV返回的位置 - 从currentPositionCode获取并去掉尾部_1后缀 string OpCode = ""; try { // 从请求的currentPositionCode字段获取位置码 string currentPositionCode = enterRequest.currentPositionCode?.ToString() ?? ""; if (!string.IsNullOrEmpty(currentPositionCode)) { // 去掉尾部的_1后缀,保留前面的库位号 int lastUnderscoreIndex = currentPositionCode.LastIndexOf('_'); if (lastUnderscoreIndex > 0) { OpCode = currentPositionCode.Substring(0, lastUnderscoreIndex); } else { // 如果没有下划线,直接使用原值 OpCode = currentPositionCode; } } // 如果从currentPositionCode获取不到,使用wbCode作为备用 if (string.IsNullOrEmpty(OpCode)) { OpCode = enterRequest.wbCode?.ToString() ?? ""; } } catch (Exception ex) { // 解析失败时使用wbCode作为备用 OpCode = enterRequest.wbCode?.ToString() ?? ""; SaveMesLog("AGV进入请求", $"解析currentPositionCode失败,使用wbCode作为备用:{ex.Message}", MesLogType.WARNING); } // 跟新Moby表 AGV进入离开、下降举升状态 MisDataFun.Location_MIS_MOBY_Insert(OpCode, method, "1"); // 执行存储过程 DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("AGV_光栅请求记录_增加", ref param, out errorMessage); switch (method) { case "apply": MisDataFun.Location_MIS_MOBY_Insert(OpCode, "inReq", enterRequest.reqCode); MisDataFun.Location_MIS_MOBY_Insert(OpCode, "inTask", enterRequest.taskCode); MisDataFun.Rrunning_AGV_Arrive(OpCode); // 磨合AGV到达 MIS_BASE.WritePLC(301, OpCode, true); // 请求进入 SaveMesLog(OpCode, $"AGV请求进入成功:工位{OpCode}", MesLogType.INFO); break; case "release": // 离开在收到后反馈回去 发给PLC MisDataFun.Location_MIS_MOBY_Insert(OpCode, "outReq", enterRequest.reqCode); MisDataFun.Location_MIS_MOBY_Insert(OpCode, "outTask", enterRequest.taskCode); MisDataFun.Rrunning_AGV_Leave(OpCode); // 磨合AGV离开 // 读取一下上一个请求进入的工件编号~~~ 然后传过去 找对应的 //bool agvOutResult = PassAgvInOut(OpCode, "", "release"); // 通知AGV可以离开 //if (!agvOutResult) //{ // errorMessage = $"AGV离开通知失败:工位{OpCode}"; // SaveMesLog("AGV进入请求", errorMessage, "error"); //} SaveMesLog(OpCode, $"AGV离开通知成功:工位{OpCode}", MesLogType.INFO); MIS_BASE.WritePLC(301, OpCode, false); // 请求进入 // AGV已离开 - 通知PLC MIS_BASE.WritePLC(303, OpCode, true); MIS_BASE.WritePLC(302, OpCode, false); // 托盘到位 器具放置完毕 请求扫描器具码 MisDataFun.Location_MIS_MOBY_Insert(OpCode, "AllowAGVLeave", "1"); break; case "lower": MisDataFun.Location_MIS_MOBY_Insert(OpCode, "lowerReq", enterRequest.reqCode); MisDataFun.Location_MIS_MOBY_Insert(OpCode, "lowerTask", enterRequest.taskCode); MisDataFun.Location_MIS_MOBY_Insert(OpCode, "当前状态", "AGV请求下降"); MisDataFun.Location_MIS_MOBY_Insert(OpCode, "备注", $"lowerReq={enterRequest.reqCode};lowerTask={enterRequest.taskCode}"); MIS_BASE.WritePLC(500, OpCode, true); // AGV请求下降 SaveMesLog(OpCode, $"AGV请求下降成功:工位{OpCode}", MesLogType.INFO); break; case "raise": MisDataFun.Location_MIS_MOBY_Insert(OpCode, "raiseReq", enterRequest.reqCode); MisDataFun.Location_MIS_MOBY_Insert(OpCode, "raiseTask", enterRequest.taskCode); MisDataFun.Location_MIS_MOBY_Insert(OpCode, "当前状态", "AGV请求举升"); MisDataFun.Location_MIS_MOBY_Insert(OpCode, "备注", $"raiseReq={enterRequest.reqCode};raiseTask={enterRequest.taskCode}"); MIS_BASE.WritePLC(501, OpCode, true); // AGV请求举升 SaveMesLog(OpCode, $"AGV请求举升成功:工位{OpCode}", MesLogType.INFO); break; default: break; } if (!string.IsNullOrEmpty(errorMessage)) { result.code = "500"; result.message = "AGV请求处理失败"; result.reqCode = enterRequest.reqCode; SaveMesLog("AGV进入请求", errorMessage, MesLogType.ERROR); } else { result.code = "0"; result.message = ""; result.reqCode = enterRequest.reqCode; } } catch (Exception err) { // 记录错误日志 SaveMesLog("AGV进入请求", err.Message, MesLogType.ERROR); result.code = "1"; result.message = err.Message; // 尝试从请求中获取reqCode try { AGV_EnterRequest tempRequest = JsonConvert.DeserializeObject(str); result.reqCode = tempRequest?.reqCode ?? ""; } catch { result.reqCode = ""; } } string retString = JsonConvert.SerializeObject(result); // 存储响应日志 SaveLog_Interface_Response(retString, AID); MyLog4Net.MyLogHelper.Info("AGV请求进入接口res:", retString); return retString; } public static string RemoveTrailingZero(string input) { if (input != null && input.Contains("-0") && input.Length >= 3) { int dashIndex = input.LastIndexOf("-0"); if (dashIndex > 0 && dashIndex == input.Length - 3) // 确保是最后的-0x格式 { return input.Remove(dashIndex + 1, 1); // 去掉"-0"中的0 } } return input; } /// /// 发送AGV任务继续执行请求(允许进入、离开、下降或举升) /// /// 工位号 /// 工件编号 /// 任务类型 /// 操作是否成功 public static bool PassAgvInOut(string opName, string engineID, string type) { try { // 其实没有用 engineID 这玩意正常本工位获取不到 // 调用存储过程获取AGV任务数据 var param = new SqlParameter[] { new SqlParameter("@opName", opName), new SqlParameter("@engineID", engineID), new SqlParameter("@type", type) }; DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("AGV_允许进入离开_查询", ref param, out DataTable dtResult, out string errMessage); if (dtResult == null || dtResult.Rows.Count == 0) { SaveMesLog(opName, $"获取AGV任务数据失败:工位号={opName}, 工件编号={engineID}, 任务类型={type}, 错误信息={errMessage}", MesLogType.ERROR); return false; } // 从数据库获取请求编号和任务号 string reqCode = dtResult.Rows[0]["reqCode"].ToString(); string taskCode = dtResult.Rows[0]["taskCode"].ToString(); // 构造AGV反馈请求对象 AGV_FeedbackRequest agvFeedbackRequest = new AGV_FeedbackRequest() { reqCode = reqCode, taskCode = taskCode }; // 获取AGV接口地址并发送请求 string interfaceUrl = agvBaseUrl.TrimEnd('/') + "/rcms/services/rest/hikRpcService/continueTask"; string jsonStr = JsonConvert.SerializeObject(agvFeedbackRequest); //存储请求日志 SaveLog_Interface_Request(interfaceUrl, 1, jsonStr, out int AID); string resultStr = ""; try { resultStr = Post.Post_Auto(interfaceUrl, jsonStr); } catch (Exception httpEx) { SaveMesLog(opName, $"AGV接口HTTP请求异常:工位号={opName}, 工件编号={engineID}, 任务类型={type}, 异常信息={httpEx.Message}", MesLogType.ERROR); // 存储响应日志 SaveLog_Interface_Response($"HTTP请求异常:{httpEx.Message}", AID); return false; } // 存储响应日志 SaveLog_Interface_Response(resultStr, AID); // 解析响应结果 if (string.IsNullOrWhiteSpace(resultStr)) { SaveMesLog(opName, "AGV接口返回空响应", MesLogType.ERROR); return false; } // 检查是否为Post.Post_Auto返回的错误格式 try { JObject tempResult = JsonConvert.DeserializeObject(resultStr); if (tempResult != null && tempResult["code"] != null && tempResult["code"].ToString() == "500") { string errorMsg = tempResult["message"]?.ToString() ?? "HTTP请求异常"; SaveMesLog(opName, $"AGV接口HTTP异常:工位号={opName}, 工件编号={engineID}, 任务类型={type}, 错误信息={errorMsg}", MesLogType.ERROR); return false; } } catch { // 如果不是标准JSON格式,继续后续处理 } AGV_Response result = JsonConvert.DeserializeObject(resultStr); if (result == null) { SaveMesLog(opName, "AGV接口返回数据格式错误", MesLogType.ERROR); return false; } // 检查AGV返回码 string code = result.code?.ToString(); if (code != "0") { string message = result.message?.ToString() ?? "未知错误"; SaveMesLog(opName, $"允许AGV光栅请求失败:工位号={opName}, 工件编号={engineID}, 任务类型={type}, code={code}, message={message}", MesLogType.ERROR); return false; } // 请求成功后调用存储过程更新送料状态 var updateParam = new SqlParameter[] { new SqlParameter("@opName", opName), new SqlParameter("@engineID", engineID), new SqlParameter("@reqCode", reqCode), new SqlParameter("@taskCode", taskCode) }; DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("AGV_光栅请求记录_允许", ref updateParam, out string updateErrMessage); if (!string.IsNullOrEmpty(updateErrMessage)) { SaveMesLog(opName, $"允许AGV光栅请求失败:工位号={opName}, 工件编号={engineID}, 任务类型={type}, 异常信息={updateErrMessage}", MesLogType.ERROR); return false; } // 根据任务类型进行后续操作 if (type == "apply") { // AGV已进入 MisDataFun.Location_MIS_MOBY_Insert(opName, "AllowAGVEnter", "1"); } else if (type == "release") { // AGV已离开 - 通知PLC MIS_BASE.WritePLC(301, opName, false); // 请求进入 MIS_BASE.WritePLC(303, opName, true); MisDataFun.Location_MIS_MOBY_Insert(opName, "AllowAGVLeave", "1"); } else if (type == "lower") { // AGV允许下降 MIS_BASE.WritePLC(500, opName, false); // AGV请求下降 MisDataFun.Location_MIS_MOBY_Insert(opName, "AllowAGVLower", "1"); MisDataFun.Location_MIS_MOBY_Insert(opName, "当前状态", "允许AGV下降"); } else if (type == "raise") { // AGV允许举升 MIS_BASE.WritePLC(501, opName, false); // AGV请求举升 MisDataFun.Location_MIS_MOBY_Insert(opName, "AllowAGVRaise", "1"); MisDataFun.Location_MIS_MOBY_Insert(opName, "当前状态", "允许AGV举升"); } SaveMesLog(opName, $"允许AGV光栅请求成功:工件编号={engineID}, 请求编号={reqCode}, 任务号={taskCode}, 工位号={opName}, 任务类型={type}", MesLogType.INFO); return true; } catch (Exception ex) { SaveMesLog(opName, $"允许AGV光栅请求失败:工位号={opName}, 工件编号={engineID}, 任务类型={type}, 异常信息={ex.Message}", MesLogType.ERROR); return false; } } } }