2026-01-29 08:39:56 +08:00

1045 lines
42 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 System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;
using Newtonsoft.Json;
using YiDa_WinForm.Business;
using YiDa_WinForm.Config;
using YiDa_WinForm.Model;
using YiDa_WinForm.Service;
using YiDa_WinForm.Service.Mqtt;
using YiDa_WinForm.Utils;
namespace YiDa_WinForm
{
public partial class MainForm : Form
{
// 依赖注入
private readonly MqttClientService _mqttService;
private readonly YiDaUploadService _uploadService;
private readonly ButtonOperationService _buttonService;
private readonly FormulaBusinessService _formulaBusinessService;
// 通用上传定时器
private System.Timers.Timer _timer;
// 日志文件相关路径
private readonly string _logDirectory = "log";
private string _currentLogFile;
private DateTime _lastLogDate = DateTime.MinValue;
// 工作时间配置(默认 9:00 - 23:30
private TimeSpan _workStartTime = new TimeSpan(9, 0, 0);
private TimeSpan _workEndTime = new TimeSpan(23, 30, 0);
// 连杆测试定时报警相关
private System.Timers.Timer _rodAlarmTimer;
private bool _isImageUploadedInCycle = false;
// 报废上传定时报警相关(和连杆完全对齐)
private System.Timers.Timer _scrapAlarmTimer;
private bool _isScrapImageUploadedInCycle = false;
// ======================================== 初始化相关方法 ========================================
public MainForm()
{
// 初始化设计器方法
InitializeComponent();
// 订阅日志事件
LogHelper.OnLogGenerated += LogHelper_OnLogGenerated;
// 初始化服务实例
_buttonService = new ButtonOperationService();
_mqttService = new MqttClientService();
_uploadService = new YiDaUploadService();
_formulaBusinessService = new FormulaBusinessService(_buttonService);
// 绑定回调事件(连杆+报废)
_mqttService.MessageReceived += OnMqttMessage;
_uploadService.RodUploadStatusChanged += OnRodUploadStatusChanged;
_uploadService.ScrapUploadStatusChanged += OnScrapUploadStatusChanged;
// UI初始化配置
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>
private async void Form1_Load(object sender, EventArgs e)
{
try
{
MakePanelRound(panelLed);
await LoadFormula();
await LoadMqttDic();
timer1.Enabled = true;
}
catch (Exception ex)
{
LogHelper.AppendLog($"初始化失败:{ex.Message}");
}
}
/// <summary>
/// 将指定 Panel 变成圆形
/// </summary>
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>
/// 加载配方到UI下拉框
/// </summary>
private async Task LoadFormula()
{
await _formulaBusinessService.LoadFormulaAsync();
// 绑定下拉框数据源
bsPF.DataSource = _formulaBusinessService.UniqueFormula;
bsPF2.DataSource = _formulaBusinessService.UniqueFormula;
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"]} - {drv["part_name"]}";
}
};
comboBox2.Format += (s, e) =>
{
if (e.ListItem is DataRowView drv)
{
e.Value = string.IsNullOrEmpty(drv["part_number_name"].ToString())
? ""
: $"{drv["part_number"]} - {drv["part_name"]}";
}
};
}
/// <summary>
/// 加载MQTT字典到UI
/// </summary>
private async Task LoadMqttDic()
{
await _formulaBusinessService.LoadMqttDicAsync();
}
// ======================================== 按钮相关方法 ========================================
/// <summary>
/// 网关连接按钮
/// </summary>
private async void buttonConnect_Click(object sender, EventArgs e)
{
try
{
LogHelper.AppendLog("正在连接MQTT服务器...");
await _mqttService.MqttClientStartAsync();
LogHelper.AppendLog("连接成功!");
panelLed.BackColor = Color.Green;
toolStripStatusLabel1.Text = "已连接";
buttonConnect.Enabled = false;
buttonDisconnect.Enabled = true;
}
catch (Exception ex)
{
panelLed.BackColor = Color.Red;
LogHelper.AppendLog($"连接失败:{ex.Message}");
toolStripStatusLabel1.Text = "连接失败";
}
}
/// <summary>
/// 网关断开按钮
/// </summary>
private async void buttonDisconnect_Click(object sender, EventArgs e)
{
try
{
await _mqttService.MqttClientStopAsync();
LogHelper.AppendLog("已断开连接");
panelLed.BackColor = Color.Red;
toolStripStatusLabel1.Text = "未连接";
buttonConnect.Enabled = true;
buttonDisconnect.Enabled = false;
}
catch (Exception ex)
{
LogHelper.AppendLog($"无法断开连接:{ex.Message}");
}
}
/// <summary>
/// 配方导入按钮
/// </summary>
private async void button1_Click(object sender, EventArgs e)
{
try
{
OpenFileDialog openFile = new OpenFileDialog();
openFile.Filter = "Excel文件|*.xlsx;*.xls";
if (openFile.ShowDialog() == DialogResult.OK)
{
string filePath = openFile.FileName;
DataTable excelDt = ExcelHelper.GetExcelToDataTable(filePath);
if (excelDt != null && excelDt.Rows.Count > 0)
{
await _buttonService.SaveFormulaByExcel(excelDt);
await LoadFormula();
MessageBox.Show("配方信息已导入!", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("不允许导入空表!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
}
catch (Exception ex)
{
LogHelper.AppendLog($"配方导入失败:{ex.Message}");
MessageBox.Show($"配方导入失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 上传宜搭按钮
/// </summary>
private async void button2_Click(object sender, EventArgs e)
{
try
{
if (toolStripStatusLabel1.Text != "已连接")
{
MessageBox.Show("请先连接MQTT网关", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
if (string.IsNullOrEmpty(comboBox1.Text) && string.IsNullOrEmpty(comboBox2.Text))
{
MessageBox.Show("请先导入配方信息并选择配方!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
button2.Enabled = false;
if (_timer != null)
{
_timer.Enabled = false;
_timer.Dispose();
}
RefreshSelectedFormulaToService();
double seconds = 10;
if (double.TryParse(txtLUploadPL.Text, out double inputSeconds) && inputSeconds > 0)
{
seconds = inputSeconds;
}
await MqttYiDaUpload();
_timer = new System.Timers.Timer(seconds * 1000);
_timer.Elapsed += Timer_Elapsed;
_timer.AutoReset = true;
_timer.Enabled = true;
LogHelper.AppendLog($"自动上传已启动,间隔:{seconds}秒");
MessageBox.Show($"自动上传已启动,间隔:{seconds}秒", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
button2.Enabled = true;
LogHelper.AppendLog($"上传宜搭失败:{ex.Message}");
MessageBox.Show($"上传宜搭失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 中止上传按钮
/// </summary>
private void button3_Click(object sender, EventArgs e)
{
button2.Enabled = true;
if (_timer != null)
{
_timer.Enabled = false;
_timer.Dispose();
_timer = null;
LogHelper.AppendLog("已停止自动上传数据");
MessageBox.Show("已停止自动上传", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
LogHelper.AppendLog("无运行中的上传定时器");
MessageBox.Show("当前无自动上传任务", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
/// <summary>
/// 报废上传凭证按钮(完整逻辑:定时报警 + 全不选中关闭定时器)
/// </summary>
private async void button4_Click(object sender, EventArgs e)
{
using (var scrapForm = new ScrapUploadForm())
{
DialogResult result = scrapForm.ShowDialog(this);
if (result == DialogResult.OK)
{
bool isScrapUpload = scrapForm.IsScrapUploadSelected;
bool isScrapTimedAlarm = scrapForm.IsScrapTimedAlarmSelected;
int interval = scrapForm.ScrapTimedInterval;
// ========== 核心逻辑:全不选中时销毁报废定时器 ==========
if (!isScrapUpload && !isScrapTimedAlarm)
{
if (_scrapAlarmTimer != null)
{
_scrapAlarmTimer.Enabled = false;
_scrapAlarmTimer.Dispose();
_scrapAlarmTimer = null;
LogHelper.AppendLog("未勾选任何选框,已销毁报废上传定时报警定时器");
MessageBox.Show("未勾选任何选框,已关闭报废上传定时报警", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
LogHelper.AppendLog("未勾选任何选框,当前无运行中的报废上传定时报警定时器");
MessageBox.Show("未勾选任何选框,当前无运行中的定时报警任务", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
return;
}
bool isImageUploadSuccess = false;
if (isScrapUpload)
{
OpenFileDialog openFile = new OpenFileDialog();
if (openFile.ShowDialog() == DialogResult.OK)
{
string filePath = openFile.FileName;
if (!string.IsNullOrEmpty(filePath))
{
isImageUploadSuccess = await _uploadService.UploadScrapImageInternalAsync(filePath);
MessageBox.Show(isImageUploadSuccess ? "报废凭证图片已上传!" : "报废凭证图片上传失败!");
}
else
{
MessageBox.Show("不允许上传空文件!");
}
}
}
if (isScrapTimedAlarm)
{
LogHelper.AppendLog($"勾选了报废定时上传报警,准备启动定时任务(间隔{interval}分钟)");
TimeSpan currentTime = DateTime.Now.TimeOfDay;
if (currentTime < _workStartTime || currentTime > _workEndTime)
{
this.Invoke(new Action(() =>
{
MessageBox.Show(
$"当前时间不在工作时间({_workStartTime:hh\\:mm}-{_workEndTime:hh\\:mm})内,定时任务将在工作时间内自动生效",
"提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}));
}
StartScrapAlarmTimer(interval);
}
LogHelper.AppendLog(
$"选择结果:报废凭证上传={isScrapUpload}(上传结果={isImageUploadSuccess}),定时上传报警={isScrapTimedAlarm},时间间隔={interval}分钟");
if (!isScrapUpload && isScrapTimedAlarm)
{
MessageBox.Show("定时报警任务已启动,将在工作时间内按配置间隔执行判断", "成功", MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
}
}
}
/// <summary>
/// 连杆测试上传按钮(完整逻辑:定时报警 + 全不选中关闭定时器)
/// </summary>
private async void button5_Click(object sender, EventArgs e)
{
using (var selectForm = new StrengthTestUploadForm())
{
DialogResult result = selectForm.ShowDialog(this);
if (result == DialogResult.OK)
{
bool isMoldUpload = selectForm.IsMoldProductionSelected;
bool isTimedAlarm = selectForm.IsTimedAlarmSelected;
int interval = selectForm.TimedInterval;
// ========== 核心逻辑:全不选中时销毁连杆定时器 ==========
if (!isMoldUpload && !isTimedAlarm)
{
if (_rodAlarmTimer != null)
{
_rodAlarmTimer.Enabled = false;
_rodAlarmTimer.Dispose();
_rodAlarmTimer = null;
LogHelper.AppendLog("未勾选任何选框,已销毁连杆测试定时报警定时器");
MessageBox.Show("未勾选任何选框,已关闭连杆测试定时报警", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
LogHelper.AppendLog("未勾选任何选框,当前无运行中的连杆测试定时报警定时器");
MessageBox.Show("未勾选任何选框,当前无运行中的定时报警任务", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
return;
}
bool isImageUploadSuccess = false;
if (isMoldUpload)
{
OpenFileDialog openFile = new OpenFileDialog();
if (openFile.ShowDialog() == DialogResult.OK)
{
string filePath = openFile.FileName;
if (!string.IsNullOrEmpty(filePath))
{
isImageUploadSuccess = await _uploadService.UploadRodTestImageInternalAsync(filePath);
MessageBox.Show(isImageUploadSuccess ? "连杆测试图片已上传!" : "连杆测试图片上传失败!");
}
else
{
MessageBox.Show("不允许上传空文件!");
}
}
}
if (isTimedAlarm)
{
LogHelper.AppendLog($"勾选了定时上传报警,准备启动定时任务(间隔{interval}分钟)");
TimeSpan currentTime = DateTime.Now.TimeOfDay;
if (currentTime < _workStartTime || currentTime > _workEndTime)
{
this.Invoke(new Action(() =>
{
MessageBox.Show(
$"当前时间不在工作时间({_workStartTime:hh\\:mm}-{_workEndTime:hh\\:mm})内,定时任务将在工作时间内自动生效",
"提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}));
}
StartRodAlarmTimer(interval);
}
LogHelper.AppendLog(
$"选择结果:模具投产上传={isMoldUpload}(上传结果={isImageUploadSuccess}),定时上传报警={isTimedAlarm},时间间隔={interval}分钟");
if (!isMoldUpload && isTimedAlarm)
{
MessageBox.Show("定时报警任务已启动,将在工作时间内按配置间隔执行判断", "成功", MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
}
}
}
/// <summary>
/// 配置按钮
/// </summary>
private void button6_Click(object sender, EventArgs e)
{
try
{
using (var configForm = new WorkTimeConfigForm(_workStartTime, _workEndTime))
{
DialogResult result = configForm.ShowDialog(this);
if (result == DialogResult.OK)
{
_workStartTime = configForm.WorkStartTime;
_workEndTime = configForm.WorkEndTime;
LogHelper.AppendLog($"工作时间配置更新:{_workStartTime:hh\\:mm} - {_workEndTime:hh\\:mm}");
MessageBox.Show("工作时间配置成功!", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
catch (Exception ex)
{
LogHelper.AppendLog($"工作时间配置失败:{ex.Message}");
MessageBox.Show($"配置失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 关闭MainForm按钮
/// </summary>
private async void MainFormClosing(object sender, FormClosingEventArgs e)
{
try
{
if (_timer != null)
{
_timer.Enabled = false;
_timer.Dispose();
}
// 销毁连杆+报废定时器
if (_rodAlarmTimer != null)
{
_rodAlarmTimer.Enabled = false;
_rodAlarmTimer.Dispose();
}
if (_scrapAlarmTimer != null)
{
_scrapAlarmTimer.Enabled = false;
_scrapAlarmTimer.Dispose();
}
await _mqttService.MqttClientStopAsync();
}
catch (Exception ex)
{
LogHelper.AppendLog($"关闭窗口失败:{ex.Message}");
}
}
/// <summary>
/// 刷新配方按钮
/// </summary>
private async void btnRefresh_Click(object sender, EventArgs e)
{
try
{
await LoadFormula();
await LoadMqttDic();
MessageBox.Show("配方已刷新!", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
LogHelper.AppendLog($"刷新配方失败:{ex.Message}");
MessageBox.Show($"刷新配方失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 上传间隔输入框校验
/// </summary>
private void txtLUploadPL_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Back)
{
e.Handled = false;
return;
}
if (char.IsDigit(e.KeyChar) || (e.KeyChar == '.' && !txtLUploadPL.Text.Contains(".")))
{
e.Handled = false;
}
else
{
e.Handled = true;
}
}
/// <summary>
/// 更新时间显示
/// </summary>
private void timer1_Tick(object sender, EventArgs e)
{
label4.Text = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
}
// ======================================== 定时报警核心方法(连杆+报废) ========================================
/// <summary>
/// 启动连杆测试定时报警任务
/// </summary>
private void StartRodAlarmTimer(int intervalMinutes)
{
if (_rodAlarmTimer != null)
{
_rodAlarmTimer.Enabled = false;
_rodAlarmTimer.Dispose();
}
_rodAlarmTimer = new System.Timers.Timer(intervalMinutes * 60 * 1000);
_rodAlarmTimer.Elapsed += RodAlarmTimer_Elapsed;
_rodAlarmTimer.AutoReset = true;
_rodAlarmTimer.Enabled = true;
_isImageUploadedInCycle = false;
LogHelper.AppendLog(
$"连杆测试定时报警已启动:间隔{intervalMinutes}分钟,工作时间{_workStartTime:hh\\:mm}-{_workEndTime:hh\\:mm}");
}
/// <summary>
/// 启动报废上传定时报警任务
/// </summary>
private void StartScrapAlarmTimer(int intervalMinutes)
{
if (_scrapAlarmTimer != null)
{
_scrapAlarmTimer.Enabled = false;
_scrapAlarmTimer.Dispose();
}
_scrapAlarmTimer = new System.Timers.Timer(intervalMinutes * 60 * 1000);
_scrapAlarmTimer.Elapsed += ScrapAlarmTimer_Elapsed;
_scrapAlarmTimer.AutoReset = true;
_scrapAlarmTimer.Enabled = true;
_isScrapImageUploadedInCycle = false;
LogHelper.AppendLog(
$"报废上传定时报警已启动:间隔{intervalMinutes}分钟,工作时间{_workStartTime:hh\\:mm}-{_workEndTime:hh\\:mm}");
}
/// <summary>
/// 连杆报警定时器触发事件
/// </summary>
private void RodAlarmTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
DateTime now = DateTime.Now;
TimeSpan currentTime = now.TimeOfDay;
if (currentTime < _workStartTime || currentTime > _workEndTime)
{
LogHelper.AppendLog($"当前时间{currentTime:hh\\:mm}不在工作时间内,跳过本次连杆报警判断");
_isImageUploadedInCycle = false;
return;
}
if (!_isImageUploadedInCycle)
{
string alarmContent =
$"连杆测试超时未上传图片!当前时间:{now:yyyy-MM-dd HH:mm:ss},配置间隔:{_rodAlarmTimer.Interval / 60000}分钟";
this.Invoke(new Action(() => SendDingDingAlarm(alarmContent, true)));
}
else
{
LogHelper.AppendLog($"连杆测试计时周期内已上传图片,无需报警,重置标记");
}
_isImageUploadedInCycle = false;
}
/// <summary>
/// 报废报警定时器触发事件
/// </summary>
private void ScrapAlarmTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
DateTime now = DateTime.Now;
TimeSpan currentTime = now.TimeOfDay;
if (currentTime < _workStartTime || currentTime > _workEndTime)
{
LogHelper.AppendLog($"当前时间{currentTime:hh\\:mm}不在工作时间内,跳过本次报废报警判断");
_isScrapImageUploadedInCycle = false;
return;
}
if (!_isScrapImageUploadedInCycle)
{
string alarmContent =
$"报废上传超时未上传凭证!当前时间:{now:yyyy-MM-dd HH:mm:ss},配置间隔:{_scrapAlarmTimer.Interval / 60000}分钟";
this.Invoke(new Action(() => SendDingDingAlarm(alarmContent, false)));
}
else
{
LogHelper.AppendLog($"报废上传计时周期内已上传凭证,无需报警,重置标记");
}
_isScrapImageUploadedInCycle = false;
}
/// <summary>
/// 发送钉钉报警(区分连杆/报废)
/// </summary>
private async void SendDingDingAlarm(string alarmContent, bool isRodAlarm)
{
try
{
LogHelper.AppendLog($"【钉钉报警】{(isRodAlarm ? "" : "")}{alarmContent}");
await _uploadService.SendDingDingTextAlarmAsync(alarmContent, isRodAlarm);
MessageBox.Show($"已发送钉钉{(isRodAlarm ? "" : "")}报警:{alarmContent}", "报警提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
catch (Exception ex)
{
LogHelper.AppendLog($"{(isRodAlarm ? "" : "")}钉钉报警发送失败:{ex.Message}");
}
}
// ======================================== 上传状态回调方法(连杆+报废) ========================================
/// <summary>
/// 处理连杆上传状态回调
/// </summary>
private void OnRodUploadStatusChanged(object sender, RodUploadStatusEventArgs e)
{
if (this.InvokeRequired)
{
this.Invoke(new Action<object, RodUploadStatusEventArgs>(OnRodUploadStatusChanged), sender, e);
return;
}
_isImageUploadedInCycle = e.IsUploadSuccess;
LogHelper.AppendLog($"连杆上传状态:{(e.IsUploadSuccess ? "" : "")},消息:{e.Message}");
}
/// <summary>
/// 处理报废上传状态回调
/// </summary>
private void OnScrapUploadStatusChanged(object sender, ScrapUploadStatusEventArgs e)
{
if (this.InvokeRequired)
{
this.Invoke(new Action<object, ScrapUploadStatusEventArgs>(OnScrapUploadStatusChanged), sender, e);
return;
}
_isScrapImageUploadedInCycle = e.IsUploadSuccess;
LogHelper.AppendLog($"报废上传状态:{(e.IsUploadSuccess ? "" : "")},消息:{e.Message}");
}
// ======================================== 辅助方法 ========================================
/// <summary>
/// 定时器触发事件
/// </summary>
private async void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
RefreshSelectedFormulaToService();
await MqttYiDaUpload();
}
/// <summary>
/// 转发下拉框选择值到配方业务服务
/// </summary>
private void RefreshSelectedFormulaToService()
{
string selected1 = comboBox1.SelectedValue?.ToString() ?? string.Empty;
string selected2 = comboBox2.SelectedValue?.ToString() ?? string.Empty;
_formulaBusinessService.RefreshSelectedFormula(selected1, selected2);
}
// ======================================== 核心上传方法 ========================================
/// <summary>
/// 上传宜搭方法
/// </summary>
private async Task MqttYiDaUpload()
{
try
{
DataTable dtMqtt = await _buttonService.GetLatestMqttDataAsync();
if (dtMqtt == null || dtMqtt.Rows.Count == 0)
{
LogHelper.AppendLog("未查询到MQTT设备数据跳过本次上传");
return;
}
LogHelper.AppendLog($"本次读取到{dtMqtt.Rows.Count}条MQTT设备数据");
foreach (DataRow dr in dtMqtt.Rows)
{
string deviceCode = dr["device_code"].ToString();
LogHelper.AppendLog($"开始处理设备[{deviceCode}]数据");
var (formulaList, site) = GetDeviceFormulaAndSite(deviceCode);
if (formulaList == null || formulaList.Count == 0)
{
LogHelper.AppendLog($"设备[{deviceCode}]未选择配方,跳过");
continue;
}
string strMessage = dr["receive_data"].ToString();
if (string.IsNullOrEmpty(strMessage))
{
LogHelper.AppendLog($"设备[{deviceCode}]无有效receive_data跳过");
continue;
}
SQLDataModel data = JsonConvert.DeserializeObject<SQLDataModel>(strMessage);
if (data == null || data.@params == null)
{
LogHelper.AppendLog($"设备[{deviceCode}]反序列化后无params数据跳过");
continue;
}
Type paramsType = data.@params.GetType();
PropertyInfo[] properties = paramsType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
List<MqttModel> mqttLists = new List<MqttModel>();
List<YiDaModel> yidaLists = new List<YiDaModel>();
foreach (PropertyInfo prop in properties)
{
string paramCode = prop.Name;
object value = prop.GetValue(data.@params);
if (value == null || string.IsNullOrWhiteSpace(value.ToString()))
{
continue;
}
string paramName = _formulaBusinessService.MapMqttParamName(paramCode);
DataRow drMatch = _formulaBusinessService.MatchFormulaByParamName(formulaList, paramName);
if (drMatch == null)
{
LogHelper.AppendLog($"设备[{deviceCode}]配方中未找到参数[{paramName}],跳过");
continue;
}
MqttModel mqttNew = BuildMqttModel(drMatch, paramName, value, site);
YiDaModel yidaNew = BuildYiDaModel(drMatch, paramName, value, site);
mqttLists.Add(mqttNew);
yidaLists.Add(yidaNew);
}
int len = Math.Min(mqttLists.Count, yidaLists.Count);
if (len > 0)
{
List<MqttModel> mqttLists1 = mqttLists.Take(len).ToList();
List<YiDaModel> yidaLists1 = yidaLists.Take(len).ToList();
string token = _uploadService.GetDingDingToken();
if (string.IsNullOrEmpty(token))
{
LogHelper.AppendLog("获取 token 失败,请检查 AppKey/AppSecret");
this.Invoke(new Action(() =>
{
MessageBox.Show("获取 token 失败,请检查 AppKey/AppSecret", "错误", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}));
return;
}
this.Invoke(new Action(() =>
{
_uploadService.UploadDatabaseDataToYiDaWithLogging(token, yidaLists1, mqttLists, this);
}));
LogHelper.AppendLog($"设备[{deviceCode}]成功上传{len}条数据到宜搭");
}
else
{
LogHelper.AppendLog($"设备[{deviceCode}]无有效参数数据可上传");
}
}
}
catch (Exception ex)
{
LogHelper.AppendLog($"MqttYiDaUpload执行失败{ex.Message}");
this.Invoke(new Action(() =>
{
MessageBox.Show($"上传失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}));
}
}
/// <summary>
/// 获取设备对应的配方和工位
/// </summary>
private Tuple<List<DataRow>, string> GetDeviceFormulaAndSite(string deviceCode)
{
if (string.Equals(deviceCode, "device1", StringComparison.Ordinal))
{
return Tuple.Create(_formulaBusinessService.SelectedFormula1, "1号设备");
}
else if (string.Equals(deviceCode, "device2", StringComparison.Ordinal))
{
return Tuple.Create(_formulaBusinessService.SelectedFormula2, "2号设备");
}
else
{
return Tuple.Create<List<DataRow>, string>(null, null);
}
}
/// <summary>
/// 构造MqttModel
/// </summary>
private MqttModel BuildMqttModel(DataRow drMatch, string paramName, object value, string site)
{
MqttModel mqttNew = new MqttModel();
mqttNew.SupplierCode = drMatch["supplier_code"].ToString();
mqttNew.SupplierName = drMatch["supplier_name"].ToString();
mqttNew.VehicleModel = drMatch["vehicle_model"].ToString();
mqttNew.PartNumber = drMatch["part_number"].ToString();
mqttNew.PartName = drMatch["part_name"].ToString();
mqttNew.ParameterName = paramName;
mqttNew.ParameterValue = value.ToString();
mqttNew.ToleranceLower = drMatch["tolerance_lower"].ToString();
mqttNew.ToleranceUpper = drMatch["tolerance_upper"].ToString();
mqttNew.LeaderPart = drMatch["leader_part"].ToString();
mqttNew.WorkStation = site;
mqttNew.LeaderOutProtection = drMatch["leader_out_protection"].ToString();
mqttNew.IsQualification = JudgeQualification(paramName, value, drMatch);
return mqttNew;
}
/// <summary>
/// 构造YiDaModel
/// </summary>
private YiDaModel BuildYiDaModel(DataRow drMatch, string paramName, object value, string site)
{
YiDaModel yidaNew = new YiDaModel();
yidaNew.textField_mha98neu = drMatch["supplier_code"].ToString();
yidaNew.textField_mha98nev = drMatch["supplier_name"].ToString();
yidaNew.textField_mha98new = drMatch["vehicle_model"].ToString();
yidaNew.textField_mha98nex = drMatch["part_number"].ToString();
yidaNew.textField_mha98ney = drMatch["part_name"].ToString();
yidaNew.textField_mha98nf1 = paramName;
yidaNew.textField_mhx44i2i = value.ToString();
yidaNew.textField_mhx44i2j = drMatch["tolerance_lower"].ToString();
yidaNew.textField_mhx44i2k = drMatch["tolerance_upper"].ToString();
yidaNew.textField_mha98nf7 = drMatch["leader_part"].ToString();
yidaNew.textField_mha98nf0 = site;
yidaNew.textField_mha98nfh = drMatch["leader_out_protection"].ToString();
yidaNew.textField_mhlvt8ht =
Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc))
.TotalMilliseconds);
if (paramName == "报废图片路径" && _buttonService._formulaValue == "报废图片路径")
{
yidaNew.imageField_mii5s85z = _uploadService._reformationPicture;
}
yidaNew.textField_mha98nf5 = JudgeQualification(paramName, value, drMatch);
return yidaNew;
}
/// <summary>
/// 合格判断
/// </summary>
private string JudgeQualification(string paramName, object value, DataRow drMatch)
{
if (paramName == "报警信息")
{
return string.Equals(value?.ToString(), "无错误", StringComparison.Ordinal) ? "合格" : "不合格";
}
else if (paramName == "开模总数实时" || paramName == "托模次数" || paramName == "报废图片路径")
{
return "合格";
}
else
{
if (float.TryParse(value?.ToString(), out float paramValue) &&
float.TryParse(drMatch["tolerance_lower"].ToString(), out float toleranceLower) &&
float.TryParse(drMatch["tolerance_upper"].ToString(), out float toleranceUpper))
{
return (paramValue >= toleranceLower && paramValue <= toleranceUpper) ? "合格" : "不合格";
}
else
{
LogHelper.AppendLog(
$"数值转换失败:参数名={paramName},参数值={value},下公差={drMatch["tolerance_lower"]},上公差={drMatch["tolerance_upper"]}");
return "不合格";
}
}
}
// ======================================== 日志相关方法 ========================================
/// <summary>
/// 接收MQTT消息并写入日志
/// </summary>
private void OnMqttMessage(string msg)
{
if (this.InvokeRequired)
{
this.Invoke(new Action<string>(OnMqttMessage), msg);
return;
}
LogHelper.AppendLog($"收到消息: {msg}");
}
/// <summary>
/// 处理日志事件将日志追加到WinForm界面的txtLog控件
/// </summary>
private void LogHelper_OnLogGenerated(string logContent)
{
if (textBoxLog.InvokeRequired)
{
textBoxLog.Invoke(new Action(() => { AppendLogToTextBox(logContent); }));
}
else
{
AppendLogToTextBox(logContent);
}
}
/// <summary>
/// 追加日志到TextBox并自动滚动到最新日志
/// </summary>
private void AppendLogToTextBox(string logContent)
{
textBoxLog.Text += $"{logContent}\r\n";
textBoxLog.SelectionStart = textBoxLog.Text.Length;
textBoxLog.ScrollToCaret();
}
// ======================================== 未实现方法(保留窗体设计器生成) ========================================
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void button5_Click_1(object sender, EventArgs e)
{
}
private void txtLUploadPL_TextChanged(object sender, EventArgs e)
{
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
}
private void panel1_Paint_1(object sender, EventArgs e)
{
}
private void label6_Click(object sender, EventArgs e)
{
}
}
}