392 lines
15 KiB
C#
392 lines
15 KiB
C#
using Modbus.Device;
|
||
using OfficeOpenXml;
|
||
using OfficeOpenXml.Style;
|
||
using Sunny.UI;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.ComponentModel;
|
||
using System.Data;
|
||
using System.Drawing;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Net.Sockets;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using System.Windows.Forms;
|
||
using 薄膜气体透过率测试仪.Data;
|
||
using static 薄膜气体透过率测试仪.TestScreen;
|
||
|
||
namespace 薄膜气体透过率测试仪
|
||
{
|
||
public partial class TianpaReport : UIForm
|
||
{
|
||
#region 私有字段
|
||
|
||
private TcpClient _tcpClient => ModbusResourceManager.Instance.TcpClient;
|
||
private IModbusMaster _modbusMaster => ModbusResourceManager.Instance.ModbusMaster;
|
||
|
||
#endregion
|
||
|
||
private TestScreen _testScreen;
|
||
Timer Timer;
|
||
Function ma;
|
||
|
||
private List<TianpaReportRecord> reports;
|
||
|
||
public TianpaReport(List<TianpaReportRecord> reports)
|
||
{
|
||
InitializeComponent();
|
||
|
||
this.reports = reports;
|
||
|
||
Timer = new Timer();
|
||
Timer.Tick += Timer_Tick;
|
||
Timer.Interval = 500;
|
||
Timer.Start();
|
||
}
|
||
|
||
private void Timer_Tick(object sender, EventArgs e)
|
||
{
|
||
uiLabel2.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||
}
|
||
|
||
private void SwitchWindow<T>(ref T windowInstance, Func<T> createFunc) where T : UIForm
|
||
{
|
||
//1.停止当前窗口的定时器(不释放资源)
|
||
Timer?.Stop();
|
||
|
||
// 2. 检查资源是否可用(添加重连机制)
|
||
if (_tcpClient == null || !_tcpClient.Connected || _modbusMaster == null)
|
||
{
|
||
//尝试重新连接
|
||
bool reconnectSuccess = TryReconnect();
|
||
if (!reconnectSuccess)
|
||
{
|
||
MessageBox.Show("TCP连接已断开,请重新连接!", "提示");
|
||
return;
|
||
}
|
||
}
|
||
|
||
// 3. 复用窗口实例:不存在则创建,存在则激活
|
||
if (windowInstance == null)
|
||
{
|
||
windowInstance = createFunc();
|
||
// 添加窗口关闭事件处理
|
||
windowInstance.Closed += (s, args) =>
|
||
{
|
||
// 窗口关闭时重新启动定时器并显示当前窗口
|
||
//_readtimer?.Start();
|
||
//this.Show();
|
||
this.Activate();
|
||
};
|
||
}
|
||
else
|
||
{
|
||
// 激活已存在的窗口(前置显示)
|
||
windowInstance.Activate();
|
||
return;
|
||
}
|
||
|
||
// 4. 切换窗口:隐藏当前窗口,显示目标窗口(非模态)
|
||
this.Hide();
|
||
windowInstance.Show(); // 使用 Show() 而不是 ShowDialog()
|
||
}
|
||
private bool TryReconnect()
|
||
{
|
||
try
|
||
{
|
||
string plcIp = "192.168.1.10";
|
||
bool initSuccess = Data.ModbusResourceManager.Instance.Init(plcIp, 502);
|
||
if (initSuccess)
|
||
{
|
||
ma = new Function(_modbusMaster);
|
||
return true;
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
ShowError($"重新连接失败:{ex.Message}");
|
||
}
|
||
return false;
|
||
}
|
||
|
||
private void ShowError(string msg) => MessageBox.Show(msg, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
|
||
private void AdjustDataGridViewStyle()
|
||
{
|
||
foreach (DataGridViewColumn column in uiDataGridView1.Columns)
|
||
{
|
||
// 自动调整列宽(适配内容)
|
||
column.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
|
||
// 列宽最小值(防止过窄)
|
||
if (column.Width < 120) column.Width = 150;
|
||
// 单元格内容居中
|
||
column.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
|
||
column.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
|
||
}
|
||
}
|
||
|
||
private void ExportToExcel(string filePath)
|
||
{
|
||
try
|
||
{
|
||
string extension = Path.GetExtension(filePath).ToLower();
|
||
|
||
// 根据文件后缀分支处理
|
||
switch (extension)
|
||
{
|
||
case ".xlsx":
|
||
ExportToXlsx(filePath); // Excel格式(支持样式)
|
||
break;
|
||
case ".csv":
|
||
ExportToCsv(filePath); // CSV格式(基础导出)
|
||
break;
|
||
case ".pdf":
|
||
ShowMessage("提示", "PDF导出暂未实现,已自动切换为Excel格式", UIMessageBoxIcon.Info);
|
||
ExportToXlsx(Path.ChangeExtension(filePath, ".xlsx"));
|
||
filePath = Path.ChangeExtension(filePath, ".xlsx");
|
||
break;
|
||
default:
|
||
throw new NotSupportedException("不支持的文件格式!");
|
||
}
|
||
|
||
ShowMessage("导出成功", $"报表已成功导出到:{filePath}", UIMessageBoxIcon.Success);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
ShowMessage("导出错误", $"导出失败:{ex.Message}", UIMessageBoxIcon.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 导出为Excel(.xlsx),支持列宽调整+居中样式
|
||
/// </summary>
|
||
private void ExportToXlsx(string filePath)
|
||
{
|
||
// 授权EPPlus使用(非商业用途)
|
||
//ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial;
|
||
|
||
using (var package = new ExcelPackage())
|
||
{
|
||
var worksheet = package.Workbook.Worksheets.Add("秒帕记录报告");
|
||
|
||
// 找到化验编号输入文本框
|
||
//var labNumberInput = this.Controls.OfType<TextBox>()
|
||
// .FirstOrDefault(tb => tb.Location.X == uiDataGridView1.Width - 130 && tb.ReadOnly == false);
|
||
//string labNumberValue = labNumberInput?.Text?.Trim() ?? "未填写";
|
||
|
||
// 1. 写入化验编号(第1行)
|
||
//worksheet.Cells["A1"].Value = "化验编号";
|
||
//worksheet.Cells["B1"].Value = labNumberValue;
|
||
// 合并单元格(美化)
|
||
//worksheet.Cells["A1:B1"].Style.Font.Bold = true;
|
||
//worksheet.Cells["A1:B1"].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
|
||
|
||
// 2. 写入表头(第3行,空出第2行分隔)
|
||
int headerRow = 1;
|
||
for (int i = 0; i < uiDataGridView1.Columns.Count; i++)
|
||
{
|
||
worksheet.Cells[headerRow, i + 1].Value = uiDataGridView1.Columns[i].HeaderText;
|
||
// 表头样式:加粗+居中
|
||
worksheet.Cells[headerRow, i + 1].Style.Font.Bold = true;
|
||
worksheet.Cells[headerRow, i + 1].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
|
||
worksheet.Cells[headerRow, i + 1].Style.VerticalAlignment = ExcelVerticalAlignment.Center;
|
||
}
|
||
|
||
// 3. 写入数据行
|
||
int dataRow = headerRow + 1;
|
||
foreach (DataGridViewRow row in uiDataGridView1.Rows)
|
||
{
|
||
if (!row.IsNewRow)
|
||
{
|
||
for (int i = 0; i < row.Cells.Count; i++)
|
||
{
|
||
string cellValue = row.Cells[i].Value?.ToString() ?? "";
|
||
cellValue = cellValue.Replace("\n", " ").Replace("\r", " ").Trim();
|
||
worksheet.Cells[dataRow, i + 1].Value = cellValue;
|
||
// 数据居中
|
||
worksheet.Cells[dataRow, i + 1].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
|
||
worksheet.Cells[dataRow, i + 1].Style.VerticalAlignment = ExcelVerticalAlignment.Center;
|
||
// 日期列特殊处理(确保格式完整)
|
||
if (uiDataGridView1.Columns[i].HeaderText.Contains("时间") ||
|
||
uiDataGridView1.Columns[i].HeaderText.Contains("日期"))
|
||
{
|
||
worksheet.Cells[dataRow, i + 1].Style.Numberformat.Format = "yyyy-MM-dd HH:mm:ss";
|
||
}
|
||
}
|
||
dataRow++;
|
||
}
|
||
}
|
||
|
||
// 4. 自动调整列宽(关键:解决日期显示不完整)
|
||
for (int i = 1; i <= uiDataGridView1.Columns.Count; i++)
|
||
{
|
||
// 自动适配内容宽度,最小值15(Excel列宽单位)
|
||
worksheet.Column(i).AutoFit();
|
||
if (worksheet.Column(i).Width < 15)
|
||
{
|
||
worksheet.Column(i).Width = 15;
|
||
}
|
||
// 日期列强制加宽(避免仍截断)
|
||
if (worksheet.Cells[headerRow, i].Value?.ToString().Contains("时间") == true ||
|
||
worksheet.Cells[headerRow, i].Value?.ToString().Contains("日期") == true)
|
||
{
|
||
worksheet.Column(i).Width = 25;
|
||
}
|
||
}
|
||
|
||
// 5. 保存文件
|
||
package.SaveAs(new FileInfo(filePath));
|
||
}
|
||
}
|
||
|
||
private void ExportToCsv(string filePath)
|
||
{
|
||
var labNumberInput = this.Controls.OfType<TextBox>()
|
||
.FirstOrDefault(tb => tb.Location.X == uiDataGridView1.Width - 130 && tb.ReadOnly == false);
|
||
string labNumberValue = labNumberInput?.Text?.Trim() ?? "未填写";
|
||
|
||
using (var writer = new StreamWriter(filePath, false, System.Text.Encoding.UTF8))
|
||
{
|
||
writer.Write('\uFEFF');
|
||
writer.WriteLine(); // 空行分隔
|
||
|
||
// 写入表头
|
||
var headerCells = new List<string>();
|
||
foreach (DataGridViewColumn column in uiDataGridView1.Columns)
|
||
{
|
||
headerCells.Add(EscapeCsv(column.HeaderText));
|
||
}
|
||
writer.WriteLine(string.Join(",", headerCells));
|
||
|
||
// 写入数据
|
||
foreach (DataGridViewRow row in uiDataGridView1.Rows)
|
||
{
|
||
if (!row.IsNewRow)
|
||
{
|
||
var cells = new List<string>();
|
||
foreach (DataGridViewCell cell in row.Cells)
|
||
{
|
||
string cellValue = cell.Value?.ToString() ?? "";
|
||
cellValue = cellValue.Replace("\n", " ").Replace("\r", " ").Trim();
|
||
cells.Add(EscapeCsv(cellValue));
|
||
}
|
||
writer.WriteLine(string.Join(",", cells));
|
||
}
|
||
}
|
||
}
|
||
|
||
// 提示CSV样式调整方法
|
||
ShowMessage("提示", "CSV文件导出成功!打开后可手动设置:\n1. 选中列 → 右键 → 列宽(建议日期列设为20)\n2. 选中单元格 → 开始 → 居中对齐", UIMessageBoxIcon.Info);
|
||
}
|
||
|
||
private string EscapeCsv(string value)
|
||
{
|
||
if (string.IsNullOrEmpty(value))
|
||
return "";
|
||
|
||
if (value.Contains(",") || value.Contains("\"") || value.Contains("\n") || value.Contains("\r"))
|
||
{
|
||
value = value.Replace("\"", "\"\"");
|
||
return $"\"{value}\"";
|
||
}
|
||
|
||
return value;
|
||
}
|
||
|
||
private void ShowMessage(string title, string message, UIMessageBoxIcon icon)
|
||
{
|
||
switch (icon)
|
||
{
|
||
case UIMessageBoxIcon.Success:
|
||
UIMessageTip.ShowOk(message);
|
||
break;
|
||
case UIMessageBoxIcon.Error:
|
||
UIMessageTip.ShowError(message);
|
||
break;
|
||
case UIMessageBoxIcon.Info:
|
||
UIMessageTip.ShowWarning(message); // 此处可根据实际控件调整为Info样式
|
||
break;
|
||
default:
|
||
UIMessageBox.Show(message, title);
|
||
break;
|
||
}
|
||
}
|
||
|
||
private void TianpaReport_Load(object sender, EventArgs e)
|
||
{
|
||
string plcIp = "192.168.1.10";
|
||
bool initSuccess = Data.ModbusResourceManager.Instance.Init(plcIp, 502);
|
||
if (!initSuccess)
|
||
{
|
||
MessageBox.Show("连接Modbus服务器失败!", "错误");
|
||
this.Close();
|
||
return;
|
||
}
|
||
|
||
// 检查连接状态
|
||
if (_tcpClient == null || !_tcpClient.Connected)
|
||
{
|
||
MessageBox.Show("Modbus连接异常!", "错误");
|
||
this.Close();
|
||
return;
|
||
}
|
||
ma = new Function(_modbusMaster);
|
||
|
||
|
||
uiDataGridView1.DataSource = reports;
|
||
uiDataGridView1.AllowUserToAddRows = false;
|
||
AdjustDataGridViewStyle();
|
||
}
|
||
|
||
private void TianpaReport_FormClosing(object sender, FormClosingEventArgs e)
|
||
{
|
||
Timer?.Stop();
|
||
Timer?.Dispose();
|
||
|
||
// 仅用户主动关闭时退出应用
|
||
if (e.CloseReason == CloseReason.UserClosing)
|
||
{
|
||
ModbusResourceManager.Instance?.Dispose();
|
||
Application.Exit();
|
||
}
|
||
}
|
||
|
||
//打印
|
||
private void uiButton1_Click(object sender, EventArgs e)
|
||
{
|
||
ma?.BtnClickFunctionForNew(Function.ButtonType.切换型, 15);
|
||
}
|
||
|
||
//导出
|
||
private void uiButton2_Click(object sender, EventArgs e)
|
||
{
|
||
try
|
||
{
|
||
using (SaveFileDialog saveDialog = new SaveFileDialog())
|
||
{
|
||
saveDialog.Filter = "Excel文件|*.xlsx|CSV文件|*.csv|PDF文件|*.pdf";
|
||
saveDialog.Title = "导出报表";
|
||
saveDialog.FileName = $"天帕记录报告_{DateTime.Now:yyyyMMdd_HHmmss}";
|
||
|
||
if (saveDialog.ShowDialog() == DialogResult.OK)
|
||
{
|
||
string filePath = saveDialog.FileName;
|
||
ExportToExcel(filePath);
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
ShowMessage("导出错误", $"导出失败:{ex.Message}", UIMessageBoxIcon.Error);
|
||
}
|
||
}
|
||
|
||
//返回
|
||
private void uiButton3_Click(object sender, EventArgs e)
|
||
{
|
||
SwitchWindow(ref _testScreen, () => new TestScreen());
|
||
}
|
||
}
|
||
}
|