From 69b69af17fa0b1e053dd7a03b414b329c3f3c581 Mon Sep 17 00:00:00 2001 From: XingCheng3 <1773407212@qq.com> Date: Wed, 13 May 2026 01:01:09 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=B7=A5=E4=BD=8D=E5=8F=B7?= =?UTF-8?q?=E5=85=BC=E5=AE=B9=E5=8A=9F=E8=83=BD=20=E4=B8=8D=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=E5=9B=BA=E5=AE=9A=E7=9A=84=20OP10=20OP20=E5=81=9A?= =?UTF-8?q?=E7=A1=AC=E7=BC=96=E7=A0=81=E5=88=A4=E5=AE=9A=20=E9=80=9A?= =?UTF-8?q?=E8=BF=87App.config=E4=BD=9C=E4=B8=BA=E5=B7=A5=E4=BD=8D?= =?UTF-8?q?=E4=BE=9D=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SCADA/App.config | 67 ++++---- SCADA/Core/AppConfig.cs | 18 ++- SCADA/Core/BarcodeManager.cs | 35 ++--- SCADA/Funtion/MIS_Funtion.cs | 34 +++-- SCADA/MainGuide/MW.OnStart.cs | 254 +++++++++++++++++-------------- SCADA/Pages/UC_SystemSettings.cs | 27 ++-- 6 files changed, 244 insertions(+), 191 deletions(-) diff --git a/SCADA/App.config b/SCADA/App.config index 0657fcd..eb058e4 100644 --- a/SCADA/App.config +++ b/SCADA/App.config @@ -1,38 +1,41 @@ - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/SCADA/Core/AppConfig.cs b/SCADA/Core/AppConfig.cs index 5c9382a..d28eb1d 100644 --- a/SCADA/Core/AppConfig.cs +++ b/SCADA/Core/AppConfig.cs @@ -57,18 +57,28 @@ namespace MesWork /// public static string WeighingType = AppSettings["WeighingType"] ?? "Hanging"; + /// + /// 工位1现场工位号,Hanging模式下代表放油前工位 + /// + public static string Station1OpName = AppSettings["Station1OpName"] ?? ""; + + /// + /// 工位2现场工位号,Hanging模式下代表放油后工位 + /// + public static string Station2OpName = AppSettings["Station2OpName"] ?? ""; + /// /// 是否启用扫码枪:1=启用, 0=禁用 /// public static int IsUseBarcode = int.TryParse(AppSettings["IsUseBarcode"], out var _iub) ? _iub : 0; /// - /// OP10扫码枪COM口(如COM3),空则不启用 + /// 工位1扫码枪COM口(如COM3),空则不启用 /// - public static string OP10BarCOM = AppSettings["OP10BarCOM"] ?? ""; + public static string Station1BarCOM = AppSettings["Station1BarCOM"] ?? ""; /// - /// OP20扫码枪COM口(如COM4),空则不启用 + /// 工位2扫码枪COM口(如COM4),空则不启用 /// - public static string OP20BarCOM = AppSettings["OP20BarCOM"] ?? ""; + public static string Station2BarCOM = AppSettings["Station2BarCOM"] ?? ""; /// /// 扫码枪波特率 /// diff --git a/SCADA/Core/BarcodeManager.cs b/SCADA/Core/BarcodeManager.cs index 46b89cb..e52e772 100644 --- a/SCADA/Core/BarcodeManager.cs +++ b/SCADA/Core/BarcodeManager.cs @@ -10,7 +10,7 @@ namespace MesWork public static class BarcodeManager { /// - /// 扫码枪实例字典,key = opName(OP10/OP20) + /// 扫码枪实例字典,key = opName /// public static Dictionary Scanners { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -33,27 +33,24 @@ namespace MesWork int baudRate = MesWorkForm.BarcodeBaudRate; - // OP10 - string op10Com = MesWorkForm.OP10BarCOM?.Trim(); - if (!string.IsNullOrEmpty(op10Com)) + InitScanner(MesWorkForm.Station1OpName, MesWorkForm.Station1BarCOM, baudRate); + InitScanner(MesWorkForm.Station2OpName, MesWorkForm.Station2BarCOM, baudRate); + } + + private static void InitScanner(string opName, string comPort, int baudRate) + { + opName = opName?.Trim(); + comPort = comPort?.Trim(); + if (string.IsNullOrEmpty(opName) || string.IsNullOrEmpty(comPort)) { - var scanner = new BarcodeScanner("OP10", baudRate); - scanner.BarcodeReceived += HandleBarcodeReceived; - scanner.Log += HandleLog; - Scanners["OP10"] = scanner; - scanner.Connect(op10Com); + return; } - // OP20 - string op20Com = MesWorkForm.OP20BarCOM?.Trim(); - if (!string.IsNullOrEmpty(op20Com)) - { - var scanner = new BarcodeScanner("OP20", baudRate); - scanner.BarcodeReceived += HandleBarcodeReceived; - scanner.Log += HandleLog; - Scanners["OP20"] = scanner; - scanner.Connect(op20Com); - } + var scanner = new BarcodeScanner(opName, baudRate); + scanner.BarcodeReceived += HandleBarcodeReceived; + scanner.Log += HandleLog; + Scanners[opName] = scanner; + scanner.Connect(comPort); } /// diff --git a/SCADA/Funtion/MIS_Funtion.cs b/SCADA/Funtion/MIS_Funtion.cs index 6764166..60bfc97 100644 --- a/SCADA/Funtion/MIS_Funtion.cs +++ b/SCADA/Funtion/MIS_Funtion.cs @@ -134,18 +134,24 @@ namespace MesWork // ==================================================================== // 称重交互核心方法 // ==================================================================== - /// - /// 获取称重类型:地面/放油前/放油后 - /// Ground模式:统一返回"地面" - /// Hanging模式:OP10=放油前,OP20=放油后 - /// - private string GetWeighingType(string opName) - { - if (WeighingType == "Ground") - return "地面"; - // Hanging模式 - return opName == "OP10" ? "放油前" : "放油后"; - } + /// + /// 获取称重类型:地面/放油前/放油后 + /// Ground模式:统一返回"地面" + /// Hanging模式:工位1=放油前,工位2=放油后 + /// + private string GetWeighingType(string opName) + { + if (WeighingType == "Ground") + return "地面"; + + if (string.Equals(opName, Station1OpName, StringComparison.OrdinalIgnoreCase)) + return "放油前"; + + if (string.Equals(opName, Station2OpName, StringComparison.OrdinalIgnoreCase)) + return "放油后"; + + throw new InvalidOperationException($"工位号[{opName}]未匹配到App.config中的Station1OpName/Station2OpName,请检查工位配置"); + } /// @@ -422,7 +428,7 @@ namespace MesWork } else { - // 找不到放油前记录(可能直接进OP20):创建一条放油后记录并标记完成 + // 找不到放油前记录(可能直接进放油后工位):创建一条放油后记录并标记完成 curveWeighingRecordId = B_DB_Opera.InsertWeighingRecord(opName, "空中放油后", engineNo, "", "", "", 0, weight, 0, 0, 0, 0, 0, 0, 0, 2, waterContent, opName, Curr_UserName, isComplete: 1); // 异常兜底记录,质量直接判不合格 @@ -458,7 +464,7 @@ namespace MesWork /// 扫码枪扫码完成后的业务处理 /// 将码值写入PLC地址102500,触发完成信号100016=1,1秒后复位 /// - /// 工位号(OP10/OP20),由COM口绑定决定 + /// 工位号,由COM口绑定决定 /// 扫到的条码值 public void Barcode_HandleScan(string opName, string barcode) { diff --git a/SCADA/MainGuide/MW.OnStart.cs b/SCADA/MainGuide/MW.OnStart.cs index a9679f6..8288413 100644 --- a/SCADA/MainGuide/MW.OnStart.cs +++ b/SCADA/MainGuide/MW.OnStart.cs @@ -1,44 +1,44 @@ -using DC_A95; -using ExternalDataSync; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Data; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Forms; -using SystemFramework; -using WebApi; - -namespace MesWork -{ - /// - /// 程式启动 - /// - public partial class MesWorkForm - { - /// - /// 从这里启动 - /// - /// - protected override void OnShown(EventArgs e) - { - } - - public void OnStart(params object[] o) - { - //【1】系统基本参数设定 - ThreadPool.SetMaxThreads(workerThreads, completionPortThreads); - Never_Know.Hello_You_All_Never_Know = Hello_You_All_Never_Know; - - // 加载信号表(按设备类型对应表展开多工位) - var (dt_Tag_Mes, dt_Device) = BuildSignalTable(BasicDataTableFile); - - // 保存工位名称列表及显示名映射(供UC_Weighing标题使用) - StationOpNames = new System.Collections.Generic.List(); - StationDisplayNames = new System.Collections.Generic.Dictionary(System.StringComparer.OrdinalIgnoreCase); - int stIdx = 1; +using DC_A95; +using ExternalDataSync; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using SystemFramework; +using WebApi; + +namespace MesWork +{ + /// + /// 程式启动 + /// + public partial class MesWorkForm + { + /// + /// 从这里启动 + /// + /// + protected override void OnShown(EventArgs e) + { + } + + public void OnStart(params object[] o) + { + //【1】系统基本参数设定 + ThreadPool.SetMaxThreads(workerThreads, completionPortThreads); + Never_Know.Hello_You_All_Never_Know = Hello_You_All_Never_Know; + + // 加载信号表(按设备类型对应表展开多工位) + var (dt_Tag_Mes, dt_Device) = BuildSignalTable(BasicDataTableFile); + + // 保存工位名称列表及显示名映射(供UC_Weighing标题使用) + StationOpNames = new System.Collections.Generic.List(); + StationDisplayNames = new System.Collections.Generic.Dictionary(System.StringComparer.OrdinalIgnoreCase); + int stIdx = 1; foreach (System.Data.DataRow row in dt_Device.Rows) { string opName = row["工位号"].ToString().Trim(); @@ -48,87 +48,117 @@ namespace MesWork StationDisplayNames[opName] = $"{opName}-{dataSource}"; stIdx++; } + ValidateStationConfig(); LoadOPCData(dt_Tag_Mes, dt_Device, IsDemoMesServer, IsWriteMonitorLog, true, false, out string error); - if (error.Length > 0) - { - MessageBox.Show($"加载信号产生错误,程序不能启动!!错误:{error}"); - Process.GetCurrentProcess().Kill(); - } - - Thread.Sleep(200); - StartServer(); - Thread.Sleep(200); - First_TagMonitor(); - - var task1 = new Thread(new ThreadStart(Loop_SelectAlarmShow)); - task1.IsBackground = true; - task1.Start(); - - // Loop_ReadRealPageShow 已移除,PLC信号显示将在 UC_Weighing 中实现 - // var task2 = new Thread(new ThreadStart(Loop_ReadRealPageShow)); - // task2.IsBackground = true; - // task2.Start(); - - - initServer = new InitServer(MesWorkForm.WebApi_Port); - + if (error.Length > 0) + { + MessageBox.Show($"加载信号产生错误,程序不能启动!!错误:{error}"); + Process.GetCurrentProcess().Kill(); + } + + Thread.Sleep(200); + StartServer(); + Thread.Sleep(200); + First_TagMonitor(); + + var task1 = new Thread(new ThreadStart(Loop_SelectAlarmShow)); + task1.IsBackground = true; + task1.Start(); + + // Loop_ReadRealPageShow 已移除,PLC信号显示将在 UC_Weighing 中实现 + // var task2 = new Thread(new ThreadStart(Loop_ReadRealPageShow)); + // task2.IsBackground = true; + // task2.Start(); + + + initServer = new InitServer(MesWorkForm.WebApi_Port); + B_DB_Opera.SaveLog_Request(Curr_Station, Log_Type.ZK_Login, "", Log_FromAndTo.ZK, Log_FromAndTo.ZK, $"称重系统启动成功!WebPort:[{MesWorkForm.WebApi_Port}]", out long AID); } - - - /// - /// 构建信号表:读取Excel模板,按「设备类型对应表」的工位配置展开 - /// 每个工位独立克隆一份模板,TagID加工位号前缀(如 OP10_TAG_0000001), - /// 并填充对应的 工位号、数据来源、IP、DB + /// 校验App.config中的逻辑工位必须能匹配Excel启用工位,避免工位号配错后继续运行。 /// - /// 信号表Excel文件路径 - /// (展开后的信号表, 设备类型对应表) - private static (DataTable dtTagMes, DataTable dtDevice) BuildSignalTable(string excelFile) + private static void ValidateStationConfig() { - // 读取设备类型对应表(所有启用的工位) - var dtDevice = NPOITest.ExeclHelper.ExcelToDataTable(excelFile, "设备类型对应表", true) - .Select("是否启用='1'").CopyToDataTable(); - - // 读取 MES_基本变量原始数据 模板(取全部启用行作为模板) - var dtTemplate = NPOITest.ExeclHelper.ExcelToDataTable(excelFile, "MES_基本变量原始数据", true) - .Select("是否启用='1'").CopyToDataTable(); - - // 按工位数量克隆模板 - var dtTagMes = dtTemplate.Clone(); - foreach (DataRow devRow in dtDevice.Rows) + string station1 = Station1OpName?.Trim(); + string station2 = Station2OpName?.Trim(); + if (string.IsNullOrWhiteSpace(station1) || string.IsNullOrWhiteSpace(station2)) { - string stationNo = devRow["工位号"].ToString().Trim(); // OP10, OP20 - string dataSource = devRow["数据来源"].ToString().Trim(); // 称重位1, 称重位2 - string deviceIP = devRow["设备IP"].ToString().Trim(); // 192.168.0.1 - string deviceDB = devRow["DB"].ToString().Trim(); // DB1310, DB1311 - - // 提取纯DB号 ("DB1310" → "1310",若本身是数字则保持) - //string dbNumber = deviceDB.StartsWith("DB", StringComparison.OrdinalIgnoreCase) - // ? deviceDB.Substring(2) : deviceDB; - string dbNumber = deviceDB; - - foreach (DataRow tplRow in dtTemplate.Rows) - { - var newRow = dtTagMes.NewRow(); - for (int c = 0; c < dtTemplate.Columns.Count; c++) - newRow[c] = tplRow[c]; - - // 覆盖关键字段 - newRow["TagID"] = $"{stationNo}_{tplRow["TagID"].ToString().Trim()}"; - newRow["工位号"] = stationNo; - newRow["数据来源"] = dataSource; - newRow["IP"] = deviceIP; - newRow["DBName"] = dbNumber; - - dtTagMes.Rows.Add(newRow); - } + MessageBox.Show("App.config未配置Station1OpName或Station2OpName,程序不能启动。"); + Process.GetCurrentProcess().Kill(); } - return (dtTagMes, dtDevice); + if (string.Equals(station1, station2, StringComparison.OrdinalIgnoreCase)) + { + MessageBox.Show($"App.config中Station1OpName和Station2OpName不能相同,当前均为[{station1}],程序不能启动。"); + Process.GetCurrentProcess().Kill(); + } + + bool hasStation1 = StationOpNames.Exists(x => string.Equals(x, station1, StringComparison.OrdinalIgnoreCase)); + bool hasStation2 = StationOpNames.Exists(x => string.Equals(x, station2, StringComparison.OrdinalIgnoreCase)); + if (!hasStation1 || !hasStation2) + { + string excelStations = string.Join("、", StationOpNames); + MessageBox.Show($"App.config工位配置与SignalTable_CZ.xlsx不一致,程序不能启动。\r\nStation1OpName={station1}\r\nStation2OpName={station2}\r\nExcel启用工位={excelStations}"); + Process.GetCurrentProcess().Kill(); + } } - } -} + + + + /// + /// 构建信号表:读取Excel模板,按「设备类型对应表」的工位配置展开 + /// 每个工位独立克隆一份模板,TagID加工位号前缀(如 OP10_TAG_0000001), + /// 并填充对应的 工位号、数据来源、IP、DB + /// + /// 信号表Excel文件路径 + /// (展开后的信号表, 设备类型对应表) + private static (DataTable dtTagMes, DataTable dtDevice) BuildSignalTable(string excelFile) + { + // 读取设备类型对应表(所有启用的工位) + var dtDevice = NPOITest.ExeclHelper.ExcelToDataTable(excelFile, "设备类型对应表", true) + .Select("是否启用='1'").CopyToDataTable(); + + // 读取 MES_基本变量原始数据 模板(取全部启用行作为模板) + var dtTemplate = NPOITest.ExeclHelper.ExcelToDataTable(excelFile, "MES_基本变量原始数据", true) + .Select("是否启用='1'").CopyToDataTable(); + + // 按工位数量克隆模板 + var dtTagMes = dtTemplate.Clone(); + foreach (DataRow devRow in dtDevice.Rows) + { + string stationNo = devRow["工位号"].ToString().Trim(); // OP10, OP20 + string dataSource = devRow["数据来源"].ToString().Trim(); // 称重位1, 称重位2 + string deviceIP = devRow["设备IP"].ToString().Trim(); // 192.168.0.1 + string deviceDB = devRow["DB"].ToString().Trim(); // DB1310, DB1311 + + // 提取纯DB号 ("DB1310" → "1310",若本身是数字则保持) + //string dbNumber = deviceDB.StartsWith("DB", StringComparison.OrdinalIgnoreCase) + // ? deviceDB.Substring(2) : deviceDB; + string dbNumber = deviceDB; + + foreach (DataRow tplRow in dtTemplate.Rows) + { + var newRow = dtTagMes.NewRow(); + for (int c = 0; c < dtTemplate.Columns.Count; c++) + newRow[c] = tplRow[c]; + + // 覆盖关键字段 + newRow["TagID"] = $"{stationNo}_{tplRow["TagID"].ToString().Trim()}"; + newRow["工位号"] = stationNo; + newRow["数据来源"] = dataSource; + newRow["IP"] = deviceIP; + newRow["DBName"] = dbNumber; + + dtTagMes.Rows.Add(newRow); + } + } + + return (dtTagMes, dtDevice); + } + + } +} diff --git a/SCADA/Pages/UC_SystemSettings.cs b/SCADA/Pages/UC_SystemSettings.cs index bdf5e0c..1b0d5f8 100644 --- a/SCADA/Pages/UC_SystemSettings.cs +++ b/SCADA/Pages/UC_SystemSettings.cs @@ -10,13 +10,13 @@ namespace MesWork.Pages /// public partial class UC_SystemSettings : UserControl { - // OP10 控件 + // 工位1控件 private ComboBox cmb_Com1; private Button btn_Connect1, btn_Disconnect1, btn_ManualSend1; private Label lbl_Status1, lbl_ScanTime1; private TextBox txt_Barcode1; - // OP20 控件 + // 工位2控件 private ComboBox cmb_Com2; private Button btn_Connect2, btn_Disconnect2, btn_ManualSend2; private Label lbl_Status2, lbl_ScanTime2; @@ -26,19 +26,26 @@ namespace MesWork.Pages { InitializeComponent(); + string station1 = MesWorkForm.Station1OpName; + string station2 = MesWorkForm.Station2OpName; + grp_Station1.Text = $" 工位1({station1}) "; + grp_Station2.Text = $" 工位2({station2}) "; + grp_Scanner1.Text = $" {station1} 扫码枪 "; + grp_Scanner2.Text = $" {station2} 扫码枪 "; + if (BarcodeManager.IsEnabled) { - BuildScannerPanel(grp_Scanner1, "OP10", ref cmb_Com1, ref lbl_Status1, ref txt_Barcode1, ref lbl_ScanTime1, + BuildScannerPanel(grp_Scanner1, station1, ref cmb_Com1, ref lbl_Status1, ref txt_Barcode1, ref lbl_ScanTime1, ref btn_Connect1, ref btn_Disconnect1, ref btn_ManualSend1); - BuildScannerPanel(grp_Scanner2, "OP20", ref cmb_Com2, ref lbl_Status2, ref txt_Barcode2, ref lbl_ScanTime2, + BuildScannerPanel(grp_Scanner2, station2, ref cmb_Com2, ref lbl_Status2, ref txt_Barcode2, ref lbl_ScanTime2, ref btn_Connect2, ref btn_Disconnect2, ref btn_ManualSend2); timer_Refresh.Start(); } else { - BuildScannerPanel(grp_Scanner1, "OP10", ref cmb_Com1, ref lbl_Status1, ref txt_Barcode1, ref lbl_ScanTime1, + BuildScannerPanel(grp_Scanner1, station1, ref cmb_Com1, ref lbl_Status1, ref txt_Barcode1, ref lbl_ScanTime1, ref btn_Connect1, ref btn_Disconnect1, ref btn_ManualSend1); - BuildScannerPanel(grp_Scanner2, "OP20", ref cmb_Com2, ref lbl_Status2, ref txt_Barcode2, ref lbl_ScanTime2, + BuildScannerPanel(grp_Scanner2, station2, ref cmb_Com2, ref lbl_Status2, ref txt_Barcode2, ref lbl_ScanTime2, ref btn_Connect2, ref btn_Disconnect2, ref btn_ManualSend2); grp_Scanner1.Enabled = false; grp_Scanner2.Enabled = false; @@ -182,12 +189,12 @@ namespace MesWork.Pages private async void btn_WeightClear1_Click(object sender, EventArgs e) { - await DoWeightClearAsync("OP10", btn_WeightClear1); + await DoWeightClearAsync(MesWorkForm.Station1OpName, btn_WeightClear1); } private async void btn_WeightClear2_Click(object sender, EventArgs e) { - await DoWeightClearAsync("OP20", btn_WeightClear2); + await DoWeightClearAsync(MesWorkForm.Station2OpName, btn_WeightClear2); } private async Task DoWeightClearAsync(string opName, Button btn) @@ -230,8 +237,8 @@ namespace MesWork.Pages private void timer_Refresh_Tick(object sender, EventArgs e) { - RefreshScannerStatus("OP10", lbl_Status1, txt_Barcode1, lbl_ScanTime1); - RefreshScannerStatus("OP20", lbl_Status2, txt_Barcode2, lbl_ScanTime2); + RefreshScannerStatus(MesWorkForm.Station1OpName, lbl_Status1, txt_Barcode1, lbl_ScanTime1); + RefreshScannerStatus(MesWorkForm.Station2OpName, lbl_Status2, txt_Barcode2, lbl_ScanTime2); } private void RefreshScannerStatus(string opName, Label lblStatus, TextBox txtBar, Label lblTime)