ProcessDetailViewModel.cs 65 KB

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