From 24e1fa423a911febf2a16ae8637a1cdc9d09012f Mon Sep 17 00:00:00 2001 From: XingCheng3 <1773407212@qq.com> Date: Tue, 12 May 2026 15:55:42 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BC=82=E5=B8=B8=E6=83=85=E5=86=B5=E5=85=9C?= =?UTF-8?q?=E5=BA=95=E4=B8=8D=E4=B8=AD=E6=96=AD=E4=BF=A1=E5=8F=B7=E6=B5=81?= =?UTF-8?q?=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SCADA/Funtion/MIS_Funtion.cs | 163 ++++++++++++++++++++++------------- SCADA/Pages/UC_Report.cs | 58 ++++++++++++- SCADA/WC_GKJ_OIL.csproj | 8 +- 3 files changed, 164 insertions(+), 65 deletions(-) diff --git a/SCADA/Funtion/MIS_Funtion.cs b/SCADA/Funtion/MIS_Funtion.cs index 6b766a4..efbd15d 100644 --- a/SCADA/Funtion/MIS_Funtion.cs +++ b/SCADA/Funtion/MIS_Funtion.cs @@ -152,6 +152,18 @@ namespace MesWork return !string.IsNullOrWhiteSpace(productNo); } + + /// + /// 业务资料异常时只记录兜底日志,PLC交互仍尽量继续,避免现场流程被MES辅助数据卡住。 + /// + private void LogWeighingFallback(string opName, string productNo, string flowName, string reason, long AID) + { + string safeProductNo = string.IsNullOrWhiteSpace(productNo) ? "未知产品" : productNo; + string msg = $"【{opName}】兜底放行:产品={safeProductNo},流程={flowName},原因={reason}"; + B_DB_Opera.SaveLog_Response(msg, AID); + WeighingPage?.AppendLog($"[{opName}] {msg}"); + } + /// /// 处理请求工作信号 (tagTypeCodeID=44) /// 流程:读取工件信息 → 查询参数 → 写过站记录 → 按类型处理称重记录 → 回写允许工作 @@ -166,7 +178,8 @@ namespace MesWork string modelNo = PLC_R.GetString_CleanGarbled(ReadPLC(11, opName)); // 机型号 string orderNo = PLC_R.GetString_CleanGarbled(ReadPLC(39, opName)); // 工单号 string palletNo = PLC_R.GetString_CleanGarbled(ReadPLC(80, opName)); // 托盘号 - // 解析代码串格式: 0/DHN2.5Q0219-36/D426E016767 或 DHH02K0014-400/B726E00584555 + string rawCodeBlock = engineNo; + // 解析代码串格式: 0/DHN2.5Q0219-36/D426E016767 或 DHH02K0014-400/B726E00584555 if (TryConvertCodeBlockData(engineNo, out string parsedOrderNo, out string parsedProductNo)) { if (!string.IsNullOrWhiteSpace(parsedOrderNo)) @@ -175,19 +188,21 @@ namespace MesWork } engineNo = parsedProductNo; - int stIdx = WeighingPage?.GetStationIndex(opName) ?? 1; - if (!B_DB_Opera.QueryWorkpieceByOrderNo(orderNo, out string matchedModelNo, out decimal addOilQty, out decimal extractOilQty, out decimal density, - out decimal residualOilUpperLimit, out decimal residualOilLowerLimit)) // 根据订货号 查询基本参数 - { - WritePLC_IF(112, opName, 3); // 报警代码=3,机型错误 - B_DB_Opera.SaveLog_Response($"【{opName}】工件管理中未找到订货号[{orderNo}]的匹配规则,发动机={engineNo}", AID); - WeighingPage?.AppendLog($"[{opName}] 订货号[{orderNo}]未匹配到工件参数"); - return; - } - modelNo = matchedModelNo; - B_DB_Opera.SaveLog_Response($"【{opName}】读取工件:发动机={engineNo},机型={modelNo},订货号={orderNo},托盘={palletNo}", AID); - WeighingPage?.UpdateStationInfo(stIdx, engineNo, modelNo, orderNo); - WeighingPage?.AppendLog($"[{opName}] 读取工件:{engineNo},机型={modelNo}"); + int stIdx = WeighingPage?.GetStationIndex(opName) ?? 1; + if (!B_DB_Opera.QueryWorkpieceByOrderNo(orderNo, out string matchedModelNo, out decimal addOilQty, out decimal extractOilQty, out decimal density, + out decimal residualOilUpperLimit, out decimal residualOilLowerLimit)) // 根据订货号 查询基本参数 + { + WritePLC_IF(112, opName, 3); // 报警代码=3,机型错误 + LogWeighingFallback(opName, engineNo, "请求工作", $"订货号[{orderNo}]未匹配到工件参数,使用PLC机型[{modelNo}]继续允许工作", AID); + // 兜底机制:参数资料缺失不再卡PLC,请求保存时若无法正常更新记录会生成异常完成记录。 + WritePLC_IF(66, opName, true); + CurveCollector_Start(opName, engineNo, modelNo); + return; + } + modelNo = matchedModelNo; + B_DB_Opera.SaveLog_Response($"【{opName}】读取工件:发动机={engineNo},机型={modelNo},订货号={orderNo},托盘={palletNo}", AID); + WeighingPage?.UpdateStationInfo(stIdx, engineNo, modelNo, orderNo); + WeighingPage?.AppendLog($"[{opName}] 读取工件:{engineNo},机型={modelNo}"); WeighingPage?.UpdateOilInfo(stIdx, addOilQty, extractOilQty, density, 0, 0); string weighType = GetWeighingType(opName); // 地面/放油前/放油后 string stationName = weighType; // 工位名称直接用称重类型名 @@ -199,9 +214,7 @@ namespace MesWork if (!B_DB_Opera.QueryWeighingBeforeOil(engineNo, out _, out decimal preWeight, out _, out _, out _)) { WritePLC_IF(112, opName, 3); - B_DB_Opera.SaveLog_Response($"【{opName}】未找到发动机[{engineNo}]的空中称重记录", AID); - WeighingPage?.AppendLog($"[{opName}] 未找到[{engineNo}]放油前记录,进站失败"); - return; + LogWeighingFallback(opName, engineNo, "请求工作-放油后", "未找到放油前记录,继续允许工作,保存时按异常放油后记录处理", AID); } else { @@ -223,8 +236,11 @@ namespace MesWork else { WritePLC_IF(112, opName, 1); // 报警代码=1,获取数据失败 - B_DB_Opera.SaveLog_Response($"【{opName}】码块数据转换失败:原始码值=[{engineNo}]", AID); - WeighingPage?.AppendLog($"[{opName}] 码块数据转换失败:{engineNo}"); + engineNo = string.IsNullOrWhiteSpace(rawCodeBlock) ? $"未知产品_{opName}_{DateTime.Now:yyyyMMddHHmmss}" : rawCodeBlock.Trim(); + LogWeighingFallback(opName, engineNo, "请求工作", $"码块数据转换失败,原始码值=[{rawCodeBlock}],仍允许工作", AID); + // 兜底机制:产品解析失败时仍给允许工作,后续保存阶段会按异常产品记录并判不合格。 + WritePLC_IF(66, opName, true); + CurveCollector_Start(opName, engineNo, modelNo); } } catch (Exception err) @@ -251,27 +267,34 @@ namespace MesWork { engineNo = parsedProductNo; } + else if (string.IsNullOrWhiteSpace(engineNo)) + { + engineNo = $"未知产品_{opName}_{DateTime.Now:yyyyMMddHHmmss}"; + LogWeighingFallback(opName, engineNo, "请求保存", "保存时产品编号为空,使用临时产品号继续保存", AID); + } - if (CurveCollector_TryGetStableWeight(opName, out decimal curveWeight, out int curvePointCount, out string curveMsg)) - { - weight = curveWeight; // 曲线采样点已按工具标定公式处理,稳定重量不再二次标定 - B_DB_Opera.SaveLog_Response($"【{opName}】标定曲线重量={curveWeight:F3}kg,PLC锁定重量={plcWeight:F3}kg,点数={curvePointCount}", AID); - } - else - { - B_DB_Opera.SaveLog_Response($"【{opName}】曲线重量不可用,使用PLC锁定重量={plcWeight:F3}kg,原因={curveMsg}", AID); - decimal rawWeight = plcWeight; - if (!WeightCalibrationHelper.Apply(opName, rawWeight, out decimal calibratedWeight, out string calibrationFormula, out string calibrationMsg)) - { - throw new Exception($"工具标定公式处理失败:{calibrationMsg}"); - } - weight = calibratedWeight; - B_DB_Opera.SaveLog_Response($"【{opName}】PLC锁定重量标定:原始重量={rawWeight:F3}kg,公式={calibrationFormula},标定后={weight:F3}kg", AID); - WeighingPage?.AppendLog($"[{opName}] PLC锁定重量标定:原始={rawWeight:F3}kg,公式={calibrationFormula},结果={weight:F3}kg"); - } - - long curveWeighingRecordId = 0; - B_DB_Opera.UpdateStationComplete(engineNo, opName, weight); // 过站记录保存最终采用重量 + if (CurveCollector_TryGetStableWeight(opName, out decimal curveWeight, out int curvePointCount, out string curveMsg)) + { + weight = curveWeight; // 曲线采样点已按工具标定公式处理,稳定重量不再二次标定 + B_DB_Opera.SaveLog_Response($"【{opName}】标定曲线重量={curveWeight:F3}kg,PLC锁定重量={plcWeight:F3}kg,点数={curvePointCount}", AID); + } + else + { + B_DB_Opera.SaveLog_Response($"【{opName}】曲线重量不可用,使用PLC锁定重量={plcWeight:F3}kg,原因={curveMsg}", AID); + decimal rawWeight = plcWeight; + if (!WeightCalibrationHelper.Apply(opName, rawWeight, out decimal calibratedWeight, out string calibrationFormula, out string calibrationMsg)) + { + LogWeighingFallback(opName, engineNo, "请求保存", $"工具标定公式处理失败:{calibrationMsg},使用PLC原始重量继续保存", AID); + calibrationFormula = "未标定兜底"; + calibratedWeight = rawWeight; + } + weight = calibratedWeight; + B_DB_Opera.SaveLog_Response($"【{opName}】PLC锁定重量标定:原始重量={rawWeight:F3}kg,公式={calibrationFormula},标定后={weight:F3}kg", AID); + WeighingPage?.AppendLog($"[{opName}] PLC锁定重量标定:原始={rawWeight:F3}kg,公式={calibrationFormula},结果={weight:F3}kg"); + } + + long curveWeighingRecordId = 0; + B_DB_Opera.UpdateStationComplete(engineNo, opName, weight); // 过站记录保存最终采用重量 string weighType = GetWeighingType(opName); decimal oilReleaseQty = 0; decimal residualOilQty = 0; @@ -280,29 +303,53 @@ namespace MesWork if (weighType == "地面") { // 地面:查最新记录 → 放油量=重量/密度 → 标记完成 - B_DB_Opera.QueryLatestRecord(opName, engineNo, - out long recordId, out _, out decimal addOil, out decimal extractOil, out decimal dens); - curveWeighingRecordId = recordId; // 曲线记录最终关联这条称重记录 - oilReleaseQty = dens > 0 ? weight / dens : 0; // 地面:油桶重量/密度=放油量 - residualOilQty = addOil - extractOil - oilReleaseQty; // 残油=加油-抽油-放油 - B_DB_Opera.UpdateWeighingComplete(recordId, "地面", opName, - weight, oilReleaseQty, residualOilQty, waterContent, out finalQualityFlag, out qualityMsg); - B_DB_Opera.SaveLog_Response( - $"【{opName}】地面保存完成:发动机={engineNo},重量={weight}kg,放油量={oilReleaseQty:F4}L,残油量={residualOilQty:F4}L,合格标志={finalQualityFlag},{qualityMsg}", AID); - WeighingPage?.UpdateOilResult(WeighingPage?.GetStationIndex(opName) ?? 1, oilReleaseQty, residualOilQty); - WeighingPage?.AppendLog($"[{opName}] 保存完成:{engineNo},重量={weight:F2}kg,放油量={oilReleaseQty:F4}L"); + if (B_DB_Opera.QueryLatestRecord(opName, engineNo, + out long recordId, out _, out decimal addOil, out decimal extractOil, out decimal dens)) + { + curveWeighingRecordId = recordId; // 曲线记录最终关联这条称重记录 + oilReleaseQty = dens > 0 ? weight / dens : 0; // 地面:油桶重量/密度=放油量 + residualOilQty = addOil - extractOil - oilReleaseQty; // 残油=加油-抽油-放油 + B_DB_Opera.UpdateWeighingComplete(recordId, "地面", opName, + weight, oilReleaseQty, residualOilQty, waterContent, out finalQualityFlag, out qualityMsg); + B_DB_Opera.SaveLog_Response( + $"【{opName}】地面保存完成:发动机={engineNo},重量={weight}kg,放油量={oilReleaseQty:F4}L,残油量={residualOilQty:F4}L,合格标志={finalQualityFlag},{qualityMsg}", AID); + WeighingPage?.UpdateOilResult(WeighingPage?.GetStationIndex(opName) ?? 1, oilReleaseQty, residualOilQty); + WeighingPage?.AppendLog($"[{opName}] 保存完成:{engineNo},重量={weight:F2}kg,放油量={oilReleaseQty:F4}L"); + } + else + { + // 兜底机制:请求工作阶段资料异常可能没有占位记录,保存时补一条异常完成记录,避免PLC等不到保存完成。 + curveWeighingRecordId = B_DB_Opera.InsertWeighingRecord(opName, "地面", engineNo, "", "", "", + 0, weight, 0, 0, 0, 0, 0, 0, 0, 2, waterContent, + opName, Curr_UserName, isComplete: 1); + finalQualityFlag = 2; + qualityMsg = "未找到请求工作占位记录,已按异常地面记录保存"; + LogWeighingFallback(opName, engineNo, "请求保存-地面", qualityMsg, AID); + } } else if (weighType == "放油前") { // 空中放油前:查最新记录 → 仅写入进站重量,不标记完成 - B_DB_Opera.QueryLatestRecord(opName, engineNo, - out long recordId, out _, out _, out _, out _); - curveWeighingRecordId = recordId; // 放油前曲线也关联同一条称重记录 - B_DB_Opera.UpdateWeighingComplete(recordId, "空中放油前", opName, - weight, 0, 0, waterContent, out finalQualityFlag, out qualityMsg); - B_DB_Opera.SaveLog_Response( - $"【{opName}】空中放油前保存完成:发动机={engineNo},进站重量={weight}kg,合格标志={finalQualityFlag},{qualityMsg}", AID); - WeighingPage?.AppendLog($"[{opName}] 放油前保存:{engineNo},重量={weight:F2}kg"); + if (B_DB_Opera.QueryLatestRecord(opName, engineNo, + out long recordId, out _, out _, out _, out _)) + { + curveWeighingRecordId = recordId; // 放油前曲线也关联同一条称重记录 + B_DB_Opera.UpdateWeighingComplete(recordId, "空中放油前", opName, + weight, 0, 0, waterContent, out finalQualityFlag, out qualityMsg); + B_DB_Opera.SaveLog_Response( + $"【{opName}】空中放油前保存完成:发动机={engineNo},进站重量={weight}kg,合格标志={finalQualityFlag},{qualityMsg}", AID); + WeighingPage?.AppendLog($"[{opName}] 放油前保存:{engineNo},重量={weight:F2}kg"); + } + else + { + // 兜底机制:没有占位记录时补异常记录并完成握手,后续放油后仍可按异常链路继续。 + curveWeighingRecordId = B_DB_Opera.InsertWeighingRecord(opName, "空中", engineNo, "", "", "", + weight, 0, 0, 0, 0, 0, 0, 0, 0, 2, waterContent, + opName, Curr_UserName, isComplete: 1); + finalQualityFlag = 2; + qualityMsg = "未找到请求工作占位记录,已按异常放油前记录保存"; + LogWeighingFallback(opName, engineNo, "请求保存-放油前", qualityMsg, AID); + } } else // 放油后 { diff --git a/SCADA/Pages/UC_Report.cs b/SCADA/Pages/UC_Report.cs index 96cb5a2..95ec928 100644 --- a/SCADA/Pages/UC_Report.cs +++ b/SCADA/Pages/UC_Report.cs @@ -38,14 +38,13 @@ namespace MesWork.Pages dgv_Data.Columns.Add(new DataGridViewTextBoxColumn { Name = "发动机号", HeaderText = "发动机号", DataPropertyName = "发动机号", FillWeight = 100 }); dgv_Data.Columns.Add(new DataGridViewTextBoxColumn { Name = "机型号", HeaderText = "机型号", DataPropertyName = "机型号", FillWeight = 80 }); dgv_Data.Columns.Add(new DataGridViewTextBoxColumn { Name = "订单号", HeaderText = "订单号", DataPropertyName = "订单号", FillWeight = 80 }); - dgv_Data.Columns.Add(new DataGridViewTextBoxColumn { Name = "称重类型", HeaderText = "称重类型", DataPropertyName = "称重类型", FillWeight = 70 }); - dgv_Data.Columns.Add(new DataGridViewTextBoxColumn { Name = "托盘号", HeaderText = "托盘号", DataPropertyName = "托盘号", FillWeight = 60 }); dgv_Data.Columns.Add(new DataGridViewTextBoxColumn { Name = "进站重量", HeaderText = "进站重量(KG)", DataPropertyName = "进站重量", FillWeight = 80 }); dgv_Data.Columns.Add(new DataGridViewTextBoxColumn { Name = "离站重量", HeaderText = "离站重量(KG)", DataPropertyName = "离站重量", FillWeight = 80 }); dgv_Data.Columns.Add(new DataGridViewTextBoxColumn { Name = "加油量", HeaderText = "加油量", DataPropertyName = "加油量", FillWeight = 60 }); dgv_Data.Columns.Add(new DataGridViewTextBoxColumn { Name = "抽油量", HeaderText = "抽油量", DataPropertyName = "抽油量", FillWeight = 60 }); dgv_Data.Columns.Add(new DataGridViewTextBoxColumn { Name = "放油量", HeaderText = "放油量", DataPropertyName = "放油量", FillWeight = 70 }); dgv_Data.Columns.Add(new DataGridViewTextBoxColumn { Name = "残留量", HeaderText = "残留量", DataPropertyName = "残留量", FillWeight = 60 }); + dgv_Data.Columns.Add(new DataGridViewTextBoxColumn { Name = "残油量上下限", HeaderText = "残油量上下限", DataPropertyName = "残油量上下限", FillWeight = 90 }); dgv_Data.Columns.Add(new DataGridViewTextBoxColumn { Name = "油密度", HeaderText = "油密度", DataPropertyName = "油密度", FillWeight = 60 }); dgv_Data.Columns.Add(new DataGridViewTextBoxColumn { Name = "合格标志", HeaderText = "合格", DataPropertyName = "合格标志", FillWeight = 50 }); dgv_Data.Columns.Add(new DataGridViewTextBoxColumn { Name = "操作员", HeaderText = "操作员", DataPropertyName = "操作员", FillWeight = 60 }); @@ -81,7 +80,11 @@ namespace MesWork.Pages itemCountParam }; SqlOperation.ExecuteStoredProcedure("称重记录_分页查询", parms, out DataTable dt, out string err); - if (dt != null) dgv_Data.DataSource = dt; + if (dt != null) + { + AddResidualOilLimitColumn(dt); + dgv_Data.DataSource = dt; + } _pager.UpdateState(pageCountParam, itemCountParam); } catch (Exception ex) @@ -90,6 +93,53 @@ namespace MesWork.Pages } } + /// + /// 将残油量上下限合并为报表显示列。 + /// + private void AddResidualOilLimitColumn(DataTable dt) + { + if (!dt.Columns.Contains("残油量上下限")) + { + dt.Columns.Add("残油量上下限", typeof(string)); + } + if (dt.Columns.Contains("残留量")) + { + dt.Columns["残油量上下限"].SetOrdinal(dt.Columns["残留量"].Ordinal + 1); + } + + foreach (DataRow row in dt.Rows) + { + row["残油量上下限"] = $"{FormatLimit(row, "残油量下限")}~{FormatLimit(row, "残油量上限")}"; + } + } + + private string FormatLimit(DataRow row, string columnName) + { + if (!row.Table.Columns.Contains(columnName) || row[columnName] == DBNull.Value) + { + return ""; + } + + if (decimal.TryParse(row[columnName].ToString(), out decimal value)) + { + return value.ToString("0.###"); + } + + return row[columnName].ToString(); + } + + private void RemoveHiddenExportColumns(DataTable dt) + { + string[] hiddenColumns = { "称重类型", "托盘号", "残油量上限", "残油量下限" }; + foreach (string columnName in hiddenColumns) + { + if (dt.Columns.Contains(columnName)) + { + dt.Columns.Remove(columnName); + } + } + } + /// /// 导出 Excel(重新查询全量数据后导出) /// @@ -126,6 +176,8 @@ namespace MesWork.Pages if (dt != null && dt.Rows.Count > 0) { + AddResidualOilLimitColumn(dt); + RemoveHiddenExportColumns(dt); bool exported = NPOITest.ExeclHelper.DataTableToExcel(dt, "称重记录", sfd.FileName); if (exported) { diff --git a/SCADA/WC_GKJ_OIL.csproj b/SCADA/WC_GKJ_OIL.csproj index 0e97a83..faf92e4 100644 --- a/SCADA/WC_GKJ_OIL.csproj +++ b/SCADA/WC_GKJ_OIL.csproj @@ -165,9 +165,9 @@ - - - + + + Form @@ -364,4 +364,4 @@ - + \ No newline at end of file