using Aitex.Core.RT.Log; using Aitex.Core.UI.ControlDataContext; using Aitex.Core.Util; using Caliburn.Micro; using Caliburn.Micro.Core; using MECF.Framework.Common.CommonData; using MECF.Framework.Common.ControlDataContext; using MECF.Framework.Common.DataCenter; using MECF.Framework.Common.Utilities; using MECF.Framework.UI.Client.CenterViews.Configs.SystemConfig; using MECF.Framework.UI.Client.CenterViews.DataLogs.ProcessHistory; using MECF.Framework.UI.Client.CenterViews.Dialogs; using MECF.Framework.UI.Client.ClientBase; using OpenSEMI.ClientBase; using SciChart.Charting.Visuals; using SciChart.Charting.Visuals.Annotations; using SciChart.Charting.Visuals.Axes; using SciChart.Charting.Visuals.RenderableSeries; using SciChart.Data.Model; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows; using Action = System.Action; using Media = System.Windows.Media; using System.Windows.Controls; using SciChart.Charting.Model.ChartData; using MECF.Framework.UI.Client.Converter; using MECF.Framework.UI.Client.CenterViews.Operations.RealTime; namespace MECF.Framework.UI.Client.CenterViews.DataLogs.ProcessHistory { public class StepInfo { public DateTime StartTime { get; set; } public DateTime StepEndTime { get; set; } public DateTime EndTime { get; set; } public string StepNo { get; set; } public string StepName { get; set; } public double StepTime { get; set; } public bool IsChecked { get; set; } = true; public string SubRecipeStepNumber { get; set; } public string SubRecipeStepName { get; set; } public string SubRecipeStepTime { get; set; } public string SubRecipeLoopInfo { get; set; } public string TempCorrection { get; set; } public string TempPid { get; set; } } public class ProcessDetailViewModel : ModuleUiViewModelBase where T : IComparable { public class TimeChartDataLine : ChartDataLine { public string Module { get; set; } public DateTime StartTime { get; set; } public DateTime EndTime { get; set; } public TimeChartDataLine(string dataName, string module, DateTime startTime, DateTime endTime) : base(dataName) { StartTime = startTime; EndTime = endTime; Module = module; } } public class QueryIndexer { public TimeChartDataLine DataLine { get; set; } public List DataList { get; set; } public DateTime TimeToken { get; set; } } public bool IsPermission { get => this.Permission == 3; } private byte _directionByte = 0x03; private ProcessDetailView view; /// /// 正在导出数据事件。 /// private event EventHandler Exporting; private CancellationTokenSource _cancellationTokenSource; #region Property private const int MAX_PARAMETERS = 20; private Queue colorQueue = new Queue(new Color[]{Color.Red,Color.Orange,Color.Yellow,Color.Green,Color.Blue,Color.Pink,Color.Purple,Color.Aqua,Color.Bisque,Color.Brown,Color.BurlyWood,Color.CadetBlue, Color.CornflowerBlue,Color.DarkBlue,Color.DarkCyan,Color.DarkGray,Color.DarkGreen,Color.DarkKhaki,Color.DarkMagenta,Color.DarkOliveGreen, Color.DarkOrange, Color.DarkSeaGreen,Color.DarkSlateBlue,Color.DarkSlateGray,Color.DarkViolet,Color.DeepPink,Color.DeepSkyBlue,Color.DimGray, Color.DodgerBlue,Color.ForestGreen, Color.Gold, Color.Gray,Color.GreenYellow,Color.HotPink,Color.Indigo,Color.Khaki,Color.LightBlue,Color.LightCoral,Color.LightGreen, Color.LightPink,Color.LightSalmon,Color.LightSkyBlue, Color.LightSlateGray,Color.LightSteelBlue,Color.LimeGreen,Color.MediumOrchid,Color.MediumPurple,Color.MediumSeaGreen,Color.MediumSlateBlue,Color.MediumSpringGreen, Color.MediumTurquoise,Color.Moccasin,Color.NavajoWhite,Color.Olive,Color.OliveDrab,Color.OrangeRed,Color.Orchid,Color.PaleGoldenrod,Color.PaleGreen, Color.PeachPuff,Color.Peru,Color.Plum,Color.PowderBlue,Color.RosyBrown,Color.RoyalBlue,Color.SaddleBrown,Color.Salmon,Color.SeaGreen, Color.Sienna, Color.SkyBlue,Color.SlateBlue,Color.SlateGray,Color.SpringGreen,Color.Teal,Color.Aquamarine,Color.Tomato,Color.Turquoise,Color.Violet,Color.Wheat, Color.YellowGreen}); private ObservableCollection _ParameterNodes; public ObservableCollection ParameterNodes { get { return _ParameterNodes; } set { _ParameterNodes = value; NotifyOfPropertyChange("ParameterNodes"); } } public ObservableCollection SelectedData { get; set; } public ObservableCollection SynSelectedData { get; set; } public List RecipeDatas { get; set; } private static object _lockSelection = new object(); private AutoRange _autoRange; public AutoRange ChartAutoRange { get { return _autoRange; } set { _autoRange = value; NotifyOfPropertyChange(nameof(ChartAutoRange)); } } private IRange _timeRange; public IRange VisibleRangeTime { get { return _timeRange; } set { _timeRange = value; NotifyOfPropertyChange(nameof(VisibleRangeTime)); } } private IRange _VisibleRangeValue; public IRange VisibleRangeValue { get { return _VisibleRangeValue; } set { _VisibleRangeValue = value; NotifyOfPropertyChange(nameof(VisibleRangeValue)); } } private PeriodicJob _thread; private ConcurrentBag _lstTokenTimeData = new ConcurrentBag(); private Dictionary _processDetailDisplayDic = new Dictionary(); private string _resolution; private AnnotationCollection _annotations; public AnnotationCollection Annotations { get => _annotations; set { _annotations = value; InvokePropertyChanged(nameof(Annotations)); } } //StartTime,EndTime,StepNo,StepName private List _stepInfo = new List(); public List StepInfo { get { return _stepInfo; } set { _stepInfo = value; this.NotifyOfPropertyChange(nameof(StepInfo)); } } public bool IsStepVisiable => RecipeDatas.Count == 1; public DateTime StepStartTime { get; set; } public DateTime StepEndTime { get; set; } private bool _isAdding; private string _stepName; public string StepNameDisPlay { get { return _stepName; } set { if (_stepName != value) { _stepName = value; NotifyOfPropertyChange(nameof(StepNameDisPlay)); } } } private string _recipeNameDisPlay; public string RecipeNameDisPlay { get { return _recipeNameDisPlay; } set { if (_recipeNameDisPlay != value) { _recipeNameDisPlay = value; NotifyOfPropertyChange(nameof(RecipeNameDisPlay)); } } } private DateTime _pointTime; public DateTime PointTime { get { return _pointTime; } set { if (_pointTime != value) { _pointTime = value; NotifyOfPropertyChange(nameof(PointTime)); } } } private double _lastPointX; private string _direction = "XYDirection"; public string Direction { get { return _direction; } set { if (value != _direction) { _direction = value; if (_direction == "XDirection") _directionByte = 1; else if (_direction == "YDirection") _directionByte = 2; else if (_direction == "XYDirection") _directionByte = 3; NotifyOfPropertyChange(nameof(Direction)); } } } //public Tuple _timePairs; private MultiLineXAxisLabelProvider _mulitiLineLabel; public MultiLineXAxisLabelProvider MultiLineLabel { get { return _mulitiLineLabel; } set { if (_mulitiLineLabel != value) { _mulitiLineLabel = value; NotifyOfPropertyChange(nameof(MultiLineLabel)); } } } private double _xScale = 1; public double XScale { get { return _xScale; } set { if (_xScale != value) { _xScale = value; NotifyOfPropertyChange(nameof(XScale)); } } } private double _yScale = 0.1; public double YScale { get { return _yScale; } set { if (value != _yScale) { _yScale = value; NotifyOfPropertyChange(nameof(YScale)); } } } #endregion private RealtimeProvider _realtimeProvider; #region Function public ProcessDetailViewModel(List recipes) { _realtimeProvider = new RealtimeProvider(); DisplayName = "Process Detail"; RecipeDatas = recipes; ParameterNodes = _realtimeProvider.GetParameters(out var dict); _processDetailDisplayDic = dict; if (recipes == null || recipes.Count == 0) { return; } SelectedData = new ObservableCollection(); SynSelectedData = new ObservableCollection(); VisibleRangeValue = new DoubleRange(0, 10); // Annotations = new AnnotationCollection(); _thread = new PeriodicJob(200, MonitorData, "ProcessDetail", true); try { RecipeDatas.ToList().ForEach(recipe => { QueryStep(recipe.StartTime, recipe.EndTime); }); if (StepInfo != null && StepInfo.Count > 0) { StepStartTime = StepInfo.FirstOrDefault().StartTime; StepEndTime = StepInfo.LastOrDefault().EndTime; } MultiLineLabel = new MultiLineXAxisLabelProvider(StepStartTime); } catch (Exception ex) { LOG.Info(ex.StackTrace + ":" + ex.Message); } } protected override void OnViewLoaded(object view) { base.OnViewLoaded(view); this.view = (ProcessDetailView)view; } protected override void OnActivate() { _resolution = "f1"; if (QueryDataClient.Instance.Service.GetConfig($"System.DataHistoryResolution") != null) _resolution = $"f{QueryDataClient.Instance.Service.GetConfig($"System.DataHistoryResolution")}"; base.OnActivate(); } public void QueryStep(DateTime starTime, DateTime endTime)//, string recipeName去掉查询recipeName名称,有嵌套调用 { starTime = starTime.AddMinutes(-1); endTime = endTime.AddMinutes(1); string sql = $"SELECT * FROM \"process_data\" where (\"process_begin_time\" >= '{starTime:yyyy/MM/dd HH:mm:ss.fff}' and \"process_end_time\" <= '{endTime:yyyy/MM/dd HH:mm:ss.fff}') order by \"process_begin_time\" DESC;"; DataTable dbData = QueryDataClient.Instance.Service.QueryData(sql); if (dbData != null && dbData.Rows.Count > 0) { List ProcessDataLotList = new List(); for (int i = 0; i < dbData.Rows.Count; i++) { ProcessDataLot item = new ProcessDataLot(); item.GUID = dbData.Rows[i]["guid"].ToString(); item.RecipeName = dbData.Rows[i]["recipe_name"].ToString().Trim('\\'); item.ProcessStatus = dbData.Rows[i]["process_status"].ToString(); item.WaferDataGUID = dbData.Rows[i]["wafer_data_guid"].ToString(); item.ProcessIn = dbData.Rows[i]["process_in"].ToString(); if (!dbData.Rows[i]["process_begin_time"].Equals(DBNull.Value)) { item.ProcessBeginTime = (DateTime)dbData.Rows[i]["process_begin_time"]; } if (!dbData.Rows[i]["process_end_time"].Equals(DBNull.Value)) { item.ProcessEndTime = (DateTime)dbData.Rows[i]["process_end_time"]; } ProcessDataLotList.Add(item); } //Annotations.Add(VerLine(Media.Brushes.Blue, ProcessDataLotList[0].ProcessBeginTime, Media.Brushes.Blue, $"{ProcessDataLotList[0].RecipeName}")); //Annotations.Add(VerLine(Media.Brushes.Blue, ProcessDataLotList[0].ProcessEndTime, Media.Brushes.Blue, $"Recipe End")); string sql2 = $"SELECT * FROM \"recipe_step_data\" where"; sql2 += $" \"recipe_step_data\".\"process_data_guid\" = '{ProcessDataLotList[0].GUID.ToString()}'"; sql2 += " order by \"step_begin_time\" ASC;"; using (var table = QueryDataClient.Instance.Service.QueryData(sql2)) { if (!(table == null || table.Rows.Count == 0)) { for (int i = 0; i < table.Rows.Count; i++) { var item = table.Rows[i]; DateTime StartTime = DateTime.MinValue; DateTime EndTime = DateTime.MinValue; double stepTime = 0; if (!item["step_begin_time"].Equals(DBNull.Value)) StartTime = (DateTime)item["step_begin_time"]; if (!item["step_end_time"].Equals(DBNull.Value)) EndTime = (DateTime)item["step_end_time"]; if (!item["step_time"].Equals(DBNull.Value)) { stepTime = (float)item["step_time"]; } string stepNo = item["step_number"].ToString(); string stepName = item["step_name"].ToString(); if (StartTime>DateTime.MinValue &&EndTime>DateTime.MinValue ) { if (EndTime < StartTime.AddSeconds(stepTime)) { EndTime = StartTime.AddSeconds(stepTime); } else { if (_stepInfo.Any())//临时处理表中recipe_step_data step_end_time数据不能真实反映步次结束时间的问题 { int lastIndex = _stepInfo.Count-1; if (_stepInfo[lastIndex].EndTime> StartTime) _stepInfo[lastIndex].EndTime= StartTime; } _stepInfo.Add(new StepInfo() { StartTime = StartTime, EndTime = EndTime, StepName = stepName, StepTime = stepTime, StepNo = stepNo }); } } } } } } } public static VerticalLineAnnotation VerLine(Media.Brush stroke, DateTime x, Media.Brush color, string text) { var label = new AnnotationLabel() { LabelPlacement = LabelPlacement.TopRight, FontSize = 12, RotationAngle = 0, Foreground = color, Text = text }; var line = new VerticalLineAnnotation() { Stroke = stroke, StrokeThickness = 1, X1 = x, IsEditable = false, VerticalAlignment = VerticalAlignment.Stretch, AnnotationLabels = new ObservableCollection() { label }, }; return line; } protected bool MonitorData() { try { if (_isAdding) return true; bool allUpdated = true; for (int j = 0; j < ParameterNodes.Count; j++) { ParameterNode par = ParameterNodes[j]; par.IsVisibilityParentNode = Visibility.Hidden; } lock (_lockSelection) { foreach (var item in _lstTokenTimeData) { DateTime timeFrom = item.TimeToken; if (timeFrom >= item.DataLine.EndTime) continue; allUpdated = false; ChartAutoRange = AutoRange.Always; DateTime timeTo = timeFrom.AddMinutes(60); if (timeTo.DayOfYear > timeFrom.DayOfYear) timeTo = new DateTime(timeFrom.Year, timeFrom.Month, timeFrom.Day).AddDays(1); if (timeTo > item.DataLine.EndTime) timeTo = item.DataLine.EndTime; item.TimeToken = timeTo; GetData(item.DataList, timeFrom, timeTo, item.DataLine.Module, item.DataLine.DataSource); #region Update VisualMin、VisualMax、DataStatisticsInfo Application.Current.Dispatcher.BeginInvoke(new Action(() => { double min = ((DoubleRange)VisibleRangeValue).Min; double max = ((DoubleRange)VisibleRangeValue).Max; int PointCount = 0; foreach (var selectedData in SelectedData) { var seriesItem = selectedData as ChartDataLine; if (seriesItem == null) continue; double sumValue = 0; double minValue = 100000; double maxValue = 0; double averageValue = 0; double stdevValue = 0; double sigma3Value = 0; var pointValueList = seriesItem.Points.Select(x => x.Item2).ToList(); for (int i = 0; i < pointValueList.Count; i++) { sumValue += pointValueList[i]; if (pointValueList[i] < minValue) minValue = pointValueList[i]; if (pointValueList[i] > maxValue) maxValue = pointValueList[i]; } averageValue = pointValueList.Count==0?0: sumValue / pointValueList.Count; for (int i = 0; i < pointValueList.Count; i++) { stdevValue += Math.Pow(pointValueList[i] - averageValue, 2); } stdevValue = pointValueList.Count == 0 ? 0 : stdevValue / pointValueList.Count; sigma3Value = Math.Sqrt(stdevValue) * 3; (seriesItem.Tag as ParameterNode).AverageValue = averageValue.ToString("F2"); (seriesItem.Tag as ParameterNode).MinValue = minValue.ToString("F2"); (seriesItem.Tag as ParameterNode).MaxValue = maxValue.ToString("F2"); (seriesItem.Tag as ParameterNode).Sigma3Value = sigma3Value.ToString("F2"); min = minValue; if (maxValue != max) max = maxValue * 1.1; PointCount = pointValueList.Count; } VisibleRangeValue = new DoubleRange(min, max); })); #endregion } } if (allUpdated) { lock (_lockSelection) { while (_lstTokenTimeData.Count > 0) { _lstTokenTimeData.TryTake(out _); } ChartAutoRange = AutoRange.Never; } } } catch (Exception ex) { LOG.Error(ex.Message); } return true; } private void GetData(List keys, DateTime from, DateTime to, string module, string dataSource) { string sql = "select time AS InternalTimeStamp"; foreach (var dataKey in keys) { var dataId = _processDetailDisplayDic.ContainsKey(dataKey) ? _processDetailDisplayDic[dataKey] : dataKey; sql += "," + string.Format("\"{0}\"", dataId); } sql += string.Format(" from \"{0}\" where time > {1} and time <= {2} order by time asc", from.ToString("yyyyMMdd") + "." + module, from.Ticks, to.Ticks); DataTable dataTable = QueryDataClient.Instance.Service.QueryData(sql); Dictionary> historyData = new Dictionary>(); if (dataTable == null || dataTable.Rows.Count == 0) return; DateTime dt = new DateTime(); Dictionary colName = new Dictionary(); for (int colNo = 0; colNo < dataTable.Columns.Count; colNo++) { colName.Add(colNo, dataTable.Columns[colNo].ColumnName); historyData[dataTable.Columns[colNo].ColumnName] = new List(); } for (int rowNo = 0; rowNo < dataTable.Rows.Count; rowNo++) { var row = dataTable.Rows[rowNo]; for (int i = 0; i < dataTable.Columns.Count; i++) { HistoryDataItem data = new HistoryDataItem(); if (i == 0) { dt = new DateTime((long)row[i]); continue; } else { string dataId = colName[i]; if (row[i] is DBNull || row[i] == null) { data.dateTime = dt; data.dbName = colName[i]; data.value = 0; } else if (row[i] is bool) { data.dateTime = dt; data.dbName = colName[i]; data.value = (bool)row[i] ? 1 : 0; } else { data.dateTime = dt; data.dbName = colName[i]; var value = float.Parse(row[i].ToString()).ToString(_resolution); data.value = float.Parse(value); } } historyData[data.dbName].Add(data); } } Application.Current.Dispatcher.BeginInvoke(new Action(() => { try { var items = SelectedData.Where(x => (x as ChartDataLine).DataSource == dataSource); foreach (var item in items) { var seriesItem = item as ChartDataLine; if (seriesItem == null) continue; foreach (var data in historyData) { var dataKey = _processDetailDisplayDic.ContainsKey(seriesItem.DataName) ? _processDetailDisplayDic[seriesItem.DataName] : seriesItem.DataName; if (data.Key != dataKey) continue; seriesItem.Capacity += data.Value.Count; //DateTime beginTime = StepStartTime; for (int i = 0; i < data.Value.Count; i++) { var historyDataItem = data.Value[i]; if (typeof(T) == typeof(double)) { //xData = Math.Round((historyDataItem.dateTime - beginTime).TotalMilliseconds / 1000, 0, MidpointRounding.AwayFromZero); seriesItem.Append((T)Convert.ChangeType((historyDataItem.dateTime- StepStartTime).TotalMilliseconds/1000d, typeof(T)), historyDataItem.value); } else seriesItem.Append((T)Convert.ChangeType(historyDataItem.dateTime, typeof(T)), historyDataItem.value); } } } RefresCharView(); } catch (Exception ex) { LOG.Write(ex); } })); } /// /// 获取时间列表 /// /// /// /// /// private void GetData(DateTime from, DateTime to, string module = "PM1") { string sql = "select time AS InternalTimeStamp,\"PM1.RecipeTotalElapseTime\""; sql += string.Format(" from \"{0}\" where time > {1} and time <= {2} order by time limt 1", from.ToString("yyyyMMdd") + "." + module, from.Ticks, to.Ticks); DataTable dataTable = QueryDataClient.Instance.Service.QueryData(sql); Dictionary> historyData = new Dictionary>(); if (dataTable == null || dataTable.Rows.Count == 0) { return; } foreach (DataRow row in dataTable.Rows) { DateTime dt = new DateTime(); dt = new DateTime((long)row[0]); var elapseTime = Convert.ToDouble(row[1]); } } private void SelectedDataChanged() { foreach (var item in SelectedData) { if (item.Stroke.Equals(System.Windows.Media.Color.FromArgb(255, 0, 0, 255))) { Color drawingColor = colorQueue.Peek(); item.Stroke = System.Windows.Media.Color.FromRgb(drawingColor.R, drawingColor.G, drawingColor.B); colorQueue.Enqueue(colorQueue.Dequeue()); } } } public void TxtMouseLeftButtonDown(ParameterNode node) { node.Selected = !node.Selected; ParameterCheck(node); } public void ParameterCheck(ParameterNode node) { bool result = RefreshTreeStatusToChild(node); if (!result) { node.Selected=!node.Selected; DialogBox.ShowWarning($"The max number of parameters is {MAX_PARAMETERS}."); } else RefreshTreeStatusToParent(node); } /// /// Refresh tree node status from current to children, and add data to SelectedData /// private bool RefreshTreeStatusToChild(ParameterNode node) { if (node?.ChildNodes.Count > 0) { for (int i = 0; i < node.ChildNodes.Count; i++) { ParameterNode n = node.ChildNodes[i]; n.Selected = node.Selected; if (!RefreshTreeStatusToChild(n)) { n.Selected = !n.Selected; return false; } } } else //leaf node { bool lockTaken = false; try { var item = SelectedData?.FirstOrDefault(x => (x as ChartDataLine).DataName == node.Name); if (item == null) item = SynSelectedData.FirstOrDefault(x => (x as ChartDataLine).DataName == node.Name); bool isExist = item != null; if (isExist && !node.Selected)//删除 { SelectedData.Remove(item); SynSelectedData.Remove(item); if (SynSelectedData.Count == 0 && this.view.syncChart.Visibility == Visibility.Visible) { this.view.syncChart.Visibility = Visibility.Hidden; Grid.SetRowSpan(this.view.sciChart, 2); } } else { if (!isExist && node.Selected) { if (SelectedData.Count >= MAX_PARAMETERS) { return false; } Monitor.TryEnter(_lockSelection, 1000, ref lockTaken); if (lockTaken) { var dataId = _processDetailDisplayDic.ContainsKey(node.Name) ? _processDetailDisplayDic[node.Name] : node.Name; var module = dataId.Split('.').ToList()[0]; _isAdding = true; foreach (var recipe in RecipeDatas) { TimeChartDataLine line; if (IsStepVisiable) line = new TimeChartDataLine(node.Name.Replace("Tube", "PM1"), module, StepStartTime, StepEndTime); else line = new TimeChartDataLine(node.Name.Replace("Tube", "PM1"), module, recipe.StartTime, recipe.EndTime); line.DataSource = $"{recipe.BatchID}.{recipe.RecipeName}"; line.Tag = node; if (isExist) { line.Stroke = item.Stroke; line.IsVisible = item.IsVisible; line.ClearData(); SelectedData.Remove(item); } else SelectedData.Add(line); AddToMonitor(line); } _isAdding = false; if (!isExist) SelectedDataChanged(); } } } } finally { if (lockTaken) { Monitor.Exit(_lockSelection); } } } return true; } private void AddToMonitor(TimeChartDataLine line) { QueryIndexer indexer = new QueryIndexer() { DataLine = line, DataList = new List() { line.DataName }, TimeToken = line.StartTime, }; _lstTokenTimeData.Add(indexer); } /// /// Refresh tree node status from current to parent /// /// /// private void RefreshTreeStatusToParent(ParameterNode node) { if (node.ParentNode != null) { if (node.Selected) { bool flag = true; for (int i = 0; i < node.ParentNode.ChildNodes.Count; i++) { if (!node.ParentNode.ChildNodes[i].Selected) { flag = false; //as least one child is unselected break; } } if (flag) node.ParentNode.Selected = true; } else { node.ParentNode.Selected = false; } RefreshTreeStatusToParent(node.ParentNode); } } #region Parameter Grid Control public void DeleteAll() { //uncheck all tree nodes foreach (ChartDataLine cp in SelectedData) { (cp.Tag as ParameterNode).Selected = false; RefreshTreeStatusToParent(cp.Tag as ParameterNode); } SelectedData.Clear(); SynSelectedData.Clear(); if (this.view.syncChart.Visibility == Visibility.Visible) { this.view.syncChart.Visibility = Visibility.Hidden; Grid.SetRowSpan(this.view.sciChart, 2); } } private void SetParameterNode(ObservableCollection nodes, bool isChecked) { foreach (ParameterNode n in nodes) { n.Selected = isChecked; SetParameterNode(n.ChildNodes, isChecked); } } public void Delete(ChartDataLine cp) { if (cp != null) { if (SelectedData.Contains(cp)) { //uncheck tree node (cp.Tag as ParameterNode).Selected = false; RefreshTreeStatusToParent(cp.Tag as ParameterNode); SelectedData.Remove(cp); } if (SynSelectedData.Contains(cp)) { SynSelectedData.Remove(cp); } } } public async void ExportAll() { try { if (SelectedData.Count == 0) { MessageBox.Show($"Please select the data you want to export.", "Export", MessageBoxButton.OK, MessageBoxImage.Warning); return; } Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog(); dlg.DefaultExt = ".xlsx"; // Default file extension dlg.Filter = "Excel数据表格文件(*.xlsx)|*.xlsx"; // Filter files by extension dlg.FileName = $"{DisplayName}_{string.Join(",", RecipeDatas.Select(x => x.RecipeName.Replace('\\','.')).ToArray())}_{DateTime.Now:yyyyMMdd_HHmmss}"; Nullable result = dlg.ShowDialog();// Show open file dialog box if (result == true) // Process open file dialog box results { Exporting?.Invoke(this, System.EventArgs.Empty); _cancellationTokenSource = new CancellationTokenSource(); var sw = new Stopwatch(); sw.Restart(); System.Data.DataSet ds = new System.Data.DataSet(); ds.Tables.Add(new System.Data.DataTable($"{DisplayName}_{DateTime.Now:yyyyMMdd_HHmmss}")); ds.Tables[0].Columns.Add("Recipe Info"); ds.Tables[0].Columns[0].DataType = typeof(string); ds.Tables[0].Columns.Add("Date"); ds.Tables[0].Columns[1].DataType = typeof(string); ds.Tables[0].Columns.Add("Time"); ds.Tables[0].Columns[2].DataType = typeof(string); ds.Tables[0].Columns.Add("Step ID"); ds.Tables[0].Columns[3].DataType = typeof(string); ds.Tables[0].Columns.Add("Step Name"); ds.Tables[0].Columns[4].DataType = typeof(string); Dictionary timeValue = new Dictionary(); await Task.Run(() => { for (int i = 0; i < SelectedData.Count; i++) { List> data = (SelectedData[i] as ChartDataLine).Points; foreach (var tuple in data) { if (!timeValue.ContainsKey(tuple.Item1)) timeValue[tuple.Item1] = new double[SelectedData.Count]; timeValue[tuple.Item1][i] = tuple.Item2; } ds.Tables[0].Columns.Add((SelectedData[i] as ChartDataLine).DataName); ds.Tables[0].Columns[i + 5].DataType = typeof(double); } var recipeInfoRow = ds.Tables[0].NewRow(); recipeInfoRow[0] = $"Recipe:{string.Join(",", RecipeDatas.Select(x => x.RecipeName).ToArray())}"; ds.Tables[0].Rows.Add(recipeInfoRow); recipeInfoRow = ds.Tables[0].NewRow(); recipeInfoRow[0] = $"Start Time"; recipeInfoRow[1] = string.Join(",", RecipeDatas.Select(x => x.StartTime).ToArray()); recipeInfoRow[2] = string.Join(",", RecipeDatas.Select(x => x.StartTime).ToArray()); ds.Tables[0].Rows.Add(recipeInfoRow); recipeInfoRow = ds.Tables[0].NewRow(); recipeInfoRow[0] = $"End Time"; recipeInfoRow[1] = string.Join(",", RecipeDatas.Select(x => x.EndTime).ToArray()); recipeInfoRow[2] = string.Join(",", RecipeDatas.Select(x => x.EndTime).ToArray()); ds.Tables[0].Rows.Add(recipeInfoRow); QueryDataClientFromTable(ds); }, _cancellationTokenSource.Token).ContinueWith(t => { if (t.IsCanceled || t.IsFaulted) return; }); if (_cancellationTokenSource?.Token.IsCancellationRequested == true) return; if (!ExcelHelper.ExportToExcel(dlg.FileName, ds, out string reason)) { MessageBox.Show($"Export failed, {reason}", "Export", MessageBoxButton.OK, MessageBoxImage.Warning); return; } MessageBox.Show($"Export succeed, file save as {dlg.FileName}", "Export", MessageBoxButton.OK, MessageBoxImage.Information); } } catch (Exception ex) { LOG.Write(ex); MessageBox.Show("Write failed," + ex.Message, "export failed", MessageBoxButton.OK, MessageBoxImage.Warning); } } public void DGSelectionChanged(object sender, EventArgs e) { var temp = (DataGrid)sender; var tempSelected = (IRenderableSeries)temp.SelectedItem; tempSelected.IsVisible = !tempSelected.IsVisible; } private void QueryDataClientFromTable(DataSet ds) { DateTime startTime = StepStartTime; DateTime endTime = StepEndTime; if (StepStartTime.Date == StepEndTime.Date) { SaveDataToTable(ds, startTime, endTime); } else { endTime = new DateTime(startTime.Year, startTime.Month, startTime.Day, 23, 59, 59); while (endTime < StepEndTime) { SaveDataToTable(ds, startTime, endTime); startTime = new DateTime(startTime.Year, startTime.Month, startTime.Day, 0, 0, 0).AddDays(1); endTime = new DateTime(startTime.Year, startTime.Month, startTime.Day, 23, 59, 59); } SaveDataToTable(ds, startTime, StepEndTime); } } private void SaveDataToTable(DataSet ds, DateTime startTime, DateTime endTime) { string stepID = "", stepName = ""; string pmsql = "select time AS InternalTimeStamp"; var pmColNames = _realtimeProvider.GetDBCol(startTime.ToString("yyyyMMdd") + "." + "PM1"); List keys = SelectedData.Select(x => (x as ChartDataLine).DataName).ToList(); DataTable pmDataTable = null; if (keys != null && keys.Count > 0) { List pmList = new List(); foreach (var dataKey in keys) { var dataId = _processDetailDisplayDic.ContainsKey(dataKey) ? _processDetailDisplayDic[dataKey] : dataKey; var module = dataId.Split('.').ToList()[0]; if (module.ToLower() == "pm1") { if (!pmColNames.Contains(dataId)) { continue; } pmList.Add(dataId); pmsql += "," + string.Format("\"{0}\"", dataId); } } if (pmList.Count > 0) { pmsql += string.Format(" from \"{0}\" where time > {1} and time <= {2} order by time asc", startTime.ToString("yyyyMMdd") + "." + "PM1", startTime.Ticks, endTime.Ticks); pmDataTable = QueryDataClient.Instance.Service.QueryData(pmsql); if (pmDataTable == null) { MessageBox.Show($"Export failed, sql:{pmsql}", "Export", MessageBoxButton.OK, MessageBoxImage.Warning); return; } } } string systemsql = "select time AS InternalTimeStamp"; var systemColNames = _realtimeProvider.GetDBCol(startTime.ToString("yyyyMMdd") + "." + "System"); DataTable systemDataTable = null; if (keys != null && keys.Count > 0) { List systemList = new List(); foreach (var dataKey in keys) { var dataId = _processDetailDisplayDic.ContainsKey(dataKey) ? _processDetailDisplayDic[dataKey] : dataKey; var module = dataId.Split('.').ToList()[0]; if (module.ToLower() == "system") { if (!systemColNames.Contains(dataId)) { continue; } systemsql += "," + string.Format("\"{0}\"", dataId); systemList.Add(dataId); } } if (systemList.Count > 0) { systemsql += string.Format(" from \"{0}\" where time > {1} and time <= {2} order by time asc", startTime.ToString("yyyyMMdd") + "." + "System", startTime.Ticks, endTime.Ticks); systemDataTable = QueryDataClient.Instance.Service.QueryData(systemsql); if (systemDataTable == null) { MessageBox.Show($"Export failed, sql:{systemsql}", "Export", MessageBoxButton.OK, MessageBoxImage.Warning); return; } } } int maxRow = 0; if ((pmDataTable == null || pmDataTable.Rows.Count == 0)) { if (systemDataTable != null) { maxRow = systemDataTable.Rows.Count; } } else if ((systemDataTable == null || systemDataTable.Rows.Count == 0)) { if (pmDataTable != null) { maxRow = pmDataTable.Rows.Count; } } else { maxRow = pmDataTable.Rows.Count > systemDataTable.Rows.Count ? systemDataTable.Rows.Count : pmDataTable.Rows.Count; } for (int i = 0; i < maxRow; i++) { var pmRow = pmDataTable != null ? pmDataTable.Rows[i] : null; var systemRow = systemDataTable != null ? systemDataTable.Rows[i] : null; //float timeIndex = 0; //float.TryParse(item.Key.ToString(), out timeIndex); //DateTime dateTimeKey = startTime.AddMilliseconds(timeIndex * 1000); ;// DateTime.Parse(item.Key.ToString()); DateTime dateTimeKey = new DateTime(pmRow != null ? (long)pmRow[0] : (long)systemRow[0]); var tempStepInfo = _stepInfo.FirstOrDefault(x => x.StartTime < dateTimeKey && x.EndTime > dateTimeKey); if (tempStepInfo != null)// && dateTimeKey > _stepInfo[iIndex].StartTime { stepID = tempStepInfo.StepNo; stepName = tempStepInfo.StepName; } var row = ds.Tables[0].NewRow(); row[1] = dateTimeKey.ToString("yyyy/MM/dd"); row[2] = dateTimeKey.ToString("HH:mm:ss:fff"); row[3] = stepID; row[4] = stepName; for (int j = 5; j < ds.Tables[0].Columns.Count; j++) { string colName = ds.Tables[0].Columns[j].ColumnName; DataRow dataRow = null; var dataId = _processDetailDisplayDic.ContainsKey(colName) ? _processDetailDisplayDic[colName] : colName; var module = dataId.Split('.').ToList()[0]; int index = 0; if (module == "PM1") { dataRow = pmRow; foreach (var item in pmDataTable.Columns) { if (((DataColumn)item).ColumnName == dataId) { break; } index++; } } else if (module == "System") { dataRow = systemRow; foreach (var item in systemDataTable.Columns) { if (((DataColumn)item).ColumnName == dataId) { break; } index++; } } if (dataRow[index] is DBNull || dataRow[index] == null) { row[j] = dataRow[index]; } else if (dataRow[index] is bool) { row[j] = (bool)dataRow[index] ? 1 : 0; } else { var value = float.Parse(dataRow[index].ToString()).ToString(_resolution); row[j] = float.Parse(value); } } ds.Tables[0].Rows.Add(row); } } public void Export(ChartDataLine cp) { try { Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog(); dlg.DefaultExt = ".xlsx"; // Default file extension dlg.Filter = "Excel数据表格文件(*.xlsx)|*.xlsx"; // Filter files by extension dlg.FileName = $"{cp.DataName}_{DateTime.Now:yyyyMMdd_HHmmss}"; Nullable result = dlg.ShowDialog();// Show open file dialog box if (result == true) // Process open file dialog box results { System.Data.DataSet ds = new System.Data.DataSet(); ds.Tables.Add(new System.Data.DataTable(cp.DataName)); ds.Tables[0].Columns.Add("Time"); ds.Tables[0].Columns[0].DataType = typeof(DateTime); ds.Tables[0].Columns.Add(cp.DataName); ds.Tables[0].Columns[1].DataType = typeof(double); int i = 0; foreach (var item in cp.Points) { var row = ds.Tables[0].NewRow(); row[0] =StepStartTime.AddSeconds(Convert.ToDouble(item.Item1)); row[1] = item.Item2; ds.Tables[0].Rows.Add(row); i++; } if (!ExcelHelper.ExportToExcel(dlg.FileName, ds, out string reason)) { MessageBox.Show($"Export failed, {reason}", "Export", MessageBoxButton.OK, MessageBoxImage.Warning); return; } MessageBox.Show($"Export succeed, file save as {dlg.FileName}", "Export", MessageBoxButton.OK, MessageBoxImage.Information); } } catch (Exception ex) { LOG.Write(ex); MessageBox.Show("Write failed," + ex.Message, "export failed", MessageBoxButton.OK, MessageBoxImage.Warning); } } public void SelectColor(ChartDataLine cp) { if (cp == null) return; var dlg = new System.Windows.Forms.ColorDialog(); if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) { cp.Stroke = new System.Windows.Media.Color() { A = dlg.Color.A, B = dlg.Color.B, G = dlg.Color.G, R = dlg.Color.R }; } } public void CloseCmd() { ((Window)GetView()).Close(); } #endregion #region SciChart Move public void RefresCharView() { this.view.sciChart.ZoomExtents(); } public void BackPan()//前移 { if ((_directionByte & 0x01) == 1)//x { // LOG.Info($"A BackPan.X:scale{XScale},{VisibleRangeTime.Min}:{VisibleRangeTime.Max}"); if (VisibleRangeTime is DoubleRange range) { VisibleRangeTime = new DoubleRange(range.Min - XScale, range.Max - XScale); // LOG.Info($"BackPan.X:scale{XScale},{VisibleRangeTime.Min}:{VisibleRangeTime.Max}"); } } if ((_directionByte & 0x02) == 2) { // LOG.Info($"A BackPan.Y:scale{YScale},{VisibleRangeValue.Min}:{VisibleRangeValue.Max}"); if (VisibleRangeValue is DoubleRange range) { VisibleRangeValue = new DoubleRange(range.Min - YScale, range.Max - YScale); //LOG.Info($"BackPan.Y:scale{YScale},{VisibleRangeValue.Min}:{VisibleRangeValue.Max}"); } } } public void ForwardPan()//后移 { if ((_directionByte & 0x01) == 1)//x { // LOG.Info($"A ForwardPan.X:scale{XScale},{VisibleRangeTime.Min}:{VisibleRangeTime.Max}"); if (VisibleRangeTime is DoubleRange range) { VisibleRangeTime = new DoubleRange(range.Min + XScale, range.Max + XScale); // LOG.Info($"ForwardPan.X:scale{XScale},{VisibleRangeTime.Min}:{VisibleRangeTime.Max}"); } } if ((_directionByte & 0x02) == 2) { //LOG.Info($"A ForwardPan.Y:scale{YScale},{VisibleRangeValue.Min}:{VisibleRangeValue.Max}"); if (VisibleRangeValue is DoubleRange range) { VisibleRangeValue = new DoubleRange(range.Min + YScale, range.Max + YScale); //LOG.Info($"ForwardPan.Y:scale{YScale},{VisibleRangeValue.Min}:{VisibleRangeValue.Max}"); } } } public void ZoomInClick()//放大 { double scale = 0; if ((_directionByte & 0x01) == 1)//x { //LOG.Info($"A ZoomInClick.X:scale{XScale}-{VisibleRangeTime.Min}: {VisibleRangeTime.Max}"); if (VisibleRangeTime is DoubleRange range) { if (range.Max - range.Min <= XScale) return; if (range.Max - range.Min > 2 * XScale) scale = XScale; else scale = XScale / 2; VisibleRangeTime = new DoubleRange(range.Min + scale, range.Max - scale); //LOG.Info($"ZoomInClick.X:scale{XScale}-{VisibleRangeTime.Min}: {VisibleRangeTime.Max}"); } } if ((_directionByte & 0x02) == 2)//y { //LOG.Info($"A ZoomInClick.Y:scale{YScale}-{VisibleRangeValue.Min}: {VisibleRangeValue.Max}"); if (VisibleRangeValue is DoubleRange range) { if (range.Max - range.Min <= YScale) return; if (range.Max - range.Min > 2 * XScale) scale = YScale; else scale = YScale / 2; VisibleRangeValue = new DoubleRange(range.Min + scale, range.Max - scale); //LOG.Info($"ZoomInClick.Y:scale{YScale}-{VisibleRangeValue.Min}: {VisibleRangeValue.Max}"); } } } public void ZoomOutClick()//缩小 { if ((_directionByte & 0x01) == 1)//x { //LOG.Info($"A ZoomOutClick.X:scale{XScale}-{VisibleRangeTime.Min}: {VisibleRangeTime.Max}"); if (VisibleRangeTime is DoubleRange range) { VisibleRangeTime = new DoubleRange(range.Min - XScale, range.Max + XScale); //LOG.Info($"ZoomOutClick.X:scale{XScale}-{VisibleRangeTime.Min}: {VisibleRangeTime.Max}"); } } if ((_directionByte & 0x02) == 2)//y { //LOG.Info($"A ZoomOutClick.Y:scale{YScale}-{VisibleRangeValue.Min}: {VisibleRangeValue.Max}"); if (VisibleRangeValue is DoubleRange range) { VisibleRangeValue = new DoubleRange(range.Min - YScale, range.Max + YScale); // LOG.Info($"ZoomOutClick.Y:scale{YScale}-{VisibleRangeValue.Min}: {VisibleRangeValue.Max}"); } } } public void SelectStep() { ObservableCollection