首次提交
This commit is contained in:
317
SCADA/Core/AppConfig.cs
Normal file
317
SCADA/Core/AppConfig.cs
Normal file
@@ -0,0 +1,317 @@
|
||||
|
||||
using HslCommunication.WebSocket;
|
||||
using Newtonsoft.Json;
|
||||
using NPOI.POIFS.Properties;
|
||||
using NPOI.SS.Formula.Functions;
|
||||
using OpcBasic;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Reflection.Emit;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using WebApi;
|
||||
using static System.Configuration.ConfigurationManager;
|
||||
|
||||
namespace MesWork
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public partial class Temp {
|
||||
public static MesWorkForm mesWorkForm = null;
|
||||
}
|
||||
/// <summary>
|
||||
/// 配置信息
|
||||
/// </summary>
|
||||
public partial class MesWorkForm
|
||||
{
|
||||
|
||||
public static int workerThreads = 4000;
|
||||
public static int completionPortThreads = 2000;
|
||||
|
||||
|
||||
public static string BasicDataTableFile = AppSettings["BasicDataTableFile"];
|
||||
public static int IsDemoMesServer = Convert.ToInt32(AppSettings["IsDemoMesServer"]);
|
||||
public static int IsAllowWrite = Convert.ToInt32(AppSettings["IsAllowWrite"]);
|
||||
public static int IsWriteMonitorLog = Convert.ToInt32(AppSettings["IsWriteMonitorLog"]);
|
||||
public static int IsWriteLog4 = Convert.ToInt32(AppSettings["IsWriteLog4"]);
|
||||
public static string ConnectionString = AppSettings["ConnectionString"];
|
||||
|
||||
public static string AuthorizationSet = AppSettings["AuthorizationSet"];
|
||||
|
||||
public static int WebApi_Port = Convert.ToInt32(AppSettings["WebApi_Port"]);
|
||||
|
||||
public static string WebApi_ReqUrl = AppSettings["WebApi_ReqUrl"];
|
||||
|
||||
/// <summary>
|
||||
/// 当前工位号
|
||||
/// </summary>
|
||||
public static string Curr_Station = AppSettings["Curr_Station"] ?? "";
|
||||
|
||||
/// <summary>
|
||||
/// 称重类型:Ground=地面称重, Hanging=空中称重/吊称
|
||||
/// </summary>
|
||||
public static string WeighingType = AppSettings["WeighingType"] ?? "Hanging";
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用扫码枪:1=启用, 0=禁用
|
||||
/// </summary>
|
||||
public static int IsUseBarcode = int.TryParse(AppSettings["IsUseBarcode"], out var _iub) ? _iub : 0;
|
||||
/// <summary>
|
||||
/// OP10扫码枪COM口(如COM3),空则不启用
|
||||
/// </summary>
|
||||
public static string OP10BarCOM = AppSettings["OP10BarCOM"] ?? "";
|
||||
/// <summary>
|
||||
/// OP20扫码枪COM口(如COM4),空则不启用
|
||||
/// </summary>
|
||||
public static string OP20BarCOM = AppSettings["OP20BarCOM"] ?? "";
|
||||
/// <summary>
|
||||
/// 扫码枪波特率
|
||||
/// </summary>
|
||||
public static int BarcodeBaudRate = int.TryParse(AppSettings["BarcodeBaudRate"], out var _bbr) ? _bbr : 9600;
|
||||
|
||||
/// <summary>
|
||||
/// 设备工位名称列表(如 OP10, OP20),在OnStart中从设备表加载
|
||||
/// </summary>
|
||||
public static System.Collections.Generic.List<string> StationOpNames = new System.Collections.Generic.List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// 工位显示名称映射(opName → "OP10 — 称重位1"),在OnStart中从设备表加载
|
||||
/// </summary>
|
||||
public static System.Collections.Generic.Dictionary<string, string> StationDisplayNames
|
||||
= new System.Collections.Generic.Dictionary<string, string>(System.StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// 称重作业页面实例引用,供MIS_Funtion推送交互消息
|
||||
/// </summary>
|
||||
public static Pages.UC_Weighing WeighingPage;
|
||||
|
||||
public static Color color_Faw = Color.FromArgb(0, 44, 101);//蓝色,大众:0,44,101
|
||||
public static Color color_Good = Color.FromArgb(132, 185, 235);//浅蓝,自定义
|
||||
public static Color color_Wait = Color.FromArgb(240, 230, 140);//淡黄,显示等待状态
|
||||
public static Color color_Bad = SystemColors.ActiveBorder;//灰色,显示操作过程
|
||||
public static Color color_Grey = Color.FromArgb(192, 192, 192);//灰色,Table底色
|
||||
|
||||
public static Color color_Green = Color.FromArgb(22, 161, 136);//绿色
|
||||
public static Color color_Yellow = Color.FromArgb(246, 227, 74);//黄色
|
||||
public static Color color_Red = Color.FromArgb(255, 0, 0);//红色
|
||||
|
||||
public static Color color_Blue_FJ = Color.FromArgb(19, 34, 122);//深蓝
|
||||
public static Color color_White_FJ = Color.White;//白色
|
||||
public static Color color_Control = SystemColors.Control;//控件默认颜色
|
||||
|
||||
|
||||
|
||||
public static bool OnLine_Sql = false;
|
||||
|
||||
public static string Curr_UserName = "";
|
||||
public static string Curr_LoginID = "";
|
||||
public static string Curr_UserPassWord = "";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// WebApi
|
||||
/// </summary>
|
||||
public static InitServer initServer = null;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 监控数据的所有变化,从这里产生
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
public override void OPCTagData_TagDataOnChangeMIS(object sender, DeviceDriver_BasicData.CustomeEvetnArgs e)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(new WaitCallback(MIS_Funtion), e);
|
||||
}
|
||||
/// <summary>
|
||||
/// 定时触发,检测PLC在线状态,周期:3 s
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="eState"></param>
|
||||
public override void PlcStateEvent(object sender, DeviceDriver_BasicData.PlcStateEvetnArgs eState)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(new WaitCallback(MIS_Device), eState);
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <param name="location"></param>
|
||||
/// <param name="content"></param>
|
||||
public override void E_WriteLog(Enum_LogType t, string location, string content)
|
||||
{
|
||||
if (content .Contains("GetTagIDByTagTypeCodeID(),"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
WriteLog_Info(t.ToString(), $"<[<{location}>]>{content}");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
new System.Threading.Mutex(true, $"MES_PWT_A95", out bool bCanRun);
|
||||
if (!bCanRun)
|
||||
{
|
||||
MessageBox.Show("MES采集系统 已经在运行!不可重复启动!");
|
||||
return;
|
||||
}
|
||||
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.Run(Temp.mesWorkForm = new MesWorkForm());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
private string Hello_You_All_Never_Know(string[] args)
|
||||
{
|
||||
return Guid.NewGuid().ToString() + Guid.NewGuid().ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入信号
|
||||
/// </summary>
|
||||
/// <param name="tagTypeCodeID"></param>
|
||||
/// <param name="ststionName"></param>
|
||||
/// <param name="value"></param>
|
||||
public static void WritePLC_IF(int tagTypeCodeID,string ststionName,object value)
|
||||
{
|
||||
if (IsAllowWrite == 1)
|
||||
{
|
||||
WritePLC(tagTypeCodeID, ststionName, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 写日志
|
||||
/// 2023.10.30.llx
|
||||
/// </summary>
|
||||
public static void WriteLog_Info(string type, string msg, Exception ex = null)
|
||||
{
|
||||
if (IsWriteLog4 == 1)
|
||||
{
|
||||
MW_Log.LoggerHelper.Info(type, msg, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void CommunicationCheckOnLine()
|
||||
{
|
||||
|
||||
new Thread(new ThreadStart(delegate ()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
MesWorkForm.OnLine_Sql = DataLinkMesWork.SQLCommon.ExecuteDataTable("select getdate()", ConnectionString, out DataTable dt, out string err);
|
||||
}
|
||||
catch (Exception) { }
|
||||
Thread.Sleep(5000);
|
||||
}
|
||||
}))
|
||||
{ IsBackground = true }.Start();
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void Loop_SelectAlarmShow()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
B_DB_Opera.Query_AlarmData(Curr_Station, out int count, out string text);
|
||||
if (count > 0)
|
||||
{
|
||||
label_Alarm.Text = $"({count}) {text}";
|
||||
panel_Alarm.BackColor = Color.Red;
|
||||
}
|
||||
else
|
||||
{
|
||||
label_Alarm.Text = $"";
|
||||
panel_Alarm.BackColor = Color.FromArgb(30, 58, 95);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
}
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
// Loop_ReadRealPageShow 已移除(旧UI控件引用),PLC信号显示将在 UC_Weighing 中实现
|
||||
|
||||
public void ShowSignal(Control c,string opName)
|
||||
{
|
||||
if (!c.Name.Contains("_Show_"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
var tagTypeCodeID = Convert.ToInt32(c.Name.Split('_')[3]);
|
||||
if (c is TextBox)
|
||||
{
|
||||
try
|
||||
{
|
||||
c.Text = PlcLinkForm.ReadPLC(tagTypeCodeID, opName).ToString();
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
c.Text = "不存在该信号!";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void ShowSignal(Control c, int tagTypeCodeID, string opName)
|
||||
{
|
||||
if (c is Panel)
|
||||
{
|
||||
try
|
||||
{
|
||||
c.BackColor = PlcLinkForm.ReadPLC(tagTypeCodeID, opName).ToString().ToLower().Replace("true", "1").Replace("false", "0") == "1" ? Color.Lime : color_Grey;
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
c.BackColor = color_Grey;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ConcurrentDictionary<string, TagFormat> ReadPLC_OpName(string opName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var res = new ConcurrentDictionary<string, TagFormat>();
|
||||
var tagAdrListTagFormat0 = PlcLinkForm.ReadPLC_GroupData_SingleTag(opName);
|
||||
foreach (var item in tagAdrListTagFormat0)
|
||||
{
|
||||
var key = item.Key;
|
||||
var value = (TagFormat)item.Value;
|
||||
res.TryAdd(key, value);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
107
SCADA/Core/BarcodeManager.cs
Normal file
107
SCADA/Core/BarcodeManager.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MesWork
|
||||
{
|
||||
/// <summary>
|
||||
/// 扫码枪管理器 — 管理最多2把扫码枪的生命周期和事件分发
|
||||
/// </summary>
|
||||
public static class BarcodeManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 扫码枪实例字典,key = opName(OP10/OP20)
|
||||
/// </summary>
|
||||
public static Dictionary<string, BarcodeScanner> Scanners { get; } = new Dictionary<string, BarcodeScanner>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用扫码枪功能
|
||||
/// </summary>
|
||||
public static bool IsEnabled => MesWorkForm.IsUseBarcode == 1;
|
||||
|
||||
/// <summary>
|
||||
/// 扫码事件回调(由外部设置,通常指向 MIS_Funtion 的处理方法)
|
||||
/// </summary>
|
||||
public static Action<string, string> OnBarcodeScanned;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化扫码枪(读取配置并创建实例)
|
||||
/// </summary>
|
||||
public static void Init()
|
||||
{
|
||||
if (!IsEnabled) return;
|
||||
|
||||
int baudRate = MesWorkForm.BarcodeBaudRate;
|
||||
|
||||
// OP10
|
||||
string op10Com = MesWorkForm.OP10BarCOM?.Trim();
|
||||
if (!string.IsNullOrEmpty(op10Com))
|
||||
{
|
||||
var scanner = new BarcodeScanner("OP10", baudRate);
|
||||
scanner.BarcodeReceived += HandleBarcodeReceived;
|
||||
scanner.Log += HandleLog;
|
||||
Scanners["OP10"] = scanner;
|
||||
scanner.Connect(op10Com);
|
||||
}
|
||||
|
||||
// OP20
|
||||
string op20Com = MesWorkForm.OP20BarCOM?.Trim();
|
||||
if (!string.IsNullOrEmpty(op20Com))
|
||||
{
|
||||
var scanner = new BarcodeScanner("OP20", baudRate);
|
||||
scanner.BarcodeReceived += HandleBarcodeReceived;
|
||||
scanner.Log += HandleLog;
|
||||
Scanners["OP20"] = scanner;
|
||||
scanner.Connect(op20Com);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 统一扫码事件处理
|
||||
/// </summary>
|
||||
private static void HandleBarcodeReceived(string opName, string barcode)
|
||||
{
|
||||
OnBarcodeScanned?.Invoke(opName, barcode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 扫码枪日志 → 系统日志 + 称重页面
|
||||
/// </summary>
|
||||
private static void HandleLog(string message)
|
||||
{
|
||||
MesWorkForm.WriteLog_Info("BarcodeScanner", message);
|
||||
MesWorkForm.WeighingPage?.AppendLog(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 手动发送条码(模拟扫码触发)
|
||||
/// </summary>
|
||||
public static void ManualSend(string opName, string barcode)
|
||||
{
|
||||
// 直接走事件回调,和自动扫码一样的路径
|
||||
if (!string.IsNullOrWhiteSpace(barcode))
|
||||
HandleBarcodeReceived(opName, barcode.Trim());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放所有扫码枪
|
||||
/// </summary>
|
||||
public static void Shutdown()
|
||||
{
|
||||
foreach (var scanner in Scanners.Values)
|
||||
{
|
||||
try { scanner.Dispose(); } catch { }
|
||||
}
|
||||
Scanners.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有可用COM口
|
||||
/// </summary>
|
||||
public static string[] GetAvailablePorts()
|
||||
{
|
||||
try { return System.IO.Ports.SerialPort.GetPortNames(); }
|
||||
catch { return new string[0]; }
|
||||
}
|
||||
}
|
||||
}
|
||||
323
SCADA/Core/BarcodeScanner.cs
Normal file
323
SCADA/Core/BarcodeScanner.cs
Normal file
@@ -0,0 +1,323 @@
|
||||
using System;
|
||||
using System.IO.Ports;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MesWork
|
||||
{
|
||||
/// <summary>
|
||||
/// 单把扫码枪的串口通信封装
|
||||
/// 包含数据接收(缓冲+空闲提交)、防抖、断线自动重连
|
||||
/// </summary>
|
||||
public class BarcodeScanner : IDisposable
|
||||
{
|
||||
// ── 基本属性 ──
|
||||
/// <summary>关联工位号(OP10/OP20)</summary>
|
||||
public string OpName { get; }
|
||||
|
||||
/// <summary>当前COM口</summary>
|
||||
public string ComPort { get; private set; }
|
||||
|
||||
/// <summary>是否已连接</summary>
|
||||
public bool IsConnected
|
||||
{
|
||||
get { try { return _serial != null && _serial.IsOpen; } catch { return false; } }
|
||||
}
|
||||
|
||||
/// <summary>最近一次扫到的条码</summary>
|
||||
public string LastBarcode { get; private set; } = "";
|
||||
|
||||
/// <summary>最近一次扫码时间</summary>
|
||||
public DateTime? LastScanTime { get; private set; }
|
||||
|
||||
// ── 事件 ──
|
||||
/// <summary>扫码完成事件(opName, barcode)</summary>
|
||||
public event Action<string, string> BarcodeReceived;
|
||||
|
||||
/// <summary>日志事件(message),由外部接入系统日志</summary>
|
||||
public event Action<string> Log;
|
||||
|
||||
// ── 私有字段 ──
|
||||
private SerialPort _serial;
|
||||
private readonly int _baudRate;
|
||||
private readonly object _bufferLock = new object();
|
||||
private readonly StringBuilder _buffer = new StringBuilder(256);
|
||||
private System.Windows.Forms.Timer _flushTimer;
|
||||
private const int FlushIntervalMs = 60;
|
||||
|
||||
// 防抖
|
||||
private string _lastDebounceCode = "";
|
||||
private DateTime _lastDebounceTime = DateTime.MinValue;
|
||||
private const int DebounceMs = 500;
|
||||
|
||||
// 断线重连
|
||||
private System.Windows.Forms.Timer _reconnectTimer;
|
||||
private volatile bool _reconnecting = false;
|
||||
private bool _disposed = false;
|
||||
|
||||
public BarcodeScanner(string opName, int baudRate = 9600)
|
||||
{
|
||||
OpName = opName;
|
||||
_baudRate = baudRate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 连接指定COM口
|
||||
/// </summary>
|
||||
public bool Connect(string comPort)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(comPort) || comPort.Length < 3)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
Disconnect();
|
||||
ComPort = comPort;
|
||||
|
||||
_serial = new SerialPort
|
||||
{
|
||||
PortName = comPort,
|
||||
BaudRate = _baudRate,
|
||||
Parity = Parity.None,
|
||||
StopBits = StopBits.One,
|
||||
ReadTimeout = 1000,
|
||||
DtrEnable = true
|
||||
};
|
||||
_serial.DataReceived += Serial_DataReceived;
|
||||
_serial.Open();
|
||||
|
||||
// 空闲提交定时器
|
||||
if (_flushTimer == null)
|
||||
{
|
||||
_flushTimer = new System.Windows.Forms.Timer { Interval = FlushIntervalMs };
|
||||
_flushTimer.Tick += FlushTimer_Tick;
|
||||
}
|
||||
|
||||
// 断线重连定时器(每3秒检测)
|
||||
if (_reconnectTimer == null)
|
||||
{
|
||||
_reconnectTimer = new System.Windows.Forms.Timer { Interval = 3000 };
|
||||
_reconnectTimer.Tick += ReconnectTimer_Tick;
|
||||
}
|
||||
_reconnectTimer.Start();
|
||||
|
||||
Log?.Invoke($"[{OpName}] 扫码枪已连接 ({comPort})");
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log?.Invoke($"[{OpName}] 扫码枪连接失败 ({comPort}):{ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 断开连接
|
||||
/// </summary>
|
||||
public void Disconnect()
|
||||
{
|
||||
try
|
||||
{
|
||||
_reconnectTimer?.Stop();
|
||||
_flushTimer?.Stop();
|
||||
|
||||
if (_serial != null)
|
||||
{
|
||||
_serial.DataReceived -= Serial_DataReceived;
|
||||
if (_serial.IsOpen) _serial.Close();
|
||||
_serial.Dispose();
|
||||
_serial = null;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试当前COM口是否可连接
|
||||
/// </summary>
|
||||
public bool TestConnection(string comPort)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var sp = new SerialPort(comPort, _baudRate))
|
||||
{
|
||||
sp.Open();
|
||||
sp.Close();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch { return false; }
|
||||
}
|
||||
|
||||
// ── 串口数据接收 ──
|
||||
private void Serial_DataReceived(object sender, SerialDataReceivedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_serial == null || !_serial.IsOpen) return;
|
||||
|
||||
int bytesToRead = _serial.BytesToRead;
|
||||
if (bytesToRead <= 0) return;
|
||||
|
||||
byte[] buf = new byte[bytesToRead];
|
||||
_serial.Read(buf, 0, bytesToRead);
|
||||
string chunk = Encoding.UTF8.GetString(buf, 0, bytesToRead);
|
||||
|
||||
lock (_bufferLock)
|
||||
{
|
||||
_buffer.Append(chunk);
|
||||
string acc = _buffer.ToString();
|
||||
|
||||
// 按换行符(\r \n)拆分完整条码
|
||||
int startIndex = 0;
|
||||
for (int i = 0; i < acc.Length; i++)
|
||||
{
|
||||
if (acc[i] == '\r' || acc[i] == '\n')
|
||||
{
|
||||
int len = i - startIndex;
|
||||
if (len > 0)
|
||||
{
|
||||
string line = acc.Substring(startIndex, len).Trim();
|
||||
if (!string.IsNullOrEmpty(line))
|
||||
SubmitBarcode(line);
|
||||
}
|
||||
startIndex = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (startIndex >= acc.Length)
|
||||
_buffer.Clear();
|
||||
else if (startIndex > 0)
|
||||
{
|
||||
_buffer.Clear();
|
||||
_buffer.Append(acc.Substring(startIndex));
|
||||
}
|
||||
|
||||
// 无换行 → 启动空闲定时器
|
||||
if (_buffer.Length > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
_flushTimer?.Stop();
|
||||
_flushTimer?.Start();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is System.IO.IOException || ex is InvalidOperationException)
|
||||
{
|
||||
Log?.Invoke($"[{OpName}] 扫码枪通信异常,尝试重连:{ex.Message}");
|
||||
TryReopen();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
try { _serial?.DiscardInBuffer(); } catch { }
|
||||
}
|
||||
}
|
||||
|
||||
// 空闲超时提交缓冲区
|
||||
private void FlushTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
_flushTimer.Stop();
|
||||
string toSend;
|
||||
lock (_bufferLock)
|
||||
{
|
||||
toSend = _buffer.ToString().Trim();
|
||||
_buffer.Clear();
|
||||
}
|
||||
if (!string.IsNullOrEmpty(toSend))
|
||||
SubmitBarcode(toSend);
|
||||
}
|
||||
|
||||
// 提交条码(含防抖)
|
||||
private void SubmitBarcode(string barcode)
|
||||
{
|
||||
barcode = barcode.Replace("\r", "").Replace("\n", "").Replace("\0", "").Trim();
|
||||
if (string.IsNullOrEmpty(barcode)) return;
|
||||
|
||||
// 防抖
|
||||
var now = DateTime.Now;
|
||||
if (barcode == _lastDebounceCode && (now - _lastDebounceTime).TotalMilliseconds < DebounceMs)
|
||||
return;
|
||||
_lastDebounceCode = barcode;
|
||||
_lastDebounceTime = now;
|
||||
|
||||
// 更新状态
|
||||
LastBarcode = barcode;
|
||||
LastScanTime = now;
|
||||
|
||||
// 触发事件
|
||||
BarcodeReceived?.Invoke(OpName, barcode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 手动发送条码(模拟扫码触发,走完整业务流程)
|
||||
/// </summary>
|
||||
public void ManualSend(string barcode)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(barcode))
|
||||
SubmitBarcode(barcode.Trim());
|
||||
}
|
||||
|
||||
// ── 断线重连 ──
|
||||
private void ReconnectTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
if (_reconnecting || string.IsNullOrWhiteSpace(ComPort)) return;
|
||||
if (IsConnected) return;
|
||||
|
||||
_reconnecting = true;
|
||||
Task.Run(() =>
|
||||
{
|
||||
try { TryReopen(); }
|
||||
catch { }
|
||||
finally { _reconnecting = false; }
|
||||
});
|
||||
}
|
||||
|
||||
private void TryReopen()
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] ports = SerialPort.GetPortNames();
|
||||
bool exists = Array.Exists(ports, p => string.Equals(p, ComPort, StringComparison.OrdinalIgnoreCase));
|
||||
if (!exists) return;
|
||||
|
||||
if (_serial != null)
|
||||
{
|
||||
try { if (_serial.IsOpen) _serial.Close(); } catch { }
|
||||
try { _serial.Dispose(); } catch { }
|
||||
}
|
||||
|
||||
_serial = new SerialPort
|
||||
{
|
||||
PortName = ComPort,
|
||||
BaudRate = _baudRate,
|
||||
Parity = Parity.None,
|
||||
StopBits = StopBits.One,
|
||||
ReadTimeout = 1000,
|
||||
DtrEnable = true
|
||||
};
|
||||
_serial.DataReceived += Serial_DataReceived;
|
||||
_serial.Open();
|
||||
Log?.Invoke($"[{OpName}] 扫码枪自动重连成功 ({ComPort})");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log?.Invoke($"[{OpName}] 扫码枪自动重连失败 ({ComPort}):{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
Disconnect();
|
||||
_flushTimer?.Dispose();
|
||||
_reconnectTimer?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
40
SCADA/Core/IconHelper.cs
Normal file
40
SCADA/Core/IconHelper.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace MesWork
|
||||
{
|
||||
/// <summary>
|
||||
/// 窗口图标加载工具类(多路径搜索 + exe回退)
|
||||
/// </summary>
|
||||
public static class IconHelper
|
||||
{
|
||||
private static readonly string[] IconSearchPaths = new[]
|
||||
{
|
||||
System.IO.Path.Combine(Application.StartupPath, "任务管理.ico"),
|
||||
System.IO.Path.Combine(System.IO.Path.GetDirectoryName(
|
||||
System.Reflection.Assembly.GetExecutingAssembly().Location) ?? "", "任务管理.ico"),
|
||||
"任务管理.ico"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 为指定窗体加载图标
|
||||
/// </summary>
|
||||
public static void ApplyIcon(Form form)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var path in IconSearchPaths)
|
||||
{
|
||||
if (System.IO.File.Exists(path))
|
||||
{
|
||||
form.Icon = new Icon(path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
form.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
626
SCADA/Core/OExcel.cs
Normal file
626
SCADA/Core/OExcel.cs
Normal file
@@ -0,0 +1,626 @@
|
||||
using NPOI.HPSF;
|
||||
using NPOI.HSSF.UserModel;
|
||||
using NPOI.SS.UserModel;
|
||||
using NPOI.XSSF.UserModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NPOITest
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Execl工具辅助类
|
||||
/// </summary>
|
||||
public class ExeclHelper
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 读取Execl数据到DataTable中
|
||||
/// </summary>
|
||||
/// <param name="filePath">指定Execl文件路径</param>
|
||||
/// <param name="isColumnName">设置第一行是否是列名</param>
|
||||
/// <returns>返回一个DataTable数据集</returns>
|
||||
public static DataTable ExcelToDataTable(string filePath, string sheetName, bool isColumnName)
|
||||
{
|
||||
DataTable dataTable = null;
|
||||
FileStream fs = null;
|
||||
DataColumn column = null;
|
||||
DataRow dataRow = null;
|
||||
IWorkbook workbook = null;
|
||||
ISheet sheet = null;
|
||||
IRow row = null;
|
||||
ICell cell = null;
|
||||
int startRow = 0;
|
||||
try
|
||||
{
|
||||
using (fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
// 2007版本
|
||||
if (filePath.IndexOf(".xlsx") > 0)
|
||||
workbook = new XSSFWorkbook(fs);
|
||||
// 2003版本
|
||||
else if (filePath.IndexOf(".xls") > 0)
|
||||
workbook = new HSSFWorkbook(fs);
|
||||
if (workbook != null)
|
||||
{
|
||||
sheet = workbook.GetSheet(sheetName);//读取第一个sheet,当然也可以循环读取每个sheet
|
||||
dataTable = new DataTable();
|
||||
if (sheet != null)
|
||||
{
|
||||
int rowCount = sheet.LastRowNum;//总行数
|
||||
if (rowCount > 0)
|
||||
{
|
||||
IRow firstRow = sheet.GetRow(0);//第一行
|
||||
int cellCount = firstRow.LastCellNum;//列数
|
||||
|
||||
//构建datatable的列
|
||||
if (isColumnName)
|
||||
{
|
||||
startRow = 1;//如果第一行是列名,则从第二行开始读取
|
||||
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
|
||||
{
|
||||
cell = firstRow.GetCell(i);
|
||||
if (cell != null)
|
||||
{
|
||||
if (cell.StringCellValue != null)
|
||||
{
|
||||
column = new DataColumn(cell.StringCellValue);
|
||||
dataTable.Columns.Add(column);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
|
||||
{
|
||||
column = new DataColumn("column" + (i + 1));
|
||||
dataTable.Columns.Add(column);
|
||||
}
|
||||
}
|
||||
|
||||
//填充行
|
||||
for (int i = startRow; i <= rowCount; ++i)
|
||||
{
|
||||
row = sheet.GetRow(i);
|
||||
if (row == null) continue;
|
||||
|
||||
dataRow = dataTable.NewRow();
|
||||
for (int j = row.FirstCellNum; j < cellCount; ++j)
|
||||
{
|
||||
cell = row.GetCell(j);
|
||||
if (cell == null)
|
||||
{
|
||||
dataRow[j] = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
//CellType(Unknown = -1,Numeric = 0,String = 1,Formula = 2,Blank = 3,Boolean = 4,Error = 5,)
|
||||
switch (cell.CellType)
|
||||
{
|
||||
case CellType.Blank:
|
||||
dataRow[j] = "";
|
||||
break;
|
||||
case CellType.Numeric:
|
||||
short format = cell.CellStyle.DataFormat;
|
||||
//对时间格式(2015.12.5、2015/12/5、2015-12-5等)的处理
|
||||
if (format == 14 || format == 31 || format == 57 || format == 58)
|
||||
dataRow[j] = cell.DateCellValue;
|
||||
else
|
||||
dataRow[j] = cell.NumericCellValue;
|
||||
break;
|
||||
case CellType.String:
|
||||
dataRow[j] = cell.StringCellValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
dataTable.Rows.Add(dataRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return dataTable;
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
if (fs != null)
|
||||
{
|
||||
fs.Close();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static DataTable ExcelToDataTable(string filePath,int sheetIndex, bool isColumnName)
|
||||
{
|
||||
DataTable dataTable = null;
|
||||
FileStream fs = null;
|
||||
DataColumn column = null;
|
||||
DataRow dataRow = null;
|
||||
IWorkbook workbook = null;
|
||||
ISheet sheet = null;
|
||||
IRow row = null;
|
||||
ICell cell = null;
|
||||
int startRow = 0;
|
||||
try
|
||||
{
|
||||
using (fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
// 2007版本
|
||||
if (filePath.IndexOf(".xlsx") > 0)
|
||||
workbook = new XSSFWorkbook(fs);
|
||||
// 2003版本
|
||||
else if (filePath.IndexOf(".xls") > 0)
|
||||
workbook = new HSSFWorkbook(fs);
|
||||
if (workbook != null)
|
||||
{
|
||||
sheet = workbook.GetSheetAt(sheetIndex);//读取第一个sheet,当然也可以循环读取每个sheet
|
||||
dataTable = new DataTable();
|
||||
if (sheet != null)
|
||||
{
|
||||
int rowCount = sheet.LastRowNum;//总行数
|
||||
if (rowCount > 0)
|
||||
{
|
||||
IRow firstRow = sheet.GetRow(0);//第一行
|
||||
int cellCount = firstRow.LastCellNum;//列数
|
||||
|
||||
//构建datatable的列
|
||||
if (isColumnName)
|
||||
{
|
||||
startRow = 1;//如果第一行是列名,则从第二行开始读取
|
||||
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
|
||||
{
|
||||
cell = firstRow.GetCell(i);
|
||||
if (cell != null)
|
||||
{
|
||||
if (cell.StringCellValue != null)
|
||||
{
|
||||
column = new DataColumn(cell.StringCellValue);
|
||||
dataTable.Columns.Add(column);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
|
||||
{
|
||||
column = new DataColumn("column" + (i + 1));
|
||||
dataTable.Columns.Add(column);
|
||||
}
|
||||
}
|
||||
|
||||
//填充行
|
||||
for (int i = startRow; i <= rowCount; ++i)
|
||||
{
|
||||
row = sheet.GetRow(i);
|
||||
if (row == null) continue;
|
||||
|
||||
dataRow = dataTable.NewRow();
|
||||
for (int j = row.FirstCellNum; j < cellCount; ++j)
|
||||
{
|
||||
cell = row.GetCell(j);
|
||||
if (cell == null)
|
||||
{
|
||||
dataRow[j] = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
//CellType(Unknown = -1,Numeric = 0,String = 1,Formula = 2,Blank = 3,Boolean = 4,Error = 5,)
|
||||
switch (cell.CellType)
|
||||
{
|
||||
case CellType.Blank:
|
||||
dataRow[j] = "";
|
||||
break;
|
||||
case CellType.Numeric:
|
||||
short format = cell.CellStyle.DataFormat;
|
||||
//对时间格式(2015.12.5、2015/12/5、2015-12-5等)的处理
|
||||
if (format == 14 || format == 31 || format == 57 || format == 58 || format == 22)
|
||||
dataRow[j] = cell.DateCellValue;
|
||||
else
|
||||
dataRow[j] = cell.NumericCellValue;
|
||||
break;
|
||||
case CellType.String:
|
||||
dataRow[j] = cell.StringCellValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
dataTable.Rows.Add(dataRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return dataTable;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
if (fs != null)
|
||||
{
|
||||
fs.Close();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static void DataTableToExcel(DataTable dataTable, string templatePath, string outputPath, int startRow, int startCol)
|
||||
{
|
||||
// 加载模板文件
|
||||
using (FileStream fs = new FileStream(templatePath, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
IWorkbook workbook = new XSSFWorkbook(fs);
|
||||
ISheet sheet = workbook.GetSheetAt(0); // 获取第一个工作表
|
||||
// 创建单元格样式
|
||||
ICellStyle cellStyle = workbook.CreateCellStyle();
|
||||
IFont font = workbook.CreateFont();
|
||||
font.FontHeightInPoints = 12;
|
||||
cellStyle.SetFont(font);
|
||||
cellStyle.BorderTop = BorderStyle.Thin;
|
||||
cellStyle.BorderBottom = BorderStyle.Thin;
|
||||
cellStyle.BorderLeft = BorderStyle.Thin;
|
||||
cellStyle.BorderRight = BorderStyle.Thin;
|
||||
cellStyle.Alignment = HorizontalAlignment.Center;
|
||||
// 遍历DataTable的每一行
|
||||
for (int i = 0; i < dataTable.Rows.Count; i++)
|
||||
{
|
||||
IRow row = sheet.CreateRow(startRow + i); // 创建新行
|
||||
|
||||
// 遍历DataTable的每一列
|
||||
for (int j = 0; j < dataTable.Columns.Count; j++)
|
||||
{
|
||||
ICell cell = row.CreateCell(startCol + j); // 创建新单元格
|
||||
cell.SetCellValue(dataTable.Rows[i][j].ToString());
|
||||
cell.CellStyle = cellStyle; // 应用单元格样式
|
||||
}
|
||||
}
|
||||
|
||||
// 保存输出文件
|
||||
using (FileStream outputStream = new FileStream(outputPath, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
workbook.Write(outputStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 将DataTable导出到Excel文档(自动根据扩展名选择 .xlsx / .xls 格式)
|
||||
/// </summary>
|
||||
/// <param name="dt">传入一个DataTable数据集</param>
|
||||
/// <param name="sheetName">工作表名称</param>
|
||||
/// <param name="Outpath">导出文件完整路径(支持 .xlsx 和 .xls)</param>
|
||||
/// <returns>True表示导出成功,False表示导出失败</returns>
|
||||
public static bool DataTableToExcel(DataTable dt, string sheetName, string Outpath)
|
||||
{
|
||||
if (dt == null || dt.Rows.Count == 0 || string.IsNullOrWhiteSpace(Outpath))
|
||||
return false;
|
||||
|
||||
IWorkbook workbook = null;
|
||||
try
|
||||
{
|
||||
// ── 1. 根据文件扩展名选择正确的 Workbook 类型 ──
|
||||
string ext = Path.GetExtension(Outpath).ToLowerInvariant();
|
||||
if (ext == ".xlsx")
|
||||
workbook = new XSSFWorkbook(); // OOXML 格式
|
||||
else
|
||||
workbook = new HSSFWorkbook(); // BIFF8 格式
|
||||
|
||||
ISheet sheet = workbook.CreateSheet(sheetName);
|
||||
int rowCount = dt.Rows.Count;
|
||||
int columnCount = dt.Columns.Count;
|
||||
|
||||
// ── 2. 创建表头样式(加粗 + 背景色 + 边框) ──
|
||||
ICellStyle headerStyle = workbook.CreateCellStyle();
|
||||
IFont headerFont = workbook.CreateFont();
|
||||
headerFont.IsBold = true;
|
||||
headerFont.FontHeightInPoints = 11;
|
||||
headerFont.FontName = "微软雅黑";
|
||||
headerStyle.SetFont(headerFont);
|
||||
headerStyle.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.Grey25Percent.Index;
|
||||
headerStyle.FillPattern = FillPattern.SolidForeground;
|
||||
headerStyle.Alignment = HorizontalAlignment.Center;
|
||||
headerStyle.VerticalAlignment = VerticalAlignment.Center;
|
||||
headerStyle.BorderTop = BorderStyle.Thin;
|
||||
headerStyle.BorderBottom = BorderStyle.Thin;
|
||||
headerStyle.BorderLeft = BorderStyle.Thin;
|
||||
headerStyle.BorderRight = BorderStyle.Thin;
|
||||
|
||||
// ── 3. 创建数据行样式(边框) ──
|
||||
ICellStyle dataStyle = workbook.CreateCellStyle();
|
||||
IFont dataFont = workbook.CreateFont();
|
||||
dataFont.FontHeightInPoints = 10;
|
||||
dataFont.FontName = "微软雅黑";
|
||||
dataStyle.SetFont(dataFont);
|
||||
dataStyle.VerticalAlignment = VerticalAlignment.Center;
|
||||
dataStyle.BorderTop = BorderStyle.Thin;
|
||||
dataStyle.BorderBottom = BorderStyle.Thin;
|
||||
dataStyle.BorderLeft = BorderStyle.Thin;
|
||||
dataStyle.BorderRight = BorderStyle.Thin;
|
||||
|
||||
// ── 4. 写入列头 ──
|
||||
IRow headerRow = sheet.CreateRow(0);
|
||||
headerRow.HeightInPoints = 22;
|
||||
for (int c = 0; c < columnCount; c++)
|
||||
{
|
||||
ICell cell = headerRow.CreateCell(c);
|
||||
cell.SetCellValue(dt.Columns[c].ColumnName);
|
||||
cell.CellStyle = headerStyle;
|
||||
}
|
||||
|
||||
// ── 5. 写入数据行 ──
|
||||
for (int i = 0; i < rowCount; i++)
|
||||
{
|
||||
IRow row = sheet.CreateRow(i + 1);
|
||||
for (int j = 0; j < columnCount; j++)
|
||||
{
|
||||
ICell cell = row.CreateCell(j);
|
||||
object val = dt.Rows[i][j];
|
||||
// 根据数据类型设置单元格值,保留数值精度
|
||||
if (val == null || val == DBNull.Value)
|
||||
{
|
||||
cell.SetCellValue("");
|
||||
}
|
||||
else if (val is DateTime dtVal)
|
||||
{
|
||||
cell.SetCellValue(dtVal.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||
}
|
||||
else if (val is double || val is float || val is decimal)
|
||||
{
|
||||
cell.SetCellValue(Convert.ToDouble(val));
|
||||
}
|
||||
else if (val is int || val is long || val is short)
|
||||
{
|
||||
cell.SetCellValue(Convert.ToDouble(val));
|
||||
}
|
||||
else
|
||||
{
|
||||
cell.SetCellValue(val.ToString());
|
||||
}
|
||||
cell.CellStyle = dataStyle;
|
||||
}
|
||||
}
|
||||
|
||||
// ── 6. 自动调整列宽(限制最大宽度避免过宽) ──
|
||||
for (int c = 0; c < columnCount; c++)
|
||||
{
|
||||
sheet.AutoSizeColumn(c);
|
||||
int colWidth = sheet.GetColumnWidth(c);
|
||||
// 最大列宽限制为 50 个字符宽度 (50 * 256)
|
||||
if (colWidth > 50 * 256)
|
||||
sheet.SetColumnWidth(c, 50 * 256);
|
||||
// 最小列宽
|
||||
else if (colWidth < 10 * 256)
|
||||
sheet.SetColumnWidth(c, 10 * 256);
|
||||
}
|
||||
|
||||
// ── 7. 写入文件(使用 FileMode.Create 确保覆盖写入) ──
|
||||
using (FileStream fs = new FileStream(Outpath, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
workbook.Write(fs);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"[ExeclHelper] 导出Excel失败: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (workbook != null)
|
||||
{
|
||||
workbook.Close();
|
||||
workbook = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 读取Execl数据到DataTable(DataSet)中
|
||||
/// </summary>
|
||||
/// <param name="filePath">指定Execl文件路径</param>
|
||||
/// <param name="isFirstLineColumnName">设置第一行是否是列名</param>
|
||||
/// <returns>返回一个DataTable数据集</returns>
|
||||
public static DataSet ExcelToDataSet(string filePath, bool isFirstLineColumnName)
|
||||
{
|
||||
DataSet dataSet = new DataSet();
|
||||
int startRow = 0;
|
||||
try
|
||||
{
|
||||
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
IWorkbook workbook = null;
|
||||
// 如果是2007+的Excel版本
|
||||
if (filePath.IndexOf(".xlsx") > 0)
|
||||
{
|
||||
workbook = new XSSFWorkbook(fs);
|
||||
}
|
||||
// 如果是2003-的Excel版本
|
||||
else if (filePath.IndexOf(".xls") > 0)
|
||||
{
|
||||
workbook = new HSSFWorkbook(fs);
|
||||
}
|
||||
if (workbook != null)
|
||||
{
|
||||
//循环读取Excel的每个sheet,每个sheet页都转换为一个DataTable,并放在DataSet中
|
||||
for (int p = 0; p < workbook.NumberOfSheets; p++)
|
||||
{
|
||||
ISheet sheet = workbook.GetSheetAt(p);
|
||||
DataTable dataTable = new DataTable();
|
||||
dataTable.TableName = sheet.SheetName;
|
||||
if (sheet != null)
|
||||
{
|
||||
int rowCount = sheet.LastRowNum;//获取总行数
|
||||
if (rowCount > 0)
|
||||
{
|
||||
IRow firstRow = sheet.GetRow(0);//获取第一行
|
||||
int cellCount = firstRow.LastCellNum;//获取总列数
|
||||
|
||||
//构建datatable的列
|
||||
if (isFirstLineColumnName)
|
||||
{
|
||||
startRow = 1;//如果第一行是列名,则从第二行开始读取
|
||||
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
|
||||
{
|
||||
ICell cell = firstRow.GetCell(i);
|
||||
if (cell != null)
|
||||
{
|
||||
if (cell.StringCellValue != null)
|
||||
{
|
||||
DataColumn column = new DataColumn(cell.StringCellValue);
|
||||
dataTable.Columns.Add(column);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
|
||||
{
|
||||
DataColumn column = new DataColumn("column" + (i + 1));
|
||||
dataTable.Columns.Add(column);
|
||||
}
|
||||
}
|
||||
|
||||
//填充行
|
||||
for (int i = startRow; i <= rowCount; ++i)
|
||||
{
|
||||
IRow row = sheet.GetRow(i);
|
||||
if (row == null) continue;
|
||||
|
||||
DataRow dataRow = dataTable.NewRow();
|
||||
for (int j = row.FirstCellNum; j < cellCount; ++j)
|
||||
{
|
||||
ICell cell = row.GetCell(j);
|
||||
if (cell == null)
|
||||
{
|
||||
dataRow[j] = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
//CellType(Unknown = -1,Numeric = 0,String = 1,Formula = 2,Blank = 3,Boolean = 4,Error = 5,)
|
||||
switch (cell.CellType)
|
||||
{
|
||||
case CellType.Blank:
|
||||
dataRow[j] = "";
|
||||
break;
|
||||
case CellType.Numeric:
|
||||
short format = cell.CellStyle.DataFormat;
|
||||
//对时间格式(2015.12.5、2015/12/5、2015-12-5等)的处理
|
||||
if (format == 14 || format == 31 || format == 57 || format == 58)
|
||||
dataRow[j] = cell.DateCellValue;
|
||||
else
|
||||
dataRow[j] = cell.NumericCellValue;
|
||||
break;
|
||||
case CellType.String:
|
||||
dataRow[j] = cell.StringCellValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
dataTable.Rows.Add(dataRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
dataSet.Tables.Add(dataTable);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return dataSet;
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 将DataTable(DataSet)导出到Execl文档
|
||||
/// </summary>
|
||||
/// <param name="dataSet">传入一个DataSet</param>
|
||||
/// <param name="Outpath">导出路径(可以不加扩展名,不加默认为.xls)</param>
|
||||
/// <returns>返回一个Bool类型的值,表示是否导出成功</returns>
|
||||
/// True表示导出成功,Flase表示导出失败
|
||||
public static bool DataSetToExcel(DataSet dataSet, string Outpath)
|
||||
{
|
||||
bool result = false;
|
||||
try
|
||||
{
|
||||
if (dataSet == null || dataSet.Tables == null || dataSet.Tables.Count == 0 || string.IsNullOrEmpty(Outpath))
|
||||
throw new Exception("输入的DataSet或路径异常");
|
||||
int sheetIndex = 0;
|
||||
//根据输出路径的扩展名判断workbook的实例类型
|
||||
IWorkbook workbook = null;
|
||||
string pathExtensionName = Outpath.Trim().Substring(Outpath.Length - 5);
|
||||
if (pathExtensionName.Contains(".xlsx"))
|
||||
{
|
||||
workbook = new XSSFWorkbook();
|
||||
}
|
||||
else if (pathExtensionName.Contains(".xls"))
|
||||
{
|
||||
workbook = new HSSFWorkbook();
|
||||
}
|
||||
else
|
||||
{
|
||||
Outpath = Outpath.Trim() + ".xls";
|
||||
workbook = new HSSFWorkbook();
|
||||
}
|
||||
//将DataSet导出为Excel
|
||||
foreach (DataTable dt in dataSet.Tables)
|
||||
{
|
||||
sheetIndex++;
|
||||
if (dt != null && dt.Rows.Count > 0)
|
||||
{
|
||||
ISheet sheet = workbook.CreateSheet(string.IsNullOrEmpty(dt.TableName) ? ("sheet" + sheetIndex) : dt.TableName);//创建一个名称为Sheet0的表
|
||||
int rowCount = dt.Rows.Count;//行数
|
||||
int columnCount = dt.Columns.Count;//列数
|
||||
|
||||
//设置列头
|
||||
IRow row = sheet.CreateRow(0);//excel第一行设为列头
|
||||
for (int c = 0; c < columnCount; c++)
|
||||
{
|
||||
ICell cell = row.CreateCell(c);
|
||||
cell.SetCellValue(dt.Columns[c].ColumnName);
|
||||
}
|
||||
|
||||
//设置每行每列的单元格,
|
||||
for (int i = 0; i < rowCount; i++)
|
||||
{
|
||||
row = sheet.CreateRow(i + 1);
|
||||
for (int j = 0; j < columnCount; j++)
|
||||
{
|
||||
ICell cell = row.CreateCell(j);//excel第二行开始写入数据
|
||||
cell.SetCellValue(dt.Rows[i][j].ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//向outPath输出数据
|
||||
using (FileStream fs = File.OpenWrite(Outpath))
|
||||
{
|
||||
workbook.Write(fs);//向打开的这个xls文件中写入数据
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
25
SCADA/Core/PLC_R.cs
Normal file
25
SCADA/Core/PLC_R.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace DC_A95
|
||||
{
|
||||
public class PLC_R
|
||||
{
|
||||
/// <summary>
|
||||
/// 清理PLC字符串乱码(统一入口,支持object参数)
|
||||
/// 过滤不可见字符,保留可打印ASCII和中文等有效字符
|
||||
/// </summary>
|
||||
public static string GetString_CleanGarbled(object input)
|
||||
{
|
||||
if (input == null) return "";
|
||||
string str = input.ToString();
|
||||
if (string.IsNullOrEmpty(str)) return "";
|
||||
var sb = new StringBuilder();
|
||||
foreach (char c in str)
|
||||
{
|
||||
if (c >= 0x20 && c < 0xFFFE) sb.Append(c);
|
||||
}
|
||||
return sb.ToString().Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
72
SCADA/Core/SqlOperation.cs
Normal file
72
SCADA/Core/SqlOperation.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using MesWork;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MesWork
|
||||
{
|
||||
public class SqlOperation
|
||||
{
|
||||
public static bool ExecuteStoredProcedure(string name, SqlParameter[] sqlParameters, out string errorMessage)
|
||||
{
|
||||
return DataLinkMesWork.SQLCommon.ExecuteStoredProcedure(name, MesWorkForm.ConnectionString, ref sqlParameters, out errorMessage);
|
||||
}
|
||||
public static bool ExecuteStoredProcedure(string name, SqlParameter[] sqlParameters, out DataTable dt, out string errorMessage)
|
||||
{
|
||||
return DataLinkMesWork.SQLCommon.ExecuteStoredProcedure(name, MesWorkForm.ConnectionString, ref sqlParameters, out dt, out errorMessage);
|
||||
}
|
||||
public static bool ExecuteStoredProcedure(string name, SqlParameter[] sqlParameters, out DataSet ds, out string errorMessage)
|
||||
{
|
||||
return DataLinkMesWork.SQLCommon.ExecuteStoredProcedure(name, MesWorkForm.ConnectionString, ref sqlParameters, out ds, out errorMessage);
|
||||
}
|
||||
public static bool ExecuteSql(string sql, out DataTable dt, out string errorMessage)
|
||||
{
|
||||
return DataLinkMesWork.SQLCommon.ExecuteSql(sql, MesWorkForm.ConnectionString, out dt, out errorMessage);
|
||||
}
|
||||
|
||||
public static bool ExecuteSql(string sql, out DataSet ds, out string errorMessage)
|
||||
{
|
||||
return DataLinkMesWork.SQLCommon.ExecuteDataset(sql, MesWorkForm.ConnectionString, out ds, out errorMessage);
|
||||
}
|
||||
|
||||
public static bool ExecuteSql(string sql, out string errorMessage)
|
||||
{
|
||||
return DataLinkMesWork.SQLCommon.ExecuteSql(sql, MesWorkForm.ConnectionString, out errorMessage);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 通过SqlBulkCopy复制table数据到数据库
|
||||
/// </summary>
|
||||
/// <param name="dataset"></param>
|
||||
public static bool SqlbulkcopyInsert(DataTable dt, out string ErrMsg)
|
||||
{
|
||||
bool success = false;
|
||||
ErrMsg = "";
|
||||
try
|
||||
{
|
||||
// SqlBulkCopy sqlbulkcopy = new SqlBulkCopy(connectString, SqlBulkCopyOptions.KeepIdentity);//删除自增ID插入原始数据
|
||||
SqlBulkCopy sqlbulkcopy = new SqlBulkCopy(MesWorkForm.ConnectionString, SqlBulkCopyOptions.UseInternalTransaction);//批量事务处理
|
||||
sqlbulkcopy.DestinationTableName = dt.TableName;//数据库中的表名
|
||||
for (int i = 0; i < dt.Columns.Count; i++)
|
||||
{
|
||||
var columnName = dt.Columns[i].ColumnName.ToString();
|
||||
sqlbulkcopy.ColumnMappings.Add(columnName, columnName);
|
||||
}
|
||||
sqlbulkcopy.WriteToServer(dt);
|
||||
success = true;
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
ErrMsg = err.Message;
|
||||
}
|
||||
return success;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user