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)