fg_yida_2/YiDa_WinForm/MainForm.cs

1019 lines
38 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using YiDa_WinForm.Model;
using Newtonsoft.Json;
using NPOI.SS.UserModel;
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;
using MQTT_WinformV1.Service;
using YiDa_WinForm.Config;
using YiDa_WinForm.Service.Mqtt;
namespace YiDa_WinForm
{
public partial class MainForm : Form
{
// 依赖注入
private readonly MqttClientService _mqttService;
private readonly YiDaUploadService _uploadService;
private readonly ButtonOperationService _buttonService;
// 配方配置
private DataTable _formula; // 配方缓存
private DataTable _immFormulaDic;
private DataTable _tcFormulaDic;
private List<DataRow> _formulaList1; // 设备1选择的配方
private List<DataRow> _formulaList2; // 设备2选择的配方
private System.Timers.Timer _timer;
// 日志文件相关路径
private readonly string _logDirectory = "log";
private string _currentLogFile;
private DateTime _lastLogDate = DateTime.MinValue;
// ======================================== 初始化相关方法 ========================================
/// <summary>
/// 构造器
/// </summary>
public MainForm()
{
// 初始化设计器方法
InitializeComponent();
_mqttService = new MqttClientService();
_buttonService = new ButtonOperationService();
_uploadService = new YiDaUploadService();
_mqttService.MessageReceived += OnMqttMessage;
_formula = new DataTable();
_immFormulaDic = new DataTable();
_tcFormulaDic = new DataTable();
buttonDisconnect.Enabled = false;
// 初始化日志目录
InitializeLogDirectory();
}
/// <summary>
/// 初始化日志目录
/// </summary>
private void InitializeLogDirectory()
{
if (!Directory.Exists(_logDirectory))
{
Directory.CreateDirectory(_logDirectory);
}
UpdateLogFile();
}
/// <summary>
/// 更新当前日志文件(每日一个新文件)
/// </summary>
private void UpdateLogFile()
{
DateTime today = DateTime.Now.Date;
if (today != _lastLogDate)
{
_lastLogDate = today;
_currentLogFile = Path.Combine(_logDirectory, $"log_{today:yyyyMMdd}.txt");
}
}
/// <summary>
/// 加载MainForm信息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void Form1_Load(object sender, EventArgs e)
{
try
{
MakePanelRound(panelLed);
await LoadFormula();
await LoadInjectionMqttDic();
await LoadTemperatureMqttDic();
timer1.Enabled = true;
}
catch (Exception ex)
{
AppendLog($"初始化失败:{ex.Message}");
}
}
/// <summary>
/// 将指定 Panel 变成圆形
/// </summary>
/// <param name="panel"></param>
private static void MakePanelRound(Panel panel)
{
int size = Math.Min(panel.Width, panel.Height);
panel.Size = new Size(size, size);
GraphicsPath path = new GraphicsPath();
path.AddEllipse(0, 0, panel.Width, panel.Height);
panel.Region = new Region(path);
}
/// <summary>
/// 加载配方
/// </summary>
private async Task LoadFormula()
{
// 从数据库查询配方信息
DataTable dt = await _buttonService.QueryFormulaAsync();
if (dt != null && dt.Rows.Count > 0)
{
// 新增列用于拼接 part_number|part_name
if (!dt.Columns.Contains("part_number_name"))
dt.Columns.Add("part_number_name", typeof(string));
foreach (DataRow row in dt.Rows)
{
row["part_number_name"] = row["part_number"].ToString() + "|" + row["part_name"].ToString();
}
// 使用 LINQ 去重,按 part_number + part_name
var uniqueParts = dt.AsEnumerable()
.GroupBy(r => r["part_number_name"].ToString())
.Select(g => g.First())
.ToList();
// 新建 DataTable 用于绑定下拉框
DataTable dtUnique = dt.Clone(); // 保留原有列
foreach (var row in uniqueParts)
{
dtUnique.ImportRow(row);
}
// 新建空白行
DataRow drNew = dtUnique.NewRow();
drNew["id"] = -1;
drNew["part_number_name"] = ""; // 空行值
dtUnique.Rows.InsertAt(drNew, 0);
_formula = dt; // 原始配方表(多行)
bsPF.DataSource = dtUnique;
bsPF2.DataSource = dtUnique;
comboBox1.DisplayMember = "part_number_name"; // 显示“零件号|零件名”
comboBox1.ValueMember = "part_number_name";
comboBox2.DisplayMember = "part_number_name";
comboBox2.ValueMember = "part_number_name";
// 自定义显示格式:显示“零件号 - 零件名”
comboBox1.Format += (s, e) =>
{
if (e.ListItem is DataRowView drv)
{
e.Value = string.IsNullOrEmpty(drv["part_number_name"].ToString())
? ""
: drv["part_number"].ToString() + " - " + drv["part_name"].ToString();
}
};
comboBox2.Format += (s, e) =>
{
if (e.ListItem is DataRowView drv)
{
e.Value = string.IsNullOrEmpty(drv["part_number_name"].ToString())
? ""
: drv["part_number"].ToString() + " - " + drv["part_name"].ToString();
}
};
}
}
/// <summary>
/// 加载注塑机MQTT字典
/// </summary>
private async Task LoadInjectionMqttDic()
{
DataTable dt = await _buttonService.InitInjectionMqttDic();
if (dt != null)
{
_immFormulaDic = dt;
}
}
/// <summary>
/// 加载温控器MQTT字典
/// </summary>
private async Task LoadTemperatureMqttDic()
{
DataTable dt = await _buttonService.InitTemperatureMqttDic();
if (dt != null)
{
_tcFormulaDic = dt;
}
}
// ======================================== 按钮相关方法 ========================================
/// <summary>
/// 网关连接按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void buttonConnect_Click(object sender, EventArgs e)
{
try
{
AppendLog("正在连接MQTT服务器...");
await _mqttService.MqttClientStartAsync();
AppendLog("连接成功!");
panelLed.BackColor = Color.Green;
toolStripStatusLabel1.Text = "已连接";
buttonConnect.Enabled = false;
buttonDisconnect.Enabled = true;
}
catch (Exception ex)
{
panelLed.BackColor = Color.Red;
AppendLog($"连接失败:{ex.Message}");
toolStripStatusLabel1.Text = "连接失败";
}
}
/// <summary>
/// 网关断开按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void buttonDisconnect_Click(object sender, EventArgs e)
{
try
{
await _mqttService.MqttClientStopAsync();
AppendLog("已断开连接");
panelLed.BackColor = Color.Red;
toolStripStatusLabel1.Text = "未连接";
buttonConnect.Enabled = true;
buttonDisconnect.Enabled = false;
}
catch (Exception ex)
{
AppendLog($"无法断开连接:{ex.Message}");
}
}
/// <summary>
/// 关闭MainForm按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void MainFormClosing(object sender, FormClosingEventArgs e)
{
try
{
await _mqttService.MqttClientStopAsync();
}
catch (Exception ex)
{
AppendLog($"关闭窗口失败:{ex.Message}");
}
}
/// <summary>
/// 配方导入按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void button1_Click(object sender, EventArgs e)
{
try
{
//弹出文件选择窗口
OpenFileDialog openFile = new OpenFileDialog();
if (openFile.ShowDialog() == DialogResult.OK)
{
string filePath = openFile.FileName;
DataTable excelDt = GetExcel(filePath);
if (excelDt != null && excelDt.Rows.Count > 0)
{
await _buttonService.SaveFormulaByExcel(excelDt);
await LoadFormula();
MessageBox.Show("配方信息已导入!");
}
else
{
MessageBox.Show("不允许导入空表!");
}
}
}
catch (Exception ex)
{
AppendLog($"配方导入失败:{ex.Message}");
}
}
/// <summary>
/// 上传宜搭按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void button2_Click(object sender, EventArgs e)
{
try
{
// 如果 MQTT 没连接,就不允许上传
if (toolStripStatusLabel1.Text != "已连接")
{
MessageBox.Show("请先连接MQTT网关");
return;
}
if (this.comboBox1.Text.Length == 0 && this.comboBox2.Text.Length == 0)
{
//如果两个下拉框都还没数据,说明没导入过配方,直接中止。
MessageBox.Show("请先导入配方信息,再刷新!");
return;
}
this.button2.Enabled = false;
// 设备1选择配方
string selected1 = this.comboBox1.SelectedValue?.ToString();
if (string.IsNullOrEmpty(selected1) || selected1 == "-1")
{
_formulaList1 = null;
}
else
{
string[] arr1 = selected1.Split('|');
if (arr1.Length == 2)
{
string partNumber1 = arr1[0];
string partName1 = arr1[1];
_formulaList1 = _formula.AsEnumerable()
.Where(r => r.Field<string>("part_number") == partNumber1
&& r.Field<string>("part_name") == partName1)
.ToList();
}
else
{
_formulaList1 = null;
}
}
// 设备2选择配方
string selected2 = this.comboBox2.SelectedValue?.ToString();
if (string.IsNullOrEmpty(selected2) || selected2 == "-1")
{
_formulaList2 = null;
}
else
{
string[] arr2 = selected2.Split('|');
if (arr2.Length == 2)
{
string partNumber2 = arr2[0];
string partName2 = arr2[1];
_formulaList2 = _formula.AsEnumerable()
.Where(r => r.Field<string>("part_number") == partNumber2
&& r.Field<string>("part_name") == partName2)
.ToList();
}
else
{
_formulaList2 = null;
}
}
double seconds;
if (!double.TryParse(txtLUploadPL.Text, out seconds) || seconds <= 0)
{
seconds = 10; //控制上传间隔默认10秒。
}
// 立即上传一次
await MqttYiDaUpload();
_timer = new System.Timers.Timer(seconds * 1000);
_timer.Elapsed += async (s, evt) => { await MqttYiDaUpload(); };
_timer.AutoReset = true; // 是否重复
_timer.Enabled = true; // 开始计时
}
catch (Exception ex)
{
this.button2.Enabled = true;
AppendLog($"上传宜搭失败:{ex.Message}");
}
}
/// <summary>
/// 刷新配方
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnRefresh_Click(object sender, EventArgs e)
{
LoadFormula();
}
/// <summary>
/// 中止上传按钮
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button3_Click(object sender, EventArgs e)
{
this.button2.Enabled = true;
if (this._timer != null)
{
this._timer.Enabled = false;
}
AppendLog("停止上传数据");
MessageBox.Show("待程序完成后,将停止自动上传", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
/// <summary>
/// 刷新秒数
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void txtLUploadPL_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Back)
{
e.Handled = false;
return;
}
if (char.IsDigit(e.KeyChar))
{
e.Handled = false;
}
else if (e.KeyChar == '.' && !txtLUploadPL.Text.Contains("."))
{
e.Handled = false;
}
else
{
e.Handled = true;
}
}
/// <summary>
/// 更新时间
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void timer1_Tick(object sender, EventArgs e)
{
// 每秒更新一次时间显示
this.label4.Text = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
}
// ======================================== 工具方法 ========================================
// <summary>
/// 获取Excel到Datatable中
/// </summary>
/// <param name="filePath">Excel路径</param>
/// <returns>返回DataTable数据</returns>
private static DataTable GetExcel(string filePath)
{
IWorkbook iwkX;
using (FileStream fs = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
iwkX = WorkbookFactory.Create(fs);
fs.Close();
}
//sheet
DataTable dt = new DataTable();
for (int h = 0; h < iwkX.NumberOfSheets; h++)
{
ISheet sheet = iwkX.GetSheetAt(h);
var rows = sheet.GetRowEnumerator();
bool isMove = rows.MoveNext();
//循环sheet
if (isMove)
{
var Cols = (IRow)rows.Current;
dt.TableName = sheet.SheetName;
for (int i = 0; i < Cols.LastCellNum; i++)
{
string str = Cols.GetCell(i).ToString();
dt.Columns.Add(Cols.GetCell(i).ToString());
}
while (rows.MoveNext())
{
var row = (IRow)rows.Current;
var dr = dt.NewRow();
for (int i = 0; i < row.LastCellNum; i++)
{
var cell = row.GetCell(i);
if (cell == null)
{
dr[i] = "";
}
else
{
string strdr = cell.ToString();
dr[i] = cell.ToString();
}
}
dt.Rows.Add(dr);
}
}
}
return dt;
}
/// <summary>
/// 上传后续
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void _timer_Tick(object sender, ElapsedEventArgs e)
{
MqttYiDaUpload();
AppendLog("宜搭数据已上传!");
}
/// <summary>
/// 上传宜搭方法
/// </summary>
private async Task MqttYiDaUpload()
{
// 1. 查询4个设备的最新MQTT数据
DataTable mqttData = await _buttonService.GetLatestMqttDataAsync();
if (mqttData == null || mqttData.Rows.Count == 0)
{
AppendLog("未查询到任何设备的MQTT数据跳过上传");
return;
}
// 存储所有设备的Model后续按part_number排序
List<MqttModel> allMqttModels = new List<MqttModel>();
List<YiDaModel> allYiDaModels = new List<YiDaModel>();
// 2. 遍历4个设备的每条数据逐个参数生成Model
foreach (DataRow row in mqttData.Rows)
{
string deviceCode = row["device_code"].ToString();
if (string.IsNullOrWhiteSpace(deviceCode))
{
AppendLog($"发现空设备编码数据,跳过");
continue;
}
// ========== 设备基础配置 ==========
List<DataRow> formulaList = null;
string site = null;
DeviceType deviceType = DeviceType.InjectionMoldingMachine;
DataTable currentFormulaDic = null;
// 按设备编码分配配置
switch (deviceCode)
{
case "device1":
formulaList = _formulaList1;
site = "1号注塑机";
deviceType = DeviceType.InjectionMoldingMachine;
currentFormulaDic = _immFormulaDic;
break;
case "device2":
formulaList = _formulaList2;
site = "2号注塑机";
deviceType = DeviceType.InjectionMoldingMachine;
currentFormulaDic = _immFormulaDic;
break;
case "device3":
formulaList = _formulaList1;
site = "1号温控器";
deviceType = DeviceType.TemperatureController;
currentFormulaDic = _tcFormulaDic;
break;
case "device4":
formulaList = _formulaList2;
site = "2号温控器";
deviceType = DeviceType.TemperatureController;
currentFormulaDic = _tcFormulaDic;
break;
default:
AppendLog($"未知设备编码:{deviceCode},跳过该设备数据");
continue;
}
// 校验配方和字典表
if (formulaList == null || formulaList.Count == 0)
{
AppendLog($"设备{deviceCode}未选择配方,跳过该设备");
continue;
}
if (currentFormulaDic == null || currentFormulaDic.Rows.Count == 0)
{
AppendLog($"设备{deviceCode}字典表为空,跳过该设备");
continue;
}
// ========== 反序列化MQTT数据 ==========
string receiveData = row["receive_data"].ToString();
if (string.IsNullOrWhiteSpace(receiveData))
{
AppendLog($"设备{deviceCode}的receive_data为空跳过该设备");
continue;
}
object dataObj = null;
try
{
if (deviceType == DeviceType.InjectionMoldingMachine)
{
// device1/2反序列化为注塑机模型
dataObj = JsonConvert.DeserializeObject<ImmDataModel>(receiveData);
}
else
{
// device3/4反序列化为温控器模型
dataObj = JsonConvert.DeserializeObject<TcDataModel>(receiveData);
}
}
catch (Exception ex)
{
AppendLog($"设备{deviceCode}反序列化失败:{ex.Message},原始数据:{receiveData}");
continue;
}
// ========== 解析参数(注塑机多参数/温控器PV ==========
Dictionary<string, string> paramDict = new Dictionary<string, string>();
if (deviceType == DeviceType.InjectionMoldingMachine)
{
ImmDataModel immData = dataObj as ImmDataModel;
paramDict = ParseImmParams(immData?.@params);
}
else
{
TcDataModel tcData = dataObj as TcDataModel;
paramDict = ParseTcParams(tcData?.@params); // 仅解析PV参数
}
if (paramDict.Count == 0)
{
AppendLog($"设备{deviceCode}无有效参数(注塑机参数为空/温控器PV为空跳过该设备");
continue;
}
// ========== 逐个参数生成Model ==========
foreach (var kvp in paramDict)
{
string paramCode = kvp.Key; // 原始参数编码PV/Alarm/T1等
string paramValue = kvp.Value; // 参数值
// 1. 查字典表获取中文参数名
DataRow[] drs = currentFormulaDic.Select($"param_code = '{paramCode}'");
string paramName = paramCode;
if (drs != null && drs.Length > 0)
{
paramName = drs[0]["param_name"].ToString();
}
else
{
AppendLog($"设备{deviceCode}参数{paramCode}无字典映射,使用原编码作为参数名");
}
// 2. 匹配配方数据
DataRow drMatch = formulaList.FirstOrDefault(r =>
r.Field<string>("parameter_name").Equals(paramName, StringComparison.OrdinalIgnoreCase) ||
r.Field<string>("parameter_name").Equals(paramCode, StringComparison.OrdinalIgnoreCase));
if (drMatch == null)
{
AppendLog($"设备{deviceCode}配方中未找到参数[{paramCode}/{paramName}],跳过该参数");
continue;
}
// 3. 生成MqttModel单个参数
MqttModel mqttModel = new MqttModel
{
SupplierCode = drMatch["supplier_code"].ToString(),
SupplierName = drMatch["supplier_name"].ToString(),
VehicleModel = drMatch["vehicle_model"].ToString(),
PartNumber = drMatch["part_number"].ToString(), // 排序依据
PartName = drMatch["part_name"].ToString(),
Configuration = drMatch["configuration"]?.ToString() ?? "",
ParameterName = paramName,
ParameterValue = paramValue,
ToleranceLower = drMatch["tolerance_lower"].ToString(),
ToleranceUpper = drMatch["tolerance_upper"].ToString(),
IsQualification = GetQualificationResult(deviceType, paramName, paramValue, drMatch),
LeaderPart = drMatch["leader_part"].ToString(),
WorkStation = site,
LeaderOutProtection = drMatch["leader_out_protection"].ToString()
};
// 4. 生成YiDaModel单个参数
YiDaModel yiDaModel = new YiDaModel
{
textField_mha98neu = drMatch["supplier_code"].ToString(),
textField_mha98nev = drMatch["supplier_name"].ToString(),
textField_mha98new = drMatch["vehicle_model"].ToString(),
textField_mha98nex = drMatch["part_number"].ToString(), // 排序依据
textField_mha98ney = drMatch["part_name"].ToString(),
textField_mha98nez = drMatch["configuration"]?.ToString() ?? "",
textField_mha98nf0 = site,
textField_mha98nf1 = paramName,
textField_mhx44i2i = paramValue,
textField_mhx44i2j = drMatch["tolerance_lower"].ToString(),
textField_mhx44i2k = drMatch["tolerance_upper"].ToString(),
textField_mha98nf5 = mqttModel.IsQualification,
textField_mhlvt8ht = DateTimeOffset.Now.ToUnixTimeMilliseconds(),
textField_mha98nf7 = drMatch["leader_part"].ToString(),
textField_mha98nfh = drMatch["leader_out_protection"].ToString(),
// 其他字段赋空值
textField_mha98nf8 = "",
textField_mha98nf9 = "",
textField_mha98nfa = "",
textField_mha98nfb = "",
textField_mha98nfc = "",
textField_mha98nfd = "",
imageField_mii5s85z = "",
textField_mha98nff = "",
textField_mha98nfg = ""
};
// 5. 添加到总列表
allMqttModels.Add(mqttModel);
allYiDaModels.Add(yiDaModel);
}
}
// ========== 核心按part_number排序升序 ==========
if (allMqttModels.Count > 0 && allYiDaModels.Count > 0)
{
// 按part_number升序排序保证两个列表排序一致
var sortedModels = allMqttModels
.Select((mqtt, index) => new { Mqtt = mqtt, YiDa = allYiDaModels[index] })
.OrderBy(item => item.Mqtt.PartNumber) // 按part_number升序
.ToList();
// 重新赋值排序后的列表
allMqttModels = sortedModels.Select(item => item.Mqtt).ToList();
allYiDaModels = sortedModels.Select(item => item.YiDa).ToList();
AppendLog($"所有参数Model已按part_number排序共{allMqttModels.Count}条数据");
}
// ========== 统一上传排序后的Model ==========
if (allMqttModels.Count > 0 && allYiDaModels.Count > 0)
{
string token = _uploadService.GetDingDingToken();
if (string.IsNullOrEmpty(token))
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => MessageBox.Show("获取 token 失败,请检查 AppKey/AppSecret")));
}
else
{
MessageBox.Show("获取 token 失败,请检查 AppKey/AppSecret");
}
return;
}
// WinForm跨线程安全上传
if (InvokeRequired)
{
BeginInvoke(
new Action<string, List<YiDaModel>, List<MqttModel>, MainForm>(_uploadService
.UploadDatabaseDataToYiDaWithLogging),
token, allYiDaModels, allMqttModels, this);
}
else
{
_uploadService.UploadDatabaseDataToYiDaWithLogging(token, allYiDaModels, allMqttModels, this);
}
AppendLog($"成功上传{allMqttModels.Count}条参数数据按part_number排序");
}
else
{
AppendLog("无有效参数Model可上传");
}
}
/// <summary>
/// 辅助方法:获取合格判定结果
/// </summary>
private string GetQualificationResult(DeviceType deviceType, string paramName, string paramValue,
DataRow drMatch)
{
try
{
if (deviceType == DeviceType.InjectionMoldingMachine)
{
// 注塑机特殊参数判断
if (paramName == "报警信息" || paramName == "Alarm")
{
return string.Equals(paramValue, "无错误", StringComparison.Ordinal) ? "合格" : "不合格";
}
else if (paramName == "开模总数实时" || paramName == "托模次数" || paramName == "ProductCounts")
{
return "合格";
}
}
// 数值型参数公差判断(注塑机普通参数/温控器PV
if (float.TryParse(paramValue, out float val) &&
float.TryParse(drMatch["tolerance_lower"].ToString(), out float lower) &&
float.TryParse(drMatch["tolerance_upper"].ToString(), out float upper))
{
return (val >= lower && val <= upper) ? "合格" : "不合格";
}
return "不合格";
}
catch
{
return "不合格";
}
}
/// <summary>
/// 解析注塑机模型参数
/// </summary>
/// <param name="paramsModel"></param>
/// <returns></returns>
private Dictionary<string, string> ParseImmParams(ImmParamsModel paramsModel)
{
Dictionary<string, string> paramDict = new Dictionary<string, string>();
if (paramsModel == null) return paramDict;
AddParamIfNotEmpty(paramDict, "Alarm", paramsModel.Alarm);
AddParamIfNotEmpty(paramDict, "ProductCounts", paramsModel.ProductCounts);
AddParamIfNotEmpty(paramDict, "CT", paramsModel.CT);
AddParamIfNotEmpty(paramDict, "T1", paramsModel.T1);
AddParamIfNotEmpty(paramDict, "T2", paramsModel.T2);
AddParamIfNotEmpty(paramDict, "T3", paramsModel.T3);
AddParamIfNotEmpty(paramDict, "T4", paramsModel.T4);
AddParamIfNotEmpty(paramDict, "T5", paramsModel.T5);
AddParamIfNotEmpty(paramDict, "IP1", paramsModel.IP1);
AddParamIfNotEmpty(paramDict, "IP2", paramsModel.IP2);
AddParamIfNotEmpty(paramDict, "IP3", paramsModel.IP3);
AddParamIfNotEmpty(paramDict, "IP4", paramsModel.IP4);
AddParamIfNotEmpty(paramDict, "IP5", paramsModel.IP5);
AddParamIfNotEmpty(paramDict, "IV1", paramsModel.IV1);
AddParamIfNotEmpty(paramDict, "IV2", paramsModel.IV2);
AddParamIfNotEmpty(paramDict, "IV3", paramsModel.IV3);
AddParamIfNotEmpty(paramDict, "IV4", paramsModel.IV4);
AddParamIfNotEmpty(paramDict, "IV5", paramsModel.IV5);
AddParamIfNotEmpty(paramDict, "ITT", paramsModel.ITT);
AddParamIfNotEmpty(paramDict, "PP1", paramsModel.PP1);
AddParamIfNotEmpty(paramDict, "PP2", paramsModel.PP2);
AddParamIfNotEmpty(paramDict, "PP3", paramsModel.PP3);
AddParamIfNotEmpty(paramDict, "PV1", paramsModel.PV1);
AddParamIfNotEmpty(paramDict, "PV2", paramsModel.PV2);
AddParamIfNotEmpty(paramDict, "PV3", paramsModel.PV3);
AddParamIfNotEmpty(paramDict, "PT1", paramsModel.PT1);
AddParamIfNotEmpty(paramDict, "PT2", paramsModel.PT2);
AddParamIfNotEmpty(paramDict, "PT3", paramsModel.PT3);
AddParamIfNotEmpty(paramDict, "CC", paramsModel.CC);
return paramDict;
}
/// <summary>
/// 解析温控器模型参数
/// </summary>
/// <param name="paramsModel"></param>
/// <returns></returns>
private Dictionary<string, string> ParseTcParams(TcParamsModel paramsModel)
{
Dictionary<string, string> paramDict = new Dictionary<string, string>();
if (paramsModel == null) return paramDict;
// 仅解析PV参数核心需求
AddParamIfNotEmpty(paramDict, "PV", paramsModel.PV);
return paramDict;
}
/// <summary>
/// 判断参数是否为空
/// </summary>
/// <param name="dict"></param>
/// <param name="key"></param>
/// <param name="value"></param>
private void AddParamIfNotEmpty(Dictionary<string, string> dict, string key, string value)
{
if (!string.IsNullOrWhiteSpace(value))
{
dict[key] = value.Trim();
}
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
}
// ======================================== 日志相关方法 ========================================
/// <summary>
/// 接收 MQTT 消息后,将消息日志显示到 UI 控件上
/// </summary>
/// <param name="msg"></param>
private void OnMqttMessage(string msg)
{
if (InvokeRequired)
{
BeginInvoke(new Action<string>(OnMqttMessage), msg);
return;
}
AppendLog($"收到消息: {msg}");
}
/// <summary>
/// 写入日志到文本框并保存到文件
/// </summary>
public void AppendLog(string message)
{
try
{
if (InvokeRequired)
{
BeginInvoke(new Action<string>(AppendLog), message);
return;
}
// 格式化带时间戳的日志
string timeStamped = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}\r\n";
// 保存到日志文件
SaveToLogFile(timeStamped);
// 添加到文本框并限制行数
textBoxLog.AppendText(timeStamped);
LimitLogLines(500);
}
catch (Exception ex)
{
// 可以在这里添加错误处理,例如写入错误日志
// MessageBox.Show($"日志处理错误: {ex.Message}");
}
}
/// <summary>
/// 将日志保存到文件
/// </summary>
private void SaveToLogFile(string logContent)
{
try
{
UpdateLogFile(); // 确保使用当天的日志文件
// 追加写入日志使用UTF8编码避免中文乱码
File.AppendAllText(_currentLogFile, logContent, System.Text.Encoding.UTF8);
}
catch (Exception ex)
{
// 文件写入错误处理
// MessageBox.Show($"日志文件写入错误: {ex.Message}");
}
}
/// <summary>
/// 限制日志文本框的最大行数
/// </summary>
private void LimitLogLines(int maxLines)
{
// 按换行符分割所有行
string[] lines = textBoxLog.Text.Split(new[] { "\r\n" }, StringSplitOptions.None);
// 如果超过最大行数只保留最后maxLines行
if (lines.Length > maxLines)
{
// 计算需要保留的起始索引
int startIndex = lines.Length - maxLines;
string[] newLines = new string[maxLines];
Array.Copy(lines, startIndex, newLines, 0, maxLines);
// 重新设置文本框内容并保持滚动到最底部
textBoxLog.Text = string.Join("\r\n", newLines);
// 滚动到最新内容
textBoxLog.SelectionStart = textBoxLog.TextLength;
textBoxLog.ScrollToCaret();
}
else
{
// 未超过限制时也滚动到最底部
textBoxLog.SelectionStart = textBoxLog.TextLength;
textBoxLog.ScrollToCaret();
}
}
}
}