ProcessDetailViewModel.cs 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563
  1. using Aitex.Core.RT.Log;
  2. using Aitex.Core.UI.ControlDataContext;
  3. using Aitex.Core.Util;
  4. using Caliburn.Micro;
  5. using Caliburn.Micro.Core;
  6. using MECF.Framework.Common.CommonData;
  7. using MECF.Framework.Common.ControlDataContext;
  8. using MECF.Framework.Common.DataCenter;
  9. using MECF.Framework.Common.Utilities;
  10. using MECF.Framework.UI.Client.CenterViews.Configs.SystemConfig;
  11. using MECF.Framework.UI.Client.CenterViews.DataLogs.ProcessHistory;
  12. using MECF.Framework.UI.Client.CenterViews.Dialogs;
  13. using MECF.Framework.UI.Client.ClientBase;
  14. using OpenSEMI.ClientBase;
  15. using SciChart.Charting.Visuals;
  16. using SciChart.Charting.Visuals.Annotations;
  17. using SciChart.Charting.Visuals.Axes;
  18. using SciChart.Charting.Visuals.RenderableSeries;
  19. using SciChart.Data.Model;
  20. using System;
  21. using System.Collections.Concurrent;
  22. using System.Collections.Generic;
  23. using System.Collections.ObjectModel;
  24. using System.Data;
  25. using System.Diagnostics;
  26. using System.Drawing;
  27. using System.Linq;
  28. using System.Threading;
  29. using System.Threading.Tasks;
  30. using System.Windows;
  31. using Action = System.Action;
  32. using Media = System.Windows.Media;
  33. using System.Windows.Controls;
  34. using SciChart.Charting.Model.ChartData;
  35. using MECF.Framework.UI.Client.Converter;
  36. using MECF.Framework.UI.Client.CenterViews.Operations.RealTime;
  37. using Mapster;
  38. using System.Globalization;
  39. using System.Windows.Data;
  40. using DocumentFormat.OpenXml.Bibliography;
  41. namespace MECF.Framework.UI.Client.CenterViews.DataLogs.ProcessHistory
  42. {
  43. public class StepInfo
  44. {
  45. public DateTime StartTime { get; set; }
  46. public DateTime StepEndTime { get; set; }
  47. public DateTime EndTime { get; set; }
  48. public string StepNo { get; set; }
  49. public string StepName { get; set; }
  50. public double StepTime { get; set; }
  51. public bool IsChecked { get; set; } = true;
  52. public string SubRecipeStepNumber { get; set; }
  53. public string SubRecipeStepName { get; set; }
  54. public string SubRecipeStepTime { get; set; }
  55. public string SubRecipeLoopInfo { get; set; }
  56. public string TempCorrection { get; set; }
  57. public string TempPid { get; set; }
  58. }
  59. public class ProcessDetailViewModel<T> : ModuleUiViewModelBase where T : IComparable
  60. {
  61. public class TimeChartDataLine : ChartDataLine<T>
  62. {
  63. public string Module { get; set; }
  64. public DateTime StartTime { get; set; }
  65. public DateTime EndTime { get; set; }
  66. public TimeChartDataLine(string dataName, string module, DateTime startTime, DateTime endTime) : base(dataName)
  67. {
  68. StartTime = startTime;
  69. EndTime = endTime;
  70. Module = module;
  71. }
  72. }
  73. public class QueryIndexer
  74. {
  75. public TimeChartDataLine DataLine { get; set; }
  76. public List<string> DataList { get; set; }
  77. public DateTime TimeToken { get; set; }
  78. }
  79. public bool IsPermission { get => this.Permission == 3; }
  80. private byte _directionByte = 0x03;
  81. private ProcessDetailView view;
  82. /// <summary>
  83. /// 正在导出数据事件。
  84. /// </summary>
  85. private event EventHandler Exporting;
  86. private CancellationTokenSource _cancellationTokenSource;
  87. #region Property
  88. private const int MAX_PARAMETERS = 20;
  89. private Queue<Color> colorQueue = new Queue<Color>(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,
  90. Color.CornflowerBlue,Color.DarkBlue,Color.DarkCyan,Color.DarkGray,Color.DarkGreen,Color.DarkKhaki,Color.DarkMagenta,Color.DarkOliveGreen, Color.DarkOrange,
  91. Color.DarkSeaGreen,Color.DarkSlateBlue,Color.DarkSlateGray,Color.DarkViolet,Color.DeepPink,Color.DeepSkyBlue,Color.DimGray, Color.DodgerBlue,Color.ForestGreen, Color.Gold,
  92. Color.Gray,Color.GreenYellow,Color.HotPink,Color.Indigo,Color.Khaki,Color.LightBlue,Color.LightCoral,Color.LightGreen, Color.LightPink,Color.LightSalmon,Color.LightSkyBlue,
  93. Color.LightSlateGray,Color.LightSteelBlue,Color.LimeGreen,Color.MediumOrchid,Color.MediumPurple,Color.MediumSeaGreen,Color.MediumSlateBlue,Color.MediumSpringGreen,
  94. Color.MediumTurquoise,Color.Moccasin,Color.NavajoWhite,Color.Olive,Color.OliveDrab,Color.OrangeRed,Color.Orchid,Color.PaleGoldenrod,Color.PaleGreen,
  95. Color.PeachPuff,Color.Peru,Color.Plum,Color.PowderBlue,Color.RosyBrown,Color.RoyalBlue,Color.SaddleBrown,Color.Salmon,Color.SeaGreen, Color.Sienna,
  96. Color.SkyBlue,Color.SlateBlue,Color.SlateGray,Color.SpringGreen,Color.Teal,Color.Aquamarine,Color.Tomato,Color.Turquoise,Color.Violet,Color.Wheat, Color.YellowGreen});
  97. private ObservableCollection<ParameterNode> _ParameterNodes;
  98. public ObservableCollection<ParameterNode> ParameterNodes
  99. {
  100. get { return _ParameterNodes; }
  101. set { _ParameterNodes = value; NotifyOfPropertyChange("ParameterNodes"); }
  102. }
  103. public List<ParameterNode> DoubleParameterNodes { get; set; } = new List<ParameterNode>();
  104. public ObservableCollection<IRenderableSeries> SelectedData { get; set; }
  105. public ObservableCollection<IRenderableSeries> SynSelectedData { get; set; }
  106. public List<ProcessHistoryLot> RecipeDatas { get; set; }
  107. private static object _lockSelection = new object();
  108. private AutoRange _autoRange;
  109. public AutoRange ChartAutoRange
  110. {
  111. get { return _autoRange; }
  112. set
  113. {
  114. _autoRange = value;
  115. NotifyOfPropertyChange(nameof(ChartAutoRange));
  116. }
  117. }
  118. private DoubleRange _timeRange;
  119. public DoubleRange VisibleRangeTime
  120. {
  121. get { return _timeRange; }
  122. set
  123. {
  124. _timeRange = value;
  125. NotifyOfPropertyChange(nameof(VisibleRangeTime));
  126. }
  127. }
  128. private IRange _VisibleRangeValue;
  129. public IRange VisibleRangeValue
  130. {
  131. get { return _VisibleRangeValue; }
  132. set { _VisibleRangeValue = value; NotifyOfPropertyChange(nameof(VisibleRangeValue)); }
  133. }
  134. private DoubleRange _doubleRangeTime;
  135. public DoubleRange DoubleRangeTime
  136. {
  137. get => _doubleRangeTime;
  138. set
  139. {
  140. if (value != _doubleRangeTime)
  141. {
  142. _doubleRangeTime = value;
  143. NotifyOfPropertyChange(nameof(DoubleRangeTime));
  144. }
  145. }
  146. }
  147. private bool _isDoubleChartLinkage=true;
  148. public bool IsDoubleChartLinkage
  149. {
  150. get { return _isDoubleChartLinkage; }
  151. set
  152. {
  153. if (_isDoubleChartLinkage != value)
  154. {
  155. _isDoubleChartLinkage = value;
  156. NotifyOfPropertyChange(nameof(IsDoubleChartLinkage));
  157. if (!value) VisibleRangeTime.Adapt(DoubleRangeTime);
  158. ApplyBindings(value);
  159. }
  160. }
  161. }
  162. private PeriodicJob _thread;
  163. private ConcurrentBag<QueryIndexer> _lstTokenTimeData = new ConcurrentBag<QueryIndexer>();
  164. private Dictionary<string, string> _processDetailDisplayDic = new Dictionary<string, string>();
  165. private string _resolution;
  166. private AnnotationCollection _annotations;
  167. public AnnotationCollection Annotations
  168. {
  169. get => _annotations;
  170. set
  171. {
  172. _annotations = value;
  173. InvokePropertyChanged(nameof(Annotations));
  174. }
  175. }
  176. //StartTime,EndTime,StepNo,StepName
  177. private List<StepInfo> _stepInfo = new List<StepInfo>();
  178. public List<StepInfo> StepInfo
  179. {
  180. get { return _stepInfo; }
  181. set { _stepInfo = value; this.NotifyOfPropertyChange(nameof(StepInfo)); }
  182. }
  183. public bool IsStepVisiable => RecipeDatas.Count == 1;
  184. public DateTime StepStartTime { get; set; }
  185. public DateTime StepEndTime { get; set; }
  186. private bool _isAdding;
  187. private string _stepName;
  188. public string StepNameDisPlay
  189. {
  190. get { return _stepName; }
  191. set
  192. {
  193. if (_stepName != value)
  194. {
  195. _stepName = value;
  196. NotifyOfPropertyChange(nameof(StepNameDisPlay));
  197. }
  198. }
  199. }
  200. private string _recipeNameDisPlay;
  201. public string RecipeNameDisPlay
  202. {
  203. get { return _recipeNameDisPlay; }
  204. set
  205. {
  206. if (_recipeNameDisPlay != value)
  207. {
  208. _recipeNameDisPlay = value;
  209. NotifyOfPropertyChange(nameof(RecipeNameDisPlay));
  210. }
  211. }
  212. }
  213. private DateTime _pointTime;
  214. public DateTime PointTime
  215. {
  216. get { return _pointTime; }
  217. set
  218. {
  219. if (_pointTime != value)
  220. {
  221. _pointTime = value;
  222. NotifyOfPropertyChange(nameof(PointTime));
  223. }
  224. }
  225. }
  226. private double _lastPointX;
  227. private string _direction = "XYDirection";
  228. public string Direction
  229. {
  230. get { return _direction; }
  231. set
  232. {
  233. if (value != _direction)
  234. {
  235. _direction = value;
  236. if (_direction == "XDirection") _directionByte = 1;
  237. else if (_direction == "YDirection") _directionByte = 2;
  238. else if (_direction == "XYDirection") _directionByte = 3;
  239. NotifyOfPropertyChange(nameof(Direction));
  240. }
  241. }
  242. }
  243. //public Tuple<DateTime,double> _timePairs;
  244. private MultiLineXAxisLabelProvider _mulitiLineLabel;
  245. public MultiLineXAxisLabelProvider MultiLineLabel
  246. {
  247. get { return _mulitiLineLabel; }
  248. set
  249. {
  250. if (_mulitiLineLabel != value)
  251. {
  252. _mulitiLineLabel = value;
  253. NotifyOfPropertyChange(nameof(MultiLineLabel));
  254. }
  255. }
  256. }
  257. private double _xScale = 1;
  258. public double XScale
  259. {
  260. get { return _xScale; }
  261. set
  262. {
  263. if (_xScale != value)
  264. {
  265. _xScale = value;
  266. NotifyOfPropertyChange(nameof(XScale));
  267. }
  268. }
  269. }
  270. private double _yScale = 0.1;
  271. public double YScale
  272. {
  273. get { return _yScale; }
  274. set
  275. {
  276. if (value != _yScale)
  277. {
  278. _yScale = value;
  279. NotifyOfPropertyChange(nameof(YScale));
  280. }
  281. }
  282. }
  283. #endregion
  284. private RealtimeProvider _realtimeProvider;
  285. #region Function
  286. public ProcessDetailViewModel(List<ProcessHistoryLot> recipes)
  287. {
  288. _realtimeProvider = new RealtimeProvider();
  289. DisplayName = "Process Detail";
  290. RecipeDatas = recipes;
  291. ParameterNodes = _realtimeProvider.GetParameters(out var dict);
  292. DoubleParameterNodes = _realtimeProvider.GetParameters(out dict).ToList();
  293. for (int j = 0; j < ParameterNodes.Count; j++)
  294. {
  295. ParameterNodes[j].IsVisibilityParentNode = Visibility.Hidden;
  296. DoubleParameterNodes[j].IsVisibilityParentNode = Visibility.Hidden;
  297. }
  298. _processDetailDisplayDic = dict;
  299. if (recipes == null || recipes.Count == 0)
  300. {
  301. return;
  302. }
  303. SelectedData = new ObservableCollection<IRenderableSeries>();
  304. SynSelectedData = new ObservableCollection<IRenderableSeries>();
  305. VisibleRangeValue = new DoubleRange(0, 10);
  306. // Annotations = new AnnotationCollection();
  307. _thread = new PeriodicJob(200, MonitorData, "ProcessDetail", true);
  308. try
  309. {
  310. RecipeDatas.ToList().ForEach(recipe =>
  311. {
  312. QueryStep(recipe.StartTime, recipe.EndTime);
  313. });
  314. if (StepInfo != null && StepInfo.Count > 0)
  315. {
  316. StepStartTime = StepInfo.FirstOrDefault().StartTime;
  317. StepEndTime = StepInfo.LastOrDefault().EndTime;
  318. }
  319. MultiLineLabel = new MultiLineXAxisLabelProvider(StepStartTime);
  320. }
  321. catch (Exception ex)
  322. {
  323. LOG.Info(ex.StackTrace + ":" + ex.Message);
  324. }
  325. }
  326. protected override void OnViewLoaded(object view)
  327. {
  328. base.OnViewLoaded(view);
  329. this.view = (ProcessDetailView)view;
  330. ApplyBindings(IsDoubleChartLinkage);
  331. }
  332. protected override void OnActivate()
  333. {
  334. _resolution = "f1";
  335. if (QueryDataClient.Instance.Service.GetConfig($"System.DataHistoryResolution") != null)
  336. _resolution = $"f{QueryDataClient.Instance.Service.GetConfig($"System.DataHistoryResolution")}";
  337. base.OnActivate();
  338. }
  339. public void QueryStep(DateTime starTime, DateTime endTime)//, string recipeName去掉查询recipeName名称,有嵌套调用
  340. {
  341. starTime = starTime.AddMinutes(-1);
  342. endTime = endTime.AddMinutes(1);
  343. 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;";
  344. DataTable dbData = QueryDataClient.Instance.Service.QueryData(sql);
  345. if (dbData != null && dbData.Rows.Count > 0)
  346. {
  347. List<ProcessDataLot> ProcessDataLotList = new List<ProcessDataLot>();
  348. for (int i = 0; i < dbData.Rows.Count; i++)
  349. {
  350. ProcessDataLot item = new ProcessDataLot();
  351. item.GUID = dbData.Rows[i]["guid"].ToString();
  352. item.RecipeName = dbData.Rows[i]["recipe_name"].ToString().Trim('\\');
  353. item.ProcessStatus = dbData.Rows[i]["process_status"].ToString();
  354. item.WaferDataGUID = dbData.Rows[i]["wafer_data_guid"].ToString();
  355. item.ProcessIn = dbData.Rows[i]["process_in"].ToString();
  356. if (!dbData.Rows[i]["process_begin_time"].Equals(DBNull.Value))
  357. {
  358. item.ProcessBeginTime = (DateTime)dbData.Rows[i]["process_begin_time"];
  359. }
  360. if (!dbData.Rows[i]["process_end_time"].Equals(DBNull.Value))
  361. {
  362. item.ProcessEndTime = (DateTime)dbData.Rows[i]["process_end_time"];
  363. }
  364. ProcessDataLotList.Add(item);
  365. }
  366. //Annotations.Add(VerLine(Media.Brushes.Blue, ProcessDataLotList[0].ProcessBeginTime, Media.Brushes.Blue, $"{ProcessDataLotList[0].RecipeName}"));
  367. //Annotations.Add(VerLine(Media.Brushes.Blue, ProcessDataLotList[0].ProcessEndTime, Media.Brushes.Blue, $"Recipe End"));
  368. string sql2 = $"SELECT * FROM \"recipe_step_data\" where";
  369. sql2 += $" \"recipe_step_data\".\"process_data_guid\" = '{ProcessDataLotList[0].GUID.ToString()}'";
  370. sql2 += " order by \"step_begin_time\" ASC;";
  371. using (var table = QueryDataClient.Instance.Service.QueryData(sql2))
  372. {
  373. if (!(table == null || table.Rows.Count == 0))
  374. {
  375. for (int i = 0; i < table.Rows.Count; i++)
  376. {
  377. var item = table.Rows[i];
  378. DateTime StartTime = DateTime.MinValue;
  379. DateTime EndTime = DateTime.MinValue;
  380. double stepTime = 0;
  381. if (!item["step_begin_time"].Equals(DBNull.Value))
  382. StartTime = (DateTime)item["step_begin_time"];
  383. if (!item["step_end_time"].Equals(DBNull.Value))
  384. EndTime = (DateTime)item["step_end_time"];
  385. if (!item["step_time"].Equals(DBNull.Value))
  386. {
  387. stepTime = (float)item["step_time"];
  388. }
  389. string stepNo = item["step_number"].ToString();
  390. string stepName = item["step_name"].ToString();
  391. if (StartTime > DateTime.MinValue && EndTime > DateTime.MinValue)
  392. {
  393. var time = StartTime.AddSeconds(stepTime);
  394. if (EndTime < time && time < ProcessDataLotList[0].ProcessEndTime)//解决process过程abort,数据导出。
  395. {
  396. EndTime = StartTime.AddSeconds(stepTime);
  397. }
  398. else
  399. {
  400. if (_stepInfo.Any())//临时处理表中recipe_step_data step_end_time数据不能真实反映步次结束时间的问题
  401. {
  402. int lastIndex = _stepInfo.Count - 1;
  403. if (_stepInfo[lastIndex].EndTime > StartTime) _stepInfo[lastIndex].EndTime = StartTime;
  404. }
  405. _stepInfo.Add(new StepInfo() { StartTime = StartTime, EndTime = EndTime, StepName = stepName, StepTime = stepTime, StepNo = stepNo });
  406. }
  407. }
  408. }
  409. }
  410. }
  411. }
  412. }
  413. public static VerticalLineAnnotation VerLine(Media.Brush stroke, DateTime x, Media.Brush color, string text)
  414. {
  415. var label = new AnnotationLabel()
  416. {
  417. LabelPlacement = LabelPlacement.TopRight,
  418. FontSize = 12,
  419. RotationAngle = 0,
  420. Foreground = color,
  421. Text = text
  422. };
  423. var line = new VerticalLineAnnotation()
  424. {
  425. Stroke = stroke,
  426. StrokeThickness = 1,
  427. X1 = x,
  428. IsEditable = false,
  429. VerticalAlignment = VerticalAlignment.Stretch,
  430. AnnotationLabels = new ObservableCollection<AnnotationLabel>() { label },
  431. };
  432. return line;
  433. }
  434. protected bool MonitorData()
  435. {
  436. try
  437. {
  438. if (_isAdding)
  439. return true;
  440. bool allUpdated = true;
  441. lock (_lockSelection)
  442. {
  443. foreach (var item in _lstTokenTimeData)
  444. {
  445. DateTime timeFrom = item.TimeToken;
  446. if (timeFrom >= item.DataLine.EndTime)
  447. continue;
  448. allUpdated = false;
  449. ChartAutoRange = AutoRange.Always;
  450. DateTime timeTo = timeFrom.AddMinutes(60);
  451. if (timeTo.DayOfYear > timeFrom.DayOfYear)
  452. timeTo = new DateTime(timeFrom.Year, timeFrom.Month, timeFrom.Day).AddDays(1);
  453. if (timeTo > item.DataLine.EndTime)
  454. timeTo = item.DataLine.EndTime;
  455. item.TimeToken = timeTo;
  456. GetData(item.DataList, timeFrom, timeTo, item.DataLine.Module, item.DataLine.DataSource);
  457. #region Update VisualMin、VisualMax、DataStatisticsInfo
  458. Application.Current.Dispatcher.BeginInvoke(new Action(() =>
  459. {
  460. double min = ((DoubleRange)VisibleRangeValue).Min;
  461. double max = ((DoubleRange)VisibleRangeValue).Max;
  462. int PointCount = 0;
  463. foreach (var selectedData in SelectedData)
  464. {
  465. var seriesItem = selectedData as ChartDataLine<T>;
  466. if (seriesItem == null)
  467. continue;
  468. double sumValue = 0;
  469. double minValue = 100000;
  470. double maxValue = 0;
  471. double averageValue = 0;
  472. double stdevValue = 0;
  473. double sigma3Value = 0;
  474. var pointValueList = seriesItem.Points.Select(x => x.Item2).ToList();
  475. for (int i = 0; i < pointValueList.Count; i++)
  476. {
  477. sumValue += pointValueList[i];
  478. if (pointValueList[i] < minValue)
  479. minValue = pointValueList[i];
  480. if (pointValueList[i] > maxValue)
  481. maxValue = pointValueList[i];
  482. }
  483. averageValue = pointValueList.Count == 0 ? 0 : sumValue / pointValueList.Count;
  484. for (int i = 0; i < pointValueList.Count; i++)
  485. {
  486. stdevValue += Math.Pow(pointValueList[i] - averageValue, 2);
  487. }
  488. stdevValue = pointValueList.Count == 0 ? 0 : stdevValue / pointValueList.Count;
  489. sigma3Value = Math.Sqrt(stdevValue) * 3;
  490. (seriesItem.Tag as ParameterNode).AverageValue = averageValue.ToString("F2");
  491. (seriesItem.Tag as ParameterNode).MinValue = minValue.ToString("F2");
  492. (seriesItem.Tag as ParameterNode).MaxValue = maxValue.ToString("F2");
  493. (seriesItem.Tag as ParameterNode).Sigma3Value = sigma3Value.ToString("F2");
  494. min = minValue;
  495. if (maxValue != max)
  496. max = maxValue * 1.1;
  497. PointCount = pointValueList.Count;
  498. }
  499. VisibleRangeValue = new DoubleRange(min, max);
  500. }));
  501. #endregion
  502. }
  503. }
  504. if (allUpdated)
  505. {
  506. lock (_lockSelection)
  507. {
  508. while (_lstTokenTimeData.Count > 0)
  509. {
  510. _lstTokenTimeData.TryTake(out _);
  511. }
  512. ChartAutoRange = AutoRange.Never;
  513. }
  514. }
  515. }
  516. catch (Exception ex)
  517. {
  518. LOG.Error(ex.Message);
  519. }
  520. return true;
  521. }
  522. private void GetData(List<string> keys, DateTime from, DateTime to, string module, string dataSource)
  523. {
  524. string sql = "select time AS InternalTimeStamp";
  525. foreach (var dataKey in keys)
  526. {
  527. var dataId = _processDetailDisplayDic.ContainsKey(dataKey) ? _processDetailDisplayDic[dataKey] : dataKey;
  528. sql += "," + string.Format("\"{0}\"", dataId);
  529. }
  530. sql += string.Format(" from \"{0}\" where time > {1} and time <= {2} order by time asc",
  531. from.ToString("yyyyMMdd") + "." + module, from.Ticks, to.Ticks);
  532. DataTable dataTable = QueryDataClient.Instance.Service.QueryData(sql);
  533. Dictionary<string, List<HistoryDataItem>> historyData = new Dictionary<string, List<HistoryDataItem>>();
  534. if (dataTable == null || dataTable.Rows.Count == 0)
  535. return;
  536. DateTime dt = new DateTime();
  537. Dictionary<int, string> colName = new Dictionary<int, string>();
  538. for (int colNo = 0; colNo < dataTable.Columns.Count; colNo++)
  539. {
  540. colName.Add(colNo, dataTable.Columns[colNo].ColumnName);
  541. historyData[dataTable.Columns[colNo].ColumnName] = new List<HistoryDataItem>();
  542. }
  543. for (int rowNo = 0; rowNo < dataTable.Rows.Count; rowNo++)
  544. {
  545. var row = dataTable.Rows[rowNo];
  546. for (int i = 0; i < dataTable.Columns.Count; i++)
  547. {
  548. HistoryDataItem data = new HistoryDataItem();
  549. if (i == 0)
  550. {
  551. dt = new DateTime((long)row[i]);
  552. continue;
  553. }
  554. else
  555. {
  556. string dataId = colName[i];
  557. if (row[i] is DBNull || row[i] == null)
  558. {
  559. data.dateTime = dt;
  560. data.dbName = colName[i];
  561. data.value = 0;
  562. }
  563. else if (row[i] is bool)
  564. {
  565. data.dateTime = dt;
  566. data.dbName = colName[i];
  567. data.value = (bool)row[i] ? 1 : 0;
  568. }
  569. else
  570. {
  571. data.dateTime = dt;
  572. data.dbName = colName[i];
  573. var value = float.Parse(row[i].ToString()).ToString(_resolution);
  574. data.value = float.Parse(value);
  575. }
  576. }
  577. historyData[data.dbName].Add(data);
  578. }
  579. }
  580. Application.Current.Dispatcher.BeginInvoke(new Action(() =>
  581. {
  582. try
  583. {
  584. FillDataToChart(SelectedData, dataSource, historyData);
  585. FillDataToChart(SynSelectedData, dataSource, historyData);
  586. RefresCharView();
  587. }
  588. catch (Exception ex)
  589. {
  590. LOG.Write(ex);
  591. }
  592. }));
  593. }
  594. void FillDataToChart(ObservableCollection<IRenderableSeries> series, string dataSource, Dictionary<string, List<HistoryDataItem>> historyData)
  595. {
  596. var items = series.Where(x => (x as ChartDataLine<T>).DataSource == dataSource);
  597. if (items == null) return;
  598. foreach (var item in items)
  599. {
  600. var seriesItem = item as ChartDataLine<T>;
  601. if (seriesItem == null)
  602. continue;
  603. foreach (var data in historyData)
  604. {
  605. var dataKey = _processDetailDisplayDic.ContainsKey(seriesItem.DataName) ? _processDetailDisplayDic[seriesItem.DataName] : seriesItem.DataName;
  606. if (data.Key != dataKey)
  607. continue;
  608. seriesItem.Capacity += data.Value.Count;
  609. //DateTime beginTime = StepStartTime;
  610. for (int i = 0; i < data.Value.Count; i++)
  611. {
  612. var historyDataItem = data.Value[i];
  613. if (typeof(T) == typeof(double))
  614. {
  615. //xData = Math.Round((historyDataItem.dateTime - beginTime).TotalMilliseconds / 1000, 0, MidpointRounding.AwayFromZero);
  616. seriesItem.Append((T)Convert.ChangeType((historyDataItem.dateTime - StepStartTime).TotalMilliseconds / 1000d, typeof(T)), historyDataItem.value);
  617. }
  618. else
  619. seriesItem.Append((T)Convert.ChangeType(historyDataItem.dateTime, typeof(T)), historyDataItem.value);
  620. }
  621. }
  622. }
  623. }
  624. /// <summary>
  625. /// 获取时间列表
  626. /// </summary>
  627. /// <param name="from"></param>
  628. /// <param name="to"></param>
  629. /// <param name="module"></param>
  630. /// <param name="dataSource"></param>
  631. private void GetData(DateTime from, DateTime to, string module = "PM1")
  632. {
  633. string sql = "select time AS InternalTimeStamp,\"PM1.RecipeTotalElapseTime\"";
  634. sql += string.Format(" from \"{0}\" where time > {1} and time <= {2} order by time limt 1",
  635. from.ToString("yyyyMMdd") + "." + module, from.Ticks, to.Ticks);
  636. DataTable dataTable = QueryDataClient.Instance.Service.QueryData(sql);
  637. Dictionary<string, List<HistoryDataItem>> historyData = new Dictionary<string, List<HistoryDataItem>>();
  638. if (dataTable == null || dataTable.Rows.Count == 0)
  639. {
  640. return;
  641. }
  642. foreach (DataRow row in dataTable.Rows)
  643. {
  644. DateTime dt = new DateTime();
  645. dt = new DateTime((long)row[0]);
  646. var elapseTime = Convert.ToDouble(row[1]);
  647. }
  648. }
  649. private void SelectedDataChanged()
  650. {
  651. foreach (var item in SelectedData)
  652. {
  653. if (item.Stroke.Equals(System.Windows.Media.Color.FromArgb(255, 0, 0, 255)))
  654. {
  655. Color drawingColor = colorQueue.Peek();
  656. item.Stroke = System.Windows.Media.Color.FromRgb(drawingColor.R, drawingColor.G, drawingColor.B);
  657. colorQueue.Enqueue(colorQueue.Dequeue());
  658. }
  659. }
  660. }
  661. public void TxtMouseLeftButtonDown(ParameterNode node, ObservableCollection<IRenderableSeries> series)
  662. {
  663. node.Selected = !node.Selected;
  664. ParameterCheck(node, series);
  665. }
  666. public void ParameterCheck(ParameterNode node, ObservableCollection<IRenderableSeries> series)
  667. {
  668. bool result = RefreshTreeStatusToChild(node, series);
  669. if (!result)
  670. {
  671. node.Selected = !node.Selected;
  672. DialogBox.ShowWarning($"The max number of parameters is {MAX_PARAMETERS}.");
  673. }
  674. else
  675. RefreshTreeStatusToParent(node);
  676. }
  677. /// <summary>
  678. /// Refresh tree node status from current to children, and add data to SelectedData
  679. /// </summary>
  680. private bool RefreshTreeStatusToChild(ParameterNode node, ObservableCollection<IRenderableSeries> SelectedData)
  681. {
  682. if (node?.ChildNodes.Count > 0)
  683. {
  684. for (int i = 0; i < node.ChildNodes.Count; i++)
  685. {
  686. ParameterNode n = node.ChildNodes[i];
  687. n.Selected = node.Selected;
  688. if (!RefreshTreeStatusToChild(n, SelectedData))
  689. {
  690. n.Selected = !n.Selected;
  691. return false;
  692. }
  693. }
  694. }
  695. else //leaf node
  696. {
  697. bool lockTaken = false;
  698. try
  699. {
  700. var item = SelectedData?.FirstOrDefault(x => (x as ChartDataLine<T>).DataName == node.Name);
  701. bool isExist = item != null;
  702. if (isExist && !node.Selected)//删除
  703. {
  704. SelectedData.Remove(item);
  705. }
  706. else
  707. {
  708. if (!isExist && node.Selected)
  709. {
  710. if (SelectedData.Count >= MAX_PARAMETERS)
  711. {
  712. return false;
  713. }
  714. Monitor.TryEnter(_lockSelection, 1000, ref lockTaken);
  715. if (lockTaken)
  716. {
  717. var dataId = _processDetailDisplayDic.ContainsKey(node.Name) ? _processDetailDisplayDic[node.Name] : node.Name;
  718. var module = dataId.Split('.').ToList()[0];
  719. _isAdding = true;
  720. foreach (var recipe in RecipeDatas)
  721. {
  722. TimeChartDataLine line;
  723. if (IsStepVisiable)
  724. line = new TimeChartDataLine(node.Name.Replace("Tube", "PM1"), module, StepStartTime, StepEndTime);
  725. else
  726. line = new TimeChartDataLine(node.Name.Replace("Tube", "PM1"), module, recipe.StartTime, recipe.EndTime);
  727. line.DataSource = $"{recipe.BatchID}.{recipe.RecipeName}";
  728. line.Tag = node;
  729. if (isExist)
  730. {
  731. line.Stroke = item.Stroke;
  732. line.IsVisible = item.IsVisible;
  733. line.ClearData();
  734. SelectedData.Remove(item);
  735. }
  736. else
  737. SelectedData.Add(line);
  738. AddToMonitor(line);
  739. }
  740. _isAdding = false;
  741. if (!isExist)
  742. SelectedDataChanged();
  743. }
  744. }
  745. }
  746. }
  747. finally
  748. {
  749. if (lockTaken)
  750. {
  751. Monitor.Exit(_lockSelection);
  752. }
  753. }
  754. }
  755. return true;
  756. }
  757. private void AddToMonitor(TimeChartDataLine line)
  758. {
  759. QueryIndexer indexer = new QueryIndexer()
  760. {
  761. DataLine = line,
  762. DataList = new List<string>() { line.DataName },
  763. TimeToken = line.StartTime,
  764. };
  765. _lstTokenTimeData.Add(indexer);
  766. }
  767. /// <summary>
  768. /// Refresh tree node status from current to parent
  769. /// </summary>
  770. /// <param name="node"></param>
  771. /// <returns></returns>
  772. private void RefreshTreeStatusToParent(ParameterNode node)
  773. {
  774. if (node.ParentNode != null)
  775. {
  776. if (node.Selected)
  777. {
  778. bool flag = true;
  779. for (int i = 0; i < node.ParentNode.ChildNodes.Count; i++)
  780. {
  781. if (!node.ParentNode.ChildNodes[i].Selected)
  782. {
  783. flag = false; //as least one child is unselected
  784. break;
  785. }
  786. }
  787. if (flag)
  788. node.ParentNode.Selected = true;
  789. }
  790. else
  791. {
  792. node.ParentNode.Selected = false;
  793. }
  794. RefreshTreeStatusToParent(node.ParentNode);
  795. }
  796. }
  797. #region Parameter Grid Control
  798. public void DeleteAll()
  799. {
  800. //uncheck all tree nodes
  801. foreach (ChartDataLine<T> cp in SelectedData)
  802. {
  803. (cp.Tag as ParameterNode).Selected = false;
  804. RefreshTreeStatusToParent(cp.Tag as ParameterNode);
  805. }
  806. SelectedData.Clear();
  807. }
  808. private void SetParameterNode(ObservableCollection<ParameterNode> nodes, bool isChecked)
  809. {
  810. foreach (ParameterNode n in nodes)
  811. {
  812. n.Selected = isChecked;
  813. SetParameterNode(n.ChildNodes, isChecked);
  814. }
  815. }
  816. public void Delete(ChartDataLine<T> cp)
  817. {
  818. if (cp != null)
  819. {
  820. if (SelectedData.Contains(cp))
  821. {
  822. //uncheck tree node
  823. (cp.Tag as ParameterNode).Selected = false;
  824. RefreshTreeStatusToParent(cp.Tag as ParameterNode);
  825. SelectedData.Remove(cp);
  826. }
  827. }
  828. }
  829. public async void ExportAll()
  830. {
  831. try
  832. {
  833. if (SelectedData.Count == 0)
  834. {
  835. MessageBox.Show($"Please select the data you want to export.", "Export", MessageBoxButton.OK,
  836. MessageBoxImage.Warning);
  837. return;
  838. }
  839. Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
  840. dlg.DefaultExt = ".xlsx"; // Default file extension
  841. dlg.Filter = "Excel数据表格文件(*.xlsx)|*.xlsx"; // Filter files by extension
  842. dlg.FileName = $"{DisplayName}_{string.Join(",", RecipeDatas.Select(x => x.RecipeName.Replace('\\', '.')).ToArray())}_{DateTime.Now:yyyyMMdd_HHmmss}";
  843. Nullable<bool> result = dlg.ShowDialog();// Show open file dialog box
  844. if (result == true) // Process open file dialog box results
  845. {
  846. Exporting?.Invoke(this, System.EventArgs.Empty);
  847. _cancellationTokenSource = new CancellationTokenSource();
  848. var sw = new Stopwatch();
  849. sw.Restart();
  850. System.Data.DataSet ds = new System.Data.DataSet();
  851. ds.Tables.Add(new System.Data.DataTable($"{DisplayName}_{DateTime.Now:yyyyMMdd_HHmmss}"));
  852. ds.Tables[0].Columns.Add("Recipe Info");
  853. ds.Tables[0].Columns[0].DataType = typeof(string);
  854. ds.Tables[0].Columns.Add("Date");
  855. ds.Tables[0].Columns[1].DataType = typeof(string);
  856. ds.Tables[0].Columns.Add("Time");
  857. ds.Tables[0].Columns[2].DataType = typeof(string);
  858. ds.Tables[0].Columns.Add("Step ID");
  859. ds.Tables[0].Columns[3].DataType = typeof(string);
  860. ds.Tables[0].Columns.Add("Step Name");
  861. ds.Tables[0].Columns[4].DataType = typeof(string);
  862. Dictionary<T, double[]> timeValue = new Dictionary<T, double[]>();
  863. await Task.Run(() =>
  864. {
  865. for (int i = 0; i < SelectedData.Count; i++)
  866. {
  867. List<Tuple<T, double>> data = (SelectedData[i] as ChartDataLine<T>).Points;
  868. foreach (var tuple in data)
  869. {
  870. if (!timeValue.ContainsKey(tuple.Item1))
  871. timeValue[tuple.Item1] = new double[SelectedData.Count];
  872. timeValue[tuple.Item1][i] = tuple.Item2;
  873. }
  874. ds.Tables[0].Columns.Add((SelectedData[i] as ChartDataLine<T>).DataName);
  875. ds.Tables[0].Columns[i + 5].DataType = typeof(double);
  876. }
  877. var recipeInfoRow = ds.Tables[0].NewRow();
  878. recipeInfoRow[0] = $"Recipe:{string.Join(",", RecipeDatas.Select(x => x.RecipeName).ToArray())}";
  879. ds.Tables[0].Rows.Add(recipeInfoRow);
  880. recipeInfoRow = ds.Tables[0].NewRow();
  881. recipeInfoRow[0] = $"Start Time";
  882. recipeInfoRow[1] = string.Join(",", RecipeDatas.Select(x => x.StartTime).ToArray());
  883. recipeInfoRow[2] = string.Join(",", RecipeDatas.Select(x => x.StartTime).ToArray());
  884. ds.Tables[0].Rows.Add(recipeInfoRow);
  885. recipeInfoRow = ds.Tables[0].NewRow();
  886. recipeInfoRow[0] = $"End Time";
  887. recipeInfoRow[1] = string.Join(",", RecipeDatas.Select(x => x.EndTime).ToArray());
  888. recipeInfoRow[2] = string.Join(",", RecipeDatas.Select(x => x.EndTime).ToArray());
  889. ds.Tables[0].Rows.Add(recipeInfoRow);
  890. QueryDataClientFromTable(ds);
  891. }, _cancellationTokenSource.Token).ContinueWith(t =>
  892. {
  893. if (t.IsCanceled || t.IsFaulted)
  894. return;
  895. });
  896. if (_cancellationTokenSource?.Token.IsCancellationRequested == true)
  897. return;
  898. if (!ExcelHelper.ExportToExcel(dlg.FileName, ds, out string reason))
  899. {
  900. MessageBox.Show($"Export failed, {reason}", "Export", MessageBoxButton.OK, MessageBoxImage.Warning);
  901. return;
  902. }
  903. MessageBox.Show($"Export succeed, file save as {dlg.FileName}", "Export", MessageBoxButton.OK, MessageBoxImage.Information);
  904. }
  905. }
  906. catch (Exception ex)
  907. {
  908. LOG.Write(ex);
  909. MessageBox.Show("Write failed," + ex.Message, "export failed", MessageBoxButton.OK, MessageBoxImage.Warning);
  910. }
  911. }
  912. public void DGSelectionChanged(object sender, EventArgs e)
  913. {
  914. var temp = (DataGrid)sender;
  915. var tempSelected = (IRenderableSeries)temp.SelectedItem;
  916. tempSelected.IsVisible = !tempSelected.IsVisible;
  917. }
  918. private void QueryDataClientFromTable(DataSet ds)
  919. {
  920. DateTime startTime = StepStartTime;
  921. DateTime endTime = StepEndTime;
  922. if (StepStartTime.Date == StepEndTime.Date)
  923. {
  924. SaveDataToTable(ds, startTime, endTime);
  925. }
  926. else
  927. {
  928. endTime = new DateTime(startTime.Year, startTime.Month, startTime.Day, 23, 59, 59);
  929. while (endTime < StepEndTime)
  930. {
  931. SaveDataToTable(ds, startTime, endTime);
  932. startTime = new DateTime(startTime.Year, startTime.Month, startTime.Day, 0, 0, 0).AddDays(1);
  933. endTime = new DateTime(startTime.Year, startTime.Month, startTime.Day, 23, 59, 59);
  934. }
  935. SaveDataToTable(ds, startTime, StepEndTime);
  936. }
  937. }
  938. private void SaveDataToTable(DataSet ds, DateTime startTime, DateTime endTime)
  939. {
  940. string stepID = "", stepName = "";
  941. string pmsql = "select time AS InternalTimeStamp";
  942. var pmColNames = _realtimeProvider.GetDBCol(startTime.ToString("yyyyMMdd") + "." + "PM1");
  943. List<string> keys = SelectedData.Select(x => (x as ChartDataLine<T>).DataName).ToList();
  944. DataTable pmDataTable = null;
  945. if (keys != null && keys.Count > 0)
  946. {
  947. List<string> pmList = new List<string>();
  948. foreach (var dataKey in keys)
  949. {
  950. var dataId = _processDetailDisplayDic.ContainsKey(dataKey) ? _processDetailDisplayDic[dataKey] : dataKey;
  951. var module = dataId.Split('.').ToList()[0];
  952. if (module.ToLower() == "pm1")
  953. {
  954. if (!pmColNames.Contains(dataId))
  955. {
  956. continue;
  957. }
  958. pmList.Add(dataId);
  959. pmsql += "," + string.Format("\"{0}\"", dataId);
  960. }
  961. }
  962. if (pmList.Count > 0)
  963. {
  964. pmsql += string.Format(" from \"{0}\" where time > {1} and time <= {2} order by time asc",
  965. startTime.ToString("yyyyMMdd") + "." + "PM1", startTime.Ticks, endTime.Ticks);
  966. pmDataTable = QueryDataClient.Instance.Service.QueryData(pmsql);
  967. if (pmDataTable == null)
  968. {
  969. MessageBox.Show($"Export failed, sql:{pmsql}", "Export", MessageBoxButton.OK, MessageBoxImage.Warning);
  970. return;
  971. }
  972. }
  973. }
  974. string systemsql = "select time AS InternalTimeStamp";
  975. var systemColNames = _realtimeProvider.GetDBCol(startTime.ToString("yyyyMMdd") + "." + "System");
  976. DataTable systemDataTable = null;
  977. if (keys != null && keys.Count > 0)
  978. {
  979. List<string> systemList = new List<string>();
  980. foreach (var dataKey in keys)
  981. {
  982. var dataId = _processDetailDisplayDic.ContainsKey(dataKey) ? _processDetailDisplayDic[dataKey] : dataKey;
  983. var module = dataId.Split('.').ToList()[0];
  984. if (module.ToLower() == "system")
  985. {
  986. if (!systemColNames.Contains(dataId))
  987. {
  988. continue;
  989. }
  990. systemsql += "," + string.Format("\"{0}\"", dataId);
  991. systemList.Add(dataId);
  992. }
  993. }
  994. if (systemList.Count > 0)
  995. {
  996. systemsql += string.Format(" from \"{0}\" where time > {1} and time <= {2} order by time asc",
  997. startTime.ToString("yyyyMMdd") + "." + "System", startTime.Ticks, endTime.Ticks);
  998. systemDataTable = QueryDataClient.Instance.Service.QueryData(systemsql);
  999. if (systemDataTable == null)
  1000. {
  1001. MessageBox.Show($"Export failed, sql:{systemsql}", "Export", MessageBoxButton.OK, MessageBoxImage.Warning);
  1002. return;
  1003. }
  1004. }
  1005. }
  1006. int maxRow = 0;
  1007. if ((pmDataTable == null || pmDataTable.Rows.Count == 0))
  1008. {
  1009. if (systemDataTable != null)
  1010. {
  1011. maxRow = systemDataTable.Rows.Count;
  1012. }
  1013. }
  1014. else if ((systemDataTable == null || systemDataTable.Rows.Count == 0))
  1015. {
  1016. if (pmDataTable != null)
  1017. {
  1018. maxRow = pmDataTable.Rows.Count;
  1019. }
  1020. }
  1021. else
  1022. {
  1023. maxRow = pmDataTable.Rows.Count > systemDataTable.Rows.Count ? systemDataTable.Rows.Count : pmDataTable.Rows.Count;
  1024. }
  1025. for (int i = 0; i < maxRow; i++)
  1026. {
  1027. var pmRow = pmDataTable != null ? pmDataTable.Rows[i] : null;
  1028. var systemRow = systemDataTable != null ? systemDataTable.Rows[i] : null;
  1029. //float timeIndex = 0;
  1030. //float.TryParse(item.Key.ToString(), out timeIndex);
  1031. //DateTime dateTimeKey = startTime.AddMilliseconds(timeIndex * 1000); ;// DateTime.Parse(item.Key.ToString());
  1032. DateTime dateTimeKey = new DateTime(pmRow != null ? (long)pmRow[0] : (long)systemRow[0]);
  1033. var tempStepInfo = _stepInfo.FirstOrDefault(x => x.StartTime < dateTimeKey && x.EndTime > dateTimeKey);
  1034. if (tempStepInfo != null)// && dateTimeKey > _stepInfo[iIndex].StartTime
  1035. {
  1036. stepID = tempStepInfo.StepNo;
  1037. stepName = tempStepInfo.StepName;
  1038. }
  1039. var row = ds.Tables[0].NewRow();
  1040. row[1] = dateTimeKey.ToString("yyyy/MM/dd");
  1041. row[2] = dateTimeKey.ToString("HH:mm:ss:fff");
  1042. row[3] = stepID;
  1043. row[4] = stepName;
  1044. for (int j = 5; j < ds.Tables[0].Columns.Count; j++)
  1045. {
  1046. string colName = ds.Tables[0].Columns[j].ColumnName;
  1047. DataRow dataRow = null;
  1048. var dataId = _processDetailDisplayDic.ContainsKey(colName) ? _processDetailDisplayDic[colName] : colName;
  1049. var module = dataId.Split('.').ToList()[0];
  1050. int index = 0;
  1051. if (module == "PM1")
  1052. {
  1053. dataRow = pmRow;
  1054. foreach (var item in pmDataTable.Columns)
  1055. {
  1056. if (((DataColumn)item).ColumnName == dataId)
  1057. {
  1058. break;
  1059. }
  1060. index++;
  1061. }
  1062. }
  1063. else if (module == "System")
  1064. {
  1065. dataRow = systemRow;
  1066. foreach (var item in systemDataTable.Columns)
  1067. {
  1068. if (((DataColumn)item).ColumnName == dataId)
  1069. {
  1070. break;
  1071. }
  1072. index++;
  1073. }
  1074. }
  1075. if (dataRow[index] is DBNull || dataRow[index] == null)
  1076. {
  1077. row[j] = dataRow[index];
  1078. }
  1079. else if (dataRow[index] is bool)
  1080. {
  1081. row[j] = (bool)dataRow[index] ? 1 : 0;
  1082. }
  1083. else
  1084. {
  1085. var value = float.Parse(dataRow[index].ToString()).ToString(_resolution);
  1086. row[j] = float.Parse(value);
  1087. }
  1088. }
  1089. ds.Tables[0].Rows.Add(row);
  1090. }
  1091. }
  1092. public void Export(ChartDataLine<T> cp)
  1093. {
  1094. try
  1095. {
  1096. Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
  1097. dlg.DefaultExt = ".xlsx"; // Default file extension
  1098. dlg.Filter = "Excel数据表格文件(*.xlsx)|*.xlsx"; // Filter files by extension
  1099. dlg.FileName = $"{cp.DataName}_{DateTime.Now:yyyyMMdd_HHmmss}";
  1100. Nullable<bool> result = dlg.ShowDialog();// Show open file dialog box
  1101. if (result == true) // Process open file dialog box results
  1102. {
  1103. System.Data.DataSet ds = new System.Data.DataSet();
  1104. ds.Tables.Add(new System.Data.DataTable(cp.DataName));
  1105. ds.Tables[0].Columns.Add("Time");
  1106. ds.Tables[0].Columns[0].DataType = typeof(DateTime);
  1107. ds.Tables[0].Columns.Add(cp.DataName);
  1108. ds.Tables[0].Columns[1].DataType = typeof(double);
  1109. int i = 0;
  1110. foreach (var item in cp.Points)
  1111. {
  1112. var row = ds.Tables[0].NewRow();
  1113. row[0] = StepStartTime.AddSeconds(Convert.ToDouble(item.Item1));
  1114. row[1] = item.Item2;
  1115. ds.Tables[0].Rows.Add(row);
  1116. i++;
  1117. }
  1118. if (!ExcelHelper.ExportToExcel(dlg.FileName, ds, out string reason))
  1119. {
  1120. MessageBox.Show($"Export failed, {reason}", "Export", MessageBoxButton.OK, MessageBoxImage.Warning);
  1121. return;
  1122. }
  1123. MessageBox.Show($"Export succeed, file save as {dlg.FileName}", "Export", MessageBoxButton.OK, MessageBoxImage.Information);
  1124. }
  1125. }
  1126. catch (Exception ex)
  1127. {
  1128. LOG.Write(ex);
  1129. MessageBox.Show("Write failed," + ex.Message, "export failed", MessageBoxButton.OK, MessageBoxImage.Warning);
  1130. }
  1131. }
  1132. public void SelectColor(ChartDataLine<T> cp)
  1133. {
  1134. if (cp == null)
  1135. return;
  1136. var dlg = new System.Windows.Forms.ColorDialog();
  1137. if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
  1138. {
  1139. cp.Stroke = new System.Windows.Media.Color() { A = dlg.Color.A, B = dlg.Color.B, G = dlg.Color.G, R = dlg.Color.R };
  1140. }
  1141. }
  1142. public void CloseCmd()
  1143. {
  1144. ((Window)GetView()).Close();
  1145. }
  1146. #endregion
  1147. #region SciChart Move
  1148. public void RefresCharView()
  1149. {
  1150. this.view.sciChart.ZoomExtents();
  1151. }
  1152. public void ArrowClick(string direction)
  1153. {
  1154. switch (direction)
  1155. {
  1156. case "Up":
  1157. if (VisibleRangeValue is DoubleRange uprange)
  1158. {
  1159. VisibleRangeValue = new DoubleRange(uprange.Min + YScale, uprange.Max + YScale);
  1160. }
  1161. break;
  1162. case "Down":
  1163. if (VisibleRangeValue is DoubleRange downrange)
  1164. {
  1165. VisibleRangeValue = new DoubleRange(downrange.Min - YScale, downrange.Max - YScale);
  1166. }
  1167. break;
  1168. case "Left":
  1169. if (VisibleRangeTime is DoubleRange leftrange)
  1170. {
  1171. VisibleRangeTime = new DoubleRange(leftrange.Min - XScale, leftrange.Max - XScale);
  1172. }
  1173. break;
  1174. case "Right":
  1175. if (VisibleRangeTime is DoubleRange range)
  1176. {
  1177. VisibleRangeTime = new DoubleRange(range.Min + XScale, range.Max + XScale);
  1178. }
  1179. break;
  1180. }
  1181. }
  1182. public void ZoomInClick()//放大
  1183. {
  1184. double scale = 0;
  1185. if ((_directionByte & 0x01) == 1)//x
  1186. {
  1187. //LOG.Info($"A ZoomInClick.X:scale{XScale}-{VisibleRangeTime.Min}: {VisibleRangeTime.Max}");
  1188. if (VisibleRangeTime is DoubleRange range)
  1189. {
  1190. if (range.Max - range.Min <= XScale) return;
  1191. if (range.Max - range.Min > 2 * XScale) scale = XScale;
  1192. else scale = XScale / 2;
  1193. VisibleRangeTime = new DoubleRange(range.Min + scale, range.Max - scale);
  1194. //LOG.Info($"ZoomInClick.X:scale{XScale}-{VisibleRangeTime.Min}: {VisibleRangeTime.Max}");
  1195. }
  1196. }
  1197. if ((_directionByte & 0x02) == 2)//y
  1198. {
  1199. //LOG.Info($"A ZoomInClick.Y:scale{YScale}-{VisibleRangeValue.Min}: {VisibleRangeValue.Max}");
  1200. if (VisibleRangeValue is DoubleRange range)
  1201. {
  1202. if (range.Max - range.Min <= YScale) return;
  1203. if (range.Max - range.Min > 2 * XScale) scale = YScale;
  1204. else scale = YScale / 2;
  1205. VisibleRangeValue = new DoubleRange(range.Min + scale, range.Max - scale);
  1206. //LOG.Info($"ZoomInClick.Y:scale{YScale}-{VisibleRangeValue.Min}: {VisibleRangeValue.Max}");
  1207. }
  1208. }
  1209. }
  1210. public void ZoomOutClick()//缩小
  1211. {
  1212. if ((_directionByte & 0x01) == 1)//x
  1213. {
  1214. //LOG.Info($"A ZoomOutClick.X:scale{XScale}-{VisibleRangeTime.Min}: {VisibleRangeTime.Max}");
  1215. if (VisibleRangeTime is DoubleRange range)
  1216. {
  1217. VisibleRangeTime = new DoubleRange(range.Min - XScale, range.Max + XScale);
  1218. //LOG.Info($"ZoomOutClick.X:scale{XScale}-{VisibleRangeTime.Min}: {VisibleRangeTime.Max}");
  1219. }
  1220. }
  1221. if ((_directionByte & 0x02) == 2)//y
  1222. {
  1223. //LOG.Info($"A ZoomOutClick.Y:scale{YScale}-{VisibleRangeValue.Min}: {VisibleRangeValue.Max}");
  1224. if (VisibleRangeValue is DoubleRange range)
  1225. {
  1226. VisibleRangeValue = new DoubleRange(range.Min - YScale, range.Max + YScale);
  1227. // LOG.Info($"ZoomOutClick.Y:scale{YScale}-{VisibleRangeValue.Min}: {VisibleRangeValue.Max}");
  1228. }
  1229. }
  1230. }
  1231. public void SelectStep()
  1232. {
  1233. ObservableCollection<Option> Items = new ObservableCollection<Option>();
  1234. foreach (var item in StepInfo)
  1235. {
  1236. Items.Add(new Option() { Name = $"{item.StepNo} {item.StepName}", Index = int.Parse(item.StepNo) });
  1237. }
  1238. ItemsSelectDialogViewModel itemsSelectDialogView = new ItemsSelectDialogViewModel();
  1239. itemsSelectDialogView.Items = Items;
  1240. itemsSelectDialogView.ColumnsCount = Items.Count / 10 + 1;
  1241. WindowManager windowManager = IoC.Get<IWindowManager>() as WindowManager;
  1242. if ((bool)(windowManager as WindowManager)?.ShowDialogWithNoWindow(itemsSelectDialogView))
  1243. {
  1244. var startItem = StepInfo.FirstOrDefault(step => step.StepNo == Items.FirstOrDefault(x => x.IsChecked)?.Index.ToString());
  1245. var endItem = StepInfo.FirstOrDefault(step => step.StepNo == Items.LastOrDefault(x => x.IsChecked)?.Index.ToString());
  1246. if (startItem == null)
  1247. {
  1248. DialogBox.ShowError("Please select begin step!");
  1249. return;
  1250. }
  1251. if (endItem == null)
  1252. {
  1253. DialogBox.ShowError("Please select end step!");
  1254. return;
  1255. }
  1256. if (Items.Where(x => x.IsChecked).Count() > 2)
  1257. {
  1258. DialogBox.ShowError("The selected step numbers must be 1 or 2.");
  1259. return;
  1260. }
  1261. StepStartTime = startItem.StartTime;
  1262. StepEndTime = endItem.EndTime;
  1263. List<ParameterNode> allCheckNode = new List<ParameterNode>();
  1264. ParameterNodes.ToList().ForEach(x =>
  1265. {
  1266. allCheckNode.AddRange(GetAllCheckedLeafNode(x));
  1267. });
  1268. allCheckNode.ForEach(x => { ParameterCheck(x, SelectedData); });
  1269. }
  1270. }
  1271. private List<ParameterNode> GetAllCheckedLeafNode(ParameterNode parameterNode)
  1272. {
  1273. List<ParameterNode> retNodes = new List<ParameterNode>();
  1274. if (parameterNode.ChildNodes != null && parameterNode.ChildNodes.Count > 0)
  1275. {
  1276. foreach (var item in parameterNode.ChildNodes)
  1277. {
  1278. retNodes.AddRange(GetAllCheckedLeafNode(item));
  1279. }
  1280. }
  1281. else
  1282. {
  1283. if (parameterNode.Selected)
  1284. retNodes.Add(parameterNode);
  1285. }
  1286. return retNodes;
  1287. }
  1288. #endregion
  1289. #endregion
  1290. public void GetCursorPoint(IEnumerable<SeriesInfo> infos)
  1291. {
  1292. if (infos.Any())
  1293. {
  1294. var seriesinfo = infos.First();
  1295. if (seriesinfo.XValue is double xvalue && _lastPointX != xvalue)
  1296. {
  1297. _lastPointX = xvalue;
  1298. PointTime = StepStartTime.AddSeconds(xvalue);
  1299. if (PointTime == DateTime.MinValue) return;
  1300. var step = _stepInfo.Find(r => r.StartTime <= PointTime && r.EndTime >= PointTime);
  1301. if (step == null)
  1302. {
  1303. LOG.Info($"couldn't find CurrentTime:{PointTime:yyyy/MM/dd HH:mm:ss.FFF} in steps ,display last step:{StepNameDisPlay}");
  1304. }
  1305. else
  1306. {
  1307. StepNameDisPlay = $"{step.StepNo}:{step.StepName}";
  1308. //LOG.Info($"CurrentTime:{PointTime:yyyy/MM/dd HH:mm:ss.FFF} {StepNameDisPlay}");
  1309. }
  1310. var name = (seriesinfo.RenderableSeries as ChartDataLine<T>).DataSource.Split('.', '\\');
  1311. if (name.Length > 0)
  1312. {
  1313. RecipeNameDisPlay = name.Last();
  1314. }
  1315. else RecipeNameDisPlay = string.Empty;
  1316. }
  1317. }
  1318. }
  1319. public void ScaleChange(string direction, double factor)
  1320. {
  1321. double t = 0;
  1322. if (direction == "X")
  1323. {
  1324. t = Math.Floor(_xScale * factor * 10) / 10d;//只保留3位小数
  1325. if (t >= 0.1) XScale = t;
  1326. else DialogBox.ShowWarning("already min value");
  1327. }
  1328. else if (direction == "Y")
  1329. {
  1330. t = Math.Floor(_yScale * factor * 1000) / 1000d;
  1331. if (t >= 0.001) YScale = t;
  1332. else DialogBox.ShowWarning("already min value");
  1333. }
  1334. }
  1335. public void DoubleChartLink()
  1336. {
  1337. if (IsDoubleChartLinkage) IsDoubleChartLinkage = false;
  1338. else IsDoubleChartLinkage = true;
  1339. }
  1340. private void ApplyBindings(bool isLinkMode)
  1341. {
  1342. var axis = view.syncChart.XAxis as NumericAxis;
  1343. BindingOperations.ClearBinding(axis, NumericAxis.VisibleRangeProperty);
  1344. var binding = new Binding(isLinkMode ? nameof(VisibleRangeTime) : nameof(DoubleRangeTime))
  1345. {
  1346. Source = this,
  1347. Mode = BindingMode.TwoWay,
  1348. UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
  1349. };
  1350. BindingOperations.SetBinding(axis, NumericAxis.VisibleRangeProperty, binding);
  1351. }
  1352. }
  1353. public class ProcessDataLot : NotifiableItem
  1354. {
  1355. private string _guid;
  1356. public string GUID
  1357. {
  1358. get => _guid;
  1359. set
  1360. {
  1361. _guid = value;
  1362. InvokePropertyChanged(nameof(GUID));
  1363. }
  1364. }
  1365. private DateTime _processBeginTime;
  1366. public DateTime ProcessBeginTime
  1367. {
  1368. get => _processBeginTime;
  1369. set
  1370. {
  1371. _processBeginTime = value;
  1372. InvokePropertyChanged(nameof(ProcessBeginTime));
  1373. }
  1374. }
  1375. private DateTime _processEndTime;
  1376. public DateTime ProcessEndTime
  1377. {
  1378. get => _processEndTime;
  1379. set
  1380. {
  1381. _processEndTime = value;
  1382. InvokePropertyChanged(nameof(ProcessEndTime));
  1383. }
  1384. }
  1385. private string _recipeName;
  1386. public string RecipeName
  1387. {
  1388. get => _recipeName;
  1389. set
  1390. {
  1391. _recipeName = value;
  1392. InvokePropertyChanged(nameof(RecipeName));
  1393. }
  1394. }
  1395. private string _processStatus;
  1396. public string ProcessStatus
  1397. {
  1398. get => _processStatus;
  1399. set
  1400. {
  1401. _processStatus = value;
  1402. InvokePropertyChanged(nameof(ProcessStatus));
  1403. }
  1404. }
  1405. private string _waferDataguid;
  1406. public string WaferDataGUID
  1407. {
  1408. get => _waferDataguid;
  1409. set
  1410. {
  1411. _waferDataguid = value;
  1412. InvokePropertyChanged(nameof(WaferDataGUID));
  1413. }
  1414. }
  1415. private string _processIn;
  1416. public string ProcessIn
  1417. {
  1418. get => _processIn;
  1419. set
  1420. {
  1421. _processIn = value;
  1422. InvokePropertyChanged(nameof(ProcessIn));
  1423. }
  1424. }
  1425. private int _recipeSettingTime;
  1426. public int RecipeSettingTime
  1427. {
  1428. get => _recipeSettingTime;
  1429. set
  1430. {
  1431. _recipeSettingTime = value;
  1432. InvokePropertyChanged(nameof(RecipeSettingTime));
  1433. }
  1434. }
  1435. }
  1436. }