ProcessExportAllViewModel.cs 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  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.CenterViews.Operations.RealTime;
  14. using MECF.Framework.UI.Client.ClientBase;
  15. using OpenSEMI.ClientBase;
  16. using SciChart.Charting.Visuals;
  17. using SciChart.Charting.Visuals.Annotations;
  18. using SciChart.Charting.Visuals.Axes;
  19. using SciChart.Charting.Visuals.RenderableSeries;
  20. using SciChart.Data.Model;
  21. using System;
  22. using System.Collections.Concurrent;
  23. using System.Collections.Generic;
  24. using System.Collections.ObjectModel;
  25. using System.Data;
  26. using System.Diagnostics;
  27. using System.Drawing;
  28. using System.Linq;
  29. using System.Text;
  30. using System.Threading;
  31. using System.Threading.Tasks;
  32. using System.Windows;
  33. using static MECF.Framework.Common.FAServices.DataVariables;
  34. using Action = System.Action;
  35. using Media = System.Windows.Media;
  36. namespace MECF.Framework.UI.Client.CenterViews.DataLogs.ProcessHistory
  37. {
  38. class ProcessExportAllViewModel<T> : ModuleUiViewModelBase where T : IComparable
  39. {
  40. private ProcessExportAllView view;
  41. private CancellationTokenSource _cancellationTokenSource;
  42. private event EventHandler Exporting;
  43. private const int MAX_PARAMETERS = 1000;
  44. public List<ProcessHistoryLot> RecipeDatas { get; set; }
  45. private ObservableCollection<ParameterNode> _ParameterNodes;
  46. public ObservableCollection<ParameterNode> ParameterNodes
  47. {
  48. get { return _ParameterNodes; }
  49. set { _ParameterNodes = value; NotifyOfPropertyChange("ParameterNodes"); }
  50. }
  51. private Dictionary<string, string> _processDetailDisplayDic = new Dictionary<string, string>();
  52. private Dictionary<string, Dictionary<string, string>> _processProcessDetailAttributeDict = new Dictionary<string, Dictionary<string, string>>();
  53. // public ObservableCollection<IRenderableSeries> SelectedData { get; set; }
  54. public ObservableCollection<ParameterNode> GetParameters()
  55. {
  56. ObservableCollection<ParameterNode> rootNode = new ObservableCollection<ParameterNode>();
  57. try
  58. {
  59. Dictionary<string, string> displayDic = QueryDataClient.Instance.Service.GetData("System.ProcessDetailDisplay") as Dictionary<string, string>;
  60. if (displayDic == null)
  61. return rootNode;
  62. List<string> dataList = new List<string>();
  63. foreach (var key in displayDic.Keys)
  64. {
  65. string[] item = key.Split('.');
  66. if (item != null)
  67. {
  68. if (item.Length == 2)
  69. {
  70. _processDetailDisplayDic.Add($"{item[1]}", displayDic[key]);
  71. dataList.Add($"{item[0]}.{item[1]}");
  72. }
  73. else if (item.Length == 3)
  74. {
  75. _processDetailDisplayDic.Add($"{item[1]} {item[2]}", displayDic[key]);
  76. dataList.Add($"{item[0]}.{item[1]}.{item[2]}");
  77. }
  78. }
  79. Dictionary<string, ParameterNode> indexer = new Dictionary<string, ParameterNode>();
  80. foreach (string dataName in dataList)
  81. {
  82. string[] nodeName = dataName.Split('.');
  83. ParameterNode parentNode = null;
  84. string pathName = "";
  85. for (int i = 0; i < nodeName.Length; i++)
  86. {
  87. pathName = (i == 0 || i == 1) ? nodeName[i] : (pathName + " " + nodeName[i]);
  88. if (!indexer.ContainsKey(pathName))
  89. {
  90. indexer[pathName] = new ParameterNode() { Name = pathName, ChildNodes = new ObservableCollection<ParameterNode>(), ParentNode = parentNode };
  91. if (parentNode == null)
  92. {
  93. rootNode.Add(indexer[pathName]);
  94. }
  95. else
  96. {
  97. parentNode.ChildNodes.Add(indexer[pathName]);
  98. }
  99. }
  100. parentNode = indexer[pathName];
  101. }
  102. }
  103. SortParameterNode(rootNode, "Heater", 0);
  104. SortParameterNode(rootNode, "MFC", 1);
  105. SortParameterNode(rootNode, "Pressure", 2);
  106. SortParameterNode(rootNode, "Boat", 3);
  107. SortParameterNode(rootNode, "HeaterBand", 4);
  108. SortParameterNode(rootNode, "Valve", 5);
  109. }
  110. }
  111. catch (Exception ex)
  112. {
  113. LOG.Write(ex);
  114. }
  115. return rootNode;
  116. }
  117. void SortParameterNode(ObservableCollection<ParameterNode> rootNode, string Name, int Index)
  118. {
  119. if (rootNode[Index].Name != Name)
  120. {
  121. for (int i = 0; i < rootNode.Count; i++)
  122. {
  123. rootNode[i].Selected = true;
  124. if (rootNode[i].Name == Name)
  125. {
  126. ParameterNode node = rootNode[i];
  127. rootNode.RemoveAt(i);
  128. rootNode.Insert(Index, node);
  129. }
  130. }
  131. }
  132. }
  133. private IRange _timeRange;
  134. public IRange VisibleRangeTime
  135. {
  136. get { return _timeRange; }
  137. set
  138. {
  139. _timeRange = value;
  140. NotifyOfPropertyChange(nameof(VisibleRangeTime));
  141. }
  142. }
  143. private IRange _VisibleRangeValue;
  144. public IRange VisibleRangeValue
  145. {
  146. get { return _VisibleRangeValue; }
  147. set { _VisibleRangeValue = value; NotifyOfPropertyChange(nameof(VisibleRangeValue)); }
  148. }
  149. private AnnotationCollection _annotations;
  150. public AnnotationCollection Annotations
  151. {
  152. get => _annotations;
  153. set
  154. {
  155. _annotations = value;
  156. InvokePropertyChanged(nameof(Annotations));
  157. }
  158. }
  159. //private PeriodicJob _thread;
  160. private List<StepInfo> _stepInfo = new List<StepInfo>();
  161. public List<StepInfo> StepInfo
  162. {
  163. get { return _stepInfo; }
  164. set { _stepInfo = value; this.NotifyOfPropertyChange(nameof(StepInfo)); }
  165. }
  166. private bool _isBusy = false;
  167. private string _busyIndicatorMessage;
  168. /// <summary>
  169. /// 设置或返回忙信息。
  170. /// </summary>
  171. public string BusyIndicatorContent
  172. {
  173. get => _busyIndicatorMessage;
  174. set
  175. {
  176. _busyIndicatorMessage = value;
  177. NotifyOfPropertyChange(nameof(BusyIndicatorContent));
  178. }
  179. }
  180. /// <summary>
  181. /// 设置或返回视图是否正忙。
  182. /// </summary>
  183. public bool IsBusy
  184. {
  185. get => _isBusy;
  186. set
  187. {
  188. _isBusy = value;
  189. NotifyOfPropertyChange(nameof(IsBusy));
  190. }
  191. }
  192. private RealtimeProvider _realtimeProvider;
  193. public ProcessExportAllViewModel(List<ProcessHistoryLot> recipes)
  194. {
  195. DisplayName = "Process Export";
  196. RecipeDatas = recipes;
  197. _realtimeProvider = new RealtimeProvider();
  198. ParameterNodes = _realtimeProvider.GetParameters(out var dict, true);
  199. _processDetailDisplayDic = dict;
  200. _processProcessDetailAttributeDict = _realtimeProvider.GetProcessProcessDetailAttributeDict();
  201. if (recipes == null || recipes.Count == 0)
  202. {
  203. return;
  204. }
  205. //SelectedData = new ObservableCollection<IRenderableSeries>();
  206. var now = DateTime.Now;
  207. VisibleRangeTime = new DateRange(DateTime.Now.AddMinutes(60), DateTime.Now.AddMinutes(-60));
  208. VisibleRangeValue = new DoubleRange(0, 10);
  209. Annotations = new AnnotationCollection();
  210. // _thread = new PeriodicJob(200, MonitorData, "ProcessExport", true);
  211. RecipeDatas.ToList().ForEach(recipe =>
  212. {
  213. QueryStep(recipe);
  214. });
  215. if (StepInfo != null && StepInfo.Count > 0)
  216. {
  217. StepStartTime = StepInfo.FirstOrDefault().StartTime;
  218. StepEndTime = StepInfo.LastOrDefault().EndTime;
  219. }
  220. else
  221. {
  222. if (recipes.Count > 0)
  223. {
  224. StepStartTime = recipes[0].StartTime;
  225. StepEndTime = recipes[0].EndTime;
  226. }
  227. }
  228. }
  229. public bool IsStepVisiable => RecipeDatas.Count == 1;
  230. public DateTime StepStartTime { get; set; }
  231. public DateTime StepEndTime { get; set; }
  232. private bool _isAdding;
  233. private static object _lockSelection = new object();
  234. private ConcurrentBag<QueryIndexer> _lstTokenTimeData = new ConcurrentBag<QueryIndexer>();
  235. public class QueryIndexer
  236. {
  237. public TimeChartDataLine DataLine { get; set; }
  238. public List<string> DataList { get; set; }
  239. public DateTime TimeToken { get; set; }
  240. }
  241. public class TimeChartDataLine : ChartDataLine<T>
  242. {
  243. public string Module { get; set; }
  244. public DateTime StartTime { get; set; }
  245. public DateTime EndTime { get; set; }
  246. public TimeChartDataLine(string dataName, string module, DateTime startTime, DateTime endTime) : base(dataName)
  247. {
  248. StartTime = startTime;
  249. EndTime = endTime;
  250. Module = module;
  251. }
  252. }
  253. private string _resolution;
  254. private AutoRange _autoRange;
  255. public AutoRange ChartAutoRange
  256. {
  257. get { return _autoRange; }
  258. set
  259. {
  260. _autoRange = value;
  261. NotifyOfPropertyChange(nameof(ChartAutoRange));
  262. }
  263. }
  264. public void QueryStep(ProcessHistoryLot historyLot)//, string recipeName去掉查询recipeName名称,有嵌套调用
  265. {
  266. string sql = string.Empty;
  267. DataTable dbData = new DataTable();
  268. if (!string.IsNullOrEmpty(historyLot.PjId))
  269. {
  270. sql = $"SELECT * FROM process_data where pj_id='{historyLot.PjId}'";
  271. dbData = QueryDataClient.Instance.Service.QueryData(sql);
  272. }
  273. if (dbData == null || dbData.Rows.Count == 0)
  274. {
  275. DateTime starTime = historyLot.StartTime.AddMinutes(-1);
  276. DateTime endTime = historyLot.EndTime.AddMinutes(1);
  277. 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;";
  278. dbData = QueryDataClient.Instance.Service.QueryData(sql);
  279. }
  280. if (dbData != null && dbData.Rows.Count > 0)
  281. {
  282. List<ProcessDataLot> ProcessDataLotList = new List<ProcessDataLot>();
  283. for (int i = 0; i < dbData.Rows.Count; i++)
  284. {
  285. ProcessDataLot item = new ProcessDataLot();
  286. item.GUID = dbData.Rows[i]["guid"].ToString();
  287. item.RecipeName = dbData.Rows[i]["recipe_name"].ToString();
  288. item.ProcessStatus = dbData.Rows[i]["process_status"].ToString();
  289. item.WaferDataGUID = dbData.Rows[i]["wafer_data_guid"].ToString();
  290. item.ProcessIn = dbData.Rows[i]["process_in"].ToString();
  291. if (!dbData.Rows[i]["process_begin_time"].Equals(DBNull.Value))
  292. {
  293. item.ProcessBeginTime = (DateTime)dbData.Rows[i]["process_begin_time"];
  294. }
  295. if (!dbData.Rows[i]["process_end_time"].Equals(DBNull.Value))
  296. {
  297. item.ProcessEndTime = (DateTime)dbData.Rows[i]["process_end_time"];
  298. }
  299. ProcessDataLotList.Add(item);
  300. }
  301. if (ProcessDataLotList.Count == 0) { LOG.Warning($"QueryStep:No process data({sql})"); return; }
  302. // Annotations.Add(VerLine(Media.Brushes.Blue, ProcessDataLotList[0].ProcessBeginTime, Media.Brushes.Blue, $"{ProcessDataLotList[0].RecipeName}"));
  303. //Annotations.Add(VerLine(Media.Brushes.Blue, ProcessDataLotList[0].ProcessEndTime, Media.Brushes.Blue, $"Recipe End"));
  304. string sql2 = $"SELECT * FROM \"recipe_step_data\" where";
  305. sql2 += $" \"recipe_step_data\".\"process_data_guid\" = '{ProcessDataLotList[0].GUID.ToString()}'";
  306. sql2 += " order by \"step_begin_time\" ASC;";
  307. using (var table = QueryDataClient.Instance.Service.QueryData(sql2))
  308. {
  309. if (!(table == null || table.Rows.Count == 0))
  310. {
  311. for (int i = 0; i < table.Rows.Count; i++)
  312. {
  313. var item = table.Rows[i];
  314. string startStepTime = "";
  315. string endStepTime = "";
  316. double stepTime = 0;
  317. string subRecipeStepNumber = "";
  318. string subRecipeStepTime = "";
  319. string subRecipeStepName = "";
  320. string subRecipeLoopInfo = "";
  321. string tempCorrection = "";
  322. string tempPid = "";
  323. if (!item["step_begin_time"].Equals(DBNull.Value))
  324. startStepTime = ((DateTime)item["step_begin_time"]).ToString("yyyy/MM/dd HH:mm:ss.fff");
  325. if (!item["step_end_time"].Equals(DBNull.Value))
  326. {
  327. endStepTime = ((DateTime)item["step_end_time"]).ToString("yyyy/MM/dd HH:mm:ss.fff");
  328. }
  329. if (!item["step_time"].Equals(DBNull.Value))
  330. {
  331. stepTime = (float)item["step_time"];
  332. }
  333. if (!item["sub_recipe_step_time"].Equals(DBNull.Value))
  334. {
  335. subRecipeStepTime = item["sub_recipe_step_time"].ToString();
  336. }
  337. if (!item["sub_recipe_step_number"].Equals(DBNull.Value))
  338. {
  339. subRecipeStepNumber = item["sub_recipe_step_number"].ToString();
  340. }
  341. if (!item["sub_recipe_step_name"].Equals(DBNull.Value))
  342. {
  343. subRecipeStepName = item["sub_recipe_step_name"].ToString();
  344. }
  345. if (!item["sub_recipe_loop_info"].Equals(DBNull.Value))
  346. {
  347. subRecipeLoopInfo = item["sub_recipe_loop_info"].ToString();
  348. }
  349. if (!item["temp_correction"].Equals(DBNull.Value))
  350. {
  351. tempCorrection = item["temp_correction"].ToString().Replace(",", ":");
  352. }
  353. if (!item["temp_pid"].Equals(DBNull.Value))
  354. {
  355. tempPid = item["temp_pid"].ToString().Replace(",", ":");
  356. }
  357. string stepNo = item["step_number"].ToString();
  358. string stepName = item["step_name"].ToString();
  359. if (DateTime.TryParse(startStepTime, out DateTime StartTime) && DateTime.TryParse(endStepTime, out DateTime EndTime))
  360. {
  361. //Annotations.Add(VerLine(Media.Brushes.AliceBlue, StartTime, Media.Brushes.Blue, $"{stepNo}"));
  362. var time = StartTime.AddSeconds(stepTime);
  363. if (EndTime < time && time < ProcessDataLotList[0].ProcessEndTime)//解决process过程abort,数据导出问题:数据点时间范围大于recipe结束时间。
  364. {
  365. EndTime = StartTime.AddSeconds(stepTime);
  366. }
  367. _stepInfo.Add(new StepInfo()
  368. {
  369. StartTime = StartTime,
  370. EndTime = EndTime,
  371. StepName = stepName,
  372. StepTime = stepTime,
  373. StepNo = stepNo,
  374. StepEndTime = StartTime.AddSeconds(stepTime),
  375. SubRecipeStepNumber = subRecipeStepNumber,
  376. SubRecipeStepTime = subRecipeStepTime,
  377. SubRecipeStepName = subRecipeStepName,
  378. SubRecipeLoopInfo = subRecipeLoopInfo,
  379. TempCorrection = tempCorrection,
  380. TempPid = tempPid,
  381. });
  382. }
  383. }
  384. }
  385. }
  386. }
  387. }
  388. protected override void OnViewLoaded(object view)
  389. {
  390. base.OnViewLoaded(view);
  391. useMaxRow = (int)QueryDataClient.Instance.Service.GetConfig("System.SetUp.ExportMaxRow");
  392. this.view = (ProcessExportAllView)view;
  393. }
  394. List<string> nodeOrigin = new List<string>();
  395. void GetNode(ParameterNode pNode, bool Selected)
  396. {
  397. foreach (var item in pNode.ChildNodes)
  398. {
  399. if (item.ChildNodes.Count > 0)
  400. {
  401. GetNode(item, Selected);
  402. }
  403. else
  404. {
  405. //if(item.Selected == true)
  406. {
  407. nodeOrigin.Add(item.Name);
  408. }
  409. }
  410. }
  411. }
  412. public static int DivideAndRoundUp(int dividend, int divisor)
  413. {
  414. int result = dividend / divisor;
  415. int remainder = dividend % divisor;
  416. if (remainder > 0)
  417. {
  418. result++;
  419. }
  420. return result;
  421. }
  422. private int useMaxRow = 25000;
  423. string csv = ",";
  424. public async void ExportAll()
  425. {
  426. try
  427. {
  428. nodeOrigin.Clear();
  429. if (StepStartTime.Year == 1 || StepEndTime.Year == 1)
  430. {
  431. MessageBox.Show("No data is available in the selected period!", "Export", MessageBoxButton.OK, MessageBoxImage.Warning);
  432. return;
  433. }
  434. foreach (var node in ParameterNodes)
  435. {
  436. if (node.Selected == true)
  437. {
  438. GetNode(node, node.Selected);
  439. }
  440. }
  441. if (nodeOrigin.Count == 0)
  442. {
  443. MessageBox.Show($"Please select the data you want to export.", "Export", MessageBoxButton.OK,
  444. MessageBoxImage.Warning);
  445. return;
  446. }
  447. Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
  448. dlg.DefaultExt = ".csv"; // Default file extension
  449. dlg.Filter = "Excel数据表格文件(*.csv)|*.csv"; // Filter files by extension
  450. dlg.FileName = $"{DisplayName}_{string.Join(",", RecipeDatas.Select(x => x.RecipeName.Replace('\\', '.')))}_{DateTime.Now:yyyyMMdd_HHmmss}";
  451. Nullable<bool> result = dlg.ShowDialog();// Show open file dialog box
  452. if (result == true) // Process open file dialog box results
  453. {
  454. BusyIndicatorContent = "Exporting start ...";
  455. IsBusy = true;
  456. Exporting?.Invoke(this, System.EventArgs.Empty);
  457. _cancellationTokenSource = new CancellationTokenSource();
  458. //System.Data.DataSet ds = new System.Data.DataSet();
  459. //var sw = new Stopwatch();
  460. //sw.Restart();
  461. //BusyIndicatorContent = "Create table header start ...";
  462. //ds.Tables.Add(new System.Data.DataTable($"{DisplayName}_{DateTime.Now:yyyyMMdd_HHmmss}"));
  463. //ds.Tables[0].Columns.Add("Recipe Info");
  464. //ds.Tables[0].Columns[0].DataType = typeof(string);
  465. //ds.Tables[0].Columns.Add("Date");
  466. //ds.Tables[0].Columns[1].DataType = typeof(string);
  467. //ds.Tables[0].Columns.Add("Time");
  468. //ds.Tables[0].Columns[2].DataType = typeof(string);
  469. //ds.Tables[0].Columns.Add("Step ID");
  470. //ds.Tables[0].Columns[3].DataType = typeof(string);
  471. //ds.Tables[0].Columns.Add("Step Name");
  472. //ds.Tables[0].Columns[4].DataType = typeof(string);
  473. StringBuilder stringBuilder = new StringBuilder();
  474. stringBuilder.AppendLine($"Recipe Info{csv}Date{csv}Time{csv}Step ID{csv}Step Name");
  475. Dictionary<T, double[]> timeValue = new Dictionary<T, double[]>();
  476. await Task.Run(() =>
  477. {
  478. for (int i = 0; i < nodeOrigin.Count; i++)
  479. {
  480. //List<Tuple<T, double>> data = (nodeOrigin[i] as ChartDataLine<T>).Points;
  481. //foreach (var tuple in data)
  482. //{
  483. // if (!timeValue.ContainsKey(tuple.Item1))
  484. // timeValue[tuple.Item1] = new double[nodeOrigin.Count];
  485. // timeValue[tuple.Item1][i] = tuple.Item2;
  486. //}
  487. // ds.Tables[0].Columns.Add(nodeOrigin[i]);
  488. // ds.Tables[0].Columns[i + 5].DataType = typeof(double);
  489. }
  490. stringBuilder.AppendLine($"Recipe:{string.Join(",", RecipeDatas.Select(x => x.RecipeName).ToArray())}");
  491. stringBuilder.AppendLine($"Start Time{csv}{string.Join(",", RecipeDatas.Select(x => x.StartTime).ToArray())}{csv}{string.Join(",", RecipeDatas.Select(x => x.StartTime).ToArray())}");
  492. stringBuilder.AppendLine($"End Time{csv}{string.Join(",", RecipeDatas.Select(x => x.EndTime).ToArray())}{csv}{string.Join(",", RecipeDatas.Select(x => x.EndTime).ToArray())}");
  493. FileHelper.Instance.SaveText(dlg.FileName, stringBuilder.ToString());
  494. //var recipeInfoRow = ds.Tables[0].NewRow();
  495. //recipeInfoRow[0] = $"Recipe:{string.Join(",", RecipeDatas.Select(x => x.RecipeName).ToArray())}";
  496. //ds.Tables[0].Rows.Add(recipeInfoRow);
  497. //recipeInfoRow = ds.Tables[0].NewRow();
  498. //recipeInfoRow[0] = $"Start Time";
  499. //recipeInfoRow[1] = string.Join(",", RecipeDatas.Select(x => x.StartTime).ToArray());
  500. //recipeInfoRow[2] = string.Join(",", RecipeDatas.Select(x => x.StartTime).ToArray());
  501. //ds.Tables[0].Rows.Add(recipeInfoRow);
  502. //recipeInfoRow = ds.Tables[0].NewRow();
  503. //recipeInfoRow[0] = $"End Time";
  504. //recipeInfoRow[1] = string.Join(",", RecipeDatas.Select(x => x.EndTime).ToArray());
  505. //recipeInfoRow[2] = string.Join(",", RecipeDatas.Select(x => x.EndTime).ToArray());
  506. //ds.Tables[0].Rows.Add(recipeInfoRow);
  507. //var rowCaption = ds.Tables[0].NewRow();
  508. //for (int i = 0; i < ds.Tables[0].Columns.Count; i++)
  509. //{
  510. // rowCaption[i] = ds.Tables[0].Columns[i].Caption;
  511. //}
  512. //ds.Tables[0].Rows.Add(rowCaption);
  513. //for (int i = 0; i < ds.Tables[0].Columns.Count; i++)
  514. //{
  515. // ds.Tables[0].Columns[i].Caption = null;
  516. //}
  517. DateTime startTime = startTime = StepStartTime;
  518. QueryDataClientFromTable(dlg.FileName);
  519. }, _cancellationTokenSource.Token).ContinueWith(t =>
  520. {
  521. if (t.IsCanceled || t.IsFaulted)
  522. {
  523. IsBusy = false;
  524. return;
  525. }
  526. });
  527. if (_cancellationTokenSource?.Token.IsCancellationRequested == true)
  528. {
  529. IsBusy = false;
  530. return;
  531. }
  532. BusyIndicatorContent = "Data is written to Excel file ...";
  533. IsBusy = false;
  534. MessageBox.Show($"Export succeed, file save as {dlg.FileName}", "Export", MessageBoxButton.OK, MessageBoxImage.Information);
  535. Window window = Window.GetWindow(this.view);
  536. window.Close();
  537. }
  538. }
  539. catch (Exception ex)
  540. {
  541. LOG.Write(ex);
  542. MessageBox.Show("Write failed," + ex.Message, "export failed", MessageBoxButton.OK, MessageBoxImage.Warning);
  543. IsBusy = false;
  544. }
  545. }
  546. private void QueryDataClientFromTable(string fileName)
  547. {
  548. DateTime startTime = StepStartTime;
  549. DateTime endTime = StepEndTime;
  550. List<string> keys = new List<string>(nodeOrigin);
  551. List<string> pmList = new List<string>();
  552. List<string> systemList = new List<string>();
  553. if (keys != null && keys.Count > 0)
  554. {
  555. foreach (var dataKey in keys)
  556. {
  557. var dataId = _processDetailDisplayDic.ContainsKey(dataKey) ? _processDetailDisplayDic[dataKey] : dataKey;
  558. var module = dataId.Split('.').ToList()[0];
  559. if (module.ToLower() == "pm1")
  560. {
  561. pmList.Add(dataId);
  562. }
  563. else if (module.ToLower() == "system")
  564. {
  565. systemList.Add(dataId);
  566. // systemList.Add(string.Format("\"{0}\"", dataId));
  567. }
  568. }
  569. }
  570. if (StepStartTime.Date == StepEndTime.Date)
  571. {
  572. SaveDataToTable(fileName, pmList, systemList, startTime, endTime);
  573. }
  574. else
  575. {
  576. endTime = new DateTime(startTime.Year, startTime.Month, startTime.Day, 23, 59, 59);
  577. while (endTime < StepEndTime)
  578. {
  579. SaveDataToTable(fileName, pmList, systemList, startTime, endTime);
  580. startTime = new DateTime(startTime.Year, startTime.Month, startTime.Day, 0, 0, 0).AddDays(1);
  581. endTime = new DateTime(startTime.Year, startTime.Month, startTime.Day, 23, 59, 59);
  582. }
  583. SaveDataToTable(fileName, pmList, systemList, startTime, StepEndTime);
  584. }
  585. }
  586. private bool firstHeader = false;
  587. private Dictionary<string, string> GetReverseDict()
  588. {
  589. Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();
  590. foreach (var kvp in _processDetailDisplayDic)
  591. {
  592. if (!keyValuePairs.ContainsKey(kvp.Value))
  593. keyValuePairs[kvp.Value] = kvp.Key.Trim().Contains(" ") ? kvp.Key.Trim().Substring(kvp.Key.Trim().LastIndexOf(" ") + 1) : kvp.Key;
  594. }
  595. return keyValuePairs;
  596. }
  597. private void SaveDataToTable(string fileName, List<string> pmList, List<string> systemList, DateTime startTime, DateTime endTime)
  598. {
  599. string stepID = "", stepName = "", subRecipeLoopInfo = "", subRecipeStepName = "", subRecipeStepNumber = "", tempCorrection = "", tempPid = "";
  600. DataTable pmDataTable = null;
  601. Dictionary<string, string> reverseDict = GetReverseDict();
  602. var columnsql = $"select column_name from information_schema.columns where table_name = '{startTime.ToString("yyyyMMdd")}.PM1'";
  603. var columnTable = QueryDataClient.Instance.Service.QueryData(columnsql);
  604. List<string> col = columnTable.Rows.Cast<DataRow>().Select(x => x.ItemArray[0].ToString()).ToList();
  605. pmList = pmList.Where(x => col.Any(y => y == x)).ToList();
  606. string pmsql = $"select time AS InternalTimeStamp, {string.Join(",", pmList.Select(x => string.Format("\"{0}\"", x)))}";
  607. DataTable systemDataTable = null;
  608. pmsql += string.Format(" from \"{0}\" where time > {1} and time <= {2} order by time asc",
  609. startTime.ToString("yyyyMMdd") + "." + "PM1", startTime.Ticks, endTime.Ticks);
  610. BusyIndicatorContent = "Example Query PM data ...";
  611. pmDataTable = QueryDataClient.Instance.Service.QueryData(pmsql);
  612. if (pmDataTable != null)
  613. {
  614. foreach (DataRow item in pmDataTable.Rows)
  615. {
  616. if (item.Table.Columns.Contains("PM1.APC.ModeFeedback"))
  617. {
  618. if (item.Table.Columns.Contains("PM1.APC.PressureSetPoint"))
  619. {
  620. if (item.Field<float>("PM1.APC.ModeFeedback") != 7 && item.Field<float>("PM1.APC.ModeFeedback") != 8)
  621. {
  622. item["PM1.APC.PressureSetPoint"] = 0;
  623. }
  624. }
  625. if (item.Table.Columns.Contains("PM1.APC.PositionSetPoint"))
  626. {
  627. if (item.Field<float>("PM1.APC.ModeFeedback") != 2)
  628. {
  629. item["PM1.APC.PositionSetPoint"] = 0;
  630. }
  631. }
  632. if (item.Table.Columns.Contains("PM1.APC.SlowRateSetPoint"))
  633. {
  634. if (item.Field<float>("PM1.APC.ModeFeedback") != 12)
  635. {
  636. item["PM1.APC.SlowRateSetPoint"] = 0;
  637. }
  638. }
  639. }
  640. }
  641. }
  642. var sysColumnsql = $"select column_name from information_schema.columns where table_name = '{startTime.ToString("yyyyMMdd")}.System'";
  643. var sysColumnTable = QueryDataClient.Instance.Service.QueryData(sysColumnsql);
  644. List<string> systemCol = sysColumnTable.Rows.Cast<DataRow>().Select(x => x.ItemArray[0].ToString()).ToList();
  645. systemList = systemList.Where(x => systemCol.Any(y => y == x)).ToList();
  646. string systemsql = $"select time AS InternalTimeStamp, {string.Join(",", systemList.Select(x => string.Format("\"{0}\"", x)))}";
  647. systemsql += string.Format(" from \"{0}\" where time > {1} and time <= {2} order by time asc",
  648. startTime.ToString("yyyyMMdd") + "." + "System", startTime.Ticks, endTime.Ticks);
  649. BusyIndicatorContent = "Example Query System data ...";
  650. systemDataTable = QueryDataClient.Instance.Service.QueryData(systemsql);
  651. int maxRow = 0;
  652. if ((pmDataTable == null || pmDataTable.Rows.Count == 0))
  653. {
  654. if (systemDataTable != null)
  655. {
  656. maxRow = systemDataTable.Rows.Count;
  657. }
  658. }
  659. else if ((systemDataTable == null || systemDataTable.Rows.Count == 0))
  660. {
  661. if (pmDataTable != null)
  662. {
  663. maxRow = pmDataTable.Rows.Count;
  664. }
  665. }
  666. else
  667. {
  668. maxRow = pmDataTable.Rows.Count > systemDataTable.Rows.Count ? systemDataTable.Rows.Count : pmDataTable.Rows.Count;
  669. }
  670. var subColNames = new List<DataColumn>() {
  671. new DataColumn("SubRecipeStepName"),
  672. new DataColumn("SubRecipeStepNumber"),
  673. new DataColumn("SubRecipeLoopInfo"),
  674. new DataColumn("TempCorrection"),
  675. new DataColumn("TempPid"),
  676. };
  677. BusyIndicatorContent = "Data is saved to excel Table ...";
  678. StringBuilder stringBuilder = new StringBuilder();
  679. if (!firstHeader)
  680. {
  681. firstHeader = true;
  682. var systemColNames = systemDataTable?.Columns.Cast<DataColumn>().Where(x => x.ColumnName != "internaltimestamp").Select(x =>
  683. {
  684. if (_processProcessDetailAttributeDict.ContainsKey(x.ColumnName))
  685. {
  686. var colAttributeName = "ColName";
  687. if (!_processProcessDetailAttributeDict[x.ColumnName].ContainsKey(colAttributeName))
  688. {
  689. colAttributeName = "DisplayName";
  690. }
  691. return string.IsNullOrEmpty(_processProcessDetailAttributeDict[x.ColumnName][colAttributeName]) ? x.ColumnName : _processProcessDetailAttributeDict[x.ColumnName][colAttributeName];
  692. }
  693. return x.ColumnName;
  694. });
  695. var pmColNames = pmDataTable?.Columns.Cast<DataColumn>().Where(x => x.ColumnName != "internaltimestamp").Select(x =>
  696. {
  697. if (_processProcessDetailAttributeDict.ContainsKey(x.ColumnName))
  698. {
  699. var colAttributeName = "ColName";
  700. if (!_processProcessDetailAttributeDict[x.ColumnName].ContainsKey(colAttributeName))
  701. {
  702. colAttributeName = "DisplayName";
  703. }
  704. return string.IsNullOrEmpty(_processProcessDetailAttributeDict[x.ColumnName][colAttributeName]) ? x.ColumnName : _processProcessDetailAttributeDict[x.ColumnName][colAttributeName];
  705. }
  706. return x.ColumnName;
  707. });
  708. stringBuilder.AppendLine($"{csv}{csv}{csv}{csv}{csv}{string.Join($"{csv}", subColNames.Cast<DataColumn>())} {csv}{string.Join($"{csv}", systemColNames ?? new string[0])} {csv}{string.Join($"{csv}", pmColNames ?? new string[0])}");
  709. }
  710. for (int i = 0; i < maxRow; i++)
  711. {
  712. BusyIndicatorContent = $"Total data {maxRow} current {i + 1} ...";
  713. var pmRow = pmDataTable != null && pmDataTable.Rows.Count > 0 ? pmDataTable.Rows[i] : null;
  714. var systemRow = systemDataTable != null && systemDataTable.Rows.Count > 0 ? systemDataTable.Rows[i] : null;
  715. //float timeIndex = 0;
  716. //float.TryParse(item.Key.ToString(), out timeIndex);
  717. //DateTime dateTimeKey = startTime.AddMilliseconds(timeIndex * 1000); ;// DateTime.Parse(item.Key.ToString());
  718. DateTime dateTimeKey = new DateTime(systemRow != null ? (long)systemRow[0] : (long)pmRow[0]);
  719. var tempStepInfo = _stepInfo.OrderByDescending(x => x.StartTime).Where(x => x.StartTime <= dateTimeKey).FirstOrDefault();
  720. if (tempStepInfo != null)// && dateTimeKey > _stepInfo[iIndex].StartTime && x.StepEndTime >= dateTimeKey
  721. {
  722. stepID = tempStepInfo.StepNo;
  723. stepName = tempStepInfo.StepName;
  724. subRecipeStepName = tempStepInfo.SubRecipeStepName;
  725. subRecipeStepNumber = tempStepInfo.SubRecipeStepNumber;
  726. subRecipeLoopInfo = !string.IsNullOrEmpty(tempStepInfo.SubRecipeLoopInfo) ? tempStepInfo.SubRecipeLoopInfo.Replace("/", "|") : tempStepInfo.SubRecipeLoopInfo;
  727. tempCorrection = !string.IsNullOrEmpty(tempStepInfo.TempCorrection) ? tempStepInfo.TempCorrection : "";
  728. tempPid = !string.IsNullOrEmpty(tempStepInfo.TempPid) ? tempStepInfo.TempPid : "";
  729. }
  730. if (pmRow == null && systemRow != null)
  731. {
  732. stringBuilder.AppendLine($"{csv}{dateTimeKey.ToString("yyyy/MM/dd")}{csv}{dateTimeKey.ToString("HH:mm:ss:fff")}{csv}{stepID}{csv}{stepName}{csv}{subRecipeStepName}{csv}{subRecipeStepNumber}{csv}{subRecipeLoopInfo}{csv}{tempCorrection}{csv}{tempPid}{csv}{string.Join($"{csv}", systemRow.ItemArray.ToList().GetRange(1, systemRow.ItemArray.Count() - 1).Select(x => x.ToString()))}{csv}{string.Join($"{csv}", Enumerable.Repeat("", pmDataTable?.Columns.Count ?? 0).ToArray())}");
  733. }
  734. else if (pmRow != null && systemRow == null)
  735. {
  736. stringBuilder.AppendLine($"{csv}{dateTimeKey.ToString("yyyy/MM/dd")}{csv}{dateTimeKey.ToString("HH:mm:ss:fff")}{csv}{stepID}{csv}{stepName}{csv}{subRecipeStepName}{csv}{subRecipeStepNumber}{csv}{subRecipeLoopInfo}{csv}{tempCorrection}{csv}{tempPid}{csv}{string.Join($"{csv}", Enumerable.Repeat("", systemDataTable?.Columns?.Count ?? 0).ToArray())}{csv}{string.Join($"{csv}", pmRow.ItemArray.ToList().GetRange(1, pmRow.ItemArray.Count() - 1).Select(x => x.ToString()))}");
  737. }
  738. else if (systemDataTable != null)
  739. {
  740. stringBuilder.AppendLine($"{csv}{dateTimeKey.ToString("yyyy/MM/dd")}{csv}{dateTimeKey.ToString("HH:mm:ss:fff")}{csv}{stepID}{csv}{stepName}{csv}{subRecipeStepName}{csv}{subRecipeStepNumber}{csv}{subRecipeLoopInfo}{csv}{tempCorrection}{csv}{tempPid}{csv}{string.Join($"{csv}", systemDataTable.Rows[i].ItemArray.ToList().GetRange(1, systemDataTable.Rows[i].ItemArray.Count() - 1).Select(x => x.ToString()))}{csv}{string.Join($"{csv}", pmDataTable.Rows[i].ItemArray.ToList().GetRange(1, pmDataTable.Rows[i].ItemArray.Count() - 1).Select(x => x.ToString()))}");
  741. }
  742. if (i == maxRow - 1)
  743. {
  744. var str = stringBuilder.ToString();
  745. str = str.TrimEnd((new char[] { '\r', '\n' }));
  746. FileHelper.Instance.SaveNewLineDataToTxt(fileName, str, true);
  747. stringBuilder.Clear();
  748. }
  749. }
  750. }
  751. static string CheckAndReplace(string input)
  752. {
  753. if (input.StartsWith("PM1"))
  754. {
  755. return input.Substring(4);
  756. }
  757. if (input.StartsWith("System"))
  758. {
  759. return input.Substring(7);
  760. }
  761. return input;
  762. }
  763. /// <summary>
  764. /// 取消查询。
  765. /// </summary>
  766. public void CancelQuery()
  767. {
  768. Task.Run(() =>
  769. {
  770. if (_cancellationTokenSource?.Token.CanBeCanceled == true)
  771. {
  772. _cancellationTokenSource.Cancel();
  773. }
  774. Thread.Sleep(100);
  775. //_progQueryUpdate.Report(new ProgressUpdatingEventArgs(100, 100, ""));
  776. //_progChartSuspendUpdating.Report(false);
  777. });
  778. }
  779. }
  780. }