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;
}
}
}
}