2178 lines
92 KiB
C#
2178 lines
92 KiB
C#
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 MySql.Data.MySqlClient;
|
||
using Newtonsoft.Json;
|
||
using YiDa_WinForm.Config;
|
||
using YiDa_WinForm.Model;
|
||
using YiDa_WinForm.Service;
|
||
using YiDa_WinForm.Utils;
|
||
using NPOI.SS.UserModel;
|
||
|
||
namespace YiDa_WinForm
|
||
{
|
||
public partial class MainForm : Form
|
||
{
|
||
/// <summary>
|
||
/// 依赖注入
|
||
/// </summary>
|
||
private readonly MqttClientService _mqttService;
|
||
|
||
private readonly YiDaUploadService _uploadService;
|
||
private readonly ButtonOperationService _buttonService;
|
||
|
||
/// <summary>
|
||
/// 日志文件相关路径
|
||
/// </summary>
|
||
private readonly string _logDirectory = "log";
|
||
|
||
private string _currentLogFile;
|
||
private DateTime _lastLogDate = DateTime.MinValue;
|
||
|
||
/// <summary>
|
||
/// 配方配置
|
||
/// </summary>
|
||
private DataTable _formulas; // 原始配方表(含多行,未去重)
|
||
|
||
private DataTable _dtMqttDic; // MQTT 参数字典表
|
||
private List<DataRow> _formulasListOne; // 设备1选择的配方(多行)
|
||
private List<DataRow> _formulasListTwo; // 设备2选择的配方(多行)
|
||
|
||
/// <summary>
|
||
/// 定时任务
|
||
/// </summary>
|
||
// 通用上传定时器
|
||
private System.Timers.Timer _timer;
|
||
|
||
// 设备1
|
||
private System.Timers.Timer _scrapAlarmTimerOne; // 报废上传定时任务
|
||
private int _lastScrapIntervalOne = 60; // 报废间隔
|
||
private static bool _isScrapImageUploadedOne = false; // 报废图片是否上传
|
||
private static bool _isScrapImageUploadedInCycleOne = false;
|
||
private System.Timers.Timer _rodAlarmTimerOne; // 连杆测试定时任务
|
||
private int _lastRodIntervalOne = 60; // 连杆间隔
|
||
private static bool _isRodImageUploadedOne = false; // 连杆图片是否上传
|
||
private static bool _isRodUploadedInCycleOne = false;
|
||
|
||
private static bool _isScrapImageWorkNoticeOne = false; // 报废图片工作通知标记
|
||
private static bool _isRodImageWorkNoticeOne = false; // 连杆图片工作通知标记
|
||
// 设备2
|
||
private System.Timers.Timer _scrapAlarmTimerTwo; // 报废上传定时任务
|
||
private int _lastScrapIntervalTwo = 60; // 报废间隔
|
||
private static bool _isScrapImageUploadedTwo = false; // 报废图片是否上传
|
||
private static bool _isScrapImageUploadedInCycleTwo = false;
|
||
private System.Timers.Timer _rodAlarmTimerTwo; // 连杆测试定时任务
|
||
private int _lastRodIntervalTwo = 60; // 连杆间隔
|
||
private static bool _isRodImageUploadedTwo = false; // 连杆图片是否上传
|
||
private static bool _isRodUploadedInCycleTwo = false;
|
||
|
||
private static bool _isScrapImageWorkNoticeTwo = false; // 报废图片工作通知标记
|
||
private static bool _isRodImageWorkNoticeTwo = false; // 连杆图片工作通知标记
|
||
|
||
// 连杆工作时间配置
|
||
private System.Timers.Timer _morningRodAlarmTimerOne; // 早上检查点定时器(工作开始+30分钟)
|
||
private System.Timers.Timer _eveningRodAlarmTimerOne; // 晚上检查点定时器(工作结束-30分钟)
|
||
private System.Timers.Timer _morningRodAlarmTimerTwo; // 早上检查点定时器(工作开始+30分钟)
|
||
private System.Timers.Timer _eveningRodAlarmTimerTwo; // 晚上检查点定时器(工作结束-30分钟)
|
||
private bool _isMorningRodUploadedOne = false; // 早上标记(工作开始后30分钟前是否上传)
|
||
private bool _isEveningRodUploadedOne = false; // 晚上标记(工作结束前30分钟前是否上传)
|
||
private bool _isMorningRodUploadedTwo = false; // 早上标记(工作开始后30分钟前是否上传)
|
||
private bool _isEveningRodUploadedTwo = false; // 晚上标记(工作结束前30分钟前是否上传)
|
||
public static TimeSpan _workStartTimeOne = new TimeSpan(9, 0, 0);
|
||
public static TimeSpan _workEndTimeOne = new TimeSpan(17, 30, 0);
|
||
private TimeSpan _morningCheckTimeOne; // 早上检查节点(_workStartTime + 30分钟)
|
||
private TimeSpan _eveningCheckTimeOne; // 晚上检查节点(_workEndTime + 30分钟)
|
||
public static TimeSpan _workStartTimeTwo = new TimeSpan(9, 0, 0);
|
||
public static TimeSpan _workEndTimeTwo = new TimeSpan(17, 30, 0);
|
||
private TimeSpan _morningCheckTimeTwo; // 早上检查节点(_workStartTime + 30分钟)
|
||
private TimeSpan _eveningCheckTimeTwo; // 晚上检查节点(_workEndTime + 30分钟)
|
||
|
||
|
||
// ======================================== 初始化相关方法 ========================================
|
||
public MainForm()
|
||
{
|
||
// 初始化设计器方法
|
||
InitializeComponent();
|
||
|
||
// 订阅日志事件
|
||
LogHelper.OnLogGenerated += LogHelper_OnLogGenerated;
|
||
|
||
// 初始化服务实例
|
||
_buttonService = new ButtonOperationService();
|
||
_mqttService = new MqttClientService();
|
||
_uploadService = new YiDaUploadService();
|
||
|
||
_buttonService.MessageReceived += (msg) => { LogHelper.AppendLog($"服务层消息:{msg}"); };
|
||
|
||
// 绑定回调事件
|
||
_mqttService.MessageReceived += OnMqttMessage;
|
||
|
||
_uploadService.ScrapUploadStatusChangedOne += OnScrapUploadStatusChangedOne;
|
||
_uploadService.ScrapUploadStatusChangedTwo += OnScrapUploadStatusChangedTwo;
|
||
_uploadService.RodUploadStatusChangedOne += OnRodUploadStatusChangedOne;
|
||
_uploadService.RodUploadStatusChangedTwo += OnRodUploadStatusChangedTwo;
|
||
|
||
// UI初始化配置
|
||
buttonDisconnect.Enabled = false;
|
||
|
||
// 初始化日志目录
|
||
InitializeLogDirectory();
|
||
|
||
// 初始化配方相关变量
|
||
_formulas = new DataTable();
|
||
_dtMqttDic = new DataTable();
|
||
_formulasListOne = new List<DataRow>();
|
||
_formulasListTwo = new List<DataRow>();
|
||
|
||
InitDailyRodDeviceOneCheckTimes();
|
||
InitDailyRodDeviceTwoCheckTimes();
|
||
}
|
||
|
||
/// <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 InitFormulas(); // 移植:加载配方
|
||
InitMqttDic(); // 移植:加载MQTT字典
|
||
timer1.Enabled = true;
|
||
|
||
// 初始化时,若下拉框未选择,禁用所有按钮
|
||
UpdateDevice1ButtonStates();
|
||
UpdateDevice2ButtonStates();
|
||
|
||
// 绑定下拉框的选择变化事件
|
||
comboBox1.SelectedIndexChanged += comboBox1_SelectedIndexChanged;
|
||
comboBox2.SelectedIndexChanged += comboBox2_SelectedIndexChanged;
|
||
}
|
||
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>
|
||
/// 查询配方并去重
|
||
/// </summary>
|
||
private async Task InitFormulas()
|
||
{
|
||
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);
|
||
|
||
_formulas = 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 void InitMqttDic()
|
||
{
|
||
DataTable dt = await _buttonService.InitMqttDic();
|
||
if (dt != null)
|
||
{
|
||
_dtMqttDic = dt;
|
||
}
|
||
}
|
||
|
||
// ======================================== 按钮相关方法 ========================================
|
||
/// <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)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 显示加载提示
|
||
this.Cursor = Cursors.WaitCursor;
|
||
LogHelper.AppendLog("正在导入配方,请稍候...");
|
||
|
||
string filePath = openFile.FileName;
|
||
// 优化:使用 Task.Run 异步执行,不阻塞UI线程
|
||
DataTable excelDt = await Task.Run(() => ExcelHelper.GetExcel(filePath));
|
||
|
||
if (excelDt == null || excelDt.Rows.Count == 0)
|
||
{
|
||
MessageBox.Show("Excel解析后无有效数据,不允许导入!");
|
||
LogHelper.AppendLog("Excel无有效数据,导入中止");
|
||
return;
|
||
}
|
||
|
||
// excel导入列
|
||
string[] requiredColumns = { "供应商代码", "供应商名称", "车型", "零件号", "零件名", "参数名" };
|
||
var missingColumns = requiredColumns.Where(col => !excelDt.Columns.Contains(col)).ToList();
|
||
if (missingColumns.Count > 0)
|
||
{
|
||
string msg = $"Excel缺少必要列:{string.Join("、", missingColumns)},导入失败";
|
||
MessageBox.Show(msg);
|
||
LogHelper.AppendLog(msg);
|
||
return;
|
||
}
|
||
|
||
// 异步执行批量插入
|
||
await _buttonService.SaveFormulaByExcel(excelDt);
|
||
// 异步刷新配方
|
||
await InitFormulas();
|
||
|
||
MessageBox.Show("配方信息已导入!");
|
||
LogHelper.AppendLog($"配方导入成功:{Path.GetFileName(filePath)},共{excelDt.Rows.Count}行");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogHelper.AppendLog($"配方导入失败:{ex.Message}");
|
||
MessageBox.Show($"导入失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
finally
|
||
{
|
||
// 恢复光标
|
||
this.Cursor = Cursors.Default;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 上传宜搭按钮
|
||
/// </summary>
|
||
private async void button2_Click(object sender, EventArgs e)
|
||
{
|
||
try
|
||
{
|
||
if (toolStripStatusLabel1.Text != "已连接") //如果 MQTT 没连接,就不允许上传。
|
||
{
|
||
MessageBox.Show("请先连接MQTT网关!");
|
||
return;
|
||
}
|
||
|
||
if (this.comboBox1.Text.Length == 0 && this.comboBox2.Text.Length == 0)
|
||
{
|
||
//如果两个下拉框都还没数据,说明没导入过配方,直接中止。
|
||
MessageBox.Show("请先导入配方信息,再刷新!");
|
||
return;
|
||
}
|
||
|
||
string selection = null;
|
||
// 判断是否选择有效下拉框
|
||
bool hasSelection1 = comboBox1.SelectedIndex > 0 &&
|
||
!string.IsNullOrEmpty(comboBox1.SelectedValue?.ToString());
|
||
|
||
bool hasSelection2 = comboBox2.SelectedIndex > 0 &&
|
||
!string.IsNullOrEmpty(comboBox2.SelectedValue?.ToString());
|
||
|
||
// 1. 重置静态上传标记(每次连接都重新开始判断)
|
||
_isScrapImageUploadedOne = false;
|
||
_isRodImageUploadedOne = false;
|
||
_isScrapImageUploadedTwo = false;
|
||
_isRodImageUploadedTwo = false;
|
||
_isRodImageWorkNoticeOne = false;
|
||
_isRodImageWorkNoticeTwo = false;
|
||
_isScrapImageWorkNoticeOne = false;
|
||
_isScrapImageWorkNoticeTwo = false;
|
||
LogHelper.AppendLog("重置上传标记:连杆未上传、报废未上传");
|
||
|
||
string selectedContent1 = string.Empty;
|
||
string selectedContent2 = string.Empty;
|
||
|
||
// 获取选中项的DataRowView(增加判空)
|
||
DataRowView drv1 = comboBox1.SelectedItem as DataRowView;
|
||
// 先判断drv1是否为null,再访问字段
|
||
selectedContent1 = drv1 != null ? (drv1["part_name"]?.ToString()?.Trim() ?? string.Empty) : string.Empty;
|
||
|
||
// 获取选中项的DataRowView(增加判空)
|
||
DataRowView drv2 = comboBox2.SelectedItem as DataRowView;
|
||
// 先判断drv2是否为null,再访问字段
|
||
selectedContent2 = drv2 != null ? (drv2["part_name"]?.ToString()?.Trim() ?? string.Empty) : string.Empty;
|
||
|
||
if (hasSelection1 && hasSelection2)
|
||
{
|
||
selection = "3";
|
||
StartScrapOneAlarmTimers();
|
||
StartScrapTwoAlarmTimers();
|
||
if (selectedContent1.Contains("连杆2") && selectedContent2.Contains("连杆2"))
|
||
{
|
||
StartRodOneAlarmTimers();
|
||
StartDailyRodDeviceOneFixedTimers();
|
||
|
||
StartRodTwoAlarmTimers();
|
||
StartDailyRodDeviceTwoFixedTimers();
|
||
}
|
||
}
|
||
else if (hasSelection1)
|
||
{
|
||
selection = "1";
|
||
StartScrapOneAlarmTimers();
|
||
if (selectedContent1.Contains("连杆2"))
|
||
{
|
||
StartRodOneAlarmTimers();
|
||
StartDailyRodDeviceOneFixedTimers();
|
||
}
|
||
}
|
||
else if (hasSelection2)
|
||
{
|
||
selection = "2";
|
||
StartScrapTwoAlarmTimers();
|
||
if (selectedContent2.Contains("连杆2"))
|
||
{
|
||
StartRodTwoAlarmTimers();
|
||
StartDailyRodDeviceTwoFixedTimers();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
MessageBox.Show("未选择数据!");
|
||
}
|
||
|
||
this.button2.Enabled = false;
|
||
|
||
// 设备1选择配方
|
||
string selected1 = this.comboBox1.SelectedValue?.ToString();
|
||
if (string.IsNullOrEmpty(selected1) || selected1 == "-1")
|
||
{
|
||
_formulasListOne = null;
|
||
}
|
||
else
|
||
{
|
||
string[] arr1 = selected1.Split('|');
|
||
if (arr1.Length == 2)
|
||
{
|
||
string partNumber1 = arr1[0];
|
||
string partName1 = arr1[1];
|
||
_formulasListOne = _formulas.AsEnumerable()
|
||
.Where(r => r.Field<string>("part_number") == partNumber1
|
||
&& r.Field<string>("part_name") == partName1)
|
||
.ToList();
|
||
}
|
||
else
|
||
{
|
||
_formulasListOne = null;
|
||
}
|
||
}
|
||
|
||
// 设备2选择配方
|
||
string selected2 = this.comboBox2.SelectedValue?.ToString();
|
||
if (string.IsNullOrEmpty(selected2) || selected2 == "-1")
|
||
{
|
||
_formulasListTwo = null;
|
||
}
|
||
else
|
||
{
|
||
string[] arr2 = selected2.Split('|');
|
||
if (arr2.Length == 2)
|
||
{
|
||
string partNumber2 = arr2[0];
|
||
string partName2 = arr2[1];
|
||
_formulasListTwo = _formulas.AsEnumerable()
|
||
.Where(r => r.Field<string>("part_number") == partNumber2
|
||
&& r.Field<string>("part_name") == partName2)
|
||
.ToList();
|
||
}
|
||
else
|
||
{
|
||
_formulasListTwo = null;
|
||
}
|
||
}
|
||
|
||
double seconds;
|
||
if (!double.TryParse(txtLUploadPL.Text, out seconds) || seconds <= 0)
|
||
{
|
||
seconds = 10; //控制上传间隔,默认10秒。
|
||
}
|
||
|
||
// 立即上传一次
|
||
await MqttYiDaUpload(selection, null);
|
||
|
||
_timer = new System.Timers.Timer(seconds * 1000);
|
||
_timer.Elapsed += async (s, evt) => { await MqttYiDaUpload(selection, null); };
|
||
_timer.AutoReset = true; // 是否重复
|
||
_timer.Enabled = true; // 开始计时
|
||
|
||
LogHelper.AppendLog($"自动上传已启动,间隔:{seconds}秒");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
this.button2.Enabled = true;
|
||
LogHelper.AppendLog($"上传宜搭失败:{ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <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);
|
||
}
|
||
|
||
StopDeviceOneAlarmTimers();
|
||
StopDeviceTwoAlarmTimers();
|
||
StopDailyRodDeviceOneFixedTimers();
|
||
StopDailyRodDeviceTwoFixedTimers();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 报废上传凭证按钮(设备1)
|
||
/// </summary>
|
||
private async void button4_Click(object sender, EventArgs e)
|
||
{
|
||
// 传入间隔值
|
||
using (var scrapForm = new ScrapUploadForm(_lastScrapIntervalOne, "1"))
|
||
{
|
||
DialogResult result = scrapForm.ShowDialog(this);
|
||
|
||
if (result == DialogResult.OK)
|
||
{
|
||
// 1. 提取用户本次选择结果
|
||
int interval = scrapForm.ScrapTimedIntervalOne;
|
||
|
||
_lastScrapIntervalOne = interval;
|
||
|
||
// 2. 上传逻辑
|
||
bool isImageUploadSuccess = false;
|
||
|
||
using (OpenFileDialog openFile = new OpenFileDialog())
|
||
{
|
||
if (openFile.ShowDialog() == DialogResult.OK)
|
||
{
|
||
string filePath = openFile.FileName;
|
||
if (!string.IsNullOrEmpty(filePath))
|
||
{
|
||
isImageUploadSuccess = await _uploadService.UploadScrapDeviceOneAsync(filePath);
|
||
LogHelper.AppendLog(isImageUploadSuccess ? "报废凭证图片已上传!" : "报废凭证图片上传失败!");
|
||
if (isImageUploadSuccess)
|
||
{
|
||
_buttonService.MergeAndSaveData("1", "device1");
|
||
MqttYiDaUpload("1", "device1");
|
||
// 上传成功:直接标记为已上传(避免后续定时报警)
|
||
_isScrapImageUploadedOne = true;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
MessageBox.Show("不允许上传空文件!");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 报废上传凭证按钮(设备2)
|
||
/// </summary>
|
||
/// <param name="sender"></param>
|
||
/// <param name="e"></param>
|
||
private async void button7_Click(object sender, EventArgs e)
|
||
{
|
||
// 传入间隔值
|
||
using (var scrapForm = new ScrapUploadForm(_lastScrapIntervalTwo, "2"))
|
||
{
|
||
DialogResult result = scrapForm.ShowDialog(this);
|
||
|
||
if (result == DialogResult.OK)
|
||
{
|
||
// 1. 提取用户本次选择结果
|
||
int interval = scrapForm.ScrapTimedIntervalTwo;
|
||
|
||
_lastScrapIntervalTwo = interval;
|
||
|
||
// 2. 上传逻辑
|
||
bool isImageUploadSuccess = false;
|
||
|
||
OpenFileDialog openFile = new OpenFileDialog();
|
||
if (openFile.ShowDialog() == DialogResult.OK)
|
||
{
|
||
string filePath = openFile.FileName;
|
||
if (!string.IsNullOrEmpty(filePath))
|
||
{
|
||
isImageUploadSuccess = await _uploadService.UploadScrapDeviceTwoAsync(filePath);
|
||
LogHelper.AppendLog(isImageUploadSuccess ? "报废凭证图片已上传!" : "报废凭证图片上传失败!");
|
||
if (isImageUploadSuccess)
|
||
{
|
||
_buttonService.MergeAndSaveData("1", "device2");
|
||
MqttYiDaUpload("2", "device2");
|
||
// 上传成功:直接标记为已上传(避免后续定时报警)
|
||
_isScrapImageUploadedTwo = true;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
MessageBox.Show("不允许上传空文件!");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 连杆测试上传按钮(设备1)
|
||
/// </summary>
|
||
private async void button5_Click(object sender, EventArgs e)
|
||
{
|
||
if (!button5.Enabled)
|
||
{
|
||
StopDeviceOneAlarmTimers();
|
||
return;
|
||
}
|
||
|
||
using (var selectForm = new RodTestUploadForm(_lastRodIntervalOne, "1"))
|
||
{
|
||
DialogResult result = selectForm.ShowDialog(this);
|
||
|
||
if (result == DialogResult.OK)
|
||
{
|
||
int interval = selectForm.RodTimedIntervalOne;
|
||
|
||
_lastRodIntervalOne = interval;
|
||
|
||
// 3. 上传逻辑:仅当勾选「模具上传」时,才弹出文件选择框(分离上传和报警逻辑)
|
||
bool isImageUploadSuccess = false;
|
||
OpenFileDialog openFile = new OpenFileDialog();
|
||
if (openFile.ShowDialog() == DialogResult.OK)
|
||
{
|
||
string filePath = openFile.FileName;
|
||
if (!string.IsNullOrEmpty(filePath))
|
||
{
|
||
isImageUploadSuccess = await _uploadService.UploadRodTestDeviceOneAsync(filePath);
|
||
LogHelper.AppendLog(isImageUploadSuccess ? "连杆测试图片已上传!" : "连杆测试图片上传失败!");
|
||
if (isImageUploadSuccess)
|
||
{
|
||
_buttonService.MergeAndSaveData("2", "device1");
|
||
MqttYiDaUpload("2", "device1");
|
||
// 上传成功:直接标记为已上传(避免后续定时报警)
|
||
_isRodImageUploadedOne = true;
|
||
DateTime now = DateTime.Now;
|
||
TimeSpan timeOfDay = now.TimeOfDay;
|
||
if (timeOfDay > _workStartTimeOne && timeOfDay < _morningCheckTimeOne)
|
||
{
|
||
_isMorningRodUploadedOne = true;
|
||
}
|
||
|
||
if (timeOfDay > _workEndTimeOne || timeOfDay < _eveningCheckTimeOne)
|
||
{
|
||
_isEveningRodUploadedOne = true;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
MessageBox.Show("不允许上传空文件!");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 配置按钮(设备1)
|
||
/// </summary>
|
||
/// <param name="sender"></param>
|
||
/// <param name="e"></param>
|
||
private async void button6_Click(object sender, EventArgs e)
|
||
{
|
||
try
|
||
{
|
||
if (!button6.Enabled)
|
||
{
|
||
StopDailyRodDeviceOneFixedTimers();
|
||
return;
|
||
}
|
||
|
||
using (var configForm = new WorkTimeConfigForm(_workStartTimeOne, _workEndTimeOne, "1"))
|
||
{
|
||
DialogResult result = configForm.ShowDialog(this);
|
||
if (result == DialogResult.OK)
|
||
{
|
||
_workStartTimeOne = configForm.WorkStartTimeOne;
|
||
_workEndTimeOne = configForm.WorkEndTimeOne;
|
||
|
||
// ========== 重新初始化早晚连杆检查节点 ==========
|
||
InitDailyRodDeviceOneCheckTimes();
|
||
|
||
// ========== 如果网关已连接,重启早晚固定检查定时器 ==========
|
||
if (toolStripStatusLabel1.Text == "已连接")
|
||
{
|
||
StartDailyRodDeviceOneFixedTimers();
|
||
}
|
||
|
||
LogHelper.AppendLog($"工作时间配置更新:{_workStartTimeOne:hh\\:mm} - {_workEndTimeOne:hh\\:mm}");
|
||
|
||
// 3. 上传逻辑:仅当勾选「模具上传」时,才弹出文件选择框(分离上传和报警逻辑)
|
||
bool isImageUploadSuccess = true;
|
||
OpenFileDialog openFile = new OpenFileDialog();
|
||
if (openFile.ShowDialog() == DialogResult.OK)
|
||
{
|
||
string filePath = openFile.FileName;
|
||
if (!string.IsNullOrEmpty(filePath))
|
||
{
|
||
isImageUploadSuccess =
|
||
await _uploadService.UploadRodTestDeviceOneAsync(filePath);
|
||
LogHelper.AppendLog(isImageUploadSuccess ? "连杆测试图片已上传!" : "连杆测试图片上传失败!");
|
||
if (isImageUploadSuccess)
|
||
{
|
||
_buttonService.MergeAndSaveData("2", "device1");
|
||
MqttYiDaUpload("2", "device1");
|
||
// 上传成功:直接标记为已上传(避免后续定时报警)
|
||
_isRodImageUploadedOne = true;
|
||
DateTime now = DateTime.Now;
|
||
TimeSpan timeOfDay = now.TimeOfDay;
|
||
if (timeOfDay > _workStartTimeOne && timeOfDay < _morningCheckTimeOne)
|
||
{
|
||
_isMorningRodUploadedOne = true;
|
||
}
|
||
|
||
if (timeOfDay > _workEndTimeOne || timeOfDay < _eveningCheckTimeOne)
|
||
{
|
||
_isEveningRodUploadedOne = true;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
MessageBox.Show("不允许上传空文件!");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogHelper.AppendLog($"工作时间配置失败:{ex.Message}");
|
||
MessageBox.Show($"配置失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 时间配置(设备2)
|
||
/// </summary>
|
||
/// <param name="sender"></param>
|
||
/// <param name="e"></param>
|
||
private async void button9_Click(object sender, EventArgs e)
|
||
{
|
||
try
|
||
{
|
||
if (!button9.Enabled)
|
||
{
|
||
StopDailyRodDeviceTwoFixedTimers();
|
||
return;
|
||
}
|
||
|
||
using (var configForm = new WorkTimeConfigForm(_workStartTimeTwo, _workEndTimeTwo, "2"))
|
||
{
|
||
DialogResult result = configForm.ShowDialog(this);
|
||
if (result == DialogResult.OK)
|
||
{
|
||
_workStartTimeTwo = configForm.WorkStartTimeTwo;
|
||
_workEndTimeTwo = configForm.WorkEndTimeTwo;
|
||
|
||
// ========== 重新初始化早晚连杆检查节点 ==========
|
||
InitDailyRodDeviceTwoCheckTimes();
|
||
|
||
// ========== 如果网关已连接,重启早晚固定检查定时器 ==========
|
||
if (toolStripStatusLabel1.Text == "已连接")
|
||
{
|
||
StartDailyRodDeviceTwoFixedTimers();
|
||
}
|
||
|
||
LogHelper.AppendLog($"工作时间配置更新:{_workStartTimeTwo:hh\\:mm} - {_workEndTimeTwo:hh\\:mm}");
|
||
|
||
// 3. 上传逻辑:仅当勾选「模具上传」时,才弹出文件选择框(分离上传和报警逻辑)
|
||
bool isImageUploadSuccess = true;
|
||
OpenFileDialog openFile = new OpenFileDialog();
|
||
if (openFile.ShowDialog() == DialogResult.OK)
|
||
{
|
||
string filePath = openFile.FileName;
|
||
if (!string.IsNullOrEmpty(filePath))
|
||
{
|
||
isImageUploadSuccess =
|
||
await _uploadService.UploadRodTestDeviceTwoAsync(filePath);
|
||
LogHelper.AppendLog(isImageUploadSuccess ? "连杆测试图片已上传!" : "连杆测试图片上传失败!");
|
||
if (isImageUploadSuccess)
|
||
{
|
||
_buttonService.MergeAndSaveData("2", "device2");
|
||
MqttYiDaUpload("2", "device2");
|
||
// 上传成功:直接标记为已上传(避免后续定时报警)
|
||
_isRodImageUploadedTwo = true;
|
||
DateTime now = DateTime.Now;
|
||
TimeSpan timeOfDay = now.TimeOfDay;
|
||
if (timeOfDay > _workStartTimeTwo && timeOfDay < _morningCheckTimeTwo)
|
||
{
|
||
_isMorningRodUploadedTwo = true;
|
||
}
|
||
|
||
if (timeOfDay > _workEndTimeTwo || timeOfDay < _eveningCheckTimeTwo)
|
||
{
|
||
_isEveningRodUploadedTwo = true;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
MessageBox.Show("不允许上传空文件!");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogHelper.AppendLog($"工作时间配置失败:{ex.Message}");
|
||
MessageBox.Show($"配置失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 连杆测试上传按钮(设备2)
|
||
/// </summary>
|
||
/// <param name="sender"></param>
|
||
/// <param name="e"></param>
|
||
private async void button8_Click(object sender, EventArgs e)
|
||
{
|
||
if (!button8.Enabled)
|
||
{
|
||
StopDeviceTwoAlarmTimers();
|
||
return;
|
||
}
|
||
|
||
using (var selectForm = new RodTestUploadForm(_lastRodIntervalTwo, "2"))
|
||
{
|
||
DialogResult result = selectForm.ShowDialog(this);
|
||
|
||
if (result == DialogResult.OK)
|
||
{
|
||
int interval = selectForm.RodTimedIntervalTwo;
|
||
|
||
_lastRodIntervalTwo = interval;
|
||
|
||
// 3. 上传逻辑
|
||
bool isImageUploadSuccess = false;
|
||
OpenFileDialog openFile = new OpenFileDialog();
|
||
if (openFile.ShowDialog() == DialogResult.OK)
|
||
{
|
||
string filePath = openFile.FileName;
|
||
if (!string.IsNullOrEmpty(filePath))
|
||
{
|
||
isImageUploadSuccess = await _uploadService.UploadRodTestDeviceTwoAsync(filePath);
|
||
LogHelper.AppendLog(isImageUploadSuccess ? "连杆测试图片已上传!" : "连杆测试图片上传失败!");
|
||
if (isImageUploadSuccess)
|
||
{
|
||
_buttonService.MergeAndSaveData("2", "device2");
|
||
MqttYiDaUpload("2", "device2");
|
||
// 上传成功:直接标记为已上传(避免后续定时报警)
|
||
_isRodImageUploadedTwo = true;
|
||
DateTime now = DateTime.Now;
|
||
TimeSpan timeOfDay = now.TimeOfDay;
|
||
if (timeOfDay > _workStartTimeTwo && timeOfDay < _morningCheckTimeTwo)
|
||
{
|
||
_isMorningRodUploadedTwo = true;
|
||
}
|
||
|
||
if (timeOfDay > _workEndTimeTwo || timeOfDay < _eveningCheckTimeTwo)
|
||
{
|
||
_isEveningRodUploadedTwo = true;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
MessageBox.Show("不允许上传空文件!");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 关闭MainForm按钮
|
||
/// </summary>
|
||
private async void MainFormClosing(object sender, FormClosingEventArgs e)
|
||
{
|
||
try
|
||
{
|
||
if (_timer != null)
|
||
{
|
||
_timer.Enabled = false;
|
||
_timer.Dispose();
|
||
}
|
||
|
||
StopDeviceOneAlarmTimers();
|
||
StopDeviceTwoAlarmTimers();
|
||
StopDailyRodDeviceOneFixedTimers();
|
||
StopDailyRodDeviceTwoFixedTimers();
|
||
|
||
await _mqttService.MqttClientStopAsync();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogHelper.AppendLog($"关闭窗口失败:{ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 刷新配方按钮
|
||
/// </summary>
|
||
private async void btnRefresh_Click(object sender, EventArgs e)
|
||
{
|
||
try
|
||
{
|
||
await InitFormulas();
|
||
InitMqttDic();
|
||
MessageBox.Show("配方已刷新!", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||
UpdateDevice1ButtonStates();
|
||
UpdateDevice2ButtonStates();
|
||
}
|
||
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");
|
||
}
|
||
|
||
|
||
// ======================================== 事件绑定 ========================================
|
||
|
||
// 设备1下拉框选择变化事件
|
||
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
|
||
{
|
||
UpdateDevice1ButtonStates();
|
||
}
|
||
|
||
// 设备2下拉框选择变化事件
|
||
private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
|
||
{
|
||
UpdateDevice2ButtonStates();
|
||
}
|
||
|
||
// 更新设备1对应按钮的状态
|
||
private void UpdateDevice1ButtonStates()
|
||
{
|
||
// 判断下拉框是否有有效选择
|
||
bool hasSelection = comboBox1.SelectedIndex > 0 &&
|
||
!string.IsNullOrEmpty(comboBox1.SelectedValue?.ToString());
|
||
|
||
// 判断是否选中连杆2
|
||
string selectedContent = string.Empty;
|
||
if (hasSelection)
|
||
{
|
||
// 获取选中项的DataRowView
|
||
DataRowView drv = comboBox1.SelectedItem as DataRowView;
|
||
// 取零件名(part_name)字段,这是你的配方表中实际存储"连杆2"的字段
|
||
selectedContent = drv["part_name"]?.ToString()?.Trim() ?? string.Empty;
|
||
}
|
||
|
||
// 判断是否包含"连杆2"
|
||
button6.Enabled = hasSelection && selectedContent.Contains("连杆2");
|
||
button5.Enabled = hasSelection && selectedContent.Contains("连杆2");
|
||
button4.Enabled = hasSelection; // 报废上传凭证1
|
||
}
|
||
|
||
// 更新设备2对应按钮的状态
|
||
private void UpdateDevice2ButtonStates()
|
||
{
|
||
bool hasSelection = comboBox2.SelectedIndex > 0 &&
|
||
!string.IsNullOrEmpty(comboBox2.SelectedValue?.ToString());
|
||
|
||
// 判断是否选中连杆2
|
||
string selectedContent = string.Empty;
|
||
if (hasSelection)
|
||
{
|
||
// 获取选中项的DataRowView
|
||
DataRowView drv = comboBox2.SelectedItem as DataRowView;
|
||
// 取零件名(part_name)字段,这是你的配方表中实际存储"连杆2"的字段
|
||
selectedContent = drv["part_name"]?.ToString()?.Trim() ?? string.Empty;
|
||
}
|
||
|
||
// 判断是否包含"连杆2"
|
||
button9.Enabled = hasSelection && selectedContent.Contains("连杆2");
|
||
button8.Enabled = hasSelection && selectedContent.Contains("连杆2");
|
||
button7.Enabled = hasSelection; // 报废上传凭证2
|
||
}
|
||
|
||
// ======================================== 定时报警核心方法 ========================================
|
||
|
||
/// <summary>
|
||
/// 启动报废定时任务(前30分钟上传)
|
||
/// </summary>
|
||
private void StartScrapOneAlarmTimers()
|
||
{
|
||
// 设备1
|
||
if (_scrapAlarmTimerOne != null)
|
||
{
|
||
_scrapAlarmTimerOne.Enabled = false;
|
||
_scrapAlarmTimerOne.Dispose();
|
||
}
|
||
|
||
int scrapIntervalMsOne = _lastScrapIntervalOne * 60 * 1000; // 分钟 → 毫秒
|
||
_scrapAlarmTimerOne = new System.Timers.Timer(scrapIntervalMsOne);
|
||
_scrapAlarmTimerOne.AutoReset = false; // 关键:一次性执行,不循环
|
||
_scrapAlarmTimerOne.Elapsed += ScrapAlarmTimerOne_Elapsed;
|
||
_scrapAlarmTimerOne.Enabled = true; // 启动定时
|
||
LogHelper.AppendLog($"设备1报废上传定时已启动:若{_lastScrapIntervalOne}分钟内未上传凭证,将触发钉钉报警");
|
||
}
|
||
|
||
private void StartScrapTwoAlarmTimers()
|
||
{
|
||
// 设备2
|
||
if (_scrapAlarmTimerTwo != null)
|
||
{
|
||
_scrapAlarmTimerTwo.Enabled = false;
|
||
_scrapAlarmTimerTwo.Dispose();
|
||
}
|
||
|
||
int scrapIntervalMsTwo = _lastScrapIntervalTwo * 60 * 1000; // 分钟 → 毫秒
|
||
_scrapAlarmTimerTwo = new System.Timers.Timer(scrapIntervalMsTwo);
|
||
_scrapAlarmTimerTwo.AutoReset = false; // 关键:一次性执行,不循环
|
||
_scrapAlarmTimerTwo.Elapsed += ScrapAlarmTimerTwo_Elapsed;
|
||
_scrapAlarmTimerTwo.Enabled = true; // 启动定时
|
||
LogHelper.AppendLog($"设备1报废上传定时已启动:若{_lastScrapIntervalTwo}分钟内未上传凭证,将触发钉钉报警");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 启动连杆定时任务(前30分钟上传)
|
||
/// </summary>
|
||
private void StartRodOneAlarmTimers()
|
||
{
|
||
// 设备1
|
||
if (_rodAlarmTimerOne != null)
|
||
{
|
||
_rodAlarmTimerOne.Enabled = false;
|
||
_rodAlarmTimerOne.Dispose();
|
||
}
|
||
|
||
int rodIntervalMsOne = _lastRodIntervalOne * 60 * 1000; // 分钟 → 毫秒
|
||
_rodAlarmTimerOne = new System.Timers.Timer(rodIntervalMsOne);
|
||
_rodAlarmTimerOne.AutoReset = false; // 关键:一次性执行,不循环
|
||
_rodAlarmTimerOne.Elapsed += RodAlarmTimerOne_Elapsed;
|
||
_rodAlarmTimerOne.Enabled = true; // 启动定时
|
||
LogHelper.AppendLog($"设备1连杆定时已启动:若{_lastRodIntervalOne}分钟内未上传凭证,将触发钉钉报警");
|
||
}
|
||
|
||
private void StartRodTwoAlarmTimers()
|
||
{
|
||
// 设备2
|
||
if (_rodAlarmTimerTwo != null)
|
||
{
|
||
_rodAlarmTimerTwo.Enabled = false;
|
||
_rodAlarmTimerTwo.Dispose();
|
||
}
|
||
|
||
int scrapIntervalMsTwo = _lastRodIntervalTwo * 60 * 1000; // 分钟 → 毫秒
|
||
_rodAlarmTimerTwo = new System.Timers.Timer(scrapIntervalMsTwo);
|
||
_rodAlarmTimerTwo.AutoReset = false; // 关键:一次性执行,不循环
|
||
_rodAlarmTimerTwo.Elapsed += RodAlarmTimerTwo_Elapsed;
|
||
_rodAlarmTimerTwo.Enabled = true; // 启动定时
|
||
LogHelper.AppendLog($"设备2连杆上传定时已启动:若{_lastRodIntervalTwo}分钟内未上传凭证,将触发钉钉报警");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 启动连杆定时任务(设备1早晚检查)
|
||
/// </summary>
|
||
private void StartDailyRodDeviceOneFixedTimers()
|
||
{
|
||
// 先停止并释放原有定时器(防止重复启动)
|
||
StopDailyRodDeviceOneFixedTimers();
|
||
|
||
// 重置早晚标记
|
||
ResetDailyRodMarks();
|
||
|
||
DateTime now = DateTime.Now;
|
||
DayOfWeek weekEnum = now.DayOfWeek;
|
||
if (weekEnum.Equals(DayOfWeek.Monday))
|
||
{
|
||
_morningCheckTimeOne = new TimeSpan(10, 30, 0);
|
||
_workStartTimeOne = new TimeSpan(10, 0, 0);
|
||
}
|
||
|
||
// 1. 启动早上检查定时器(若目标时间未过)
|
||
long morningDelayMs = CalculateDelayToTargetTime(_morningCheckTimeOne, "morning");
|
||
if (morningDelayMs > 0 && _morningCheckTimeOne > _workStartTimeOne)
|
||
{
|
||
_morningRodAlarmTimerOne = new System.Timers.Timer(morningDelayMs);
|
||
_morningRodAlarmTimerOne.AutoReset = false; // 一次性执行,不循环
|
||
_morningRodAlarmTimerOne.Elapsed += MorningRodDeviceOneAlarmTimer_Elapsed;
|
||
_morningRodAlarmTimerOne.Enabled = true; // 启动定时器
|
||
LogHelper.AppendLog(
|
||
$"早上连杆检查定时器已启动:将在{_morningCheckTimeOne:hh\\:mm}触发");
|
||
}
|
||
else
|
||
{
|
||
LogHelper.AppendLog("早上检查节点已过当天当前时间,跳过早上连杆检查定时器启动");
|
||
_isMorningRodUploadedOne = true; // 标记为已检查,避免重复判断
|
||
}
|
||
|
||
// 2. 启动晚上检查定时器(若目标时间未过)
|
||
long eveningDelayMs = CalculateDelayToTargetTime(_eveningCheckTimeOne, "evening");
|
||
if (eveningDelayMs > 0 && _eveningCheckTimeOne > _workEndTimeOne)
|
||
{
|
||
_eveningRodAlarmTimerOne = new System.Timers.Timer(eveningDelayMs);
|
||
_eveningRodAlarmTimerOne.AutoReset = false; // 一次性执行,不循环
|
||
_eveningRodAlarmTimerOne.Elapsed += EveningRodDeviceOneAlarmTimer_Elapsed;
|
||
_eveningRodAlarmTimerOne.Enabled = true; // 启动定时器
|
||
LogHelper.AppendLog(
|
||
$"晚上连杆检查定时器已启动:将在{_eveningCheckTimeOne:hh\\:mm}触发");
|
||
}
|
||
else
|
||
{
|
||
LogHelper.AppendLog("晚上检查节点已过当天当前时间,跳过晚上连杆检查定时器启动");
|
||
_isEveningRodUploadedOne = true; // 标记为已检查,避免重复判断
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 启动连杆定时任务(设备2早晚检查)
|
||
/// </summary>
|
||
private void StartDailyRodDeviceTwoFixedTimers()
|
||
{
|
||
// 先停止并释放原有定时器(防止重复启动)
|
||
StopDailyRodDeviceTwoFixedTimers();
|
||
|
||
// 重置早晚标记
|
||
ResetDailyRodMarks();
|
||
DateTime now = DateTime.Now;
|
||
DayOfWeek weekEnum = now.DayOfWeek;
|
||
if (weekEnum.Equals(DayOfWeek.Monday))
|
||
{
|
||
_morningCheckTimeTwo = new TimeSpan(10, 30, 0);
|
||
_workStartTimeTwo = new TimeSpan(10, 0, 0);
|
||
}
|
||
|
||
// 1. 启动早上检查定时器(若目标时间未过)
|
||
long morningDelayMs = CalculateDelayToTargetTime(_morningCheckTimeTwo, "morning");
|
||
if (morningDelayMs > 0 && _morningCheckTimeTwo > _workStartTimeTwo)
|
||
{
|
||
_morningRodAlarmTimerTwo = new System.Timers.Timer(morningDelayMs);
|
||
_morningRodAlarmTimerTwo.AutoReset = false; // 一次性执行,不循环
|
||
_morningRodAlarmTimerTwo.Elapsed += MorningRodDeviceTwoAlarmTimer_Elapsed;
|
||
_morningRodAlarmTimerTwo.Enabled = true; // 启动定时器
|
||
LogHelper.AppendLog(
|
||
$"早上连杆检查定时器已启动:将在{_morningCheckTimeTwo:hh\\:mm}触发");
|
||
}
|
||
else
|
||
{
|
||
LogHelper.AppendLog("早上检查节点已过当天当前时间,跳过早上连杆检查定时器启动");
|
||
_isMorningRodUploadedTwo = true; // 标记为已检查,避免重复判断
|
||
}
|
||
|
||
// 2. 启动晚上检查定时器(若目标时间未过)
|
||
long eveningDelayMs = CalculateDelayToTargetTime(_eveningCheckTimeTwo, "evening");
|
||
if (eveningDelayMs > 0 && _eveningCheckTimeTwo > _workEndTimeTwo)
|
||
{
|
||
_eveningRodAlarmTimerTwo = new System.Timers.Timer(eveningDelayMs);
|
||
_eveningRodAlarmTimerTwo.AutoReset = false; // 一次性执行,不循环
|
||
_eveningRodAlarmTimerTwo.Elapsed += EveningRodDeviceTwoAlarmTimer_Elapsed;
|
||
_eveningRodAlarmTimerTwo.Enabled = true; // 启动定时器
|
||
LogHelper.AppendLog(
|
||
$"晚上连杆检查定时器已启动:将在{_eveningCheckTimeTwo:hh\\:mm}触发");
|
||
}
|
||
else
|
||
{
|
||
LogHelper.AppendLog("晚上检查节点已过当天当前时间,跳过晚上连杆检查定时器启动");
|
||
_isEveningRodUploadedTwo = true; // 标记为已检查,避免重复判断
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 终止所有报警定时任务并重置标记
|
||
/// </summary>
|
||
private void StopDeviceOneAlarmTimers()
|
||
{
|
||
// 终止报废定时
|
||
if (_scrapAlarmTimerOne != null)
|
||
{
|
||
_scrapAlarmTimerOne.Enabled = false;
|
||
_scrapAlarmTimerOne.Dispose();
|
||
_scrapAlarmTimerOne = null;
|
||
}
|
||
|
||
if (_scrapAlarmTimerTwo != null)
|
||
{
|
||
_scrapAlarmTimerTwo.Enabled = false;
|
||
_scrapAlarmTimerTwo.Dispose();
|
||
_scrapAlarmTimerTwo = null;
|
||
}
|
||
|
||
LogHelper.AppendLog("报废上传报警定时已终止");
|
||
|
||
// 重置静态上传标记
|
||
_isScrapImageUploadedOne = false;
|
||
_isRodImageUploadedOne = false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 终止所有报警定时任务并重置标记
|
||
/// </summary>
|
||
private void StopDeviceTwoAlarmTimers()
|
||
{
|
||
// 终止报废定时
|
||
if (_rodAlarmTimerOne != null)
|
||
{
|
||
_rodAlarmTimerOne.Enabled = false;
|
||
_rodAlarmTimerOne.Dispose();
|
||
_rodAlarmTimerOne = null;
|
||
}
|
||
|
||
if (_rodAlarmTimerTwo != null)
|
||
{
|
||
_rodAlarmTimerTwo.Enabled = false;
|
||
_rodAlarmTimerTwo.Dispose();
|
||
_rodAlarmTimerTwo = null;
|
||
}
|
||
|
||
LogHelper.AppendLog("连杆上传报警定时已终止");
|
||
|
||
// 重置静态上传标记
|
||
_isScrapImageUploadedTwo = false;
|
||
_isRodImageUploadedTwo = false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 跳过报废报警(设备1)
|
||
/// </summary>
|
||
/// <param name="sender"></param>
|
||
/// <param name="e"></param>
|
||
private void ScrapAlarmTimerOne_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||
{
|
||
DateTime now = DateTime.Now;
|
||
TimeSpan currentTime = now.TimeOfDay;
|
||
|
||
// 使用静态标记 _isScrapImageUploaded 判断是否报警(核心:上传成功则不报警)
|
||
if (!_isScrapImageUploadedOne)
|
||
{
|
||
string alarmContent = $"报废上传超时未上传凭证!<br>当前时间:{now:yyyy-MM-dd HH:mm:ss}";
|
||
this.Invoke(new Action(() => SendDingDingAlarm(alarmContent, false, "1")));
|
||
_isScrapImageWorkNoticeOne = true;
|
||
}
|
||
else
|
||
{
|
||
LogHelper.AppendLog($"报废上传{_lastScrapIntervalOne}分钟内已上传凭证,无需触发报警");
|
||
}
|
||
|
||
// 3. 销毁定时器,重置标记
|
||
_scrapAlarmTimerOne?.Dispose();
|
||
_scrapAlarmTimerOne = null;
|
||
_isScrapImageUploadedOne = false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 跳过报废报警(设备2)
|
||
/// </summary>
|
||
/// <param name="sender"></param>
|
||
/// <param name="e"></param>
|
||
private void ScrapAlarmTimerTwo_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||
{
|
||
DateTime now = DateTime.Now;
|
||
TimeSpan currentTime = now.TimeOfDay;
|
||
|
||
// 使用静态标记 _isScrapImageUploaded 判断是否报警(核心:上传成功则不报警)
|
||
if (!_isScrapImageUploadedTwo)
|
||
{
|
||
string alarmContent = $"报废上传超时未上传凭证!<br>当前时间:{now:yyyy-MM-dd HH:mm:ss}";
|
||
this.Invoke(new Action(() => SendDingDingAlarm(alarmContent, false, "2")));
|
||
_isScrapImageWorkNoticeTwo = true;
|
||
}
|
||
else
|
||
{
|
||
LogHelper.AppendLog($"报废上传{_lastScrapIntervalTwo}分钟内已上传凭证,无需触发报警");
|
||
}
|
||
|
||
// 3. 销毁定时器,重置标记
|
||
_scrapAlarmTimerTwo?.Dispose();
|
||
_scrapAlarmTimerTwo = null;
|
||
_isScrapImageUploadedTwo = false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 跳过连杆报警(设备1)
|
||
/// </summary>
|
||
/// <param name="sender"></param>
|
||
/// <param name="e"></param>
|
||
private void RodAlarmTimerOne_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||
{
|
||
DateTime now = DateTime.Now;
|
||
TimeSpan currentTime = now.TimeOfDay;
|
||
|
||
// 2. 使用静态标记 _isRodImageUploaded 判断是否报警
|
||
if (!_isRodImageUploadedOne)
|
||
{
|
||
string alarmContent = $"连杆测试超时未上传图片!<br>当前时间:{now:yyyy-MM-dd HH:mm:ss}";
|
||
this.Invoke(new Action(() => SendDingDingAlarm(alarmContent, true, "1")));
|
||
_isRodImageWorkNoticeOne = true;
|
||
}
|
||
else
|
||
{
|
||
LogHelper.AppendLog($"连杆测试{_lastRodIntervalOne}分钟内已上传图片,无需触发报警");
|
||
}
|
||
|
||
// 3. 销毁定时器,重置标记
|
||
_rodAlarmTimerOne?.Dispose();
|
||
_rodAlarmTimerOne = null;
|
||
_isRodImageUploadedOne = false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 跳过连杆报警(设备2)
|
||
/// </summary>
|
||
/// <param name="sender"></param>
|
||
/// <param name="e"></param>
|
||
private void RodAlarmTimerTwo_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||
{
|
||
DateTime now = DateTime.Now;
|
||
TimeSpan currentTime = now.TimeOfDay;
|
||
|
||
// 2. 使用静态标记 _isRodImageUploaded 判断是否报警
|
||
if (!_isRodImageUploadedTwo)
|
||
{
|
||
string alarmContent = $"连杆测试超时未上传图片!<br>当前时间:{now:yyyy-MM-dd HH:mm:ss}";
|
||
this.Invoke(new Action(() => SendDingDingAlarm(alarmContent, true, "2")));
|
||
_isRodImageWorkNoticeTwo = true;
|
||
}
|
||
else
|
||
{
|
||
LogHelper.AppendLog($"连杆测试{_lastRodIntervalTwo}分钟内已上传图片,无需触发报警");
|
||
}
|
||
|
||
// 3. 销毁定时器,重置标记
|
||
_rodAlarmTimerTwo?.Dispose();
|
||
_rodAlarmTimerTwo = null;
|
||
_isRodImageUploadedTwo = false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 发送钉钉报警
|
||
/// </summary>
|
||
/// <param name="alarmContent"></param>
|
||
/// <param name="isRodAlarm"></param>
|
||
private async void SendDingDingAlarm(string alarmContent, bool isRodAlarm, string deviceCode)
|
||
{
|
||
try
|
||
{
|
||
LogHelper.AppendLog($"【钉钉报警】{(isRodAlarm ? "连杆" : "报废")}:{alarmContent}");
|
||
await _uploadService.SendDingDingTextAlarmAsync(alarmContent, deviceCode, isRodAlarm);
|
||
// if (deviceCode.Contains("1"))
|
||
// {
|
||
// _isScrapImageWorkNoticeOne = true;
|
||
// }
|
||
// else
|
||
// {
|
||
// _isScrapImageWorkNoticeTwo = true;
|
||
// }
|
||
|
||
|
||
// MessageBox.Show($"已发送钉钉{(isRodAlarm ? "连杆" : "报废")}报警:{alarmContent}", "报警提示", MessageBoxButtons.OK,
|
||
// MessageBoxIcon.Warning);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogHelper.AppendLog($"{(isRodAlarm ? "连杆" : "报废")}钉钉报警发送失败:{ex.Message}");
|
||
}
|
||
}
|
||
|
||
// ======================================== 上传状态回调方法(连杆+报废) ========================================
|
||
|
||
/// <summary>
|
||
/// 报废上传状态回调(设备1)
|
||
/// </summary>
|
||
private void OnScrapUploadStatusChangedOne(object sender, ScrapUploadStatusEventArgs e)
|
||
{
|
||
if (this.InvokeRequired)
|
||
{
|
||
this.Invoke(new Action<object, ScrapUploadStatusEventArgs>(OnScrapUploadStatusChangedOne), sender, e);
|
||
return;
|
||
}
|
||
|
||
_isScrapImageUploadedInCycleOne = e.IsUploadSuccess;
|
||
// 上传成功时更新静态标记
|
||
if (e.IsUploadSuccess)
|
||
{
|
||
_isScrapImageUploadedOne = true;
|
||
LogHelper.AppendLog("设备1报废凭证上传成功");
|
||
}
|
||
|
||
LogHelper.AppendLog($"报废上传状态:{(e.IsUploadSuccess ? "成功" : "失败")},消息:{e.Message}");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 报废上传状态回调(设备2)
|
||
/// </summary>
|
||
private void OnScrapUploadStatusChangedTwo(object sender, ScrapUploadStatusEventArgs e)
|
||
{
|
||
if (this.InvokeRequired)
|
||
{
|
||
this.Invoke(new Action<object, ScrapUploadStatusEventArgs>(OnScrapUploadStatusChangedOne), sender, e);
|
||
return;
|
||
}
|
||
|
||
_isScrapImageUploadedInCycleTwo = e.IsUploadSuccess;
|
||
// 上传成功时更新静态标记
|
||
if (e.IsUploadSuccess)
|
||
{
|
||
_isScrapImageUploadedTwo = true;
|
||
LogHelper.AppendLog("设备2报废凭证上传成功");
|
||
}
|
||
|
||
LogHelper.AppendLog($"报废上传状态:{(e.IsUploadSuccess ? "成功" : "失败")},消息:{e.Message}");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 连杆上传状态回调(设备1)
|
||
/// </summary>
|
||
private void OnRodUploadStatusChangedOne(object sender, RodUploadStatusEventArgs e)
|
||
{
|
||
if (this.InvokeRequired)
|
||
{
|
||
this.Invoke(new Action<object, RodUploadStatusEventArgs>(OnRodUploadStatusChangedOne), sender, e);
|
||
return;
|
||
}
|
||
|
||
_isRodUploadedInCycleOne = e.IsUploadSuccess;
|
||
// 上传成功时更新静态标记
|
||
if (e.IsUploadSuccess)
|
||
{
|
||
_isRodImageUploadedOne = true;
|
||
LogHelper.AppendLog("连杆图片上传成功,标记为「已上传」,定时结束后将不触发报警");
|
||
|
||
// // ========== 保留:同步更新早晚连杆上传标记(未到节点时) ==========
|
||
// TimeSpan currentTime = DateTime.Now.TimeOfDay;
|
||
//
|
||
// // 早上节点前上传,更新早上标记
|
||
// if (currentTime < _morningCheckTime && !_isMorningRodUploaded)
|
||
// {
|
||
// _isMorningRodUploaded = true;
|
||
// LogHelper.AppendLog("连杆图片上传成功,同步标记:早上无需触发强制上传报警");
|
||
// }
|
||
// // 晚上节点前上传,更新晚上标记
|
||
// else if (currentTime >= _morningCheckTime && currentTime < _eveningCheckTime && !_isEveningRodUploaded)
|
||
// {
|
||
// _isEveningRodUploaded = true;
|
||
// LogHelper.AppendLog("连杆图片上传成功,同步标记:晚上无需触发强制上传报警");
|
||
// }
|
||
}
|
||
|
||
LogHelper.AppendLog($"连杆上传状态:{(e.IsUploadSuccess ? "成功" : "失败")},消息:{e.Message}");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 连杆上传状态回调(设备2)
|
||
/// </summary>
|
||
private void OnRodUploadStatusChangedTwo(object sender, RodUploadStatusEventArgs e)
|
||
{
|
||
if (this.InvokeRequired)
|
||
{
|
||
this.Invoke(new Action<object, RodUploadStatusEventArgs>(OnRodUploadStatusChangedTwo), sender, e);
|
||
return;
|
||
}
|
||
|
||
_isRodUploadedInCycleTwo = e.IsUploadSuccess;
|
||
// 上传成功时更新静态标记
|
||
if (e.IsUploadSuccess)
|
||
{
|
||
_isRodImageUploadedTwo = true;
|
||
LogHelper.AppendLog("连杆图片上传成功,标记为「已上传」,定时结束后将不触发报警");
|
||
|
||
// // ========== 保留:同步更新早晚连杆上传标记(未到节点时) ==========
|
||
// TimeSpan currentTime = DateTime.Now.TimeOfDay;
|
||
//
|
||
// // 早上节点前上传,更新早上标记
|
||
// if (currentTime < _morningCheckTime && !_isMorningRodUploaded)
|
||
// {
|
||
// _isMorningRodUploaded = true;
|
||
// LogHelper.AppendLog("连杆图片上传成功,同步标记:早上无需触发强制上传报警");
|
||
// }
|
||
// // 晚上节点前上传,更新晚上标记
|
||
// else if (currentTime >= _morningCheckTime && currentTime < _eveningCheckTime && !_isEveningRodUploaded)
|
||
// {
|
||
// _isEveningRodUploaded = true;
|
||
// LogHelper.AppendLog("连杆图片上传成功,同步标记:晚上无需触发强制上传报警");
|
||
// }
|
||
}
|
||
|
||
LogHelper.AppendLog($"连杆上传状态:{(e.IsUploadSuccess ? "成功" : "失败")},消息:{e.Message}");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化早晚连杆检查节点时间(基于配置的工作时间)
|
||
/// </summary>
|
||
private void InitDailyRodDeviceOneCheckTimes()
|
||
{
|
||
// 计算早上检查节点:工作开始时间 + 30分钟
|
||
_morningCheckTimeOne = _workStartTimeOne.Add(TimeSpan.FromMinutes(2));
|
||
// 计算晚上检查节点:工作结束时间 + 30分钟
|
||
_eveningCheckTimeOne = _workEndTimeOne.Add(TimeSpan.FromMinutes(2));
|
||
|
||
// 校验:防止晚上检查节点早于早上检查节点(避免用户配置异常)
|
||
if (_eveningCheckTimeOne <= _morningCheckTimeOne)
|
||
{
|
||
LogHelper.AppendLog("警告:工作时间配置异常,结束时间前30分钟早于开始时间后30分钟,早晚连杆检查功能将失效");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化早晚连杆检查节点时间(设备2)
|
||
/// </summary>
|
||
private void InitDailyRodDeviceTwoCheckTimes()
|
||
{
|
||
// 计算早上检查节点:工作开始时间 + 2分钟
|
||
_morningCheckTimeTwo = _workStartTimeTwo.Add(TimeSpan.FromMinutes(2));
|
||
// 计算晚上检查节点:工作结束时间 + 2分钟
|
||
_eveningCheckTimeTwo = _workEndTimeTwo.Add(TimeSpan.FromMinutes(2));
|
||
|
||
// 校验:防止晚上检查节点早于早上检查节点(避免用户配置异常)
|
||
if (_eveningCheckTimeTwo <= _morningCheckTimeTwo)
|
||
{
|
||
LogHelper.AppendLog("警告:工作时间配置异常,结束时间前30分钟早于开始时间后30分钟,早晚连杆检查功能将失效");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算当前时间到目标检查节点的毫秒数(用于设置定时器延迟)
|
||
/// </summary>
|
||
/// <param name="targetTime">目标检查节点(当天的时间点)</param>
|
||
/// <returns>延迟毫秒数(若目标时间已过,返回-1)</returns>
|
||
private long CalculateDelayToTargetTime(TimeSpan targetTime, string dayOrNight)
|
||
{
|
||
DateTime now = DateTime.Now;
|
||
// 拼接当天的目标日期时间
|
||
DateTime targetDateTime = new DateTime(now.Year, now.Month, now.Day,
|
||
targetTime.Hours, targetTime.Minutes, targetTime.Seconds);
|
||
TimeSpan delay;
|
||
if (targetDateTime <= now)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
// 计算延迟毫秒数
|
||
delay = targetDateTime - now;
|
||
return (long)delay.TotalMilliseconds;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 停止设备1早晚连杆检查定时器
|
||
/// </summary>
|
||
private void StopDailyRodDeviceOneFixedTimers()
|
||
{
|
||
// 仅停止设备1的定时器
|
||
if (_morningRodAlarmTimerOne != null)
|
||
{
|
||
_morningRodAlarmTimerOne.Enabled = false;
|
||
_morningRodAlarmTimerOne.Dispose();
|
||
_morningRodAlarmTimerOne = null;
|
||
}
|
||
|
||
if (_eveningRodAlarmTimerOne != null)
|
||
{
|
||
_eveningRodAlarmTimerOne.Enabled = false;
|
||
_eveningRodAlarmTimerOne.Dispose();
|
||
_eveningRodAlarmTimerOne = null;
|
||
}
|
||
|
||
LogHelper.AppendLog("设备1早晚连杆检查定时器已停止");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 停止设备2早晚连杆检查定时器
|
||
/// </summary>
|
||
private void StopDailyRodDeviceTwoFixedTimers()
|
||
{
|
||
// 仅停止设备2的定时器
|
||
if (_morningRodAlarmTimerTwo != null)
|
||
{
|
||
_morningRodAlarmTimerTwo.Enabled = false;
|
||
_morningRodAlarmTimerTwo.Dispose();
|
||
_morningRodAlarmTimerTwo = null;
|
||
}
|
||
|
||
if (_eveningRodAlarmTimerTwo != null)
|
||
{
|
||
_eveningRodAlarmTimerTwo.Enabled = false;
|
||
_eveningRodAlarmTimerTwo.Dispose();
|
||
_eveningRodAlarmTimerTwo = null;
|
||
}
|
||
|
||
LogHelper.AppendLog("设备2早晚连杆检查定时器已停止");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 重置早晚连杆上传标记(每日启动定时器或网关断开时调用)
|
||
/// </summary>
|
||
private void ResetDailyRodMarks()
|
||
{
|
||
_isMorningRodUploadedOne = false;
|
||
_isEveningRodUploadedOne = false;
|
||
|
||
_isMorningRodUploadedTwo = false;
|
||
_isEveningRodUploadedTwo = false;
|
||
LogHelper.AppendLog("早晚连杆上传标记已重置:早上未上传、晚上未上传");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 早上连杆检查定时器回调(工作开始+30分钟)
|
||
/// </summary>
|
||
private void MorningRodDeviceOneAlarmTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||
{
|
||
// 1. 判断是否已上传,未上传则触发报警
|
||
if (!_isMorningRodUploadedOne)
|
||
{
|
||
DateTime now = DateTime.Now;
|
||
string morningAlarmContent =
|
||
$"【早上连杆强制上传报警】<br>当前时间{now:yyyy-MM-dd HH:mm:ss},<br>已超过工作开始后30分钟({_morningCheckTimeOne:hh\\:mm}),<br>未上传连杆测试图片!";
|
||
this.Invoke(new Action(() => SendDingDingAlarm(morningAlarmContent, true, "1")));
|
||
_isRodImageWorkNoticeOne = true;
|
||
}
|
||
else
|
||
{
|
||
LogHelper.AppendLog($"早上{_morningCheckTimeOne:hh\\:mm}:连杆图片已上传,无需触发强制上传报警");
|
||
}
|
||
|
||
// 2. 销毁早上定时器,标记为已检查(避免重复触发)
|
||
_morningRodAlarmTimerOne?.Dispose();
|
||
_morningRodAlarmTimerOne = null;
|
||
_isMorningRodUploadedOne = true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 晚上连杆检查定时器回调(工作结束+30分钟)
|
||
/// </summary>
|
||
private void EveningRodDeviceOneAlarmTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||
{
|
||
// 1. 判断是否已上传,未上传则触发报警
|
||
if (!_isEveningRodUploadedOne)
|
||
{
|
||
DateTime now = DateTime.Now;
|
||
string eveningAlarmContent =
|
||
$"【晚上连杆强制上传报警】<br>当前时间{now:yyyy-MM-dd HH:mm:ss},<br>已超过工作结束前30分钟({_eveningCheckTimeOne:hh\\:mm}),<br>未上传连杆测试图片!";
|
||
this.Invoke(new Action(() => SendDingDingAlarm(eveningAlarmContent, true, "1")));
|
||
_isRodImageWorkNoticeOne = true;
|
||
}
|
||
else
|
||
{
|
||
LogHelper.AppendLog($"晚上{_eveningCheckTimeOne:hh\\:mm}:连杆图片已上传,无需触发强制上传报警");
|
||
}
|
||
|
||
// 2. 销毁晚上定时器,标记为已检查(避免重复触发)
|
||
_eveningRodAlarmTimerOne?.Dispose();
|
||
_eveningRodAlarmTimerOne = null;
|
||
_isEveningRodUploadedOne = true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 早上连杆检查定时器回调(工作开始+30分钟)
|
||
/// </summary>
|
||
private void MorningRodDeviceTwoAlarmTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||
{
|
||
// 1. 判断是否已上传,未上传则触发报警
|
||
if (!_isMorningRodUploadedTwo)
|
||
{
|
||
DateTime now = DateTime.Now;
|
||
string morningAlarmContent =
|
||
$"【早上连杆强制上传报警】<br>当前时间{now:yyyy-MM-dd HH:mm:ss},<br>已超过工作开始后30分钟({_morningCheckTimeTwo:hh\\:mm}),<br>未上传连杆测试图片!";
|
||
this.Invoke(new Action(() => SendDingDingAlarm(morningAlarmContent, true, "2")));
|
||
_isRodImageWorkNoticeTwo = true;
|
||
}
|
||
else
|
||
{
|
||
LogHelper.AppendLog($"早上{_morningCheckTimeTwo:hh\\:mm}:连杆图片已上传,无需触发强制上传报警");
|
||
}
|
||
|
||
// 2. 销毁早上定时器,标记为已检查(避免重复触发)
|
||
_morningRodAlarmTimerTwo?.Dispose();
|
||
_morningRodAlarmTimerTwo = null;
|
||
_isMorningRodUploadedTwo = true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 晚上连杆检查定时器回调(工作结束+30分钟)
|
||
/// </summary>
|
||
private void EveningRodDeviceTwoAlarmTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||
{
|
||
// 1. 判断是否已上传,未上传则触发报警
|
||
if (!_isEveningRodUploadedTwo)
|
||
{
|
||
DateTime now = DateTime.Now;
|
||
string eveningAlarmContent =
|
||
$"【晚上连杆强制上传报警】<br>当前时间{now:yyyy-MM-dd HH:mm:ss},<br>已超过工作结束前30分钟({_eveningCheckTimeTwo:hh\\:mm}),<br>未上传连杆测试图片!";
|
||
this.Invoke(new Action(() => SendDingDingAlarm(eveningAlarmContent, true, "2")));
|
||
_isRodImageWorkNoticeTwo = true;
|
||
}
|
||
else
|
||
{
|
||
LogHelper.AppendLog($"晚上{_eveningCheckTimeTwo:hh\\:mm}:连杆图片已上传,无需触发强制上传报警");
|
||
}
|
||
|
||
// 2. 销毁晚上定时器,标记为已检查(避免重复触发)
|
||
_eveningRodAlarmTimerTwo?.Dispose();
|
||
_eveningRodAlarmTimerTwo = null;
|
||
_isEveningRodUploadedTwo = true;
|
||
}
|
||
|
||
// ======================================== 辅助方法 ========================================
|
||
private async void Timer_Elapsed(object sender, ElapsedEventArgs e)
|
||
{
|
||
// 适配移植的配方变量,刷新选中配方
|
||
string selected1 = this.comboBox1.SelectedValue?.ToString();
|
||
string selected2 = this.comboBox2.SelectedValue?.ToString();
|
||
RefreshSelectedFormula(selected1, selected2);
|
||
// await MqttYiDaUpload();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 刷新选中配方(辅助方法)
|
||
/// </summary>
|
||
private void RefreshSelectedFormula(string selected1, string selected2)
|
||
{
|
||
if (string.IsNullOrEmpty(selected1) || selected1 == "-1")
|
||
{
|
||
_formulasListOne = null;
|
||
return;
|
||
}
|
||
|
||
string[] arr1 = selected1.Split('|');
|
||
if (arr1.Length == 2)
|
||
{
|
||
string partNumber1 = arr1[0];
|
||
string partName1 = arr1[1];
|
||
_formulasListOne = _formulas.AsEnumerable()
|
||
.Where(r => r.Field<string>("part_number") == partNumber1
|
||
&& r.Field<string>("part_name") == partName1)
|
||
.ToList();
|
||
}
|
||
|
||
if (string.IsNullOrEmpty(selected2) || selected2 == "-1")
|
||
{
|
||
_formulasListTwo = null;
|
||
return;
|
||
}
|
||
|
||
string[] arr2 = selected2.Split('|');
|
||
if (arr2.Length == 2)
|
||
{
|
||
string partNumber2 = arr2[0];
|
||
string partName2 = arr2[1];
|
||
_formulasListTwo = _formulas.AsEnumerable()
|
||
.Where(r => r.Field<string>("part_number") == partNumber2
|
||
&& r.Field<string>("part_name") == partName2)
|
||
.ToList();
|
||
}
|
||
}
|
||
|
||
// ======================================== 核心上传方法 ========================================
|
||
private async Task MqttYiDaUpload(string selection, string device)
|
||
{
|
||
try
|
||
{
|
||
DataTable dtMqtt = await _buttonService.GetLatestMqttDataAsync(selection, device);
|
||
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}]数据");
|
||
|
||
// ======================================== 使用移植的配方列表变量 ========================================
|
||
List<DataRow> formulaList = null;
|
||
string site = null;
|
||
if (string.Equals(deviceCode, "device1", StringComparison.Ordinal))
|
||
{
|
||
formulaList = _formulasListOne;
|
||
site = "1号设备";
|
||
}
|
||
else if (string.Equals(deviceCode, "device2", StringComparison.Ordinal))
|
||
{
|
||
formulaList = _formulasListTwo;
|
||
site = "2号设备";
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
// ======================================== 使用移植的MQTT字典进行参数映射 ========================================
|
||
DataRow[] drs = _dtMqttDic.Select($"param_code = '" + paramCode + "'");
|
||
string paramName = paramCode;
|
||
if (drs != null && drs.Length > 0)
|
||
{
|
||
paramName = drs[0]["param_name"].ToString();
|
||
}
|
||
|
||
DataRow drMatch =
|
||
formulaList.FirstOrDefault(r => r.Field<string>("parameter_name") == paramName);
|
||
if (drMatch == null)
|
||
{
|
||
LogHelper.AppendLog($"设备[{deviceCode}]配方中未找到参数[{paramName}],跳过");
|
||
continue;
|
||
}
|
||
|
||
|
||
YiDaModel yidaNew = BuildYiDaModel(drMatch, paramName, value, site);
|
||
MqttModel mqttNew = BuildMqttModel(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, mqttLists1, 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);
|
||
}));
|
||
}
|
||
}
|
||
|
||
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, site);
|
||
|
||
return mqttNew;
|
||
}
|
||
|
||
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);
|
||
|
||
yidaNew.textField_mha98nf5 = JudgeQualification(paramName, value, drMatch, site);
|
||
|
||
return yidaNew;
|
||
}
|
||
|
||
private string JudgeQualification(string paramName, object value, DataRow drMatch, string site)
|
||
{
|
||
if (paramName == "报警信息")
|
||
{
|
||
return string.Equals(value?.ToString(), "无错误", StringComparison.Ordinal) ? "合格" : "不合格";
|
||
}
|
||
else if (paramName == "报废图片" || paramName == "连杆测试")
|
||
{
|
||
bool isNoticeTriggered = false;
|
||
if (paramName == "报废图片")
|
||
{
|
||
isNoticeTriggered = (site == "1号设备" && _isScrapImageWorkNoticeOne)
|
||
|| (site == "2号设备" && _isScrapImageWorkNoticeTwo);
|
||
}
|
||
else if (paramName == "连杆测试")
|
||
{
|
||
isNoticeTriggered = (site == "1号设备" && _isRodImageWorkNoticeOne)
|
||
|| (site == "2号设备" && _isRodImageWorkNoticeTwo);
|
||
}
|
||
if (isNoticeTriggered)
|
||
{
|
||
// 重置对应设备的标记
|
||
if (paramName == "报废图片")
|
||
{
|
||
if (site == "1号设备") _isScrapImageWorkNoticeOne = false;
|
||
if (site == "2号设备") _isScrapImageWorkNoticeTwo = false;
|
||
}
|
||
else if (paramName == "连杆测试")
|
||
{
|
||
if (site == "1号设备") _isRodImageWorkNoticeOne = false;
|
||
if (site == "2号设备") _isRodImageWorkNoticeTwo = false;
|
||
}
|
||
return "不合格";
|
||
}
|
||
else
|
||
{
|
||
return "合格";
|
||
}
|
||
}
|
||
else if (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 "不合格";
|
||
}
|
||
}
|
||
}
|
||
|
||
// ======================================== 日志相关方法 ========================================
|
||
private void OnMqttMessage(string msg)
|
||
{
|
||
if (this.InvokeRequired)
|
||
{
|
||
this.Invoke(new Action<string>(OnMqttMessage), msg);
|
||
return;
|
||
}
|
||
|
||
LogHelper.AppendLog($"收到消息: {msg}");
|
||
}
|
||
|
||
private void LogHelper_OnLogGenerated(string logContent)
|
||
{
|
||
Action appendAction = () => AppendLogToTextBox(logContent);
|
||
if (textBoxLog.InvokeRequired)
|
||
{
|
||
textBoxLog.BeginInvoke(appendAction); // 改用BeginInvoke避免阻塞
|
||
}
|
||
else
|
||
{
|
||
appendAction();
|
||
}
|
||
}
|
||
|
||
// 定义日志最大行数
|
||
private const int MAX_LOG_LINES = 100;
|
||
|
||
/// <summary>
|
||
/// 日志到WinForm弹窗
|
||
/// </summary>
|
||
/// <param name="logContent"></param>
|
||
private void AppendLogToTextBox(string logContent)
|
||
{
|
||
// 解决跨线程访问控件的问题(WinForm必备)
|
||
if (textBoxLog.InvokeRequired)
|
||
{
|
||
textBoxLog.Invoke(new Action<string>(AppendLogToTextBox), logContent);
|
||
return;
|
||
}
|
||
|
||
// 1. 拆分现有日志为行列表(修复原代码空行问题)
|
||
List<string> logLines = textBoxLog.Text
|
||
.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries)
|
||
.ToList();
|
||
|
||
// 2. 添加新日志行(原代码错误地添加了logContent而非newLog,这里统一处理)
|
||
logLines.Add(logContent);
|
||
|
||
// 3. 如果超过最大行数,删除最旧的行(核心逻辑优化)
|
||
if (logLines.Count > MAX_LOG_LINES)
|
||
{
|
||
// 移除超出部分的最旧日志(从列表头部删除)
|
||
logLines.RemoveRange(0, logLines.Count - MAX_LOG_LINES);
|
||
}
|
||
|
||
// 4. 重新拼接日志内容(避免末尾多余空行)
|
||
textBoxLog.Text = string.Join("\r\n", logLines);
|
||
|
||
// 5. 保持滚动到底部
|
||
textBoxLog.SelectionStart = textBoxLog.Text.Length;
|
||
textBoxLog.ScrollToCaret();
|
||
|
||
}
|
||
|
||
// ======================================== 未实现方法 ========================================
|
||
|
||
private void txtLUploadPL_TextChanged(object sender, EventArgs e)
|
||
{
|
||
}
|
||
|
||
private void panel1_Paint_1(object sender, PaintEventArgs e)
|
||
{
|
||
}
|
||
|
||
private void label6_Click(object sender, EventArgs e)
|
||
{
|
||
}
|
||
|
||
private void label8_Click(object sender, EventArgs e)
|
||
{
|
||
}
|
||
|
||
private void panel3_Paint(object sender, PaintEventArgs e)
|
||
{
|
||
}
|
||
|
||
private void toolStripStatusLabel1_Click(object sender, EventArgs e)
|
||
{
|
||
}
|
||
}
|
||
} |