using BaseFunction; using DAL; using HslCommunication.Profinet.Siemens; using Newtonsoft.Json; using NSAnalysis.Properties; using PLCModule; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.IO.Ports; using System.Linq; using System.Net; using System.Text; using System.Threading; using System.Windows.Forms; using Telerik.WinControls; using Telerik.WinControls.UI; using UserControlClass; namespace NSAnalysis { /// /// /// /// /// 2025.08.29 /// -------------------------------------------------------------- /// 1、增加对 生成报告数据的备份、上传情况的记录√ /// 2、增加对IOT json报文 上传情况的记录√ /// 3、增加对 PLC 传输过点信号的 记录 (抵达,测量,离开) √ /// 4、PLC通讯阻塞问题 √ /// /// /// /// 2025.8.31 /// -------------------------------------------------------------- /// 1、增加对IOT 上传失败的重传功能 √ /// /// /// /// /// 2025.11.03 /// -------------------------------------------------------------- /// 1、修改大屏页面的后台刷新,避免长时间卡死不刷新的问题 √ /// /// /// /// /// /// 2026.03.16 /// -------------------------------------------------------------- /// 1、新增EHV车型的大屏显示,解析,与报告生成 √ /// 2、增加公差的批量导入功能 √ /// 3、修复 自定义表格控件会超出区域的问题 WorkingArea → Bounds √ /// 4、新大屏窗体要先show一下,然后hide, 否则窗体内后台刷新没有启动 √ /// /// /// public partial class CenterControl : Telerik.WinControls.UI.ShapedForm { #region 全局变量 private int[] yValues = new int[3]; private string[] xValues = new string[3]; private DataTable dtCSVContent = new DataTable(); private DataTable dtRangeData = new DataTable(); private TMeasureMSSQLDAL tmdal = new TMeasureMSSQLDAL(); private string strSaveReprotPath = ""; private bool bReadCSVFlag = false; private List ListPostIOTData = new List(); private FEHYLeftCarData fLEHY = null; private FEHYRightCarData fREHY = null; private FEH3LeftCarData fLEH3 = null; private FEH3RightCarData fREH3 = null; private FEHVLeftCarData fLEHV = null; private FEHVRightCarData fREHV = null; private int iCurrentMeasureItemsFailedCount = 0; private BackgroundWorker m_bgwAnalysisCSVReport = new BackgroundWorker(); #region PLC相关变量 private bool bStopPlcNormal = false; private static int HeartBeatCount = 0; private bool bPlcLiveTickLast = false; private Thread m_ThreadReconnectPLC = null; private int m_ReConnectNum = 0; private bool bTickt = true; private int iLastNSStartMeasure = 0; private int iLastCarPassFlag = 0; private int iLastStation1To2 = 0; private int iLastStation2To3 = 0; private int iLastReadVINFinishFlag = 0; private int iLastNoCarTypeFlag = 0; private SerialPort serialTestPort = null; private SerialPort serialPort = null; private int iLastMesureCount = 0; private System.Timers.Timer ttmrReadPLCData = new System.Timers.Timer(); private System.Timers.Timer ttmrWritePLCLive = new System.Timers.Timer(); private System.Timers.Timer ttmrReadNSCSV = new System.Timers.Timer(); #endregion PLC相关变量 #region 分页全局变量 private DataTable PageTable = new DataTable(); /// /// 每页记录数 /// public int pageSize = 20; /// /// 总记录数 /// public int recordCount = 0; /// /// 总页数 /// public int pageCount = 0; /// /// 当前页 /// public int currentPage = 0; #endregion 分页全局变量 #endregion 全局变量 #region 主窗口事件 public CenterControl() { InitializeComponent(); SQLHelper.connStr = DatabaseDfn.SqlConnectStr(); #region 加载皮肤 ThemeResolutionService.LoadPackageFile(ConfigDfn.strTheme); this.ThemeName = ConfigDfn.strSkinName.Substring(0, ConfigDfn.strSkinName.Length - 5); RPV.ThemeName = ConfigDfn.strSkinName.Substring(0, ConfigDfn.strSkinName.Length - 5); #endregion 加载皮肤 } private void CenterControl_Load(object sender, EventArgs e) { ttmrReadPLCData.Interval = 300; ttmrReadPLCData.SynchronizingObject = this; ttmrReadPLCData.Elapsed += ttmrReadPLCData_Elapsed; ttmrWritePLCLive.Interval = 1000; ttmrWritePLCLive.SynchronizingObject = this; ttmrWritePLCLive.Elapsed += ttmrWritePLCLive_Elapsed; ttmrReadNSCSV.Interval = 500; ttmrReadNSCSV.SynchronizingObject = this; ttmrReadNSCSV.Elapsed += ttmrReadNSCSV_Elapsed; #region 初始化全局变量 fLEHY = new FEHYLeftCarData(this); fREHY = new FEHYRightCarData(this); fLEH3 = new FEH3LeftCarData(this); fREH3 = new FEH3RightCarData(this); fLEHV = new FEHVLeftCarData(this); fREHV = new FEHVRightCarData(this); // 触发所有大屏窗体的 Load 事件,确保后台刷新线程启动,再隐藏 fLEHV.Show(); fLEHV.Hide(); fREHV.Show(); fREHV.Hide(); fLEH3.Show(); fLEH3.Hide(); fREH3.Show(); fREH3.Hide(); fLEHY.Show(); fLEHY.Hide(); fREHY.Show(); fREHY.Hide(); MyBase.rleMessage = rleMessage; rdtpStartTime.Text = DateTime.Now.ToString("yyyy-MM-dd"); rdtpEndTime.Text = DateTime.Now.ToString("yyyy-MM-dd"); #endregion 初始化全局变量 //需要显示车身数据 不分析csv文件 if (ConfigDfn.iShowCarDataFlag == 1) { MyBase.TraceWriteLine(" 进入显示车身模式!显示车身界面。"); lpcShowCarData_Click(null, null); //serialPort = new SerialPort(ConfigDfn.strCOMPort, 115200, Parity.None, 8, StopBits.One); // 设置串口参数 //serialPort.DataReceived += new SerialDataReceivedEventHandler(DataAutoReceivedHandler); // 注册数据接收事件处理方法 //serialPort.Open(); // 打开串口 //if (serialPort.IsOpen) //{ // MyBase.TraceWriteLine(ConfigDfn.strCOMPort + "打开成功O(∩_∩)O"); //} //else //{ // MyBase.TraceWriteLine(ConfigDfn.strCOMPort + "打开失败!"); // MessageBox.Show(ConfigDfn.strCOMPort + "打开失败!请检查扫抢串口设置是否正确。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); //} } else { MyBase.TraceWriteLine(" 进入不显示车身模式!"); } if (ConfigDfn.iAnalysisCSVFlag == 1) { btnConnectPlc_Click(null, null); MyBase.TraceWriteLine(" 进入解析CSV文件模式,开始解析扫码CSV文件!"); //ttmrReadNSCSV.Start(); //tmdal.updateMaintenceInfoEmpty(); m_bgwAnalysisCSVReport.DoWork += new DoWorkEventHandler(m_bgwAnalysisCSVReport_DoWork); m_bgwAnalysisCSVReport.RunWorkerAsync(); } else { MyBase.TraceWriteLine(" 进入不解析CSV文件模式!"); ttmrReadNSCSV.Stop(); } if (Directory.Exists(ConfigDfn.strNextSenseCSVEH3Path)) { MyBase.TraceWriteLine("软件首次启动, Nextsense EH3 CSV读取路径存在;不清空,读取NextSense生成 CSV报告路径下的所有文件,路径为:" + ConfigDfn.strNextSenseCSVEH3Path); } else { string strTip = "错误:软件首次启动,读取NextSense生成EH3 CSV报告的路径:" + ConfigDfn.strNextSenseCSVEH3Path + " 不存在!请检查并进行修改!点击是按钮,软件将自动创建该路径!"; MyBase.TraceWriteLine(strTip); Directory.CreateDirectory(ConfigDfn.strNextSenseCSVEH3Path); //DialogResult dResult = MessageBox.Show(strTip, "错误", MessageBoxButtons.YesNo, MessageBoxIcon.Error); //if (dResult == DialogResult.Yes) //{ // Directory.CreateDirectory(ConfigDfn.strNextSenseCSVEH3Path); // MyBase.TraceWriteLine(strTip + " ; 点击了是按钮,软件自动创建读取目录:" + ConfigDfn.strNextSenseCSVEH3Path); //} //else //{ // MyBase.TraceWriteLine(strTip + " ;点击了否按钮,不创建目录!"); //} } if (Directory.Exists(ConfigDfn.strNextSenseCSVEHYPath)) { MyBase.TraceWriteLine("软件首次启动, Nextsense EHY CSV读取路径存在;不清空,读取NextSense生成 CSV报告路径下的所有文件,路径为:" + ConfigDfn.strNextSenseCSVEHYPath); } else { string strTip = "错误:软件首次启动,读取NextSense生成EHY CSV报告的路径:" + ConfigDfn.strNextSenseCSVEHYPath + " 不存在!请检查并进行修改!点击是按钮,软件将自动创建该路径!"; MyBase.TraceWriteLine(strTip); Directory.CreateDirectory(ConfigDfn.strNextSenseCSVEHYPath); } if (!string.IsNullOrWhiteSpace(ConfigDfn.strNextSenseCSVEHVPath)) { if (Directory.Exists(ConfigDfn.strNextSenseCSVEHVPath)) { MyBase.TraceWriteLine("软件首次启动, Nextsense EHV CSV读取路径存在;不清空,读取NextSense生成 CSV报告路径下的所有文件,路径为:" + ConfigDfn.strNextSenseCSVEHVPath); } else { string strTipEHV = "错误:软件首次启动,读取NextSense生成EHV CSV报告的路径:" + ConfigDfn.strNextSenseCSVEHVPath + " 不存在!请检查并进行修改!软件将自动创建该路径!"; MyBase.TraceWriteLine(strTipEHV); Directory.CreateDirectory(ConfigDfn.strNextSenseCSVEHVPath); } } else { MyBase.TraceWriteLine("EHV CSV读取路径未配置,跳过路径检查。"); } initLPCControl(); //tmdal.updateMaintenceInfoEmpty(); //iLastMesureCount = tmdal.SelectTMeasureResultCount(); #region 清空信息 labVIN.Text = ""; labOKCount.Text = ""; labNGCount.Text = ""; labRejectCount.Text = ""; labSumMeasureCount.Text = ""; labMeaTime.Text = ""; labResultPercent.Text = ""; labResult.Text = ""; labCarType.Text = ""; #endregion 清空信息 InitTableColumns(); strSaveReprotPath = ConfigDfn.strReportPath + @"\"; //testIotUpload(); } private void InitTableColumns() { #region 测量数据表始化表 //创建虚拟表 DataColumn column2 = new DataColumn("CarID", Type.GetType("System.String")); DataColumn dcCarType = new DataColumn("CarType", Type.GetType("System.String")); DataColumn column3 = new DataColumn("MeasPointName", Type.GetType("System.String")); DataColumn column4 = new DataColumn("DimensionName", Type.GetType("System.String")); DataColumn column5 = new DataColumn("NormalValue", Type.GetType("System.String")); DataColumn column6 = new DataColumn("LowerTolVal", Type.GetType("System.String")); DataColumn column7 = new DataColumn("UpperTolVal", Type.GetType("System.String")); DataColumn column8 = new DataColumn("MeasureValue", Type.GetType("System.String")); DataColumn column10 = new DataColumn("MeasureItemResult", Type.GetType("System.String")); DataColumn column9 = new DataColumn("MeasureDate", Type.GetType("System.DateTime")); DataColumn column1 = new DataColumn("Remark", Type.GetType("System.String")); //将列添加到table表中 dtCSVContent.Columns.Add(column2); dtCSVContent.Columns.Add(dcCarType); dtCSVContent.Columns.Add(column3); dtCSVContent.Columns.Add(column4); dtCSVContent.Columns.Add(column5); dtCSVContent.Columns.Add(column6); dtCSVContent.Columns.Add(column7); dtCSVContent.Columns.Add(column8); dtCSVContent.Columns.Add(column10); dtCSVContent.Columns.Add(column9); dtCSVContent.Columns.Add(column1); #endregion 测量数据表始化表 #region 极差数据Table初始化 //创建虚拟表 DataColumn dcCarID = new DataColumn("CarID", Type.GetType("System.String")); DataColumn dcRangeName = new DataColumn("RangeName", Type.GetType("System.String")); DataColumn dcRangeValue = new DataColumn("RangeValue", Type.GetType("System.String")); DataColumn dcRangeLowUpp = new DataColumn("RangeLowUpp", Type.GetType("System.String")); DataColumn dcResult = new DataColumn("Result", Type.GetType("System.String")); DataColumn dcCreateTime = new DataColumn("CreateTime", Type.GetType("System.DateTime")); DataColumn dcRemark = new DataColumn("Remark", Type.GetType("System.String")); //将列添加到table表中 dtRangeData.Columns.Add(dcCarID); dtRangeData.Columns.Add(dcRangeName); dtRangeData.Columns.Add(dcRangeValue); dtRangeData.Columns.Add(dcRangeLowUpp); dtRangeData.Columns.Add(dcResult); dtRangeData.Columns.Add(dcCreateTime); dtRangeData.Columns.Add(dcRemark); #endregion 极差数据Table初始化 #region 分页相关 //创建分页虚拟表 DataColumn column11 = new DataColumn("CarID", Type.GetType("System.String")); DataColumn column12 = new DataColumn("MeasPointName", Type.GetType("System.String")); DataColumn column13 = new DataColumn("DimensionName", Type.GetType("System.String")); DataColumn column14 = new DataColumn("NormalValue", Type.GetType("System.String")); DataColumn column15 = new DataColumn("LowerTolVal", Type.GetType("System.String")); DataColumn column16 = new DataColumn("UpperTolVal", Type.GetType("System.String")); DataColumn column17 = new DataColumn("MeasureValue", Type.GetType("System.String")); DataColumn column18 = new DataColumn("MeasureDate", Type.GetType("System.String")); DataColumn column19 = new DataColumn("MeasureItemResult", Type.GetType("System.String")); //将列添加到table表中 PageTable.Columns.Add(column11); PageTable.Columns.Add(column12); PageTable.Columns.Add(column13); PageTable.Columns.Add(column14); PageTable.Columns.Add(column15); PageTable.Columns.Add(column16); PageTable.Columns.Add(column17); PageTable.Columns.Add(column18); PageTable.Columns.Add(column19); labCurrentPage.Text = "当前页:" + currentPage.ToString(); //当前页 labSumPages.Text = "共 " + pageCount.ToString() + " 页";//总页数 labSumRecorders.Text = "总共 " + recordCount.ToString() + " 条记录";//总记录数 rddlPageRecorderCount.SelectedIndex = 0; #endregion 分页相关 } private void DataAutoReceivedHandler(object sender, SerialDataReceivedEventArgs e) { SerialPort sp = (SerialPort)sender; string strScanVIN = sp.ReadExisting(); MyBase.TraceWriteLine("扫抢获取的VIN码为:" + strScanVIN); if (strScanVIN.Length > 0) { tmdal.updateMaintenceInfo(strScanVIN, 3); MyBase.TraceWriteLine("更新数据库中存储的VIN码:" + strScanVIN); } } private void initLPCControl() { lpcSoftwareSetup.labPicture.Click += new EventHandler(lpcSoftwareSetup_Click); lpcSoftwareSetup.labText.Click += new EventHandler(lpcSoftwareSetup_Click); lpcToleranceSetup.labPicture.Click += new EventHandler(lpcToleranceSetup_Click); lpcToleranceSetup.labText.Click += new EventHandler(lpcToleranceSetup_Click); lpcRange.labPicture.Click += new EventHandler(lpcRange_Click); lpcRange.labText.Click += new EventHandler(lpcRange_Click); lpcPLCAddress.labPicture.Click += new EventHandler(lpcPLCAddress_Click); lpcPLCAddress.labText.Click += new EventHandler(lpcPLCAddress_Click); lpcPLCTest.labPicture.Click += new EventHandler(lpcPLCTest_Click); lpcPLCTest.labText.Click += new EventHandler(lpcPLCTest_Click); lpcAboutSoftware.labPicture.Click += new EventHandler(lpcAboutSoftware_Click); lpcAboutSoftware.labText.Click += new EventHandler(lpcAboutSoftware_Click); lpcUploadIOTTest.labPicture.Click += new EventHandler(lpcUploadIOTTest_Click); lpcUploadIOTTest.labText.Click += new EventHandler(lpcUploadIOTTest_Click); lpcTestGetCarTye.labPicture.Click += new EventHandler(lpcTestGetCarTye_Click); lpcTestGetCarTye.labText.Click += new EventHandler(lpcTestGetCarTye_Click); lpcShowCarData.labPicture.Click += new EventHandler(lpcShowCarData_Click); lpcShowCarData.labText.Click += new EventHandler(lpcShowCarData_Click); lpcShowLog.labPicture.Click += new EventHandler(lpcShowLog_Click); lpcShowLog.labText.Click += new EventHandler(lpcShowLog_Click); } private void CenterControl_FormClosed(object sender, FormClosedEventArgs e) { MyBase.TraceWriteLine("-------------海克斯康面隙分析软件程序关闭---------------------"); LogDebugDfn.strEndTime = DateTime.Now.ToString("yyyy.MM.dd HH-mm-ss"); string CopyFileName = ConfigDfn.strFileFolder + "\\DebugFiles\\" + "Debug(" + LogDebugDfn.strStartTime + " To " + LogDebugDfn.strEndTime + ")" + ".txt"; if (File.Exists(LogDebugDfn.strDebugFile)) File.Copy(LogDebugDfn.strDebugFile, CopyFileName); System.Environment.Exit(0); } private void tmSystem_Tick(object sender, EventArgs e) { rleTime.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); if (ConfigDfn.iAnalysisCSVFlag == 1) rleReadCSVStatus.ForeColor = bReadCSVFlag ? Color.Green : Color.White; bReadCSVFlag = !bReadCSVFlag; } #endregion 主窗口事件 #region⭐⭐⭐⭐⭐ 解析Nextsense CSV文件功能 核心算法 ⭐⭐⭐⭐⭐ private double CalculateStrictLowerTolerance(double dLower, double dUpper) { double dStrictLower = 0; double dNormalValue = (dLower + dUpper) / 2; dStrictLower = dNormalValue + (dLower - dNormalValue) * ConfigDfn.dTolerancePer; return dStrictLower; } private double CalculateStrictUpperTolerance(double dLower, double dUpper) { double dStrictUpper = 0; double dNormalValue = (dLower + dUpper) / 2; dStrictUpper = dNormalValue + (dUpper - dNormalValue) * ConfigDfn.dTolerancePer; return dStrictUpper; } private double CalculateExceptionLowerTolerance(double dLower, double dUpper) { double dStrictLower = 0; double dNormalValue = (dLower + dUpper) / 2; dStrictLower = dNormalValue + (dLower - dNormalValue) * ConfigDfn.dExceptionTolerancePer; return dStrictLower; } private double CalculateExceptionUpperTolerance(double dLower, double dUpper) { double dStrictUpper = 0; double dNormalValue = (dLower + dUpper) / 2; dStrictUpper = dNormalValue + (dUpper - dNormalValue) * ConfigDfn.dExceptionTolerancePer; return dStrictUpper; } /// /// 解析EH3 CSV文件函数;后续如果Nextsense的csv报告模板变了,修改该函数的行号即可LineNum wsp /// private void AnalysisNextSenseEH3CSV() // 解析EH3 车型 { try { Invoke((MethodInvoker)(() => { lbCSVFiles.Items.Clear(); })); FileInfo[] fileInfos = null; if (Directory.Exists(ConfigDfn.strNextSenseCSVEH3Path)) { DirectoryInfo di = new DirectoryInfo(ConfigDfn.strNextSenseCSVEH3Path); fileInfos = di.GetFiles("*.CSV"); if (fileInfos.Count() >= 1) { MyBase.TraceWriteLine("存在EH3 CSV文件,开始解析:"); List listCSVTitleInfo = new List(); string strCarID = ""; foreach (FileInfo fi in fileInfos) { listCSVTitleInfo.Clear(); ListPostIOTData.Clear(); dtCSVContent.Clear(); string strCSVName = fi.FullName; try { File.Copy(fi.FullName, ConfigDfn.strFileFolder + "\\NextSenseCSVBackup\\" + fi.Name, true); } catch (IOException ioEx) { MyBase.TraceWriteLine("EH3 CSV文件被占用,跳过本次解析,等待下次轮询:" + fi.Name + " | " + ioEx.Message); Thread.Sleep(500); continue; } MyBase.TraceWriteLine("Copy " + fi.FullName + " TO " + ConfigDfn.strFileFolder + "\\NextSenseCSVBackup\\" + fi.Name + " Done. 备份完成"); Invoke((MethodInvoker)(() => { dgvMeasureContent.Rows.Clear(); lbCSVFiles.Items.Add(fi.Name); })); #region 解析EH3 CSV报告 MyBase.TraceWriteLine("开始解析NextSense EH3 CSV 报告:" + strCSVName); Encoding encoding = GetType(strCSVName); FileStream fs = new FileStream(strCSVName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); StreamReader sr = new StreamReader(fs, encoding); //记录每次读取的一行记录 string strLine = ""; //记录每行记录中的各字段内容 string[] aryLineContent = null; //逐行读取CSV中的数据 int LineNum = 0; //表格行数 int dtRowCount = 0; //超差个数 double OutCount = 0; //Ok个数 double OKCount = 0; //异常个数 double RejectedCount = 0; //合格率 double FPYPercent = 0; double dStrictTLower = 0; double dStrictTUpper = 0; double dLowerValue = 0; double dUpperValue = 0; double dExcepitonTLower = 0; double dExceptionTUpper = 0; double dMeasureValue = 0.0; DataTable dt = null; while ((strLine = sr.ReadLine()) != null) { LineNum++; if (LineNum >= 3 & LineNum <= 16) { listCSVTitleInfo.Add(strLine); } if (LineNum == 10) { aryLineContent = strLine.Split(','); MyBase.TraceWriteLine("解析出NextSense CSV中的VIN为:" + aryLineContent[1]); strCarID = tmdal.SelectVINByCSVVIN(aryLineContent[1]); MyBase.TraceWriteLine("通过CSV VIN从数据库中获取的完整VIN为:" + strCarID); if (strCarID.ToLower().Contains("nofind")) { MyBase.TraceWriteLine("数据库中没有查找到VIN码,NoFind, +L 使用CSV码"); labVIN.Text = "L" + aryLineContent[1]; strCarID = "L" + aryLineContent[1]; } else { labVIN.Text = strCarID; tmdal.DeleteOneTTempVIN(strCarID); MyBase.TraceWriteLine("在数据库表TTempSaveVIN中删除该VIN:" + strCarID); } } if (LineNum >= 19) { aryLineContent = strLine.Split(','); //ConfigDfn.strMeasureTime = aryLineContent[6].Substring(0, 4) + "-" + aryLineContent[6].Substring(4, 2) + "-" + aryLineContent[6].Substring(6, 2) + " " + aryLineContent[7].Substring(0, 2) + ":" + aryLineContent[7].Substring(2, 2) + ":" + aryLineContent[7].Substring(4, 2); ConfigDfn.strMeasureTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); double dNormalValue = 0.0d; bool bToleranceValid = false; dt = tmdal.SelectOneToleranceByCondition("EH3", aryLineContent[0], aryLineContent[1]); if (dt.Rows.Count == 1) { dLowerValue = double.Parse(dt.Rows[0]["TolLower"].ToString()); dUpperValue = double.Parse(dt.Rows[0]["TolUpper"].ToString()); dNormalValue = (dLowerValue + dUpperValue) / 2; dStrictTLower = CalculateStrictLowerTolerance(dLowerValue, dUpperValue); dStrictTUpper = CalculateStrictUpperTolerance(dLowerValue, dUpperValue); dExcepitonTLower = CalculateExceptionLowerTolerance(dLowerValue, dUpperValue); dExceptionTUpper = CalculateExceptionUpperTolerance(dLowerValue, dUpperValue); bToleranceValid = true; } else { // 修复:公差未配置时显式重置异常公差,避免上一轮循环遗留值 // 同时不再用0作为默认公差(否则后续 dMeasureValue>=0||<=0 几乎恒真,会把所有实测值误判为ng3并清空) dStrictTLower = 0; dStrictTUpper = 0; dLowerValue = 0; dUpperValue = 0; dExcepitonTLower = 0; dExceptionTUpper = 0; MyBase.TraceWriteLine("EH3 " + aryLineContent[0] + " " + aryLineContent[1] + " 查询数据获取公差带失败!数据库中数量不唯一,请检查公差带配置!原始测量值将保留并写入数据库,结果标记为noTol。"); } if (aryLineContent[2].ToLower().Contains("inv")) { aryLineContent[2] = ""; aryLineContent[4] = "ng2"; } else if (!bToleranceValid) { // 修复:公差缺失时保留原始测量值,标记为noTol,避免数据系统性丢失 MyBase.TraceWriteLine("EH3 " + aryLineContent[0] + " " + aryLineContent[1] + " 公差未配置,保留原始测量值=" + aryLineContent[2] + ",结果标记为noTol。"); aryLineContent[4] = "noTol"; } else { dMeasureValue = double.Parse(aryLineContent[2]); if (dMeasureValue >= dLowerValue && dMeasureValue <= dUpperValue) { aryLineContent[4] = "good"; } else if (dMeasureValue >= dStrictTLower && dMeasureValue <= dStrictTUpper) { aryLineContent[4] = "ng1"; } else if (dMeasureValue >= dExceptionTUpper || dMeasureValue <= dExcepitonTLower) { // 修复:原先此处 aryLineContent[2] = "" 会把超差的实测值清空, // 导致客户CSV报告与XML汇总测出率系统性偏低,现仅打标ng3,保留原始测量值。 aryLineContent[4] = "ng3"; MyBase.TraceWriteLine("EH3 " + aryLineContent[0] + " " + aryLineContent[1] + " 实测值=" + dMeasureValue.ToString("F2") + " 超出异常公差区间[" + dExcepitonTLower.ToString("F2") + "," + dExceptionTUpper.ToString("F2") + "],结果ng3,原值保留。"); } else { aryLineContent[4] = "ng2"; } } //测量数据存储到table里 dtCSVContent.Rows.Add(strCarID, "EH3", aryLineContent[0], aryLineContent[1], dNormalValue.ToString("F1"), dLowerValue.ToString("F1"), dUpperValue.ToString("F1"), aryLineContent[2], aryLineContent[4], DateTime.Now, ""); string strMeasureResult = aryLineContent[4].ToLower(); if (strMeasureResult.Contains("good") || strMeasureResult.Contains("best") || strMeasureResult.Contains("ng1")) { OKCount++; aryLineContent[4] = "OK"; } else if (strMeasureResult.Contains("ng2")) { OutCount++; aryLineContent[4] = "NG"; } else { // ng3 / noTol 等异常分支:原先此处 aryLineContent[2] = "" 也会清空实测值, // 现保留原始值用于追溯,仅清空结果列。 RejectedCount++; aryLineContent[4] = ""; } Invoke((MethodInvoker)(() => { dgvMeasureContent.Rows.Add(aryLineContent[0], aryLineContent[1], dNormalValue.ToString("F1"), dLowerValue.ToString("F1"), dUpperValue.ToString("F1"), aryLineContent[2], ConfigDfn.strMeasureTime, aryLineContent[4]); })); CheryIOTData cIOTData = new CheryIOTData(); cIOTData.vin = strCarID; cIOTData.gfNo = aryLineContent[1]; cIOTData.pointNumber = aryLineContent[0]; cIOTData.actualValue = aryLineContent[2]; cIOTData.controlLine = dLowerValue.ToString("F1") + @"/" + dUpperValue.ToString("F1"); if (strMeasureResult.Contains("good") || strMeasureResult.Contains("best") || strMeasureResult.Contains("ng1")) { cIOTData.measurementResult = "OK"; } else { cIOTData.measurementResult = "NG"; } ListPostIOTData.Add(cIOTData); dtRowCount++; Invoke((MethodInvoker)(() => { dgvMeasureContent.Rows[dtRowCount - 1].HeaderCell.Value = dtRowCount.ToString(); })); } }//End While sr.Close(); fs.Close(); // 数据完整性校验日志:统计本次解析后多少测点保留了原始测量值(修复Bug前ng3/noTol会被清空) int iEH3TotalRows = dtCSVContent.Rows.Count; int iEH3WithValue = 0; int iEH3EmptyValue = 0; int iEH3NoTolCount = 0; int iEH3Ng3Count = 0; foreach (DataRow drCheck in dtCSVContent.Rows) { string sVal = drCheck["MeasureValue"]?.ToString() ?? ""; string sRes = (drCheck["MeasureItemResult"]?.ToString() ?? "").ToLower(); if (string.IsNullOrEmpty(sVal)) iEH3EmptyValue++; else iEH3WithValue++; if (sRes.Contains("notol")) iEH3NoTolCount++; if (sRes.Contains("ng3")) iEH3Ng3Count++; } MyBase.TraceWriteLine($"[EH3完整性] 车号={strCarID} 测点总数={iEH3TotalRows} 有值={iEH3WithValue} 空值={iEH3EmptyValue} ng3={iEH3Ng3Count} noTol={iEH3NoTolCount}"); tmdal.InsertTMeasureDatabyDataTable(dtCSVContent); MyBase.TraceWriteLine("解析EH3数据完成,并将所有测量数据插入到数据库完毕。"); MyBase.TraceWriteLine("解析NextSense EH3 CSV 报告完毕!检测项数=" + dtRowCount.ToString()); if (dtRowCount <= ConfigDfn.iMeasureItemsCount) { iCurrentMeasureItemsFailedCount++; } else { iCurrentMeasureItemsFailedCount = 0; } // 连续多个车异常 if (iCurrentMeasureItemsFailedCount >= ConfigDfn.iFailedCarCount) { MyBase.TraceWriteLine("iCurrentMeasureItemsFailedCount=" + iCurrentMeasureItemsFailedCount.ToString() + "超过报警数量" + ConfigDfn.iFailedCarCount.ToString() + " ;给PLC发送报警10。"); PlcObject.InsertWriteQueue(PlcSignalDfn.MeasureError, (byte)10); } // 单个报告内 invalued 项超过某个值 // 机器人忙碌状态 且 多个小时无测量报告 #endregion 解析EH3 CSV报告 #region 计算极差 CalculateRange(strCarID, "EH3"); Thread.Sleep(20); DataTable dtAllRangeDate = tmdal.SelectRangeDatabyCarID(strCarID); if (dtAllRangeDate.Rows.Count > 0) { foreach (DataRow row in dtAllRangeDate.Rows) { if (ConfigDfn.iIncludeRangeFlag == 1) { if (row.ItemArray[5].ToString().Contains("OK")) { OKCount++; } else { OutCount++; } } Invoke((MethodInvoker)(() => { dgvMeasureContent.Rows.Add(row.ItemArray[2].ToString(), "G", "0", row.ItemArray[4].ToString().Substring(0, 3), row.ItemArray[4].ToString().Substring(4, 3), row.ItemArray[3].ToString(), ConfigDfn.strMeasureTime, row.ItemArray[5].ToString()); })); } } if (ConfigDfn.iIncludeRangeFlag == 1) { dtRowCount = dtRowCount + dtAllRangeDate.Rows.Count; for (int i = 1; i <= dtRowCount; i++) { Invoke((MethodInvoker)(() => { dgvMeasureContent.Rows[i - 1].HeaderCell.Value = i.ToString(); })); } MyBase.TraceWriteLine("计算合格率的时:包含极差计算项!"); } #endregion 计算极差 string strTargetRate = ""; Invoke((MethodInvoker)(() => { #region 界面显示功能 labCarType.Text = "EH3"; TMeasureResultModel tmrm = new TMeasureResultModel(); labNGCount.Text = OutCount.ToString(); labOKCount.Text = OKCount.ToString(); labRejectCount.Text = RejectedCount.ToString(); labMeaTime.Text = ConfigDfn.strMeasureTime; labSumMeasureCount.Text = dtRowCount.ToString(); FPYPercent = OKCount / (OKCount + OutCount); if (FPYPercent >= ConfigDfn.dFPY) { labResultPercent.Text = Math.Round(FPYPercent * 100.00d, 2).ToString("F2") + "%"; labResult.Text = "合格"; labResultPercent.ForeColor = Color.LimeGreen; labResult.ForeColor = Color.LimeGreen; pbResult.Image = Resources.OK; tmrm.Result = 1; PlcObject.InsertWriteQueue(PlcSignalDfn.CMMResult, (byte)10); } else if (FPYPercent >= ConfigDfn.dFPY2 && FPYPercent < ConfigDfn.dFPY) { labResultPercent.Text = Math.Round(FPYPercent * 100.00d, 2).ToString("F2") + "%"; labResult.Text = "合格"; labResultPercent.ForeColor = Color.Yellow; labResult.ForeColor = Color.Yellow; pbResult.Image = Resources.OK; tmrm.Result = 1; PlcObject.InsertWriteQueue(PlcSignalDfn.CMMResult, (byte)20); } else { labResultPercent.Text = Math.Round(FPYPercent * 100.00d, 2).ToString("F2") + "%"; labResult.Text = "不合格"; labResultPercent.ForeColor = Color.Red; labResult.ForeColor = Color.Red; pbResult.Image = Resources.NG; tmrm.Result = 2; PlcObject.InsertWriteQueue(PlcSignalDfn.CMMResult, (byte)30); } xValues[0] = "合格 : " + OKCount.ToString(); xValues[1] = "不合格 : " + OutCount.ToString(); xValues[2] = "异常 : " + RejectedCount.ToString(); yValues[0] = (int)OKCount; yValues[1] = (int)OutCount; yValues[2] = (int)RejectedCount; chartResultPie.Series[0].Points.DataBindXY(xValues, yValues); strTargetRate = Math.Round(ConfigDfn.dFPY2 * 100.00d, 2).ToString("F2") + "%"; tmrm.CarID = strCarID; tmrm.CarType = "EH3"; tmrm.SumMeasureItems = dtRowCount; tmrm.GoodMeasureItems = (int)OKCount; tmrm.NoGoodMeasureItems = (int)OutCount; tmrm.RejectMeasureItems = (int)RejectedCount; tmrm.FPY = FPYPercent.ToString("F4"); tmrm.Remark = ""; tmrm.MeasureDate = ConfigDfn.strMeasureTime; tmdal.InsertTMeasureResult(tmrm); MyBase.TraceWriteLine("将EH3总结果插入数据库完毕。"); MyBase.TraceWriteLine("全部插入解析完毕,删除文件:" + fi.Name); fi.Delete(); dgvMeasureContent.Rows.Add(); dgvMeasureContent.Rows[dgvMeasureContent.Rows.Count - 1].Cells["MResult"].Value = (dtRowCount - OutCount - RejectedCount).ToString() + "/" + dtRowCount.ToString(); this.dgvMeasureContent.Rows[dgvMeasureContent.Rows.Count - 1].DefaultCellStyle.ForeColor = Color.White; if (dgvMeasureContent.Rows.Count > 0) { SetdgvRowBgColor(dgvMeasureContent); for (int i = 0; i < dgvMeasureContent.Rows.Count; i++) { //if (dgvMeasureContent.Rows[i].Cells["MResult"].Value.ToString().ToLower().Contains("ok")) //{ // dgvMeasureContent.Rows[i].DefaultCellStyle.BackColor = Color.Orange; //} if (dgvMeasureContent.Rows[i].Cells["MResult"].Value.ToString().ToLower().Contains("ng")) { dgvMeasureContent.Rows[i].DefaultCellStyle.BackColor = Color.Orange; } else if (string.IsNullOrEmpty(dgvMeasureContent.Rows[i].Cells["MResult"].Value.ToString())) { dgvMeasureContent.Rows[i].DefaultCellStyle.BackColor = Color.Red; } else { } } } #endregion 界面显示功能 })); //生成客户的 CSV文件 if (ConfigDfn.iCreateReportFlag == 1) { GenUserReportCSV(strCarID, listCSVTitleInfo, dtAllRangeDate, FPYPercent); } else { MyBase.TraceWriteLine("EH3数据生成报告功能未启用!"); } #region Update Data To IOT if (ConfigDfn.iStartIOTFlag == 1) { bool bVINMeasuedFlag = tmdal.CheckVINExistInDB(strCarID); if (bVINMeasuedFlag) { MyBase.TraceWriteLine("VIN:" + strCarID + " 该VIN码已经在数据库中存在了,说明已经测量过了,不再进行IOT数据上传操作。"); } else { #region IOT上传功能 if (dtAllRangeDate.Rows.Count > 0) { foreach (DataRow row in dtAllRangeDate.Rows) { CheryIOTData cIOTData = new CheryIOTData(); cIOTData.vin = strCarID; cIOTData.gfNo = "G"; cIOTData.pointNumber = row.ItemArray[2].ToString(); cIOTData.actualValue = row.ItemArray[3].ToString(); cIOTData.controlLine = row.ItemArray[4].ToString(); cIOTData.measurementResult = row.ItemArray[5].ToString(); if (cIOTData.measurementResult.ToUpper().Contains("NG")) { if (!string.IsNullOrEmpty(cIOTData.actualValue) && !cIOTData.actualValue.ToLower().Contains("inv")) //避免为空的情况 { dLowerValue = double.Parse(row.ItemArray[4].ToString().Substring(0, 3)); dUpperValue = double.Parse(row.ItemArray[4].ToString().Substring(4, 3)); dStrictTLower = CalculateStrictLowerTolerance(dLowerValue, dUpperValue); dStrictTUpper = CalculateStrictUpperTolerance(dLowerValue, dUpperValue); double dValue = double.Parse(row.ItemArray[3].ToString()); if (dValue > dStrictTLower && dValue < dStrictTUpper) { cIOTData.measurementResult = "OK"; } } } ListPostIOTData.Add(cIOTData); } } string strGapList = JsonHelper.ObjectToJson(ListPostIOTData); string strCaliResult = "OK"; if (labResult.Text == "合格") { strCaliResult = "OK"; } else { strCaliResult = "NG"; } string strPostData = "{\"serno\":\"" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + "\",\"requestData\":[{\"vin\":\"" + strCarID + "\",\"model\":\"EH3\",\"equipmentNo\":\"" + ConfigDfn.strEquipNo + "\",\"equipmentName\":\"" + ConfigDfn.strEquipName + "\",\"calibrationResult\":\"" + strCaliResult + "\",\"detectionTime\":\"" + ConfigDfn.strMeasureTime + "\",\"targetRate\":\"" + strTargetRate + "\",\"rate\":\"" + labResultPercent.Text + "\",\"GapList\":" + strGapList + "}]}"; MyBase.TraceWriteLine("Update To IOT Data Content: " + strPostData); string strPostResult = PostJsonToIOT(ConfigDfn.strIOTAddress, strPostData, 10000); MyBase.TraceWriteLine("EH3数据上传IOT完成,结果返回为:" + strPostResult); if (strPostResult.Contains("成功")) { MyBase.TraceWriteLine("EH3数据上传IOT成功 ^_^"); tmdal.InsertIOTUploadLog(strCarID, strPostData, true, labResultPercent.Text); } else { MyBase.TraceWriteLine("EH3数据上传IOT失败!"); tmdal.InsertIOTUploadLog(strCarID, strPostData, false, labResultPercent.Text); } #endregion IOT上传功能 } } else { MyBase.TraceWriteLine("数据上传IOT功能未启用!"); } #endregion Update Data To IOT } } } //else //{ // MyBase.TraceWriteLine("错误:AnalysisNextSenseEH3CSV函数中,检测EH3 CSV 路径不存在:" + ConfigDfn.strNextSenseCSVPath); //} } catch (Exception ex) { MyBase.TraceWriteLine("AnalysisNextSenseCSV 函数分析异常:" + ex.ToString()); } } private void AnalysisNextSenseEHYCSV() //解析EHY 车型 { try { Invoke((MethodInvoker)(() => { lbCSVFiles.Items.Clear(); })); FileInfo[] fileInfos = null; if (Directory.Exists(ConfigDfn.strNextSenseCSVEHYPath)) { DirectoryInfo di = new DirectoryInfo(ConfigDfn.strNextSenseCSVEHYPath); fileInfos = di.GetFiles("*.CSV"); if (fileInfos.Count() >= 1) { MyBase.TraceWriteLine("存在EHY CSV文件,开始解析:"); List listCSVTitleInfo = new List(); string strCarID = ""; foreach (FileInfo fi in fileInfos) { listCSVTitleInfo.Clear(); ListPostIOTData.Clear(); dtCSVContent.Clear(); string strCSVName = fi.FullName; try { File.Copy(fi.FullName, ConfigDfn.strFileFolder + "\\NextSenseCSVBackup\\" + fi.Name, true); } catch (IOException ioEx) { MyBase.TraceWriteLine("EHY CSV文件被占用,跳过本次解析,等待下次轮询:" + fi.Name + " | " + ioEx.Message); Thread.Sleep(500); continue; } MyBase.TraceWriteLine("Copy " + fi.FullName + " TO " + ConfigDfn.strFileFolder + "\\NextSenseCSVBackup\\" + fi.Name + " Done. 备份完成"); Invoke((MethodInvoker)(() => { dgvMeasureContent.Rows.Clear(); lbCSVFiles.Items.Add(fi.Name); })); #region 解析EHY CSV报告 MyBase.TraceWriteLine("开始解析NextSense EHY CSV 报告:" + strCSVName); Encoding encoding = GetType(strCSVName); FileStream fs = new FileStream(strCSVName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); StreamReader sr = new StreamReader(fs, encoding); //记录每次读取的一行记录 string strLine = ""; //记录每行记录中的各字段内容 string[] aryLineContent = null; //逐行读取CSV中的数据 int LineNum = 0; //表格行数 int dtRowCount = 0; //超差个数 double OutCount = 0; //Ok个数 double OKCount = 0; //异常个数 double RejectedCount = 0; //合格率 double FPYPercent = 0; double dStrictTLower = 0; double dStrictTUpper = 0; double dLowerValue = 0; double dUpperValue = 0; double dExcepitonTLower = 0; double dExceptionTUpper = 0; double dMeasureValue = 0.0; DataTable dt = null; while ((strLine = sr.ReadLine()) != null) { LineNum++; if (LineNum >= 3 & LineNum <= 16) { listCSVTitleInfo.Add(strLine); } if (LineNum == 10) { aryLineContent = strLine.Split(','); MyBase.TraceWriteLine("解析出NextSense CSV中的VIN为:" + aryLineContent[1]); strCarID = tmdal.SelectVINByCSVVIN(aryLineContent[1]); MyBase.TraceWriteLine("通过CSV VIN从数据库中获取的完整VIN为:" + strCarID); if (strCarID.ToLower().Contains("nofind")) { MyBase.TraceWriteLine("数据库中没有查找到VIN码,NoFind, +L 使用CSV码"); labVIN.Text = "L" + aryLineContent[1]; strCarID = "L" + aryLineContent[1]; } else { labVIN.Text = strCarID; tmdal.DeleteOneTTempVIN(strCarID); MyBase.TraceWriteLine("在数据库表TTempSaveVIN中删除该VIN:" + strCarID); } } if (LineNum >= 19) { aryLineContent = strLine.Split(','); ConfigDfn.strMeasureTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); double dNormalValue = 0.0d; bool bToleranceValid = false; dt = tmdal.SelectOneToleranceByCondition("EHY", aryLineContent[0], aryLineContent[1]); if (dt.Rows.Count == 1) { dLowerValue = double.Parse(dt.Rows[0]["TolLower"].ToString()); dUpperValue = double.Parse(dt.Rows[0]["TolUpper"].ToString()); dNormalValue = (dLowerValue + dUpperValue) / 2; dStrictTLower = CalculateStrictLowerTolerance(dLowerValue, dUpperValue); dStrictTUpper = CalculateStrictUpperTolerance(dLowerValue, dUpperValue); dExcepitonTLower = CalculateExceptionLowerTolerance(dLowerValue, dUpperValue); dExceptionTUpper = CalculateExceptionUpperTolerance(dLowerValue, dUpperValue); bToleranceValid = true; } else { // 修复:公差未配置时显式重置异常公差,避免上一轮循环遗留值 // 同时不再用0作为默认公差(否则后续 dMeasureValue>=0||<=0 几乎恒真,会把所有实测值误判为ng3并清空) dStrictTLower = 0; dStrictTUpper = 0; dLowerValue = 0; dUpperValue = 0; dExcepitonTLower = 0; dExceptionTUpper = 0; MyBase.TraceWriteLine("EHY " + aryLineContent[0] + " " + aryLineContent[1] + " 查询数据获取公差带失败!数据库中数量不唯一或不存在,请检查公差带配置!原始测量值将保留并写入数据库,结果标记为noTol。"); } if (aryLineContent[2].ToLower().Contains("inv")) { aryLineContent[2] = ""; aryLineContent[4] = "ng2"; } else if (!bToleranceValid) { // 修复:公差缺失时保留原始测量值,标记为noTol,避免数据系统性丢失 MyBase.TraceWriteLine("EHY " + aryLineContent[0] + " " + aryLineContent[1] + " 公差未配置,保留原始测量值=" + aryLineContent[2] + ",结果标记为noTol。"); aryLineContent[4] = "noTol"; } else { dMeasureValue = double.Parse(aryLineContent[2]); if (dMeasureValue >= dLowerValue && dMeasureValue <= dUpperValue) { aryLineContent[4] = "good"; } else if (dMeasureValue >= dStrictTLower && dMeasureValue <= dStrictTUpper) { aryLineContent[4] = "ng1"; } else if (dMeasureValue >= dExceptionTUpper || dMeasureValue <= dExcepitonTLower) { // 修复:原先此处 aryLineContent[2] = "" 会把超差的实测值清空, // 导致客户CSV报告与XML汇总测出率系统性偏低,现仅打标ng3,保留原始测量值。 aryLineContent[4] = "ng3"; MyBase.TraceWriteLine("EHY " + aryLineContent[0] + " " + aryLineContent[1] + " 实测值=" + dMeasureValue.ToString("F2") + " 超出异常公差区间[" + dExcepitonTLower.ToString("F2") + "," + dExceptionTUpper.ToString("F2") + "],结果ng3,原值保留。"); } else { aryLineContent[4] = "ng2"; } } //测量数据存储到table里 dtCSVContent.Rows.Add(strCarID, "EHY", aryLineContent[0], aryLineContent[1], dNormalValue.ToString("F1"), dLowerValue.ToString("F1"), dUpperValue.ToString("F1"), aryLineContent[2], aryLineContent[4], DateTime.Now, ""); string strMeasureResult = aryLineContent[4].ToLower(); if (strMeasureResult.Contains("good") || strMeasureResult.Contains("best") || strMeasureResult.Contains("ng1")) { OKCount++; aryLineContent[4] = "OK"; } else if (strMeasureResult.Contains("ng2")) { OutCount++; aryLineContent[4] = "NG"; } else { // ng3 / noTol 等异常分支:原先此处 aryLineContent[2] = "" 也会清空实测值, // 现保留原始值用于追溯,仅清空结果列。 RejectedCount++; aryLineContent[4] = ""; } Invoke((MethodInvoker)(() => { dgvMeasureContent.Rows.Add(aryLineContent[0], aryLineContent[1], dNormalValue.ToString("F1"), dLowerValue.ToString("F1"), dUpperValue.ToString("F1"), aryLineContent[2], ConfigDfn.strMeasureTime, aryLineContent[4]); })); CheryIOTData cIOTData = new CheryIOTData(); cIOTData.vin = strCarID; cIOTData.gfNo = aryLineContent[1]; cIOTData.pointNumber = aryLineContent[0]; cIOTData.actualValue = aryLineContent[2]; cIOTData.controlLine = dLowerValue.ToString("F1") + @"/" + dUpperValue.ToString("F1"); if (strMeasureResult.Contains("good") || strMeasureResult.Contains("best") || strMeasureResult.Contains("ng1")) { cIOTData.measurementResult = "OK"; } else { cIOTData.measurementResult = "NG"; } ListPostIOTData.Add(cIOTData); dtRowCount++; Invoke((MethodInvoker)(() => { dgvMeasureContent.Rows[dtRowCount - 1].HeaderCell.Value = dtRowCount.ToString(); })); } }//End While sr.Close(); fs.Close(); // 数据完整性校验日志:统计本次解析后多少测点保留了原始测量值(修复Bug前ng3/noTol会被清空) int iEHYTotalRows = dtCSVContent.Rows.Count; int iEHYWithValue = 0; int iEHYEmptyValue = 0; int iEHYNoTolCount = 0; int iEHYNg3Count = 0; foreach (DataRow drCheck in dtCSVContent.Rows) { string sVal = drCheck["MeasureValue"]?.ToString() ?? ""; string sRes = (drCheck["MeasureItemResult"]?.ToString() ?? "").ToLower(); if (string.IsNullOrEmpty(sVal)) iEHYEmptyValue++; else iEHYWithValue++; if (sRes.Contains("notol")) iEHYNoTolCount++; if (sRes.Contains("ng3")) iEHYNg3Count++; } MyBase.TraceWriteLine($"[EHY完整性] 车号={strCarID} 测点总数={iEHYTotalRows} 有值={iEHYWithValue} 空值={iEHYEmptyValue} ng3={iEHYNg3Count} noTol={iEHYNoTolCount}"); tmdal.InsertTMeasureDatabyDataTable(dtCSVContent); MyBase.TraceWriteLine("解析EHY数据完成,并将所有测量数据插入到数据库完毕。"); MyBase.TraceWriteLine("解析NextSense EHY CSV 报告完毕!检查数量=" + dtRowCount.ToString()); if (dtRowCount <= ConfigDfn.iMeasureItemsCount) { iCurrentMeasureItemsFailedCount++; } else { iCurrentMeasureItemsFailedCount = 0; } if (iCurrentMeasureItemsFailedCount >= ConfigDfn.iFailedCarCount) { MyBase.TraceWriteLine("iCurrentMeasureItemsFailedCount=" + iCurrentMeasureItemsFailedCount.ToString() + "超过报警数量" + ConfigDfn.iFailedCarCount.ToString() + " ;给PLC发送报警10。"); PlcObject.InsertWriteQueue(PlcSignalDfn.MeasureError, (byte)10); } #endregion 解析EHY CSV报告 #region 计算极差 CalculateRange(strCarID, "EHY"); Thread.Sleep(20); DataTable dtAllRangeDate = tmdal.SelectRangeDatabyCarID(strCarID); if (dtAllRangeDate.Rows.Count > 0) { foreach (DataRow row in dtAllRangeDate.Rows) { if (ConfigDfn.iIncludeRangeFlag == 1) { if (row.ItemArray[5].ToString().Contains("OK")) { OKCount++; } else { OutCount++; } } Invoke((MethodInvoker)(() => { dgvMeasureContent.Rows.Add(row.ItemArray[2].ToString(), "G", "0", row.ItemArray[4].ToString().Substring(0, 3), row.ItemArray[4].ToString().Substring(4, 3), row.ItemArray[3].ToString(), ConfigDfn.strMeasureTime, row.ItemArray[5].ToString()); })); } } if (ConfigDfn.iIncludeRangeFlag == 1) { dtRowCount = dtRowCount + dtAllRangeDate.Rows.Count; for (int i = 1; i <= dtRowCount; i++) { Invoke((MethodInvoker)(() => { dgvMeasureContent.Rows[i - 1].HeaderCell.Value = i.ToString(); })); } MyBase.TraceWriteLine("计算合格率的时:包含极差计算项!"); } #endregion 计算极差 string strTargetRate = ""; Invoke((MethodInvoker)(() => { #region 界面显示功能 labCarType.Text = "EHY"; TMeasureResultModel tmrm = new TMeasureResultModel(); labNGCount.Text = OutCount.ToString(); labOKCount.Text = OKCount.ToString(); labRejectCount.Text = RejectedCount.ToString(); labMeaTime.Text = ConfigDfn.strMeasureTime; labSumMeasureCount.Text = dtRowCount.ToString(); FPYPercent = OKCount / (OKCount + OutCount); if (FPYPercent >= ConfigDfn.dFPY) { labResultPercent.Text = Math.Round(FPYPercent * 100.00d, 2).ToString("F2") + "%"; labResult.Text = "合格"; labResultPercent.ForeColor = Color.LimeGreen; labResult.ForeColor = Color.LimeGreen; pbResult.Image = Resources.OK; tmrm.Result = 1; PlcObject.InsertWriteQueue(PlcSignalDfn.CMMResult, (byte)10); } else if (FPYPercent >= ConfigDfn.dFPY2 && FPYPercent < ConfigDfn.dFPY) { labResultPercent.Text = Math.Round(FPYPercent * 100.00d, 2).ToString("F2") + "%"; labResult.Text = "合格"; labResultPercent.ForeColor = Color.Yellow; labResult.ForeColor = Color.Yellow; pbResult.Image = Resources.OK; tmrm.Result = 1; PlcObject.InsertWriteQueue(PlcSignalDfn.CMMResult, (byte)20); } else { labResultPercent.Text = Math.Round(FPYPercent * 100.00d, 2).ToString("F2") + "%"; labResult.Text = "不合格"; labResultPercent.ForeColor = Color.Red; labResult.ForeColor = Color.Red; pbResult.Image = Resources.NG; tmrm.Result = 2; PlcObject.InsertWriteQueue(PlcSignalDfn.CMMResult, (byte)30); } xValues[0] = "合格 : " + OKCount.ToString(); xValues[1] = "不合格 : " + OutCount.ToString(); xValues[2] = "异常 : " + RejectedCount.ToString(); yValues[0] = (int)OKCount; yValues[1] = (int)OutCount; yValues[2] = (int)RejectedCount; chartResultPie.Series[0].Points.DataBindXY(xValues, yValues); strTargetRate = Math.Round(ConfigDfn.dFPY2 * 100.00d, 2).ToString("F2") + "%"; tmrm.CarID = strCarID; tmrm.CarType = "EHY"; tmrm.SumMeasureItems = dtRowCount; tmrm.GoodMeasureItems = (int)OKCount; tmrm.NoGoodMeasureItems = (int)OutCount; tmrm.RejectMeasureItems = (int)RejectedCount; tmrm.FPY = FPYPercent.ToString("F4"); tmrm.Remark = ""; tmrm.MeasureDate = ConfigDfn.strMeasureTime; tmdal.InsertTMeasureResult(tmrm); MyBase.TraceWriteLine("将总结果插入数据库完毕。"); MyBase.TraceWriteLine("全部插入解析完毕,删除文件:" + fi.Name); fi.Delete(); dgvMeasureContent.Rows.Add(); dgvMeasureContent.Rows[dgvMeasureContent.Rows.Count - 1].Cells["MResult"].Value = (dtRowCount - OutCount - RejectedCount).ToString() + "/" + dtRowCount.ToString(); this.dgvMeasureContent.Rows[dgvMeasureContent.Rows.Count - 1].DefaultCellStyle.ForeColor = Color.White; if (dgvMeasureContent.Rows.Count > 0) { SetdgvRowBgColor(dgvMeasureContent); for (int i = 0; i < dgvMeasureContent.Rows.Count; i++) { //if (dgvMeasureContent.Rows[i].Cells["MResult"].Value.ToString().ToLower().Contains("ok")) //{ // dgvMeasureContent.Rows[i].DefaultCellStyle.BackColor = Color.Orange; //} if (dgvMeasureContent.Rows[i].Cells["MResult"].Value.ToString().ToLower().Contains("ng")) { dgvMeasureContent.Rows[i].DefaultCellStyle.BackColor = Color.Orange; } else if (string.IsNullOrEmpty(dgvMeasureContent.Rows[i].Cells["MResult"].Value.ToString())) { dgvMeasureContent.Rows[i].DefaultCellStyle.BackColor = Color.Red; } else { } } } #endregion 界面显示功能 })); if (ConfigDfn.iCreateReportFlag == 1) { GenUserReportCSV(strCarID, listCSVTitleInfo, dtAllRangeDate, FPYPercent); } else { MyBase.TraceWriteLine("iCreateReportFlag=0 : EHY数据生成报告功能未启用!"); } #region Update Data To IOT if (ConfigDfn.iStartIOTFlag == 1) { bool bVINMeasuedFlag = tmdal.CheckVINExistInDB(strCarID); if (bVINMeasuedFlag) { MyBase.TraceWriteLine("VIN:" + strCarID + " 该VIN码已经在数据库中存在了,说明已经测量过了,不再进行IOT数据上传操作。"); } else { // 上传 IOT功能 if (dtAllRangeDate.Rows.Count > 0) { foreach (DataRow row in dtAllRangeDate.Rows) { CheryIOTData cIOTData = new CheryIOTData(); cIOTData.vin = strCarID; cIOTData.gfNo = "G"; cIOTData.pointNumber = row.ItemArray[2].ToString(); cIOTData.actualValue = row.ItemArray[3].ToString(); cIOTData.controlLine = row.ItemArray[4].ToString(); cIOTData.measurementResult = row.ItemArray[5].ToString(); if (cIOTData.measurementResult.ToUpper().Contains("NG")) { if (!string.IsNullOrEmpty(cIOTData.actualValue) && !cIOTData.actualValue.ToLower().Contains("inv")) //避免为空的情况 { dLowerValue = double.Parse(row.ItemArray[4].ToString().Substring(0, 3)); dUpperValue = double.Parse(row.ItemArray[4].ToString().Substring(4, 3)); dStrictTLower = CalculateStrictLowerTolerance(dLowerValue, dUpperValue); dStrictTUpper = CalculateStrictUpperTolerance(dLowerValue, dUpperValue); double dValue = double.Parse(row.ItemArray[3].ToString()); if (dValue > dStrictTLower && dValue < dStrictTUpper) { cIOTData.measurementResult = "OK"; } } } ListPostIOTData.Add(cIOTData); } } string strGapList = JsonHelper.ObjectToJson(ListPostIOTData); string strCaliResult = "OK"; if (labResult.Text == "合格") { strCaliResult = "OK"; } else { strCaliResult = "NG"; } string strPostData = "{\"serno\":\"" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + "\",\"requestData\":[{\"vin\":\"" + strCarID + "\",\"model\":\"EHY\",\"equipmentNo\":\"" + ConfigDfn.strEquipNo + "\",\"equipmentName\":\"" + ConfigDfn.strEquipName + "\",\"calibrationResult\":\"" + strCaliResult + "\",\"detectionTime\":\"" + ConfigDfn.strMeasureTime + "\",\"targetRate\":\"" + strTargetRate + "\",\"rate\":\"" + labResultPercent.Text + "\",\"GapList\":" + strGapList + "}]}"; MyBase.TraceWriteLine("Update To IOT Data Content: " + strPostData); string strPostResult = PostJsonToIOT(ConfigDfn.strIOTAddress, strPostData, 10000); MyBase.TraceWriteLine("EHY数据上传IOT完成,结果返回为:" + strPostResult); if (strPostResult.Contains("成功")) { MyBase.TraceWriteLine("EHY数据上传IOT成功 ^_^"); tmdal.InsertIOTUploadLog(strCarID, strPostData, true, labResultPercent.Text); } else { MyBase.TraceWriteLine("EHY数据上传IOT失败!"); tmdal.InsertIOTUploadLog(strCarID, strPostData, false, labResultPercent.Text); } } } else { MyBase.TraceWriteLine("EHY数据上传IOT功能未启用!"); } #endregion Update Data To IOT } } } //else //{ // MyBase.TraceWriteLine("错误:AnalysisNextSenseEHYCSV 函数中,检测EHY CSV 路径不存在:" + ConfigDfn.strNextSenseCSVEHYPath); //} } catch (Exception ex) { MyBase.TraceWriteLine("AnalysisNextSenseEHYCSV 函数分析异常:" + ex.ToString()); } } private void AnalysisNextSenseEHVCSV() // 解析EHV 车型 { try { Invoke((MethodInvoker)(() => { lbCSVFiles.Items.Clear(); })); FileInfo[] fileInfos = null; if (Directory.Exists(ConfigDfn.strNextSenseCSVEHVPath)) { DirectoryInfo di = new DirectoryInfo(ConfigDfn.strNextSenseCSVEHVPath); fileInfos = di.GetFiles("*.CSV"); if (fileInfos.Count() >= 1) { MyBase.TraceWriteLine("存在EHV CSV文件,开始解析:"); List listCSVTitleInfo = new List(); string strCarID = ""; foreach (FileInfo fi in fileInfos) { listCSVTitleInfo.Clear(); ListPostIOTData.Clear(); dtCSVContent.Clear(); string strCSVName = fi.FullName; try { File.Copy(fi.FullName, ConfigDfn.strFileFolder + "\\NextSenseCSVBackup\\" + fi.Name, true); } catch (IOException ioEx) { MyBase.TraceWriteLine("EHV CSV文件被占用,跳过本次解析,等待下次轮询:" + fi.Name + " | " + ioEx.Message); Thread.Sleep(500); continue; } MyBase.TraceWriteLine("Copy " + fi.FullName + " TO " + ConfigDfn.strFileFolder + "\\NextSenseCSVBackup\\" + fi.Name + " Done. 备份完成"); Invoke((MethodInvoker)(() => { dgvMeasureContent.Rows.Clear(); lbCSVFiles.Items.Add(fi.Name); })); #region 解析EHV CSV报告 MyBase.TraceWriteLine("开始解析NextSense EHV CSV 报告:" + strCSVName); Encoding encoding = GetType(strCSVName); FileStream fs = new FileStream(strCSVName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); StreamReader sr = new StreamReader(fs, encoding); string strLine = ""; string[] aryLineContent = null; int LineNum = 0; int dtRowCount = 0; double OutCount = 0; double OKCount = 0; double RejectedCount = 0; double FPYPercent = 0; double dStrictTLower = 0; double dStrictTUpper = 0; double dLowerValue = 0; double dUpperValue = 0; double dExcepitonTLower = 0; double dExceptionTUpper = 0; double dMeasureValue = 0.0; DataTable dt = null; while ((strLine = sr.ReadLine()) != null) { LineNum++; if (LineNum >= 3 & LineNum <= 16) { listCSVTitleInfo.Add(strLine); } if (LineNum == 10) { aryLineContent = strLine.Split(','); MyBase.TraceWriteLine("解析出NextSense CSV中的VIN为:" + aryLineContent[1]); strCarID = tmdal.SelectVINByCSVVIN(aryLineContent[1]); MyBase.TraceWriteLine("通过CSV VIN从数据库中获取的完整VIN为:" + strCarID); if (strCarID.ToLower().Contains("nofind")) { MyBase.TraceWriteLine("数据库中没有查找到VIN码,NoFind, +L 使用CSV码"); strCarID = "L" + aryLineContent[1]; Invoke((MethodInvoker)(() => { labVIN.Text = strCarID; })); } else { Invoke((MethodInvoker)(() => { labVIN.Text = strCarID; })); tmdal.DeleteOneTTempVIN(strCarID); MyBase.TraceWriteLine("在数据库表TTempSaveVIN中删除该VIN:" + strCarID); } } if (LineNum >= 19) { aryLineContent = strLine.Split(','); ConfigDfn.strMeasureTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); double dNormalValue = 0.0d; bool bToleranceValid = false; dt = tmdal.SelectOneToleranceByCondition("EHV", aryLineContent[0], aryLineContent[1]); if (dt.Rows.Count == 1) { dLowerValue = double.Parse(dt.Rows[0]["TolLower"].ToString()); dUpperValue = double.Parse(dt.Rows[0]["TolUpper"].ToString()); dNormalValue = (dLowerValue + dUpperValue) / 2; dStrictTLower = CalculateStrictLowerTolerance(dLowerValue, dUpperValue); dStrictTUpper = CalculateStrictUpperTolerance(dLowerValue, dUpperValue); dExcepitonTLower = CalculateExceptionLowerTolerance(dLowerValue, dUpperValue); dExceptionTUpper = CalculateExceptionUpperTolerance(dLowerValue, dUpperValue); bToleranceValid = true; } else { // 修复:公差未配置时显式重置异常公差,避免上一轮循环遗留值 // 同时不再用0作为默认公差(否则后续 dMeasureValue>=0||<=0 几乎恒真,会把所有实测值误判为ng3并清空) dStrictTLower = 0; dStrictTUpper = 0; dLowerValue = 0; dUpperValue = 0; dExcepitonTLower = 0; dExceptionTUpper = 0; MyBase.TraceWriteLine("EHV " + aryLineContent[0] + " " + aryLineContent[1] + " 查询数据获取公差带失败!数据库中数量不唯一或不存在,请检查公差带配置!原始测量值将保留并写入数据库,结果标记为noTol。"); } if (aryLineContent[2].ToLower().Contains("inv")) { aryLineContent[2] = ""; aryLineContent[4] = "ng2"; } else if (!bToleranceValid) { // 修复:公差缺失时保留原始测量值,标记为noTol,避免数据系统性丢失 MyBase.TraceWriteLine("EHV " + aryLineContent[0] + " " + aryLineContent[1] + " 公差未配置,保留原始测量值=" + aryLineContent[2] + ",结果标记为noTol。"); aryLineContent[4] = "noTol"; } else { dMeasureValue = double.Parse(aryLineContent[2]); if (dMeasureValue >= dLowerValue && dMeasureValue <= dUpperValue) { aryLineContent[4] = "good"; } else if (dMeasureValue >= dStrictTLower && dMeasureValue <= dStrictTUpper) { aryLineContent[4] = "ng1"; } else if (dMeasureValue >= dExceptionTUpper || dMeasureValue <= dExcepitonTLower) { // 修复:原先此处 aryLineContent[2] = "" 会把超差的实测值清空, // 导致客户CSV报告与XML汇总测出率系统性偏低,现仅打标ng3,保留原始测量值。 aryLineContent[4] = "ng3"; MyBase.TraceWriteLine("EHV " + aryLineContent[0] + " " + aryLineContent[1] + " 实测值=" + dMeasureValue.ToString("F2") + " 超出异常公差区间[" + dExcepitonTLower.ToString("F2") + "," + dExceptionTUpper.ToString("F2") + "],结果ng3,原值保留。"); } else { aryLineContent[4] = "ng2"; } } dtCSVContent.Rows.Add(strCarID, "EHV", aryLineContent[0], aryLineContent[1], dNormalValue.ToString("F1"), dLowerValue.ToString("F1"), dUpperValue.ToString("F1"), aryLineContent[2], aryLineContent[4], DateTime.Now, ""); string strMeasureResult = aryLineContent[4].ToLower(); if (strMeasureResult.Contains("good") || strMeasureResult.Contains("best") || strMeasureResult.Contains("ng1")) { OKCount++; aryLineContent[4] = "OK"; } else if (strMeasureResult.Contains("ng2")) { OutCount++; aryLineContent[4] = "NG"; } else { // ng3 / noTol 等异常分支:原先此处 aryLineContent[2] = "" 也会清空实测值, // 现保留原始值用于追溯,仅清空结果列。 RejectedCount++; aryLineContent[4] = ""; } Invoke((MethodInvoker)(() => { dgvMeasureContent.Rows.Add(aryLineContent[0], aryLineContent[1], dNormalValue.ToString("F1"), dLowerValue.ToString("F1"), dUpperValue.ToString("F1"), aryLineContent[2], ConfigDfn.strMeasureTime, aryLineContent[4]); })); CheryIOTData cIOTData = new CheryIOTData(); cIOTData.vin = strCarID; cIOTData.gfNo = aryLineContent[1]; cIOTData.pointNumber = aryLineContent[0]; cIOTData.actualValue = aryLineContent[2]; cIOTData.controlLine = dLowerValue.ToString("F1") + @"/" + dUpperValue.ToString("F1"); if (strMeasureResult.Contains("good") || strMeasureResult.Contains("best") || strMeasureResult.Contains("ng1")) { cIOTData.measurementResult = "OK"; } else { cIOTData.measurementResult = "NG"; } ListPostIOTData.Add(cIOTData); dtRowCount++; Invoke((MethodInvoker)(() => { dgvMeasureContent.Rows[dtRowCount - 1].HeaderCell.Value = dtRowCount.ToString(); })); } }//End While sr.Close(); fs.Close(); // 数据完整性校验日志:统计本次解析后多少测点保留了原始测量值(修复Bug前ng3/noTol会被清空) int iEHVTotalRows = dtCSVContent.Rows.Count; int iEHVWithValue = 0; int iEHVEmptyValue = 0; int iEHVNoTolCount = 0; int iEHVNg3Count = 0; foreach (DataRow drCheck in dtCSVContent.Rows) { string sVal = drCheck["MeasureValue"]?.ToString() ?? ""; string sRes = (drCheck["MeasureItemResult"]?.ToString() ?? "").ToLower(); if (string.IsNullOrEmpty(sVal)) iEHVEmptyValue++; else iEHVWithValue++; if (sRes.Contains("notol")) iEHVNoTolCount++; if (sRes.Contains("ng3")) iEHVNg3Count++; } MyBase.TraceWriteLine($"[EHV完整性] 车号={strCarID} 测点总数={iEHVTotalRows} 有值={iEHVWithValue} 空值={iEHVEmptyValue} ng3={iEHVNg3Count} noTol={iEHVNoTolCount}"); tmdal.InsertTMeasureDatabyDataTable(dtCSVContent); MyBase.TraceWriteLine("解析EHV数据完成,并将所有测量数据插入到数据库完毕。"); MyBase.TraceWriteLine("解析NextSense EHV CSV 报告完毕!检测项数=" + dtRowCount.ToString()); if (dtRowCount <= ConfigDfn.iMeasureItemsCount) { iCurrentMeasureItemsFailedCount++; } else { iCurrentMeasureItemsFailedCount = 0; } if (iCurrentMeasureItemsFailedCount >= ConfigDfn.iFailedCarCount) { MyBase.TraceWriteLine("iCurrentMeasureItemsFailedCount=" + iCurrentMeasureItemsFailedCount.ToString() + "超过报警数量" + ConfigDfn.iFailedCarCount.ToString() + " ;给PLC发送报警10。"); PlcObject.InsertWriteQueue(PlcSignalDfn.MeasureError, (byte)10); } #endregion 解析EHV CSV报告 #region 计算极差 CalculateRange(strCarID, "EHV"); Thread.Sleep(20); DataTable dtAllRangeDate = tmdal.SelectRangeDatabyCarID(strCarID); if (dtAllRangeDate.Rows.Count > 0) { foreach (DataRow row in dtAllRangeDate.Rows) { if (ConfigDfn.iIncludeRangeFlag == 1) { if (row.ItemArray[5].ToString().Contains("OK")) { OKCount++; } else { OutCount++; } } Invoke((MethodInvoker)(() => { dgvMeasureContent.Rows.Add(row.ItemArray[2].ToString(), "G", "0", row.ItemArray[4].ToString().Substring(0, 3), row.ItemArray[4].ToString().Substring(4, 3), row.ItemArray[3].ToString(), ConfigDfn.strMeasureTime, row.ItemArray[5].ToString()); })); } } if (ConfigDfn.iIncludeRangeFlag == 1) { dtRowCount = dtRowCount + dtAllRangeDate.Rows.Count; for (int i = 1; i <= dtRowCount; i++) { Invoke((MethodInvoker)(() => { dgvMeasureContent.Rows[i - 1].HeaderCell.Value = i.ToString(); })); } MyBase.TraceWriteLine("计算合格率的时:包含极差计算项!"); } #endregion 计算极差 MyBase.TraceWriteLine($"[EHV] 准备更新UI:OKCount={OKCount}, OutCount={OutCount}, RejectedCount={RejectedCount}, dtRowCount={dtRowCount}, listCSVTitleInfo.Count={listCSVTitleInfo.Count}, dtCSVContent.Rows.Count={dtCSVContent.Rows.Count}"); string strTargetRate = ""; try { Invoke((MethodInvoker)(() => { #region 界面显示功能 labCarType.Text = "EHV"; TMeasureResultModel tmrm = new TMeasureResultModel(); labNGCount.Text = OutCount.ToString(); labOKCount.Text = OKCount.ToString(); labRejectCount.Text = RejectedCount.ToString(); labMeaTime.Text = ConfigDfn.strMeasureTime; labSumMeasureCount.Text = dtRowCount.ToString(); FPYPercent = OKCount / (OKCount + OutCount); if (FPYPercent >= ConfigDfn.dFPY) { labResultPercent.Text = Math.Round(FPYPercent * 100.00d, 2).ToString("F2") + "%"; labResult.Text = "合格"; labResultPercent.ForeColor = Color.LimeGreen; labResult.ForeColor = Color.LimeGreen; pbResult.Image = Resources.OK; tmrm.Result = 1; PlcObject.InsertWriteQueue(PlcSignalDfn.CMMResult, (byte)10); } else if (FPYPercent >= ConfigDfn.dFPY2 && FPYPercent < ConfigDfn.dFPY) { labResultPercent.Text = Math.Round(FPYPercent * 100.00d, 2).ToString("F2") + "%"; labResult.Text = "合格"; labResultPercent.ForeColor = Color.Yellow; labResult.ForeColor = Color.Yellow; pbResult.Image = Resources.OK; tmrm.Result = 1; PlcObject.InsertWriteQueue(PlcSignalDfn.CMMResult, (byte)20); } else { labResultPercent.Text = Math.Round(FPYPercent * 100.00d, 2).ToString("F2") + "%"; labResult.Text = "不合格"; labResultPercent.ForeColor = Color.Red; labResult.ForeColor = Color.Red; pbResult.Image = Resources.NG; tmrm.Result = 2; PlcObject.InsertWriteQueue(PlcSignalDfn.CMMResult, (byte)30); } xValues[0] = "合格 : " + OKCount.ToString(); xValues[1] = "不合格 : " + OutCount.ToString(); xValues[2] = "异常 : " + RejectedCount.ToString(); yValues[0] = (int)OKCount; yValues[1] = (int)OutCount; yValues[2] = (int)RejectedCount; chartResultPie.Series[0].Points.DataBindXY(xValues, yValues); strTargetRate = Math.Round(ConfigDfn.dFPY2 * 100.00d, 2).ToString("F2") + "%"; tmrm.CarID = strCarID; tmrm.CarType = "EHV"; tmrm.SumMeasureItems = dtRowCount; tmrm.GoodMeasureItems = (int)OKCount; tmrm.NoGoodMeasureItems = (int)OutCount; tmrm.RejectMeasureItems = (int)RejectedCount; tmrm.FPY = FPYPercent.ToString("F4"); tmrm.Remark = ""; tmrm.MeasureDate = ConfigDfn.strMeasureTime; tmdal.InsertTMeasureResult(tmrm); MyBase.TraceWriteLine("将EHV总结果插入数据库完毕。"); MyBase.TraceWriteLine("全部插入解析完毕,删除文件:" + fi.Name); fi.Delete(); dgvMeasureContent.Rows.Add(); dgvMeasureContent.Rows[dgvMeasureContent.Rows.Count - 1].Cells["MResult"].Value = (dtRowCount - OutCount - RejectedCount).ToString() + "/" + dtRowCount.ToString(); this.dgvMeasureContent.Rows[dgvMeasureContent.Rows.Count - 1].DefaultCellStyle.ForeColor = Color.White; if (dgvMeasureContent.Rows.Count > 0) { SetdgvRowBgColor(dgvMeasureContent); for (int i = 0; i < dgvMeasureContent.Rows.Count; i++) { if (dgvMeasureContent.Rows[i].Cells["MResult"].Value.ToString().ToLower().Contains("ng")) { dgvMeasureContent.Rows[i].DefaultCellStyle.BackColor = Color.Orange; } else if (string.IsNullOrEmpty(dgvMeasureContent.Rows[i].Cells["MResult"].Value.ToString())) { dgvMeasureContent.Rows[i].DefaultCellStyle.BackColor = Color.Red; } } } #endregion 界面显示功能 })); } catch (Exception exInvoke) { MyBase.TraceWriteLine("[EHV] Invoke UI更新异常:" + exInvoke.Message + " | StackTrace: " + exInvoke.StackTrace); } MyBase.TraceWriteLine($"[EHV] iCreateReportFlag={ConfigDfn.iCreateReportFlag}, strSaveReprotPath={strSaveReprotPath}, listCSVTitleInfo.Count={listCSVTitleInfo.Count}, dtAllRangeDate.Rows.Count={dtAllRangeDate.Rows.Count}, FPYPercent={FPYPercent}"); if (ConfigDfn.iCreateReportFlag == 1) { MyBase.TraceWriteLine("[EHV] 开始调用 GenUserReportCSV..."); GenUserReportCSV(strCarID, listCSVTitleInfo, dtAllRangeDate, FPYPercent); MyBase.TraceWriteLine("[EHV] GenUserReportCSV 调用完毕。"); } else { MyBase.TraceWriteLine("EHV数据生成报告功能未启用!"); } #region Update Data To IOT if (ConfigDfn.iStartIOTFlag == 1) { bool bVINMeasuedFlag = tmdal.CheckVINExistInDB(strCarID); if (bVINMeasuedFlag) { MyBase.TraceWriteLine("VIN:" + strCarID + " 该VIN码已经在数据库中存在了,说明已经测量过了,不再进行IOT数据上传操作。"); } else { if (dtAllRangeDate.Rows.Count > 0) { foreach (DataRow row in dtAllRangeDate.Rows) { CheryIOTData cIOTData = new CheryIOTData(); cIOTData.vin = strCarID; cIOTData.gfNo = "G"; cIOTData.pointNumber = row.ItemArray[2].ToString(); cIOTData.actualValue = row.ItemArray[3].ToString(); cIOTData.controlLine = row.ItemArray[4].ToString(); cIOTData.measurementResult = row.ItemArray[5].ToString(); if (cIOTData.measurementResult.ToUpper().Contains("NG")) { if (!string.IsNullOrEmpty(cIOTData.actualValue) && !cIOTData.actualValue.ToLower().Contains("inv")) { dLowerValue = double.Parse(row.ItemArray[4].ToString().Substring(0, 3)); dUpperValue = double.Parse(row.ItemArray[4].ToString().Substring(4, 3)); dStrictTLower = CalculateStrictLowerTolerance(dLowerValue, dUpperValue); dStrictTUpper = CalculateStrictUpperTolerance(dLowerValue, dUpperValue); double dValue = double.Parse(row.ItemArray[3].ToString()); if (dValue > dStrictTLower && dValue < dStrictTUpper) { cIOTData.measurementResult = "OK"; } } } ListPostIOTData.Add(cIOTData); } } string strGapList = JsonHelper.ObjectToJson(ListPostIOTData); string strCaliResult = labResult.Text == "合格" ? "OK" : "NG"; string strPostData = "{\"serno\":\"" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + "\",\"requestData\":[{\"vin\":\"" + strCarID + "\",\"model\":\"EHV\",\"equipmentNo\":\"" + ConfigDfn.strEquipNo + "\",\"equipmentName\":\"" + ConfigDfn.strEquipName + "\",\"calibrationResult\":\"" + strCaliResult + "\",\"detectionTime\":\"" + ConfigDfn.strMeasureTime + "\",\"targetRate\":\"" + strTargetRate + "\",\"rate\":\"" + labResultPercent.Text + "\",\"GapList\":" + strGapList + "}]}"; MyBase.TraceWriteLine("Update To IOT Data Content: " + strPostData); string strPostResult = PostJsonToIOT(ConfigDfn.strIOTAddress, strPostData, 10000); MyBase.TraceWriteLine("EHV数据上传IOT完成,结果返回为:" + strPostResult); if (strPostResult.Contains("成功")) { MyBase.TraceWriteLine("EHV数据上传IOT成功 ^_^"); tmdal.InsertIOTUploadLog(strCarID, strPostData, true, labResultPercent.Text); } else { MyBase.TraceWriteLine("EHV数据上传IOT失败!"); tmdal.InsertIOTUploadLog(strCarID, strPostData, false, labResultPercent.Text); } } } else { MyBase.TraceWriteLine("EHV数据上传IOT功能未启用!"); } #endregion Update Data To IOT } } } } catch (Exception ex) { MyBase.TraceWriteLine("AnalysisNextSenseEHVCSV 函数分析异常:" + ex.ToString()); } } private void AnalysisNextSenseSelfMeasureCSV() { try { Invoke((MethodInvoker)(() => { lbCSVFiles.Items.Clear(); })); FileInfo[] fileInfos = null; if (Directory.Exists(ConfigDfn.strNextSenseSelfMeasurePath)) { DirectoryInfo di = new DirectoryInfo(ConfigDfn.strNextSenseSelfMeasurePath); fileInfos = di.GetFiles("*.CSV"); if (fileInfos.Count() >= 1) { MyBase.TraceWriteLine("存在NS 自检报告 CSV文件,开始解析:"); List listCSVTitleInfo = new List(); string strCarID = "SelfMeasure" + DateTime.Now.ToString("yyyyMMddHHmmss"); foreach (FileInfo fi in fileInfos) { listCSVTitleInfo.Clear(); ListPostIOTData.Clear(); dtCSVContent.Clear(); string strCSVName = fi.FullName; File.Copy(fi.FullName, ConfigDfn.strFileFolder + "\\NextSenseCSVBackup\\" + fi.Name, true); MyBase.TraceWriteLine("Copy " + fi.FullName + " TO " + ConfigDfn.strFileFolder + "\\NextSenseCSVBackup\\" + fi.Name + " Done. 备份完成"); Invoke((MethodInvoker)(() => { dgvMeasureContent.Rows.Clear(); lbCSVFiles.Items.Add(fi.Name); })); #region 解析NextSense自检CSV报告 MyBase.TraceWriteLine("开始解析NextSense 自检报告 CSV 报告:" + strCSVName); Encoding encoding = GetType(strCSVName); FileStream fs = new FileStream(strCSVName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); StreamReader sr = new StreamReader(fs, encoding); //记录每次读取的一行记录 string strLine = ""; //记录每行记录中的各字段内容 string[] aryLineContent = null; //逐行读取CSV中的数据 int LineNum = 0; //表格行数 int dtRowCount = 0; while ((strLine = sr.ReadLine()) != null) { LineNum++; if (LineNum >= 1 & LineNum <= 17) { listCSVTitleInfo.Add(strLine); } if (LineNum >= 19) { aryLineContent = strLine.Split(','); ConfigDfn.strMeasureTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); if (aryLineContent[2].ToLower().Contains("inv")) { aryLineContent[2] = ""; //当为inv ,内容为空 aryLineContent[10] = "NG"; } string strMeasPointName = ""; if (aryLineContent[0].ToUpper().Contains("L")) { strMeasPointName = "L-ZJ1"; } else { strMeasPointName = "R-ZJ1"; } //测量数据存储到table里 dtCSVContent.Rows.Add(strCarID, "SelfMeasure", strMeasPointName, aryLineContent[1], aryLineContent[4], aryLineContent[8], aryLineContent[9], aryLineContent[2], aryLineContent[10], DateTime.Now, ""); Invoke((MethodInvoker)(() => { dgvMeasureContent.Rows.Add(strMeasPointName, aryLineContent[1], aryLineContent[4], aryLineContent[8], aryLineContent[9], aryLineContent[2], ConfigDfn.strMeasureTime, aryLineContent[10]); dtRowCount++; dgvMeasureContent.Rows[dtRowCount - 1].HeaderCell.Value = dtRowCount.ToString(); })); } }//End While sr.Close(); fs.Close(); MyBase.TraceWriteLine("解析NextSense 自检报告完毕!检查数量=" + dtRowCount.ToString()); Invoke((MethodInvoker)(() => { labCarType.Text = "自检报告"; })); fi.Delete(); #endregion 解析NextSense自检CSV报告 if (ConfigDfn.iCreateReportFlag == 1) { #region 解析完报告后,重新生成客户模板报告 MyBase.TraceWriteLine("开始生成客户所需要的CSV格式文件:"); string targetFilePath = strSaveReprotPath + DateTime.Now.ToString("yyyyMMddHHmmss") + "_" + strCarID + ".csv"; //wsp 后期还要再改 // 创建临时路径,为应用程序目录\ReportBackup 路径下 string backupDirectoryPath = Application.StartupPath + "\\ReportBackup"; if (!Directory.Exists(backupDirectoryPath)) { Directory.CreateDirectory(backupDirectoryPath); //日志 MyBase.TraceWriteLine("创建ReportBackup文件夹完毕,路径为:" + backupDirectoryPath); } // 构造备份文件路径,\\" + DateTime.Now.ToString("yyyyMMddHHmmss") + "_" + // strCarID + ".csv" string backupFilePath = backupDirectoryPath + "\\" + DateTime.Now.ToString("yyyyMMddHHmmss") + "_" + strCarID + ".csv"; // 记录备份文件路径 MyBase.TraceWriteLine("客户自检报告备份路径为:" + backupFilePath); StringBuilder sb = new StringBuilder(); //添加表头 sb.Append("Measurement Info Name"); sb.Append(","); sb.Append("Measurement Info"); sb.AppendLine(); sb.Append("Date_Time"); sb.Append(","); sb.Append(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")); sb.AppendLine(); for (int i = 2; i < listCSVTitleInfo.Count - 1; i++) { if (listCSVTitleInfo[i].Contains("prodnum")) { listCSVTitleInfo[i] = listCSVTitleInfo[i].Replace("prodnum,", "Part_ident," + DateTime.Now.ToString("yyyyMMdd")); } sb.Append(listCSVTitleInfo[i]); sb.AppendLine(); } sb.AppendLine(); sb.AppendLine(); sb.AppendLine(); sb.AppendLine(); sb.AppendLine(); //添加测量数据 sb.Append("Characteristic"); sb.Append(","); sb.Append("Extension"); sb.Append(","); sb.Append("Measured_Value"); sb.AppendLine(); foreach (DataRow row in dtCSVContent.Rows) { sb.Append(row.ItemArray[2]); sb.Append(","); sb.Append(row.ItemArray[3]); sb.Append(","); sb.Append(row.ItemArray[7]); sb.AppendLine(); } sb.AppendLine(); // 将数据写入CSV文件 File.WriteAllText(backupFilePath, sb.ToString()); MyBase.TraceWriteLine("客户自检报告生成完毕,备份路径为:" + targetFilePath); // 尝试进行复制到 目标路径 往目标路径copy该文件,并记录是否成功 try { File.Copy(backupFilePath, targetFilePath, true); // 记录上传情况 bool isUploaded = true; // 记录输入情况 strCarID、目标路径、备份路径、是否上传成功 MyBase.TraceWriteLine($"车号: {strCarID} | 目标路径: {targetFilePath} | 备份路径: {backupDirectoryPath} | 上传成功: {isUploaded}"); tmdal.InsertCsvReportUploadLog(strCarID, targetFilePath, backupDirectoryPath, isUploaded); } catch (Exception ex) { MyBase.TraceWriteLine("客户自检报告复制异常:" + ex.Message); // 记录上传情况 bool isUploaded = false; MyBase.TraceWriteLine($"车号: {strCarID} | 目标路径: {targetFilePath} | 备份路径: {backupDirectoryPath} | 上传成功: {isUploaded}"); tmdal.InsertCsvReportUploadLog(strCarID, targetFilePath, backupDirectoryPath, isUploaded); } #endregion 解析完报告后,重新生成客户模板报告 } else { MyBase.TraceWriteLine("iCreateReportFlag=0 : 数据生成报告功能未启用!"); } } } } } catch (Exception ex) { MyBase.TraceWriteLine("AnalysisNextSenseSelfMeasureCSV 函数分析异常:" + ex.ToString()); } } public void GenUserReportCSV(string strCarID, List listCSVTitleInfo, DataTable dtAllRangeDate, double FPYPercent) { #region 解析完报告后,重新生成客户模板报告 MyBase.TraceWriteLine($"[GenUserReportCSV] 进入函数:strCarID={strCarID}, listCSVTitleInfo.Count={listCSVTitleInfo.Count}, dtAllRangeDate.Rows.Count={dtAllRangeDate.Rows.Count}, FPYPercent={FPYPercent}, dtCSVContent.Rows.Count={dtCSVContent.Rows.Count}"); MyBase.TraceWriteLine($"[GenUserReportCSV] strSaveReprotPath={strSaveReprotPath}"); // 目的路径 string targetFilePath = strSaveReprotPath + DateTime.Now.ToString("yyyyMMddHHmmss") + "_" + strCarID + ".csv"; //wsp 后期还要再改 // 新建一个备份路径,应用程序根目录\ReportBackup string backupFolderPath = Application.StartupPath + "\\ReportBackup"; if (!Directory.Exists(backupFolderPath)) { Directory.CreateDirectory(backupFolderPath); //日志 MyBase.TraceWriteLine("创建ReportBackup文件夹完毕,路径为:" + backupFolderPath); } // 构造备份文件路径,\\" + DateTime.Now.ToString("yyyyMMddHHmmss") + "_" + strCarID + ".csv" string backupFilePath = backupFolderPath + "\\" + DateTime.Now.ToString("yyyyMMddHHmmss") + "_" + strCarID + ".csv"; // 记录备份文件路径 MyBase.TraceWriteLine("客户自检报告备份路径为:" + backupFilePath); string strWithoutLCarVin = strCarID.Substring(1); StringBuilder sb = new StringBuilder(); //添加表头 sb.Append("Measurement Info Name"); sb.Append(","); sb.Append("Measurement Info"); sb.AppendLine(); sb.Append("Date_Time"); sb.Append(","); sb.Append(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")); sb.AppendLine(); for (int i = 0; i < listCSVTitleInfo.Count; i++) { if (listCSVTitleInfo[i].Contains("prodnum")) { listCSVTitleInfo[i] = listCSVTitleInfo[i].Replace("prodnum", "Part_ident"); } if (listCSVTitleInfo[i].Contains(strWithoutLCarVin)) { listCSVTitleInfo[i] = listCSVTitleInfo[i].Replace(strWithoutLCarVin, strCarID); } sb.Append(listCSVTitleInfo[i]); sb.AppendLine(); } sb.AppendLine(); sb.AppendLine(); sb.AppendLine(); sb.AppendLine(); sb.AppendLine(); //添加测量数据 sb.Append("Characteristic"); sb.Append(","); sb.Append("Extension"); sb.Append(","); sb.Append("Measured_Value"); sb.AppendLine(); int iReportTotal = 0; int iReportEmpty = 0; foreach (DataRow row in dtCSVContent.Rows) { sb.Append(row.ItemArray[2]); sb.Append(","); sb.Append(row.ItemArray[3]); sb.Append(","); sb.Append(row.ItemArray[7]); sb.AppendLine(); iReportTotal++; if (string.IsNullOrEmpty(row.ItemArray[7]?.ToString())) iReportEmpty++; } MyBase.TraceWriteLine($"[GenUserReportCSV] 客户报告测量行总数={iReportTotal} 其中Measured_Value为空的行数={iReportEmpty} (空值率={(iReportTotal == 0 ? 0 : iReportEmpty * 100.0 / iReportTotal):F1}%)"); if (dtAllRangeDate.Rows.Count > 0) { foreach (DataRow row in dtAllRangeDate.Rows) { sb.Append(row.ItemArray[2]); sb.Append(","); sb.Append("G"); sb.Append(","); sb.Append(row.ItemArray[3]); sb.AppendLine(); } } sb.Append("POP"); sb.Append(","); sb.Append("P"); sb.Append(","); sb.Append(Math.Round(FPYPercent * 100.00d, 2).ToString("F2")); sb.AppendLine(); // 将数据写入CSV文件 File.WriteAllText(backupFilePath, sb.ToString()); // 记录日志,说明备份成功 MyBase.TraceWriteLine("客户 csv报告备份完毕,路径为:" + backupFilePath); // 往目标路径copy该文件,并记录是否成功 try { if (!Directory.Exists(strSaveReprotPath)) { Directory.CreateDirectory(strSaveReprotPath); MyBase.TraceWriteLine("[GenUserReportCSV] 目标目录不存在,已创建:" + strSaveReprotPath); } File.Copy(backupFilePath, targetFilePath, true); // 记录上传情况 bool isUploaded = true; // 记录输入情况 strCarID、目标路径、备份路径、是否上传成功 MyBase.TraceWriteLine($"车号: {strCarID} | 目标路径: {targetFilePath} | 备份路径: {backupFilePath} | 上传成功: {isUploaded}"); tmdal.InsertCsvReportUploadLog(strCarID, targetFilePath, backupFolderPath, isUploaded); } catch (Exception ex) { MyBase.TraceWriteLine("客户csv报告复制异常:" + ex.Message); // 记录上传情况 bool isUploaded = false; MyBase.TraceWriteLine($"车号: {strCarID} | 目标路径: {targetFilePath} | 备份路径: {backupFilePath} | 上传成功: {isUploaded}"); tmdal.InsertCsvReportUploadLog(strCarID, targetFilePath, backupFolderPath, isUploaded); } #endregion 解析完报告后,重新生成客户模板报告 } private void UploadIOTData(string strCarID, DataTable dtAllRangeDate, string strTargetRate) { double dStrictTLower = 0; double dStrictTUpper = 0; double dLowerValue = 0; double dUpperValue = 0; bool bVINMeasuedFlag = tmdal.CheckVINExistInDB(strCarID); if (bVINMeasuedFlag) { MyBase.TraceWriteLine("VIN:" + strCarID + " 该VIN码已经在数据库中存在了,说明已经测量过了,不再进行IOT数据上传操作。"); } else { // 上传 IOT功能 if (dtAllRangeDate.Rows.Count > 0) { foreach (DataRow row in dtAllRangeDate.Rows) { CheryIOTData cIOTData = new CheryIOTData(); cIOTData.vin = strCarID; cIOTData.gfNo = "G"; cIOTData.pointNumber = row.ItemArray[2].ToString(); cIOTData.actualValue = row.ItemArray[3].ToString(); cIOTData.controlLine = row.ItemArray[4].ToString(); cIOTData.measurementResult = row.ItemArray[5].ToString(); if (cIOTData.measurementResult.ToUpper().Contains("NG")) { if (!string.IsNullOrEmpty(cIOTData.actualValue) && !cIOTData.actualValue.ToLower().Contains("inv")) // 2025.08.27 修复NG数据实际值为空时,上传IOT报错问题 { dLowerValue = double.Parse(row.ItemArray[4].ToString().Substring(0, 3)); dUpperValue = double.Parse(row.ItemArray[4].ToString().Substring(4, 3)); dStrictTLower = CalculateStrictLowerTolerance(dLowerValue, dUpperValue); dStrictTUpper = CalculateStrictUpperTolerance(dLowerValue, dUpperValue); double dValue = double.Parse(row.ItemArray[3].ToString()); if (dValue > dStrictTLower && dValue < dStrictTUpper) { cIOTData.measurementResult = "OK"; } } } ListPostIOTData.Add(cIOTData); } } string strGapList = JsonHelper.ObjectToJson(ListPostIOTData); string strCaliResult = "OK"; if (labResult.Text == "合格") { strCaliResult = "OK"; } else { strCaliResult = "NG"; } string strPostData = "{\"serno\":\"" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + "\",\"requestData\":[{\"vin\":\"" + strCarID + "\",\"model\":\"EHY\",\"equipmentNo\":\"" + ConfigDfn.strEquipNo + "\",\"equipmentName\":\"" + ConfigDfn.strEquipName + "\",\"calibrationResult\":\"" + strCaliResult + "\",\"detectionTime\":\"" + ConfigDfn.strMeasureTime + "\",\"targetRate\":\"" + strTargetRate + "\",\"rate\":\"" + labResultPercent.Text + "\",\"GapList\":" + strGapList + "}]}"; MyBase.TraceWriteLine("Update To IOT Data Content: " + strPostData); string strPostResult = PostJsonToIOT(ConfigDfn.strIOTAddress, strPostData, 10000); MyBase.TraceWriteLine("EHY数据上传IOT完成,结果返回为:" + strPostResult); if (strPostResult.Contains("成功")) { MyBase.TraceWriteLine("EHY数据上传IOT成功 ^_^"); } else { MyBase.TraceWriteLine("EHY数据上传IOT失败!"); } } } private void CalculateRange(string strVIN, string strCarType) { MyBase.TraceWriteLine(strVIN + " " + strCarType + "开始计算极差:============"); tmdal.DeleteRangeData(strVIN); dtRangeData.Clear(); DataTable dtRange = tmdal.SelectRangeByCarType(strCarType); if (dtRange != null && dtRange.Rows.Count > 0) { string strRangeValue = ""; string strRangeLowUpp = ""; string strRangeResult = ""; DateTime dtTime = DateTime.Now; string strRemark = ""; for (int i = 0; i < dtRange.Rows.Count; i++) { string[] strArrRangePoint = dtRange.Rows[i]["RangePoint"].ToString().Split(','); double[] dMeasureData = new double[strArrRangePoint.Length]; int iCalcCount = 0; for (int j = 0; j < strArrRangePoint.Length; j++) { string strMeasureValue = tmdal.SelectOneMeasureValueByCondition(strVIN, strArrRangePoint[j].Substring(0, 4)); if (string.IsNullOrEmpty(strMeasureValue) || strMeasureValue.ToLower().Contains("inv")) { strRangeValue = ""; strRangeResult = "NG"; MyBase.TraceWriteLine(strArrRangePoint[j] + " G 查询的测量值为inv"); break; } else if (strMeasureValue.ToLower().Contains("nofind")) { strRangeValue = ""; strRangeResult = "NG"; MyBase.TraceWriteLine(strArrRangePoint[j] + " G 查询的测量值为no find"); break; } else { dMeasureData[j] = Convert.ToDouble(strMeasureValue); iCalcCount++; } } //iCalcCount 的作用就是确保只有全部测点都有效时才计算极差,否则提前退出。 if (iCalcCount == strArrRangePoint.Length) { double dMax = dMeasureData.Max(); double dMin = dMeasureData.Min(); double dRangeData = dMax - dMin; strRangeValue = dRangeData.ToString("F1"); if (dRangeData >= Convert.ToDouble(dtRange.Rows[i]["RangeLower"]) && dRangeData <= Convert.ToDouble(dtRange.Rows[i]["RangeUpper"])) { strRangeResult = "OK"; } else { strRangeResult = "NG"; } } strRangeLowUpp = dtRange.Rows[i]["RangeLower"].ToString() + @"/" + dtRange.Rows[i]["RangeUpper"].ToString(); dtRangeData.Rows.Add(strVIN, dtRange.Rows[i]["RangeName"].ToString(), strRangeValue, strRangeLowUpp, strRangeResult, dtTime, strRemark); } tmdal.InsertTRangeDatabyDataTable(dtRangeData); MyBase.TraceWriteLine(strVIN + " " + strCarType + "计算极差完成,并插入数据库:============"); } } public string PostJsonToIOT(string url, string jsonData, int? timeout = null) { try { HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url); if (null != timeout && 0 != timeout) { req.Timeout = timeout.Value; } Encoding encoding = Encoding.UTF8; byte[] bs = Encoding.UTF8.GetBytes(jsonData); string responseData; req.Method = "POST"; req.ContentType = "application/json"; req.ContentLength = bs.Length; using (Stream reqStream = req.GetRequestStream()) { reqStream.Write(bs, 0, bs.Length); reqStream.Close(); } using (HttpWebResponse response = (HttpWebResponse)req.GetResponse()) { using (StreamReader reader = new StreamReader(response.GetResponseStream(), encoding)) { responseData = reader.ReadToEnd(); } } return responseData; } catch (Exception ex) { return "Error: " + ex.ToString(); } } /// 通过给定的文件流,判断文件的编码类型 /// 文件流 /// 文件的编码类型 public static Encoding GetType(FileStream fs) { byte[] Unicode = new byte[] { 0xFF, 0xFE, 0x41 }; byte[] UnicodeBIG = new byte[] { 0xFE, 0xFF, 0x00 }; byte[] UTF8 = new byte[] { 0xEF, 0xBB, 0xBF }; //带BOM System.Text.Encoding reVal = System.Text.Encoding.Default; System.IO.BinaryReader r = new System.IO.BinaryReader(fs, System.Text.Encoding.Default); int i; int.TryParse(fs.Length.ToString(), out i); byte[] ss = r.ReadBytes(i); if (IsUTF8Bytes(ss) || (ss[0] == 0xEF && ss[1] == 0xBB && ss[2] == 0xBF)) { reVal = System.Text.Encoding.UTF8; } else if (ss[0] == 0xFE && ss[1] == 0xFF && ss[2] == 0x00) { reVal = System.Text.Encoding.BigEndianUnicode; } else if (ss[0] == 0xFF && ss[1] == 0xFE && ss[2] == 0x41) { reVal = System.Text.Encoding.Unicode; } r.Close(); return reVal; } /// 判断是否是不带 BOM 的 UTF8 格式 /// /// private static bool IsUTF8Bytes(byte[] data) { int charByteCounter = 1; //计算当前正分析的字符应还有的字节数 byte curByte; //当前分析的字节. for (int i = 0; i < data.Length; i++) { curByte = data[i]; if (charByteCounter == 1) { if (curByte >= 0x80) { //判断当前 while (((curByte <<= 1) & 0x80) != 0) { charByteCounter++; } //标记位首位若为非0 则至少以2个1开始 如:110XXXXX...........1111110X  if (charByteCounter == 1 || charByteCounter > 6) { return false; } } } else { //若是UTF-8 此时第一位必须为1 if ((curByte & 0xC0) != 0x80) { return false; } charByteCounter--; } } if (charByteCounter > 1) { throw new Exception("非预期的byte格式"); } return true; } public Encoding GetType(string FileName) { FileStream fs = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); Encoding er = GetType(fs); fs.Close(); return er; } private void testIotUpload() { // 修复极差 计算问题 //LNNBBDEC7SDF49695 //string strVIN = "LNNBBDEC5SDF49694"; // string strCarType = "EHY"; //CalculateRange(strVIN, strCarType); //修复IOt上传问题 string strCarID = "LNNBDDEF4SDF49707"; DataTable dtAllRangeDate = tmdal.SelectRangeDatabyCarID(strCarID); string strTargetRate = "97.00%"; UploadIOTData(strCarID, dtAllRangeDate, strTargetRate); } #endregion 解析Nextsense CSV文件功能 #region Home Page /// /// 设置DataGridView各行变色 /// /// DataGridView public void SetdgvRowBgColor(DataGridView dgv) { if (dgv.Rows.Count > 0) { foreach (DataGridViewRow item in dgv.Rows) { if (item.Index % 2 == 0) { item.DefaultCellStyle.BackColor = Color.FromArgb(19, 46, 53); } else { item.DefaultCellStyle.BackColor = Color.FromArgb(27, 60, 68); } } } } //TODO: #endregion Home Page #region Search Data #region datagridview分页功能 /// /// LoadPage方法 /// private void LoadPage() { if (currentPage < 1) currentPage = 1; if (currentPage > pageCount) currentPage = pageCount; int beginRecord; //开始指针 int endRecord; //结束指针 DataTable dtTemp; dtTemp = PageTable.Clone();//Clone方法只会复制DataTable的结构(列定义),而不会复制数据行的引用。 beginRecord = pageSize * (currentPage - 1); if (currentPage == 1) beginRecord = 0; endRecord = pageSize * currentPage; if (currentPage == pageCount) endRecord = recordCount; for (int i = beginRecord; i < endRecord; i++) { // 使用ImportRow方法将源PageTable的行导入到目标dtTemp dtTemp.ImportRow(PageTable.Rows[i]); } dgvSelectMeasureData.Rows.Clear(); for (int i = 0; i < dtTemp.Rows.Count; i++) { dgvSelectMeasureData.Rows.Add(new object[] { dtTemp.Rows[i][0], dtTemp.Rows[i][1], dtTemp.Rows[i][2], dtTemp.Rows[i][3], dtTemp.Rows[i][4], dtTemp.Rows[i][5], dtTemp.Rows[i][6], dtTemp.Rows[i][7], dtTemp.Rows[i][8] }); } SetdgvRowBgColor(dgvSelectMeasureData); for (int i = 0; i < dgvSelectMeasureData.Rows.Count; i++) { string strResult = dgvSelectMeasureData.Rows[i].Cells["MeasureItemResult"].Value.ToString(); if (strResult.ToLower().Contains("ng")) { //dgvSelectMeasureData.Rows[i].Cells["MeasureItemResult"].Style.ForeColor = Color.Orange; dgvSelectMeasureData.Rows[i].DefaultCellStyle.BackColor = Color.Orange; } if (strResult.ToLower().Contains("rej")) { dgvSelectMeasureData.Rows[i].Cells["MeasureItemResult"].Style.ForeColor = Color.Red; } } labCurrentPage.Text = "当前页:" + currentPage.ToString(); //当前页 labSumPages.Text = "共 " + pageCount.ToString() + " 页";//总页数 labSumRecorders.Text = "总共 " + recordCount.ToString() + " 条记录";//总记录数 } private void rbtnFirtstPage_Click(object sender, EventArgs e) { if (currentPage == 1) { return; } currentPage = 1; LoadPage(); } private void rbtnPrevPage_Click(object sender, EventArgs e) { if (currentPage == 1) { return; } currentPage--; LoadPage(); } private void rbtnNextPage_Click(object sender, EventArgs e) { if (currentPage == pageCount) { return; } currentPage++; LoadPage(); } private void rbtnLastPage_Click(object sender, EventArgs e) { if (currentPage == pageCount) { return; } currentPage = pageCount; LoadPage(); } private void rddlPageRecorderCount_SelectedIndexChanged(object sender, Telerik.WinControls.UI.Data.PositionChangedEventArgs e) { pageSize = int.Parse(rddlPageRecorderCount.Text.Trim()); //PageSorter(); } #endregion datagridview分页功能 private void rbtnSearchMeaserData_Click(object sender, EventArgs e) { dgvFPYResult.Visible = false; chartFPYLine.Visible = false; rbtnExportCSVReport.Visible = false; string strStartTime = rdtpStartTime.Value.ToString("yyyy-MM-dd") + " 00:00:00"; string strEndTime = rdtpEndTime.Value.ToString("yyyy-MM-dd") + " 23:59:59"; string strCarID = rtbPartID.Text.Trim(); PageTable.Clear(); PageTable = tmdal.SelectTMeasureDataByCarIDAndTime(strCarID, strStartTime, strEndTime); if (PageTable.Rows.Count > 0) { recordCount = PageTable.Rows.Count; //记录总行数 pageCount = (recordCount / pageSize); if ((recordCount % pageSize) > 0) { pageCount++; } //默认第一页 currentPage = 1; LoadPage();//调用加载数据的方法 dgvSelectMeasureData.Visible = true; rbtnExportCSVReport.Visible = true; pnlPage.Visible = true; labSearchResult.Visible = false; pnlPage.Visible = true; } else { dgvSelectMeasureData.Visible = false; labSearchResult.Visible = true; rbtnExportCSVReport.Visible = false; pnlPage.Visible = false; } } private void rbtSelectFPY_Click(object sender, EventArgs e) { dgvSelectMeasureData.Visible = false; rbtnExportCSVReport.Visible = false; pnlPage.Visible = false; string strStartTime = rdtpStartTime.Value.ToString("yyyy-MM-dd") + " 00:00:00"; string strEndTime = rdtpEndTime.Value.ToString("yyyy-MM-dd") + " 23:59:59"; string strCarID = rtbPartID.Text.Trim(); DataTable dtFPY = new DataTable(); dtFPY = tmdal.SelectTMeasureResultByTime(strCarID, strStartTime, strEndTime); if (dtFPY.Rows.Count > 0) { dgvFPYResult.Visible = true; labSearchResult.Visible = false; rbtnExportCSVReport.Visible = true; chartFPYLine.Visible = true; dgvFPYResult.DataSource = dtFPY; SetdgvRowBgColor(dgvFPYResult); for (int i = 0; i < dgvFPYResult.Rows.Count; i++) { if (dgvFPYResult.Rows[i].Cells["SMResult"].Value.ToString().ToLower().Contains("不合格")) { dgvFPYResult.Rows[i].Cells["SMResult"].Style.ForeColor = Color.Red; } } #region 合格率折线图 //合格率折线图 string[] strXDate = new string[dtFPY.Rows.Count]; double[] dFPYResult = new double[dtFPY.Rows.Count]; for (int i = 0; i < dtFPY.Rows.Count; i++) { strXDate[i] = dtFPY.Rows[i]["CarID"].ToString(); } for (int i = 0; i < dtFPY.Rows.Count; i++) { double dResult = double.Parse(dtFPY.Rows[i]["FPY"].ToString()); dFPYResult[i] = dResult * 100.00; } chartFPYLine.ChartAreas[0].AxisX.LabelStyle.Angle = -50; //X轴标签倾斜角度设置 chartFPYLine.ChartAreas[0].AxisY.LabelStyle.Format = "{0:F2}" + "%"; //设置Y轴值的格式化 带% chartFPYLine.Series[0].Label = "#VAL%"; //设置显示Y的值 chartFPYLine.Series[0].LabelForeColor = Color.White; chartFPYLine.Series[0].ToolTip = "车身编号 : #VALX \r\n合格率 : #VAL%"; //鼠标移动到对应点显示数值 chartFPYLine.Series[0].Points.DataBindXY(strXDate, dFPYResult); #endregion 合格率折线图 } else { dgvFPYResult.Visible = false; labSearchResult.Visible = true; rbtnExportCSVReport.Visible = false; chartFPYLine.Visible = false; } } public static void ExportdgvDataToCsv(DataGridView dataGridView, string filePath) { StringBuilder sb = new StringBuilder(); // 添加列标题 foreach (DataGridViewColumn column in dataGridView.Columns) { sb.Append(column.HeaderText); sb.Append(","); } sb.Remove(sb.Length - 1, 1); sb.AppendLine(); // 添加行数据 foreach (DataGridViewRow row in dataGridView.Rows) { foreach (DataGridViewCell cell in row.Cells) { sb.Append(cell.Value); sb.Append(","); } sb.Remove(sb.Length - 1, 1); sb.AppendLine(); } // 将数据写入CSV文件 File.WriteAllText(filePath, sb.ToString()); } public static void ExportDataTableDataToCsv(DataTable dt, string filePath) { StringBuilder sb = new StringBuilder(); // 添加列标题 foreach (DataColumn column in dt.Columns) { sb.Append(column.ColumnName); sb.Append(","); } sb.Remove(sb.Length - 1, 1); sb.AppendLine(); // 添加行数据 foreach (DataRow row in dt.Rows) { foreach (object item in row.ItemArray) { sb.Append(item); sb.Append(","); } sb.Remove(sb.Length - 1, 1); sb.AppendLine(); } // 将数据写入CSV文件 File.WriteAllText(filePath, sb.ToString()); } private void rbtnExportCSVReport_Click(object sender, EventArgs e) { string strCSVExportPath = ""; string strExportTime = DateTime.Now.ToString("yyyyMMddHHmmssfff"); FolderBrowserDialog m_Folder = new FolderBrowserDialog(); m_Folder.Description = "请选择要导出的CSV文件的路径"; m_Folder.RootFolder = Environment.SpecialFolder.Desktop; if (dgvFPYResult.Visible == true && dgvFPYResult.Rows.Count > 0) { m_Folder.ShowDialog(); if (Directory.Exists(m_Folder.SelectedPath)) { strCSVExportPath = m_Folder.SelectedPath + "\\合格率" + strExportTime + ".CSV"; ExportdgvDataToCsv(dgvFPYResult, strCSVExportPath); } } if (dgvSelectMeasureData.Visible == true && dgvSelectMeasureData.Rows.Count > 0) { m_Folder.ShowDialog(); if (Directory.Exists(m_Folder.SelectedPath)) { strCSVExportPath = m_Folder.SelectedPath + "\\车身尺寸数据" + strExportTime + ".CSV"; ExportDataTableDataToCsv(PageTable, strCSVExportPath); } } } private void dgvFPYResult_RowStateChanged(object sender, DataGridViewRowStateChangedEventArgs e) { e.Row.HeaderCell.Value = string.Format("{0}", e.Row.Index + 1); } private void dgvSelectMeasureData_RowStateChanged(object sender, DataGridViewRowStateChangedEventArgs e) { e.Row.HeaderCell.Value = string.Format("{0}", e.Row.Index + 1); } #endregion Search Data #region IOT数据的重传 private void ReSendIotData() { DataTable dtUnuploaded = tmdal.SelectUnuploadedIOTLogs(); foreach (DataRow row in dtUnuploaded.Rows) { string carId = row["CarID"].ToString(); string content = row["Content"].ToString(); string fpy = row["FPY"]?.ToString(); int id = Convert.ToInt32(row["Id"]); // 调用上传接口 string result = PostJsonToIOT(ConfigDfn.strIOTAddress, content, 10000); bool isSuccess = result.Contains("成功"); // 更新上传状态 if (isSuccess) { tmdal.UpdateIOTUploadStatus(id, true); } } } #endregion #region CP CPK private void rbtnSearchCPCPK_Click(object sender, EventArgs e) { DataTable dtCPCPK = new DataTable(); string strMeasureName = rddlMeasurePoint.Text; string strSizeName = rddlSizeName.Text.Trim().Substring(0, 1); int iLimitCount = (int)nudMeasureCount.Value; dtCPCPK = tmdal.SelectMeasureValuebyMeasureNameAndSize(strMeasureName, strSizeName, iLimitCount); int iSelectRows = dtCPCPK.Rows.Count; if (iSelectRows < 5) { chartCPCPK.Visible = false; labSearchCPCPKResult.Visible = true; pnlCPCPK.Visible = false; } else { double dNormalValue = double.Parse(dtCPCPK.Rows[0]["NormalValue"].ToString()); double dLowerTolValue = double.Parse(dtCPCPK.Rows[0]["LowerTolVal"].ToString()); double dUpperTolValue = double.Parse(dtCPCPK.Rows[0]["UpperTolVal"].ToString()); double dLSL = dNormalValue + dLowerTolValue; double dUSL = dNormalValue + dUpperTolValue; List listMDoubleData = new List(); List listMStrData = new List(); listMStrData.Clear(); listMDoubleData.Clear(); for (int i = 0; i < iSelectRows; i++) { listMDoubleData.Add(double.Parse(dtCPCPK.Rows[i]["MeasureValue"].ToString())); listMStrData.Add(dtCPCPK.Rows[i]["MeasureValue"].ToString()); } #region 数据赋值 labLSL.Text = dLSL.ToString("F2"); labUSL.Text = dUSL.ToString("F2"); labTarget.Text = dNormalValue.ToString("F2"); labSampleSize.Text = iSelectRows.ToString(); labAverage.Text = CpCpkHelper.GetAverage(listMStrData).ToString("F4"); labStdDev.Text = CpCpkHelper.GetSigma(listMStrData).ToString("F4"); List listCpCpk = CpCpkHelper.GetCpList(listMStrData, dUSL, dLSL); labCp.Text = listCpCpk[0].ToString("F4"); labCpl.Text = listCpCpk[1].ToString("F4"); labCpu.Text = listCpCpk[2].ToString("F4"); labCpk.Text = listCpCpk[3].ToString("F4"); List listPpPpk = CpCpkHelper.GetPpList(listMStrData, dUSL, dLSL); labPp.Text = listPpPpk[0].ToString("F4"); labPpl.Text = listPpPpk[1].ToString("F4"); labPpu.Text = listPpPpk[2].ToString("F4"); labPpk.Text = listPpPpk[3].ToString("F4"); #endregion 数据赋值 #region 画柱状图 Dictionary histogramDataDic = new Dictionary(); histogramDataDic = CpCpkHelper.GetHistogramData(listMDoubleData); string[] strXValue = new string[histogramDataDic.Count]; int[] dYValue = new int[histogramDataDic.Count]; for (int i = 0; i <= histogramDataDic.Count - 1; i++) { strXValue[i] = (histogramDataDic.ElementAt(i).Key); dYValue[i] = int.Parse(histogramDataDic.ElementAt(i).Value); } chartCPCPK.Series[0].Label = "#VAL"; //设置显示Y的值 chartCPCPK.Series[0].LabelForeColor = Color.White; chartCPCPK.Series[0].ToolTip = "区间范围 : #VALX \r\n数量 : #VAL"; //鼠标移动到对应点显示数值 chartCPCPK.Series[0].Points.DataBindXY(strXValue, dYValue); #endregion 画柱状图 chartCPCPK.Visible = true; labSearchCPCPKResult.Visible = false; pnlCPCPK.Visible = true; } } #endregion CP CPK #region 软件设置 private void lpcSoftwareSetup_Click(object sender, EventArgs e) { string strInputPwd = MyBase.InputBox("密码", "请输入密码 : ", "", "确定", "取消"); if (strInputPwd.Contains("-999.999")) { return; } else if (strInputPwd == ConfigDfn.strPwd) { FSoftwareSetup fss = new FSoftwareSetup(); fss.ShowDialog(this); } else { MessageBox.Show("密码错误! ", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } } private void lpcToleranceSetup_Click(object sender, EventArgs e) { string strInputPwd = MyBase.InputBox("密码", "请输入密码 : ", "", "确定", "取消"); if (strInputPwd.Contains("-999.999")) { return; } else if (strInputPwd == ConfigDfn.strPwd) { FToleranceSetup fts = new FToleranceSetup(); fts.ShowDialog(this); } else { MessageBox.Show("密码错误! ", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } } private void lpcRange_Click(object sender, EventArgs e) { string strInputPwd = MyBase.InputBox("密码", "请输入密码 : ", "", "确定", "取消"); if (strInputPwd.Contains("-999.999")) { return; } else if (strInputPwd == ConfigDfn.strPwd) { FRangeSetup frs = new FRangeSetup(); frs.ShowDialog(this); } else { MessageBox.Show("密码错误! ", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } } private void lpcPLCAddress_Click(object sender, EventArgs e) { string strInputPwd = MyBase.InputBox("密码", "请输入密码 : ", "", "确定", "取消"); if (strInputPwd.Contains("-999.999")) { return; } else if (strInputPwd == ConfigDfn.strPwd) { PlcAddrSetup PLCAS = new PlcAddrSetup(3, ConfigDfn.strConfigFile); PLCAS.Show(); } else { MessageBox.Show("密码错误! ", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } } private void lpcPLCTest_Click(object sender, EventArgs e) { FormDebugSiemensS7 FDS7 = new FormDebugSiemensS7(SiemensPLCS.S1200); FDS7.Show(); } private void lpcAboutSoftware_Click(object sender, EventArgs e) { AboutSoftwareInfo asi = new AboutSoftwareInfo(); asi.ShowDialog(); } private void lpcShowLog_Click(object sender, EventArgs e) { System.Diagnostics.Process.Start("notepad.exe", LogDebugDfn.strDebugFile); } #endregion 软件设置 #region RadButton鼠标事件 private void btn_MouseHover(object sender, EventArgs e) { RadButton btn = sender as RadButton; btn.BackColor = Color.FromArgb(0, 151, 186); } private void btn_MouseLeave(object sender, EventArgs e) { RadButton btn = sender as RadButton; btn.BackColor = Color.FromArgb(19, 46, 53); } #endregion RadButton鼠标事件 #region PLC相关函数 #region PLC重连操作 private void ttmrReadPLCData_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { ttmrReadPLCData.Stop(); ReadAndProcessPlcData(); ttmrReadPLCData.Start(); } private void ttmrWritePLCLive_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { ttmrWritePLCLive.Stop(); bTickt = !bTickt; PlcObject.InsertWriteQueue(PlcSignalDfn.SoftLive, Convert.ToByte(bTickt ? 1 : 0)); ttmrWritePLCLive.Start(); } private void m_bgwAnalysisCSVReport_DoWork(object sender, DoWorkEventArgs e) { while (true) { AnalysisNextSenseSelfMeasureCSV(); AnalysisNextSenseEH3CSV(); AnalysisNextSenseEHYCSV(); AnalysisNextSenseEHVCSV(); } } private void ttmrReadNSCSV_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { ttmrReadNSCSV.Stop(); //AnalysisNextSenseSelfMeasureCSV(); //AnalysisNextSenseEH3CSV(); //AnalysisNextSenseEHYCSV(); ttmrReadNSCSV.Start(); } private void ReadAndProcessPlcData() { #region 判断PLC是否正常运行 if (ConfigPlc.PlcType == 3 && ConfigPlc.bReConnect && !HslSiemensS7Obj.bConnected) { MyBase.TraceWriteLine("PLC断开,重连!"); tmrHeartBeatConnect.Stop(); ReConnectPLC(); return; } byte[] m_Datas = null; if (!HslSiemensS7Obj.ReadDatas(PlcAddrSetup.S7ReadStartAddr, (ushort)PlcAddrSetup.S7ReadByteCount, ref m_Datas)) { //tmrReadPLCData.Start(); ttmrReadPLCData.Start(); ttmrReadPLCData.Start(); return; } if (m_Datas == null) { //tmrReadPLCData.Start(); ttmrReadPLCData.Start(); ttmrReadPLCData.Start(); MyBase.TraceWriteLine("PLC读取数据对象为空,退出!"); return; } #endregion 判断PLC是否正常运行 try { #region 循环读取PLC数据块中的信息 if (m_Datas.Length >= PlcAddrSetup.S7ReadByteCount) { PLCDfn.bPlcLiveTick = PlcObject.GetS7ByteData(PlcSignalDfn.PlcLive) == 1; PLCDfn.ReadVINFinishFlag = PlcObject.GetS7ByteData(PlcSignalDfn.ReadVINFinishFlag); PLCDfn.NSStartMeasure = PlcObject.GetS7ByteData(PlcSignalDfn.NSStartMeasure); PLCDfn.CarPassFlag = PlcObject.GetS7ByteData(PlcSignalDfn.CarPassFlag); PLCDfn.NoCarTypeFlag = PlcObject.GetS7ByteData(PlcSignalDfn.NoCarTypeFlag); //从PLC获取VIN码后,通过访问IOT接口 获取汽车类型,再反馈给PLC if (iLastReadVINFinishFlag == 0 && PLCDfn.ReadVINFinishFlag == 10) //到达信号 { string strCarID = PlcObject.GetS7StringData(PlcSignalDfn.PartID); //PLCDfn.CarType = PlcObject.GetS7ByteData(PlcSignalDfn.CarType); MyBase.TraceWriteLine("PLC读码完成信号:0->10;Read PLC VIN is: " + strCarID); if (strCarID.Length > 10) { string strCarColor = ""; string strCarType = GetCarTypeByIOTAPI(strCarID, out strCarColor); if (!strCarType.ToUpper().Contains("ERR")) { if (strCarType.ToUpper().Contains("EH3")) { PlcObject.InsertWriteQueue(PlcSignalDfn.WCarType, (byte)1); } else if (strCarType.ToUpper().Contains("EHY")) { PlcObject.InsertWriteQueue(PlcSignalDfn.WCarType, (byte)2); } else if (strCarType.ToUpper().Contains("EHV")) { PlcObject.InsertWriteQueue(PlcSignalDfn.WCarType, (byte)3); } else { PlcObject.InsertWriteQueue(PlcSignalDfn.WCarType, (byte)0); MyBase.TraceWriteLine($"未匹配到车型,输入字符为:{strCarType}"); } PlcObject.InsertWriteQueue(PlcSignalDfn.WCarColor, strCarColor); MyBase.TraceWriteLine("往PLC写入车型: " + strCarType + " ;车身颜色:" + strCarColor); tmdal.InsertVIN(strCarID); MyBase.TraceWriteLine(strCarID + " 插入到数据库表TTempSaveVIN中完成。"); #region 记录PLC过点信息 try { DateTime arriveTime = DateTime.Now; if (tmdal.ExistsArriveLog(strCarID) == 0) { tmdal.InsertArriveLog(strCarID, arriveTime); } else { MyBase.TraceWriteLine($"车辆 {strCarID} 当天已存在抵达记录,未重复插入。"); } } catch (Exception ex) { MyBase.TraceWriteLine("记录PLC过点信息异常,异常信息: " + ex.ToString()); } #endregion } else { MyBase.TraceWriteLine("报错:根据VIN从IOT上获取车型信息失败,不发送给PLC车型信息和颜色信息。 "); } } } if (iLastNoCarTypeFlag == 0 && PLCDfn.NoCarTypeFlag == 10) { string strCarID = PlcObject.GetS7StringData(PlcSignalDfn.PartID); MyBase.TraceWriteLine("NoCarTypeFlag:0->10; PLC 反馈未收到软件发送的车类型码信息; VIN=" + strCarID); } if (iLastNSStartMeasure == 0 && PLCDfn.NSStartMeasure == 10) //启动测量信号 { string strCarID = PlcObject.GetS7StringData(PlcSignalDfn.PartID); if (strCarID.Length > 10) { // 记录日志,此时该车开始测量 MyBase.TraceWriteLine($"检测开始测量0->10: {strCarID} 机器人安全判断合格,启动NXS测量"); #region 记录PLC过点信息 // 记录启动测量时间 try { DateTime measureStartTime = DateTime.Now; tmdal.UpdateStartMeasureTime(strCarID, measureStartTime); } catch (Exception ex) { MyBase.TraceWriteLine("记录测量开始时间异常,异常信息: " + ex.ToString()); } #endregion } else { //记录日志,获取到启动测量信号,但没有获取 车号 MyBase.TraceWriteLine("报错:获取到启动NXS测量信号,但没有获取 车号 "); } } if (iLastCarPassFlag == 0 && PLCDfn.CarPassFlag == 10) //离开信号 { string strCarID = PlcObject.GetS7StringData(PlcSignalDfn.PartID); MyBase.TraceWriteLine("读取PLC CarPassFlag 完成信号:0->10;Read PLC VIN is: " + strCarID); string strSecondPosCarID = tmdal.SelectMaintenanceStationVINbyStationNo(2); if (strSecondPosCarID.Length == 21) { string strTempCarID = strSecondPosCarID.Substring(0, 17); string strTempCarType = strSecondPosCarID.Substring(18, 3); if (tmdal.CheckMRVINExistOrNotByVIN(strTempCarID) == 0) { string strTargetRate = Math.Round(ConfigDfn.dFPY2 * 100.00d, 2).ToString("F2") + "%"; MyBase.TraceWriteLine(strSecondPosCarID + " ;该VIN码只扫码没有测量,没有测量结果,上传IOT NG消息。"); string strPostData = "{\"serno\":\"" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + "\",\"requestData\":[{\"vin\":\"" + strTempCarID + "\",\"model\":\"" + strTempCarType + "\",\"equipmentNo\":\"" + ConfigDfn.strEquipNo + "\",\"equipmentName\":\"" + ConfigDfn.strEquipName + "\",\"calibrationResult\":\"NG\",\"detectionTime\":\"" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\",\"targetRate\":\"" + strTargetRate + "\",\"rate\":\"0.00%\",\"GapList\":[]}]}"; MyBase.TraceWriteLine("Update NG To IOT Data Content: " + strPostData); string strPostResult = PostJsonToIOT(ConfigDfn.strIOTAddress, strPostData, 10000); MyBase.TraceWriteLine("NG数据上传IOT完成,结果返回为:" + strPostResult); if (strPostResult.Contains("成功")) { MyBase.TraceWriteLine("NG数据上传IOT成功 ^_^"); tmdal.InsertIOTUploadLog(strCarID, strPostData, true, "0.00"); } else { MyBase.TraceWriteLine("NG数据上传IOT失败!"); tmdal.InsertIOTUploadLog(strCarID, strPostData, false, "0.00"); } } #region 记录PLC过点信息 try { DateTime leaveTime = DateTime.Now; tmdal.UpdateLeaveTime(strTempCarID, leaveTime); } catch (Exception ex) { MyBase.TraceWriteLine("记录PLC过点信息异常,异常信息: " + ex.ToString()); } #endregion } if (!string.IsNullOrEmpty(strCarID) && strCarID.Length > 10) { MyBase.TraceWriteLine("CarPassFlag 0->10 开始更新MaintenceInfo数据库位置7-2中的VIN码 "); string strTempCarID = tmdal.SelectMaintenanceStationVINbyStationNo(6); Thread.Sleep(10); tmdal.updateMaintenceInfo(strTempCarID, 7); MyBase.TraceWriteLine($"CarPassFlag 0->10 更新VIN={strTempCarID} 到MaintenceInfo数据库位置7完成。"); Thread.Sleep(15); tmdal.updateMaintenceInfo(tmdal.SelectMaintenanceStationVINbyStationNo(5), 6); Thread.Sleep(20); tmdal.updateMaintenceInfo(tmdal.SelectMaintenanceStationVINbyStationNo(4), 5); Thread.Sleep(20); tmdal.updateMaintenceInfo(tmdal.SelectMaintenanceStationVINbyStationNo(3), 4); Thread.Sleep(20); tmdal.updateMaintenceInfo(tmdal.SelectMaintenanceStationVINbyStationNo(2), 3); Thread.Sleep(20); tmdal.updateMaintenceInfo(tmdal.SelectMaintenanceStationVINbyStationNo(1), 2); Thread.Sleep(20); string strCarColor = ""; string strCarType = GetCarTypeByIOTAPI(strCarID, out strCarColor); if (!strCarType.ToUpper().Contains("ERR")) { if (strCarType.ToUpper().Contains("EH3")) { strCarID = strCarID + "_EH3"; } else if (strCarType.ToUpper().Contains("EHY")) { strCarID = strCarID + "_EHY"; } else if (strCarType.ToUpper().Contains("EHV")) { strCarID = strCarID + "_EHV"; } else { MyBase.TraceWriteLine($"未匹配到具体的车型,传入字符{strCarType}"); } } tmdal.updateMaintenceInfo(strCarID, 1); MyBase.TraceWriteLine("CarPassFlag 0->10 更新到MaintenceInfo数据库位置1中的VIN为: " + strCarID); } else { MyBase.TraceWriteLine("CarPassFlag 0->10 strCarID Error = " + strCarID); string strTempCarID = tmdal.SelectMaintenanceStationVINbyStationNo(6); Thread.Sleep(10); tmdal.updateMaintenceInfo(strTempCarID, 7); MyBase.TraceWriteLine($"CarPassFlag 0->10 更新VIN={strTempCarID} 到MaintenceInfo数据库位置7完成。"); Thread.Sleep(15); tmdal.updateMaintenceInfo(tmdal.SelectMaintenanceStationVINbyStationNo(5), 6); Thread.Sleep(20); tmdal.updateMaintenceInfo(tmdal.SelectMaintenanceStationVINbyStationNo(4), 5); Thread.Sleep(20); tmdal.updateMaintenceInfo(tmdal.SelectMaintenanceStationVINbyStationNo(3), 4); Thread.Sleep(20); tmdal.updateMaintenceInfo(tmdal.SelectMaintenanceStationVINbyStationNo(2), 3); Thread.Sleep(20); tmdal.updateMaintenceInfo(tmdal.SelectMaintenanceStationVINbyStationNo(1), 2); Thread.Sleep(20); tmdal.updateMaintenceInfo("empty", 1); MyBase.TraceWriteLine("CarPassFlag 0->10 更新到MaintenceInfo数据库位置1中的VIN为:empty "); } } //记录编码器速度等值 if (ConfigDfn.iRecordEncoderFlag == 1) { double dSpeed1 = PlcObject.GetS7Double(PlcSignalDfn.Speed1); double dSpeed2 = PlcObject.GetS7Double(PlcSignalDfn.Speed2); double dR01 = PlcObject.GetS7Double(PlcSignalDfn.R01_Pules); double dR02 = PlcObject.GetS7Double(PlcSignalDfn.R02_Pules); NLogger.Fatal(dSpeed1 + "," + dSpeed2 + "," + dR01 + "," + dR02); } } iLastCarPassFlag = PLCDfn.CarPassFlag; iLastReadVINFinishFlag = PLCDfn.ReadVINFinishFlag; iLastNSStartMeasure = PLCDfn.NSStartMeasure; iLastNoCarTypeFlag = PLCDfn.NoCarTypeFlag; #endregion 循环读取PLC数据块中的信息 } catch (Exception ex) { MyBase.TraceWriteLine("tmrReadPLCData_Tick exception: " + ex.ToString()); } } private void tmrRefreshPLCStatus_Tick(object sender, EventArgs e) { if (labelTimeStatus_Tip.Text == "─") { labelTimeStatus_Tip.Text = "╲"; } else if (labelTimeStatus_Tip.Text == "╲") { labelTimeStatus_Tip.Text = "│"; } else if (labelTimeStatus_Tip.Text == "│") { labelTimeStatus_Tip.Text = "╱"; } else if (labelTimeStatus_Tip.Text == "╱") { labelTimeStatus_Tip.Text = "─"; } lampPLCHeart.State = PLCDfn.bPlcLiveTick ? LampColor.Green : LampColor.Silver; rlePLCHeart.ForeColor = PLCDfn.bPlcLiveTick ? Color.Lime : Color.White; } private void tmrHeartBeatConnect_Tick(object sender, EventArgs e) { if (bPlcLiveTickLast != PLCDfn.bPlcLiveTick) { HeartBeatCount = 0; } else { HeartBeatCount++; } if (HeartBeatCount >= 600) { HeartBeatCount = 0; if (!bStopPlcNormal) { MyBase.TraceWriteLine("PLC心跳检测10分钟内未变化,断开PLC,进行PLC重连!"); PlcObject.ClosePlc(); } } bPlcLiveTickLast = PLCDfn.bPlcLiveTick; } private void ReConnectPLC() { m_ThreadReconnectPLC = null; m_ThreadReconnectPLC = new Thread(new ThreadStart(ReConnectPlcProcess)); if (!m_ThreadReconnectPLC.IsAlive) { m_ThreadReconnectPLC.Start(); } } private void ReConnectPlcProcess() { while (!PlcObject.IsPlcConnected()) { bool bConnectResult = PlcObject.ConnectPlc(); if (!bConnectResult) { m_ReConnectNum++; MyBase.TraceWriteLine("重连PLC,第" + m_ReConnectNum + "次!"); } Thread.Sleep(1000); } MyBase.TraceWriteLine("重新连接PLC成功!"); lampConnectPLCStatus.State = LampColor.Green; rlePLCStatus.ForeColor = Color.Lime; this.BeginInvoke((EventHandler)delegate { tmrHeartBeatConnect.Start(); }); bStopPlcNormal = false; m_ReConnectNum = 0; this.Invoke((EventHandler)(delegate { //tmrReadPLCData.Start(); ttmrWritePLCLive.Start();//启动给PLC写入心跳 1s写一次 0 1 tmrRefreshPLCStatus.Start();//刷新PLC等的状态 })); m_ThreadReconnectPLC.Abort(); } #endregion PLC重连操作 private void ConnectThread() { MyBase.TraceWriteLine("连接PLC...."); bool bConnectResult = PlcObject.ConnectPlc(); this.Invoke((EventHandler)(delegate { if (bConnectResult) { lampConnectPLCStatus.State = LampColor.Green; rlePLCStatus.ForeColor = Color.Lime; MyBase.TraceWriteLine("连接PLC成功"); } else { lampConnectPLCStatus.State = LampColor.Red; rlePLCStatus.ForeColor = Color.Red; ttmrReadPLCData.Stop(); MyBase.TraceWriteLine("连接PLC失败"); return; } //tmrReadPLCData.Start(); //读取PLC数据信息 ttmrReadPLCData.Start(); ttmrWritePLCLive.Start();//启动给PLC写入心跳 1s写一次 0 1 tmrRefreshPLCStatus.Start();//刷新PLC等的状态 if (ConfigPlc.bReConnect) tmrHeartBeatConnect.Start(); //监测来自plc的心跳5分钟内没有变化,重新连接PLC })); } private void btnConnectPlc_Click(object sender, EventArgs e) { try { PlcObject.InitWritePlcThread(); bStopPlcNormal = false; Thread m_Thread = new Thread(ConnectThread); m_Thread.Start(); return; } catch (Exception ex) { MessageBox.Show(ex.Message, "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } private void btnClosePlc_Click(object sender, EventArgs e) { try { MyBase.TraceWriteLine("点击了断开PLC按钮,断开PLC!"); ttmrReadPLCData.Stop(); tmrHeartBeatConnect.Stop(); ttmrWritePLCLive.Stop(); tmrRefreshPLCStatus.Stop(); lampConnectPLCStatus.State = LampColor.White; rlePLCStatus.ForeColor = Color.White; rlePLCHeart.ForeColor = Color.White; lampPLCHeart.State = LampColor.White; bStopPlcNormal = true; PlcObject.ClosePlc(); } catch (Exception ex) { MessageBox.Show(ex.Message, "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } #endregion PLC相关函数 private void lpcUploadIOTTest_Click(object sender, EventArgs e) { string strPostData = "{\"serno\":\"" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + "\",\"requestData\":[{\"vin\":\"test001\",\"model\":\"EHY\",\"equipmentNo\":\"" + ConfigDfn.strEquipNo + "\",\"equipmentName\":\"" + ConfigDfn.strEquipName + "\",\"calibrationResult\":\"OK\",\"detectionTime\":\"" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\",\"GapList\":[{\"vin\":\"test001\",\"gfNo\":\"F\",\"pointNumber\":\"L-01\",\"actualValue\":\"-0.30\",\"controlLine\":\"-1.00/1.00\",\"measurementResult\":\"OK\"}]}]}"; MyBase.TraceWriteLine("Test Post Data: " + strPostData); //插入记录测试 tmdal.InsertIOTUploadLog("test001", strPostData, true, labResultPercent.Text); string strPostResult = PostJsonToIOT(ConfigDfn.strIOTAddress, strPostData, 10000); MessageBox.Show("测试上传数据完成,获取到的返回值为: " + strPostResult, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); MyBase.TraceWriteLine("测试上传数据完成,获取到的返回值为: " + strPostResult); } private void lpcTestGetCarTye_Click(object sender, EventArgs e) { string strPostData = "{\"serno\":\"312314141\",\"vin\":\"LNNAJDDU9RDA00213\"}"; MyBase.TraceWriteLine("Test Post Data: " + strPostData); string strPostResult = PostJsonToIOT(ConfigDfn.strIOTCarTypeAddress, strPostData, 10000); MessageBox.Show("测试从IOT获取车型信息完成,获取到的返回值为: " + strPostResult, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); MyBase.TraceWriteLine("测试从IOT获取车型信息完成,获取到的原返回值为: " + strPostResult); string strNewResult = strPostResult.Substring(1, strPostResult.Length - 2).Replace("]", ""); MessageBox.Show("测试从IOT获取车型信息完成,处理后 获取到的返回值为: " + strNewResult, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); MyBase.TraceWriteLine("测试从IOT获取车型信息完成,处理后 获取到的返回值为: " + strNewResult); CheryCarTypeInfo ccti = new CheryCarTypeInfo(); ccti = JsonConvert.DeserializeObject(strNewResult); MessageBox.Show("测试从IOT获取车型信息完成,获取到的返回值为: " + strNewResult + "; 解析出的车型:" + ccti.data.model + " ;解析出的物料号为" + ccti.data.material + " ;解析出颜色编号:" + ccti.data.material.Substring(7, 2), "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } private string GetCarTypeByIOTAPI(string strVIN, out string strMaterialNo) { string strPostData = "{\"serno\":\"" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + "\",\"vin\":\"" + strVIN + "\"}"; MyBase.TraceWriteLine(" Post VIN Data: " + strPostData); string strPostResult = PostJsonToIOT(ConfigDfn.strIOTCarTypeAddress, strPostData, 5000); MyBase.TraceWriteLine("GetCarTypeByIOTAPI IOT Return CarType Infomation : " + strPostResult); string strNewResult = strPostResult.Substring(1, strPostResult.Length - 2).Replace("]", ""); //MyBase.TraceWriteLine("GetCarTypeByIOTAPI IOT Return New CarType Infomation : " + strNewResult); CheryCarTypeInfo ccti = new CheryCarTypeInfo(); ccti = JsonConvert.DeserializeObject(strNewResult); if (ccti.message.Contains("成功")) { if (ccti.data.material != null && ccti.data.material.Length > 9) { strMaterialNo = ccti.data.material.Substring(7, 2); MyBase.TraceWriteLine(" IOT Return CarType Infomation : " + strNewResult + "; 解析出的车型:" + ccti.data.model + "解析出车颜色编号:" + strMaterialNo); } else { strMaterialNo = "TE"; MyBase.TraceWriteLine(" IOT Return CarType Infomation : " + strNewResult + "; 解析出的车型:" + ccti.data.model + ";未解析出车颜色编号"); } return ccti.data.model; } else { MyBase.TraceWriteLine(" IOT Return CarType Infomation ERROR : " + strPostResult); strMaterialNo = "ER"; return "ERR"; } } private void lpcShowCarData_Click(object sender, EventArgs e) { if (ConfigDfn.strShowCarLR == "L") { if (ConfigDfn.strCarModel.ToUpper().Contains("EH3")) { fLEH3.Show(); fLEHY.Hide(); fLEHV.Hide(); } else if (ConfigDfn.strCarModel.ToUpper().Contains("EHV")) { fLEHV.Show(); fLEH3.Hide(); fLEHY.Hide(); } else { fLEHY.Show(); fLEH3.Hide(); fLEHV.Hide(); } } else { if (ConfigDfn.strCarModel.ToUpper().Contains("EH3")) { fREH3.Show(); fREHY.Hide(); fREHV.Hide(); } else if (ConfigDfn.strCarModel.ToUpper().Contains("EHV")) { fREHV.Show(); fREH3.Hide(); fREHY.Hide(); } else { fREHY.Show(); fREH3.Hide(); fREHV.Hide(); } } } public void ShowCarMeasureDataByCarType(int iCarType) { Invoke((MethodInvoker)(() => { if (ConfigDfn.strShowCarLR == "L") { if (iCarType == 1) { fLEH3.Show(); fLEHY.Hide(); fLEHV.Hide(); MyBase.TraceWriteLine("显示左侧EH3车身数据界面。"); } else if (iCarType == 2) { fLEHY.Show(); fLEH3.Hide(); fLEHV.Hide(); MyBase.TraceWriteLine("显示左侧EHY车身数据界面。"); } else if(iCarType == 3) { fLEHV.Show(); fLEH3.Hide(); fLEHY.Hide(); MyBase.TraceWriteLine("显示左侧EHV车身数据界面。"); } else { MyBase.TraceWriteLine("未知车型,不显示"); } } else { if (iCarType == 1) { fREH3.Show(); fREHY.Hide(); fREHV.Hide(); MyBase.TraceWriteLine("显示右侧EH3车身数据界面。"); } else if (iCarType == 2) { fREHY.Show(); fREH3.Hide(); fREHV.Hide(); MyBase.TraceWriteLine("显示右侧EHY车身数据界面。"); } else if (iCarType == 3) { fREHV.Show(); fREH3.Hide(); fREHY.Hide(); MyBase.TraceWriteLine("显示右侧EHV车身数据界面。"); } else { MyBase.TraceWriteLine("未知车型,不显示"); } } })); } private void rbtnTestCOM_Click(object sender, EventArgs e) { if (rbtnTestCOM.Text == "打开串口") { serialTestPort = new SerialPort(rtbPort.Text.Trim(), 115200, Parity.None, 8, StopBits.One); // 设置串口参数 serialTestPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); // 注册数据接收事件处理方法 serialTestPort.Open(); // 打开串口 if (serialTestPort.IsOpen) { rbtnTestCOM.Text = "关闭串口"; } } else { serialTestPort.DataReceived -= new SerialDataReceivedEventHandler(DataReceivedHandler); serialTestPort.Close(); serialTestPort.Dispose(); rbtnTestCOM.Text = "打开串口"; } } private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) { SerialPort sp = (SerialPort)sender; string indata = sp.ReadExisting(); MyBase.TraceWriteLine(indata); rtbCOMContent.Text = indata; } private void CenterControl_Shown(object sender, EventArgs e) { rddlSizeName.SelectedIndex = 0; DataTable dtMPName = tmdal.SelectAllMeasPointName(); if (dtMPName.Rows.Count > 0) { for (int i = 0; i < dtMPName.Rows.Count; i++) { rddlMeasurePoint.Items.Add(dtMPName.Rows[i][0].ToString()); } rddlMeasurePoint.SelectedIndex = 0; } } } public class CheryIOTData { /// /// VIN号 /// public string vin { get; set; } /// /// FG /// public string gfNo { get; set; } /// /// 测点编号 /// public string pointNumber { get; set; } /// /// 实测值 /// public string actualValue { get; set; } /// /// 控制线 /// public string controlLine { get; set; } /// /// 测量结果 /// public string measurementResult { get; set; } } public class CarInfoData { public string material { get; set; } public string model { get; set; } } public class CheryCarTypeInfo { /// /// data /// public CarInfoData data { get; set; } /// /// message /// public string message { get; set; } /// /// serno /// public string serno { get; set; } /// /// success /// public string success { get; set; } } public static class JsonHelper { /// /// 对象转成JSON 格式字符串 /// /// 对象 /// JSON格式的字符串 public static string ObjectToJson(object obj) { return JsonConvert.SerializeObject(obj); } /// /// 解析JSON字符串生成对象实体 /// /// 对象类型 /// json字符串 /// 对象实体 public static T DeserializeJsonToObject(string json) where T : class { Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer(); StringReader sr = new StringReader(json); object o = serializer.Deserialize(new JsonTextReader(sr), typeof(T)); T t = o as T; return t; } /// /// 解析JSON数组生成对象实体集合 /// /// 对象类型 /// json数组字符串(eg.[{"ID":"112","Name":"石子儿"}]) /// 对象实体集合 public static List DeserializeJsonToList(string json) where T : class { Newtonsoft.Json.JsonSerializer serializer = new JsonSerializer(); StringReader sr = new StringReader(json); object o = serializer.Deserialize(new JsonTextReader(sr), typeof(List)); List list = o as List; return list; } /// /// 数据表转键值对集合 把DataTable转成 List集合, 存每一行 集合中放的是键值对字典,存每一列 /// /// 数据表 /// 哈希表数组 public static List> DataTableToList(DataTable dt) { List> list = new List>(); foreach (DataRow dr in dt.Rows) { Dictionary dic = new Dictionary(); foreach (DataColumn dc in dt.Columns) { dic.Add(dc.ColumnName, dr[dc.ColumnName]); } list.Add(dic); } return list; } /// /// 数据集转键值对数组字典 /// /// 键值对数组字典 public static Dictionary>> DataSetToDic(DataSet ds) { Dictionary>> result = new Dictionary>>(); foreach (DataTable dt in ds.Tables) result.Add(dt.TableName, DataTableToList(dt)); return result; } /// /// 数据表转JSON /// /// 数据表 /// JSON字符串 public static string DataTableToJson(DataTable dt) { return ObjectToJson(DataTableToList(dt)); } /// /// JSON文本转对象,泛型方法 常用 /// /// 类型 /// JSON文本 /// 指定类型的对象 public static T JsonToObject(string jsonText) { return JsonConvert.DeserializeObject(jsonText); } /// /// 将JSON文本转换为数据表数据 /// /// JSON文本 /// 数据表字典 public static Dictionary>> TablesDataFromJson(string jsonText) { return JsonToObject>>>(jsonText); } /// /// 将JSON文本转换成数据行 /// /// JSON文本 /// 数据行的字典 public static Dictionary DataRowFromJson(string jsonText) { return JsonToObject>(jsonText); } } }