diff --git a/Common/09MesDataFunction/MesDataFunction/14MisDataFunctionDB/MisDataFun.BaseFlow.cs b/Common/09MesDataFunction/MesDataFunction/14MisDataFunctionDB/MisDataFun.BaseFlow.cs index af91faf..1c5dd60 100644 --- a/Common/09MesDataFunction/MesDataFunction/14MisDataFunctionDB/MisDataFun.BaseFlow.cs +++ b/Common/09MesDataFunction/MesDataFunction/14MisDataFunctionDB/MisDataFun.BaseFlow.cs @@ -211,5 +211,26 @@ namespace MisDataFunDll MisDataFun.LogRecording_OP(OpName, "WARNING", "MOM", msg); return false; } + + /// + /// 写入 保存完成和工作完成 并且对此进行一定判断校验 + /// + /// + public static void WriteMesReadOver(string OpName,bool isOver) + { + if (isOver) + { + MIS_BASE.Read_WorkStart(OpName,out bool isWorkStart); + if(!isWorkStart) + { + MisDataFun.LogRecording_OP(OpName, "WARNING", "WriteMesReadOver", "产品未在位 不予写入工作完成"); + return; + } + } + //通知PLC,MES工作完成 + MIS_BASE.Write_MesWorkFinish(OpName, isOver); + //通知PLC,MES保存完成 + MIS_BASE.Write_MesReadOver(OpName, isOver); + } } } diff --git a/Common/09MesDataFunction/MesDataFunction/14MisDataFunctionDB/MisDataFun.DB.cs b/Common/09MesDataFunction/MesDataFunction/14MisDataFunctionDB/MisDataFun.DB.cs index 0421fea..4198d1c 100644 --- a/Common/09MesDataFunction/MesDataFunction/14MisDataFunctionDB/MisDataFun.DB.cs +++ b/Common/09MesDataFunction/MesDataFunction/14MisDataFunctionDB/MisDataFun.DB.cs @@ -542,12 +542,19 @@ namespace MisDataFunDll { // 机型代码 对应客户标签字段映射 string targetField; - switch (EngineTypeID) + if (OpName.StartsWith("OP450")) { - case 1: case 5: targetField = "TEXT9"; break; - case 2: case 3: case 6: case 7: targetField = "TEXT14"; break; - case 4: targetField = "TEXT16"; break; - default: targetField = ""; break; + targetField = "TEXT1"; + } + else + { + switch (EngineTypeID) + { + case 1: case 5: targetField = "TEXT9"; break; + case 2: case 3: case 6: case 7: targetField = "TEXT14"; break; + case 4: targetField = "TEXT16"; break; + default: targetField = ""; break; + } } if (!string.IsNullOrEmpty(targetField)) diff --git a/Common/09MesDataFunction/MesDataFunction/webService/CallWebService.cs b/Common/09MesDataFunction/MesDataFunction/webService/CallWebService.cs index 382fa30..2cc9769 100644 --- a/Common/09MesDataFunction/MesDataFunction/webService/CallWebService.cs +++ b/Common/09MesDataFunction/MesDataFunction/webService/CallWebService.cs @@ -1405,6 +1405,7 @@ namespace MisDataSaveDate } getAllLabelContents.sfcList = sfc; if (opName == "OP490-3") getAllLabelContents.Y = "2"; + if (opName.StartsWith("OP450")) getAllLabelContents.Y = "3"; MisDataFun.LogRecording_OP(opName, "INFO", "MOM", "调用打印配置接口"); ND_Api.getAllLabelContents(apiName, opName, getAllLabelContents,out string responseContent, out code, out message); if (code == "0") @@ -1535,6 +1536,9 @@ namespace MisDataSaveDate case "dcGroupRevision": dataCollectForResourceInspect.dcGroupRevision = paramValue?.ToString() ?? ""; break; + case "executeMode": + dataCollectForResourceInspect.executeMode = paramValue?.ToString() ?? ""; + break; case "operation": dataCollectForResourceInspect.operation = operation; break; @@ -1556,9 +1560,11 @@ namespace MisDataSaveDate int EngineTypeID = Convert.ToInt32(dt_quality.Rows[0]["产品代码"]); if (opName == "OP320") { - if (EngineTypeID == 2 || EngineTypeID == 6 || EngineTypeID == 7) dataCollectForResourceInspect.dcSequence = "B1"; + if (EngineTypeID == 2 ) dataCollectForResourceInspect.dcSequence = "B1"; if (EngineTypeID == 3) dataCollectForResourceInspect.dcSequence = "B2"; if (EngineTypeID == 4) dataCollectForResourceInspect.dcSequence = "B3"; + if (EngineTypeID == 5) dataCollectForResourceInspect.dcSequence = "B4"; + if (EngineTypeID == 6) dataCollectForResourceInspect.dcSequence = "B5"; } List parametricDataArray = new List(); diff --git a/MisDataFun/MisDataFun/webApi/WebSendServer.cs b/MisDataFun/MisDataFun/webApi/WebSendServer.cs index 1f95acd..b8e9490 100644 --- a/MisDataFun/MisDataFun/webApi/WebSendServer.cs +++ b/MisDataFun/MisDataFun/webApi/WebSendServer.cs @@ -701,6 +701,10 @@ namespace MisDataSaveDate { throw new Exception("参数EngineID为空!"); } + if (string.IsNullOrWhiteSpace(req.OpName)) + { + throw new Exception("参数OpName为空!"); + } if (req.EngineTypeID <= 0) { throw new Exception("参数EngineTypeID无效!"); @@ -708,7 +712,7 @@ namespace MisDataSaveDate string engineID = req.EngineID.Trim(); int engineTypeID = req.EngineTypeID; - string opName = "OP490-3"; + string opName = req.OpName.Trim(); string tagValue = MisDataFunDll.MisDataFun.GetMesClientTagValue(opName, engineID, engineTypeID); @@ -857,6 +861,10 @@ namespace MisDataSaveDate /// 产品型号代码 /// public int EngineTypeID { get; set; } + /// + /// 工位号 + /// + public string OpName { get; set; } } public class GetClientTagValueRes diff --git a/MisDataFunction/Function1051/OpcServer/MesRead.cs b/MisDataFunction/Function1051/OpcServer/MesRead.cs index 9e5b14c..d33030c 100644 --- a/MisDataFunction/Function1051/OpcServer/MesRead.cs +++ b/MisDataFunction/Function1051/OpcServer/MesRead.cs @@ -1,5 +1,6 @@ using System; using System.Data; +using MesDataFunction; using MesServerWork; using MisDataFunDll; using MisDataSaveDate; @@ -84,18 +85,15 @@ namespace MesServerFunctions return; } - //通知PLC,MES工作完成 - MIS_BASE.Write_MesWorkFinish(OpName, true); - //通知PLC,MES保存完成 - MIS_BASE.Write_MesReadOver(OpName, true); + // 保存完成工作完成 + MisDataBaseFun.WriteMesReadOver(OpName, true); MisDataFun.LogRecording_OP(OpName, "INFO", "MIS", "MES保存数据完成!"); MisDataFun.LogRecording_OP(OpName, "INFO", "MIS", "MES工作完成!"); } else { - MIS_BASE.Write_MesReadOver(OpName, false); - MIS_BASE.Write_MesWorkFinish(OpName, false); + MisDataBaseFun.WriteMesReadOver(OpName, false); // 写入加工合格还是不合格 根据工位合格标志写 MIS_BASE.Write_OpNameIsOk(OpName, -99); MisDataFun.LogRecording_OP(OpName, "INFO", "MIS", "PLC允许保存数据取消!"); diff --git a/MisDataFunction/Function1052/OpcServer/MesRead.cs b/MisDataFunction/Function1052/OpcServer/MesRead.cs index ef5d436..c48861c 100644 --- a/MisDataFunction/Function1052/OpcServer/MesRead.cs +++ b/MisDataFunction/Function1052/OpcServer/MesRead.cs @@ -124,18 +124,16 @@ namespace MesServerFunctions return; } - //通知PLC,MES工作完成 - MIS_BASE.Write_MesWorkFinish(OpName, true); - //通知PLC,MES保存完成 - MIS_BASE.Write_MesReadOver(OpName, true); + // 保存完成工作完成 + MisDataBaseFun.WriteMesReadOver(OpName, true); MisDataFun.LogRecording_OP(OpName, "INFO", "MIS", "MES保存数据完成!"); MisDataFun.LogRecording_OP(OpName, "INFO", "MIS", "MES工作完成!"); } else { - MIS_BASE.Write_MesReadOver(OpName, false); - MIS_BASE.Write_MesWorkFinish(OpName, false); + MisDataBaseFun.WriteMesReadOver(OpName, false); + // 写入加工合格还是不合格 根据工位合格标志写 MIS_BASE.Write_OpNameIsOk(OpName, -99); MisDataFun.LogRecording_OP(OpName, "INFO", "MIS", "PLC允许保存数据取消!"); diff --git a/MisDataFunction/Function1055/Function1055.csproj b/MisDataFunction/Function1055/Function1055.csproj index 8e117ed..bd457a9 100644 --- a/MisDataFunction/Function1055/Function1055.csproj +++ b/MisDataFunction/Function1055/Function1055.csproj @@ -81,6 +81,7 @@ + @@ -116,4 +117,4 @@ --> - \ No newline at end of file + diff --git a/MisDataFunction/Function1055/MesServerFunction/Fun_1055.cs b/MisDataFunction/Function1055/MesServerFunction/Fun_1055.cs index c341e7c..276a9d0 100644 --- a/MisDataFunction/Function1055/MesServerFunction/Fun_1055.cs +++ b/MisDataFunction/Function1055/MesServerFunction/Fun_1055.cs @@ -100,6 +100,13 @@ namespace MesServerFunctions case "65": fun_MesSaveNowData(e); break; + //OP420 静置B位产品信息保存请求 + case "64": + if (m_OpName == "OP420") + { + fun_ManualStaticBSave(e); + } + break; //MES 系统健康心跳 case "14": fun_HeartBeatMIS(e); @@ -251,6 +258,16 @@ namespace MesServerFunctions ThreadPool.QueueUserWorkItem(MesSaveNowData, e); } + /// + /// OP420 静置B位产品信息保存 + /// + /// + /// + public void fun_ManualStaticBSave(DeviceDriver_BasicData.CustomeEvetnArgs e) + { + ThreadPool.QueueUserWorkItem(ManualStaticBSave, e); + } + /// /// 拧紧完成 /// diff --git a/MisDataFunction/Function1055/OpcServer/ManualStaticBSave.cs b/MisDataFunction/Function1055/OpcServer/ManualStaticBSave.cs new file mode 100644 index 0000000..26a184d --- /dev/null +++ b/MisDataFunction/Function1055/OpcServer/ManualStaticBSave.cs @@ -0,0 +1,114 @@ +using DataLinkMesWork1; +using MesServerWork; +using MisDataFunDll; +using System; +using System.Data.SqlClient; + +namespace MesServerFunctions +{ + partial class FunctionMES + { + /// + /// OP420 静置B位产品信息保存:64=1 保存开始静置信息,64=0 复位保存完成点位。 + /// + private void ManualStaticBSave(object e) + { + try + { + var msgEvent = (DeviceDriver_BasicData.CustomeEvetnArgs)e; + string opName = Convert.ToString(msgEvent.OpName); + int tagValue = Convert.ToInt32(msgEvent.TagValue); + + if (opName != "OP420") + { + return; + } + + if (tagValue != 1) + { + MIS_BASE.Write_TagValueByTagTypeID(31, opName, false); + MisDataFun.LogRecording_OP(opName, "INFO", "ManualStaticBSave", "PLC请求保存静置B位产品信息取消!"); + return; + } + + int engineTypeID; + string engineType; + string engineID; + int palletCode; + string orderForm; + + // 从 PLC 当前产品区读取 B 位产品信息,作为线下手动静置开始记录。 + MIS_BASE.GetEngineTypeFromPLC(opName, out engineTypeID, out engineType, out engineID, out palletCode, out orderForm); + if (string.IsNullOrWhiteSpace(engineID)) + { + WriteManualStaticBSaveError(opName, "PLC当前产品码为空,无法记录静置B位产品信息"); + return; + } + + // PLC 可能只给产品码和机型代码,补查数据库中的产品型号。 + string dbEngineType; + int dbEngineTypeID; + MisDataFun.Moby_Select_PDC(engineID, out orderForm, out dbEngineType, out dbEngineTypeID); + if (dbEngineTypeID > 0) + { + engineTypeID = dbEngineTypeID; + } + if (!string.IsNullOrWhiteSpace(dbEngineType)) + { + engineType = dbEngineType; + } + + string message; + if (!SaveManualStaticBRecord(engineID, engineType, engineTypeID, out message)) + { + WriteManualStaticBSaveError(opName, message); + return; + } + + MIS_BASE.Write_TagValueByTagTypeID(31, opName, true); + MisDataFun.LogRecording_OP(opName, "INFO", "ManualStaticBSave", "静置B位产品信息保存完成:" + engineID); + } + catch (Exception err) + { + MyLog4Net.MyLogHelper.Error("Function1055.ManualStaticBSave", err.Message); + WriteManualStaticBSaveError("OP420", err.Message); + } + } + + /// + /// 保存 OP420 静置B位开始记录,同一产品只保留最新一条。 + /// + private bool SaveManualStaticBRecord(string engineID, string engineType, int engineTypeID, out string message) + { + message = ""; + SqlParameter[] sqlParameters = new SqlParameter[] + { + new SqlParameter("@产品编号", engineID), + new SqlParameter("@产品型号", engineType), + new SqlParameter("@产品型号代码", engineTypeID), + new SqlParameter("@静置开始时间", DateTime.Now) + }; + + string errorMessage; + DataAccess.ExecuteStoredProcedure("线下手动静置_记录_保存", ref sqlParameters, out errorMessage); + if (!string.IsNullOrWhiteSpace(errorMessage)) + { + message = "保存线下手动静置记录失败:" + errorMessage; + return false; + } + + return true; + } + + /// + /// OP420 静置B位保存失败时复位完成点位并通知页面。 + /// + private void WriteManualStaticBSaveError(string opName, string message) + { + MIS_BASE.Write_TagValueByTagTypeID(31, opName, false); + MIS_BASE.Write_TagValueByTagTypeID(34, opName, true); + SendMessage.AsyncSendMessage_Notice(opName, "【" + opName + "】" + message); + MisDataFun.LogRecording_OP(opName, "ERROR", "ManualStaticBSave", message); + } + } +} diff --git a/MisDataFunction/Function1055/OpcServer/MesRead.cs b/MisDataFunction/Function1055/OpcServer/MesRead.cs index b8a73ff..4ea964b 100644 --- a/MisDataFunction/Function1055/OpcServer/MesRead.cs +++ b/MisDataFunction/Function1055/OpcServer/MesRead.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Data; using System.Threading; +using MesDataFunction; //using SystemFramework; using MesServerWork; using MisDataFunDll; @@ -99,8 +100,7 @@ namespace MesServerFunctions } else { - MIS_BASE.Write_MesReadOver(OpName, false); - MIS_BASE.Write_MesWorkFinish(OpName, false); + MisDataBaseFun.WriteMesReadOver(OpName, false); MisDataFun.LogRecording_OP(OpName, "INFO", "MesRead", "PLC允许保存数据取消!"); } diff --git a/MisDataFunction/Function1056/OpcServer/MesRead.cs b/MisDataFunction/Function1056/OpcServer/MesRead.cs index c1849b9..198761b 100644 --- a/MisDataFunction/Function1056/OpcServer/MesRead.cs +++ b/MisDataFunction/Function1056/OpcServer/MesRead.cs @@ -111,17 +111,14 @@ namespace MesServerFunctions return; } - //通知PLC,MES保存完成 - MIS_BASE.Write_MesReadOver(OpName, true); - //通知PLC,MES工作完成 - MIS_BASE.Write_MesWorkFinish(OpName, true); + // 保存完成工作完成 + MisDataBaseFun.WriteMesReadOver(OpName, true); MisDataFun.LogRecording_OP(OpName, "INFO", "MesRead", "MES保存数据完成!"); MisDataFun.LogRecording_OP(OpName, "INFO", "MesRead", "MES工作完成!"); } else { - MIS_BASE.Write_MesReadOver(OpName, false); - MIS_BASE.Write_MesWorkFinish(OpName, false); + MisDataBaseFun.WriteMesReadOver(OpName, false); // 写入加工合格还是不合格 根据工位合格标志写 MIS_BASE.Write_OpNameIsOk(OpName, -99); MisDataFun.LogRecording_OP(OpName, "INFO", "MesRead", "PLC允许保存数据取消!"); @@ -133,4 +130,4 @@ namespace MesServerFunctions } } } -} \ No newline at end of file +} diff --git a/MisDataFunction/Function1057/OpcServer/MesRead.cs b/MisDataFunction/Function1057/OpcServer/MesRead.cs index 6381edb..127d747 100644 --- a/MisDataFunction/Function1057/OpcServer/MesRead.cs +++ b/MisDataFunction/Function1057/OpcServer/MesRead.cs @@ -1,4 +1,5 @@ using MesServerWork; +using MesDataFunction; using MisDataFunDll; using MisDataSaveDate; using System; @@ -127,9 +128,8 @@ namespace MesServerFunctions // 都出站成功了 才给PLC信号 if (part1_IsOk && part2_IsOk) { - // 4.通知PLC,MES保存完成 MES工作完成 - MIS_BASE.Write_MesReadOver(OpName, true); - MIS_BASE.Write_MesWorkFinish(OpName, true); + // 保存完成工作完成 + MisDataBaseFun.WriteMesReadOver(OpName, true); MisDataFun.LogRecording_OP(OpName, "INFO", "MesRead", "MES保存数据完成!"); MisDataFun.LogRecording_OP(OpName, "INFO", "MesRead", "MES工作完成!"); } @@ -137,8 +137,7 @@ namespace MesServerFunctions } else { - MIS_BASE.Write_MesReadOver(OpName, false); - MIS_BASE.Write_MesWorkFinish(OpName, false); + MisDataBaseFun.WriteMesReadOver(OpName, false); MisDataFun.LogRecording_OP(OpName, "INFO", "MesRead", "PLC允许保存数据取消!"); } } diff --git a/MisDataFunction/Function1058/OpcServer/MesRead.cs b/MisDataFunction/Function1058/OpcServer/MesRead.cs index d8eaaaf..14cbfc1 100644 --- a/MisDataFunction/Function1058/OpcServer/MesRead.cs +++ b/MisDataFunction/Function1058/OpcServer/MesRead.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Threading; //using SystemFramework; +using MesDataFunction; using MesServerWork; using MisDataFunDll; @@ -65,10 +66,8 @@ namespace MesServerFunctions } // 写入加工合格还是不合格 根据工位合格标志写 MIS_BASE.Write_OpNameIsOk(OpName, qualityMask); - //通知PLC,MES保存完成 - MIS_BASE.Write_MesReadOver(OpName, true); - //通知PLC,MES工作完成 - MIS_BASE.Write_MesWorkFinish(OpName, true); + // 保存完成工作完成 + MisDataBaseFun.WriteMesReadOver(OpName, true); MisDataFun.LogRecording_OP(OpName, "INFO", "MIS", "MES保存数据完成!"); MisDataFun.LogRecording_OP(OpName, "INFO", "MIS", "MES工作完成!"); } @@ -76,8 +75,7 @@ namespace MesServerFunctions { // 写入加工合格还是不合格 根据工位合格标志写 MIS_BASE.Write_OpNameIsOk(OpName, -99); - MIS_BASE.Write_MesReadOver(OpName, false); - MIS_BASE.Write_MesWorkFinish(OpName, false); + MisDataBaseFun.WriteMesReadOver(OpName, false); MisDataFun.LogRecording_OP(OpName, "INFO", "MIS", "PLC允许保存数据取消!"); } diff --git a/MisDataFunction/Function1059/OpcServer/MesRead.cs b/MisDataFunction/Function1059/OpcServer/MesRead.cs index 1d44455..acd45a3 100644 --- a/MisDataFunction/Function1059/OpcServer/MesRead.cs +++ b/MisDataFunction/Function1059/OpcServer/MesRead.cs @@ -1,4 +1,5 @@ //using SystemFramework; +using MesDataFunction; using MesServerWork; using MisDataFunDll; using MisDataSaveDate; @@ -99,10 +100,8 @@ namespace MesServerFunctions return; } - //通知PLC,MES保存完成 - MIS_BASE.Write_MesReadOver(OpName, true); - //通知PLC,MES工作完成 - MIS_BASE.Write_MesWorkFinish(OpName, true); + // 保存完成工作完成 + MisDataBaseFun.WriteMesReadOver(OpName, true); MisDataFun.LogRecording_OP(OpName, "INFO", "MesRead", "MES保存数据完成!"); MisDataFun.LogRecording_OP(OpName, "INFO", "MesRead", "MES工作完成!"); } @@ -120,8 +119,7 @@ namespace MesServerFunctions { // 写入加工合格还是不合格 根据工位合格标志写 MIS_BASE.Write_OpNameIsOk(OpName, -99); - MIS_BASE.Write_MesReadOver(OpName, false); - MIS_BASE.Write_MesWorkFinish(OpName, false); + MisDataBaseFun.WriteMesReadOver(OpName, false); MisDataFun.LogRecording_OP(OpName, "INFO", "MesRead", "PLC允许保存数据取消!"); } diff --git a/MisDataFunction/Function1061/OpcServer/MesRead.cs b/MisDataFunction/Function1061/OpcServer/MesRead.cs index 3334fc8..b751cc4 100644 --- a/MisDataFunction/Function1061/OpcServer/MesRead.cs +++ b/MisDataFunction/Function1061/OpcServer/MesRead.cs @@ -1,5 +1,6 @@ using System; using System.Data; +using MesDataFunction; using MesServerWork; using MisDataFunDll; using MisDataSaveDate; @@ -81,18 +82,15 @@ namespace MesServerFunctions return; } - //通知PLC,MES工作完成 - MIS_BASE.Write_MesWorkFinish(OpName, true); - //通知PLC,MES保存完成 - MIS_BASE.Write_MesReadOver(OpName, true); + // 保存完成工作完成 + MisDataBaseFun.WriteMesReadOver(OpName, true); MisDataFun.LogRecording_OP(OpName, "INFO", "MesRead", "MES保存数据完成!"); MisDataFun.LogRecording_OP(OpName, "INFO", "MesRead", "MES工作完成!"); } else { - MIS_BASE.Write_MesReadOver(OpName, false); - MIS_BASE.Write_MesWorkFinish(OpName, false); + MisDataBaseFun.WriteMesReadOver(OpName, false); // 写入加工合格还是不合格 根据工位合格标志写 MIS_BASE.Write_OpNameIsOk(OpName, -99); MisDataFun.LogRecording_OP(OpName, "INFO", "MesRead", "PLC允许保存数据取消!"); diff --git a/MisDataFunction/Function1062.zip b/MisDataFunction/Function1062.zip new file mode 100644 index 0000000..c765e41 Binary files /dev/null and b/MisDataFunction/Function1062.zip differ diff --git a/MisDataFunction/Function1062/DataAccess/DataAccess.cs b/MisDataFunction/Function1062/DataAccess/DataAccess.cs index c7cb3db..43b285c 100644 --- a/MisDataFunction/Function1062/DataAccess/DataAccess.cs +++ b/MisDataFunction/Function1062/DataAccess/DataAccess.cs @@ -10,14 +10,20 @@ namespace MesServerFunctions { partial class FunctionMES { + // OP431 手动静置出库固定配置。 private const string ManualStaticOutOpName = "OP431"; private const string ManualStaticPadTopic = "OP431PAD"; private const decimal DefaultManualStaticMinutes = 30m; private const string ManualStaticLocation = "777777"; private const string ManualStaticOperator = "PAD"; + + // 记录 PAD 确认时使用的最小静置分钟数,保存质量数据时沿用同一标准。 private static readonly object ManualStaticMinutesLocker = new object(); private static readonly Dictionary ManualStaticMinutesByEngine = new Dictionary(); + /// + /// OP431 当前产品基础信息。 + /// private class ManualStaticOutProduct { public string EngineID { get; set; } @@ -26,6 +32,9 @@ namespace MesServerFunctions public int EngineTypeID { get; set; } } + /// + /// OP431 静置质量数据计算结果。 + /// private class ManualStaticOutData { public string SourceOpName { get; set; } @@ -35,6 +44,9 @@ namespace MesServerFunctions public int QualityMask { get; set; } } + /// + /// 查询产品订单、型号和机型代码。 + /// private bool TryGetManualStaticOutProduct(string engineID, out ManualStaticOutProduct product, out string message) { product = null; @@ -63,6 +75,9 @@ namespace MesServerFunctions return true; } + /// + /// 查询 OP420 记录的线下手动静置开始时间。 + /// private bool TryGetManualStaticStartTime(string engineID, out string sourceOpName, out DateTime startTime, out string message) { sourceOpName = ""; @@ -71,35 +86,61 @@ namespace MesServerFunctions try { - // 取 OP400/OP410/OP420 最后一条有效离开记录作为常温静置开始时间。 - string procedureName = "OP431手动静置出库_前序离开时间_查询"; + // OP431 手动出库以 OP420 记录的线下静置开始时间为准。 + string procedureName = "线下手动静置_记录_查询"; SqlParameter[] sqlParameters = new SqlParameter[1]; - sqlParameters[0] = new SqlParameter("@发动机号", engineID); + sqlParameters[0] = new SqlParameter("@产品编号", engineID); DataAccess.ExecuteStoredProcedure(procedureName, ref sqlParameters, out DataTable dt, out string errorMessage); if (!string.IsNullOrWhiteSpace(errorMessage)) { - message = "查询前序出站时间失败:" + errorMessage; + message = "查询线下手动静置开始时间失败:" + errorMessage; return false; } if (dt == null || dt.Rows.Count == 0) { - message = "未查询到 OP400/OP410/OP420 前序出站记录"; + message = "未查询到线下手动静置开始记录:" + engineID; return false; } - sourceOpName = Convert.ToString(dt.Rows[0]["工位号"]); - startTime = Convert.ToDateTime(dt.Rows[0]["开始静置时间"]); + sourceOpName = "OP420"; + startTime = Convert.ToDateTime(dt.Rows[0]["静置开始时间"]); return true; } catch (Exception err) { - message = "查询前序出站时间失败:" + err.Message; + message = "查询线下手动静置开始时间失败:" + err.Message; return false; } } + /// + /// OP431 保存时回写线下手动静置结束时间和静置时长。 + /// + private bool FinishManualStaticRecord(string engineID, DateTime finishTime, decimal minutes, out string message) + { + message = ""; + SqlParameter[] sqlParameters = new SqlParameter[] + { + new SqlParameter("@产品编号", engineID), + new SqlParameter("@静置结束时间", finishTime), + new SqlParameter("@静置时长", minutes) + }; + + DataAccess.ExecuteStoredProcedure("线下手动静置_记录_结束", ref sqlParameters, out string errorMessage); + if (!string.IsNullOrWhiteSpace(errorMessage)) + { + message = "回写线下手动静置结束时间失败:" + errorMessage; + return false; + } + + return true; + } + + /// + /// 生成 OP431 保存时需要的静置时间和质量标识。 + /// private bool TryBuildManualStaticOutData(string engineID, int qualityMask, out ManualStaticOutData staticOutData, out string message) { staticOutData = null; @@ -110,6 +151,7 @@ namespace MesServerFunctions return false; } + // PLC 允许保存到达时的服务器时间作为静置完成时间。 DateTime finishTime = DateTime.Now; decimal minutes = Math.Round(Convert.ToDecimal((finishTime - startTime).TotalMinutes), 2); staticOutData = new ManualStaticOutData @@ -123,11 +165,17 @@ namespace MesServerFunctions return true; } + /// + /// 标准化质量标识:1 为合格,其余均按不合格处理。 + /// private int NormalizeManualStaticQualityMask(int qualityMask) { return qualityMask == 1 ? 1 : 2; } + /// + /// 判断静置时长是否达到 PAD 配置的最小分钟数。 + /// private bool IsManualStaticTimeEnough(ManualStaticOutData staticOutData, decimal minStaticMinutes, out string message) { message = ""; @@ -139,6 +187,9 @@ namespace MesServerFunctions return true; } + /// + /// 直接写入 OP431 四项静置质量数据。 + /// private bool WriteManualStaticOutQualityData(string opName, string engineID, ManualStaticOutData data, out string message) { message = ""; @@ -149,6 +200,7 @@ namespace MesServerFunctions return false; } + // 先写质量索引,取返回的 Id_tagCF 作为明细关联键。 string minStaticMinutes = rememberedMinStaticMinutes.ToString("0.##"); // OP431 的静置数据由 Function 直接落库,不再通过 OnlineCheckData 做 HTTP 自调用。 @@ -175,6 +227,7 @@ namespace MesServerFunctions return false; } + // 四条质量明细必须与 MOM 数据收集组配置的 TagID 保持一致。 object[,] detailRows = new object[,] { { "OP431_M0001_001", "开始静置时间", "min", "1", "60", minStaticMinutes, data.StartTime.ToString("yyyy-MM-dd HH:mm:ss"), data.QualityMask }, @@ -211,6 +264,9 @@ namespace MesServerFunctions return true; } + /// + /// 确认上线前校验托盘到位和 PLC 申请上线状态。 + /// private bool CheckManualStaticPadPrecondition(string opName, out string message) { message = ""; @@ -232,6 +288,9 @@ namespace MesServerFunctions return true; } + /// + /// PAD 确认上线:校验静置条件,通过后写入 PLC 产品区。 + /// private bool ConfirmManualStaticOutProduct(string opName, string engineID, decimal minStaticMinutes, out string message) { message = ""; @@ -273,6 +332,9 @@ namespace MesServerFunctions return true; } + /// + /// PAD 扫码查询:返回产品、静置时间和是否允许确认。 + /// private bool QueryManualStaticOutProduct(string opName, string engineID, decimal minStaticMinutes, out string resultMessage) { resultMessage = ""; @@ -292,6 +354,7 @@ namespace MesServerFunctions bool timeEnough = IsManualStaticTimeEnough(staticOutData, minStaticMinutes, out string timeMessage); MIS_BASE.Read_PartLoad(opName, out bool partLoad); + // PAD 直接使用 canConfirm 控制按钮,不再自行组合判断条件。 bool canConfirm = timeEnough && partLoad; string confirmMessage = canConfirm ? "允许确认上线" @@ -316,6 +379,9 @@ namespace MesServerFunctions return true; } + /// + /// 将 PAD 业务结果同时发送到 PAD 主题和工位主题。 + /// private void SendManualStaticOutResult(string opName, string command, bool success, string message) { string value = (success ? "1" : "0") + "^" + message; @@ -329,11 +395,17 @@ namespace MesServerFunctions } } + /// + /// 向 OP431 PAD 专用主题发送 MQTT 回包。 + /// private void SendManualStaticPadMqttMessage(string command, string opName, string value) { SendMessage.AsyncSendNotOpMessage(ManualStaticPadTopic, "MES|" + command + "|" + opName + "|" + value); } + /// + /// 记录产品确认上线时使用的最小静置标准。 + /// private void RememberManualStaticMinutesForProduct(string engineID, decimal minStaticMinutes) { lock (ManualStaticMinutesLocker) @@ -342,6 +414,9 @@ namespace MesServerFunctions } } + /// + /// 获取产品确认上线时记录的最小静置标准。 + /// private bool TryGetManualStaticMinutesForProduct(string engineID, out decimal minStaticMinutes) { lock (ManualStaticMinutesLocker) diff --git a/MisDataFunction/Function1062/OpcServer/EngineGetOver.cs b/MisDataFunction/Function1062/OpcServer/EngineGetOver.cs index 273079f..b7294a6 100644 --- a/MisDataFunction/Function1062/OpcServer/EngineGetOver.cs +++ b/MisDataFunction/Function1062/OpcServer/EngineGetOver.cs @@ -7,6 +7,7 @@ namespace MesServerFunctions { partial class FunctionMES { + // 防止 PLC 传递机型信号重复触发时并发进站。 object lockBarcodeEngineTypeGetOver = new object(); /// @@ -32,6 +33,7 @@ namespace MesServerFunctions MisDataFun.LogRecording_OP(opName, "INFO", "MIS", "PLC传递机型!"); MIS_BASE.Write_TagValueByTagTypeID(34, opName, false); + // 同时读取 PLC 回传信息和 PAD 确认时写入的 MES 产品区信息。 MIS_BASE.GetEngineTypeFromPLC(opName, out int engineTypeID, out string engineType, out string engineID, out int palletCode, out string orderForm); MIS_BASE.GetEngineTypeFromPLC_MES(opName, out int engineTypeIDMes, out string engineTypeMes, out string engineIDMes, out string orderFormMes); @@ -47,6 +49,7 @@ namespace MesServerFunctions return; } + // PLC 回传产品必须与 PAD 确认上线产品一致,避免错件进站。 if (!string.Equals(engineID.Trim(), engineIDMes.Trim(), StringComparison.OrdinalIgnoreCase)) { WriteManualStaticEngineError(opName, "PLC产品码与PAD确认产品码不一致,PLC:" + engineID + ",PAD:" + engineIDMes); @@ -59,12 +62,14 @@ namespace MesServerFunctions return; } + // 进站前再次取产品执行信息,后续写 MOBY 使用数据库中的订单和型号。 if (!TryGetManualStaticOutProduct(engineID, out ManualStaticOutProduct product, out string productMessage)) { WriteManualStaticEngineError(opName, productMessage); return; } + // 调用工厂 MES 进站,成功后才允许 PLC 工作。 CallWebService.Call_miFindCustomAndSfcData(opName, engineID, out string code, out string message); if (code != "0") { @@ -73,6 +78,8 @@ namespace MesServerFunctions } MisDataFun.LogRecording_OP(opName, "INFO", "MOM", "进站成功:" + engineID); + + // 写普通 MOBY 当前工位状态,供后续正常过站过程取数。 MisDataFun.OpName_MIS_MOBY_Insert(opName, product.EngineTypeID, product.EngineType, product.EngineID, palletCode, product.OrderForm, 0, 0, ""); MIS_BASE.Write_FixAllow(opName, true); @@ -86,6 +93,9 @@ namespace MesServerFunctions } } + /// + /// OP431 进站失败时禁止 PLC 工作、置 MES 报警并通知页面。 + /// private void WriteManualStaticEngineError(string opName, string message) { MIS_BASE.Write_FixAllow(opName, false); diff --git a/MisDataFunction/Function1062/OpcServer/MesRead.cs b/MisDataFunction/Function1062/OpcServer/MesRead.cs index 28ec96b..6292f6e 100644 --- a/MisDataFunction/Function1062/OpcServer/MesRead.cs +++ b/MisDataFunction/Function1062/OpcServer/MesRead.cs @@ -1,4 +1,5 @@ using MesServerWork; +using MesDataFunction; using MisDataFunDll; using MisDataSaveDate; using System; @@ -21,8 +22,7 @@ namespace MesServerFunctions if (tagValue != 1) { - MIS_BASE.Write_MesReadOver(opName, false); - MIS_BASE.Write_MesWorkFinish(opName, false); + MisDataBaseFun.WriteMesReadOver(opName, false); MIS_BASE.Write_OpNameIsOk(opName, -99); MisDataFun.LogRecording_OP(opName, "INFO", "MIS", "PLC允许保存数据取消!"); return; @@ -30,6 +30,7 @@ namespace MesServerFunctions MisDataFun.LogRecording_OP(opName, "INFO", "MIS", "PLC允许保存OP431静置数据!"); + // 读取 PLC 当前产品信息,后续质量数据和出站都以该产品码为准。 MIS_BASE.GetEngineTypeFromPLC(opName, out int engineTypeID, out string engineType, out string engineID, out int palletCode, out string orderForm); if (string.IsNullOrWhiteSpace(engineID)) { @@ -37,6 +38,7 @@ namespace MesServerFunctions return; } + // 重新查询 MES 执行信息,避免直接使用 PLC 中不完整的订单/机型数据。 MisDataFun.Moby_Select_PDC(engineID, out orderForm, out engineType, out engineTypeID); if (engineTypeID <= 0) { @@ -44,21 +46,32 @@ namespace MesServerFunctions return; } + // PLC 合格标识只保留合格/不合格两种结果。 MIS_BASE.Read_QualityMask(opName, out int qualityMask); qualityMask = NormalizeManualStaticQualityMask(qualityMask); + // 组装 OP431 静置质量数据:开始时间、完成时间、时间差、库位号。 if (!TryBuildManualStaticOutData(engineID, qualityMask, out ManualStaticOutData staticOutData, out string message)) { WriteManualStaticMesReadError(opName, message); return; } + // 保存信号到达时,回写线下静置结束时间和静置时长。 + if (!FinishManualStaticRecord(engineID, staticOutData.FinishTime, staticOutData.Minutes, out message)) + { + WriteManualStaticMesReadError(opName, message); + return; + } + + // 将四项静置质量数据写入测量数据合格索引和明细表。 if (!WriteManualStaticOutQualityData(opName, engineID, staticOutData, out message)) { WriteManualStaticMesReadError(opName, message); return; } + // 写正常过站记录后查询 MOM 上传质量数据组。 MisDataFun.WorkStartInsert(opName, qualityMask); MisDataFun.GetPartQualityGroupParams(opName, engineID, out DataTable dtQuality); if (dtQuality == null || dtQuality.Rows.Count == 0) @@ -67,6 +80,7 @@ namespace MesServerFunctions return; } + // 带质量数据调用工厂 MES 出站,返回 13921 时按不合格完成。 CallWebService.Call_dataCollectForSfcEx(opName, engineID, dtQuality, qualityMask, out string code, out string momMessage); if (code == "0") { @@ -84,8 +98,7 @@ namespace MesServerFunctions return; } - MIS_BASE.Write_MesWorkFinish(opName, true); - MIS_BASE.Write_MesReadOver(opName, true); + MisDataBaseFun.WriteMesReadOver(opName, true); MisDataFun.LogRecording_OP(opName, "INFO", "MIS", "MES保存OP431静置数据完成!"); MisDataFun.LogRecording_OP(opName, "INFO", "MIS", "MES工作完成!"); @@ -97,10 +110,12 @@ namespace MesServerFunctions } } + /// + /// OP431 保存失败时统一复位保存完成、置 MES 报警并通知页面。 + /// private void WriteManualStaticMesReadError(string opName, string message) { - MIS_BASE.Write_MesReadOver(opName, false); - MIS_BASE.Write_MesWorkFinish(opName, false); + MisDataBaseFun.WriteMesReadOver(opName, false); MIS_BASE.Write_TagValueByTagTypeID(34, opName, true); SendMessage.AsyncSendMessage_Notice(opName, "【" + opName + "】" + message); MisDataFun.LogRecording_OP(opName, "ERROR", "MesRead", message); diff --git a/MisDataFunction/Function1062/OpcServer/PartLoad.cs b/MisDataFunction/Function1062/OpcServer/PartLoad.cs index 195b3e6..cbdafc8 100644 --- a/MisDataFunction/Function1062/OpcServer/PartLoad.cs +++ b/MisDataFunction/Function1062/OpcServer/PartLoad.cs @@ -19,6 +19,7 @@ namespace MesServerFunctions if (tagValue == 1) { + // OP431 不申请新 SFC,只通知 PAD 可以扫描已有产品。 MisDataFun.LogRecording_OP(opName, "INFO", "MIS", "PLC申请上线,等待PAD扫描已有产品!"); MIS_BASE.Write_TagValueByTagTypeID(34, opName, false); SendMessage.AsyncSendMessage_Notice(opName, "【" + opName + "】PLC已申请上线,请PAD扫描产品码"); @@ -28,6 +29,7 @@ namespace MesServerFunctions } MisDataFun.LogRecording_OP(opName, "INFO", "MIS", "PLC申请上线取消!"); + // 取消申请时清掉本轮未完成的 MES 输出信号。 MIS_BASE.Write_EngineTypeGetOver_MES(opName, false); MIS_BASE.Write_FixAllow(opName, false); MIS_BASE.Write_TagValueByTagTypeID(34, opName, false); diff --git a/MisDataFunction/Function1062/OpcServer/WebSubmit.cs b/MisDataFunction/Function1062/OpcServer/WebSubmit.cs index 292786e..35b4e10 100644 --- a/MisDataFunction/Function1062/OpcServer/WebSubmit.cs +++ b/MisDataFunction/Function1062/OpcServer/WebSubmit.cs @@ -45,7 +45,6 @@ namespace MesServerFunctions bool success = QueryManualStaticOutProduct(opName, engineID, minStaticMinutes, out string message); SendManualStaticOutResult(opName, "PadScanQuery", success, message); - MisDataFun.LogRecording_OP(opName, success ? "INFO" : "WARNING", "PadScanQuery", message); break; } // PAD 确认上线:重新校验托盘到位、PLC申请上线和前端配置的最小静置时间,通过后写 PLC 产品区。 @@ -77,6 +76,9 @@ namespace MesServerFunctions } } + /// + /// 解析 PAD 命令参数,取得产品码和最小静置分钟数。 + /// private bool TryGetManualStaticPadRequest(string opName, string command, string value, out string engineID, out decimal minStaticMinutes) { engineID = ""; @@ -100,6 +102,7 @@ namespace MesServerFunctions return false; } + // 参数最多允许“产品码^最小静置分钟数”两段。 string[] requestItems = requestValue.Split('^'); if (requestItems.Length > 2) { @@ -120,6 +123,7 @@ namespace MesServerFunctions if (requestItems.Length == 2) { + // 最小静置分钟数由 PAD 配置传入,未传时使用默认 30 分钟。 string minStaticMinutesText = requestItems[1].Trim(); if (!decimal.TryParse(minStaticMinutesText, out minStaticMinutes) || minStaticMinutes < 0) { @@ -171,6 +175,9 @@ namespace MesServerFunctions InitAlarm(opName); } + /// + /// 重新发送当前工位报警状态。 + /// private void InitAlarm(string opName) { FuntionMesRead.Alarm_InitAlarm_Send(opName, out Hashtable ht);