837 lines
37 KiB
C#
837 lines
37 KiB
C#
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);
|
||
}
|
||
}
|
||
}
|