chore: initial commit

This commit is contained in:
XingCheng3
2026-05-29 09:34:04 +08:00
commit 78ae9dcd2e
683 changed files with 68110 additions and 0 deletions

View File

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

View File

@@ -0,0 +1,164 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
namespace MisDataSaveDate
{
/// <summary>
/// AGV进入请求实体类
/// </summary>
public class AGV_EnterRequest
{
/// <summary>
/// 请求编号,每个请求都要一个唯一编号,同一个请求重复提交,使用同一编号
/// </summary>
public string reqCode { get; set; }
/// <summary>
/// 请求时间戳,格式: "yyyy-MM-dd HH:mm:ss"
/// </summary>
public string reqTime { get; set; }
/// <summary>
/// 地码 X 坐标(mm):任务完成时有值
/// </summary>
public string cooX { get; set; }
/// <summary>
/// 地码 Y 坐标(mm):任务完成时有值
/// </summary>
public string cooY { get; set; }
/// <summary>
/// 当前位置编号
/// </summary>
public string currentPositionCode { get; set; }
/// <summary>
/// 自定义字段不超过2000个字符
/// </summary>
public object data { get; set; }
/// <summary>
/// 地图编号
/// </summary>
public string mapCode { get; set; }
/// <summary>
/// 地码编号:任务完成时有值
/// </summary>
public string mapDataCode { get; set; }
/// <summary>
/// 仓位编号叉车与CTU任务时有值
/// </summary>
public string stgBinCode { get; set; }
/// <summary>
/// 方法名, apply: 申请进入release申请离开
/// </summary>
public string method { get; set; }
/// <summary>
/// 货架编号:背货架时有值
/// </summary>
public string podCode { get; set; }
/// <summary>
/// "180","0","90","-90" 分别对应地图的"左","右","上","下":任务完成时有值
/// </summary>
public string podDir { get; set; }
/// <summary>
/// 物料编号
/// </summary>
public string materialLot { get; set; }
/// <summary>
/// AGV编号同 agvCode
/// </summary>
public string robotCode { get; set; }
/// <summary>
/// 当前任务单号
/// </summary>
public string taskCode { get; set; }
/// <summary>
/// 工作位与RCS-2000端配置的位置名称一致。任务完成时有值与生成任务单接口中的wbCode一致
/// </summary>
public string wbCode { get; set; }
/// <summary>
/// 容器编号
/// </summary>
public string ctnrCode { get; set; }
/// <summary>
/// 容器类型
/// </summary>
public string ctnrType { get; set; }
/// <summary>
/// 巷道编号
/// </summary>
public string roadWayCode { get; set; }
/// <summary>
/// 巷道内顺序号巷道尾是0到巷道头依次递增1
/// </summary>
public string seq { get; set; }
/// <summary>
/// 设备编号如梳齿式工作站、输送线等一般使用于CTU场景。系统根据仓位定位到关联的设备编号
/// </summary>
public string eqpCode { get; set; }
}
/// <summary>
/// AGV请求反馈实体类
/// </summary>
public class AGV_FeedbackRequest
{
/// <summary>
/// 请求编号
/// </summary>
public string reqCode { get; set; }
/// <summary>
/// 任务单号
/// </summary>
public string taskCode { get; set; }
}
/// <summary>
/// AGV接口通用响应类
/// </summary>
public class AGV_Response
{
/// <summary>
/// 返回码 "0"表示成功
/// </summary>
public string code { get; set; }
/// <summary>
/// 返回消息
/// </summary>
public string message { get; set; }
/// <summary>
/// 请求编号
/// </summary>
public string reqCode { get; set; }
public AGV_Response()
{
code = "0";
message = "成功";
reqCode = "";
}
}
}

View File

@@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using MisDataSaveDate;
using System.Web.Http;
using static MisDataSaveDate.Helper.ApiLogHelper;
using MisDataSaveDate.Helper;
namespace MisDataSaveDate
{
/// <summary>
/// 西开 AGV 业务处理类
/// 处理 AGV -> MES 的接收请求
/// </summary>
public class ZZAGV_BusinessLogic
{
/// <summary>
/// 处理状态更新请求(到达/离开)
/// </summary>
/// <param name="url">接口URL</param>
/// <param name="jobj">请求数据</param>
/// <returns>处理结果 JSON 字符串</returns>
public static string ProcessStatusUpdate(string url, [FromBody] JObject jobj)
{
var result = ZZAGV_Response.Success();
string str = jobj?.ToString() ?? "";
// 存储请求日志
SaveLog_Interface_Request(url, 2, str, out int AID);
try
{
if (jobj == null)
{
throw new Exception("请求参数不能为空");
}
ZZAGV_StatusUpdateRequest request = JsonConvert.DeserializeObject<ZZAGV_StatusUpdateRequest>(str);
// 参数校验
if (string.IsNullOrWhiteSpace(request.position))
{
throw new Exception("工位编号(position)不能为空");
}
string typeDesc = request.type == 1 ? "到达" : (request.type == 2 ? "离开" : "未知");
SaveMesLog("ZZAGV_StatusUpdate", $"AGV状态更新工位={request.position}, 类型={typeDesc}, AGV={request.agvid}, 物料={request.materialCode}", MesLogType.INFO);
// TODO: 后续业务逻辑在此添加
}
catch (Exception ex)
{
result = ZZAGV_Response.Fail(1, ex.Message);
SaveMesLog("ZZAGV_StatusUpdate", $"处理异常:{ex.Message}", MesLogType.ERROR);
}
string retString = JsonConvert.SerializeObject(result);
SaveLog_Interface_Response(retString, AID);
return retString;
}
/// <summary>
/// 处理动作完成请求(举升/下降)
/// </summary>
/// <param name="url">接口URL</param>
/// <param name="jobj">请求数据</param>
/// <returns>处理结果 JSON 字符串</returns>
public static string ProcessActionComplete(string url, [FromBody] JObject jobj)
{
var result = ZZAGV_Response.Success();
string str = jobj?.ToString() ?? "";
// 存储请求日志
SaveLog_Interface_Request(url, 2, str, out int AID);
try
{
if (jobj == null)
{
throw new Exception("请求参数不能为空");
}
ZZAGV_ActionCompleteRequest request = JsonConvert.DeserializeObject<ZZAGV_ActionCompleteRequest>(str);
// 参数校验
if (string.IsNullOrWhiteSpace(request.position))
{
throw new Exception("工位编号(position)不能为空");
}
string typeDesc = request.type == 1 ? "举升完成" : (request.type == 2 ? "下降完成" : "未知");
SaveMesLog("ZZAGV_ActionComplete", $"AGV动作完成工位={request.position}, 类型={typeDesc}", MesLogType.INFO);
// TODO: 后续业务逻辑在此添加
}
catch (Exception ex)
{
result = ZZAGV_Response.Fail(1, ex.Message);
SaveMesLog("ZZAGV_ActionComplete", $"处理异常:{ex.Message}", MesLogType.ERROR);
}
string retString = JsonConvert.SerializeObject(result);
SaveLog_Interface_Response(retString, AID);
return retString;
}
/// <summary>
/// 处理故障/报警推送请求
/// </summary>
/// <param name="url">接口URL</param>
/// <param name="jobj">请求数据</param>
/// <returns>处理结果 JSON 字符串</returns>
public static string ProcessAlarmPush(string url, [FromBody] JObject jobj)
{
var result = ZZAGV_Response.Success();
string str = jobj?.ToString() ?? "";
// 存储请求日志
SaveLog_Interface_Request(url, 2, str, out int AID);
try
{
if (jobj == null)
{
throw new Exception("请求参数不能为空");
}
ZZAGV_AlarmPushRequest request = JsonConvert.DeserializeObject<ZZAGV_AlarmPushRequest>(str);
string typeDesc = request.type == 1 ? "AGV故障" : (request.type == 2 ? "区域故障" : "未知");
SaveMesLog("ZZAGV_AlarmPush", $"AGV故障推送类型={typeDesc}, AGV={request.agvNo}, 故障码={request.errorCode}, 信息={request.errorMsg}", MesLogType.WARNING);
// TODO: 后续业务逻辑在此添加
}
catch (Exception ex)
{
result = ZZAGV_Response.Fail(1, ex.Message);
SaveMesLog("ZZAGV_AlarmPush", $"处理异常:{ex.Message}", MesLogType.ERROR);
}
string retString = JsonConvert.SerializeObject(result);
SaveLog_Interface_Response(retString, AID);
return retString;
}
/// <summary>
/// 处理任务执行结果请求
/// </summary>
/// <param name="url">接口URL</param>
/// <param name="jobj">请求数据</param>
/// <returns>处理结果 JSON 字符串</returns>
public static string ProcessTaskResult(string url, [FromBody] JObject jobj)
{
var result = ZZAGV_Response.Success();
string str = jobj?.ToString() ?? "";
// 存储请求日志
SaveLog_Interface_Request(url, 2, str, out int AID);
try
{
if (jobj == null)
{
throw new Exception("请求参数不能为空");
}
ZZAGV_TaskResultRequest request = JsonConvert.DeserializeObject<ZZAGV_TaskResultRequest>(str);
// 参数校验
if (string.IsNullOrWhiteSpace(request.requestTaskId))
{
throw new Exception("任务ID(requestTaskId)不能为空");
}
string statusDesc = request.status == "success" ? "成功" : "失败";
SaveMesLog("ZZAGV_TaskResult", $"AGV任务结果任务ID={request.requestTaskId}, 状态={statusDesc}, AGV={request.agvNo}, 消息={request.message}", MesLogType.INFO);
// TODO: 后续业务逻辑在此添加
}
catch (Exception ex)
{
result = ZZAGV_Response.Fail(1, ex.Message);
SaveMesLog("ZZAGV_TaskResult", $"处理异常:{ex.Message}", MesLogType.ERROR);
}
string retString = JsonConvert.SerializeObject(result);
SaveLog_Interface_Response(retString, AID);
return retString;
}
}
}

View File

@@ -0,0 +1,221 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MisDataSaveDate
{
#region AGV -> MES
/// <summary>
/// 状态更新请求(到达/离开)
/// AGV 到达或离开工位时通知 MES
/// </summary>
public class ZZAGV_StatusUpdateRequest
{
/// <summary>
/// 工位编号
/// </summary>
public string position { get; set; }
/// <summary>
/// 类型1-到达2-离开
/// </summary>
public int type { get; set; }
/// <summary>
/// 物料编码/产品编码
/// </summary>
public string materialCode { get; set; }
/// <summary>
/// AGV车号
/// </summary>
public string agvid { get; set; }
}
/// <summary>
/// 动作完成请求(举升/下降)
/// AGV 完成托盘举升或下降动作后通知 MES
/// </summary>
public class ZZAGV_ActionCompleteRequest
{
/// <summary>
/// 工位编号
/// </summary>
public string position { get; set; }
/// <summary>
/// 类型1-举升完成2-下降完成
/// </summary>
public int type { get; set; }
}
/// <summary>
/// 故障/报警推送请求
/// AGV 上报故障或区域故障
/// </summary>
public class ZZAGV_AlarmPushRequest
{
/// <summary>
/// AGV车号
/// </summary>
public string agvNo { get; set; }
/// <summary>
/// 故障代码
/// </summary>
public string errorCode { get; set; }
/// <summary>
/// 故障信息
/// </summary>
public string errorMsg { get; set; }
/// <summary>
/// 故障类型1-AGV故障2-区域故障
/// </summary>
public int type { get; set; }
}
/// <summary>
/// 任务执行结果请求
/// AGV 告知 MES 任务是否执行成功
/// </summary>
public class ZZAGV_TaskResultRequest
{
/// <summary>
/// 任务唯一ID与下发任务时的 requestTaskId 对应)
/// </summary>
public string requestTaskId { get; set; }
/// <summary>
/// 执行状态success-成功fail-失败
/// </summary>
public string status { get; set; }
/// <summary>
/// AGV车号
/// </summary>
public string agvNo { get; set; }
/// <summary>
/// 失败原因(成功时为空)
/// </summary>
public string message { get; set; }
}
#endregion
#region MES -> AGV
/// <summary>
/// 下发任务请求
/// MES 给 AGV 下发搬运任务
/// </summary>
public class ZZAGV_AddTaskRequest
{
/// <summary>
/// 任务唯一ID由 MES 生成)
/// </summary>
public string requestTaskId { get; set; }
/// <summary>
/// 抬货点/取货位置
/// </summary>
public string startPosition { get; set; }
/// <summary>
/// 卸货点/目标位置
/// </summary>
public string endPosition { get; set; }
/// <summary>
/// 产品编码/物料编码
/// </summary>
public string materialCode { get; set; }
}
/// <summary>
/// 放行请求
/// MES 告知 AGV 可以离开当前位置
/// </summary>
public class ZZAGV_AllowLeaveRequest
{
/// <summary>
/// 请求ID
/// </summary>
public string requestId { get; set; }
/// <summary>
/// 当前位置编号
/// </summary>
public string position { get; set; }
/// <summary>
/// 放行标志固定为1
/// </summary>
public int allowLeave { get; set; } = 1;
}
#endregion
#region
/// <summary>
/// 西开 AGV 接口通用响应
/// </summary>
public class ZZAGV_Response
{
/// <summary>
/// 返回码0-成功,其他-失败
/// </summary>
public int code { get; set; }
/// <summary>
/// 返回描述信息
/// </summary>
public string desc { get; set; }
/// <summary>
/// 是否成功
/// </summary>
public bool success { get; set; }
public ZZAGV_Response()
{
code = 0;
desc = "成功";
success = true;
}
/// <summary>
/// 设置成功响应
/// </summary>
public static ZZAGV_Response Success(string desc = "成功")
{
return new ZZAGV_Response
{
code = 0,
desc = desc,
success = true
};
}
/// <summary>
/// 设置失败响应
/// </summary>
public static ZZAGV_Response Fail(int code, string desc)
{
return new ZZAGV_Response
{
code = code,
desc = desc,
success = false
};
}
}
#endregion
}

View File

@@ -0,0 +1,44 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Web;
using System.Web.Http;
using System.Collections.Concurrent;
using Newtonsoft.Json.Linq;
using System.Threading;
using System.Net;
using System.Net.Http.Headers;
using System.IO;
using MisDataSaveDate;
namespace MisDataSaveDate
{
/// <summary>
/// AGV接口控制器
/// </summary>
public class AGVController : ApiController
{
readonly string headUrl = "agv/";
/// <summary>
/// AGV请求进入离开、下降举升接口接收方
/// 接收AGV的进入、离开、下降、举升请求并存储到数据库
/// </summary>
/// <param name="jobj">AGV请求数据</param>
/// <returns>处理结果</returns>
[HttpPost]
[Route("agv/agvReqInOut")]
public HttpResponseMessage agvReqInOut([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(AGV_BusinessLogic.ProcessAGVEnterRequest(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
}
}

View File

@@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using System.Net.Http;
using System.Web.Http;
using ExternalDataSync.MOM;
namespace ExternalDataSync.WebAPI.Controller
{
public class CheckDataController : ApiController
{
private readonly string headUrl = "TestPlatform/";
[HttpPost]
[Route("TestPlatform/OnlineCheckData")]
public HttpResponseMessage OnlineCheckData([FromBody] JObject jobj)
{
var result = Other.OnlineCheckData(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj);
return new HttpResponseMessage
{
Content = new StringContent(result, Encoding.GetEncoding("UTF-8"), "application/json")
};
}
[HttpPost]
[Route("TestPlatform/OnlineStatusData")]
public HttpResponseMessage OnlineStatusData([FromBody] JObject jobj)
{
var result = Other.OnlineStatusData(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj);
return new HttpResponseMessage
{
Content = new StringContent(result, Encoding.GetEncoding("UTF-8"), "application/json")
};
}
[HttpPost]
[Route("TestPlatform/OnlineDewPointResultData")]
public HttpResponseMessage OnlineDewPointResultData([FromBody] JObject jobj)
{
var result = DewPointDataHandler.OnlineDewPointResultData(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj);
return new HttpResponseMessage
{
Content = new StringContent(result, Encoding.GetEncoding("UTF-8"), "application/json")
};
}
[HttpPost]
[Route("TestPlatform/OnlineDewPointTechnologyData")]
public HttpResponseMessage OnlineDewPointTechnologyData([FromBody] JObject jobj)
{
var result = DewPointDataHandler.OnlineDewPointTechnologyData(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj);
return new HttpResponseMessage
{
Content = new StringContent(result, Encoding.GetEncoding("UTF-8"), "application/json")
};
}
[HttpPost]
[Route("TestPlatform/OnlineDewPointUseData")]
public HttpResponseMessage OnlineDewPointUseData([FromBody] JObject jobj)
{
var result = DewPointDataHandler.OnlineDewPointUseData(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj);
return new HttpResponseMessage
{
Content = new StringContent(result, Encoding.GetEncoding("UTF-8"), "application/json")
};
}
[HttpPost]
[Route("TestPlatform/OnlineDewPointStatusData")]
public HttpResponseMessage OnlineDewPointStatusData([FromBody] JObject jobj)
{
var result = DewPointDataHandler.OnlineDewPointStatusData(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj);
return new HttpResponseMessage
{
Content = new StringContent(result, Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// 获取位置待测试产品信息
/// </summary>
[HttpPost]
[Route("TestPlatform/GetWaitCheckProductData")]
public HttpResponseMessage GetWaitCheckProductData([FromBody] JObject jobj)
{
var result = Other.GetWaitCheckProductData(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj);
return new HttpResponseMessage
{
Content = new StringContent(result, Encoding.GetEncoding("UTF-8"), "application/json")
};
}
}
}

View File

@@ -0,0 +1,270 @@
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.RegularExpressions;
using System.Web.Http;
using DataLinkMesWork2;
namespace WebApi
{
[RoutePrefix("api/checkimage")]
public class CheckImageController : ApiController
{
private readonly string _defaultRoot = @"D:\\XDCheckImages";
public class ImageUploadRequest
{
public string ProductCode { get; set; }
public string Remark { get; set; }
public string ImageBase64 { get; set; }
public string FileExt { get; set; }
}
public class ImageDownloadRequest
{
public string Path { get; set; }
}
private string GetRootPath()
{
string root = null;
try
{
root = ConfigurationManager.AppSettings["XD_CheckImageRootPath"];
}
catch
{
}
if (string.IsNullOrWhiteSpace(root))
{
root = _defaultRoot;
}
return root;
}
private string SanitizeForPath(string input)
{
if (string.IsNullOrEmpty(input)) return string.Empty;
char[] invalid = Path.GetInvalidFileNameChars();
var value = input.Trim();
foreach (var c in invalid)
{
value = value.Replace(c.ToString(), string.Empty);
}
value = value.Replace("/", string.Empty).Replace("\\", string.Empty);
return value;
}
private string GetExtensionFromRequest(ImageUploadRequest request)
{
string ext = ".jpg";
if (request == null) return ext;
if (!string.IsNullOrWhiteSpace(request.FileExt))
{
ext = request.FileExt.Trim();
if (!ext.StartsWith("."))
{
ext = "." + ext;
}
return ext;
}
if (!string.IsNullOrWhiteSpace(request.ImageBase64) &&
request.ImageBase64.StartsWith("data:", StringComparison.OrdinalIgnoreCase))
{
try
{
var match = Regex.Match(request.ImageBase64, "^data:(?<mime>[^;]+);base64,", RegexOptions.IgnoreCase);
if (match.Success)
{
var mime = match.Groups["mime"].Value.ToLowerInvariant();
if (mime == "image/png") return ".png";
if (mime == "image/gif") return ".gif";
if (mime == "image/bmp") return ".bmp";
if (mime == "image/webp") return ".webp";
if (mime == "image/tiff" || mime == "image/tif") return ".tif";
if (mime == "image/jpeg" || mime == "image/jpg") return ".jpg";
}
}
catch
{
}
}
return ext;
}
private string GetContentType(string fileName)
{
var extension = Path.GetExtension(fileName).ToLowerInvariant();
if (extension == ".bmp") return "image/bmp";
if (extension == ".jpg" || extension == ".jpeg") return "image/jpeg";
if (extension == ".png") return "image/png";
if (extension == ".gif") return "image/gif";
if (extension == ".tiff" || extension == ".tif") return "image/tiff";
if (extension == ".webp") return "image/webp";
return "application/octet-stream";
}
private bool IsPathSafe(string fullPath)
{
try
{
var basePath = Path.GetFullPath(GetRootPath());
var requestedPath = Path.GetFullPath(fullPath);
return requestedPath.StartsWith(basePath, StringComparison.OrdinalIgnoreCase);
}
catch
{
return false;
}
}
[HttpPost]
[Route("upload")]
public IHttpActionResult Upload([FromBody] ImageUploadRequest request)
{
try
{
if (request == null ||
string.IsNullOrWhiteSpace(request.ProductCode) ||
string.IsNullOrWhiteSpace(request.Remark) ||
string.IsNullOrWhiteSpace(request.ImageBase64))
{
return Ok(new { success = false, message = "产品编号、备注和图片不能为空" });
}
string productCode = SanitizeForPath(request.ProductCode);
string remark = SanitizeForPath(request.Remark);
if (string.IsNullOrEmpty(productCode))
{
return Ok(new { success = false, message = "产品编号无效" });
}
string ext = GetExtensionFromRequest(request);
string base64 = request.ImageBase64.Trim();
int commaIndex = base64.IndexOf(',');
if (base64.StartsWith("data:", StringComparison.OrdinalIgnoreCase) && commaIndex > 0)
{
base64 = base64.Substring(commaIndex + 1);
}
byte[] bytes;
try
{
bytes = Convert.FromBase64String(base64);
}
catch
{
return Ok(new { success = false, message = "图片数据格式错误" });
}
var now = DateTime.Now;
string datePart = now.ToString("yyyyMMdd");
string timePart = now.ToString("HHmmss");
string fileName = string.Format("{0}-{1}-{2}{3}", timePart, productCode, remark, ext);
string relativePath = string.Format("/{0}/{1}", datePart, fileName);
string root = GetRootPath();
string directory = Path.Combine(root, datePart);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
string fullPath = Path.Combine(directory, fileName);
if (!IsPathSafe(fullPath))
{
return Ok(new { success = false, message = "目标路径不安全" });
}
File.WriteAllBytes(fullPath, bytes);
string errorMessage;
var sqlParameters = new SqlParameter[4];
sqlParameters[0] = new SqlParameter("@产品编号", SqlDbType.NVarChar, 500) { Value = (object)request.ProductCode ?? DBNull.Value };
sqlParameters[1] = new SqlParameter("@备注", SqlDbType.NVarChar, 500) { Value = (object)request.Remark ?? DBNull.Value };
sqlParameters[2] = new SqlParameter("@图片路径", SqlDbType.NVarChar, 500) { Value = (object)relativePath ?? DBNull.Value };
sqlParameters[3] = new SqlParameter("@图片名称", SqlDbType.NVarChar, 500) { Value = (object)fileName ?? DBNull.Value };
bool dbOk = DataAccess2.ExecuteStoredProcedure("XD_检测图片上传_增加", ref sqlParameters, out errorMessage);
if (!dbOk)
{
return Ok(new { success = false, message = "图片已保存,但写入数据库失败:" + errorMessage });
}
return Ok(new
{
success = true,
message = "上传成功",
data = new
{
= request.ProductCode,
= request.Remark,
= relativePath,
= fileName
}
});
}
catch (Exception ex)
{
return Ok(new { success = false, message = "服务器错误:" + ex.Message });
}
}
[HttpPost]
[Route("download")]
public IHttpActionResult Download([FromBody] ImageDownloadRequest request)
{
try
{
if (request == null || string.IsNullOrWhiteSpace(request.Path))
{
return Ok(new { success = false, message = "文件路径不能为空" });
}
string root = GetRootPath();
string relative = request.Path.Replace("\\", "/").Trim();
if (relative.StartsWith("/"))
{
relative = relative.Substring(1);
}
string fullPath = Path.Combine(root, relative.Replace('/', Path.DirectorySeparatorChar));
if (!IsPathSafe(fullPath) || !File.Exists(fullPath))
{
return Ok(new { success = false, message = "文件不存在" });
}
var fileInfo = new FileInfo(fullPath);
var contentType = GetContentType(fileInfo.Name);
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StreamContent(new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.Read))
};
response.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("inline")
{
FileName = fileInfo.Name
};
return ResponseMessage(response);
}
catch (Exception ex)
{
return Ok(new { success = false, message = "下载文件失败:" + ex.Message });
}
}
}
}

View File

@@ -0,0 +1,458 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Net.Http.Headers;
using WinSCP;
namespace WebApi
{
[RoutePrefix("api/craftfile")]
public class CraftFileController : ApiController
{
// 本地缓存根目录
private readonly string _cacheRoot = @"D:\\CraftFilesCache";
private readonly string _sftpHost = "10.107.69.5";
private readonly string _sftpUser = "root";
private readonly string _sftpPassword = "XKYXmes@123!";
public class FileRequestDto
{
// 远程SFTP相对路径或绝对路径如 /root/PLM-MES/.../xxx.pdf
public string RelativePath { get; set; } = "";
}
[HttpPost]
[Route("browse")]
public IHttpActionResult Browse([FromBody] FileRequestDto request)
{
try
{
if (request == null || string.IsNullOrWhiteSpace(request.RelativePath))
return Ok(new { success = false, message = "路径不能为空" });
EnsureCacheRoot();
var remotePath = NormalizeRemotePath(request.RelativePath);
var localPath = ToLocalPath(remotePath);
var isFile = Path.HasExtension(remotePath);
if (isFile)
{
// 确保本地存在
if (!System.IO.File.Exists(localPath))
{
var ok = DownloadFileFromSftp(remotePath, localPath, out string err);
if (!ok) return Ok(new { success = false, message = $"下载失败: {err}" });
}
return GetFilePreviewLocal(localPath, remotePath);
}
else
{
// 目录:优先读取本地,没有则读取远程目录结构
if (Directory.Exists(localPath))
{
return GetDirectoryContentsLocal(localPath, remotePath);
}
else
{
return GetDirectoryContentsRemote(remotePath);
}
}
}
catch (Exception ex)
{
return Ok(new { success = false, message = $"服务器错误: {ex.Message}" });
}
}
[HttpPost]
[Route("download")]
public IHttpActionResult Download([FromBody] FileRequestDto request)
{
try
{
if (request == null || string.IsNullOrWhiteSpace(request.RelativePath))
return Ok(new { success = false, message = "文件路径不能为空" });
EnsureCacheRoot();
var remotePath = NormalizeRemotePath(request.RelativePath);
var localPath = ToLocalPath(remotePath);
if (!Path.HasExtension(remotePath))
return Ok(new { success = false, message = "请传入文件路径" });
if (!System.IO.File.Exists(localPath))
{
var ok = DownloadFileFromSftp(remotePath, localPath, out string err);
if (!ok) return Ok(new { success = false, message = $"下载失败: {err}" });
}
var fileInfo = new FileInfo(localPath);
var contentType = GetContentType(fileInfo.Name);
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StreamContent(new FileStream(localPath, FileMode.Open, FileAccess.Read, FileShare.Read))
};
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType);
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = fileInfo.Name
};
return ResponseMessage(response);
}
catch (Exception ex)
{
return Ok(new { success = false, message = $"下载文件失败: {ex.Message}" });
}
}
// 新增浏览器直接预览文件支持PDF等支持Range分块
[HttpGet]
[Route("preview")]
public HttpResponseMessage Preview([FromUri] string path)
{
try
{
if (string.IsNullOrWhiteSpace(path))
{
return Request.CreateResponse(HttpStatusCode.BadRequest, new { success = false, message = "文件路径不能为空" });
}
EnsureCacheRoot();
var remotePath = NormalizeRemotePath(path);
var localPath = ToLocalPath(remotePath);
if (!Path.HasExtension(remotePath))
{
return Request.CreateResponse(HttpStatusCode.BadRequest, new { success = false, message = "请传入文件路径" });
}
if (!System.IO.File.Exists(localPath))
{
var ok = DownloadFileFromSftp(remotePath, localPath, out string err);
if (!ok)
{
return Request.CreateResponse(HttpStatusCode.InternalServerError, new { success = false, message = $"下载失败: {err}" });
}
}
var fileInfo = new FileInfo(localPath);
var contentType = GetContentType(fileInfo.Name);
var totalLength = fileInfo.Length;
var response = new HttpResponseMessage();
var range = Request.Headers.Range;
var stream = new FileStream(localPath, FileMode.Open, FileAccess.Read, FileShare.Read);
if (range != null && range.Ranges.Count > 0 && totalLength > 0)
{
// 处理 Range 请求
var from = range.Ranges.First().From ?? 0;
var to = range.Ranges.First().To ?? (totalLength - 1);
if (to >= totalLength) to = totalLength - 1;
var length = to - from + 1;
stream.Seek(from, SeekOrigin.Begin);
response.StatusCode = HttpStatusCode.PartialContent;
response.Content = new StreamContent(stream);
response.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
response.Content.Headers.ContentLength = length;
response.Content.Headers.ContentRange = new ContentRangeHeaderValue(from, to, totalLength);
response.Headers.AcceptRanges.Add("bytes");
}
else
{
// 全量流式
response.StatusCode = HttpStatusCode.OK;
response.Content = new StreamContent(stream);
response.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
response.Content.Headers.ContentLength = totalLength;
response.Headers.AcceptRanges.Add("bytes");
}
// inline 以支持浏览器内嵌预览
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("inline")
{
FileName = fileInfo.Name
};
// CORS 允许跨域及暴露必要头
if (!response.Headers.Contains("Access-Control-Allow-Origin"))
response.Headers.Add("Access-Control-Allow-Origin", "*");
if (!response.Headers.Contains("Access-Control-Expose-Headers"))
response.Headers.Add("Access-Control-Expose-Headers", "Accept-Ranges, Content-Range, Content-Length, Content-Type, Content-Disposition");
return response;
}
catch (Exception ex)
{
return Request.CreateResponse(HttpStatusCode.InternalServerError, new { success = false, message = $"预览失败: {ex.Message}" });
}
}
private IHttpActionResult GetFilePreviewLocal(string localPath, string remotePath)
{
try
{
var fileInfo = new FileInfo(localPath);
var extension = fileInfo.Extension.ToLowerInvariant();
var previewable = IsPreviewableFile(extension);
var contentType = GetContentType(fileInfo.Name);
bool tooLarge = fileInfo.Length > 500 * 1024 * 1024; // 500MB限制
string base64String = null;
string dataUrl = null;
bool canPreview = previewable && !tooLarge;
if (canPreview)
{
var fileBytes = System.IO.File.ReadAllBytes(localPath);
base64String = Convert.ToBase64String(fileBytes);
dataUrl = $"data:{contentType};base64,{base64String}";
}
var result = new
{
success = true,
type = "file",
path = remotePath,
name = fileInfo.Name,
size = fileInfo.Length,
extension = fileInfo.Extension,
contentType = contentType,
isPreviewable = canPreview,
base64Data = base64String,
dataUrl = dataUrl,
created = fileInfo.CreationTime,
modified = fileInfo.LastWriteTime,
message = tooLarge ? "文件过大,无法预览,可下载" : null
};
return Ok(result);
}
catch (Exception ex)
{
return Ok(new { success = false, message = $"获取文件预览失败: {ex.Message}" });
}
}
private IHttpActionResult GetDirectoryContentsLocal(string localPath, string remotePath)
{
try
{
var items = new List<object>();
var directories = Directory.GetDirectories(localPath);
foreach (var dir in directories)
{
var dirInfo = new DirectoryInfo(dir);
var subPath = CombineRemotePath(remotePath, dirInfo.Name);
items.Add(new
{
name = dirInfo.Name,
type = "directory",
path = subPath,
created = dirInfo.CreationTime,
modified = dirInfo.LastWriteTime,
isPreviewable = false
});
}
var files = Directory.GetFiles(localPath);
foreach (var file in files)
{
var fileInfo = new FileInfo(file);
var filePath = CombineRemotePath(remotePath, fileInfo.Name);
var extension = fileInfo.Extension.ToLowerInvariant();
items.Add(new
{
name = fileInfo.Name,
type = "file",
path = filePath,
size = fileInfo.Length,
extension = fileInfo.Extension,
created = fileInfo.CreationTime,
modified = fileInfo.LastWriteTime,
isPreviewable = IsPreviewableFile(extension),
contentType = GetContentType(fileInfo.Name)
});
}
var result = new
{
success = true,
type = "directory",
path = remotePath,
items = items.OrderBy(x => ((dynamic)x).type == "directory" ? 0 : 1)
.ThenBy(x => ((dynamic)x).name)
.ToList()
};
return Ok(result);
}
catch (Exception ex)
{
return Ok(new { success = false, message = $"读取目录失败: {ex.Message}" });
}
}
private IHttpActionResult GetDirectoryContentsRemote(string remotePath)
{
try
{
using (var session = OpenSftp())
{
var dir = session.ListDirectory(remotePath);
var items = new List<object>();
foreach (var subdir in dir.Files.Where(e => e.IsDirectory && e.Name != "." && e.Name != ".."))
{
var subPath = CombineRemotePath(remotePath, subdir.Name);
items.Add(new
{
name = subdir.Name,
type = "directory",
path = subPath,
created = subdir.LastWriteTime,
modified = subdir.LastWriteTime,
isPreviewable = false
});
}
foreach (var file in dir.Files.Where(e => !e.IsDirectory))
{
var filePath = CombineRemotePath(remotePath, file.Name);
var extension = Path.GetExtension(file.Name).ToLowerInvariant();
items.Add(new
{
name = file.Name,
type = "file",
path = filePath,
size = file.Length,
extension = Path.GetExtension(file.Name),
created = file.LastWriteTime,
modified = file.LastWriteTime,
isPreviewable = IsPreviewableFile(extension),
contentType = GetContentType(file.Name)
});
}
var result = new
{
success = true,
type = "directory",
path = remotePath,
items = items.OrderBy(x => ((dynamic)x).type == "directory" ? 0 : 1)
.ThenBy(x => ((dynamic)x).name)
.ToList()
};
return Ok(result);
}
}
catch (Exception ex)
{
return Ok(new { success = false, message = $"读取远程目录失败: {ex.Message}" });
}
}
private bool DownloadFileFromSftp(string remotePath, string localPath, out string error)
{
error = null;
try
{
var localDir = Path.GetDirectoryName(localPath);
if (!Directory.Exists(localDir)) Directory.CreateDirectory(localDir);
using (var session = OpenSftp())
{
var result = session.GetFiles(remotePath, localPath, false);
result.Check();
}
return true;
}
catch (Exception ex)
{
error = ex.Message;
return false;
}
}
private Session OpenSftp()
{
var options = new SessionOptions
{
Protocol = Protocol.Sftp,
HostName = _sftpHost,
UserName = _sftpUser,
Password = _sftpPassword,
SshHostKeyPolicy = SshHostKeyPolicy.GiveUpSecurityAndAcceptAny
};
var session = new Session();
session.Open(options);
return session;
}
private void EnsureCacheRoot()
{
if (!Directory.Exists(_cacheRoot)) Directory.CreateDirectory(_cacheRoot);
}
private string NormalizeRemotePath(string p)
{
if (string.IsNullOrWhiteSpace(p)) return "/";
var s = p.Trim();
// 统一使用正斜杠
s = s.Replace('\\', '/');
return s;
}
private string ToLocalPath(string remotePath)
{
// 去掉开头的 '/'
var relative = remotePath.Trim().TrimStart('/');
var localRelative = relative.Replace('/', Path.DirectorySeparatorChar);
return Path.Combine(_cacheRoot, localRelative);
}
private string CombineRemotePath(string basePath, string name)
{
if (string.IsNullOrEmpty(basePath) || basePath == "/") return $"/{name}";
if (basePath.EndsWith("/")) return basePath + name;
return basePath + "/" + name;
}
private bool IsPreviewableFile(string extension)
{
var previewableExtensions = new[]
{
".bmp", ".jpg", ".jpeg", ".png", ".gif", ".tiff", ".tif", ".webp",
".txt", ".json", ".xml", ".csv", ".log", ".md", ".pdf"
};
return previewableExtensions.Contains(extension);
}
private string GetContentType(string fileName)
{
var extension = Path.GetExtension(fileName).ToLowerInvariant();
if (extension == ".bmp") return "image/bmp";
if (extension == ".jpg" || extension == ".jpeg") return "image/jpeg";
if (extension == ".png") return "image/png";
if (extension == ".gif") return "image/gif";
if (extension == ".tiff" || extension == ".tif") return "image/tiff";
if (extension == ".webp") return "image/webp";
if (extension == ".pdf") return "application/pdf";
if (extension == ".txt") return "text/plain";
if (extension == ".json") return "application/json";
if (extension == ".xml") return "application/xml";
if (extension == ".csv") return "text/csv";
if (extension == ".md") return "text/markdown";
if (extension == ".log") return "text/plain";
if (extension == ".zip") return "application/zip";
if (extension == ".rar") return "application/x-rar-compressed";
return "application/octet-stream";
}
}
}

View File

@@ -0,0 +1,277 @@
using System.Net.Http;
using System.Net;
using System.Web.Http;
using Newtonsoft.Json.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System;
/////http://127.0.0.1:9981/api/file/browse
/// <summary>
///
/// </summary>
namespace WebApi
{
/// <summary>
///
/// </summary>
[RoutePrefix("api/file")]
public class IFileController : ApiController
{
// 基础路径配置
private readonly string _basePath = @"D:\CameraImg";
/// <summary>
/// 请求DTO
/// </summary>
public class FileRequestDto
{
public string RelativePath { get; set; } = "";
}
/// <summary>
/// 浏览文件或文件夹,前端传相对路径,返回文件夹内容或文件流(图片等可预览)
/// </summary>
[HttpPost]
[Route("browse")]
public IHttpActionResult BrowsePath([FromBody] FileRequestDto request)
{
try
{
if (request == null)
request = new FileRequestDto();
if (string.IsNullOrEmpty(request.RelativePath) || request.RelativePath == "/")
{
request.RelativePath = "";
}
string fullPath = Path.Combine(_basePath, request.RelativePath.Replace('/', Path.DirectorySeparatorChar));
if (!IsPathSafe(fullPath))
{
return Ok(new { success = false, message = "无效的路径" });
}
if (!Directory.Exists(fullPath) && !System.IO.File.Exists(fullPath))
{
return Ok(new { success = false, message = "路径不存在" });
}
if (System.IO.File.Exists(fullPath))
{
return GetFilePreview(fullPath, request.RelativePath);
}
if (Directory.Exists(fullPath))
{
return GetDirectoryContents(fullPath, request.RelativePath);
}
return Ok(new { success = false, message = "路径不存在" });
}
catch (Exception ex)
{
return Ok(new { success = false, message = $"服务器错误: {ex.Message}" });
}
}
/// <summary>
/// 获取文件预览数据(图片/文本base64前端可直接预览
/// </summary>
private IHttpActionResult GetFilePreview(string fullPath, string relativePath)
{
try
{
var fileInfo = new FileInfo(fullPath);
var extension = fileInfo.Extension.ToLowerInvariant();
var previewable = IsPreviewableFile(extension);
var contentType = GetContentType(fileInfo.Name);
bool tooLarge = fileInfo.Length > 10 * 1024 * 1024; // 10MB限制
string base64String = null;
string dataUrl = null;
bool canPreview = previewable && !tooLarge;
if (canPreview)
{
var fileBytes = System.IO.File.ReadAllBytes(fullPath);
base64String = Convert.ToBase64String(fileBytes);
dataUrl = $"data:{contentType};base64,{base64String}";
}
var result = new
{
success = true,
type = "file",
path = relativePath,
name = fileInfo.Name,
size = fileInfo.Length,
extension = fileInfo.Extension,
contentType = contentType,
isPreviewable = canPreview,
base64Data = base64String,
dataUrl = dataUrl,
created = fileInfo.CreationTime,
modified = fileInfo.LastWriteTime,
message = tooLarge ? "文件过大,无法预览,可下载" : null
};
return Ok(result);
}
catch (Exception ex)
{
return Ok(new { success = false, message = $"获取文件预览失败: {ex.Message}" });
}
}
/// <summary>
/// 判断文件是否可预览
/// </summary>
private bool IsPreviewableFile(string extension)
{
var previewableExtensions = new[]
{
".bmp", ".jpg", ".jpeg", ".png", ".gif", ".tiff", ".tif", ".webp",
".txt", ".json", ".xml", ".csv", ".log", ".md"
};
return previewableExtensions.Contains(extension);
}
/// <summary>
/// 安全检查:确保路径在基础目录内,防止路径遍历攻击
/// </summary>
private bool IsPathSafe(string fullPath)
{
try
{
var basePath = Path.GetFullPath(_basePath);
var requestedPath = Path.GetFullPath(fullPath);
return requestedPath.StartsWith(basePath, StringComparison.OrdinalIgnoreCase);
}
catch
{
return false;
}
}
/// <summary>
/// 根据文件扩展名获取MIME类型兼容C# 7.3
/// </summary>
private string GetContentType(string fileName)
{
var extension = Path.GetExtension(fileName).ToLowerInvariant();
if (extension == ".bmp") return "image/bmp";
if (extension == ".jpg" || extension == ".jpeg") return "image/jpeg";
if (extension == ".png") return "image/png";
if (extension == ".gif") return "image/gif";
if (extension == ".tiff" || extension == ".tif") return "image/tiff";
if (extension == ".webp") return "image/webp";
if (extension == ".pdf") return "application/pdf";
if (extension == ".txt") return "text/plain";
if (extension == ".json") return "application/json";
if (extension == ".xml") return "application/xml";
if (extension == ".csv") return "text/csv";
if (extension == ".md") return "text/markdown";
if (extension == ".log") return "text/plain";
if (extension == ".zip") return "application/zip";
if (extension == ".rar") return "application/x-rar-compressed";
return "application/octet-stream";
}
private IHttpActionResult GetDirectoryContents(string fullPath, string relativePath)
{
try
{
var items = new List<object>();
var directories = Directory.GetDirectories(fullPath);
foreach (var dir in directories)
{
var dirInfo = new DirectoryInfo(dir);
var subPath = string.IsNullOrEmpty(relativePath)
? dirInfo.Name
: $"{relativePath}/{dirInfo.Name}";
items.Add(new
{
name = dirInfo.Name,
type = "directory",
path = subPath,
created = dirInfo.CreationTime,
modified = dirInfo.LastWriteTime,
isPreviewable = false
});
}
var files = Directory.GetFiles(fullPath);
foreach (var file in files)
{
var fileInfo = new FileInfo(file);
var filePath = string.IsNullOrEmpty(relativePath)
? fileInfo.Name
: $"{relativePath}/{fileInfo.Name}";
var extension = fileInfo.Extension.ToLowerInvariant();
items.Add(new
{
name = fileInfo.Name,
type = "file",
path = filePath,
size = fileInfo.Length,
extension = fileInfo.Extension,
created = fileInfo.CreationTime,
modified = fileInfo.LastWriteTime,
isPreviewable = IsPreviewableFile(extension),
contentType = GetContentType(fileInfo.Name)
});
}
var result = new
{
success = true,
type = "directory",
path = relativePath,
items = items.OrderBy(x => ((dynamic)x).type == "directory" ? 0 : 1)
.ThenBy(x => ((dynamic)x).name)
.ToList()
};
return Ok(result);
}
catch (Exception ex)
{
return Ok(new { success = false, message = $"读取目录失败: {ex.Message}" });
}
}
[HttpPost]
[Route("download")]
public IHttpActionResult DownloadFile([FromBody] FileRequestDto request)
{
try
{
if (request == null || string.IsNullOrEmpty(request.RelativePath))
return Ok(new { success = false, message = "文件路径不能为空" });
string fullPath = Path.Combine(_basePath, request.RelativePath.Replace('/', Path.DirectorySeparatorChar));
if (!IsPathSafe(fullPath) || !System.IO.File.Exists(fullPath))
return Ok(new { success = false, message = "文件不存在" });
var fileInfo = new FileInfo(fullPath);
var contentType = GetContentType(fileInfo.Name);
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StreamContent(new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.Read))
};
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType);
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = fileInfo.Name
};
return ResponseMessage(response);
}
catch (Exception ex)
{
return Ok(new { success = false, message = $"下载文件失败: {ex.Message}" });
}
}
}
}

View File

@@ -0,0 +1,252 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Web;
using System.Web.Http;
using System.Collections.Concurrent;
using Newtonsoft.Json.Linq;
using System.Threading;
using PLMTEST;
using System.Net;
using System.Net.Http.Headers;
using System.IO;
using MisDataSaveDate;
/////http://127.0.0.1:9981/api/IOrder/InsertOrder
/// <summary>
///
/// </summary>
namespace WebApi
{
/// <summary>
///
/// </summary>
public class MomController : ApiController
{
readonly string headUrl = "/";
/// <summary>
/// 工艺信息接口
/// </summary>
/// <param name="jobj"></param>
/// <returns></returns>
[HttpPost]
[Route("ProcessInfo")]
public HttpResponseMessage ProcessInfo([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(AnalysisMomMsg.ProcessInfo(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// 生产任务接口
/// </summary>
/// <param name="jobj"></param>
/// <returns></returns>
[HttpPost]
[Route("DispatchOrder")]
public HttpResponseMessage DispatchOrder([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(AnalysisMomMsg.DispatchOrder(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// 生产工单接口
/// </summary>
/// <param name="jobj"></param>
/// <returns></returns>
[HttpPost]
[Route("ProductionOrder")]
public HttpResponseMessage ProductionOrder([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(AnalysisMomMsg.ProductionOrder(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// 员工信息下发接口
/// </summary>
/// <param name="jobj"></param>
/// <returns></returns>
[HttpPost]
[Route("EmployeeSave")]
public HttpResponseMessage EmployeeSave([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(AnalysisMomMsg.MES_To_AMS_Employee(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// 生产组织信息下发
/// </summary>
/// <param name="jobj"></param>
/// <returns></returns>
[HttpPost]
[Route("OrgInfoSave")]
public HttpResponseMessage OrgInfoSave([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(AnalysisMomMsg.MES_To_AMS_OrgInfo(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// 工作中心信息下发
/// </summary>
/// <param name="jobj"></param>
/// <returns></returns>
[HttpPost]
[Route("WorkCenterSave")]
public HttpResponseMessage WorkCenterSave([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(AnalysisMomMsg.MES_To_AMS_WorkCenterSave(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// 物料信息下发
/// </summary>
/// <param name="jobj"></param>
/// <returns></returns>
[HttpPost]
[Route("MaterialSave")]
public HttpResponseMessage MaterialSave([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(AnalysisMomMsg.MES_To_AMS_MaterialSave(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// 计量单位下发
/// </summary>
/// <param name="jobj"></param>
/// <returns></returns>
[HttpPost]
[Route("UnitInfoSave")]
public HttpResponseMessage UnitInfoSave([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(AnalysisMomMsg.MES_To_AMS_UnitInfoSave(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// 员工排班信息下发
/// </summary>
/// <param name="jobj"></param>
/// <returns></returns>
[HttpPost]
[Route("ShiftScheduleSave")]
public HttpResponseMessage ShiftScheduleSave([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(AnalysisMomMsg.MES_To_AMS_ShiftScheduleSave(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// 报警关闭
/// </summary>
/// <param name="jobj"></param>
/// <returns></returns>
[HttpPost]
[Route("AlarmClosed")]
public HttpResponseMessage AlarmClosed([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(AnalysisMomMsg.MES_To_AMS_AlarmClosed(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// AGV送料交互接口
/// </summary>
/// <param name="jobj"></param>
/// <returns></returns>
[HttpPost]
[Route("AGV_To_AMS_InterAction")]
public HttpResponseMessage AGV_To_AMS_InterAction([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(AnalysisMomMsg.AGV_To_AMS_Interaction(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// 缓存位置查询
/// </summary>
/// <param name="jobj"></param>
/// <returns></returns>
[HttpPost]
[Route("LineSideStock")]
public HttpResponseMessage LineSideStock([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(AnalysisMomMsg.AGV_To_AMS_LineSideStock(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// 点检计划下发
/// </summary>
/// <param name="jobj"></param>
/// <returns></returns>
[HttpPost]
[Route("InspectionPlan")]
public HttpResponseMessage InspectionPlan([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(AnalysisMomMsg.InspectionPlan(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
[HttpPost]
[Route("QTTemplateInfo")]
public HttpResponseMessage QTTemplateInfo([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(AnalysisMomMsg.QTItemTemplateInfo(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
[HttpPost]
[Route("QTStandardInfo")]
public HttpResponseMessage QTStandardInfo([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(AnalysisMomMsg.QTStandardInfo(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// 删除派工订单接口
/// </summary>
/// <param name="jobj"></param>
/// <returns></returns>
[HttpPost]
[Route("DeleteDispatchOrder")]
public HttpResponseMessage DeleteDispatchOrder([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(AnalysisMomMsg.DeleteDispatchOrder(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
}
}

View File

@@ -0,0 +1,134 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Web;
using System.Web.Http;
using System.Collections.Concurrent;
using Newtonsoft.Json.Linq;
using System.Threading;
using System.Net;
using System.Net.Http.Headers;
using System.IO;
using MisDataSaveDate;
using WebApi;
namespace MisDataSaveDate
{
/// <summary>
/// AGV接口控制器
/// </summary>
public class WebController : ApiController
{
readonly string headUrl = "/";
/// <summary>
/// AGV请求进入接口接收方
/// 接收AGV的进入请求并存储到数据库
/// </summary>
/// <param name="jobj">AGV请求数据</param>
/// <returns>处理结果</returns>
[HttpPost]
[Route("web/WEB_Request")]
public HttpResponseMessage WEB_Request([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(WEB_BusinessLogic.WEB_Request(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// AGV请求进入接口接收方
/// 接收AGV的进入请求并存储到数据库
/// </summary>
/// <param name="jobj">AGV请求数据</param>
/// <returns>处理结果</returns>
[HttpPost]
[Route("web/WEB_SpotCheckResultUpload")]
public HttpResponseMessage WEB_SpotCheckResultUpload([FromBody] SpotCheckResult request)
{
var result = new MsgResHeader<object>
{
code = 200,
message = "",
Data = null
};
try
{
if (request == null)
{
throw new Exception("请求体不能为空");
}
var response = CALL_Inerface_DataHandle.CALL_Inerface_SpotCheckResultUpload(request);
int.TryParse(response["code"]?.ToString() ?? "500", out int remoteCode);
result.code = remoteCode;
result.message = response["message"]?.ToString() ?? "";
result.Data = response["data"];
}
catch (Exception ex)
{
result.code = 500;
result.message = ex.Message;
}
return new HttpResponseMessage
{
Content = new StringContent(JsonConvert.SerializeObject(result), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// 磨合转序接口
/// 调用AGV转序接口成功后执行转序存储过程
/// </summary>
/// <param name="jobj">转序请求数据</param>
/// <returns>处理结果</returns>
[HttpPost]
[Route("web/WEB_RunningInTransfer")]
public HttpResponseMessage WEB_RunningInTransfer([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(WEB_BusinessLogic.WEB_RunningInTransfer(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// 批量读取PLC点位值接口
/// 前端传递TagTypeCodeID数组和工位号返回对应点位的值
/// </summary>
/// <param name="jobj">请求数据包含OpName和TagTypeCodeIDs数组</param>
/// <returns>返回对应TagTypeCodeID的值列表</returns>
[HttpPost]
[Route("web/WEB_ReadPLCValues")]
public HttpResponseMessage WEB_ReadPLCValues([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(WEB_BusinessLogic.WEB_ReadPLCValues(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
/// <summary>
/// 写入PLC接口
/// 前端传递TagTypeCodeID、工位号和值写入到PLC
/// </summary>
/// <param name="jobj">请求数据包含TagTypeCodeID、OpName和TagValue</param>
/// <returns>写入结果</returns>
[HttpPost]
[Route("web/WEB_WritePLC")]
public HttpResponseMessage WEB_WritePLC([FromBody] JObject jobj)
{
return new HttpResponseMessage
{
Content = new StringContent(WEB_BusinessLogic.WEB_WritePLC(headUrl + System.Reflection.MethodBase.GetCurrentMethod().Name, jobj), Encoding.GetEncoding("UTF-8"), "application/json")
};
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,919 @@
using DataLinkMesWork;
using MesServerWork;
using MisDataFunDll;
using MisDataSaveDate.MOM;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NPOI.HSSF.Record.Chart;
using NPOI.SS.Formula.Functions;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using static MisDataSaveDate.Helper.ApiLogHelper;
using MisDataSaveDate.Helper;
namespace WebApi
{
public class CALL_Inerface_DataHandle
{
/// <summary>
/// 开工(工序)
/// </summary>
/// <param name="OpName"></param>
/// <param name="EngineID"></param>
/// <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")
{
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)
};
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("CallWebApi_FactoryMes_JobStart", ref param, out DataTable dt, out string errorMessage);
if (dt.Rows.Count > 0)
{
JobStart ReqEntity = new JobStart
{
//orderID = dt.Rows[0]["订单ID"].ToString(),
taskID = dt.Rows[0]["任务ID"].ToString(),
processId = dt.Rows[0]["工序ID"].ToString(),
operationTime = DateTime.Now.ToString(),
createTime = DateTime.Now.ToString(),
lastModifiedTime = DateTime.Now.ToString(),
operation = "1" //0取消1开工
};
string lineType = ConfigurationManager.AppSettings["WebapiPostHeader_Systemcode"];
if (lineType == "MES_ZHDQ_126GLKG") ReqEntity.operatorName = "AC09MES";
if (lineType == "MES_ZHDQ_126DLQ") ReqEntity.operatorName = "AC06MES";
if (lineType == "MES_ZHDQ_126ZZ") ReqEntity.operatorName = "AC11MES";
if (OpName == "AC2401") ReqEntity.operatorName = "AC24MES";
string InterfaceUrl = ConfigurationManager.AppSettings["CallWebApiUrl_ProcessJobStart"];
var result = CALL_Interface_WebAPI.CALL_WebApi_JobStart(InterfaceUrl, ReqEntity);
//保存日志
SaveLog_Interface_Request("CALL_WebApi_JobStart", 1, JsonConvert.SerializeObject(ReqEntity), out int AID);
SaveLog_Interface_Response(result.ToString(), AID);
//当上报失败时,保存上报内容至缓存表
bool reqIsOk = true;
if (result["code"].ToString() != "200")
{
MisDataFun.CallWebApi_FactoryMes_NGRecordSave("CALL_WebApi_JobStart", AID, InterfaceUrl, JsonConvert.SerializeObject(ReqEntity), result.ToString());
// 设置报工状态
reqIsOk = false;
SaveMesLog(OpName, $"工序开工上报失败:订单号={OrderForm}, 工件编号={EngineID}, 返回码={result["code"]}, 消息={result["message"]}", MesLogType.ERROR);
}
else
{
SaveMesLog(OpName, $"工序开工上报成功:订单号={OrderForm}, 工件编号={EngineID}", MesLogType.INFO);
}
// 保存报工状态
MisDataFun.IOT_Data_UpLode_Res_Save(OpName, OrderForm, EngineID, "开工", reqIsOk, result.ToString());
}
else
{
SaveLog_Interface_Request("CallWebApi_FactoryMes_JobStart", 1, $"查询记录数为0订单号={OrderForm},工序号={OpName},产品流水号={EngineID}", out int AID);
SaveMesLog(OpName, $"工序开工查询记录数为0订单号={OrderForm}, 工件编号={EngineID}", MesLogType.WARNING);
}
}
/// <summary>
/// 完工
/// </summary>
/// <param name="OpName"></param>
/// <param name="EngineID"></param>
/// <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")
{
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)
};
//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 最后修改时间
if (ds.Tables[0].Rows.Count > 0)
{
//1、工单信息
DataRow orderRow = ds.Tables[0].Rows[0];
JobFinished ReqEntity = new JobFinished
{
//orderID = orderRow["订单ID"].ToString(),
taskID = orderRow["任务ID"].ToString(),
processNo = orderRow["工序编号"].ToString(),
beat = decimal.Parse(orderRow["节拍"].ToString()),
finishedQuantity = 1.0M,//完工数量
createTime = orderRow["开工时间"].ToString(),
endTime = orderRow["结束时间"].ToString(),
lastModifiedTime = DateTime.Now.ToString(),
};
//2、检验信息根据质量数据和检验模板生成
if (ds.Tables[1].Rows.Count > 0)
{
var qualityOK = ds.Tables[1].Rows[0]["是否合格"].ToString();
var OKCount = qualityOK == "1" ? 1.0M : 0.0M;
var NGCount = qualityOK == "1" ? 0.0M : 1.0M;
List<InspectionInfo> inspInfoList = new List<InspectionInfo>();
InspectionInfo inspInfo = new InspectionInfo();
string lineType = ConfigurationManager.AppSettings["WebapiPostHeader_Systemcode"];
if (lineType == "MES_ZHDQ_126GLKG") inspInfo.inspector = "AC09MES";
if (lineType == "MES_ZHDQ_126DLQ") inspInfo.inspector = "AC06MES";
if (lineType == "MES_ZHDQ_126ZZ") inspInfo.inspector = "AC11MES";
if (OpName == "AC2401") inspInfo.inspector = "AC24MES";
inspInfo.qualifiedQuantity = OKCount;
inspInfo.unqualifiedQuantity = NGCount;
inspInfo.inspectionTime = DateTime.Now.ToString();
List<InspectionDetail> inspectionDetails = new List<InspectionDetail>();
foreach (DataRow inspRow in ds.Tables[1].Rows)
{
InspectionDetail inspectionDetail = new InspectionDetail();
var qualityOKStr = "";
string TagValue = inspRow["TagValue"].ToString();
if (inspRow["检测结果"].ToString() == "1") qualityOKStr = "合格";
else qualityOKStr = inspRow["检测结果"].ToString() == "0" ? "未测量" : "不合格";
// 合格项目 使用 合格不合格
if (inspRow["测量单位"]?.ToString() == "OK/NG")
{
switch (TagValue?.ToString())
{
case ("1"):
TagValue = "合格";
break;
case ("2"):
TagValue = "不合格";
break;
case ("0"):
TagValue = "未测量";
break;
default:
TagValue = "未知";
break;
}
}
//inspectionDetail.inspectionItemName = inspRow["质检项目名称"].ToString();
inspectionDetail.inspectionItemName = inspRow["质检项目名称"].ToString();
inspectionDetail.inspectionValue = TagValue;
inspectionDetail.inspectionResult = qualityOKStr;
inspectionDetail.upperLimitValue = Convert.ToDecimal(inspRow["上限值"]);
inspectionDetail.lowerLimitValue = Convert.ToDecimal(inspRow["下限值"]);
inspectionDetail.standardValue = Convert.ToDecimal(inspRow["理论值"]);
inspectionDetail.upperLimitSymbol = inspRow["测量单位"].ToString();
inspectionDetail.lowerLimitSymbol = inspRow["测量单位"].ToString();
inspInfo.templetecode = inspRow["模板编号"].ToString();
inspectionDetail.inspectionItemID = inspRow["检验项目ID"].ToString();
inspectionDetail.inspectionItemNo = inspRow["检验项目编号"].ToString();
inspectionDetails.Add(inspectionDetail);
}
inspInfo.inspectionDetails = inspectionDetails;
inspInfoList.Add(inspInfo);
ReqEntity.inspectionInfo = inspInfoList;
}
List<MaterialInfo> materialInfoList = new List<MaterialInfo>();
//3、消耗物料信息
if (ds.Tables[2].Rows.Count > 0)
{
foreach (DataRow MRow in ds.Tables[2].Rows)
{
MaterialInfo materialInfo = new MaterialInfo();
materialInfo.consumedMaterialNo = MRow["物料编号"].ToString();
materialInfo.type = "0";
materialInfo.qty = decimal.Parse(MRow["数量"].ToString());
materialInfo.batchNo = MRow["批次号"].ToString();
materialInfoList.Add(materialInfo);
}
}
// 最后再记录一条产出
MaterialInfo materialInfo2 = new MaterialInfo();
materialInfo2.consumedMaterialNo = orderRow["产品编号"].ToString();
materialInfo2.serialNo = EngineID;
materialInfo2.type = "1";
materialInfo2.qty = 1;
materialInfo2.batchNo = "";
materialInfoList.Add(materialInfo2);
ReqEntity.materialInfo = materialInfoList;
//4、工时信息
List<Workinghours> workinghoursList = new List<Workinghours>();
Workinghours workinghours = new Workinghours();
workinghours.workingHours = Math.Round(ReqEntity.beat / 3600, 2);//将秒换算成小时
workinghours.quantity = 1.0M;
workinghours.operation = "1";//默认1完工 0 取消完工 1 完工
workinghoursList.Add(workinghours);
ReqEntity.workinghours = workinghoursList;
string InterfaceUrl = ConfigurationManager.AppSettings["CallWebApiUrl_ProcessJobFinish"];
var result = CALL_Interface_WebAPI.CALL_WebApi_JobFinished(InterfaceUrl, ReqEntity);
SaveLog_Interface_Request("CALL_WebApi_JobFinish", 1, JsonConvert.SerializeObject(ReqEntity), out int AID);
SaveLog_Interface_Response(result.ToString(), AID);
bool reqIsOk = true;
//当上报失败时,保存上报内容至缓存表
if (result["code"].ToString() != "200")
{
MisDataFun.CallWebApi_FactoryMes_NGRecordSave("CALL_WebApi_JobFinished", AID, InterfaceUrl, JsonConvert.SerializeObject(ReqEntity), result.ToString());
// 设置报工状态
reqIsOk = false;
SaveMesLog(OpName, $"工序完工上报失败:订单号={OrderForm}, 工件编号={EngineID}, 返回码={result["code"]}, 消息={result["message"]}", MesLogType.ERROR);
}
else
{
SaveMesLog(OpName, $"工序完工上报成功:订单号={OrderForm}, 工件编号={EngineID}", MesLogType.INFO);
}
// 保存报工状态
MisDataFun.IOT_Data_UpLode_Res_Save(OpName, OrderForm, EngineID, "完工", reqIsOk, result.ToString());
}
else
{
SaveLog_Interface_Request("CallWebApi_FactoryMes_JobFinish", 1, $"查询记录数为0订单号={OrderForm},工序号={OpName},产品流水号={EngineID}", out int AID);
SaveMesLog(OpName, $"工序完工查询记录数为0订单号={OrderForm}, 工件编号={EngineID}", MesLogType.WARNING);
}
}
/// <summary>
/// 产线报警信息上报
/// </summary>
/// <param name="OpName"></param>
/// <param name="TagID"></param>
/// <param name="alarmtype"></param>
/// <param name="alarmContext"></param>
public static void CALL_Inerface_DeviceAlarm(string OpName, string TagID, string alarmtype, string alarmContext)
{
MIS_BASE.Read_EngineGetOver_PLC(OpName, out bool isWorking);
if (!isWorking) return; // 没有产品 则不上传数据
//查询工单ID、任务ID、工序ID
var param = new SqlParameter[] {
new SqlParameter("@工序号",OpName)
};
string orderID = "";
string taskID = "";
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("CallWebApi_FactoryMes_DeviceAlarm", ref param, out DataTable dt, out string errMessage);
if (dt.Rows.Count > 0)
{
orderID = dt.Rows[0]["订单ID"].ToString();
taskID = dt.Rows[0]["任务ID"].ToString();
}
// 非工厂下发的订单产品,不上传报警
if (string.IsNullOrEmpty(orderID) || string.IsNullOrEmpty(taskID)) return;
DeviceAlarm ReqEntity = new DeviceAlarm
{
id = Guid.NewGuid().ToString(),
orderID = orderID,
taskID = taskID,
processNo = OpName,
alarmCode = TagID,
deviceInfo = alarmContext,
exceptionInfo = alarmContext,
exceptionType = alarmtype,
createTime = DateTime.Now.ToString(),
lastModifiedTime = DateTime.Now.ToString()
};
string InterfaceUrl = ConfigurationManager.AppSettings["CallWebApiUrl_AlarmInfoUpload"];
var result = CALL_Interface_WebAPI.CALL_WebApi_DeviceAlarm(InterfaceUrl, ReqEntity);
SaveLog_Interface_Request("CALL_WebApi_DeviceAlarm", 1, JsonConvert.SerializeObject(ReqEntity), out int AID);
SaveLog_Interface_Response(result.ToString(), AID);
//当上报失败时,保存上报内容至缓存表
if (result["code"].ToString() != "200")
{
MisDataFun.CallWebApi_FactoryMes_NGRecordSave("CALL_WebApi_DeviceAlarm", AID, InterfaceUrl, JsonConvert.SerializeObject(ReqEntity), result.ToString());
SaveMesLog(OpName, $"设备报警上报失败:报警代码={TagID}, 报警内容={alarmContext}, 返回码={result["code"]}, 消息={result["message"]}", MesLogType.ERROR);
}
else
{
SaveMesLog(OpName, $"设备报警上报成功:报警代码={TagID}, 报警类型={alarmtype}", MesLogType.INFO);
}
}
/// <summary>
/// 叫料、退料、退空、转序、下空、上空、点对点
/// </summary>
/// <param name="PositionCode"></param>
/// <param name="deliveryType">1退托盘2叫料3送料4转序5下空6上空7点对点</param>
/// <summary>
/// 叫料、退料、退空、转序、下空、上空、点对点
/// </summary>
/// <param name="PositionCode"></param>
/// <param name="deliveryType">1退托盘2叫料3送料4转序5下空6上空7点对点</param>
public static bool CALL_Inerface_CallMaterial(string PositionCode, string deliveryType)
{
// 配送类型映射1退托盘2叫料3送料4转序5下空6上空7点对点
Dictionary<string, string> deliveryTypeMap = new Dictionary<string, string>
{
{ "1", "退托盘" },
{ "2", "叫料" },
{ "3", "送料" },
{ "4", "转序" },
{ "5", "下空" },
{ "6", "上空" },
{ "7", "点对点" }
};
string deliveryTypeName = deliveryTypeMap.ContainsKey(deliveryType) ? deliveryTypeMap[deliveryType] : "未知";
//查询工单ID、任务ID、工序ID
var param = new SqlParameter[] {
new SqlParameter("@位置号",PositionCode),
new SqlParameter("@叫料类型",deliveryType)
};
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("CallWebApi_FactoryMes_CallMaterial", ref param, out DataTable dt, out string errMessage);
if (dt.Rows.Count > 0)
{
string containerNo = "";
if (deliveryType == "1")
{
// 获取器具号318
containerNo = MIS_BASE.ReadPLC(318, PositionCode).ToString();
}
var callMaterialCode = Guid.NewGuid().ToString();
MaterialSend ReqEntity = new MaterialSend
{
code = callMaterialCode,
orderID = dt.Rows[0]["派工单ID"].ToString(),
taskID = dt.Rows[0]["taskId"].ToString(),
sequenceNo = dt.Rows[0]["顺序号"].ToString(),
deliveryType = deliveryType,
processStep = dt.Rows[0]["工序号"].ToString(),
startLocation = (deliveryType == "1" || deliveryType == "3" || deliveryType == "4" || deliveryType == "5" || deliveryType == "7") ? PositionCode : "",
endLocation = (deliveryType == "2" || deliveryType == "6") ? PositionCode : "",
material = dt.Rows[0]["物料号"].ToString(),
quantity = Convert.ToInt32(dt.Rows[0]["数量"]),
trayNumber = containerNo, //dt.Rows[0]["托盘号"].ToString(),
prodline = "", // 产线
workstation = "",
workshop = "",
customerid = "",
creator = "Auto",
createTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
lastModifiedTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
};
string InterfaceUrl = ConfigurationManager.AppSettings["CallWebApiUrl_CallMaterial"];
SaveLog_Interface_Request("CallWebApiUrl_CallMaterial", 1, JsonConvert.SerializeObject(ReqEntity), out int AID);
var result = CALL_Interface_WebAPI.CALL_WebApi_CallMaterial(InterfaceUrl, ReqEntity);
SaveLog_Interface_Response(result.ToString(), AID);
//当上报失败时,保存上报内容至缓存表
if (result["code"].ToString() != "200")
{
var param1 = new SqlParameter[] {
new SqlParameter("@接口名称","CallWebApiUrl_CallMaterial"),
new SqlParameter("@接口地址",InterfaceUrl),
new SqlParameter("@请求内容",JsonConvert.SerializeObject(ReqEntity)),
new SqlParameter("@响应内容",result.ToString())
};
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("CallWebApi_FactoryMes_NGRecordSave", ref param1, out string errMessage1);
SaveMesLog(PositionCode, $"叫料上报失败:配送类型={deliveryType}({deliveryTypeName}), 起始位置={ReqEntity.startLocation}, 终点位置={ReqEntity.endLocation}, 物料号={ReqEntity.material}, 叫料任务号={callMaterialCode}, 返回码={result["code"]}, 消息={result["message"]}", MesLogType.ERROR);
return false;
}
else
{
SaveMesLog(PositionCode, $"叫料上报成功:配送类型={deliveryType}({deliveryTypeName}), 起始位置={ReqEntity.startLocation}, 终点位置={ReqEntity.endLocation}, 物料号={ReqEntity.material}, 叫料任务号={callMaterialCode}", MesLogType.INFO);
}
MisDataFun.Location_MIS_MOBY_Insert(PositionCode, "器具号", ReqEntity.trayNumber);
MisDataFun.Location_MIS_MOBY_Insert(PositionCode, "叫料任务号", callMaterialCode);
MisDataFun.Location_MIS_MOBY_Insert(PositionCode, "派工单ID", dt.Rows[0]["派工单ID"].ToString());
MisDataFun.Location_MIS_MOBY_Insert(PositionCode, "派工任务ID", dt.Rows[0]["taskId"].ToString());
MisDataFun.Location_MIS_MOBY_Insert(PositionCode, "订单号", dt.Rows[0]["订单号"].ToString());
var param2 = new SqlParameter[] {
new SqlParameter("@叫料任务号",ReqEntity.code),
new SqlParameter("@派工单ID",ReqEntity.orderID),
new SqlParameter("@派工任务ID",ReqEntity.taskID),
new SqlParameter("@顺序号",ReqEntity.sequenceNo),
new SqlParameter("@配送类型",ReqEntity.deliveryType),
new SqlParameter("@工序",ReqEntity.processStep),
new SqlParameter("@起始位置编号",ReqEntity.startLocation),
new SqlParameter("@终点位置编号",ReqEntity.endLocation),
new SqlParameter("@配送物料编码",ReqEntity.material),
new SqlParameter("@配送数量",ReqEntity.quantity),
new SqlParameter("@器具号",ReqEntity.trayNumber),
new SqlParameter("@创建人编号",ReqEntity.creator),
new SqlParameter("@创建时间",ReqEntity.createTime),
new SqlParameter("@最后修改时间",ReqEntity.lastModifiedTime),
};
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("MOM_生产任务_派工任务_叫料记录_增加", ref param2, out string errMessage2);
}
else
{
SaveLog_Interface_Request("CallWebApi_FactoryMes_DeviceAlarm", 1, $"查询记录数为0工序号={PositionCode}", out int AID);
SaveMesLog(PositionCode, $"叫料查询记录数为0配送类型={deliveryType}({deliveryTypeName})", MesLogType.WARNING);
return false;
}
return true;
}
/// <summary>
/// 物料配送确认
/// </summary>
/// <param name="PositionCode">位置号</param>
/// <param name="containerNo">器具号</param>
public static bool CALL_Inerface_MaterialConfirm(string PositionCode, string containerNo)
{
try
{
// 调用存储过程获取叫料任务号和派工任务ID
var param = new SqlParameter[] {
new SqlParameter("@位置号", PositionCode),
new SqlParameter("@器具号", containerNo)
};
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("MOM_生产任务_派工任务_叫料记录_到料确认", ref param, out DataTable dtResult, out string errMessage);
if (dtResult == null || dtResult.Rows.Count == 0)
{
SaveLog_Interface_Request("CallWebApiUrl_MaterialInfoConfirm", 0,
$"获取叫料记录失败:位置号={PositionCode}, 器具号={containerNo}, 错误信息={errMessage}", out int errorAID);
SaveMesLog(PositionCode, $"物料配送确认-获取叫料记录失败:器具号={containerNo}, 错误={errMessage}", MesLogType.ERROR);
return false;
}
// 获取存储过程返回的数据
string tackcode = dtResult.Rows[0]["叫料任务号"].ToString();
string taskID = dtResult.Rows[0]["派工任务ID"].ToString();
MaterialConfirm materialConfirm = new MaterialConfirm
{
tackcode = tackcode, // 从存储过程获取的配送任务号
orderID = "", // 派工单ID
taskID = taskID, // 从存储过程获取的派工任务ID
processId = PositionCode, // 工序ID
containerNo = containerNo // 器具号
};
string InterfaceUrl = ConfigurationManager.AppSettings["CallWebApiUrl_MaterialInfoConfirm"];
var result = CALL_Interface_WebAPI.CALL_WebApi_MaterialConfirm(InterfaceUrl, materialConfirm);
SaveLog_Interface_Request("CallWebApiUrl_MaterialInfoConfirm", 1, JsonConvert.SerializeObject(materialConfirm), out int AID);
SaveLog_Interface_Response(result.ToString(), AID);
//当上报失败时,保存上报内容至缓存表
if (result["code"].ToString() != "200")
{
var param1 = new SqlParameter[] {
new SqlParameter("@接口名称","CallWebApiUrl_MaterialInfoConfirm"),
new SqlParameter("@接口地址",InterfaceUrl),
new SqlParameter("@请求内容",JsonConvert.SerializeObject(materialConfirm)),
new SqlParameter("@响应内容",result.ToString())
};
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("CallWebApi_FactoryMes_NGRecordSave", ref param1, out string errMessage1);
SaveMesLog(PositionCode, $"物料配送确认上报失败:器具号={containerNo}, 叫料任务号={tackcode}, 返回码={result["code"]}, 消息={result["message"]}", MesLogType.ERROR);
return false;
}
SaveMesLog(PositionCode, $"物料配送确认上报成功:器具号={containerNo}, 叫料任务号={tackcode}", MesLogType.INFO);
return true;
}
catch (Exception ex)
{
SaveLog_Interface_Request("CallWebApiUrl_MaterialInfoConfirm", 0,
$"物料配送确认异常:{ex.Message}", out int exceptionAID);
SaveMesLog("MOM", $"物料配送确认异常:位置号={PositionCode}, 器具号={containerNo}, 异常={ex.Message}", MesLogType.ERROR);
return false;
}
}
/// <summary>
/// 器具信息查询
/// </summary>
/// <param name="PositionCode">位置号</param>
/// <param name="containerNo">托盘号</param>
/// <returns>器具信息查询结果</returns>
public static DeviceInfoResponse CALL_Inerface_DeviceInfoQuery(string PositionCode, string containerNo)
{
// 通过位置号查询任务号
var param = new SqlParameter[] {
new SqlParameter("@位置号",PositionCode)
};
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("MOM_生产任务_派工任务_叫料记录_器具查询", ref param, out DataTable dt, out string errMessage);
if (dt.Rows.Count > 0)
{
string taskId = dt.Rows[0]["任务号"].ToString();
DeviceInfo deviceInfo = new DeviceInfo
{
id = taskId, // 使用查询出的任务号
callcode = "",
containerNo = containerNo
};
string InterfaceUrl = ConfigurationManager.AppSettings["CallWebApiUrl_DeviceInfoQuery"];
SaveLog_Interface_Request("CallWebApiUrl_DeviceInfoQuery", 1, JsonConvert.SerializeObject(deviceInfo), out int AID);
var result = CALL_Interface_WebAPI.CALL_WebApi_DeviceInfoQuery(InterfaceUrl, deviceInfo);
SaveLog_Interface_Response(result.ToString(), AID);
// 解析返回结果
DeviceInfoResponse response = JsonConvert.DeserializeObject<DeviceInfoResponse>(result.ToString());
//当上报失败时,保存上报内容至缓存表
if (result["code"].ToString() != "200")
{
var param1 = new SqlParameter[] {
new SqlParameter("@接口名称","CallWebApiUrl_DeviceInfoQuery"),
new SqlParameter("@接口地址",InterfaceUrl),
new SqlParameter("@请求内容",JsonConvert.SerializeObject(deviceInfo)),
new SqlParameter("@响应内容",result.ToString())
};
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("CallWebApi_FactoryMes_NGRecordSave", ref param1, out string errMessage1);
SaveMesLog(PositionCode, $"器具信息查询失败:位置号={PositionCode}, 器具号={containerNo}, 任务号={taskId}, 返回码={result["code"]}, 消息={result["message"]}", MesLogType.ERROR);
}
else
{
SaveMesLog(PositionCode, $"器具信息查询成功:位置号={PositionCode}, 器具号={containerNo}, 任务号={taskId}", MesLogType.INFO);
}
return response;
}
else
{
SaveLog_Interface_Request("CALL_Inerface_DeviceInfoQuery", 1, $"查询记录数为0位置号={PositionCode}", out int AID);
// 返回空结果
return new DeviceInfoResponse
{
code = 404,
message = $"查询记录数为0位置号={PositionCode}",
data = null
};
}
}
/// <summary>
/// 物料转序
/// </summary>
/// <param name="startPositionCode">起始位置编号</param>
/// <param name="endPositionCode">终点位置编号</param>
/// <param name="taskType">任务模板编号</param>
/// <param name="dataid">派工任务id</param>
/// <param name="moveTaskType">搬运类型1搬运容器2搬运货架</param>
/// <param name="vehicleStatus">载具类型0-空1-满</param>
/// <returns>返回调用结果 JObject包含 code 和 message</returns>
public static JObject CALL_Inerface_MaterialTransfer(string startPositionCode, string endPositionCode, string taskType = "211", string dataid = "", string moveTaskType = "2", string vehicleStatus = "1")
{
JObject response = new JObject();
try
{
// 构建位置列表
List<PositionInfo> positionList = new List<PositionInfo>
{
new PositionInfo
{
type = "00", // 工位
positionCode = startPositionCode
},
new PositionInfo
{
type = "00", // 工位
positionCode = endPositionCode
}
};
MaterialTransfer ReqEntity = new MaterialTransfer
{
reqCode = Guid.NewGuid().ToString(),
reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
clientCode = "126GIS",
taskType = taskType,
moveTaskType = moveTaskType,
vehicleStatus = vehicleStatus,
positionCodeList = positionList,
dataid = dataid
};
string InterfaceUrl = ConfigurationManager.AppSettings["CallWebApiUrl_MaterialTransfer"];
SaveLog_Interface_Request("CALL_WebApi_MaterialTransfer", 1, JsonConvert.SerializeObject(ReqEntity), out int AID);
var result = CALL_Interface_WebAPI.CALL_WebApi_MaterialTransfer(InterfaceUrl, ReqEntity);
SaveLog_Interface_Response(result.ToString(), AID);
//当上报失败时,保存上报内容至缓存表
if (result["code"].ToString() != "200")
{
var param1 = new SqlParameter[] {
new SqlParameter("@接口名称","CALL_WebApi_MaterialTransfer"),
new SqlParameter("@接口地址",InterfaceUrl),
new SqlParameter("@请求内容",JsonConvert.SerializeObject(ReqEntity)),
new SqlParameter("@响应内容",result.ToString())
};
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("CallWebApi_FactoryMes_NGRecordSave", ref param1, out string errMessage1);
string errorMsg = result["message"]?.ToString() ?? "未知错误";
SaveMesLog("MOM", $"物料转序上报失败:起点={startPositionCode}终点={endPositionCode}, 返回码={result["code"]}, 消息={errorMsg}", MesLogType.ERROR);
response["code"] = result["code"];
response["message"] = errorMsg;
}
else
{
SaveMesLog("MOM", $"物料转序上报成功:起点={startPositionCode}终点={endPositionCode}", MesLogType.INFO);
response["code"] = 200;
response["message"] = "AGV调度成功";
}
}
catch (Exception ex)
{
SaveLog_Interface_Request("CALL_WebApi_MaterialTransfer", 0,
$"物料转序异常:{ex.Message}", out int exceptionAID);
SaveMesLog("MOM", $"物料转序异常:起点={startPositionCode}终点={endPositionCode}, 异常={ex.Message}", MesLogType.ERROR);
response["code"] = 500;
response["message"] = $"物料转序异常:{ex.Message}";
}
return response;
}
/// <summary>
/// 点检结果上传
/// </summary>
/// <param name="reqEntity">点检结果实体</param>
/// <returns>工厂MES响应</returns>
public static JObject CALL_Inerface_SpotCheckResultUpload(SpotCheckResult reqEntity)
{
try
{
if (reqEntity == null)
{
SaveMesLog("MOM", "点检结果上传失败:点检结果不能为空", MesLogType.ERROR);
throw new ArgumentNullException(nameof(reqEntity), "点检结果不能为空");
}
if (reqEntity.ResultData == null || reqEntity.ResultData.Count == 0)
{
SaveMesLog("MOM", "点检结果上传失败:点检结果缺少明细数据", MesLogType.ERROR);
throw new Exception("点检结果缺少明细数据");
}
string interfaceUrl = ConfigurationManager.AppSettings["CallWebApiUrl_SpotCheckRecordCreate"];
if (string.IsNullOrWhiteSpace(interfaceUrl))
{
SaveMesLog("MOM", "点检结果上传失败:未配置 CallWebApiUrl_SpotCheckRecordCreate", MesLogType.ERROR);
throw new Exception("未配置 CallWebApiUrl_SpotCheckRecordCreate");
}
string requestName = "CALL_WebApi_SpotCheckRecordCreate";
string requestBody = JsonConvert.SerializeObject(reqEntity);
SaveLog_Interface_Request(requestName, 1, requestBody, out int AID);
var result = CALL_Interface_WebAPI.CALL_WebApi_SpotCheckRecord(interfaceUrl, reqEntity);
SaveLog_Interface_Response(result.ToString(), AID);
var codeToken = result["code"];
if (codeToken == null || codeToken.ToString() != "200")
{
MisDataFun.CallWebApi_FactoryMes_NGRecordSave(requestName, AID, interfaceUrl, requestBody, result.ToString());
string errorMsg = result["message"]?.ToString() ?? "未知错误";
string code = codeToken?.ToString() ?? "null";
SaveMesLog("MOM", $"点检结果上报失败:返回码={code}, 消息={errorMsg}", MesLogType.ERROR);
}
else
{
SaveMesLog("MOM", "点检结果上报成功", MesLogType.INFO);
}
return result;
}
catch (Exception ex)
{
SaveMesLog("MOM", $"点检结果上传异常:{ex.Message}", MesLogType.ERROR);
throw;
}
}
//#region 西开 AGV 发送方法 (MES -> AGV)
///// <summary>
///// 下发任务给 AGV
///// MES 调用 AGV 接口,下发搬运任务
///// </summary>
///// <param name="requestTaskId">任务唯一ID由调用方生成如 Guid</param>
///// <param name="startPosition">抬货点/取货位置</param>
///// <param name="endPosition">卸货点/目标位置</param>
///// <param name="materialCode">产品编码/物料编码</param>
///// <returns>AGV 响应结果</returns>
//public static JObject CALL_ZZAGV_AddTask(string requestTaskId, string startPosition, string endPosition, string materialCode)
//{
// JObject response = new JObject();
// try
// {
// // 参数校验
// if (string.IsNullOrWhiteSpace(requestTaskId))
// {
// requestTaskId = Guid.NewGuid().ToString();
// }
// if (string.IsNullOrWhiteSpace(startPosition))
// {
// throw new ArgumentException("抬货点(startPosition)不能为空");
// }
// if (string.IsNullOrWhiteSpace(endPosition))
// {
// throw new ArgumentException("卸货点(endPosition)不能为空");
// }
// // 构建请求实体
// var reqEntity = new MisDataSaveDate.ZZAGV_AddTaskRequest
// {
// requestTaskId = requestTaskId,
// startPosition = startPosition,
// endPosition = endPosition,
// materialCode = materialCode ?? ""
// };
// // 获取 AGV 接口地址
// string baseUrl = ConfigurationManager.AppSettings["ZZAGV_BaseUrl"];
// if (string.IsNullOrWhiteSpace(baseUrl))
// {
// throw new Exception("未配置 ZZAGV_BaseUrl");
// }
// string interfaceUrl = baseUrl.TrimEnd('/') + "/api/mes/AddTaskFromMes";
// string jsonStr = JsonConvert.SerializeObject(reqEntity);
// SaveLog_Interface_Request("CALL_ZZAGV_AddTask", 1, jsonStr, out int AID);
// // 发送 HTTP 请求
// string resultStr = "";
// try
// {
// resultStr = WebApi.Post.Post_Auto(interfaceUrl, jsonStr);
// }
// catch (Exception httpEx)
// {
// SaveMesLog("ZZAGV", $"下发任务HTTP请求异常起点={startPosition}, 终点={endPosition}, 异常={httpEx.Message}", MesLogType.ERROR);
// SaveLog_Interface_Response($"HTTP请求异常{httpEx.Message}", AID);
// response["code"] = 500;
// response["desc"] = $"HTTP请求异常{httpEx.Message}";
// response["success"] = false;
// return response;
// }
// SaveLog_Interface_Response(resultStr, AID);
// // 解析响应
// if (string.IsNullOrWhiteSpace(resultStr))
// {
// SaveMesLog("ZZAGV", "下发任务失败AGV返回空响应", MesLogType.ERROR);
// response["code"] = 500;
// response["desc"] = "AGV返回空响应";
// response["success"] = false;
// return response;
// }
// response = JObject.Parse(resultStr);
// // 检查返回码
// string code = response["code"]?.ToString();
// if (code != "0")
// {
// string desc = response["desc"]?.ToString() ?? "未知错误";
// SaveMesLog("ZZAGV", $"下发任务失败任务ID={requestTaskId}, 起点={startPosition}, 终点={endPosition}, 返回码={code}, 消息={desc}", MesLogType.ERROR);
// // 保存失败记录
// MisDataFun.CallWebApi_FactoryMes_NGRecordSave("CALL_ZZAGV_AddTask", AID, interfaceUrl, jsonStr, resultStr);
// }
// else
// {
// SaveMesLog("ZZAGV", $"下发任务成功任务ID={requestTaskId}, 起点={startPosition}, 终点={endPosition}", MesLogType.INFO);
// }
// }
// catch (Exception ex)
// {
// SaveMesLog("ZZAGV", $"下发任务异常:{ex.Message}", MesLogType.ERROR);
// response["code"] = 500;
// response["desc"] = $"异常:{ex.Message}";
// response["success"] = false;
// }
// return response;
//}
///// <summary>
///// 放行 AGV
///// MES 调用 AGV 接口,告知 AGV 可以离开当前位置
///// </summary>
///// <param name="requestId">请求ID</param>
///// <param name="position">当前位置编号</param>
///// <returns>AGV 响应结果</returns>
//public static JObject CALL_ZZAGV_AllowLeave(string requestId, string position)
//{
// JObject response = new JObject();
// try
// {
// // 参数校验
// if (string.IsNullOrWhiteSpace(requestId))
// {
// requestId = Guid.NewGuid().ToString();
// }
// if (string.IsNullOrWhiteSpace(position))
// {
// throw new ArgumentException("位置编号(position)不能为空");
// }
// // 构建请求实体
// var reqEntity = new MisDataSaveDate.ZZAGV_AllowLeaveRequest
// {
// requestId = requestId,
// position = position,
// allowLeave = 1
// };
// // 获取 AGV 接口地址
// string baseUrl = ConfigurationManager.AppSettings["ZZAGV_BaseUrl"];
// if (string.IsNullOrWhiteSpace(baseUrl))
// {
// throw new Exception("未配置 ZZAGV_BaseUrl");
// }
// string interfaceUrl = baseUrl.TrimEnd('/') + "/api/mes/AllowLeave";
// string jsonStr = JsonConvert.SerializeObject(reqEntity);
// SaveLog_Interface_Request("CALL_ZZAGV_AllowLeave", 1, jsonStr, out int AID);
// // 发送 HTTP 请求
// string resultStr = "";
// try
// {
// resultStr = WebApi.Post.Post_Auto(interfaceUrl, jsonStr);
// }
// catch (Exception httpEx)
// {
// SaveMesLog("ZZAGV", $"放行AGV HTTP请求异常位置={position}, 异常={httpEx.Message}", MesLogType.ERROR);
// SaveLog_Interface_Response($"HTTP请求异常{httpEx.Message}", AID);
// response["code"] = 500;
// response["desc"] = $"HTTP请求异常{httpEx.Message}";
// response["success"] = false;
// return response;
// }
// SaveLog_Interface_Response(resultStr, AID);
// // 解析响应
// if (string.IsNullOrWhiteSpace(resultStr))
// {
// SaveMesLog("ZZAGV", "放行AGV失败AGV返回空响应", MesLogType.ERROR);
// response["code"] = 500;
// response["desc"] = "AGV返回空响应";
// response["success"] = false;
// return response;
// }
// response = JObject.Parse(resultStr);
// // 检查返回码
// string code = response["code"]?.ToString();
// if (code != "0")
// {
// string desc = response["desc"]?.ToString() ?? "未知错误";
// SaveMesLog("ZZAGV", $"放行AGV失败请求ID={requestId}, 位置={position}, 返回码={code}, 消息={desc}", MesLogType.ERROR);
// // 保存失败记录
// MisDataFun.CallWebApi_FactoryMes_NGRecordSave("CALL_ZZAGV_AllowLeave", AID, interfaceUrl, jsonStr, resultStr);
// }
// else
// {
// SaveMesLog("ZZAGV", $"放行AGV成功请求ID={requestId}, 位置={position}", MesLogType.INFO);
// }
// }
// catch (Exception ex)
// {
// SaveMesLog("ZZAGV", $"放行AGV异常{ex.Message}", MesLogType.ERROR);
// response["code"] = 500;
// response["desc"] = $"异常:{ex.Message}";
// response["success"] = false;
// }
// return response;
//}
//#endregion
}
}

View File

@@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Newtonsoft.Json.Linq;
using System.Security.Cryptography;
using MisDataSaveDate.MOM;
using Newtonsoft.Json;
using System.Configuration;
using ExternalDataSync;
namespace WebApi
{
public class CALL_Interface_WebAPI
{
public static JObject CALL_WebApi_CallMaterial(string InterfaceUrl, MaterialSend entity_send)
{
//string InterfaceUrl = ConfigurationManager.AppSettings["CallWebApiUrl_CallMaterial"];
string bodydata = JsonConvert.SerializeObject(entity_send);
return Post_WebAPI(InterfaceUrl, bodydata);
}
public static JObject CALL_WebApi_DeviceInfoQuery(string InterfaceUrl, DeviceInfo entity_send)
{
//string InterfaceUrl = ConfigurationManager.AppSettings["CallWebApiUrl_DeviceInfoQuery"];
string bodydata = JsonConvert.SerializeObject(entity_send);
return Post_WebAPI(InterfaceUrl, bodydata);
}
public static JObject CALL_WebApi_MaterialConfirm(string InterfaceUrl, MaterialConfirm entity_send)
{
//var InterfaceUrl = CallWebApiUrl_MaterialInfoConfirm;
//string InterfaceUrl = ConfigurationManager.AppSettings["CallWebApiUrl_MaterialInfoConfirm"];
string bodydata = JsonConvert.SerializeObject(entity_send);
return Post_WebAPI(InterfaceUrl, bodydata);
}
public static JObject CALL_WebApi_JobStart(string InterfaceUrl, JobStart entity_send)
{
//string InterfaceUrl = ConfigurationManager.AppSettings["CallWebApiUrl_ProcessJobStart"];
string bodydata = JsonConvert.SerializeObject(entity_send);
return Post_WebAPI(InterfaceUrl, bodydata);
}
public static JObject CALL_WebApi_DeviceAlarm(string InterfaceUrl, DeviceAlarm entity_send)
{
//var InterfaceUrl = CallWebApiUrl_AlarmInfoUpload;
//string InterfaceUrl = ConfigurationManager.AppSettings["CallWebApiUrl_AlarmInfoUpload"];
string bodydata = JsonConvert.SerializeObject(entity_send);
return Post_WebAPI(InterfaceUrl, bodydata);
}
public static JObject CALL_WebApi_JobFinished(string InterfaceUrl, JobFinished entity_send)
{
//var InterfaceUrl = CallWebApiUrl_ProcessJobFinish;
//string InterfaceUrl = ConfigurationManager.AppSettings["CallWebApiUrl_ProcessJobFinish"];
string bodydata = JsonConvert.SerializeObject(entity_send);
return Post_WebAPI(InterfaceUrl, bodydata);
}
public static JObject CALL_WebApi_FinishedReport(TaskFinish entity_send)
{
//var InterfaceUrl = CallWebApiUrl_TaskFinishedReport;
string InterfaceUrl = ConfigurationManager.AppSettings["CallWebApiUrl_TaskFinishedReport"];
string bodydata = JsonConvert.SerializeObject(entity_send);
return Post_WebAPI(InterfaceUrl, bodydata);
}
public static JObject CALL_WebApi_MaterialTransfer(string InterfaceUrl, MaterialTransfer entity_send)
{
//string InterfaceUrl = ConfigurationManager.AppSettings["CallWebApiUrl_MaterialTransfer"];
string bodydata = JsonConvert.SerializeObject(entity_send);
return Post_WebAPI(InterfaceUrl, bodydata);
}
public static JObject CALL_WebApi_SpotCheckRecord(string InterfaceUrl, SpotCheckResult entity_send)
{
string bodydata = JsonConvert.SerializeObject(entity_send);
return Post_WebAPI(InterfaceUrl, bodydata);
}
public static JObject Post_WebAPI(string WebAPI_Url, string m_msg)
{
try
{
if (StateVariable.online_Mes)
{
return JsonConvert.DeserializeObject<JObject>(WebApi.Post.Post_XK(WebAPI_Url, m_msg));
}
else
{
return JObject.Parse("{\"code\":404,\"离线工作模式,请求暂存。\":\"\",\"data\":{}}");
}
}
catch (Exception ex)
{
return new JObject { { "code", 500 }, { "Message", ex.Message }, { "data", new JObject() } };
}
}
}
}

View File

@@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MisDataSaveDate.Helper
{
/// <summary>
/// MES系统日志类型枚举
/// </summary>
public enum MesLogType
{
/// <summary>
/// 信息日志
/// </summary>
INFO,
/// <summary>
/// 警告日志
/// </summary>
WARNING,
/// <summary>
/// 错误日志
/// </summary>
ERROR
}
public class ApiLogHelper
{
/// <summary>
/// 验证属性值是否有效
/// </summary>
/// <param name="value"></param>
/// <param name="fieldName"></param>
/// <param name="errorMessage"></param>
/// <returns></returns>
public static bool ValidateProperty(object value, string fieldName, out string errorMessage)
{
if (value == null || value.ToString() == "")
{
errorMessage = $"参数{fieldName}值格式不正确";
return false;
}
errorMessage = string.Empty; // 无错误
return true;
}
/// <summary>
/// 非必填项Null值处理
/// </summary>
/// <param name="value"></param>
/// <param name="fieldName"></param>
/// <param name="errorMessage"></param>
/// <returns></returns>
public static string VHandle(string value)
{
return value == null ? "" : value;
}
/// <summary>
///
/// </summary>
/// <param name="url"></param>
/// <param name="type">1. 主动调用接口 2. 被调用接口 </param>
/// <param name="context"></param>
/// <param name="AID"></param>
/// <param name="errorMessage"></param>
public static void SaveLog_Interface_Request(string url, int type, string context, out int AID)
{
//存储日志
var CreateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
var param1 = new SqlParameter[] {
new SqlParameter("@接口地址",url),
new SqlParameter("@接口类型",type),
new SqlParameter("@请求内容",context),
new SqlParameter("@请求时间",CreateTime)
};
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("接口_IOT接口交互日志_请求记录", ref param1, out DataTable dt, out string errorMessage);
AID = int.Parse(dt.Rows[0][0].ToString());
}
/// <summary>
///
/// </summary>
/// <param name="context"></param>
/// <param name="AID"></param>
public static void SaveLog_Interface_Response(string context, int AID)
{
//存储日志
var CreateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
//Event_MOM_Log_Insert,@创建时间,@内容
var param1 = new SqlParameter[] {
new SqlParameter("@响应时间",CreateTime),
new SqlParameter("@响应内容",context),
new SqlParameter("@AID",AID)
};
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("接口_IOT接口交互日志_响应记录", ref param1, out string errorMessage);
}
/// <summary>
/// 保存MES系统日志到数据库
/// </summary>
/// <param name="opName">工位号/模块名称</param>
/// <param name="logText">日志内容</param>
/// <param name="logType">日志类型INFO/WARNING/ERROR</param>
public static void SaveMesLog(string opName, string logText, MesLogType logType = MesLogType.INFO)
{
string logTypeStr = logType.ToString();
var param1 = new SqlParameter[] {
new SqlParameter("@工位号", opName),
new SqlParameter("@日志类型", logTypeStr),
new SqlParameter("@日志文本", logText),
};
try
{
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("MES_系统日志_增加", ref param1, out DataTable dt, out string errorMessage);
// 同时记录到Log4Net
if (logType == MesLogType.ERROR)
{
MyLog4Net.MyLogHelper.Error("MesLog", $"[{opName}] {logText}");
}
else if (logType == MesLogType.WARNING)
{
MyLog4Net.MyLogHelper.Error("MesLog", $"[{opName}] {logText}");
}
else
{
MyLog4Net.MyLogHelper.Info("MesLog", $"[{opName}] {logText}");
}
if (!string.IsNullOrEmpty(errorMessage))
{
MyLog4Net.MyLogHelper.Error("SaveMesLog", $"保存日志到数据库失败:{errorMessage}");
}
}
catch (Exception ex)
{
MyLog4Net.MyLogHelper.Error("SaveMesLog", $"保存日志异常:{ex.Message}");
}
}
}
}

View File

@@ -0,0 +1,361 @@
using MisDataSaveDate;
using MisDataSaveDate.MOM;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
using DataLinkMesWork2;
using static MisDataSaveDate.Helper.ApiLogHelper;
using MisDataFunDll;
namespace ExternalDataSync.MOM
{
public class Other
{
public static string OnlineCheckData(string url, [FromBody] JObject jobj)
{
var result = new OnlineCheckDataResponse();
result.Code = "200";
result.Message = "";
result.MsgId = "";
result.Data = "";
string errorMessage = string.Empty;
if (jobj == null)
{
result.Code = "500";
result.Message = "参数格式不正确!";
string retString1 = JsonConvert.SerializeObject(result);
MyLog4Net.MyLogHelper.Info("接收检测数据_res", retString1);
return retString1;
}
string str = jobj.ToString();
// 存储接口请求日志
SaveLog_Interface_Request(url, 2, str, out int AID);
try
{
OnlineCheckData onlineCheckData = JsonConvert.DeserializeObject<OnlineCheckData>(str);
if (onlineCheckData == null)
{
throw new Exception("请求体反序列化失败!");
}
if (string.IsNullOrWhiteSpace(onlineCheckData.MsgId))
{
throw new Exception("参数MsgId为空");
}
// 设置响应的MsgId带回请求编号
result.MsgId = onlineCheckData.MsgId;
if (string.IsNullOrWhiteSpace(onlineCheckData.OpCode))
{
throw new Exception("参数OpCode为空");
}
if (string.IsNullOrWhiteSpace(onlineCheckData.ProductionCode))
{
throw new Exception("参数ProductionCode为空");
}
if (string.IsNullOrWhiteSpace(onlineCheckData.ScanTime))
{
throw new Exception("参数ScanTime为空");
}
if (string.IsNullOrWhiteSpace(onlineCheckData.CheckPerson))
{
throw new Exception("参数CheckPerson为空");
}
string opName = onlineCheckData.OpCode;
int idTagCf = 0;
SqlParameter[] paramIndex = new SqlParameter[8];
paramIndex[0] = new SqlParameter("@EngineID", onlineCheckData.ProductionCode);
paramIndex[1] = new SqlParameter("@工位号", opName);
paramIndex[2] = new SqlParameter("@操作者工号", onlineCheckData.CheckPerson);
paramIndex[3] = new SqlParameter("@扫码时间", onlineCheckData.ScanTime);
paramIndex[4] = new SqlParameter("@合格标志", onlineCheckData.QualityMark);
paramIndex[5] = new SqlParameter("@完成时间", onlineCheckData.EndTime);
paramIndex[6] = new SqlParameter("@能耗", onlineCheckData.Powerused);
paramIndex[7] = new SqlParameter("@Id_tagCF", SqlDbType.Int)
{
Direction = ParameterDirection.Output
};
DataAccess2.ExecuteStoredProcedure("测量数据合格索引_增加_测试设备", ref paramIndex, out errorMessage);
if (!string.IsNullOrEmpty(errorMessage))
{
throw new Exception(errorMessage);
}
if (paramIndex[7].Value == null || paramIndex[7].Value == DBNull.Value)
{
throw new Exception("测量数据合格索引_增加_测试设备 未返回Id_tagCF");
}
idTagCf = Convert.ToInt32(paramIndex[7].Value);
List<OnlineCheckData_CheckData> detailList = onlineCheckData.CheckData ?? new List<OnlineCheckData_CheckData>();
foreach (var item in detailList)
{
var paramDetail = new SqlParameter[]
{
new SqlParameter("@Id_tagCF", idTagCf),
new SqlParameter("@EngineID", onlineCheckData.ProductionCode),
new SqlParameter("@TagID", item.CheckCode ?? string.Empty),
new SqlParameter("@TagValue", item.CheckValue ?? string.Empty),
new SqlParameter("@IsGoodBad", item.QualityMark),
new SqlParameter("@工位号", opName),
new SqlParameter("@理论值", item.StandardValue ?? string.Empty),
new SqlParameter("@上限值", item.MaxValue ?? string.Empty),
new SqlParameter("@下限值", item.MinValue ?? string.Empty),
new SqlParameter("@测量项目", item.CheckName ?? string.Empty),
new SqlParameter("@测量单位", item.Unit ?? string.Empty)
};
DataAccess2.ExecuteStoredProcedure("测量数据合格_增加_测试设备", ref paramDetail, out errorMessage);
if (!string.IsNullOrEmpty(errorMessage))
{
throw new Exception(errorMessage);
}
}
// 存储到接口表里
MisDataFun.SaveQualityInterfaceData(opName, onlineCheckData.ProductionCode);
}
catch (Exception err)
{
result.Code = "500";
result.Message = err.Message;
}
string retString = JsonConvert.SerializeObject(result);
SaveLog_Interface_Response(retString, AID);
MyLog4Net.MyLogHelper.Info("接收检测数据_res", retString);
return retString;
}
public static string OnlineStatusData(string url, [FromBody] JObject jobj)
{
var result = new MsgResHeader<string>();
result.code = 200;
result.message = "";
result.Data = "";
string errorMessage = string.Empty;
if (jobj == null)
{
result.code = 500;
result.message = "参数格式不正确!";
string retString1 = JsonConvert.SerializeObject(result);
MyLog4Net.MyLogHelper.Info("接收设备状态数据_res", retString1);
return retString1;
}
string str = jobj.ToString();
SaveLog_Interface_Request(url, 2, str, out int AID);
try
{
var statusData = JsonConvert.DeserializeObject<OnlineStatusData>(str);
if (statusData == null)
{
throw new Exception("请求体反序列化失败!");
}
if (string.IsNullOrWhiteSpace(statusData.MsgId))
{
throw new Exception("参数MsgId为空");
}
if (string.IsNullOrWhiteSpace(statusData.DeviceCode))
{
throw new Exception("参数DeviceCode为空");
}
if (string.IsNullOrWhiteSpace(statusData.DataType))
{
throw new Exception("参数DataType为空");
}
if (statusData.CheckData == null || statusData.CheckData.Count == 0)
{
throw new Exception("参数CheckData为空");
}
string dataType = statusData.DataType.ToUpper();
if (dataType == "STATUS")
{
// 设备运行状态监测 - 必填字段校验
string deviceStatus = GetCheckDataValue(statusData.CheckData, "DeviceStatus");
string statusTime = GetCheckDataValue(statusData.CheckData, "StatusTime");
string statusCode = GetCheckDataValue(statusData.CheckData, "StatusCode");
if (string.IsNullOrWhiteSpace(deviceStatus))
{
throw new Exception("设备状态(DeviceStatus)为必填项!");
}
if (string.IsNullOrWhiteSpace(statusTime))
{
throw new Exception("状态时间(StatusTime)为必填项!");
}
if (string.IsNullOrWhiteSpace(statusCode))
{
throw new Exception("状态代码(StatusCode)为必填项!");
}
// 非必填字段
string malfunctionCode = GetCheckDataValue(statusData.CheckData, "MalfunctionCode");
string malfunctionName = GetCheckDataValue(statusData.CheckData, "MalfunctionName");
string malfunctionExplain = GetCheckDataValue(statusData.CheckData, "Malfunctionexplain");
string flag = GetCheckDataValue(statusData.CheckData, "Flag");
string remark = GetCheckDataValue(statusData.CheckData, "Remark");
string alarmRemove = GetCheckDataValue(statusData.CheckData, "alarmRemove");
var param = new SqlParameter[]
{
new SqlParameter("@DeviceCode", statusData.DeviceCode),
new SqlParameter("@DeviceStatus", deviceStatus),
new SqlParameter("@StatusTime", DateTime.Parse(statusTime)),
new SqlParameter("@StatusCode", statusCode),
new SqlParameter("@MalfunctionCode", string.IsNullOrWhiteSpace(malfunctionCode) ? (object)DBNull.Value : malfunctionCode),
new SqlParameter("@MalfunctionName", string.IsNullOrWhiteSpace(malfunctionName) ? (object)DBNull.Value : malfunctionName),
new SqlParameter("@Malfunctionexplain", string.IsNullOrWhiteSpace(malfunctionExplain) ? (object)DBNull.Value : malfunctionExplain),
new SqlParameter("@Flag", string.IsNullOrWhiteSpace(flag) ? (object)DBNull.Value : flag),
new SqlParameter("@Remark", string.IsNullOrWhiteSpace(remark) ? (object)DBNull.Value : remark),
new SqlParameter("@alarmRemove", string.IsNullOrWhiteSpace(alarmRemove) ? (object)DBNull.Value : alarmRemove)
};
DataAccess2.ExecuteStoredProcedure("EquipmentStatus_Backup_TestDeviceAdd", ref param, out errorMessage);
if (!string.IsNullOrEmpty(errorMessage))
{
throw new Exception(errorMessage);
}
}
else if (dataType == "USE")
{
// 设备使用情况记录 - 必填字段校验
string workDate = GetCheckDataValue(statusData.CheckData, "WorkDate");
if (string.IsNullOrWhiteSpace(workDate))
{
throw new Exception("工作日期(WorkDate)为必填项!");
}
// 非必填字段
string onhours = GetCheckDataValue(statusData.CheckData, "Onhours");
string workhours = GetCheckDataValue(statusData.CheckData, "Workhours");
string powerused = GetCheckDataValue(statusData.CheckData, "Powerused");
string flag = GetCheckDataValue(statusData.CheckData, "Flag");
var param = new SqlParameter[]
{
new SqlParameter("@Device", statusData.DeviceCode),
new SqlParameter("@WorkDate", DateTime.Parse(workDate)),
new SqlParameter("@Onhours", string.IsNullOrWhiteSpace(onhours) ? (object)DBNull.Value : double.Parse(onhours)),
new SqlParameter("@Workhours", string.IsNullOrWhiteSpace(workhours) ? (object)DBNull.Value : double.Parse(workhours)),
new SqlParameter("@Powerused", string.IsNullOrWhiteSpace(powerused) ? (object)DBNull.Value : double.Parse(powerused)),
new SqlParameter("@Flag", string.IsNullOrWhiteSpace(flag) ? (object)DBNull.Value : flag)
};
DataAccess2.ExecuteStoredProcedure("EquipmentUse_Backup_TestDeviceAdd", ref param, out errorMessage);
if (!string.IsNullOrEmpty(errorMessage))
{
throw new Exception(errorMessage);
}
}
else
{
throw new Exception($"DataType值不正确只支持Status或Use当前值{statusData.DataType}");
}
}
catch (Exception err)
{
result.code = 500;
result.message = err.Message;
}
string retString = JsonConvert.SerializeObject(result);
SaveLog_Interface_Response(retString, AID);
MyLog4Net.MyLogHelper.Info("接收设备状态数据_res", retString);
return retString;
}
/// <summary>
/// 从CheckData列表中获取指定StatuCode的StatuValue
/// </summary>
private static string GetCheckDataValue(List<OnlineStatusData_CheckData> checkDataList, string statuCode)
{
var item = checkDataList.FirstOrDefault(x => x.StatuCode?.Trim().Equals(statuCode, StringComparison.OrdinalIgnoreCase) == true);
return item?.StatuValue ?? string.Empty;
}
/// <summary>
/// 获取位置待测试产品信息
/// </summary>
public static string GetWaitCheckProductData(string url, [FromBody] JObject jobj)
{
var result = new GetWaitCheckProductDataResponse();
result.Code = "200";
result.Message = "";
result.MsgId = "";
result.Data = new GetWaitCheckProductDataResult();
if (jobj == null)
{
result.Code = "500";
result.Message = "参数格式不正确!";
string retString1 = JsonConvert.SerializeObject(result);
MyLog4Net.MyLogHelper.Info("获取待测产品信息_res", retString1);
return retString1;
}
string str = jobj.ToString();
// 存储接口请求日志
SaveLog_Interface_Request(url, 2, str, out int AID);
try
{
var requestData = JsonConvert.DeserializeObject<GetWaitCheckProductDataRequest>(str);
if (requestData == null)
{
throw new Exception("请求体反序列化失败!");
}
if (string.IsNullOrWhiteSpace(requestData.MsgId))
{
throw new Exception("参数MsgId为空");
}
// 设置响应的MsgId带回请求编号
result.MsgId = requestData.MsgId;
if (string.IsNullOrWhiteSpace(requestData.OpCode))
{
throw new Exception("参数OpCode为空");
}
// TODO: 后续实现查询待测产品逻辑
// 目前固定返回无待测产品
result.Data = new GetWaitCheckProductDataResult
{
ProductionCode = "",
ProductModel = "",
ProductModelCode = 0
};
}
catch (Exception err)
{
result.Code = "500";
result.Message = err.Message;
}
string retString = JsonConvert.SerializeObject(result);
SaveLog_Interface_Response(retString, AID);
MyLog4Net.MyLogHelper.Info("获取待测产品信息_res", retString);
return retString;
}
}
}

View File

@@ -0,0 +1,527 @@
using DataLinkMesWork2;
using MisDataFunDll;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Globalization;
using System.Web.Http;
using static MisDataSaveDate.Helper.ApiLogHelper;
namespace ExternalDataSync.MOM
{
public static class DewPointDataHandler
{
private const string DefaultFlagValue = "0";
public static string OnlineDewPointResultData(string url, [FromBody] JObject jobj)
{
return ExecuteRequest<ResultDataRequest>(url, jobj, "接收露点仪测试结果数据", request =>
{
string msgId = RequireText(request.MsgId, "MsgId");
string deviceCode = RequireText(request.DeviceCode, "DeviceCode");
string testDateText = RequireText(request.TestDate, "TestDate");
if (request.TestItems == null || request.TestItems.Count == 0)
{
throw new Exception("参数TestItems为空");
}
DateTime testDate = ParseDate(testDateText, "TestDate");
DateTime? startTime = CombineDateAndTime(testDate, request.StartTime, "StartTime");
DateTime? endTime = CombineDateAndTime(testDate, request.EndTime, "EndTime");
DateTime actionTime = startTime ?? endTime ?? testDate;
string serialNumber = CleanText(request.SectionNo);
string userNumber = GetDefaultUser(request.UserNumber);
int overallQualityMark = request.IsQualified == false ? 2 : 1;
int idTagCf = SaveMeasurementIndex(serialNumber, deviceCode, userNumber, actionTime, overallQualityMark);
foreach (MeasurementDetail detail in BuildResultDetails(request, overallQualityMark))
{
SaveMeasurementDetail(idTagCf, serialNumber, deviceCode, detail);
}
SaveQualityInterfaceRecord(deviceCode, serialNumber);
return msgId;
});
}
public static string OnlineDewPointTechnologyData(string url, [FromBody] JObject jobj)
{
return ExecuteRequest<TechnologyDataRequest>(url, jobj, "接收露点仪工艺采集数据", request =>
{
string msgId = RequireText(request.MsgId, "MsgId");
string deviceCode = RequireText(request.DeviceCode, "DeviceCode");
string serialNumber = CleanText(request.SerialNumber);
string userNumber = GetDefaultUser(request.UserNumber);
DateTime actionTime = ParseDateTimeOrNow(request.CreateTime, "CreateTime");
int idTagCf = SaveMeasurementIndex(serialNumber, deviceCode, userNumber, actionTime, 1);
foreach (MeasurementDetail detail in BuildTechnologyDetails(request))
{
SaveMeasurementDetail(idTagCf, serialNumber, deviceCode, detail);
}
SaveQualityInterfaceRecord(deviceCode, serialNumber);
return msgId;
});
}
public static string OnlineDewPointUseData(string url, [FromBody] JObject jobj)
{
return ExecuteRequest<EquipmentUseRequest>(url, jobj, "接收露点仪设备使用情况数据", request =>
{
string msgId = RequireText(request.MsgId, "MsgId");
string deviceCode = RequireText(request.DeviceCode, "DeviceCode");
DateTime testDate = ParseDate(RequireText(request.TestDate, "TestDate"), "TestDate");
int? durationMinutes = ParseNullableInt(request.DurationMinutes, "DurationMinutes");
SqlParameter[] parameters = new SqlParameter[]
{
new SqlParameter("@Device", ToDbValue(deviceCode, 50)),
new SqlParameter("@WorkDate", testDate.Date),
new SqlParameter("@Onhours", durationMinutes.HasValue ? (object)durationMinutes.Value : DBNull.Value),
new SqlParameter("@Workhours", durationMinutes.HasValue ? (object)durationMinutes.Value : DBNull.Value),
new SqlParameter("@Powerused", DBNull.Value),
new SqlParameter("@Flag", ToDbValue(CleanText(request.Flag2), 10, DefaultFlagValue))
};
ExecuteStoredProcedureOrThrow("EquipmentUse_Backup_TestDeviceAdd", ref parameters);
return msgId;
});
}
public static string OnlineDewPointStatusData(string url, [FromBody] JObject jobj)
{
return ExecuteRequest<EquipmentStatusRequest>(url, jobj, "接收露点仪设备状态数据", request =>
{
string msgId = RequireText(request.MsgId, "MsgId");
string deviceCode = RequireText(request.DeviceCode, "DeviceCode");
string status = RequireText(request.Status, "Status");
string statusCode = RequireText(request.StatusCode, "StatusCode");
DateTime statusTime = ParseDateTime(RequireText(request.StatusTime, "StatusTime"), "StatusTime");
SqlParameter[] parameters = new SqlParameter[]
{
new SqlParameter("@DeviceCode", ToDbValue(deviceCode, 20)),
new SqlParameter("@DeviceStatus", ToDbValue(status, 10)),
new SqlParameter("@StatusTime", statusTime),
new SqlParameter("@StatusCode", ToDbValue(statusCode, 4)),
new SqlParameter("@MalfunctionCode", ToNullableDbValue(request.FaultInfo == null ? string.Empty : request.FaultInfo.FaultCode, 4)),
new SqlParameter("@MalfunctionName", ToNullableDbValue(request.FaultInfo == null ? string.Empty : request.FaultInfo.FaultName, 40)),
new SqlParameter("@Malfunctionexplain", ToNullableDbValue(request.FaultInfo == null ? string.Empty : request.FaultInfo.FaultDescription, 40)),
new SqlParameter("@Flag", ToDbValue(CleanText(request.Flag3), 1, DefaultFlagValue)),
new SqlParameter("@Remark", DBNull.Value),
new SqlParameter("@alarmRemove", DBNull.Value)
};
ExecuteStoredProcedureOrThrow("EquipmentStatus_Backup_TestDeviceAdd", ref parameters);
return msgId;
});
}
private static string ExecuteRequest<TRequest>(string url, JObject jobj, string logTitle, Func<TRequest, string> executor)
{
OnlineCheckDataResponse result = new OnlineCheckDataResponse
{
Code = "200",
Message = "",
MsgId = "",
Data = ""
};
if (jobj == null)
{
result.Code = "500";
result.Message = "参数格式不正确!";
string invalidText = JsonConvert.SerializeObject(result);
MyLog4Net.MyLogHelper.Info(logTitle + "_res", invalidText);
return invalidText;
}
string requestText = jobj.ToString();
SaveLog_Interface_Request(url, 2, requestText, out int aid);
try
{
TRequest request = JsonConvert.DeserializeObject<TRequest>(requestText);
if (request == null)
{
throw new Exception("请求体反序列化失败!");
}
result.MsgId = executor(request);
}
catch (Exception err)
{
result.Code = "500";
result.Message = err.Message;
}
string responseText = JsonConvert.SerializeObject(result);
SaveLog_Interface_Response(responseText, aid);
MyLog4Net.MyLogHelper.Info(logTitle + "_res", responseText);
return responseText;
}
private static List<MeasurementDetail> BuildResultDetails(ResultDataRequest request, int overallQualityMark)
{
List<MeasurementDetail> details = new List<MeasurementDetail>();
for (int i = 0; i < request.TestItems.Count; i++)
{
ResultTestItem item = request.TestItems[i];
if (item == null)
{
continue;
}
string itemName = RequireText(item.ItemName, "TestItems[" + i + "].ItemName");
details.Add(new MeasurementDetail
{
TagId = itemName,
MeasurementName = itemName,
TagValue = GetTokenText(item.MeasuredValue),
QualityMark = MapQualityMark(item.QualityMark, overallQualityMark),
StandardValue = GetTokenText(item.SpecifiedValue),
Unit = CleanText(item.Unit)
});
}
// Environment 暂时保留字段,但当前不参与入库。
return details;
}
private static List<MeasurementDetail> BuildTechnologyDetails(TechnologyDataRequest request)
{
List<MeasurementDetail> details = new List<MeasurementDetail>();
AddTechnologyDetail(details, "CheckData", request.CheckData);
AddTechnologyDetail(details, "TechnologyData", request.TechnologyData);
if (details.Count == 0)
{
throw new Exception("参数CheckData和TechnologyData均为空");
}
return details;
}
private static void AddTechnologyDetail(List<MeasurementDetail> details, string fieldName, string fieldValue)
{
string value = CleanText(fieldValue);
if (string.IsNullOrWhiteSpace(value))
{
return;
}
details.Add(new MeasurementDetail
{
TagId = fieldName,
MeasurementName = fieldName,
TagValue = value,
QualityMark = 1,
StandardValue = "",
Unit = ""
});
}
private static int SaveMeasurementIndex(string serialNumber, string deviceCode, string userNumber, DateTime actionTime, int qualityMark)
{
SqlParameter[] parameters = new SqlParameter[]
{
new SqlParameter("@EngineID", ToNullableDbValue(serialNumber, 100)),
new SqlParameter("@工位号", ToDbValue(deviceCode, 50)),
new SqlParameter("@操作者工号", ToDbValue(userNumber, 50, "AUTO")),
new SqlParameter("@扫码时间", actionTime),
new SqlParameter("@合格标志", qualityMark),
new SqlParameter("@Id_tagCF", SqlDbType.Int) { Direction = ParameterDirection.Output }
};
ExecuteStoredProcedureOrThrow("测量数据合格索引_增加_测试设备", ref parameters);
if (parameters[5].Value == null || parameters[5].Value == DBNull.Value)
{
throw new Exception("测量数据合格索引_增加_测试设备 未返回Id_tagCF");
}
return Convert.ToInt32(parameters[5].Value);
}
private static void SaveMeasurementDetail(int idTagCf, string serialNumber, string deviceCode, MeasurementDetail detail)
{
SqlParameter[] parameters = new SqlParameter[]
{
new SqlParameter("@Id_tagCF", idTagCf),
new SqlParameter("@EngineID", ToNullableDbValue(serialNumber, 100)),
new SqlParameter("@TagID", ToDbValue(detail.TagId, 50)),
new SqlParameter("@TagValue", ToDbValue(detail.TagValue, 100)),
new SqlParameter("@IsGoodBad", detail.QualityMark),
new SqlParameter("@工位号", ToDbValue(deviceCode, 50)),
new SqlParameter("@理论值", ToDbValue(detail.StandardValue, 50)),
new SqlParameter("@上限值", ToDbValue(string.Empty, 50)),
new SqlParameter("@下限值", ToDbValue(string.Empty, 50)),
new SqlParameter("@测量项目", ToDbValue(detail.MeasurementName, 50)),
new SqlParameter("@测量单位", ToDbValue(detail.Unit, 50))
};
ExecuteStoredProcedureOrThrow("测量数据合格_增加_测试设备", ref parameters);
}
private static void SaveQualityInterfaceRecord(string deviceCode, string serialNumber)
{
if (!string.IsNullOrWhiteSpace(deviceCode) && !string.IsNullOrWhiteSpace(serialNumber))
{
MisDataFun.SaveQualityInterfaceData(deviceCode, serialNumber);
}
}
private static int MapQualityMark(int? sourceQualityMark, int defaultQualityMark)
{
if (!sourceQualityMark.HasValue)
{
return defaultQualityMark;
}
if (sourceQualityMark.Value == 0)
{
return 1;
}
if (sourceQualityMark.Value == 1)
{
return 2;
}
return sourceQualityMark.Value;
}
private static int? ParseNullableInt(JToken token, string fieldName)
{
string text = GetTokenText(token);
if (string.IsNullOrWhiteSpace(text))
{
return null;
}
if (int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out int result) ||
int.TryParse(text, NumberStyles.Integer, CultureInfo.CurrentCulture, out result))
{
return result;
}
throw new Exception("参数" + fieldName + "格式不正确!");
}
private static DateTime ParseDate(string text, string fieldName)
{
if (DateTime.TryParseExact(text, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime result) ||
DateTime.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.None, out result) ||
DateTime.TryParse(text, CultureInfo.CurrentCulture, DateTimeStyles.None, out result))
{
return result.Date;
}
throw new Exception("参数" + fieldName + "格式不正确!");
}
private static DateTime ParseDateTime(string text, string fieldName)
{
if (DateTime.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime result) ||
DateTime.TryParse(text, CultureInfo.CurrentCulture, DateTimeStyles.None, out result))
{
return result;
}
throw new Exception("参数" + fieldName + "格式不正确!");
}
private static DateTime ParseDateTimeOrNow(string text, string fieldName)
{
string value = CleanText(text);
if (string.IsNullOrWhiteSpace(value))
{
return DateTime.Now;
}
return ParseDateTime(value, fieldName);
}
private static DateTime? CombineDateAndTime(DateTime date, string timeText, string fieldName)
{
string text = CleanText(timeText);
if (string.IsNullOrWhiteSpace(text))
{
return null;
}
if (TimeSpan.TryParse(text, CultureInfo.InvariantCulture, out TimeSpan timePart) ||
TimeSpan.TryParse(text, CultureInfo.CurrentCulture, out timePart))
{
return date.Date.Add(timePart);
}
throw new Exception("参数" + fieldName + "格式不正确!");
}
private static string RequireText(string value, string fieldName)
{
string text = CleanText(value);
if (string.IsNullOrWhiteSpace(text))
{
throw new Exception("参数" + fieldName + "为空!");
}
return text;
}
private static string RequireText(JToken value, string fieldName)
{
string text = GetTokenText(value);
if (string.IsNullOrWhiteSpace(text))
{
throw new Exception("参数" + fieldName + "为空!");
}
return text;
}
private static string CleanText(string value)
{
return value == null ? string.Empty : value.Trim();
}
private static string GetDefaultUser(string userNumber)
{
string value = CleanText(userNumber);
return string.IsNullOrWhiteSpace(value) ? "AUTO" : value;
}
private static string GetTokenText(JToken token)
{
return token == null || token.Type == JTokenType.Null ? string.Empty : token.ToString().Trim();
}
private static object ToDbValue(string value, int maxLength)
{
return ToDbValue(value, maxLength, string.Empty);
}
private static object ToDbValue(string value, int maxLength, string defaultValue)
{
string text = CleanText(value);
if (string.IsNullOrWhiteSpace(text))
{
text = defaultValue ?? string.Empty;
}
return text.Length > maxLength ? text.Substring(0, maxLength) : text;
}
private static object ToNullableDbValue(string value, int maxLength)
{
string text = CleanText(value);
if (string.IsNullOrWhiteSpace(text))
{
return DBNull.Value;
}
return text.Length > maxLength ? text.Substring(0, maxLength) : text;
}
private static void ExecuteStoredProcedureOrThrow(string procedureName, ref SqlParameter[] parameters)
{
DataAccess2.ExecuteStoredProcedure(procedureName, ref parameters, out string errorMessage);
if (!string.IsNullOrWhiteSpace(errorMessage))
{
throw new Exception(errorMessage);
}
}
private sealed class ResultDataRequest
{
public string DeviceCode { get; set; } = string.Empty;
public string EndTime { get; set; } = string.Empty;
public ResultEnvironment Environment { get; set; } = new ResultEnvironment();
public bool? IsQualified { get; set; }
public JToken MsgId { get; set; }
public JToken PowerUsed { get; set; }
public string SectionNo { get; set; } = string.Empty;
public string StartTime { get; set; } = string.Empty;
public string TestDate { get; set; } = string.Empty;
public List<ResultTestItem> TestItems { get; set; } = new List<ResultTestItem>();
public string UserNumber { get; set; } = string.Empty;
}
private sealed class ResultEnvironment
{
public JToken Humidity { get; set; }
public JToken Temperature { get; set; }
}
private sealed class ResultTestItem
{
public string ItemName { get; set; } = string.Empty;
public JToken MeasuredValue { get; set; }
public int? QualityMark { get; set; }
public JToken SpecifiedValue { get; set; }
public string Unit { get; set; } = string.Empty;
}
private sealed class TechnologyDataRequest
{
public string CheckData { get; set; } = string.Empty;
public string CreateTime { get; set; } = string.Empty;
public string DeviceCode { get; set; } = string.Empty;
public string Flag { get; set; } = string.Empty;
public string MsgId { get; set; } = string.Empty;
public string PowerUsed { get; set; } = string.Empty;
public string SerialNumber { get; set; } = string.Empty;
public string TechnologyData { get; set; } = string.Empty;
public string UserNumber { get; set; } = string.Empty;
}
private sealed class EquipmentUseRequest
{
public string CreateTime { get; set; } = string.Empty;
public string DeviceCode { get; set; } = string.Empty;
public JToken DurationMinutes { get; set; }
public string Flag2 { get; set; } = string.Empty;
public JToken MsgId { get; set; }
public string StartTime { get; set; } = string.Empty;
public string TestDate { get; set; } = string.Empty;
}
private sealed class EquipmentStatusRequest
{
public string CreateTime { get; set; } = string.Empty;
public string DeviceCode { get; set; } = string.Empty;
public FaultInfo FaultInfo { get; set; } = new FaultInfo();
public JToken MsgId { get; set; }
public string Status { get; set; } = string.Empty;
public string StatusCode { get; set; } = string.Empty;
public string StatusTime { get; set; } = string.Empty;
public string Flag3 { get; set; } = string.Empty;
}
private sealed class FaultInfo
{
public string FaultCode { get; set; } = string.Empty;
public string FaultDescription { get; set; } = string.Empty;
public string FaultName { get; set; } = string.Empty;
}
private sealed class MeasurementDetail
{
public string TagId { get; set; } = string.Empty;
public string MeasurementName { get; set; } = string.Empty;
public string TagValue { get; set; } = string.Empty;
public int QualityMark { get; set; }
public string StandardValue { get; set; } = string.Empty;
public string Unit { get; set; } = string.Empty;
}
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ExternalDataSync
{
public static class StateVariable
{
public static bool online_Mes = true;
}
}

View File

@@ -0,0 +1,411 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using ExternalDataSync;
using MesServerWork;
using MisDataSaveDate;
using System.Net.Http;
using System.Web.Http;
using MisDataSaveDate.MOM;
using System.Data.SqlClient;
using static MisDataSaveDate.Helper.ApiLogHelper;
using WebApi;
using System.Security.Policy;
using System.Data;
using MisDataFunDll;
using System.Net;
namespace MisDataSaveDate
{
/// <summary>
/// WEB业务处理类
/// </summary>
public class WEB_BusinessLogic
{
/// <summary>
/// WEB端发来的请求
/// </summary>
/// <param name="url">请求URL</param>
/// <param name="jobj">请求的JSON对象</param>
/// <returns>处理结果</returns>
public static string WEB_Request(string url, [FromBody] JObject jobj)
{
var result = new MsgResHeader<string>();
result.code = 200;
result.message = "";
if (jobj == null)
{
result.code = 500;
result.message = "参数格式不正确!";
string retString1 = JsonConvert.SerializeObject(result);
SaveMesLog("WEB进入请求", "参数格式不正确!", Helper.MesLogType.ERROR);
MyLog4Net.MyLogHelper.Info("WEB请求进入接口res:", retString1);
return retString1;
}
string str = jobj.ToString();
//存储请求日志
SaveLog_Interface_Request(url, 2, str, out int AID);
try
{
// 解析WEB请求内容
WEB_Request webRequest = JsonConvert.DeserializeObject<WEB_Request>(str);
// 必填字段校验
if (string.IsNullOrWhiteSpace(webRequest.type))
{
throw new Exception("请求类型(type)不能为空");
}
switch (webRequest.type)
{
case "OperAtion_JobStart":
// 手动重新开始工作
// 使用JObject的索引器或Value<T>方法来获取值
string workStation1 = webRequest.paramObj?["工位号"]?.ToString() ?? "";
string orderNo1 = webRequest.paramObj?["订单号"]?.ToString() ?? "";
string workpieceNo1 = webRequest.paramObj?["工件编号"]?.ToString() ?? "";
// 验证必要参数
if (string.IsNullOrWhiteSpace(workStation1) ||
string.IsNullOrWhiteSpace(orderNo1) ||
string.IsNullOrWhiteSpace(workpieceNo1))
{
throw new Exception("OperAtion_JobStart 缺少必要参数:工位号、订单号或工件编号");
}
CALL_Inerface_DataHandle.CALL_Inerface_JobStart(workStation1, orderNo1, workpieceNo1);
break;
case "OperAtion_JobFinished":
// 手动完成工作
// 使用JObject的索引器或Value<T>方法来获取值
string workStation2 = webRequest.paramObj?["工位号"]?.ToString() ?? "";
string orderNo2 = webRequest.paramObj?["订单号"]?.ToString() ?? "";
string workpieceNo2 = webRequest.paramObj?["工件编号"]?.ToString() ?? "";
// 验证必要参数
if (string.IsNullOrWhiteSpace(workStation2) ||
string.IsNullOrWhiteSpace(orderNo2) ||
string.IsNullOrWhiteSpace(workpieceNo2))
{
throw new Exception("OperAtion_JobFinished 缺少必要参数:工位号、订单号或工件编号");
}
CALL_Inerface_DataHandle.CALL_Inerface_JobFinished(workStation2, orderNo2, workpieceNo2);
break;
default:
result.code = 500;
result.message = "无此类型~";
break;
}
}
catch (Exception err)
{
// 记录错误日志
SaveMesLog("WEB端调用接口", err.Message, Helper.MesLogType.ERROR);
result.code = 500;
result.message = err.Message;
}
string retString = JsonConvert.SerializeObject(result);
// 存储响应日志
SaveLog_Interface_Response(retString, AID);
return retString;
}
/// <summary>
/// 批量读取PLC点位值
/// </summary>
/// <param name="url">请求URL</param>
/// <param name="jobj">请求的JSON对象包含OpName和TagTypeCodeIDs数组</param>
/// <returns>处理结果</returns>
public static string WEB_ReadPLCValues(string url, [FromBody] JObject jobj)
{
var result = new MsgResHeader<List<PLCTagValueResult>>
{
code = 200,
message = "",
Data = new List<PLCTagValueResult>()
};
if (jobj == null)
{
result.code = 500;
result.message = "参数格式不正确!";
string retString1 = JsonConvert.SerializeObject(result);
SaveMesLog("WEB批量读取PLC点位值", "参数格式不正确!", Helper.MesLogType.ERROR);
MyLog4Net.MyLogHelper.Info("WEB_ReadPLCValues res:", retString1);
return retString1;
}
string str = jobj.ToString();
// 存储请求日志
SaveLog_Interface_Request(url, 2, str, out int AID);
try
{
string opName = jobj["OpName"]?.ToString() ?? "";
JArray tagTypeCodeIDsArray = jobj["TagTypeCodeIDs"] as JArray;
// 参数校验
if (string.IsNullOrEmpty(opName))
{
throw new Exception("工位号(OpName)不能为空");
}
if (tagTypeCodeIDsArray == null || tagTypeCodeIDsArray.Count == 0)
{
throw new Exception("TagTypeCodeID数组不能为空");
}
int[] tagTypeCodeIDs = tagTypeCodeIDsArray.Select(x => (int)x).ToArray();
// 读取工位全部数据
var rtList = MIS_BASE.ReadPLC_OpName(opName);
if (rtList == null)
{
throw new Exception($"读取工位[{opName}]数据失败");
}
var pp = JsonConvert.SerializeObject(rtList);
// 使用 dynamic 类型避免程序集引用问题
var tagValues = JsonConvert.DeserializeObject<System.Collections.Concurrent.ConcurrentDictionary<string, dynamic>>(pp);
// 根据传入的TagTypeCodeID数组过滤并返回对应的值
foreach (var tagTypeCodeID in tagTypeCodeIDs)
{
var tagResult = new PLCTagValueResult
{
TagTypeCodeID = tagTypeCodeID,
Success = false,
TagValue = null,
Message = ""
};
try
{
var matchedTag = tagValues.Where(x => (int)x.Value.TagTypeCodeID == tagTypeCodeID).FirstOrDefault();
if (matchedTag.Value != null)
{
tagResult.Success = true;
tagResult.TagValue = (int)matchedTag.Value.TagValue;
tagResult.TagName = (string)matchedTag.Value.TagName;
tagResult.OpName = (string)matchedTag.Value.OpName;
tagResult.TimeStamp = (string)matchedTag.Value.TimeStamp;
}
else
{
tagResult.Message = $"未找到TagTypeCodeID={tagTypeCodeID}的点位";
}
}
catch (Exception ex)
{
tagResult.Message = $"读取TagTypeCodeID={tagTypeCodeID}失败: {ex.Message}";
}
result.Data.Add(tagResult);
}
result.message = "读取成功";
}
catch (Exception err)
{
// 记录错误日志
SaveMesLog("WEB批量读取PLC点位值", err.Message, Helper.MesLogType.ERROR);
result.code = 500;
result.message = err.Message;
result.Data = null;
}
string retString = JsonConvert.SerializeObject(result);
// 存储响应日志
SaveLog_Interface_Response(retString, AID);
return retString;
}
/// <summary>
/// 写入PLC点位值
/// </summary>
/// <param name="url">请求URL</param>
/// <param name="jobj">请求的JSON对象包含TagTypeCodeID、OpName和TagValue</param>
/// <returns>处理结果</returns>
public static string WEB_WritePLC(string url, [FromBody] JObject jobj)
{
var result = new MsgResHeader<object>
{
code = 200,
message = "",
Data = null
};
if (jobj == null)
{
result.code = 500;
result.message = "参数格式不正确!";
string retString1 = JsonConvert.SerializeObject(result);
SaveMesLog("WEB写入PLC", "参数格式不正确!", Helper.MesLogType.ERROR);
MyLog4Net.MyLogHelper.Info("WEB_WritePLC res:", retString1);
return retString1;
}
string str = jobj.ToString();
// 存储请求日志
SaveLog_Interface_Request(url, 2, str, out int AID);
try
{
int tagTypeCodeID = jobj["TagTypeCodeID"]?.Value<int>() ?? 0;
string opName = jobj["OpName"]?.ToString() ?? "";
object tagValue = jobj["TagValue"]?.ToObject<object>();
// 参数校验
if (string.IsNullOrEmpty(opName))
{
throw new Exception("工位号(OpName)不能为空");
}
if (tagTypeCodeID == 0)
{
throw new Exception("TagTypeCodeID不能为0");
}
// 调用MIS_BASE.WritePLC方法写入PLC
bool writeResult = MIS_BASE.WritePLC(tagTypeCodeID, opName, tagValue);
if (writeResult)
{
result.code = 200;
result.message = "写入成功";
result.Data = new { Success = true };
}
else
{
result.code = 500;
result.message = "写入失败";
result.Data = new { Success = false };
}
}
catch (Exception err)
{
// 记录错误日志
SaveMesLog("WEB写入PLC", err.Message, Helper.MesLogType.ERROR);
result.code = 500;
result.message = err.Message;
result.Data = new { Success = false };
}
string retString = JsonConvert.SerializeObject(result);
// 存储响应日志
SaveLog_Interface_Response(retString, AID);
return retString;
}
/// <summary>
/// 磨合转序
/// 调用AGV转序接口成功后执行转序存储过程
/// </summary>
/// <param name="url">请求URL</param>
/// <param name="jobj">请求的JSON对象包含转序相关参数</param>
/// <returns>处理结果</returns>
public static string WEB_RunningInTransfer(string url, [FromBody] JObject jobj)
{
var result = new MsgResHeader<object>
{
code = 200,
message = "",
Data = null
};
if (jobj == null)
{
result.code = 500;
result.message = "参数格式不正确!";
string retString1 = JsonConvert.SerializeObject(result);
SaveMesLog("WEB磨合转序", "参数格式不正确!", Helper.MesLogType.ERROR);
MyLog4Net.MyLogHelper.Info("WEB_RunningInTransfer res:", retString1);
return retString1;
}
string str = jobj.ToString();
// 存储请求日志
SaveLog_Interface_Request(url, 2, str, out int AID);
try
{
// 获取参数
string startPositionCode = jobj["startPositionCode"]?.ToString() ?? "";
string endPositionCode = jobj["endPositionCode"]?.ToString() ?? "";
string productCode = jobj["productCode"]?.ToString() ?? "";
string productModel = jobj["productModel"]?.ToString() ?? "";
string targetProcess = jobj["targetProcess"]?.ToString() ?? "";
string targetProcessNo = jobj["targetProcessNo"]?.ToString() ?? "";
// 参数校验
if (string.IsNullOrEmpty(startPositionCode) || string.IsNullOrEmpty(endPositionCode))
{
throw new Exception("起始库位号和目标库位号不能为空");
}
// 1. 调用AGV转序接口
var agvResult = CALL_Inerface_DataHandle.CALL_Inerface_MaterialTransfer(startPositionCode, endPositionCode);
int agvCode = 500;
int.TryParse(agvResult["code"]?.ToString() ?? "500", out agvCode);
if (agvCode != 200)
{
result.code = agvCode;
result.message = $"AGV调度失败{agvResult["message"]?.ToString() ?? ""}";
}
else
{
// 2. AGV调度成功执行转序存储过程
var param = new SqlParameter[] {
new SqlParameter("@库位号", startPositionCode),
new SqlParameter("@产品编号", productCode),
new SqlParameter("@产品型号", productModel),
new SqlParameter("@目标库位号", endPositionCode),
new SqlParameter("@目标工序", targetProcess),
new SqlParameter("@目标工序号", targetProcessNo)
};
DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure("XD_磨合_开始下一序", ref param, out string errMessage);
if (!string.IsNullOrEmpty(errMessage))
{
result.code = 500;
result.message = $"AGV调度成功但存储过程执行失败{errMessage}";
}
else
{
result.code = 200;
result.message = "转序操作成功";
}
}
}
catch (Exception err)
{
// 记录错误日志
SaveMesLog("WEB磨合转序", err.Message, Helper.MesLogType.ERROR);
result.code = 500;
result.message = err.Message;
}
string retString = JsonConvert.SerializeObject(result);
// 存储响应日志
SaveLog_Interface_Response(retString, AID);
return retString;
}
}
}

View File

@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
namespace MisDataSaveDate
{
/// <summary>
/// WEB请求类型
/// </summary>
public class WEB_Request
{
/// <summary>
/// Type 操作类型 用来区分Web的各操作
/// </summary>
public string type { get; set; }
/// <summary>
/// 参数对象 根据Type 会传递不同的参数
/// 使用JObject可以接收任意JSON结构的数据无需定义实体类
/// </summary>
public JObject paramObj { get; set; }
}
/// <summary>
/// PLC点位值返回结果
/// </summary>
public class PLCTagValueResult
{
/// <summary>
/// TagTypeCodeID
/// </summary>
public int TagTypeCodeID { get; set; }
/// <summary>
/// 是否读取成功
/// </summary>
public bool Success { get; set; }
/// <summary>
/// 点位值
/// </summary>
public object TagValue { get; set; }
/// <summary>
/// 点位名称
/// </summary>
public string TagName { get; set; }
/// <summary>
/// 工位号
/// </summary>
public string OpName { get; set; }
/// <summary>
/// 时间戳
/// </summary>
public string TimeStamp { get; set; }
/// <summary>
/// 消息(错误时返回错误信息)
/// </summary>
public string Message { get; set; }
}
}