alielie
2025-11-24 9211ec11c112e18cd99e77f889a01110a70031ce
Plugin.DataBoard/DataBoard.xaml.cs
@@ -1,13 +1,18 @@
using HMI.Base;
using HMI.Core.Entity;
using HMI.Core.Manager;
using HMI.Core.Util;
using HMI.UI.Util;
using HMI.Util;
using Microsoft.Web.WebView2.Core;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
@@ -22,6 +27,7 @@
        {
            DataContext = this;
            InitializeComponent();
            webview2.DefaultBackgroundColor = Color.Transparent;//Color.FromArgb(243, 249, 255);
        }
        private ObservableCollection<OptionData> _options = new ObservableCollection<OptionData> {
@@ -37,9 +43,78 @@
            set { Set(ref _options, value); }
        }
        private string iniFile;
        public override void InitFinish()
        {
            iniFile = Path.Combine(BaseFolder, "Config.ini");
            if (!File.Exists(iniFile))
            {
                File.Create(iniFile);
            }
            LoadProduct();
        }
        private void PluginControl_Loaded(object sender, RoutedEventArgs e)
        {
        }
        private void LoadProduct()
        {
            List<ProductData> products = ProductManager.GetProducts<List<ProductData>>()
               ?? new List<ProductData>();
            this.modelSelect.Items.Clear();
            List<string> productSource = new List<string>();
            foreach (var prd in products)
            {
                this.modelSelect.Items.Add(prd.Name);
                productSource.Add(prd.Name);
            }
            string model = IniFileHelper.ReadIniData("Config", "Model", "", iniFile);
            if (!string.IsNullOrEmpty(model))
            {
                this.modelSelect.SelectedItem = model;
            }
            else if (products.Count > 0)
            {
                this.modelSelect.SelectedIndex = 0;
            }
        }
        private void RefreshAll()
        {
            try
            {
                var start0 = dtp00.SelectedDateTime ?? DateTime.Now;
                var end0 = dtp01.SelectedDateTime ?? DateTime.Now;
                RefreshChart0(start0, end0);
            }
            catch { }
            try
            {
                var start1 = dtp10.SelectedDateTime ?? DateTime.Now;
                var end1 = dtp11.SelectedDateTime ?? DateTime.Now;
                RefreshChart1(start1, end1);
            }
            catch { }
            try
            {
                var start2 = dtp20.SelectedDateTime ?? DateTime.Now;
                var end2 = dtp21.SelectedDateTime ?? DateTime.Now;
                RefreshChart2(start2, end2);
            }
            catch { }
            try
            {
                var start3 = dtp30.SelectedDateTime ?? DateTime.Now;
                var end3 = dtp31.SelectedDateTime ?? DateTime.Now;
                RefreshChart3(start3, end3);
            }
            catch { }
        }
        private void Button_Click(object sender, RoutedEventArgs e)
@@ -48,6 +123,9 @@
            DateTime start, end;
            switch (btn.Name)
            {
                case "btnAll":
                    RefreshAll();
                    break;
                case "btn0":
                    start = dtp00.SelectedDateTime ?? DateTime.Now;
                    end = dtp01.SelectedDateTime ?? DateTime.Now;
@@ -71,17 +149,46 @@
                default:
                    break;
            }
        }
        private List<SerialData> SelectSerialDataByTime(DateTime start, DateTime end)
        public static string[] GetDbFiles(string folderPath, DateTime startTime, DateTime endTime)
        {
            string[] files = DbFileHelper.GetDbFiles(BaseFolder, start, end);
            if (!Directory.Exists(folderPath))
            {
                return new string[0];
            }
            string startName = $"Data_{startTime.ToString("yyyyMMdd")}";
            string endName = $"Data_{endTime.ToString("yyyyMMdd")}";
            var oldFiles = Directory.GetFiles(folderPath, "Data_*.db");
            oldFiles = oldFiles.Where(file =>
            {
                var fileName = Path.GetFileNameWithoutExtension(file);
                bool flag = true;
                if (startTime != null) flag &= (string.Compare(fileName, startName) == 1 || fileName == startName);
                if (endTime != null) flag &= (string.Compare(endName, fileName) == 1 || fileName == endName);
                return flag;
            }).ToArray();
            return oldFiles;
        }
        private List<SerialData> SelectSerialDataByTime(string model, DateTime start, DateTime end)
        {
            var s1 = DateTime.Now;
            string[] files = GetDbFiles(BaseFolder, start, end);
            if (files == null || files.Length <= 0)
            {
                return new List<SerialData>();
            }
            string sql = $"SELECT * FROM serialData WHERE time BETWEEN '{start:yyyy-MM-dd HH:mm:ss}' AND '{end:yyyy-MM-dd HH:mm:ss}';";
            string segment = string.Empty;
            if (!string.IsNullOrEmpty(model))
            {
                segment = $"AND model = '{model}'";
            }
            string sql = $@"SELECT * FROM serialData WHERE time BETWEEN '{start:yyyy-MM-dd HH:mm:ss}' AND '{end:yyyy-MM-dd HH:mm:ss}'
{segment} ORDER BY time DESC;";
            DataTable dt = new DataTable();
            foreach (string file in files)
@@ -89,6 +196,38 @@
                using (SqliteHelper helper = new SqliteHelper(file))
                {
                    dt.Merge(helper.GetDataTable(sql));
                }
            }
            var s2 = DateTime.Now;
            log.Info($"SelectSerialDataByTime Cast: {(s2 - s1).TotalMilliseconds}");
            var data = BeanUtil.ReadBeanFromDataTable<SerialData>(dt);
            log.Info($"Bean Cast: {(DateTime.Now - s2).TotalMilliseconds}");
            return data;
        }
        private List<SerialData> SelectResultDataByTime(string model, DateTime start, DateTime end)
        {
            string[] files = GetDbFiles(BaseFolder, start, end);
            if (files == null || files.Length <= 0)
            {
                return new List<SerialData>();
            }
            string segment = string.Empty;
            if (!string.IsNullOrEmpty(model))
            {
                segment = $"AND model = '{model}'";
            }
            string sql = $@"SELECT * FROM testResult WHERE time BETWEEN '{start:yyyy-MM-dd HH:mm:ss}' AND '{end:yyyy-MM-dd HH:mm:ss}' {segment};";
            DataTable dt = new DataTable();
            foreach (string file in files)
            {
                using (SqliteHelper helper = new SqliteHelper(file))
                {
                    var temp = helper.GetDataTable(sql);
                    dt.Merge(temp);
                }
            }
            return BeanUtil.ReadBeanFromDataTable<SerialData>(dt);
@@ -115,158 +254,350 @@
            webview2.CoreWebView2?.ExecuteScriptAsync($"resize({width},{height})");
        }
        //private void RefreshChart0(DateTime start, DateTime end)
        //{
        //    dtp00.SelectedDateTime = start;
        //    dtp01.SelectedDateTime = end;
        //    Task.Run(() =>
        //    {
        //        try
        //        {
        //            var st = DateTime.Now;
        //            List<SerialData> datas = SelectSerialDataByTime(start, end);
        //            log.Info($"0 Select Data cast: {(DateTime.Now-st).TotalMilliseconds}");
        //            datas.OrderByDescending(e => e.time);
        //            int all = 0, output = 0;
        //            HashSet<string> snCache = new HashSet<string>();
        //            foreach (var data in datas)
        //            {
        //                if (snCache.Contains(data.sn)) continue;
        //                snCache.Add(data.sn);
        //                all++;
        //                if (data.status == "Passed") output++;
        //            }
        //            var fields = $"['{this.lang("bd.input")}','{this.lang("bd.output")}']";
        //            Dispatcher.BeginInvoke(new Action(() =>
        //            {
        //                webview2.CoreWebView2?.ExecuteScriptAsync($"drawChart0({fields}, [{all},{output}])");
        //            }));
        //        }
        //        catch (Exception ex)
        //        {
        //            log.Error("RefreshChart0 Error.", ex);
        //            ToastHelper.Error("表1刷新失败!");
        //        }
        //    });
        //}
        private void RefreshChart0(DateTime start, DateTime end)
        {
            dtp00.SelectedDateTime = start;
            dtp01.SelectedDateTime = end;
            List<SerialData> datas = SelectSerialDataByTime(start, end);
            datas.OrderByDescending(e => e.time);
            int all = 0, output = 0;
            HashSet<string> snCache = new HashSet<string>();
            foreach (var data in datas)
            string model = modelSelect.SelectedItem?.ToString();
            Task.Run(() =>
            {
                if (snCache.Contains(data.sn)) continue;
                snCache.Add(data.sn);
                all++;
                if (data.status == "Passed") output++;
            }
            var fields = $"['{this.lang("bd.input")}','{this.lang("bd.output")}']";
            webview2.CoreWebView2?.ExecuteScriptAsync($"drawChart0({fields}, [{all},{output}])");
                try
                {
                    Dispatcher.BeginInvoke(new Action(() =>
                    {
                        webview2.CoreWebView2?.ExecuteScriptAsync($"loading0('加载中,请稍后...')");
                    }));
                    List<SerialData> datas = SelectResultDataByTime(model, start, end);
                    datas.OrderByDescending(e => e.time);
                    int all = 0, output = 0;
                    HashSet<string> snCache = new HashSet<string>();
                    foreach (var data in datas)
                    {
                        if (snCache.Contains(data.sn)) continue;
                        snCache.Add(data.sn);
                        all++;
                        if (data.result == "Passed") output++;
                    }
                    var fields = $"['{this.lang("bd.input")}','{this.lang("bd.output")}']";
                    Dispatcher.BeginInvoke(new Action(() =>
                    {
                        webview2.CoreWebView2?.ExecuteScriptAsync($"drawChart0({fields}, [{all},{output}])");
                    }));
                }
                catch (Exception ex)
                {
                    log.Error("RefreshChart0 Error.", ex);
                    ToastHelper.Error("表1刷新失败!");
                }
            });
        }
        private void RefreshChart1(DateTime start, DateTime end)
        {
            dtp10.SelectedDateTime = start;
            dtp11.SelectedDateTime = end;
            List<SerialData> datas = SelectSerialDataByTime(start, end);
            string model = modelSelect.SelectedItem?.ToString();
            Task.Run(() =>
            {
                try
                {
                    Dispatcher.BeginInvoke(new Action(() =>
                    {
                        webview2.CoreWebView2?.ExecuteScriptAsync($"loading1('加载中,请稍后...')");
                    }));
                    List<SerialData> datas = SelectResultDataByTime(model, start, end);
            datas = datas.OrderByDescending(e => e.time).ToList();
            Dictionary<string, int> pieData = new Dictionary<string, int> {
                    datas = datas.OrderByDescending(e => e.time).ToList();
                    Dictionary<string, int?> pieData = new Dictionary<string, int?> {
                { "Passed",0},
                { "Failed",0},
                { "Action",0},
                { "Wait",0},
                //{ "Action",0},
                //{ "Wait",0},
            };
            HashSet<string> snCache = new HashSet<string>();
            foreach (var data in datas)
            {
                if (snCache.Contains(data.sn)) continue;
                snCache.Add(data.sn);
                if (pieData.ContainsKey(data.status))
                {
                    pieData[data.status]++;
                    //if (datas == null || datas.Count <= 0)
                    //{
                    //    pieData = new Dictionary<string, int?> {
                    //    { "Passed",null},
                    //    { "Failed",null},
                    //};
                    //}
                    HashSet<string> snCache = new HashSet<string>();
                    foreach (var data in datas)
                    {
                        if (snCache.Contains(data.sn)) continue;
                        snCache.Add(data.sn);
                        if (pieData.ContainsKey(data.result))
                        {
                            pieData[data.result]++;
                        }
                    }
                    string res = "[";
                    foreach (var key in pieData.Keys)
                    {
                        res += $"{{name:'{key}',value:{pieData[key]}}},";
                    }
                    res += "]";
                    Dispatcher.BeginInvoke(new Action(() =>
                    {
                        webview2.CoreWebView2?.ExecuteScriptAsync($"drawChart1({res})");
                    }));
                }
            }
            string res = "[";
            foreach (var key in pieData.Keys)
            {
                res += $"{{name:'{key}',value:{pieData[key]}}},";
            }
            res += "]";
            webview2.CoreWebView2?.ExecuteScriptAsync($"drawChart1({res})");
                catch (Exception ex)
                {
                    log.Error("RefreshChart1 Error.", ex);
                    ToastHelper.Error("表2刷新失败!");
                }
            });
        }
        //private void RefreshChart2(DateTime start, DateTime end)
        //{
        //    dtp20.SelectedDateTime = start;
        //    dtp21.SelectedDateTime = end;
        //    List<SerialData> datas = SelectSerialDataByTime(start, end);
        //    var groups =
        //        datas.Where(e => e.status == "Passed" || e.status == "Failed").GroupBy(d => d.time.ToString("yyyy-MM-dd"));
        //    Dictionary<string, PassRateData> res = new Dictionary<string, PassRateData>();
        //    foreach (var group in groups)
        //    {
        //        Dictionary<string, string> snStatusCache = new Dictionary<string, string>();
        //        double all = 0, oneTimePass = 0, passed = 0;
        //        var groupDatas = group.ToList();
        //        groupDatas = groupDatas.OrderBy(e => e.time).ToList();
        //        foreach (var data in groupDatas)
        //        {
        //            if (snStatusCache.ContainsKey(data.sn))
        //            {
        //                if (snStatusCache[data.sn] != "Passed" && data.status == "Passed")
        //                {
        //                    passed++;
        //                }
        //                else if (snStatusCache[data.sn] == "Passed" && data.status == "Passed")
        //                {
        //                    if (oneTimePass > 0) oneTimePass--;
        //                }
        //            }
        //            else
        //            {
        //                all++;
        //                if (data.status == "Passed")
        //                {
        //                    passed++;
        //                    oneTimePass++;
        //                }
        //                snStatusCache.Add(data.sn, data.status);
        //            }
        //        }
        //        res.Add(group.Key, new PassRateData
        //        {
        //            time = group.Key,
        //            onePassRate = oneTimePass / all * 100,
        //            passRate = passed / all * 100,
        //        });
        //    }
        //    string fields = "[", vals0 = "[", vals1 = "[";
        //    foreach (var key in res.Keys)
        //    {
        //        fields += $"'{key}',";
        //        vals0 += $"{res[key].onePassRate},";
        //        vals1 += $"{res[key].passRate},";
        //    }
        //    fields += "]";
        //    vals0 += "]";
        //    vals1 += "]";
        //    var names = $"['{this.lang("bd.onePassRate")}','{this.lang("bd.passRate")}']";
        //    webview2.CoreWebView2?.ExecuteScriptAsync($"drawChart2({fields},{names},{vals0},{vals1})");
        //}
        private void RefreshChart2(DateTime start, DateTime end)
        {
            dtp20.SelectedDateTime = start;
            dtp21.SelectedDateTime = end;
            List<SerialData> datas = SelectSerialDataByTime(start, end);
            var groups =
                datas.GroupBy(d => d.time.ToString("yyyy-MM-dd"));
            Dictionary<string, PassRateData> res = new Dictionary<string, PassRateData>();
            foreach (var group in groups)
            string model = modelSelect.SelectedItem?.ToString();
            Task.Run(() =>
            {
                Dictionary<string, string> snStatusCache = new Dictionary<string, string>();
                double all = 0, oneTimePass = 0, passed = 0;
                var groupDatas = group.ToList();
                groupDatas = groupDatas.OrderBy(e => e.time).ToList();
                foreach (var data in groupDatas)
                try
                {
                    if (snStatusCache.ContainsKey(data.sn))
                    Dispatcher.BeginInvoke(new Action(() =>
                    {
                        if (snStatusCache[data.sn] != "Passed" && data.status == "Passed")
                        {
                            passed++;
                        }
                        else if (snStatusCache[data.sn] == "Passed" && data.status == "Passed")
                        {
                            oneTimePass--;
                        }
                    }
                    else
                        webview2.CoreWebView2?.ExecuteScriptAsync($"loading2('加载中,请稍后...')");
                    }));
                    List<SerialData> datas = SelectResultDataByTime(model, start, end);
                    var groups =
                        datas.GroupBy(d => d.time.ToString("yyyy-MM-dd"));
                    Dictionary<string, PassRateData> res = new Dictionary<string, PassRateData>();
                    foreach (var group in groups)
                    {
                        all++;
                        if (data.status == "Passed")
                        Dictionary<string, string> snStatusCache = new Dictionary<string, string>();
                        double all = 0, oneTimePass = 0, passed = 0;
                        var groupDatas = group.ToList();
                        groupDatas = groupDatas.OrderByDescending(e => e.time).ToList();
                        foreach (var data in groupDatas)
                        {
                            passed++;
                            oneTimePass++;
                            if (!snStatusCache.ContainsKey(data.sn))
                            {
                                snStatusCache.Add(data.sn, data.result);
                                all++;
                                if (data.result == "Passed")
                                {
                                    passed++;
                                    oneTimePass++;
                                }
                            }
                            else
                            {
                                if (snStatusCache[data.sn] == "Passed")
                                {
                                    if (oneTimePass > 0) oneTimePass--;
                                    snStatusCache[data.sn] = "NoOnePass";
                                }
                            }
                        }
                        snStatusCache.Add(data.sn, data.status);
                        res.Add(group.Key, new PassRateData
                        {
                            time = group.Key,
                            onePassRate = oneTimePass / all * 100,
                            passRate = passed / all * 100,
                        });
                    }
                    string fields = "[", vals0 = "[", vals1 = "[";
                    foreach (var key in res.Keys)
                    {
                        fields += $"'{key}',";
                        vals0 += $"{res[key].onePassRate},";
                        vals1 += $"{res[key].passRate},";
                    }
                    fields += "]";
                    vals0 += "]";
                    vals1 += "]";
                    var names = $"['{this.lang("bd.onePassRate")}','{this.lang("bd.passRate")}']";
                    Dispatcher.BeginInvoke(new Action(() =>
                    {
                        webview2.CoreWebView2?.ExecuteScriptAsync($"drawChart2({fields},{names},{vals0},{vals1})");
                    }));
                }
                res.Add(group.Key, new PassRateData
                catch (Exception ex)
                {
                    time = group.Key,
                    onePassRate = oneTimePass / all * 100,
                    passRate = passed / all * 100,
                });
            }
            string fields = "[", vals0 = "[", vals1 = "[";
            foreach (var key in res.Keys)
            {
                fields += $"'{key}',";
                vals0 += $"{res[key].onePassRate},";
                vals1 += $"{res[key].passRate},";
            }
            fields += "]";
            vals0 += "]";
            vals1 += "]";
            var names = $"['{this.lang("bd.onePassRate")}','{this.lang("bd.passRate")}']";
            webview2.CoreWebView2?.ExecuteScriptAsync($"drawChart2({fields},{names},{vals0},{vals1})");
                    log.Error("RefreshChart2 Error.", ex);
                    ToastHelper.Error("表3刷新失败!");
                }
            });
        }
        private void RefreshChart3(DateTime start, DateTime end)
        {
            dtp30.SelectedDateTime = start;
            dtp31.SelectedDateTime = end;
            List<SerialData> datas = SelectSerialDataByTime(start, end);
            datas = datas.OrderByDescending(e => e.time).ToList();
            Dictionary<string, int> pieData = new Dictionary<string, int>();
            HashSet<string> snCache = new HashSet<string>();
            foreach (var data in datas)
            string model = modelSelect.SelectedItem?.ToString();
            Task.Run(() =>
            {
                //if (snCache.Contains(data.sn)) continue;
                if (data.status != "Failed") continue;
                snCache.Add(data.sn);
                if (pieData.ContainsKey(data.step))
                try
                {
                    pieData[data.step]++;
                }
                else
                {
                    pieData[data.step] = 1;
                }
            }
            string names = string.Empty, vals = string.Empty;
            foreach (var key in pieData.Keys)
            {
                names += $"'{key}',";
                vals += $"{pieData[key]},";
            }
                    Dispatcher.BeginInvoke(new Action(() =>
                    {
                        webview2.CoreWebView2?.ExecuteScriptAsync($"loading3('加载中,请稍后...')");
                    }));
                    var st = DateTime.Now;
                    List<SerialData> datas = SelectSerialDataByTime(model, start, end);
                    var s2 = DateTime.Now;
                    log.Info($"RefreshChart3 Data Cast {(s2 - st).TotalMilliseconds}");
            webview2.CoreWebView2?.ExecuteScriptAsync($"drawChart3([{names}],[{vals}])");
                    Dictionary<string, SimpleData> pieData = new Dictionary<string, SimpleData>();
                    List<SimpleData> datasource = new List<SimpleData>();
                    //HashSet<string> snCache = new HashSet<string>();
                    foreach (var data in datas)
                    {
                        //if (snCache.Contains(data.sn)) continue;
                        if (data.status != "Failed") continue;
                        if (pieData.ContainsKey(data.step))
                        {
                            pieData[data.step].Value++;
                        }
                        else
                        {
                            pieData[data.step] = new SimpleData
                            {
                                Name = data.step,
                                Value = 1
                            };
                            datasource.Add(pieData[data.step]);
                        }
                    }
                    datasource = datasource.OrderByDescending(e => e.Value).ToList();
                    if (datasource.Count > 10)
                    {
                        datasource = datasource.Take(10).ToList();
                    }
                    var s3 = DateTime.Now;
                    log.Info($"RefreshChart3 Build {(s3 - s2).TotalMilliseconds}");
                    string names = string.Empty, vals = string.Empty;
                    foreach (var data in datasource)
                    {
                        names += $"'{data.Name}',";
                        vals += $"{data.Value},";
                    }
                    Dispatcher.BeginInvoke(new Action(() =>
                    {
                        webview2.CoreWebView2?.ExecuteScriptAsync($"drawChart3([{names}],[{vals}])");
                    }));
                }
                catch (Exception ex)
                {
                    log.Error("RefreshChart3 Error.", ex);
                    ToastHelper.Error("表4刷新失败!");
                }
            });
        }
        private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
@@ -305,5 +636,13 @@
                    break;
            }
        }
        private void modelSelect_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (e.AddedItems.Count > 0)
            {
                IniFileHelper.WriteIniData("Config", "Model", e.AddedItems[0].ToString(), iniFile);
            }
        }
    }
}