ProcessDetailViewModel.cs 64 KB

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