wenxiangchao
2026-11-02 9d1660270272180cd71147d6ddd53d1382643d2e
Plugin.TestResult/SingleCell.xaml.cs
@@ -1,4 +1,13 @@
using HMI.Util;
using CSVHelper;
using HMI.Core.Entity;
using HMI.Core.Manager;
using HMI.Core.Setting;
using HMI.Core.Util;
using HMI.UI.Util;
using HMI.Util;
using PLCHelper;
using Plugin.TestResult;
using Plugin.TestResult.Util;
using Plugin.TestResult_WPF.Constant;
using Plugin.TestResult_WPF.Model;
using System;
@@ -6,6 +15,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Dynamic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Windows;
@@ -35,34 +45,105 @@
        }
        #endregion
        private static readonly HashSet<string> IgnoreTestItem = new HashSet<string> {
            "产品条码","checkin","预检电流","precheckresult","checkout",
        };
        private InfoWindow window;
        private int maxSize;
        public SingleCell()
        {
            DataContext = this;
            InitializeComponent();
        }
        public DataTable table { get; private set; }
        public SingleCell(string parentName, int index, int maxSize, string iniFile)
        public SingleCell(DataTable table, string title, int index, int maxSize, string iniFile)
        {
            this.parentName = parentName;
            this.table = table;
            this.title = title;
            this.index = index;
            this.maxSize = maxSize;
            this.countIniPath = iniFile;
            DataContext = this;
            InitializeComponent();
            LoadProbeCount();
            RefreshProbe();
        }
        private string _parentName;
        public string parentName
        public void RefreshProbe()
        {
            get { return _parentName; }
            try
            {
                string key = string.Empty;
                ParameterData value;
                if (ParamSetting.ProbeByModel)
                {
                    string model = table.CbProduct?.SelectedItem?.ToString();
                    key = $"{title}_{model}";
                    value = ProductManager.GetParameterByProductAndName(model, "ProbeWarn");
                    if (value == null)
                    {
                        value = ParameterManager.GetCommonParameterByName("ProbeWarn");
                    }
                    ProbeWarn = value != null ? int.Parse(value.Value) : 1000;
                }
                else
                {
                    key = $"{title}";
                    value = ParameterManager.GetCommonParameterByName("ProbeWarn");
                    ProbeWarn = value != null ? int.Parse(value.Value) : 1000;
                }
                string temp = IniFileHelper.ReadIniData(key, "ProbeCount", "0", countIniPath);
                int count = Convert.ToInt32(temp);
                ProbeCount = count;
            }
            catch
            {
                ProbeWarn = 1000;
            }
            if (window != null) window.UpdateProbeCount(ProbeCount, ProbeWarn);
        }
        public void RefreshCharts()
        {
            charts = new LiveChart[3];
            try
            {
                ParameterData value;
                string model = table.CbProduct?.SelectedItem?.ToString();
                for (int i = 0; i < charts.Length; i++)
                {
                    value = ProductManager.GetParameterByProductAndName(model, $"ChartConfig_{i}");
                    if (value == null)
                    {
                        value = ParameterManager.GetCommonParameterByName($"ChartConfig_{i}");
                    }
                    var config = value != null ? value.Value : null;
                    if (string.IsNullOrEmpty(config))
                    {
                        charts[i] = null;
                    }
                    else
                    {
                        charts[i] = new LiveChart(config) //new string[] { "温度(℃)", "流量(L/m)" }
                        {
                            MinHeight = 120
                        };
                    }
                }
            }
            catch
            {
                charts = new LiveChart[0];
            }
        }
        private string _sn;
        public string sn
        {
            get { return _sn; }
            set
            {
                RaiseAndSetIfchanged(ref _parentName, value);
                RaisePropertyChanged("title");
                RaiseAndSetIfchanged(ref _sn, value);
                RaisePropertyChanged("sn");
            }
        }
@@ -78,7 +159,36 @@
            }
        }
        public string title => $"{parentName}{index + 1}";
        private bool cellIsDisabled;
        public bool CellIsDisabled
        {
            get { return cellIsDisabled; }
            set
            {
                RaiseAndSetIfchanged(ref cellIsDisabled, value);
            }
        }
        private string _title;
        public string title
        {
            get => _title;
            set
            {
                RaiseAndSetIfchanged(ref _title, value);
            }
        }
        private int _probeWarn;
        public int ProbeWarn
        {
            get => _probeWarn;
            set
            {
                RaiseAndSetIfchanged(ref _probeWarn, value);
            }
        }
        private string _status = CommonStatus.WAITING;
@@ -106,6 +216,8 @@
        private ConcurrentQueue<Info> queue = new ConcurrentQueue<Info>();
        private List<Info> allInfos = new List<Info>();
        private ObservableCollection<Info> _infos = new ObservableCollection<Info>();
        public ObservableCollection<Info> infos
@@ -129,31 +241,38 @@
            set
            {
                RaiseAndSetIfchanged(ref probeCount, value);
                probeAlarm = value >= ProbeWarn;
            }
        }
        public void LoadProbeCount()
        private bool _probeAlarm;
        public bool probeAlarm
        {
            string temp = IniFileHelper.ReadIniData($"{title}", "ProbeCount", "", countIniPath);
            if (!string.IsNullOrEmpty(temp))
            get => _probeAlarm;
            set
            {
                int count = Convert.ToInt32(temp);
                ProbeCount = count;
                RaiseAndSetIfchanged(ref _probeAlarm, value);
            }
        }
        private void UpdateProbeCount(int count)
        {
            ProbeCount = count;
            IniFileHelper.WriteIniData($"{title}", "ProbeCount", ProbeCount.ToString(), countIniPath);
            if (window != null) window.UpdateProbeCount(ProbeCount);
            string key = $"{title}";
            if (ParamSetting.ProbeByModel)
            {
                string model = table?.CbProduct?.SelectedItem?.ToString();
                key = $"{title}_{model}";
            }
            IniFileHelper.WriteIniData(key, "ProbeCount", ProbeCount.ToString(), countIniPath);
            if (window != null) window.UpdateProbeCount(ProbeCount, ProbeWarn);
        }
        private void UserControl_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (window == null)
            {
                window = new InfoWindow(title, infos, electricChart, ProbeCount);
                window = new InfoWindow(title, infos, charts, ProbeCount, ProbeWarn);
                window.Closed += Window_Closed;
                window.ClearProbeCountEvent += Window_ClearProbeCountEvent;
                window.Owner = Window.GetWindow(this);
@@ -175,27 +294,148 @@
            this.window = null;
        }
        private string visualTestId;
        private Sqlite3Helper helper;
        private void InitCurrentTestHelper()
        {
            if (helper == null)
            {
                var now = DateTime.Now;
                string dateStr = now.ToString("yyyyMMdd");
                visualTestId = $"{title}_{now.ToString("yyyyMMddHHmmssfff")}";
                helper = CheckSqlHelper(dateStr);
            }
        }
        public void SetStatus(string status)
        {
            this.status = status;
            if (status == "testing")
            Dispatcher.Invoke(() =>
            {
                UpdateProbeCount(ProbeCount + 1);
                var oldStatus = this.status;
                this.status = status;
                if (oldStatus != "testing" && status == "testing")
                {
                    UpdateProbeCount(ProbeCount + 1);
                    InitCurrentTestHelper();
                    InsertARecord();
                }
                if (oldStatus != "ok" && status == "ok")
                {
                    SaveInfoToDB();
                }
                if (oldStatus != "ng" && status == "ng")
                {
                    SaveInfoToDB();
                }
            });
        }
        private void InsertARecord()
        {
            try
            {
                string model = table?.CbProduct?.SelectedItem?.ToString();
                var timestr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                var sql = $"INSERT INTO testResult (sn,model,station,position,result,time,resultId) VALUES ('{sn}','{model}','','{title}','{this.status}','{timestr}','{visualTestId}');";
                helper.Execute(sql);
            }
            catch (Exception ex)
            {
                ViewControl.Logger.Error($"Cell[{title}] InsertARecord Error.", ex);
            }
        }
        public void WriteCSV(Info info)
        {
            //try
            //{
            //    if (ParamSetting.CustomerCode != "LIXUN")
            //    {
            //        return;
            //    }
            //    string fileName = this.sn?.Replace("/", "#")?.Replace("\\", "#") + ".csv";
            //    string dir = Path.Combine(ParamSetting.DataLogFolder, "csv", this.title);
            //    string title = $"{this.lang("Test.Name")},{this.lang("Test.Value")},{this.lang("Test.LimitDown")},{this.lang("Test.LimitUp")},{this.lang("Test.Unit")},{this.lang("Test.Result")},{this.lang("Test.TestTime")}";
            //    string line = $"{info.step},{info.value},{info.limitDown},{info.limitUp},{info.unit},{info.result},{info.updateTime}";
            //    CSVPrinter.Print(dir, fileName, title, line);
            //    // ReverseCSV(Path.Combine(dir, fileName));
            //}
            //catch (Exception ex)
            //{
            //}
        }
        public void SendToChart(Info info)
        {
            try
            {
                foreach (var chart in charts)
                {
                    if (chart?.CanHandle(info.step) == true)
                    {
                        chart.AddData(info.step, DateTime.Parse(info.updateTime), double.Parse(info.value));
                    }
                }
                //if (electricChart.CanHandle(info.step))
                //{
                //    electricChart.AddData(info.step, DateTime.Parse(info.updateTime), double.Parse(info.value));
                //}
                //if (vChart.CanHandle(info.step))
                //{
                //    vChart.AddData(info.step, DateTime.Parse(info.updateTime), double.Parse(info.value));
                //}
                //if (waterChart?.CanHandle(info.step) == true)
                //{
                //    waterChart?.AddData(info.step, DateTime.Parse(info.updateTime), double.Parse(info.value));
                //}
            }
            catch (Exception ex)
            {
            }
        }
        public void SetInfos(Info info)
        {
            if (queue.Count >= maxSize)
            string sql = string.Empty;
            try
            {
                queue.TryDequeue(out var first);
                queue.Enqueue(info);
                this.infos = new ObservableCollection<Info>(queue);
                if (window != null) window.UpdateSource(this.infos);
            }
            else
            {
                queue.Enqueue(info);
                allInfos.Add(info);
                SendToChart(info);
                WriteCSV(info);
                /// 目前先不限制数量,后续如果数据过多导致性能问题再考虑限制数量
                //if (queue.Count >= maxSize)
                //{
                //    queue.TryDequeue(out var first);
                //    queue.Enqueue(info);
                //    this.infos = new ObservableCollection<Info>(queue);
                //    if (window != null) window.UpdateSource(this.infos);
                //}
                //else
                //{
                //    queue.Enqueue(info);
                //    if (window != null)
                //    {
                //        window.Dispatcher.Invoke(() =>
                //        {
                //            this.infos.Add(info);
                //        });
                //    }
                //    else
                //    {
                //        Dispatcher.Invoke(() =>
                //        {
                //            this.infos.Add(info);
                //        });
                //    }
                //}
                if (window != null)
                {
                    window.Dispatcher.Invoke(() =>
@@ -210,34 +450,123 @@
                        this.infos.Add(info);
                    });
                }
                return;
                Dispatcher.Invoke(() =>
                {
                    string dateStr = string.Empty;
                    try
                    {
                        dateStr = DateTime.Parse(info.updateTime).ToString("yyyy-MM-dd HH:mm:ss");
                    }
                    catch
                    {
                        dateStr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                    }
                    try
                    {
                        InitCurrentTestHelper();
                        string model = table?.CbProduct?.SelectedItem?.ToString();
                        sql = $@"INSERT INTO serialData (sn,model,station,position,step,limitDown,limitUp,unit,value,status,finalStatus,time,resultId)
VALUES ('{sn}','{model}','','{this.title}','{info.step}','{info.limitDown}','{info.limitUp}','{info.unit}','{info.value}','{info.result}',
NULL,'{dateStr}','{visualTestId}');";
                        helper.Execute(sql);
                    }
                    catch (Exception ex)
                    {
                        ViewControl.Logger.Error($"Save DB Test Data Error. {sql}", ex);
                    }
                });
            }
            catch (Exception ex)
            {
                ViewControl.Logger.Error($"Add Test Data Error. {sql}", ex);
            }
        }
        public void ClearInfo()
        {
            allInfos.Clear();
            queue = new ConcurrentQueue<Info>();
            var list = new ObservableCollection<Info>(queue);
            this.infos = list;
            if (window != null) window.UpdateSource(this.infos);
        }
        private Chart electricChart = new Chart("电流曲线(A)", false, 20);
        public void AddElectricData(double data)
        //private Chart waterChart = null;
        //private Chart electricChart = new Chart(LangUtil.Get("Tr.CurrentChart"), false, 20)
        //{
        //    Height = 120
        //};
        //private Chart vChart = new Chart(LangUtil.Get("Tr.VoltChart"), false, 20)
        //{
        //    Height = 120
        //};
        private LiveChart[] charts = new LiveChart[0];
        //private LiveChart waterChart = null;
        //private LiveChart electricChart = new LiveChart("子板电流,电流(A);母板电流,电流(A)") //new string[] { "子板电流", "模板电流" }
        //{
        //    MinHeight = 120
        //};
        //private LiveChart vChart = new LiveChart("子板电压,电压(V);母板电压,电压(V)") //new string[] { "子板电压", "模板电压" }
        //{
        //    MinHeight = 120
        //};
        public void AddWaterData(double temp, double backTemp, double pressure)
        {
            electricChart.AddData(data);
            //waterChart?.AddData(0, "水箱温度", temp);
            //waterChart?.AddData(0, "回水温度", backTemp);
            //waterChart?.AddData(1, "流量", pressure);
            //waterChart?.AddData("水箱温度", temp);
            //waterChart?.AddData("回水温度", backTemp);
            //waterChart?.AddData("流量", pressure);
        }
        public void ClearElectricData()
        public void AddElectricData(double data)
        {
            electricChart.Clear();
            //electricChart.AddData("", data);
        }
        public void AddVData(double data)
        {
            //vChart.AddData("", data);
        }
        public void ClearChart()
        {
            foreach (var chart in charts)
            {
                chart?.Clear();
            }
        }
        //public void ClearWaterData()
        //{
        //    waterChart?.Clear();
        //}
        //public void ClearElectricData()
        //{
        //    electricChart.Clear();
        //}
        //public void ClearVData()
        //{
        //    vChart.Clear();
        //}
        public void SaveElectricDataToCSV(string filePath)
        {
            try
            {
                List<double> datas = electricChart?.GetSingleData();
                List<double> datas = charts[1]?.GetSingleData("");
                FileInfo fi = new FileInfo(filePath);
                if (!fi.Directory.Exists)
@@ -248,7 +577,7 @@
                using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                using (StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8))
                {
                    string title = "电流数据(A)";
                    string title = this.lang("Tr.CurrentChart");
                    sw.WriteLine(title);
                    if (datas != null)
                    {
@@ -264,5 +593,587 @@
                Console.WriteLine(ex.ToString());
            }
        }
        public void SaveVDataToCSV(string filePath)
        {
            try
            {
                List<double> datas = charts[2]?.GetSingleData("");
                FileInfo fi = new FileInfo(filePath);
                if (!fi.Directory.Exists)
                {
                    fi.Directory.Create();  //文件不存在,创建文件
                }
                using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                using (StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8))
                {
                    string title = this.lang("Tr.VoltChart");
                    sw.WriteLine(title);
                    if (datas != null)
                    {
                        for (int i = 0; i < datas.Count; i++)
                        {
                            sw.WriteLine(datas[i].ToString());
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        public void NormalCSV(string filePath)
        {
            try
            {
                FileInfo fi = new FileInfo(filePath);
                if (!fi.Directory.Exists)
                {
                    fi.Directory.Create();  //文件不存在,创建文件
                }
                using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                using (StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8))
                {
                    string title = $"{this.lang("Test.Name")},{this.lang("Test.Value")},{this.lang("Test.LimitDown")},{this.lang("Test.LimitUp")},{this.lang("Test.Unit")},{this.lang("Test.Result")},{this.lang("Test.TestTime")}";
                    sw.WriteLine(title);
                    foreach (var info in allInfos)
                    {
                        string row = $"{info.step},{info.value},{info.limitDown},{info.limitUp},{info.unit},{info.result},{info.updateTime}";
                        sw.WriteLine(row);
                    }
                }
            }
            catch (Exception ex)
            {
                ViewControl.Logger.Error($"Cell[{title}] SaveInfoToCSV Error.", ex);
            }
        }
        public void ReverseCSV_Bak(string filePath)
        {
            try
            {
                if (allInfos == null || allInfos.Count < 4) return;
                Dictionary<string, int> columnMap = new Dictionary<string, int>();
                int colPoint = 0;
                List<string> titleRow = new List<string>();
                List<string[]> datas = new List<string[]>();
                void AddTitle(string title)
                {
                    if (titleRow.IndexOf(title) < 0)
                    {
                        titleRow.Add(title);
                    }
                }
                // 先设置表头
                for (int row = 0; row < allInfos.Count; row++)
                {
                    var info = allInfos[row];
                    if (IgnoreTestItem.Contains(info.step.ToLower()))
                    {
                        continue;
                    }
                    string title = $"{info.step}{(string.IsNullOrEmpty(info.unit) ? "" : $"({info.unit})")}";
                    AddTitle("测试时间");
                    AddTitle(title);
                    if (!string.IsNullOrEmpty(info.limitDown))
                    {
                        string key2 = $"{info.step}下限";
                        AddTitle(key2);
                    }
                    if (!string.IsNullOrEmpty(info.limitUp))
                    {
                        string key2 = $"{info.step}上限";
                        AddTitle(key2);
                    }
                    if (!string.IsNullOrEmpty(info.limitUp))
                    {
                        string key2 = $"{info.step}测试结果";
                        AddTitle(key2);
                    }
                    //if (!string.IsNullOrEmpty(info.updateTime))
                    //{
                    //    string key2 = $"{info.step}测试时间";
                    //    AddTitle(key2);
                    //}
                }
                int rowPoint = -1;
                for (int row = 0; row < allInfos.Count; row++)
                {
                    var info = allInfos[row];
                    if (IgnoreTestItem.Contains(info.step.ToLower()))
                    {
                        continue;
                    }
                    string title = $"{info.step}{(string.IsNullOrEmpty(info.unit) ? "" : $"({info.unit})")}";
                    int col = titleRow.IndexOf(title);
                    if (col == 1)
                    {
                        rowPoint++;
                    }
                    if (datas.Count <= rowPoint)
                    {
                        datas.Add(new string[titleRow.Count]);
                    }
                    var arr = datas[rowPoint];
                    arr[col] = info.value;
                    if (!string.IsNullOrEmpty(info.limitDown))
                    {
                        string key2 = $"{info.step}下限";
                        int col2 = titleRow.IndexOf(key2);
                        arr[col2] = info.limitDown;
                    }
                    if (!string.IsNullOrEmpty(info.limitUp))
                    {
                        string key2 = $"{info.step}上限";
                        int col2 = titleRow.IndexOf(key2);
                        arr[col2] = info.limitUp;
                    }
                    if (!string.IsNullOrEmpty(info.limitUp))
                    {
                        string key2 = $"{info.step}测试结果";
                        int col2 = titleRow.IndexOf(key2);
                        arr[col2] = info.result;
                    }
                    if (!string.IsNullOrEmpty(info.updateTime))
                    {
                        string key2 = "测试时间";// $"{info.step}测试时间";
                        int col2 = titleRow.IndexOf(key2);
                        arr[col2] = info.updateTime;
                    }
                }
                FileInfo fi = new FileInfo(filePath);
                if (!fi.Directory.Exists)
                {
                    fi.Directory.Create();  //文件不存在,创建文件
                }
                using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                using (StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8))
                {
                    string title = string.Join(",", titleRow);
                    sw.WriteLine(title);
                    foreach (var info in datas)
                    {
                        string row = string.Join(",", info);
                        sw.WriteLine(row);
                    }
                }
            }
            catch (Exception ex)
            {
                ViewControl.Logger.Error($"Cell[{title}] SaveInfoToCSV Error.", ex);
            }
        }
        public void ReverseCSV(string filePath)
        {
            try
            {
                if (allInfos == null || allInfos.Count < 4) return;
                Dictionary<string, int> columnMap = new Dictionary<string, int>();
                int colPoint = 0;
                List<string> titleRow = new List<string>();
                List<string[]> datas = new List<string[]>();
                List<string> timeRow = new List<string>();
                void AddTitle(string title)
                {
                    if (titleRow.IndexOf(title) < 0)
                    {
                        titleRow.Add(title);
                    }
                }
                // 先设置表头
                for (int i = 0; i < allInfos.Count; i++)
                {
                    var info = allInfos[i];
                    if (IgnoreTestItem.Contains(info.step.ToLower()))
                    {
                        continue;
                    }
                    string testTime = info.updateTime;
                    int rowIndex = timeRow.IndexOf(testTime);
                    if (rowIndex < 0)
                    {
                        timeRow.Add(testTime);
                    }
                    string title = $"{info.step}{(string.IsNullOrEmpty(info.unit) ? "" : $"({info.unit})")}";
                    AddTitle("测试时间");
                    AddTitle(title);
                    if (!string.IsNullOrEmpty(info.limitDown))
                    {
                        string key2 = $"{info.step}下限";
                        AddTitle(key2);
                    }
                    if (!string.IsNullOrEmpty(info.limitUp))
                    {
                        string key2 = $"{info.step}上限";
                        AddTitle(key2);
                    }
                    if (!string.IsNullOrEmpty(info.limitUp))
                    {
                        string key2 = $"{info.step}测试结果";
                        AddTitle(key2);
                    }
                    //if (!string.IsNullOrEmpty(info.updateTime))
                    //{
                    //    string key2 = $"{info.step}测试时间";
                    //    AddTitle(key2);
                    //}
                }
                for (int i = 0; i < allInfos.Count; i++)
                {
                    var info = allInfos[i];
                    if (IgnoreTestItem.Contains(info.step.ToLower()))
                    {
                        continue;
                    }
                    string testTime = info.updateTime;
                    int row = timeRow.IndexOf(testTime);
                    if (row < 0)
                    {
                        continue;
                    }
                    string title = $"{info.step}{(string.IsNullOrEmpty(info.unit) ? "" : $"({info.unit})")}";
                    int col = titleRow.IndexOf(title);
                    if (datas.Count <= row)
                    {
                        datas.Add(new string[titleRow.Count]);
                    }
                    var arr = datas[row];
                    arr[col] = info.value;
                    if (!string.IsNullOrEmpty(info.limitDown))
                    {
                        string key2 = $"{info.step}下限";
                        int col2 = titleRow.IndexOf(key2);
                        arr[col2] = info.limitDown;
                    }
                    if (!string.IsNullOrEmpty(info.limitUp))
                    {
                        string key2 = $"{info.step}上限";
                        int col2 = titleRow.IndexOf(key2);
                        arr[col2] = info.limitUp;
                    }
                    if (!string.IsNullOrEmpty(info.limitUp))
                    {
                        string key2 = $"{info.step}测试结果";
                        int col2 = titleRow.IndexOf(key2);
                        arr[col2] = info.result;
                    }
                    if (!string.IsNullOrEmpty(info.updateTime))
                    {
                        string key2 = "测试时间";// $"{info.step}测试时间";
                        int col2 = titleRow.IndexOf(key2);
                        arr[col2] = info.updateTime;
                    }
                }
                FileInfo fi = new FileInfo(filePath);
                if (!fi.Directory.Exists)
                {
                    fi.Directory.Create();  //文件不存在,创建文件
                }
                using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                using (StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8))
                {
                    string title = string.Join(",", titleRow);
                    sw.WriteLine(title);
                    foreach (var info in datas)
                    {
                        string row = string.Join(",", info);
                        sw.WriteLine(row);
                    }
                }
            }
            catch (Exception ex)
            {
                ViewControl.Logger.Error($"Cell[{title}] SaveInfoToCSV Error.", ex);
            }
        }
        /// <summary>
        /// 保存测试数据到CSV
        /// </summary>
        /// <param name="filePath"></param>
        public void SaveInfoToCSV(string filePath)
        {
            if (ParamSetting.ReverseCSV)
            {
                ReverseCSV(filePath);
            }
            else
            {
                NormalCSV(filePath);
            }
        }
        private Sqlite3Helper CheckSqlHelper(string dateStr = null)
        {
            dateStr = string.IsNullOrEmpty(dateStr) ? DateTime.Now.ToString("yyyyMMdd") : dateStr;
            string dbPath = Path.Combine(ParamSetting.DataLogFolder, $"Data_{dateStr}.db");
            if (!File.Exists(dbPath))
            {
                Sqlite3Helper.CreateDatabase(dbPath);
            }
            var sqliteHelper = new Sqlite3Helper(dbPath);
            sqliteHelper.Execute(@"CREATE TABLE IF NOT EXISTS serialData (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    sn TEXT NOT NULL,
                    model TEXT,
                    station TEXT NOT NULL,
                    step TEXT NOT NULL,
                    position TEXT,
                    limitDown TEXT,
                    limitUp TEXT,
                    unit TEXT,
                    offset TEXT,
                    value TEXT,
                    status TEXT,
                    finalStatus TEXT,
                    consumeTime TEXT,
                    totalConsumeTime TEXT,
                    resultId TEXT,
                    time DATETIME NOT NULL);");
            sqliteHelper.Execute(@"CREATE TABLE IF NOT EXISTS testResult (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    sn TEXT NOT NULL,
                    model TEXT,
                    station TEXT NOT NULL,
                    position TEXT,
                    status TEXT,
                    result TEXT NOT NULL,
                    resultId TEXT,
                    time DATETIME NOT NULL);");
            if (!sqliteHelper.HasData("SELECT 1 FROM pragma_table_info('serialData') WHERE name = 'resultId';"))
            {
                sqliteHelper.Execute("ALTER TABLE serialData ADD resultId TEXT;");
            }
            if (!sqliteHelper.HasData("SELECT 1 FROM pragma_table_info('testResult') WHERE name = 'resultId';"))
            {
                sqliteHelper.Execute("ALTER TABLE testResult ADD resultId TEXT;");
            }
            return sqliteHelper;
        }
        /// <summary>
        /// 保存测试数据到Sqlite
        /// </summary>
        /// <param name="filePath"></param>
        public void SaveInfoToDB()
        {
            Dispatcher.Invoke(() =>
            {
                try
                {
                    string model = table?.CbProduct?.SelectedItem?.ToString();
                    var timestr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                    //var sql = $"INSERT INTO testResult (sn,model,station,position,result,time,resultId) VALUES ('{sn}','{model}','','{title}','{this.status}','{timestr}','{visualTestId}');";
                    var sql = $"UPDATE testResult SET time = '{timestr}', result = '{this.status}' WHERE resultId = '{visualTestId}'";
                    helper.Execute(sql);
                    helper.Dispose();
                    helper = null;
                    //                using (var helper = CheckSqlHelper())
                    //                {
                    //                    List<string> sqls = new List<string>();
                    //                    var timestr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                    //                    foreach (var info in allInfos)
                    //                    {
                    //                        string sql = $@"INSERT INTO serialData (sn,station,step,limitDown,limitUp,unit,value,status,finalStatus,time)
                    //VALUES ('{sn}','','{info.step}','{info.limitDown}','{info.limitUp}','{info.unit}','{info.value}','{info.result}','{this.status}','{timestr}');";
                    //                        sqls.Add(sql);
                    //                    }
                    //                    sqls.Add($"INSERT INTO testResult (sn,station,position,result,time) VALUES ('{sn}','','{title}','{this.status}','{timestr}');");
                    //                    helper.ExecuteBatchSql(sqls);
                    //                }
                }
                catch (Exception ex)
                {
                    ViewControl.Logger.Error($"Cell[{title}] SaveToDB Error.", ex);
                }
            });
        }
        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            var item = sender as MenuItem;
            switch (item?.Name)
            {
                case "clearSNRItem":
                    table.TryClearCellSN(this.index);
                    break;
                case "exportCSVItem":
                    TryExportCSV();
                    break;
                case "manualDebugItem":
                    OpenManualDebugWindow();
                    break;
                default:
                    break;
            }
        }
        /// <summary>
        /// 打开手动调试窗口
        /// </summary>
        private void OpenManualDebugWindow()
        {
            string manualDebugSeq = ParameterManager.GetCommonParameterByName("ManualDebugSeqPath")?.Value;
            if (string.IsNullOrEmpty(manualDebugSeq))
            {
                MsgBoxHelper2.Error("请先设置手动调试序列路径[ManualDebugSeqPath]!");
                return;
            }
            string modelPath = table.parent.testModelFile;
            int dutNo = table.index * table.cellCount + this.index;
            var win = new ManualDebugWindow(manualDebugSeq, modelPath)
            {
                Title = $"{this.title}手动调试",
                Owner = Window.GetWindow(this),
                OvenIndex = this.table.index,
                OvenName = this.table.title,
                CellIndex = dutNo,
                CellName = this.title
            };
            win.ShowDialog();
        }
        /// <summary>
        /// 尝试导出CSV
        /// </summary>
        private void TryExportCSV()
        {
            System.Windows.Forms.SaveFileDialog sfd = new System.Windows.Forms.SaveFileDialog
            {
                Filter = "CSV (*.csv)|*.csv"
            };
            if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                this.NormalCSV(sfd.FileName);
            }
        }
        public void ClearSN()
        {
            sn = string.Empty;
            LightGreen(false, out _);
            LightRed(false, out _);
        }
        public bool LightGreen(bool on, out string msg)
        {
            string key = $"Oven{table.index + 1}_Cell{index + 1}_Light_OK";
            bool res = S7Context.WriteData(RunTimeVariablePool.DEFAULT_PLC_NAME, key, on, out msg);
            if (res)
            {
                ViewControl.Logger.Debug($"Set Light [{key}] {on}.");
            }
            else
            {
                ViewControl.Logger.Debug($"Open Light [{key}] {on} Error.{msg}");
            }
            return res;
        }
        public bool LightRed(bool on, out string msg)
        {
            return S7Context.WriteData(RunTimeVariablePool.DEFAULT_PLC_NAME,
                $"Oven{table.index + 1}_Cell{index + 1}_Light_NG", on, out msg);
        }
        private void OnPreviewMouseRightButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            ContextMenu contextMenu = new ContextMenu();
            contextMenu.Closed += ContextMenu_Closed;
            //<  />
            //<
            //< MenuItem IsCheckable = "False" x: Name = "manualDebugItem" Click = "MenuItem_Click" Header = "手动调试" >
            //    < MenuItem.Style >
            //        < Style TargetType = "MenuItem" BasedOn = "{StaticResource {x:Static pu:StyleKeys.MenuItemStyle}}" >
            //        </ Style >
            //    </ MenuItem.Style >
            //</ MenuItem >
            var item = new MenuItem
            {
                IsCheckable = false,
                IsEnabled = !table.IsTesting,
                Name = "clearSNRItem",
                Header = this.lang("Tr.ClearSNR"),
            };
            item.Click += MenuItem_Click;
            contextMenu.Items.Add(item);
            item = new MenuItem
            {
                IsCheckable = false,
                Name = "exportCSVItem",
                Header = this.lang("App.ExportCSV"),
            };
            item.Click += MenuItem_Click;
            contextMenu.Items.Add(item);
            if (table.parent.inManualDebugMode)
            {
                item = new MenuItem
                {
                    IsCheckable = false,
                    Name = "manualDebugItem",
                    Header = this.lang("手动调试"),
                };
                item.Click += MenuItem_Click;
                contextMenu.Items.Add(item);
            }
            this.ContextMenu = contextMenu;
        }
        private void ContextMenu_Closed(object sender, RoutedEventArgs e)
        {
            this.ContextMenu = null;
        }
    }
}