feat: 增加LG/TCS-AGV接口并完善物料校验与Function逻辑

This commit is contained in:
XingCheng3
2026-07-16 16:47:45 +08:00
parent 7303ddde9a
commit 8e44e11248
74 changed files with 4324 additions and 1091 deletions

View File

@@ -212,8 +212,14 @@
<Compile Include="WebAPI\Other\DewPointData.cs" />
<Compile Include="WebAPI\WEB\WEB_BusinessLogic.cs" />
<Compile Include="WebAPI\WEB\WEB_Models.cs" />
<Compile Include="WebAPI\WEB\LGWEB_BusinessLogic.cs" />
<Compile Include="WebAPI\WEB\LGWEB_Models.cs" />
<Compile Include="WebAPI\AGV\AGV_BusinessLogic.cs" />
<Compile Include="WebAPI\AGV\AGV_Models.cs" />
<Compile Include="WebAPI\AGV\LGAGV_BusinessLogic.cs" />
<Compile Include="WebAPI\AGV\LGAGV_Models.cs" />
<Compile Include="WebAPI\AGV\TCSAGV_BusinessLogic.cs" />
<Compile Include="WebAPI\AGV\TCSAGV_Models.cs" />
<Compile Include="WebAPI\Controller\WEBController.cs" />
<Compile Include="WebAPI\FactoryMES\Analysis508Msg.cs" />
<Compile Include="WebAPI\FactoryMES\CALL_Inerface_DataHandle.cs" />
@@ -519,4 +525,4 @@
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\WinSCP.6.5.3\build\WinSCP.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WinSCP.6.5.3\build\WinSCP.targets'))" />
</Target>
</Project>
</Project>

View File

@@ -0,0 +1,405 @@
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Web.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using MisDataSaveDate.Helper;
using static MisDataSaveDate.Helper.ApiLogHelper;
using WebApi;
using MesServerWork;
namespace MisDataSaveDate
{
/// <summary>
/// 临工AGV接口业务处理。
/// </summary>
public class LGAGV_BusinessLogic
{
private const string DirectionMesToAgv = "MES_TO_AGV";
private const string DirectionAgvToMes = "AGV_TO_MES";
/// <summary>
/// MES调用临工AGV两点任务接口。
/// </summary>
public static LGAGV_CallResult CallAddTask(LGAGV_AddTaskRequest request)
{
if (request == null)
{
throw new Exception("AGV任务参数不能为空");
}
if (string.IsNullOrWhiteSpace(request.requestTaskId))
{
throw new Exception("任务ID(requestTaskId)不能为空");
}
if (string.IsNullOrWhiteSpace(request.startPosition))
{
throw new Exception("起点位置(startPosition)不能为空");
}
if (string.IsNullOrWhiteSpace(request.endPosition))
{
throw new Exception("终点位置(endPosition)不能为空");
}
return PostToAgv("AddTaskFromMes", "/api/mes/AddTaskFromMes", request,
request.requestTaskId, null, request.endPosition, null, request.materialCode, null);
}
/// <summary>
/// MES调用临工AGV三点任务接口。
/// </summary>
public static LGAGV_CallResult CallAddTask2(LGAGV_AddTask2Request request)
{
if (request == null)
{
throw new Exception("AGV任务参数不能为空");
}
if (string.IsNullOrWhiteSpace(request.requestTaskId))
{
throw new Exception("任务ID(requestTaskId)不能为空");
}
if (string.IsNullOrWhiteSpace(request.startPosition))
{
throw new Exception("起点位置(startPosition)不能为空");
}
if (string.IsNullOrWhiteSpace(request.midPosition))
{
throw new Exception("中间位置(midPosition)不能为空");
}
if (string.IsNullOrWhiteSpace(request.endPosition))
{
throw new Exception("终点位置(endPosition)不能为空");
}
return PostToAgv("AddTaskFromMes2", "/api/mes/AddTaskFromMes2", request,
request.requestTaskId, null, request.endPosition, null, request.materialCode, null);
}
/// <summary>
/// MES调用临工AGV放行接口。
/// </summary>
public static LGAGV_CallResult CallAllowLeave(LGAGV_AllowLeaveRequest request)
{
if (request == null)
{
throw new Exception("放行参数不能为空");
}
if (string.IsNullOrWhiteSpace(request.requestId))
{
throw new Exception("请求ID(requestId)不能为空");
}
if (string.IsNullOrWhiteSpace(request.position))
{
throw new Exception("位置(position)不能为空");
}
request.allowLeave = 1;
return PostToAgv("AllowLeave", "/api/mes/AllowLeave", request,
null, request.requestId, request.position, null, null, request.agvNo);
}
/// <summary>
/// 处理临工AGV到达/离开回调。
/// </summary>
public static string ProcessStatusUpdate(string url, [FromBody] JObject jobj)
{
var result = LGAGV_Response.Success();
string requestText = jobj?.ToString() ?? "";
SaveLog_Interface_Request(url, 2, requestText, out int aid);
LGAGV_StatusUpdateRequest request = null;
try
{
if (jobj == null)
{
throw new Exception("请求参数不能为空");
}
request = JsonConvert.DeserializeObject<LGAGV_StatusUpdateRequest>(requestText);
if (request == null)
{
throw new Exception("请求参数格式不正确");
}
if (string.IsNullOrWhiteSpace(request.requestId))
{
throw new Exception("请求ID(requestId)不能为空");
}
if (string.IsNullOrWhiteSpace(request.position))
{
throw new Exception("位置(position)不能为空");
}
if (request.type != 1 && request.type != 2)
{
throw new Exception("类型(type)只支持1到达、2离开");
}
string procedureName = request.type == 1 ? "LG_AGV_库位Moby_AGV到达" : "LG_AGV_库位Moby_AGV离开";
var param = new SqlParameter[]
{
new SqlParameter("@requestId", request.requestId ?? ""),
new SqlParameter("@position", request.position ?? ""),
new SqlParameter("@materialCode", request.materialCode ?? ""),
new SqlParameter("@agvNo", request.agvNo ?? "")
};
ExecuteResultProcedure(procedureName, ref param);
WriteOp10PlcStatus(request);
SaveInterfaceRecord("StatusUpdate", DirectionAgvToMes, request.position, request.position,
null, request.requestId, request.position, request.type, request.materialCode, request.agvNo,
"", requestText, "", 1, "");
string typeDesc = request.type == 1 ? "到达" : "离开";
SaveMesLog("LGAGV_StatusUpdate", $"临工AGV{typeDesc}:位置={request.position}, requestId={request.requestId}, AGV={request.agvNo}", MesLogType.INFO);
}
catch (Exception ex)
{
result = LGAGV_Response.Fail(ex.Message);
SaveInterfaceRecord("StatusUpdate", DirectionAgvToMes, request?.position, request?.position,
null, request?.requestId, request?.position, request?.type, request?.materialCode, request?.agvNo,
"", requestText, "", 2, ex.Message);
SaveMesLog("LGAGV_StatusUpdate", ex.Message, MesLogType.ERROR);
}
string responseText = JsonConvert.SerializeObject(result);
SaveLog_Interface_Response(responseText, aid);
return responseText;
}
private static void WriteOp10PlcStatus(LGAGV_StatusUpdateRequest request)
{
if (request == null || string.IsNullOrWhiteSpace(request.position))
{
return;
}
string position = request.position.Trim();
int tagTypeCodeID = 0;
if (request.type == 1 && position.StartsWith("OP10-1-", StringComparison.OrdinalIgnoreCase))
{
tagTypeCodeID = 28;
}
else if (request.type == 1 && position.StartsWith("OP10-2-", StringComparison.OrdinalIgnoreCase))
{
tagTypeCodeID = 29;
}
else if (request.type == 2 && position.StartsWith("OP10-2-", StringComparison.OrdinalIgnoreCase))
{
tagTypeCodeID = 30;
}
if (tagTypeCodeID == 0)
{
return;
}
bool writeResult = MIS_BASE.WritePLC(tagTypeCodeID, "AC1101", true);
string actionDesc = request.type == 1 ? "到达" : "离开";
if (writeResult)
{
SaveMesLog("LGAGV_StatusUpdate", $"OP10 AGV{actionDesc}回写PLC成功点位={position}, TagTypeCodeID={tagTypeCodeID}", MesLogType.INFO);
}
else
{
SaveMesLog("LGAGV_StatusUpdate", $"OP10 AGV{actionDesc}回写PLC失败点位={position}, TagTypeCodeID={tagTypeCodeID}", MesLogType.ERROR);
}
}
/// <summary>
/// 处理临工AGV任务结果回调。
/// </summary>
public static string ProcessTaskResult(string url, [FromBody] JObject jobj)
{
var result = LGAGV_Response.Success();
string requestText = jobj?.ToString() ?? "";
SaveLog_Interface_Request(url, 2, requestText, out int aid);
LGAGV_TaskResultRequest request = null;
try
{
if (jobj == null)
{
throw new Exception("请求参数不能为空");
}
request = JsonConvert.DeserializeObject<LGAGV_TaskResultRequest>(requestText);
if (request == null)
{
throw new Exception("请求参数格式不正确");
}
if (string.IsNullOrWhiteSpace(request.requestTaskId))
{
throw new Exception("任务ID(requestTaskId)不能为空");
}
bool isSuccess = IsAgvSuccess(request.status);
var param = new SqlParameter[]
{
new SqlParameter("@requestTaskId", request.requestTaskId ?? ""),
new SqlParameter("@status", request.status ?? ""),
new SqlParameter("@agvNo", request.agvNo ?? ""),
new SqlParameter("@message", request.message ?? ""),
new SqlParameter("@materialCode", request.materialCode ?? "")
};
ExecuteResultProcedure("LG_AGV_库位Moby_任务结果", ref param);
SaveInterfaceRecord("TaskResult", DirectionAgvToMes, null, null,
request.requestTaskId, null, null, null, request.materialCode, request.agvNo, request.status,
requestText, "", isSuccess ? 1 : 2, request.message ?? "");
SaveMesLog("LGAGV_TaskResult", $"临工AGV任务结果requestTaskId={request.requestTaskId}, status={request.status}, AGV={request.agvNo}, message={request.message}", MesLogType.INFO);
}
catch (Exception ex)
{
result = LGAGV_Response.Fail(ex.Message);
SaveInterfaceRecord("TaskResult", DirectionAgvToMes, null, null,
request?.requestTaskId, null, null, null, request?.materialCode, request?.agvNo, request?.status,
requestText, "", 2, ex.Message);
SaveMesLog("LGAGV_TaskResult", ex.Message, MesLogType.ERROR);
}
string responseText = JsonConvert.SerializeObject(result);
SaveLog_Interface_Response(responseText, aid);
return responseText;
}
public static void SaveInterfaceRecord(string interfaceName, string direction, string positionCode, string workStation,
string requestTaskId, string requestId, string position, int? type, string materialCode, string agvNo, string status,
string requestText, string responseText, int isSuccess, string errorMessage)
{
var param = new SqlParameter[]
{
new SqlParameter("@库位号", positionCode ?? ""),
new SqlParameter("@工位号", workStation ?? ""),
new SqlParameter("@接口名称", interfaceName ?? ""),
new SqlParameter("@接口方向", direction ?? ""),
new SqlParameter("@requestTaskId", requestTaskId ?? ""),
new SqlParameter("@requestId", requestId ?? ""),
new SqlParameter("@position", position ?? ""),
new SqlParameter("@type", type.HasValue ? (object)type.Value : DBNull.Value),
new SqlParameter("@materialCode", materialCode ?? ""),
new SqlParameter("@agvNo", agvNo ?? ""),
new SqlParameter("@status", status ?? ""),
new SqlParameter("@message", errorMessage ?? ""),
new SqlParameter("@请求报文", requestText ?? ""),
new SqlParameter("@响应报文", responseText ?? ""),
new SqlParameter("@是否成功", isSuccess),
new SqlParameter("@错误信息", errorMessage ?? "")
};
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("LG_AGV_接口记录_增加", ref param, out string errMessage);
if (!string.IsNullOrEmpty(errMessage))
{
SaveMesLog("LGAGV_InterfaceRecord", errMessage, MesLogType.ERROR);
}
}
public static bool IsAgvSuccess(string codeOrStatus)
{
string value = (codeOrStatus ?? "").Trim().ToLower();
return value == "0" || value == "200" || value == "true" || value == "success" || value == "成功";
}
private static LGAGV_CallResult PostToAgv(string interfaceName, string path, object request,
string requestTaskId, string requestId, string position, int? type, string materialCode, string agvNo)
{
string baseUrl = ConfigurationManager.AppSettings["LGAGV_BaseUrl"];
if (string.IsNullOrWhiteSpace(baseUrl))
{
throw new Exception("未配置 LGAGV_BaseUrl");
}
string interfaceUrl = baseUrl.TrimEnd('/') + path;
string requestText = JsonConvert.SerializeObject(request);
SaveLog_Interface_Request("LGAGV_" + interfaceName, 1, requestText, out int aid);
string responseText = Post.Post_Auto(interfaceUrl, requestText);
SaveLog_Interface_Response(responseText, aid);
JObject response = ParseResponse(responseText);
string codeText = response["code"]?.ToString() ?? response["result"]?.ToString() ?? "";
string message = response["desc"]?.ToString() ?? response["message"]?.ToString() ?? response["msg"]?.ToString() ?? "";
bool success = IsAgvSuccess(codeText);
if (response["success"] != null)
{
if (bool.TryParse(response["success"].ToString(), out bool successValue))
{
success = successValue;
}
}
SaveInterfaceRecord(interfaceName, DirectionMesToAgv, position, position, requestTaskId, requestId, position,
type, materialCode, agvNo, codeText, requestText, responseText, success ? 1 : 2, success ? "" : message);
if (success)
{
SaveMesLog("LGAGV_" + interfaceName, $"临工AGV接口调用成功{interfaceName}, position={position}, requestTaskId={requestTaskId}", MesLogType.INFO);
}
else
{
SaveMesLog("LGAGV_" + interfaceName, $"临工AGV接口调用失败{interfaceName}, code={codeText}, message={message}", MesLogType.ERROR);
}
return new LGAGV_CallResult
{
Success = success,
Code = ToInt(codeText, success ? 0 : 500),
Message = message,
InterfaceUrl = interfaceUrl,
RequestText = requestText,
ResponseText = responseText,
Response = response
};
}
private static JObject ParseResponse(string responseText)
{
if (string.IsNullOrWhiteSpace(responseText))
{
return new JObject
{
{ "code", 500 },
{ "message", "AGV返回空响应" },
{ "success", false }
};
}
try
{
return JObject.Parse(responseText);
}
catch (Exception ex)
{
return new JObject
{
{ "code", 500 },
{ "message", "AGV返回非JSON响应" + ex.Message },
{ "raw", responseText },
{ "success", false }
};
}
}
private static int ToInt(string value, int defaultValue)
{
if (int.TryParse(value, out int intValue))
{
return intValue;
}
return defaultValue;
}
private static void ExecuteResultProcedure(string procedureName, ref SqlParameter[] param)
{
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure(procedureName, ref param, out DataTable dt, out string errMessage);
if (!string.IsNullOrEmpty(errMessage))
{
throw new Exception(errMessage);
}
if (dt != null && dt.Rows.Count > 0 && dt.Columns.Contains("result") && dt.Rows[0]["result"].ToString() != "1")
{
string msg = dt.Columns.Contains("msg") ? dt.Rows[0]["msg"].ToString() : "存储过程执行失败";
throw new Exception(msg);
}
}
}
}

View File

@@ -0,0 +1,106 @@
using Newtonsoft.Json.Linq;
namespace MisDataSaveDate
{
/// <summary>
/// 临工AGV两点任务请求。
/// </summary>
public class LGAGV_AddTaskRequest
{
public string requestTaskId { get; set; }
public string startPosition { get; set; }
public string endPosition { get; set; }
public string materialCode { get; set; }
}
/// <summary>
/// 临工AGV三点任务请求。
/// </summary>
public class LGAGV_AddTask2Request
{
public string requestTaskId { get; set; }
public string startPosition { get; set; }
public string midPosition { get; set; }
public string endPosition { get; set; }
public string materialCode { get; set; }
}
/// <summary>
/// 临工AGV放行请求。
/// </summary>
public class LGAGV_AllowLeaveRequest
{
public string requestId { get; set; }
public string position { get; set; }
public string agvNo { get; set; }
public int allowLeave { get; set; } = 1;
}
/// <summary>
/// 临工AGV到达/离开回调。
/// </summary>
public class LGAGV_StatusUpdateRequest
{
public string requestId { get; set; }
public string position { get; set; }
public int type { get; set; }
public string materialCode { get; set; }
public string agvNo { get; set; }
}
/// <summary>
/// 临工AGV任务执行结果回调。
/// </summary>
public class LGAGV_TaskResultRequest
{
public string requestTaskId { get; set; }
public string status { get; set; }
public string agvNo { get; set; }
public string message { get; set; }
public string materialCode { get; set; }
}
/// <summary>
/// 返回给临工AGV的通用响应。
/// </summary>
public class LGAGV_Response
{
public int code { get; set; }
public string desc { get; set; }
public bool success { get; set; }
public static LGAGV_Response Success(string desc = "成功")
{
return new LGAGV_Response
{
code = 0,
desc = desc,
success = true
};
}
public static LGAGV_Response Fail(string desc)
{
return new LGAGV_Response
{
code = 1,
desc = desc,
success = false
};
}
}
/// <summary>
/// MES调用临工AGV接口后的内部结果。
/// </summary>
public class LGAGV_CallResult
{
public bool Success { get; set; }
public int Code { get; set; }
public string Message { get; set; }
public string InterfaceUrl { get; set; }
public string RequestText { get; set; }
public string ResponseText { get; set; }
public JObject Response { get; set; }
}
}

View File

@@ -0,0 +1,836 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Net.Http;
using System.Text;
using System.Web;
using System.Web.Http;
using MesServerWork;
using MisDataSaveDate.Helper;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using static MisDataSaveDate.Helper.ApiLogHelper;
namespace MisDataSaveDate
{
/// <summary>
/// TCS插拔任务业务处理。PLC自动任务与Web人工任务共用此入口。
/// </summary>
public class TCSAGV_BusinessLogic
{
private const string TaskTypeCombined = "nav_action_program";
private const string TaskTypeProgram = "program";
public static TCSAGV_CallResult DispatchStationTask(string stationCode, string actionType,
string portCombination, string source, string operatorCode, string parentExternalCode, bool notifyPlc)
{
TCSAGV_Config config = ReadConfig(true);
TCSAGV_PointConfig point = ReadPointConfig(stationCode);
string normalizedAction = NormalizeAction(actionType);
string productModel = "";
string combination;
if (string.IsNullOrWhiteSpace(portCombination))
{
productModel = ReadCurrentProductModel(point.StationCode);
combination = ReadModelActionCombination(point.LineCode, productModel, normalizedAction);
}
else
{
combination = NormalizePortCombination(portCombination);
}
JArray parameters = new JArray
{
new JObject { { "workStation", point.WorkStation } }
};
if (combination.Contains("XSD"))
{
parameters.Add(new JObject
{
{ "programName", normalizedAction == "插" ? point.InsertXsdProgram : point.PullXsdProgram }
});
}
if (combination.Contains("XSE"))
{
parameters.Add(new JObject
{
{ "programName", normalizedAction == "插" ? point.InsertXseProgram : point.PullXseProgram }
});
}
string externalCode = CreateExternalCode(normalizedAction == "插" ? "PLUG" : "PULL");
return CreateAndSendTask(config, point, externalCode, parentExternalCode, normalizedAction, "",
productModel, combination, TaskTypeCombined, parameters.ToString(Formatting.None), source,
operatorCode, notifyPlc);
}
public static TCSAGV_CallResult DispatchSingleStep(string stationCode, string programName,
string operatorCode, string parentExternalCode)
{
TCSAGV_Config config = ReadConfig(true);
TCSAGV_PointConfig point = ReadPointConfig(stationCode);
EnsureRobotAtPoint(config, point);
string normalizedProgram = (programName ?? "").Trim();
if (!IsConfiguredProgram(point, normalizedProgram))
{
throw new Exception("所选programName不属于该工位配置");
}
string action = normalizedProgram.Contains("拔") ? "拔-单步" : "插-单步";
JArray parameters = new JArray
{
new JObject { { "programName", normalizedProgram } }
};
return CreateAndSendTask(config, point, CreateExternalCode("STEP"), parentExternalCode,
action, normalizedProgram, "", normalizedProgram.Contains("XSD") ? "XSD" : "XSE",
TaskTypeProgram, parameters.ToString(Formatting.None),
"MANUAL", operatorCode, false);
}
public static TCSAGV_CallResult RetryTask(string externalCode, string operatorCode)
{
DataRow original = ReadTask(externalCode);
if (!IsFailureStatus(ToInt(original["任务状态"], -1)))
{
throw new Exception("仅任务错误状态允许整单重发");
}
if (ToBool(original["处理状态"]))
{
throw new Exception("失败任务已处理,不能再次重发");
}
if (!ToBool(original["已复位"]))
{
throw new Exception("请先复位移动机器人再重发任务");
}
TCSAGV_Config config = ReadConfig(true);
TCSAGV_PointConfig point = ReadPointConfig(Convert.ToString(original["MES工位号"]));
string action = Convert.ToString(original["任务动作"]);
string programName = Convert.ToString(original["ProgramName"]);
string productModel = Convert.ToString(original["产品型号"]);
string combination = Convert.ToString(original["动作组合"]);
string taskType = Convert.ToString(original["任务类型"]);
string param = Convert.ToString(original["参数"]);
return CreateAndSendTask(config, point, CreateExternalCode("RETRY"), externalCode,
action, programName, productModel, combination, taskType, param, "RETRY", operatorCode, false);
}
public static TCSAGV_CallResult CancelTask(string externalCode, string operatorCode)
{
if (string.IsNullOrWhiteSpace(externalCode))
{
throw new Exception("外部任务编号不能为空");
}
TCSAGV_Config config = ReadConfig(true);
TCSAGV_CallResult result = GetFromTcs(config, "cancelExternalBusinessTask",
"/api/cancelExternalBusinessTask", new Dictionary<string, string> { { "externalCode", externalCode } });
if (result.Success)
{
SetLocalTaskStatus(externalCode, 3, "已取消", "");
}
SaveOperation(externalCode, "", "取消任务", operatorCode, result.RequestText,
result.ResponseText, result.Success, result.Message);
return result;
}
public static TCSAGV_CallResult StopPendingTasks(string externalCode, string operatorCode)
{
TCSAGV_Config config = ReadConfig(true);
TCSAGV_CallResult result = GetFromTcs(config, "stopExternalBusinessTask",
"/api/stopExternalBusinessTask", null);
if (result.Success && !string.IsNullOrWhiteSpace(externalCode))
{
DataRow task = ReadTask(externalCode);
if (ToInt(task["任务状态"], -1) == 0)
{
SetLocalTaskStatus(externalCode, 3, "已停止", "停止全部未开始任务");
}
}
SaveOperation(externalCode, "", "停止未开始任务", operatorCode, result.RequestText,
result.ResponseText, result.Success, result.Message);
return result;
}
public static TCSAGV_CallResult ResetRobot(string externalCode, string ip, string operatorCode)
{
TCSAGV_Config config = ReadConfig(true);
string robotIp = string.IsNullOrWhiteSpace(ip) ? config.McrIp : ip.Trim();
if (string.IsNullOrWhiteSpace(robotIp))
{
throw new Exception("未配置AGV IP");
}
TCSAGV_CallResult result = GetFromTcs(config, "reset", "/api/reset",
new Dictionary<string, string> { { "ip", robotIp } });
if (result.Success && !string.IsNullOrWhiteSpace(externalCode))
{
try
{
SqlParameter[] parameters =
{
new SqlParameter("@外部任务编号", externalCode.Trim())
};
EnsureBusinessSuccess(ExecuteProcedure("XD_TCS_AGV_任务_复位标记", parameters));
}
catch (Exception ex)
{
SaveOperation(externalCode, "", "移动机器人复位", operatorCode, result.RequestText,
result.ResponseText, false, "TCS复位成功但MES复位标记失败" + ex.Message);
throw;
}
}
SaveOperation(externalCode, "", "移动机器人复位", operatorCode, result.RequestText,
result.ResponseText, result.Success, result.Message);
return result;
}
public static TCSAGV_CallResult StopNow(string externalCode, string ip, string operatorCode)
{
TCSAGV_Config config = ReadConfig(true);
string robotIp = string.IsNullOrWhiteSpace(ip) ? config.McrIp : ip.Trim();
if (string.IsNullOrWhiteSpace(robotIp))
{
throw new Exception("未配置AGV IP");
}
TCSAGV_CallResult result = GetFromTcs(config, "stopNow", "/api/stopNow",
new Dictionary<string, string> { { "ip", robotIp } });
if (result.Success && !string.IsNullOrWhiteSpace(externalCode))
{
SetLocalTaskStatus(externalCode, 4, "任务错误", "人工紧急停止");
}
SaveOperation(externalCode, "", "紧急停止", operatorCode, result.RequestText,
result.ResponseText, result.Success, result.Message);
return result;
}
public static TCSAGV_CallResult SyncTaskStatus(string externalCode, string operatorCode)
{
TCSAGV_Config config = ReadConfig(true);
TCSAGV_CallResult result = GetFromTcs(config, "getExternalBusinessTaskStatus",
"/api/getExternalBusinessTaskStatus", new Dictionary<string, string> { { "externalCode", externalCode } });
if (result.Success)
{
JObject task = FirstResultObject(result.Response);
if (task != null && task["status"] != null)
{
int status = ToInt(task["status"], -1);
if (status >= 0 && status <= 5)
{
UpdateTaskStatus(externalCode, status,
Convert.ToString(task["ip"] ?? ""), Convert.ToString(task["type"] ?? ""),
Convert.ToString(task["beginTime"] ?? ""), Convert.ToString(task["endTime"] ?? ""),
Convert.ToString(task["remark"] ?? ""));
}
}
}
SaveOperation(externalCode, "", "同步任务状态", operatorCode, result.RequestText,
result.ResponseText, result.Success, result.Message);
return result;
}
public static TCSAGV_CallResult QueryRobotInfo()
{
TCSAGV_Config config = ReadConfig(true);
return QueryRobotInfo(config);
}
private static TCSAGV_CallResult QueryRobotInfo(TCSAGV_Config config)
{
Dictionary<string, string> query = new Dictionary<string, string>
{
{ "mcrGroup", config.McrGroup }
};
if (!string.IsNullOrWhiteSpace(config.McrIp))
{
query.Add("mcrIp", config.McrIp);
}
return GetFromTcs(config, "getMcrInfo", "/api/getMcrInfo", query);
}
public static void HandleFailure(string externalCode, string operatorCode, string remark, bool notifyPlc)
{
DataRow task = ReadTask(externalCode);
if (!IsFailureStatus(ToInt(task["任务状态"], -1)))
{
throw new Exception("仅任务错误状态允许人工处理");
}
if (!ToBool(task["已复位"]))
{
throw new Exception("请先复位移动机器人再完成人工处理");
}
if (string.IsNullOrWhiteSpace(remark))
{
throw new Exception("处理说明不能为空");
}
if (notifyPlc)
{
WritePlcCompletion(task);
}
SqlParameter[] parameters =
{
new SqlParameter("@外部任务编号", externalCode ?? ""),
new SqlParameter("@处理人", operatorCode ?? ""),
new SqlParameter("@处理说明", remark ?? "")
};
EnsureBusinessSuccess(ExecuteProcedure("XD_TCS_AGV_任务_人工处理", parameters));
SaveOperation(externalCode, Convert.ToString(task["MES工位号"]), "失败任务人工处理",
operatorCode, "", "", true, remark);
}
public static string ProcessTaskStatus(string url, [FromBody] JObject jobj)
{
string requestText = jobj == null ? "" : jobj.ToString(Formatting.None);
SaveLog_Interface_Request(url, 2, requestText, out int aid);
TCSAGV_ApiResponse response;
try
{
if (jobj == null)
{
throw new Exception("请求参数不能为空");
}
TCSAGV_TaskStatusPushRequest request = jobj.ToObject<TCSAGV_TaskStatusPushRequest>();
if (request == null || string.IsNullOrWhiteSpace(request.externalCode))
{
throw new Exception("外部任务编号不能为空");
}
int status = ToInt(request.status, -1);
if (status < 0 || status > 5)
{
throw new Exception("任务状态必须为0至5");
}
UpdateTaskStatus(request.externalCode, status, request.ip, request.type,
request.beginTime, request.endTime, request.remark);
response = TCSAGV_ApiResponse.Ok("接收成功", "接收成功");
}
catch (Exception ex)
{
response = TCSAGV_ApiResponse.Fail(ex.Message);
SaveMesLog("TCS任务状态推送", ex.Message, MesLogType.ERROR);
}
string responseText = JsonConvert.SerializeObject(response);
SaveLog_Interface_Response(responseText, aid);
return responseText;
}
public static string ProcessPositionPush(string url, [FromBody] JObject jobj)
{
string requestText = jobj == null ? "" : jobj.ToString(Formatting.None);
SaveLog_Interface_Request(url, 2, requestText, out int aid);
TCSAGV_ApiResponse response;
try
{
if (jobj == null)
{
throw new Exception("请求参数不能为空");
}
TCSAGV_PositionPushRequest request = jobj.ToObject<TCSAGV_PositionPushRequest>();
if (request == null || string.IsNullOrWhiteSpace(request.ip))
{
throw new Exception("机器人IP不能为空");
}
SqlParameter[] parameters =
{
new SqlParameter("@机器人IP", request.ip ?? ""),
new SqlParameter("@当前站点", request.currentPos ?? ""),
new SqlParameter("@目标站点", request.objectivePos ?? ""),
new SqlParameter("@原始报文", requestText)
};
ExecuteProcedure("XD_TCS_AGV_位置_更新", parameters);
response = TCSAGV_ApiResponse.Ok("接收成功", "接收成功");
}
catch (Exception ex)
{
response = TCSAGV_ApiResponse.Fail(ex.Message);
SaveMesLog("TCS位置推送", ex.Message, MesLogType.ERROR);
}
string responseText = JsonConvert.SerializeObject(response);
SaveLog_Interface_Response(responseText, aid);
return responseText;
}
private static TCSAGV_CallResult CreateAndSendTask(TCSAGV_Config config, TCSAGV_PointConfig point,
string externalCode, string parentExternalCode, string action, string programName,
string productModel, string combination, string taskType, string param, string source,
string operatorCode, bool notifyPlc)
{
TCSAGV_TaskRequest request = new TCSAGV_TaskRequest
{
externalCode = externalCode,
type = taskType,
priority = config.DefaultPriority,
param = param,
mcrgroup = config.McrGroup,
mcrip = config.McrIp,
operatoruserid = config.OperatorUserId
};
SqlParameter[] createParameters =
{
new SqlParameter("@外部任务编号", externalCode),
new SqlParameter("@原任务编号", parentExternalCode ?? ""),
new SqlParameter("@MES工位号", point.StationCode),
new SqlParameter("@任务动作", action),
new SqlParameter("@产品型号", productModel ?? ""),
new SqlParameter("@动作组合", combination ?? ""),
new SqlParameter("@ProgramName", programName ?? ""),
new SqlParameter("@任务类型", taskType),
new SqlParameter("@参数", param),
new SqlParameter("@优先级", config.DefaultPriority),
new SqlParameter("@机器人组", config.McrGroup ?? ""),
new SqlParameter("@机器人IP", config.McrIp ?? ""),
new SqlParameter("@来源", source ?? ""),
new SqlParameter("@操作人", operatorCode ?? ""),
new SqlParameter("@是否通知PLC", notifyPlc)
};
EnsureBusinessSuccess(ExecuteProcedure("XD_TCS_AGV_任务_创建", createParameters));
TCSAGV_CallResult result;
try
{
result = PostToTcs(config, "createExternalBusinessTask", "/api/createExternalBusinessTask", request);
}
catch (Exception ex)
{
UpdateDispatchResult(externalCode, JsonConvert.SerializeObject(request), "", false, ex.Message);
SaveOperation(externalCode, point.StationCode, "下发" + action + "任务", operatorCode,
JsonConvert.SerializeObject(request), "", false, ex.Message);
throw;
}
UpdateDispatchResult(externalCode, result.RequestText, result.ResponseText, result.Success,
result.Success ? "" : result.Message);
SaveOperation(externalCode, point.StationCode, "下发" + action + "任务", operatorCode,
result.RequestText, result.ResponseText, result.Success, result.Message);
result.ExternalCode = externalCode;
return result;
}
private static void UpdateTaskStatus(string externalCode, int status, string ip, string type,
string beginTime, string endTime, string remark)
{
SqlParameter[] parameters =
{
new SqlParameter("@外部任务编号", externalCode ?? ""),
new SqlParameter("@任务状态", status),
new SqlParameter("@机器人IP", ip ?? ""),
new SqlParameter("@任务类型", type ?? ""),
new SqlParameter("@开始时间", beginTime ?? ""),
new SqlParameter("@结束时间", endTime ?? ""),
new SqlParameter("@备注", remark ?? "")
};
DataTable result = ExecuteProcedure("XD_TCS_AGV_任务_状态更新", parameters);
EnsureBusinessSuccess(result);
if (status == 2 && result.Rows.Count > 0 && ToBool(result.Rows[0]["是否通知PLC"])
&& !ToBool(result.Rows[0]["PLC已通知"]))
{
DataRow task = ReadTask(externalCode);
WritePlcCompletion(task);
SqlParameter[] notified = { new SqlParameter("@外部任务编号", externalCode) };
ExecuteProcedure("XD_TCS_AGV_任务_PLC通知完成", notified);
}
}
private static bool IsFailureStatus(int status)
{
return status == 4 || status == 5;
}
private static void WritePlcCompletion(DataRow task)
{
string stationCode = Convert.ToString(task["MES工位号"]);
string action = Convert.ToString(task["任务动作"]);
int tagCode = action.StartsWith("插", StringComparison.Ordinal) ? 400
: action.StartsWith("拔", StringComparison.Ordinal) ? 401 : 0;
if (tagCode == 0)
{
throw new Exception("任务动作无法确定PLC完成码");
}
if (!MIS_BASE.WritePLC(tagCode, stationCode, true))
{
throw new Exception("任务完成但PLC完成信号写入失败");
}
SaveMesLog(stationCode, "TCS任务完成已写入PLC功能码" + tagCode, MesLogType.INFO);
}
private static TCSAGV_Config ReadConfig(bool requireEnabled)
{
DataTable table = ExecuteProcedure("XD_TCS_AGV_配置_获取", new SqlParameter[0]);
if (table.Rows.Count == 0)
{
throw new Exception("未配置TCS参数");
}
DataRow row = table.Rows[0];
TCSAGV_Config config = new TCSAGV_Config
{
BaseUrl = Convert.ToString(row["TCS_BaseUrl"]),
Enabled = Convert.ToString(row["TCS_Enabled"]) == "1",
McrGroup = Convert.ToString(row["McrGroup"]),
McrIp = Convert.ToString(row["McrIp"]),
OperatorUserId = Convert.ToString(row["TCS_OperatorUserId"]),
DefaultPriority = ToInt(row["DefaultPriority"], 1),
HttpTimeoutSeconds = ToInt(row["HttpTimeoutSeconds"], 15)
};
if (string.IsNullOrWhiteSpace(config.BaseUrl))
{
throw new Exception("未配置TCS服务地址");
}
if (string.IsNullOrWhiteSpace(config.OperatorUserId))
{
throw new Exception("未配置TCS任务状态推送标识");
}
if (requireEnabled && !config.Enabled)
{
throw new Exception("TCS真实下发开关未启用请先确认现场地址和AGV IP");
}
return config;
}
private static TCSAGV_PointConfig ReadPointConfig(string stationCode)
{
if (string.IsNullOrWhiteSpace(stationCode))
{
throw new Exception("MES工位号不能为空");
}
SqlParameter[] parameters = { new SqlParameter("@MES工位号", stationCode.Trim()) };
DataTable table = ExecuteProcedure("XD_TCS_AGV_点位配置_查询", parameters);
if (table.Rows.Count == 0)
{
throw new Exception("MES工位未配置TCS站点和programName");
}
DataRow row = table.Rows[0];
return new TCSAGV_PointConfig
{
LineCode = Convert.ToString(row["产线代码"]),
StationCode = Convert.ToString(row["MES工位号"]),
PositionName = Convert.ToString(row["现场位置"]),
WorkStation = Convert.ToString(row["WorkStation"]),
InsertXsdProgram = Convert.ToString(row["插XSDProgramName"]),
InsertXseProgram = Convert.ToString(row["插XSEProgramName"]),
PullXsdProgram = Convert.ToString(row["拔XSDProgramName"]),
PullXseProgram = Convert.ToString(row["拔XSEProgramName"])
};
}
private static string ReadCurrentProductModel(string stationCode)
{
SqlParameter[] parameters = { new SqlParameter("@MES工位号", stationCode) };
DataTable table = ExecuteProcedure("XD_TCS_AGV_库位产品_查询", parameters);
string productModel = table.Rows.Count == 0 ? "" : Convert.ToString(table.Rows[0]["产品型号"]);
if (string.IsNullOrWhiteSpace(productModel))
{
throw new Exception("工位" + stationCode + "未获取到当前产品型号");
}
return productModel.Trim();
}
private static string ReadModelActionCombination(string lineCode, string productModel, string action)
{
SqlParameter[] parameters =
{
new SqlParameter("@产线代码", lineCode),
new SqlParameter("@产品型号", productModel),
new SqlParameter("@任务动作", action)
};
DataTable table = ExecuteProcedure("XD_TCS_AGV_型号动作映射_查询", parameters);
if (table.Rows.Count == 0)
{
throw new Exception("产品型号" + productModel + "未配置" + action + "动作组合");
}
return Convert.ToString(table.Rows[0]["动作组合"]);
}
private static DataRow ReadTask(string externalCode)
{
if (string.IsNullOrWhiteSpace(externalCode))
{
throw new Exception("外部任务编号不能为空");
}
SqlParameter[] parameters = { new SqlParameter("@外部任务编号", externalCode.Trim()) };
DataTable table = ExecuteProcedure("XD_TCS_AGV_任务_获取", parameters);
if (table.Rows.Count == 0)
{
throw new Exception("外部任务不存在");
}
return table.Rows[0];
}
private static void EnsureRobotAtPoint(TCSAGV_Config config, TCSAGV_PointConfig point)
{
TCSAGV_CallResult result = QueryRobotInfo(config);
if (!result.Success)
{
throw new Exception("查询AGV实时位置失败" + result.Message);
}
JObject robot = FirstResultObject(result.Response);
if (robot == null)
{
throw new Exception("未查询到AGV状态不能执行单步任务");
}
if (ToInt(robot["status"], -1) == 4)
{
throw new Exception("AGV当前未连接不能执行单步任务");
}
string currentPosition = Convert.ToString(robot["currentPos"]);
if (string.IsNullOrWhiteSpace(currentPosition))
{
throw new Exception("未获取到AGV当前位置不能执行单步任务");
}
if (!string.Equals(currentPosition, point.WorkStation, StringComparison.OrdinalIgnoreCase))
{
throw new Exception("AGV当前位置" + currentPosition + "与所选站点" + point.WorkStation + "不一致");
}
}
private static void UpdateDispatchResult(string externalCode, string requestText, string responseText,
bool success, string errorMessage)
{
SqlParameter[] parameters =
{
new SqlParameter("@外部任务编号", externalCode ?? ""),
new SqlParameter("@请求报文", requestText ?? ""),
new SqlParameter("@响应报文", responseText ?? ""),
new SqlParameter("@是否成功", success),
new SqlParameter("@错误信息", errorMessage ?? "")
};
ExecuteProcedure("XD_TCS_AGV_任务_下发结果更新", parameters);
}
private static void SetLocalTaskStatus(string externalCode, int status, string statusText, string errorMessage)
{
SqlParameter[] parameters =
{
new SqlParameter("@外部任务编号", externalCode ?? ""),
new SqlParameter("@任务状态", status),
new SqlParameter("@状态说明", statusText ?? ""),
new SqlParameter("@错误信息", errorMessage ?? "")
};
ExecuteProcedure("XD_TCS_AGV_任务_本地状态设置", parameters);
}
private static void SaveOperation(string externalCode, string stationCode, string operationType,
string operatorCode, string requestText, string responseText, bool success, string message)
{
try
{
SqlParameter[] parameters =
{
new SqlParameter("@外部任务编号", externalCode ?? ""),
new SqlParameter("@MES工位号", stationCode ?? ""),
new SqlParameter("@操作类型", operationType ?? ""),
new SqlParameter("@操作人", operatorCode ?? ""),
new SqlParameter("@请求报文", requestText ?? ""),
new SqlParameter("@响应报文", responseText ?? ""),
new SqlParameter("@是否成功", success),
new SqlParameter("@操作结果", message ?? "")
};
ExecuteProcedure("XD_TCS_AGV_操作记录_增加", parameters);
}
catch (Exception ex)
{
SaveMesLog("TCS操作记录", ex.Message, MesLogType.ERROR);
}
}
private static TCSAGV_CallResult PostToTcs(TCSAGV_Config config, string interfaceName,
string path, object request)
{
string url = config.BaseUrl.TrimEnd('/') + path;
string requestText = JsonConvert.SerializeObject(request);
SaveLog_Interface_Request("TCS_" + interfaceName, 1, requestText, out int aid);
string responseText;
using (HttpClient client = CreateHttpClient(config))
using (StringContent content = new StringContent(requestText, Encoding.UTF8, "application/json"))
{
HttpResponseMessage response = client.PostAsync(url, content).GetAwaiter().GetResult();
responseText = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
if (string.IsNullOrWhiteSpace(responseText) && !response.IsSuccessStatusCode)
{
responseText = "HTTP " + (int)response.StatusCode;
}
}
SaveLog_Interface_Response(responseText, aid);
return ParseCallResult(requestText, responseText);
}
private static TCSAGV_CallResult GetFromTcs(TCSAGV_Config config, string interfaceName,
string path, IDictionary<string, string> query)
{
StringBuilder url = new StringBuilder(config.BaseUrl.TrimEnd('/') + path);
JObject request = new JObject();
if (query != null && query.Count > 0)
{
url.Append('?');
bool first = true;
foreach (KeyValuePair<string, string> item in query)
{
if (!first) url.Append('&');
first = false;
url.Append(HttpUtility.UrlEncode(item.Key));
url.Append('=');
url.Append(HttpUtility.UrlEncode(item.Value ?? ""));
request[item.Key] = item.Value ?? "";
}
}
string requestText = request.ToString(Formatting.None);
bool skipInterfaceLog = string.Equals(interfaceName, "getMcrInfo",
StringComparison.OrdinalIgnoreCase);
int aid = 0;
if (!skipInterfaceLog)
{
SaveLog_Interface_Request("TCS_" + interfaceName, 1, requestText, out aid);
}
string responseText;
using (HttpClient client = CreateHttpClient(config))
{
HttpResponseMessage response = client.GetAsync(url.ToString()).GetAwaiter().GetResult();
responseText = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
if (string.IsNullOrWhiteSpace(responseText) && !response.IsSuccessStatusCode)
{
responseText = "HTTP " + (int)response.StatusCode;
}
}
if (!skipInterfaceLog)
{
SaveLog_Interface_Response(responseText, aid);
}
return ParseCallResult(requestText, responseText);
}
private static HttpClient CreateHttpClient(TCSAGV_Config config)
{
return new HttpClient
{
Timeout = TimeSpan.FromSeconds(config.HttpTimeoutSeconds > 0 ? config.HttpTimeoutSeconds : 15)
};
}
private static TCSAGV_CallResult ParseCallResult(string requestText, string responseText)
{
JObject response;
try
{
response = JObject.Parse(responseText ?? "");
}
catch (Exception ex)
{
return new TCSAGV_CallResult
{
Success = false,
Code = 500,
Message = "TCS返回非JSON响应" + ex.Message,
RequestText = requestText,
ResponseText = responseText,
Response = null
};
}
bool successFlag = false;
bool hasSuccessFlag = response["success"] != null;
if (hasSuccessFlag)
{
bool.TryParse(Convert.ToString(response["success"]), out successFlag);
}
int code = ToInt(response["code"], successFlag ? 200 : 500);
bool success = hasSuccessFlag ? successFlag && code == 200 : code == 200;
string message = Convert.ToString(response["message"] ?? response["msg"] ?? response["result"] ?? "");
return new TCSAGV_CallResult
{
Success = success,
Code = code,
Message = message,
RequestText = requestText,
ResponseText = responseText,
Response = response
};
}
private static JObject FirstResultObject(JObject response)
{
if (response == null || response["result"] == null) return null;
JToken result = response["result"];
if (result.Type == JTokenType.Array)
{
JArray array = (JArray)result;
return array.Count > 0 ? array[0] as JObject : null;
}
return result as JObject;
}
private static DataTable ExecuteProcedure(string procedureName, SqlParameter[] parameters)
{
SqlParameter[] procedureParameters = parameters ?? new SqlParameter[0];
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure(procedureName, ref procedureParameters,
out DataTable table, out string errorMessage);
if (!string.IsNullOrWhiteSpace(errorMessage))
{
throw new Exception(errorMessage);
}
return table ?? new DataTable();
}
private static void EnsureBusinessSuccess(DataTable table)
{
if (table == null || table.Rows.Count == 0)
{
throw new Exception("数据库未返回业务结果");
}
if (ToInt(table.Rows[0]["result"], 0) != 1)
{
string message = table.Columns.Contains("msg") ? Convert.ToString(table.Rows[0]["msg"]) : "业务操作失败";
throw new Exception(message);
}
}
private static string NormalizeAction(string actionType)
{
string value = (actionType ?? "").Trim();
if (value == "插" || value.Equals("plug", StringComparison.OrdinalIgnoreCase)) return "插";
if (value == "拔" || value.Equals("pull", StringComparison.OrdinalIgnoreCase)) return "拔";
throw new Exception("任务动作只支持插或拔");
}
private static string NormalizePortCombination(string portCombination)
{
string value = (portCombination ?? "").Trim().ToUpperInvariant();
if (value == "XSD" || value == "XSE" || value == "XSD+XSE") return value;
throw new Exception("动作组合只支持XSD、XSE或XSD+XSE");
}
private static bool IsConfiguredProgram(TCSAGV_PointConfig point, string programName)
{
return programName == point.InsertXsdProgram || programName == point.InsertXseProgram
|| programName == point.PullXsdProgram || programName == point.PullXseProgram;
}
private static string CreateExternalCode(string prefix)
{
return "XD_" + prefix + "_" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + "_"
+ Guid.NewGuid().ToString("N").Substring(0, 6).ToUpperInvariant();
}
private static int ToInt(object value, int defaultValue)
{
int result;
return int.TryParse(Convert.ToString(value), out result) ? result : defaultValue;
}
private static bool ToBool(object value)
{
string text = Convert.ToString(value);
return text == "1" || text.Equals("true", StringComparison.OrdinalIgnoreCase);
}
}
}

View File

@@ -0,0 +1,133 @@
using Newtonsoft.Json.Linq;
namespace MisDataSaveDate
{
public class TCSAGV_TaskRequest
{
public string externalCode { get; set; }
public string type { get; set; }
public int priority { get; set; }
public string param { get; set; }
public string mcrgroup { get; set; }
public string mcrip { get; set; }
public string operatoruserid { get; set; }
}
public class TCSAGV_TaskStatusPushRequest
{
public string externalCode { get; set; }
public string status { get; set; }
public string ip { get; set; }
public string type { get; set; }
public string beginTime { get; set; }
public string endTime { get; set; }
public string remark { get; set; }
}
public class TCSAGV_PositionPushRequest
{
public string ip { get; set; }
public string currentPos { get; set; }
public string objectivePos { get; set; }
}
public class TCSAGV_StationDispatchRequest
{
public string stationCode { get; set; }
public string actionType { get; set; }
public string portCombination { get; set; }
public string operatorCode { get; set; }
public string parentExternalCode { get; set; }
}
public class TCSAGV_StepDispatchRequest
{
public string stationCode { get; set; }
public string programName { get; set; }
public string operatorCode { get; set; }
public string parentExternalCode { get; set; }
}
public class TCSAGV_TaskOperationRequest
{
public string externalCode { get; set; }
public string operatorCode { get; set; }
public string remark { get; set; }
public bool notifyPlc { get; set; }
}
public class TCSAGV_RobotOperationRequest
{
public string externalCode { get; set; }
public string ip { get; set; }
public string operatorCode { get; set; }
public string remark { get; set; }
}
public class TCSAGV_Config
{
public string BaseUrl { get; set; }
public bool Enabled { get; set; }
public string McrGroup { get; set; }
public string McrIp { get; set; }
public string OperatorUserId { get; set; }
public int DefaultPriority { get; set; }
public int HttpTimeoutSeconds { get; set; }
}
public class TCSAGV_PointConfig
{
public string LineCode { get; set; }
public string StationCode { get; set; }
public string PositionName { get; set; }
public string WorkStation { get; set; }
public string InsertXsdProgram { get; set; }
public string InsertXseProgram { get; set; }
public string PullXsdProgram { get; set; }
public string PullXseProgram { get; set; }
}
public class TCSAGV_CallResult
{
public bool Success { get; set; }
public int Code { get; set; }
public string Message { get; set; }
public string ExternalCode { get; set; }
public string RequestText { get; set; }
public string ResponseText { get; set; }
public JObject Response { get; set; }
}
public class TCSAGV_ApiResponse
{
public bool success { get; set; }
public int code { get; set; }
public string message { get; set; }
public object data { get; set; }
public long timestamp { get; set; }
public static TCSAGV_ApiResponse Ok(string message, object data = null)
{
return new TCSAGV_ApiResponse
{
success = true,
code = 200,
message = message,
data = data,
timestamp = System.DateTimeOffset.Now.ToUnixTimeMilliseconds()
};
}
public static TCSAGV_ApiResponse Fail(string message)
{
return new TCSAGV_ApiResponse
{
success = false,
code = 500,
message = message,
data = null,
timestamp = System.DateTimeOffset.Now.ToUnixTimeMilliseconds()
};
}
}
}

View File

@@ -40,5 +40,202 @@ namespace MisDataSaveDate
};
}
/// <summary>
/// 临工AGV到达/离开状态回调接口。
/// </summary>
/// <param name="jobj">临工AGV状态回调数据</param>
/// <returns>处理结果</returns>
[HttpPost]
[Route("agv/lgagv/statusUpdate")]
public HttpResponseMessage LGAGV_StatusUpdate([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(LGAGV_BusinessLogic.ProcessStatusUpdate(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// 临工AGV任务结果回调接口。
/// </summary>
/// <param name="jobj">临工AGV任务结果数据</param>
/// <returns>处理结果</returns>
[HttpPost]
[Route("agv/lgagv/taskResult")]
public HttpResponseMessage LGAGV_TaskResult([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(LGAGV_BusinessLogic.ProcessTaskResult(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
[HttpPost]
[Route("api/reportExternalBusinessTaskStatus")]
public HttpResponseMessage TCS_ReportExternalBusinessTaskStatus([FromBody] JObject jobj)
{
return JsonResponse(TCSAGV_BusinessLogic.ProcessTaskStatus("api/reportExternalBusinessTaskStatus", jobj));
}
[HttpPost]
[Route("api/mcrInfoLocation")]
public HttpResponseMessage TCS_McrInfoLocation([FromBody] JObject jobj)
{
return JsonResponse(TCSAGV_BusinessLogic.ProcessPositionPush("api/mcrInfoLocation", jobj));
}
[HttpPost]
[Route("agv/tcs/dispatchStation")]
public HttpResponseMessage TCS_DispatchStation([FromBody] TCSAGV_StationDispatchRequest request)
{
return ExecuteTcs(() =>
{
if (request == null) throw new Exception("请求参数不能为空");
if (string.IsNullOrWhiteSpace(request.portCombination)) throw new Exception("请选择动作组合");
TCSAGV_CallResult result = TCSAGV_BusinessLogic.DispatchStationTask(
request.stationCode, request.actionType, request.portCombination, "MANUAL", request.operatorCode,
request.parentExternalCode, false);
return result.Success
? TCSAGV_ApiResponse.Ok("任务下发成功", result)
: TCSAGV_ApiResponse.Fail(result.Message);
});
}
[HttpPost]
[Route("agv/tcs/dispatchStep")]
public HttpResponseMessage TCS_DispatchStep([FromBody] TCSAGV_StepDispatchRequest request)
{
return ExecuteTcs(() =>
{
if (request == null) throw new Exception("请求参数不能为空");
TCSAGV_CallResult result = TCSAGV_BusinessLogic.DispatchSingleStep(
request.stationCode, request.programName, request.operatorCode, request.parentExternalCode);
return result.Success
? TCSAGV_ApiResponse.Ok("单步任务下发成功", result)
: TCSAGV_ApiResponse.Fail(result.Message);
});
}
[HttpPost]
[Route("agv/tcs/retry")]
public HttpResponseMessage TCS_Retry([FromBody] TCSAGV_TaskOperationRequest request)
{
return ExecuteTcs(() =>
{
if (request == null) throw new Exception("请求参数不能为空");
TCSAGV_CallResult result = TCSAGV_BusinessLogic.RetryTask(request.externalCode, request.operatorCode);
return result.Success
? TCSAGV_ApiResponse.Ok("整单重发成功", result)
: TCSAGV_ApiResponse.Fail(result.Message);
});
}
[HttpPost]
[Route("agv/tcs/cancel")]
public HttpResponseMessage TCS_Cancel([FromBody] TCSAGV_TaskOperationRequest request)
{
return ExecuteTcs(() =>
{
if (request == null) throw new Exception("请求参数不能为空");
TCSAGV_CallResult result = TCSAGV_BusinessLogic.CancelTask(request.externalCode, request.operatorCode);
return result.Success ? TCSAGV_ApiResponse.Ok("任务取消成功", result) : TCSAGV_ApiResponse.Fail(result.Message);
});
}
[HttpPost]
[Route("agv/tcs/stopPending")]
public HttpResponseMessage TCS_StopPending([FromBody] TCSAGV_TaskOperationRequest request)
{
return ExecuteTcs(() =>
{
string externalCode = request == null ? "" : request.externalCode;
string operatorCode = request == null ? "" : request.operatorCode;
TCSAGV_CallResult result = TCSAGV_BusinessLogic.StopPendingTasks(externalCode, operatorCode);
return result.Success ? TCSAGV_ApiResponse.Ok("未开始任务已停止", result) : TCSAGV_ApiResponse.Fail(result.Message);
});
}
[HttpPost]
[Route("agv/tcs/reset")]
public HttpResponseMessage TCS_Reset([FromBody] TCSAGV_RobotOperationRequest request)
{
return ExecuteTcs(() =>
{
if (request == null) throw new Exception("请求参数不能为空");
TCSAGV_CallResult result = TCSAGV_BusinessLogic.ResetRobot(
request.externalCode, request.ip, request.operatorCode);
return result.Success ? TCSAGV_ApiResponse.Ok("移动机器人复位成功", result) : TCSAGV_ApiResponse.Fail(result.Message);
});
}
[HttpPost]
[Route("agv/tcs/stopNow")]
public HttpResponseMessage TCS_StopNow([FromBody] TCSAGV_RobotOperationRequest request)
{
return ExecuteTcs(() =>
{
if (request == null) throw new Exception("请求参数不能为空");
TCSAGV_CallResult result = TCSAGV_BusinessLogic.StopNow(
request.externalCode, request.ip, request.operatorCode);
return result.Success ? TCSAGV_ApiResponse.Ok("移动机器人已紧急停止", result) : TCSAGV_ApiResponse.Fail(result.Message);
});
}
[HttpPost]
[Route("agv/tcs/syncTask")]
public HttpResponseMessage TCS_SyncTask([FromBody] TCSAGV_TaskOperationRequest request)
{
return ExecuteTcs(() =>
{
if (request == null) throw new Exception("请求参数不能为空");
TCSAGV_CallResult result = TCSAGV_BusinessLogic.SyncTaskStatus(request.externalCode, request.operatorCode);
return result.Success ? TCSAGV_ApiResponse.Ok("任务状态同步成功", result) : TCSAGV_ApiResponse.Fail(result.Message);
});
}
[HttpGet]
[Route("agv/tcs/queryRobot")]
public HttpResponseMessage TCS_QueryRobot()
{
return ExecuteTcs(() =>
{
TCSAGV_CallResult result = TCSAGV_BusinessLogic.QueryRobotInfo();
return result.Success ? TCSAGV_ApiResponse.Ok("机器人状态查询成功", result.Response) : TCSAGV_ApiResponse.Fail(result.Message);
});
}
[HttpPost]
[Route("agv/tcs/handleFailure")]
public HttpResponseMessage TCS_HandleFailure([FromBody] TCSAGV_TaskOperationRequest request)
{
return ExecuteTcs(() =>
{
if (request == null) throw new Exception("请求参数不能为空");
TCSAGV_BusinessLogic.HandleFailure(request.externalCode, request.operatorCode, request.remark, request.notifyPlc);
return TCSAGV_ApiResponse.Ok("失败任务已人工处理");
});
}
private static HttpResponseMessage ExecuteTcs(Func<TCSAGV_ApiResponse> action)
{
TCSAGV_ApiResponse response;
try
{
response = action();
}
catch (Exception ex)
{
response = TCSAGV_ApiResponse.Fail(ex.Message);
}
return JsonResponse(JsonConvert.SerializeObject(response));
}
private static HttpResponseMessage JsonResponse(string json)
{
return new HttpResponseMessage
{
Content = new StringContent(json, Encoding.GetEncoding("UTF-8"), "application/json")
};
}
}
}

View File

@@ -99,6 +99,36 @@ namespace MisDataSaveDate
};
}
/// <summary>
/// 临工AGV网页按钮调度接口。
/// </summary>
/// <param name="jobj">调度请求数据</param>
/// <returns>处理结果</returns>
[HttpPost]
[Route("web/LGAGV_Dispatch")]
public HttpResponseMessage LGAGV_Dispatch([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(LGWEB_BusinessLogic.WEB_DispatchAGV(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// 临工AGV网页按钮放行接口。
/// </summary>
/// <param name="jobj">放行请求数据</param>
/// <returns>处理结果</returns>
[HttpPost]
[Route("web/LGAGV_AllowLeave")]
public HttpResponseMessage LGAGV_AllowLeave([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(LGWEB_BusinessLogic.WEB_AllowLeave(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// 批量读取PLC点位值接口
/// 前端传递TagTypeCodeID数组和工位号返回对应点位的值
@@ -131,4 +161,4 @@ namespace MisDataSaveDate
};
}
}
}
}

View File

@@ -1,4 +1,4 @@
using DataLinkMesWork;
using DataLinkMesWork;
using MesServerWork;
using MisDataFunDll;
using MisDataSaveDate.MOM;
@@ -24,6 +24,17 @@ namespace WebApi
{
public class CALL_Inerface_DataHandle
{
private static bool TryCheckProcessReportAllowed(string opName, string engineID, string orderForm, string reqType)
{
DataTable isSendDT = MisDataFun.IOT_ReqData_UpLoad_IsSend(opName, orderForm, reqType, engineID);
if (isSendDT.Rows[0]["result"].ToString() != "1")
{
SaveMesLog($"工序{reqType}", isSendDT.Rows[0]["msg"].ToString(), MesLogType.ERROR);
return false;
}
return true;
}
/// <summary>
/// 开工(工序)
/// </summary>
@@ -32,19 +43,17 @@ namespace WebApi
/// <param name="OrderForm"></param>
public static void CALL_Inerface_JobStart(string OpName, string EngineID, string OrderForm)
{
DataTable IsSendDT = MisDataFun.IOT_ReqData_UpLoad_IsSend(OpName, OrderForm, "工");
if (IsSendDT.Rows[0]["result"].ToString() != "1")
if (!TryCheckProcessReportAllowed(OpName, EngineID, OrderForm, "工"))
{
SaveMesLog("工序完工", IsSendDT.Rows[0]["msg"].ToString(), MesLogType.ERROR);
return;
}
//查询工单ID、任务ID、工序ID
var param = new SqlParameter[] {
new SqlParameter("@订单号",OrderForm),
new SqlParameter("@工序号",OpName),
new SqlParameter("@工件编号",EngineID)
};
new SqlParameter("@订单号",OrderForm),
new SqlParameter("@工序号",OpName),
new SqlParameter("@工件编号",EngineID)
};
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("CallWebApi_FactoryMes_JobStart", ref param, out DataTable dt, out string errorMessage);
if (dt.Rows.Count > 0)
@@ -101,19 +110,17 @@ namespace WebApi
/// <param name="OrderForm"></param>
public static void CALL_Inerface_JobFinished(string OpName, string EngineID, string OrderForm)
{
DataTable IsSendDT = MisDataFun.IOT_ReqData_UpLoad_IsSend(OpName, OrderForm, "完工");
if (IsSendDT.Rows[0]["result"].ToString() != "1")
if (!TryCheckProcessReportAllowed(OpName, EngineID, OrderForm, "完工"))
{
SaveMesLog("工序完工", IsSendDT.Rows[0]["msg"].ToString(), MesLogType.ERROR);
return;
}
//查询工单ID、任务ID、工序ID
var param = new SqlParameter[] {
new SqlParameter("@订单号",OrderForm),
new SqlParameter("@工序号",OpName),
new SqlParameter("@工件编号",EngineID)
};
new SqlParameter("@订单号",OrderForm),
new SqlParameter("@工序号",OpName),
new SqlParameter("@工件编号",EngineID)
};
//DataAccess.ExecuteStoredProcedure("CallWebApi_FactoryMes_JobFinished", ref param, out DataSet ds);
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("CallWebApi_FactoryMes_JobFinished", ref param, out DataSet ds, out string errorMessage);
//a.[订单ID],[任务ID],[工序ID],[工序名称],1 as 完工数量,@开工时间 as 开工时间,@结束时间 as 结束时间,@节拍 as 节拍,@操作时间 as 最后修改时间
@@ -283,6 +290,7 @@ namespace WebApi
orderID = dt.Rows[0]["订单ID"].ToString();
taskID = dt.Rows[0]["任务ID"].ToString();
}
// 非工厂下发的订单产品,不上传报警
if (string.IsNullOrEmpty(orderID) || string.IsNullOrEmpty(taskID)) return;
@@ -567,6 +575,15 @@ namespace WebApi
}
}
/// <summary>
/// 物料转序
/// </summary>
/// <param name="startPositionCode">起始位置编号</param>
/// <param name="endPositionCode">终点位置编号</param>
/// <param name="dataid">派工任务id</param>
/// <param name="moveTaskType">搬运类型1搬运容器2搬运货架</param>
/// <param name="vehicleStatus">载具类型0-空1-满</param>
/// <returns>返回调用结果 JObject包含 code 和 message</returns>
/// <summary>
/// 物料转序
/// </summary>
@@ -940,3 +957,4 @@ namespace WebApi
//#endregion
}
}

View File

@@ -0,0 +1,471 @@
using System;
using System.Data;
using System.Data.SqlClient;
using System.Web.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using MisDataSaveDate.Helper;
using static MisDataSaveDate.Helper.ApiLogHelper;
namespace MisDataSaveDate
{
/// <summary>
/// 临工AGV网页按钮业务处理。
/// </summary>
public class LGWEB_BusinessLogic
{
/// <summary>
/// 网页按钮下发临工AGV搬运任务。
/// </summary>
public static string WEB_DispatchAGV(string url, [FromBody] JObject jobj)
{
var result = new MsgResHeader<object>
{
code = 200,
message = "",
Data = null
};
if (jobj == null)
{
result.code = 500;
result.message = "参数格式不正确!";
return JsonConvert.SerializeObject(result);
}
string requestText = jobj.ToString();
SaveLog_Interface_Request(url, 2, requestText, out int aid);
try
{
LGWEB_DispatchRequest request = JsonConvert.DeserializeObject<LGWEB_DispatchRequest>(requestText);
LGWEB_DispatchResult dispatchResult = DispatchAGV(request);
result.code = dispatchResult.Success ? 200 : 500;
result.message = dispatchResult.Message;
result.Data = dispatchResult;
}
catch (Exception ex)
{
result.code = 500;
result.message = ex.Message;
SaveMesLog("LGWEB_DispatchAGV", ex.Message, MesLogType.ERROR);
}
string responseText = JsonConvert.SerializeObject(result);
SaveLog_Interface_Response(responseText, aid);
return responseText;
}
/// <summary>
/// 下发临工AGV搬运任务供 WebAPI 和 Function 直接复用。
/// </summary>
public static LGWEB_DispatchResult DispatchAGV(LGWEB_DispatchRequest request, string defaultTriggerMode = "WEB", bool requireProductPoint = false)
{
if (request == null)
{
throw new Exception("请求参数格式不正确");
}
if (IsPointToPointDispatch(request))
{
return DispatchPointToPoint(request, defaultTriggerMode);
}
if (string.IsNullOrWhiteSpace(request.routeCode))
{
throw new Exception("路线编码(routeCode)不能为空");
}
LGWEB_RouteInfo route = GetRouteInfo(request);
if (requireProductPoint && route.ProductPointMatched != "1")
{
throw new Exception($"未匹配产品点位配置routeCode={request.routeCode}, 产品型号代码={request.productModelCode}, 产品型号={request.productModel}, 动作={request.actionCode}, 过程点={request.processPointType}, 工位={request.workStation}");
}
string startPosition = string.IsNullOrWhiteSpace(request.startPosition) ? route.StartPosition : request.startPosition;
string midPosition = string.IsNullOrWhiteSpace(request.midPosition) ? route.MidPosition : request.midPosition;
string endPosition = route.ActualEndPosition;
string requestTaskId = string.IsNullOrWhiteSpace(request.requestTaskId) ? Guid.NewGuid().ToString() : request.requestTaskId;
string materialCode = FirstText(request.materialCode, request.productCode, request.containerNo);
if (string.IsNullOrWhiteSpace(startPosition))
{
throw new Exception("起点位置不能为空,请检查路线配置或请求参数");
}
if (string.IsNullOrWhiteSpace(endPosition))
{
throw new Exception("终点位置不能为空,请检查路线配置");
}
LGAGV_CallResult agvResult;
if (string.Equals(route.InterfaceName, "AddTaskFromMes2", StringComparison.OrdinalIgnoreCase))
{
agvResult = LGAGV_BusinessLogic.CallAddTask2(new LGAGV_AddTask2Request
{
requestTaskId = requestTaskId,
startPosition = startPosition,
midPosition = midPosition,
endPosition = endPosition,
materialCode = materialCode
});
}
else
{
agvResult = LGAGV_BusinessLogic.CallAddTask(new LGAGV_AddTaskRequest
{
requestTaskId = requestTaskId,
startPosition = startPosition,
endPosition = endPosition,
materialCode = materialCode
});
}
SaveDispatchResult(request, route, requestTaskId, startPosition, midPosition, endPosition, materialCode, agvResult, defaultTriggerMode);
return new LGWEB_DispatchResult
{
Success = agvResult.Success,
Message = agvResult.Success ? "AGV调度成功" : $"AGV调度失败{agvResult.Message}",
DispatchMode = "ROUTE",
RequestTaskId = requestTaskId,
RouteCode = request.routeCode,
StartPosition = startPosition,
MidPosition = midPosition,
EndPosition = endPosition,
OriginalEndPosition = route.OriginalEndPosition,
ProductPointMatched = route.ProductPointMatched,
ProcessPointType = route.ProcessPointType,
RouteMessage = route.RouteMessage,
AgvResponse = agvResult.Response
};
}
private static LGWEB_DispatchResult DispatchPointToPoint(LGWEB_DispatchRequest request, string defaultTriggerMode)
{
if (string.IsNullOrWhiteSpace(request.startPosition))
{
throw new Exception("点到点模式起点位置(startPosition)不能为空");
}
if (string.IsNullOrWhiteSpace(request.endPosition))
{
throw new Exception("点到点模式终点位置(endPosition)不能为空");
}
if (!string.IsNullOrWhiteSpace(request.midPosition))
{
throw new Exception("点到点模式不支持中间位置(midPosition)");
}
if (string.Equals(request.startPosition.Trim(), request.endPosition.Trim(), StringComparison.OrdinalIgnoreCase))
{
throw new Exception("点到点模式起点和终点不能相同");
}
if (string.IsNullOrWhiteSpace(request.productCode))
{
throw new Exception("点到点模式产品编码(productCode)不能为空");
}
request.routeCode = FirstText(request.routeCode, "MANUAL_POINT_TO_POINT");
string requestTaskId = string.IsNullOrWhiteSpace(request.requestTaskId) ? Guid.NewGuid().ToString() : request.requestTaskId;
string materialCode = FirstText(request.materialCode, request.productCode, request.containerNo);
string triggerMode = string.IsNullOrWhiteSpace(defaultTriggerMode) ? "WEB" : defaultTriggerMode;
DataRow validateRow = ValidatePointToPoint(request);
LGWEB_RouteInfo route = new LGWEB_RouteInfo
{
RouteCode = request.routeCode,
StartPosition = request.startPosition,
MidPosition = "",
OriginalEndPosition = request.endPosition,
ActualEndPosition = request.endPosition,
InterfaceName = "AddTaskFromMes",
BusinessType = "点到点搬运",
TriggerMode = triggerMode,
SourceWorkStation = ReadColumn(validateRow, "起点工位号"),
TargetWorkStation = ReadColumn(validateRow, "终点工位号"),
ProductPointMatched = "0",
ProcessPointType = "",
RouteMessage = ReadColumn(validateRow, "msg")
};
LGAGV_CallResult agvResult = LGAGV_BusinessLogic.CallAddTask(new LGAGV_AddTaskRequest
{
requestTaskId = requestTaskId,
startPosition = request.startPosition,
endPosition = request.endPosition,
materialCode = materialCode
});
SaveDispatchResult(request, route, requestTaskId, request.startPosition, "", request.endPosition, materialCode, agvResult, triggerMode);
return new LGWEB_DispatchResult
{
Success = agvResult.Success,
Message = agvResult.Success ? "AGV点到点调度成功" : $"AGV点到点调度失败{agvResult.Message}",
DispatchMode = "POINT_TO_POINT",
RequestTaskId = requestTaskId,
RouteCode = request.routeCode,
StartPosition = request.startPosition,
MidPosition = "",
EndPosition = request.endPosition,
OriginalEndPosition = request.endPosition,
ProductPointMatched = "0",
ProcessPointType = "",
RouteMessage = route.RouteMessage,
AgvResponse = agvResult.Response
};
}
/// <summary>
/// 网页按钮放行临工AGV离开。
/// </summary>
public static string WEB_AllowLeave(string url, [FromBody] JObject jobj)
{
var result = new MsgResHeader<object>
{
code = 200,
message = "",
Data = null
};
if (jobj == null)
{
result.code = 500;
result.message = "参数格式不正确!";
return JsonConvert.SerializeObject(result);
}
string requestText = jobj.ToString();
SaveLog_Interface_Request(url, 2, requestText, out int aid);
try
{
LGWEB_AllowLeaveRequest request = JsonConvert.DeserializeObject<LGWEB_AllowLeaveRequest>(requestText);
if (request == null)
{
throw new Exception("请求参数格式不正确");
}
if (string.IsNullOrWhiteSpace(request.requestId))
{
throw new Exception("请求ID(requestId)不能为空");
}
if (string.IsNullOrWhiteSpace(request.position))
{
throw new Exception("位置(position)不能为空");
}
LGAGV_CallResult agvResult = LGAGV_BusinessLogic.CallAllowLeave(new LGAGV_AllowLeaveRequest
{
requestId = request.requestId,
position = request.position,
agvNo = request.agvNo,
allowLeave = 1
});
var param = new SqlParameter[]
{
new SqlParameter("@requestId", request.requestId ?? ""),
new SqlParameter("@position", request.position ?? ""),
new SqlParameter("@agvNo", request.agvNo ?? ""),
new SqlParameter("@操作人工号", request.operatorCode ?? ""),
new SqlParameter("@操作人姓名", request.operatorName ?? ""),
new SqlParameter("@备注", request.remark ?? ""),
new SqlParameter("@是否成功", agvResult.Success ? 1 : 2),
new SqlParameter("@错误信息", agvResult.Success ? "" : (agvResult.Message ?? ""))
};
ExecuteResultProcedure("LG_AGV_库位Moby_允许离开", ref param);
result.code = agvResult.Success ? 200 : 500;
result.message = agvResult.Success ? "AGV放行成功" : $"AGV放行失败{agvResult.Message}";
result.Data = new
{
requestId = request.requestId,
position = request.position,
agvResponse = agvResult.Response
};
}
catch (Exception ex)
{
result.code = 500;
result.message = ex.Message;
SaveMesLog("LGWEB_AllowLeave", ex.Message, MesLogType.ERROR);
}
string responseText = JsonConvert.SerializeObject(result);
SaveLog_Interface_Response(responseText, aid);
return responseText;
}
private static bool IsPointToPointDispatch(LGWEB_DispatchRequest request)
{
if (string.Equals((request.dispatchMode ?? "").Trim(), "POINT_TO_POINT", StringComparison.OrdinalIgnoreCase))
{
return true;
}
return !string.IsNullOrWhiteSpace(request.startPosition) && !string.IsNullOrWhiteSpace(request.endPosition);
}
private static DataRow ValidatePointToPoint(LGWEB_DispatchRequest request)
{
var param = new SqlParameter[]
{
new SqlParameter("@起点位置", request.startPosition ?? ""),
new SqlParameter("@终点位置", request.endPosition ?? ""),
new SqlParameter("@产品编码", request.productCode ?? "")
};
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("LG_AGV_库位Moby_点到点校验", ref param, out DataTable dt, out string errMessage);
if (!string.IsNullOrEmpty(errMessage))
{
throw new Exception(errMessage);
}
if (dt == null || dt.Rows.Count == 0)
{
throw new Exception("点到点校验无返回结果");
}
DataRow row = dt.Rows[0];
string resultText = row.Table.Columns.Contains("result") ? row["result"].ToString() : "2";
if (resultText != "1")
{
string msg = ReadColumn(row, "msg", "message");
throw new Exception(string.IsNullOrWhiteSpace(msg) ? "点到点校验失败" : msg);
}
return row;
}
private static LGWEB_RouteInfo GetRouteInfo(LGWEB_DispatchRequest request)
{
var param = new SqlParameter[]
{
new SqlParameter("@路线编码", request.routeCode ?? ""),
new SqlParameter("@产品型号代码", request.productModelCode ?? ""),
new SqlParameter("@产品型号", request.productModel ?? ""),
new SqlParameter("@动作编码", request.actionCode ?? ""),
new SqlParameter("@过程点大类", request.processPointType ?? ""),
new SqlParameter("@工位号", request.workStation ?? "")
};
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("LG_AGV_路线_实际终点解析", ref param, out DataTable dt, out string errMessage);
if (!string.IsNullOrEmpty(errMessage))
{
throw new Exception(errMessage);
}
if (dt == null || dt.Rows.Count == 0)
{
throw new Exception("路线解析无返回结果");
}
DataRow row = dt.Rows[0];
string resultText = row.Table.Columns.Contains("result") ? row["result"].ToString() : "2";
if (resultText != "1")
{
string msg = ReadColumn(row, "msg", "message");
throw new Exception(string.IsNullOrWhiteSpace(msg) ? "路线不可用" : msg);
}
return new LGWEB_RouteInfo
{
RouteCode = ReadColumn(row, "路线编码"),
StartPosition = ReadColumn(row, "起点位置"),
MidPosition = ReadColumn(row, "中间位置"),
OriginalEndPosition = ReadColumn(row, "原终点位置", "终点位置"),
ActualEndPosition = ReadColumn(row, "实际终点位置"),
InterfaceName = FirstText(ReadColumn(row, "调用接口"), "AddTaskFromMes"),
BusinessType = ReadColumn(row, "业务类型"),
TriggerMode = ReadColumn(row, "触发方式"),
SourceWorkStation = ReadColumn(row, "源工位号"),
TargetWorkStation = ReadColumn(row, "目标工位号"),
ProductPointMatched = ReadColumn(row, "是否匹配型号点位"),
ProductModelCode = ReadColumn(row, "产品型号代码"),
ProductModel = ReadColumn(row, "产品型号"),
ActionCode = ReadColumn(row, "动作编码"),
ProcessPointType = ReadColumn(row, "过程点大类"),
RouteMessage = ReadColumn(row, "msg", "message")
};
}
private static void SaveDispatchResult(LGWEB_DispatchRequest request, LGWEB_RouteInfo route, string requestTaskId,
string startPosition, string midPosition, string endPosition, string materialCode, LGAGV_CallResult agvResult, string defaultTriggerMode)
{
var param = new SqlParameter[]
{
new SqlParameter("@路线编码", request.routeCode ?? ""),
new SqlParameter("@业务类型", route.BusinessType ?? ""),
new SqlParameter("@触发方式", string.IsNullOrWhiteSpace(route.TriggerMode) ? (defaultTriggerMode ?? "WEB") : route.TriggerMode),
new SqlParameter("@订单号", request.orderNo ?? ""),
new SqlParameter("@产品编码", FirstText(request.productCode, request.materialCode)),
new SqlParameter("@产品型号", request.productModel ?? ""),
new SqlParameter("@器具号", request.containerNo ?? ""),
new SqlParameter("@requestTaskId", requestTaskId ?? ""),
new SqlParameter("@起点位置", startPosition ?? ""),
new SqlParameter("@中间位置", midPosition ?? ""),
new SqlParameter("@终点位置", endPosition ?? ""),
new SqlParameter("@原终点位置", route.OriginalEndPosition ?? ""),
new SqlParameter("@materialCode", materialCode ?? ""),
new SqlParameter("@调用接口", route.InterfaceName ?? ""),
new SqlParameter("@操作人工号", request.operatorCode ?? ""),
new SqlParameter("@操作人姓名", request.operatorName ?? ""),
new SqlParameter("@备注", request.remark ?? ""),
new SqlParameter("@是否成功", agvResult.Success ? 1 : 2),
new SqlParameter("@错误信息", agvResult.Success ? "" : (agvResult.Message ?? ""))
};
ExecuteResultProcedure("LG_AGV_库位Moby_下发任务", ref param);
}
private static string ReadColumn(DataRow row, params string[] columnNames)
{
foreach (string columnName in columnNames)
{
if (row.Table.Columns.Contains(columnName))
{
return row[columnName]?.ToString() ?? "";
}
}
return "";
}
private static string FirstText(params string[] values)
{
foreach (string value in values)
{
if (!string.IsNullOrWhiteSpace(value))
{
return value;
}
}
return "";
}
private static void ExecuteResultProcedure(string procedureName, ref SqlParameter[] param)
{
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure(procedureName, ref param, out DataTable dt, out string errMessage);
if (!string.IsNullOrEmpty(errMessage))
{
throw new Exception(errMessage);
}
if (dt != null && dt.Rows.Count > 0 && dt.Columns.Contains("result") && dt.Rows[0]["result"].ToString() != "1")
{
string msg = dt.Columns.Contains("msg") ? dt.Rows[0]["msg"].ToString() : "存储过程执行失败";
throw new Exception(msg);
}
}
private class LGWEB_RouteInfo
{
public string RouteCode { get; set; }
public string StartPosition { get; set; }
public string MidPosition { get; set; }
public string OriginalEndPosition { get; set; }
public string ActualEndPosition { get; set; }
public string InterfaceName { get; set; }
public string BusinessType { get; set; }
public string TriggerMode { get; set; }
public string SourceWorkStation { get; set; }
public string TargetWorkStation { get; set; }
public string ProductPointMatched { get; set; }
public string ProductModelCode { get; set; }
public string ProductModel { get; set; }
public string ActionCode { get; set; }
public string ProcessPointType { get; set; }
public string RouteMessage { get; set; }
}
}
}

View File

@@ -0,0 +1,88 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace MisDataSaveDate
{
/// <summary>
/// 临工AGV网页按钮调度请求。
/// </summary>
public class LGWEB_DispatchRequest
{
public string dispatchMode { get; set; }
public string routeCode { get; set; }
public string requestTaskId { get; set; }
public string startPosition { get; set; }
public string midPosition { get; set; }
public string endPosition { get; set; }
public string materialCode { get; set; }
public string productCode { get; set; }
public string productModelCode { get; set; }
public string productModel { get; set; }
public string actionCode { get; set; }
public string processPointType { get; set; }
public string workStation { get; set; }
public string containerNo { get; set; }
public string orderNo { get; set; }
public string operatorCode { get; set; }
public string operatorName { get; set; }
public string remark { get; set; }
}
/// <summary>
/// 临工AGV网页按钮放行请求。
/// </summary>
public class LGWEB_AllowLeaveRequest
{
public string requestId { get; set; }
public string position { get; set; }
public string agvNo { get; set; }
public string operatorCode { get; set; }
public string operatorName { get; set; }
public string remark { get; set; }
}
/// <summary>
/// 临工AGV调度内部结果WebAPI 和 Function 共用。
/// </summary>
public class LGWEB_DispatchResult
{
[JsonProperty("success")]
public bool Success { get; set; }
[JsonProperty("message")]
public string Message { get; set; }
[JsonProperty("dispatchMode")]
public string DispatchMode { get; set; }
[JsonProperty("requestTaskId")]
public string RequestTaskId { get; set; }
[JsonProperty("routeCode")]
public string RouteCode { get; set; }
[JsonProperty("startPosition")]
public string StartPosition { get; set; }
[JsonProperty("midPosition")]
public string MidPosition { get; set; }
[JsonProperty("endPosition")]
public string EndPosition { get; set; }
[JsonProperty("originalEndPosition")]
public string OriginalEndPosition { get; set; }
[JsonProperty("productPointMatched")]
public string ProductPointMatched { get; set; }
[JsonProperty("processPointType")]
public string ProcessPointType { get; set; }
[JsonProperty("routeMessage")]
public string RouteMessage { get; set; }
[JsonProperty("agvResponse")]
public JObject AgvResponse { get; set; }
}
}

View File

@@ -80,7 +80,7 @@ namespace MisDataSaveDate
throw new Exception("OperAtion_JobStart 缺少必要参数:工位号、订单号或工件编号");
}
CALL_Inerface_DataHandle.CALL_Inerface_JobStart(workStation1, orderNo1, workpieceNo1);
CALL_Inerface_DataHandle.CALL_Inerface_JobStart(workStation1, workpieceNo1, orderNo1);
break;
case "OperAtion_JobFinished":