ProcessExportAllViewModel.cs 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005
  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 DocumentFormat.OpenXml.Spreadsheet;
  7. using MECF.Framework.Common.CommonData;
  8. using MECF.Framework.Common.CommonData.EnumData;
  9. using MECF.Framework.Common.ControlDataContext;
  10. using MECF.Framework.Common.DataCenter;
  11. using MECF.Framework.Common.Utilities;
  12. using MECF.Framework.UI.Client.CenterViews.Configs.SystemConfig;
  13. using MECF.Framework.UI.Client.CenterViews.DataLogs.ProcessHistory;
  14. using MECF.Framework.UI.Client.CenterViews.Dialogs;
  15. using MECF.Framework.UI.Client.CenterViews.Operations.RealTime;
  16. using MECF.Framework.UI.Client.ClientBase;
  17. using NPOI.HSSF.UserModel;
  18. using NPOI.HSSF.Util;
  19. using NPOI.SS.UserModel;
  20. using NPOI.XSSF.UserModel;
  21. using OpenSEMI.ClientBase;
  22. using SciChart.Charting.Visuals;
  23. using SciChart.Charting.Visuals.Annotations;
  24. using SciChart.Charting.Visuals.Axes;
  25. using SciChart.Charting.Visuals.RenderableSeries;
  26. using SciChart.Data.Model;
  27. using System;
  28. using System.Collections.Concurrent;
  29. using System.Collections.Generic;
  30. using System.Collections.ObjectModel;
  31. using System.Data;
  32. using System.Diagnostics;
  33. using System.Drawing;
  34. using System.IO;
  35. using System.Linq;
  36. using System.Text;
  37. using System.Threading;
  38. using System.Threading.Tasks;
  39. using System.Windows;
  40. using static MECF.Framework.Common.FAServices.DataVariables;
  41. using Action = System.Action;
  42. using Media = System.Windows.Media;
  43. namespace MECF.Framework.UI.Client.CenterViews.DataLogs.ProcessHistory
  44. {
  45. class ProcessExportAllViewModel<T> : ModuleUiViewModelBase where T : IComparable
  46. {
  47. private ProcessExportAllView view;
  48. private CancellationTokenSource _cancellationTokenSource;
  49. private event EventHandler Exporting;
  50. private const int MAX_PARAMETERS = 1000;
  51. public List<ProcessHistoryLot> RecipeDatas { get; set; }
  52. private ObservableCollection<ParameterNode> _ParameterNodes;
  53. public ObservableCollection<ParameterNode> ParameterNodes
  54. {
  55. get { return _ParameterNodes; }
  56. set { _ParameterNodes = value; NotifyOfPropertyChange("ParameterNodes"); }
  57. }
  58. private Dictionary<string, string> _processDetailDisplayDic = new Dictionary<string, string>();
  59. private Dictionary<string, Dictionary<string, string>> _processProcessDetailAttributeDict = new Dictionary<string, Dictionary<string, string>>();
  60. // public ObservableCollection<IRenderableSeries> SelectedData { get; set; }
  61. public ObservableCollection<ParameterNode> GetParameters()
  62. {
  63. ObservableCollection<ParameterNode> rootNode = new ObservableCollection<ParameterNode>();
  64. try
  65. {
  66. Dictionary<string, string> displayDic = QueryDataClient.Instance.Service.GetData("System.ProcessDetailDisplay") as Dictionary<string, string>;
  67. if (displayDic == null)
  68. return rootNode;
  69. List<string> dataList = new List<string>();
  70. foreach (var key in displayDic.Keys)
  71. {
  72. string[] item = key.Split('.');
  73. if (item != null)
  74. {
  75. if (item.Length == 2)
  76. {
  77. _processDetailDisplayDic.Add($"{item[1]}", displayDic[key]);
  78. dataList.Add($"{item[0]}.{item[1]}");
  79. }
  80. else if (item.Length == 3)
  81. {
  82. _processDetailDisplayDic.Add($"{item[1]} {item[2]}", displayDic[key]);
  83. dataList.Add($"{item[0]}.{item[1]}.{item[2]}");
  84. }
  85. }
  86. Dictionary<string, ParameterNode> indexer = new Dictionary<string, ParameterNode>();
  87. foreach (string dataName in dataList)
  88. {
  89. string[] nodeName = dataName.Split('.');
  90. ParameterNode parentNode = null;
  91. string pathName = "";
  92. for (int i = 0; i < nodeName.Length; i++)
  93. {
  94. pathName = (i == 0 || i == 1) ? nodeName[i] : (pathName + " " + nodeName[i]);
  95. if (!indexer.ContainsKey(pathName))
  96. {
  97. indexer[pathName] = new ParameterNode() { Name = pathName, ChildNodes = new ObservableCollection<ParameterNode>(), ParentNode = parentNode };
  98. if (parentNode == null)
  99. {
  100. rootNode.Add(indexer[pathName]);
  101. }
  102. else
  103. {
  104. parentNode.ChildNodes.Add(indexer[pathName]);
  105. }
  106. }
  107. parentNode = indexer[pathName];
  108. }
  109. }
  110. SortParameterNode(rootNode, "Heater", 0);
  111. SortParameterNode(rootNode, "MFC", 1);
  112. SortParameterNode(rootNode, "Pressure", 2);
  113. SortParameterNode(rootNode, "Boat", 3);
  114. SortParameterNode(rootNode, "HeaterBand", 4);
  115. SortParameterNode(rootNode, "Valve", 5);
  116. }
  117. }
  118. catch (Exception ex)
  119. {
  120. LOG.Write(ex);
  121. }
  122. return rootNode;
  123. }
  124. void SortParameterNode(ObservableCollection<ParameterNode> rootNode, string Name, int Index)
  125. {
  126. if (rootNode[Index].Name != Name)
  127. {
  128. for (int i = 0; i < rootNode.Count; i++)
  129. {
  130. rootNode[i].Selected = true;
  131. if (rootNode[i].Name == Name)
  132. {
  133. ParameterNode node = rootNode[i];
  134. rootNode.RemoveAt(i);
  135. rootNode.Insert(Index, node);
  136. }
  137. }
  138. }
  139. }
  140. private IRange _timeRange;
  141. public IRange VisibleRangeTime
  142. {
  143. get { return _timeRange; }
  144. set
  145. {
  146. _timeRange = value;
  147. NotifyOfPropertyChange(nameof(VisibleRangeTime));
  148. }
  149. }
  150. private IRange _VisibleRangeValue;
  151. public IRange VisibleRangeValue
  152. {
  153. get { return _VisibleRangeValue; }
  154. set { _VisibleRangeValue = value; NotifyOfPropertyChange(nameof(VisibleRangeValue)); }
  155. }
  156. private AnnotationCollection _annotations;
  157. public AnnotationCollection Annotations
  158. {
  159. get => _annotations;
  160. set
  161. {
  162. _annotations = value;
  163. InvokePropertyChanged(nameof(Annotations));
  164. }
  165. }
  166. //private PeriodicJob _thread;
  167. private List<StepInfo> _stepInfo = new List<StepInfo>();
  168. public List<StepInfo> StepInfo
  169. {
  170. get { return _stepInfo; }
  171. set { _stepInfo = value; this.NotifyOfPropertyChange(nameof(StepInfo)); }
  172. }
  173. private bool _isBusy = false;
  174. private string _busyIndicatorMessage;
  175. /// <summary>
  176. /// 设置或返回忙信息。
  177. /// </summary>
  178. public string BusyIndicatorContent
  179. {
  180. get => _busyIndicatorMessage;
  181. set
  182. {
  183. _busyIndicatorMessage = value;
  184. NotifyOfPropertyChange(nameof(BusyIndicatorContent));
  185. }
  186. }
  187. /// <summary>
  188. /// 设置或返回视图是否正忙。
  189. /// </summary>
  190. public bool IsBusy
  191. {
  192. get => _isBusy;
  193. set
  194. {
  195. _isBusy = value;
  196. NotifyOfPropertyChange(nameof(IsBusy));
  197. }
  198. }
  199. private RealtimeProvider _realtimeProvider;
  200. public ProcessExportAllViewModel(List<ProcessHistoryLot> recipes)
  201. {
  202. DisplayName = "Process Export";
  203. RecipeDatas = recipes;
  204. _realtimeProvider = new RealtimeProvider();
  205. ParameterNodes = _realtimeProvider.GetParameters(out var dict, true);
  206. _processDetailDisplayDic = dict;
  207. _processProcessDetailAttributeDict = _realtimeProvider.GetProcessProcessDetailAttributeDict();
  208. if (recipes == null || recipes.Count == 0)
  209. {
  210. return;
  211. }
  212. //SelectedData = new ObservableCollection<IRenderableSeries>();
  213. var now = DateTime.Now;
  214. VisibleRangeTime = new DateRange(DateTime.Now.AddMinutes(60), DateTime.Now.AddMinutes(-60));
  215. VisibleRangeValue = new DoubleRange(0, 10);
  216. Annotations = new AnnotationCollection();
  217. // _thread = new PeriodicJob(200, MonitorData, "ProcessExport", true);
  218. RecipeDatas.ToList().ForEach(recipe =>
  219. {
  220. QueryStep(recipe);
  221. });
  222. if (StepInfo != null && StepInfo.Count > 0)
  223. {
  224. StepStartTime = StepInfo.FirstOrDefault().StartTime;
  225. StepEndTime = StepInfo.LastOrDefault().EndTime;
  226. }
  227. else
  228. {
  229. if (recipes.Count > 0)
  230. {
  231. StepStartTime = recipes[0].StartTime;
  232. StepEndTime = recipes[0].EndTime;
  233. }
  234. }
  235. }
  236. public bool IsStepVisiable => RecipeDatas.Count == 1;
  237. public DateTime StepStartTime { get; set; }
  238. public DateTime StepEndTime { get; set; }
  239. private bool _isAdding;
  240. private static object _lockSelection = new object();
  241. private ConcurrentBag<QueryIndexer> _lstTokenTimeData = new ConcurrentBag<QueryIndexer>();
  242. public class QueryIndexer
  243. {
  244. public TimeChartDataLine DataLine { get; set; }
  245. public List<string> DataList { get; set; }
  246. public DateTime TimeToken { get; set; }
  247. }
  248. public class TimeChartDataLine : ChartDataLine<T>
  249. {
  250. public string Module { get; set; }
  251. public DateTime StartTime { get; set; }
  252. public DateTime EndTime { get; set; }
  253. public TimeChartDataLine(string dataName, string module, DateTime startTime, DateTime endTime) : base(dataName)
  254. {
  255. StartTime = startTime;
  256. EndTime = endTime;
  257. Module = module;
  258. }
  259. }
  260. private string _resolution;
  261. private AutoRange _autoRange;
  262. public AutoRange ChartAutoRange
  263. {
  264. get { return _autoRange; }
  265. set
  266. {
  267. _autoRange = value;
  268. NotifyOfPropertyChange(nameof(ChartAutoRange));
  269. }
  270. }
  271. public void QueryStep(ProcessHistoryLot historyLot)//, string recipeName去掉查询recipeName名称,有嵌套调用
  272. {
  273. string sql = string.Empty;
  274. DataTable dbData = new DataTable();
  275. if (!string.IsNullOrEmpty(historyLot.PjId))
  276. {
  277. sql = $"SELECT * FROM process_data where pj_id='{historyLot.PjId}'";
  278. dbData = QueryDataClient.Instance.Service.QueryData(sql);
  279. }
  280. if (dbData == null || dbData.Rows.Count == 0)
  281. {
  282. DateTime starTime = historyLot.StartTime.AddMinutes(-1);
  283. DateTime endTime = historyLot.EndTime.AddMinutes(1);
  284. 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;";
  285. dbData = QueryDataClient.Instance.Service.QueryData(sql);
  286. }
  287. if (dbData != null && dbData.Rows.Count > 0)
  288. {
  289. List<ProcessDataLot> ProcessDataLotList = new List<ProcessDataLot>();
  290. for (int i = 0; i < dbData.Rows.Count; i++)
  291. {
  292. ProcessDataLot item = new ProcessDataLot();
  293. item.GUID = dbData.Rows[i]["guid"].ToString();
  294. item.RecipeName = dbData.Rows[i]["recipe_name"].ToString();
  295. item.ProcessStatus = dbData.Rows[i]["process_status"].ToString();
  296. item.WaferDataGUID = dbData.Rows[i]["wafer_data_guid"].ToString();
  297. item.ProcessIn = dbData.Rows[i]["process_in"].ToString();
  298. item.RecipeType = dbData.Rows[i]["recipe_type"].ToString();
  299. item.RecipeExeEntry = dbData.Rows[i]["recipe_exec_entry"].ToString();
  300. if (!dbData.Rows[i]["process_begin_time"].Equals(DBNull.Value))
  301. {
  302. item.ProcessBeginTime = (DateTime)dbData.Rows[i]["process_begin_time"];
  303. }
  304. if (!dbData.Rows[i]["process_end_time"].Equals(DBNull.Value))
  305. {
  306. item.ProcessEndTime = (DateTime)dbData.Rows[i]["process_end_time"];
  307. }
  308. ProcessDataLotList.Add(item);
  309. }
  310. if (ProcessDataLotList.Count == 0) { LOG.Warning($"QueryStep:No process data({sql})"); return; }
  311. historyLot.ProcessStartTime = ProcessDataLotList[0].ProcessBeginTime;
  312. historyLot.ProcessEndTime = ProcessDataLotList[0].ProcessEndTime;
  313. if (int.TryParse(ProcessDataLotList[0].RecipeType, out int type))
  314. historyLot.RecipeType = (RecipeTypeEnum)type;
  315. if (int.TryParse(ProcessDataLotList[0].RecipeExeEntry, out int entry))
  316. historyLot.RecipeExecEntry = (RecipeExecEntryEnum)entry;
  317. // Annotations.Add(VerLine(Media.Brushes.Blue, ProcessDataLotList[0].ProcessBeginTime, Media.Brushes.Blue, $"{ProcessDataLotList[0].RecipeName}"));
  318. //Annotations.Add(VerLine(Media.Brushes.Blue, ProcessDataLotList[0].ProcessEndTime, Media.Brushes.Blue, $"Recipe End"));
  319. string sql2 = $"SELECT * FROM \"recipe_step_data\" where";
  320. sql2 += $" \"recipe_step_data\".\"process_data_guid\" = '{ProcessDataLotList[0].GUID.ToString()}'";
  321. sql2 += " order by \"step_begin_time\" ASC;";
  322. using (var table = QueryDataClient.Instance.Service.QueryData(sql2))
  323. {
  324. if (!(table == null || table.Rows.Count == 0))
  325. {
  326. for (int i = 0; i < table.Rows.Count; i++)
  327. {
  328. var item = table.Rows[i];
  329. string startStepTime = "";
  330. string endStepTime = "";
  331. double stepTime = 0;
  332. string subRecipeStepNumber = "";
  333. string subRecipeStepTime = "";
  334. string subRecipeStepName = "";
  335. string subRecipeLoopInfo = "";
  336. string tempCorrection = "";
  337. string tempPid = "";
  338. if (!item["step_begin_time"].Equals(DBNull.Value))
  339. startStepTime = ((DateTime)item["step_begin_time"]).ToString("yyyy/MM/dd HH:mm:ss.fff");
  340. if (!item["step_end_time"].Equals(DBNull.Value))
  341. {
  342. endStepTime = ((DateTime)item["step_end_time"]).ToString("yyyy/MM/dd HH:mm:ss.fff");
  343. }
  344. if (!item["step_time"].Equals(DBNull.Value))
  345. {
  346. stepTime = (float)item["step_time"];
  347. }
  348. if (!item["sub_recipe_step_time"].Equals(DBNull.Value))
  349. {
  350. subRecipeStepTime = item["sub_recipe_step_time"].ToString();
  351. }
  352. if (!item["sub_recipe_step_number"].Equals(DBNull.Value))
  353. {
  354. subRecipeStepNumber = item["sub_recipe_step_number"].ToString();
  355. }
  356. if (!item["sub_recipe_step_name"].Equals(DBNull.Value))
  357. {
  358. subRecipeStepName = item["sub_recipe_step_name"].ToString();
  359. }
  360. if (!item["sub_recipe_loop_info"].Equals(DBNull.Value))
  361. {
  362. subRecipeLoopInfo = item["sub_recipe_loop_info"].ToString();
  363. }
  364. if (!item["temp_correction"].Equals(DBNull.Value))
  365. {
  366. tempCorrection = item["temp_correction"].ToString().Replace(",", ":");
  367. }
  368. if (!item["temp_pid"].Equals(DBNull.Value))
  369. {
  370. tempPid = item["temp_pid"].ToString().Replace(",", ":");
  371. }
  372. string stepNo = item["step_number"].ToString();
  373. string stepName = item["step_name"].ToString();
  374. if (DateTime.TryParse(startStepTime, out DateTime StartTime) && DateTime.TryParse(endStepTime, out DateTime EndTime))
  375. {
  376. //Annotations.Add(VerLine(Media.Brushes.AliceBlue, StartTime, Media.Brushes.Blue, $"{stepNo}"));
  377. var time = StartTime.AddSeconds(stepTime);
  378. if (EndTime < time && time < ProcessDataLotList[0].ProcessEndTime)//解决process过程abort,数据导出问题:数据点时间范围大于recipe结束时间。
  379. {
  380. EndTime = StartTime.AddSeconds(stepTime);
  381. }
  382. _stepInfo.Add(new StepInfo()
  383. {
  384. StartTime = StartTime,
  385. EndTime = EndTime,
  386. StepName = stepName,
  387. StepTime = stepTime,
  388. StepNo = stepNo,
  389. StepEndTime = StartTime.AddSeconds(stepTime),
  390. SubRecipeStepNumber = subRecipeStepNumber,
  391. SubRecipeStepTime = subRecipeStepTime,
  392. SubRecipeStepName = subRecipeStepName,
  393. SubRecipeLoopInfo = subRecipeLoopInfo,
  394. TempCorrection = tempCorrection,
  395. TempPid = tempPid,
  396. });
  397. }
  398. }
  399. }
  400. }
  401. }
  402. }
  403. protected override void OnViewLoaded(object view)
  404. {
  405. base.OnViewLoaded(view);
  406. useMaxRow = (int)QueryDataClient.Instance.Service.GetConfig("System.SetUp.ExportMaxRow");
  407. this.view = (ProcessExportAllView)view;
  408. }
  409. List<string> nodeOrigin = new List<string>();
  410. void GetNode(ParameterNode pNode, bool Selected)
  411. {
  412. foreach (var item in pNode.ChildNodes)
  413. {
  414. if (item.ChildNodes.Count > 0)
  415. {
  416. GetNode(item, Selected);
  417. }
  418. else
  419. {
  420. //if(item.Selected == true)
  421. {
  422. nodeOrigin.Add(item.Name);
  423. }
  424. }
  425. }
  426. }
  427. public static int DivideAndRoundUp(int dividend, int divisor)
  428. {
  429. int result = dividend / divisor;
  430. int remainder = dividend % divisor;
  431. if (remainder > 0)
  432. {
  433. result++;
  434. }
  435. return result;
  436. }
  437. private int useMaxRow = 25000;
  438. string csv = ",";
  439. public async void ExportAll()
  440. {
  441. try
  442. {
  443. nodeOrigin.Clear();
  444. if (StepStartTime.Year == 1 || StepEndTime.Year == 1)
  445. {
  446. MessageBox.Show("No data is available in the selected period!", "Export", MessageBoxButton.OK, MessageBoxImage.Warning);
  447. return;
  448. }
  449. foreach (var node in ParameterNodes)
  450. {
  451. if (node.Selected == true)
  452. {
  453. GetNode(node, node.Selected);
  454. }
  455. }
  456. if (nodeOrigin.Count == 0)
  457. {
  458. MessageBox.Show($"Please select the data you want to export.", "Export", MessageBoxButton.OK,
  459. MessageBoxImage.Warning);
  460. return;
  461. }
  462. Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
  463. dlg.DefaultExt = ".csv"; // Default file extension
  464. dlg.Filter = "Excel数据表格文件(*.csv)|*.csv"; // Filter files by extension
  465. //去除创建文件时的文件名中包含的非法字符'\'
  466. dlg.FileName = $"{DisplayName}_{string.Join(",", RecipeDatas.Select(x => x.RecipeName.Replace('\\', '.')))}_{DateTime.Now:yyyyMMdd_HHmmss}";
  467. Nullable<bool> result = dlg.ShowDialog();// Show open file dialog box
  468. if (result == true) // Process open file dialog box results
  469. {
  470. BusyIndicatorContent = "Exporting start ...";
  471. IsBusy = true;
  472. Exporting?.Invoke(this, System.EventArgs.Empty);
  473. _cancellationTokenSource = new CancellationTokenSource();
  474. await Task.Run(() =>
  475. {
  476. DateTime startTime = startTime = StepStartTime;
  477. QueryDataClientFromTable(dlg.FileName, RecipeDatas.FirstOrDefault());
  478. }, _cancellationTokenSource.Token).ContinueWith(t =>
  479. {
  480. if (t.IsCanceled || t.IsFaulted)
  481. {
  482. IsBusy = false;
  483. return;
  484. }
  485. });
  486. if (_cancellationTokenSource?.Token.IsCancellationRequested == true)
  487. {
  488. IsBusy = false;
  489. return;
  490. }
  491. BusyIndicatorContent = "Data is written to Excel file ...";
  492. IsBusy = false;
  493. MessageBox.Show($"Export succeed, file save as {dlg.FileName}", "Export", MessageBoxButton.OK, MessageBoxImage.Information);
  494. Window window = Window.GetWindow(this.view);
  495. window.Close();
  496. }
  497. }
  498. catch (Exception ex)
  499. {
  500. LOG.Write(ex);
  501. MessageBox.Show("Write failed," + ex.Message, "export failed", MessageBoxButton.OK, MessageBoxImage.Warning);
  502. IsBusy = false;
  503. }
  504. }
  505. private void QueryDataClientFromTable(string fileName, ProcessHistoryLot recipeInfo)
  506. {
  507. DateTime startTime = StepStartTime;
  508. DateTime endTime = StepEndTime;
  509. List<string> keys = new List<string>(nodeOrigin);
  510. List<string> pmList = new List<string>();
  511. List<string> systemList = new List<string>();
  512. if (keys != null && keys.Count > 0)
  513. {
  514. keys = _processDetailDisplayDic.Keys.Intersect(keys).OrderBy(key => _processDetailDisplayDic.Keys.ToList().IndexOf(key)).ToList();
  515. foreach (var dataKey in keys)
  516. {
  517. var dataId = _processDetailDisplayDic.ContainsKey(dataKey) ? _processDetailDisplayDic[dataKey] : dataKey;
  518. var module = dataId.Split('.').ToList()[0];
  519. if (module.ToLower() == "pm1")
  520. {
  521. pmList.Add(dataId);
  522. }
  523. else if (module.ToLower() == "system")
  524. {
  525. systemList.Add(dataId);
  526. // systemList.Add(string.Format("\"{0}\"", dataId));
  527. }
  528. }
  529. }
  530. if (StepStartTime.Date == StepEndTime.Date)
  531. {
  532. SaveDataToTable(fileName, pmList, systemList, startTime, endTime, recipeInfo);
  533. }
  534. else
  535. {
  536. endTime = new DateTime(startTime.Year, startTime.Month, startTime.Day, 23, 59, 59);
  537. while (endTime < StepEndTime)
  538. {
  539. SaveDataToTable(fileName, pmList, systemList, startTime, endTime, recipeInfo);
  540. startTime = new DateTime(startTime.Year, startTime.Month, startTime.Day, 0, 0, 0).AddDays(1);
  541. endTime = new DateTime(startTime.Year, startTime.Month, startTime.Day, 23, 59, 59);
  542. }
  543. SaveDataToTable(fileName, pmList, systemList, startTime, StepEndTime, recipeInfo);
  544. }
  545. }
  546. private bool firstHeader = false;
  547. private Dictionary<string, string> GetReverseDict()
  548. {
  549. Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();
  550. foreach (var kvp in _processDetailDisplayDic)
  551. {
  552. if (!keyValuePairs.ContainsKey(kvp.Value))
  553. keyValuePairs[kvp.Value] = kvp.Key.Trim().Contains(" ") ? kvp.Key.Trim().Substring(kvp.Key.Trim().LastIndexOf(" ") + 1) : kvp.Key;
  554. }
  555. return keyValuePairs;
  556. }
  557. public class NeedCellColor
  558. {
  559. public bool IsNeed;
  560. public string Color;
  561. public short FillForegroundColor;
  562. public FillPattern FillPatternShort;
  563. }
  564. private ICellStyle GetICellStyle(IWorkbook workbook, NeedCellColor needCellColor = null)
  565. {
  566. ICellStyle cellStyle = workbook.CreateCellStyle();
  567. cellStyle.WrapText = true;
  568. cellStyle.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin;//粗线
  569. cellStyle.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin;//粗线
  570. cellStyle.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin;//粗线
  571. cellStyle.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin;//粗线
  572. cellStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
  573. cellStyle.VerticalAlignment = NPOI.SS.UserModel.VerticalAlignment.Center;
  574. if (needCellColor != null && needCellColor.IsNeed)
  575. {
  576. //string hexColor = needCellColor.Color;
  577. //short colorIndex = GetCustomPaletteColor(workbook, hexColor);
  578. cellStyle.FillForegroundColor = needCellColor.FillForegroundColor;
  579. cellStyle.FillPattern = needCellColor.FillPatternShort;
  580. }
  581. return cellStyle;
  582. }
  583. static short GetCustomPaletteColor(IWorkbook workbook, string hexColor)
  584. {
  585. if (hexColor.StartsWith("#"))
  586. {
  587. hexColor = hexColor.Substring(1);
  588. }
  589. int red = Convert.ToInt32(hexColor.Substring(0, 2), 16);
  590. int green = Convert.ToInt32(hexColor.Substring(2, 2), 16);
  591. int blue = Convert.ToInt32(hexColor.Substring(4, 2), 16);
  592. HSSFWorkbook hssfWorkbook = (HSSFWorkbook)workbook;
  593. HSSFPalette palette = hssfWorkbook.GetCustomPalette();
  594. try
  595. {
  596. return palette.FindSimilarColor((byte)red, (byte)green, (byte)blue).Indexed;
  597. }
  598. catch (Exception)
  599. {
  600. // 如果找不到相似的颜色,则分配新的调色板索引
  601. HSSFColor customColor = palette.FindColor((byte)red, (byte)green, (byte)blue);
  602. if (customColor == null)
  603. {
  604. customColor = palette.AddColor((byte)red, (byte)green, (byte)blue);
  605. }
  606. return customColor.Indexed;
  607. }
  608. }
  609. private void SaveDataToTable(string fileName, List<string> pmList, List<string> systemList, DateTime startTime, DateTime endTime, ProcessHistoryLot recipeInfo)
  610. {
  611. string stepID = "", stepName = "", subRecipeLoopInfo = "", subRecipeStepName = "", subRecipeStepNumber = "", tempCorrection = "", tempPid = "";
  612. DataTable pmDataTable = null;
  613. var columnsql = $"select column_name from information_schema.columns where table_name = '{startTime.ToString("yyyyMMdd")}.PM1'";
  614. var columnTable = QueryDataClient.Instance.Service.QueryData(columnsql);
  615. List<string> col = columnTable.Rows.Cast<DataRow>().Select(x => x.ItemArray[0].ToString()).ToList();
  616. pmList = pmList.Where(x => col.Any(y => y == x)).ToList();
  617. string pmsql = $"select time AS InternalTimeStamp, {string.Join(",", pmList.Select(x => string.Format("\"{0}\"", x)))}";
  618. DataTable systemDataTable = null;
  619. pmsql += string.Format(" from \"{0}\" where time > {1} and time <= {2} order by time asc",
  620. startTime.ToString("yyyyMMdd") + "." + "PM1", startTime.Ticks, endTime.Ticks);
  621. BusyIndicatorContent = "Example Query PM data ...";
  622. pmDataTable = QueryDataClient.Instance.Service.QueryData(pmsql);
  623. var sysColumnsql = $"select column_name from information_schema.columns where table_name = '{startTime.ToString("yyyyMMdd")}.System'";
  624. var sysColumnTable = QueryDataClient.Instance.Service.QueryData(sysColumnsql);
  625. List<string> systemCol = sysColumnTable?.Rows.Cast<DataRow>().Select(x => x.ItemArray[0].ToString()).ToList();
  626. systemList = systemList.Where(x => systemCol.Any(y => y == x)).ToList();
  627. string systemsql = $"select time AS InternalTimeStamp, {string.Join(",", systemList.Select(x => string.Format("\"{0}\"", x)))}";
  628. systemsql += string.Format(" from \"{0}\" where time > {1} and time <= {2} order by time asc",
  629. startTime.ToString("yyyyMMdd") + "." + "System", startTime.Ticks, endTime.Ticks);
  630. BusyIndicatorContent = "Example Query System data ...";
  631. systemDataTable = QueryDataClient.Instance.Service.QueryData(systemsql);
  632. int maxRow = 0;
  633. if ((pmDataTable == null || pmDataTable.Rows.Count == 0))
  634. {
  635. if (systemDataTable != null)
  636. {
  637. maxRow = systemDataTable.Rows.Count;
  638. }
  639. }
  640. else if ((systemDataTable == null || systemDataTable.Rows.Count == 0))
  641. {
  642. if (pmDataTable != null)
  643. {
  644. maxRow = pmDataTable.Rows.Count;
  645. }
  646. }
  647. else
  648. {
  649. maxRow = pmDataTable.Rows.Count > systemDataTable.Rows.Count ? systemDataTable.Rows.Count : pmDataTable.Rows.Count;
  650. }
  651. var subColNames = new List<DataColumn>() {
  652. new DataColumn("Step\nStartDate"),
  653. new DataColumn("Step\nStartTime"),
  654. new DataColumn("\tStepID\t "),
  655. new DataColumn("\tStepName\t"),
  656. new DataColumn("SubRecipe\nStepName"),
  657. new DataColumn("SubRecipe\nStepNumber"),
  658. new DataColumn("SubRecipe\nLoopInfo"),
  659. new DataColumn("Temp\nCorrection"),
  660. new DataColumn("\tTempPID\t"),
  661. };
  662. // Create a new workbook and sheet
  663. IWorkbook workbook = new XSSFWorkbook();
  664. ISheet sheet = workbook.CreateSheet("Sheet1");
  665. #region style
  666. ICellStyle borderCellStyle = workbook.CreateCellStyle();
  667. borderCellStyle.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin;//粗线
  668. borderCellStyle.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin;//粗线
  669. borderCellStyle.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin;//粗线
  670. borderCellStyle.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin;//粗线
  671. IFont font = workbook.CreateFont();
  672. borderCellStyle.SetFont(font);
  673. borderCellStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
  674. borderCellStyle.VerticalAlignment = NPOI.SS.UserModel.VerticalAlignment.Center;
  675. #endregion
  676. int rowIndex = 4;
  677. int cellIndex = 0;
  678. if (!firstHeader)
  679. {
  680. firstHeader = true;
  681. var systemColNames = systemDataTable?.Columns.Cast<DataColumn>().Where(x => x.ColumnName != "internaltimestamp").Select(x =>
  682. {
  683. if (_processProcessDetailAttributeDict.ContainsKey(x.ColumnName))
  684. {
  685. var colAttributeName = "ColName";
  686. if (!_processProcessDetailAttributeDict[x.ColumnName].ContainsKey(colAttributeName))
  687. {
  688. colAttributeName = "DisplayName";
  689. }
  690. var tempStr = _processProcessDetailAttributeDict[x.ColumnName].ContainsKey("DisplayName") && !string.IsNullOrEmpty(_processProcessDetailAttributeDict[x.ColumnName]["DisplayName"]) ? _processProcessDetailAttributeDict[x.ColumnName]["DisplayName"] : x.ColumnName;
  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. var tempStr = _processProcessDetailAttributeDict[x.ColumnName].ContainsKey("DisplayName") && !string.IsNullOrEmpty(_processProcessDetailAttributeDict[x.ColumnName]["DisplayName"]) ? _processProcessDetailAttributeDict[x.ColumnName]["DisplayName"] : x.ColumnName;
  705. return string.IsNullOrEmpty(_processProcessDetailAttributeDict[x.ColumnName][colAttributeName]) ? x.ColumnName : _processProcessDetailAttributeDict[x.ColumnName][colAttributeName];
  706. }
  707. return x.ColumnName;
  708. });
  709. // Create header row
  710. IRow headerRow = sheet.CreateRow(rowIndex++);
  711. cellIndex = 0;
  712. headerRow.HeightInPoints = 35;
  713. foreach (var subCol in subColNames)
  714. {
  715. ICell cell = headerRow.CreateCell(cellIndex++);
  716. string headerText = subCol.ColumnName.Replace("(", "\n(");
  717. cell.SetCellValue(headerText);
  718. cell.CellStyle = GetICellStyle(workbook);
  719. sheet.SetColumnWidth(cell.ColumnIndex, subCol.ColumnName.Length * 256);
  720. }
  721. foreach (var sysCol in systemColNames ?? new string[0])
  722. {
  723. ICell cell = headerRow.CreateCell(cellIndex++);
  724. string headerText = sysCol.Replace("(", "\n(");
  725. cell.SetCellValue(headerText);
  726. cell.CellStyle = GetICellStyle(workbook);
  727. sheet.SetColumnWidth(cell.ColumnIndex, sysCol.Length * 256);
  728. }
  729. foreach (var pmCol in pmColNames ?? new string[0])
  730. {
  731. ICell cell = headerRow.CreateCell(cellIndex++);
  732. string headerText = pmCol.Replace("(", "\n(");
  733. cell.SetCellValue(headerText);
  734. cell.CellStyle = GetICellStyle(workbook);
  735. sheet.SetColumnWidth(cell.ColumnIndex, pmCol.Length * 256);
  736. }
  737. }
  738. Dictionary<string, string> keyValuePairs = new Dictionary<string, string>()
  739. {
  740. { "Recipe Info",recipeInfo.RecipeName},
  741. { "Recipe StartTime",recipeInfo.ProcessStartTime.ToString("yyyy-MM-dd HH:mm:ss")},
  742. { "Recipe EndTime",recipeInfo.ProcessEndTime.ToString("yyyy-MM-dd HH:mm:ss")},
  743. { "Recipe Type",recipeInfo.RecipeType.ToString()},
  744. { "Recipe ExecEntry",recipeInfo.RecipeExecEntry.ToString()},
  745. };
  746. rowIndex = 0;
  747. cellIndex = 0;
  748. IRow dictRow = sheet.CreateRow(rowIndex);
  749. dictRow.HeightInPoints = 35;
  750. foreach (var kvp in keyValuePairs)
  751. {
  752. ICell keyCell = dictRow.CreateCell(cellIndex++);
  753. keyCell.SetCellValue(kvp.Key);
  754. keyCell.CellStyle = GetICellStyle(workbook);
  755. }
  756. rowIndex = 1;
  757. cellIndex = 0;
  758. dictRow = sheet.CreateRow(rowIndex);
  759. dictRow.HeightInPoints = 35;
  760. foreach (var kvp in keyValuePairs)
  761. {
  762. ICell keyCell = dictRow.CreateCell(cellIndex++);
  763. keyCell.SetCellValue(kvp.Value);
  764. keyCell.CellStyle = GetICellStyle(workbook);
  765. //sheet.AutoSizeColumn(cellIndex);
  766. sheet.SetColumnWidth(cellIndex - 1, kvp.Value.Length * 256);
  767. }
  768. int columnIndex = subColNames.Count + 1;
  769. rowIndex = 5;
  770. for (int i = 0; i < maxRow; i++)
  771. {
  772. IRow dataRow = sheet.CreateRow(rowIndex++);
  773. dataRow.HeightInPoints = 25;
  774. var pmRow = pmDataTable != null && pmDataTable.Rows.Count > 0 ? pmDataTable.Rows[i] : null;
  775. var systemRow = systemDataTable != null && systemDataTable.Rows.Count > 0 ? systemDataTable.Rows[i] : null;
  776. DateTime dateTimeKey = new DateTime(systemRow != null ? (long)systemRow[0] : (long)pmRow[0]);
  777. var tempStepInfo = _stepInfo.OrderByDescending(x => x.StartTime).Where(x => x.StartTime <= dateTimeKey).FirstOrDefault();
  778. if (tempStepInfo != null)
  779. {
  780. stepID = tempStepInfo.StepNo;
  781. stepName = tempStepInfo.StepName;
  782. subRecipeStepName = tempStepInfo.SubRecipeStepName;
  783. subRecipeStepNumber = tempStepInfo.SubRecipeStepNumber;
  784. subRecipeLoopInfo = !string.IsNullOrEmpty(tempStepInfo.SubRecipeLoopInfo) ? tempStepInfo.SubRecipeLoopInfo.Replace("/", "|") : tempStepInfo.SubRecipeLoopInfo;
  785. tempCorrection = !string.IsNullOrEmpty(tempStepInfo.TempCorrection) ? tempStepInfo.TempCorrection : "";
  786. tempPid = !string.IsNullOrEmpty(tempStepInfo.TempPid) ? tempStepInfo.TempPid : "";
  787. }
  788. cellIndex = 0;
  789. dataRow.CreateCell(cellIndex++).SetCellValue(dateTimeKey.ToString("yyyy/MM/dd"));
  790. dataRow.CreateCell(cellIndex++).SetCellValue(dateTimeKey.ToString("HH:mm:ss"));
  791. dataRow.CreateCell(cellIndex++).SetCellValue(stepID);
  792. dataRow.CreateCell(cellIndex++).SetCellValue(stepName);
  793. dataRow.CreateCell(cellIndex++).SetCellValue(subRecipeStepName);
  794. dataRow.CreateCell(cellIndex++).SetCellValue(subRecipeStepNumber);
  795. dataRow.CreateCell(cellIndex++).SetCellValue(subRecipeLoopInfo);
  796. dataRow.CreateCell(cellIndex++).SetCellValue(tempCorrection);
  797. dataRow.CreateCell(cellIndex++).SetCellValue(tempPid);
  798. if (pmRow == null && systemRow != null)
  799. {
  800. for (int j = 1; j < systemRow.ItemArray.Length; j++)
  801. {
  802. ICell cell = dataRow.CreateCell(cellIndex++);
  803. cell.SetCellValue(systemRow[j].ToString());
  804. cell.CellStyle = GetICellStyle(workbook);
  805. }
  806. for (int j = 0; j < (pmDataTable?.Columns.Count ?? 0); j++)
  807. {
  808. ICell cell = dataRow.CreateCell(cellIndex++);
  809. cell.SetCellValue("");
  810. cell.CellStyle = GetICellStyle(workbook);
  811. }
  812. }
  813. else if (pmRow != null && systemRow == null)
  814. {
  815. for (int j = 0; j < (systemDataTable?.Columns?.Count ?? 0); j++)
  816. {
  817. ICell cell = dataRow.CreateCell(cellIndex++);
  818. cell.SetCellValue("");
  819. cell.CellStyle = GetICellStyle(workbook);
  820. }
  821. for (int j = 1; j < pmRow.ItemArray.Length; j++)
  822. {
  823. ICell cell = dataRow.CreateCell(cellIndex++);
  824. var setValueData = pmRow[j].ToString();
  825. if (bool.TryParse(pmRow[j].ToString(), out var avData))
  826. setValueData = pmRow[j].ToString() == bool.TrueString ? "Open" : "Close";
  827. cell.SetCellValue(setValueData);
  828. cell.CellStyle = GetICellStyle(workbook);
  829. }
  830. }
  831. else if (systemDataTable != null)
  832. {
  833. for (int j = 1; j < systemRow.ItemArray.Length; j++)
  834. {
  835. ICell cell = dataRow.CreateCell(cellIndex++);
  836. cell.SetCellValue(systemRow[j].ToString());
  837. cell.CellStyle = GetICellStyle(workbook);
  838. }
  839. for (int j = 1; j < pmRow.ItemArray.Length; j++)
  840. {
  841. ICell cell = dataRow.CreateCell(cellIndex++);
  842. var setValueData = pmRow[j].ToString();
  843. if (bool.TryParse(pmRow[j].ToString(), out var avData))
  844. setValueData = pmRow[j].ToString() == bool.TrueString ? "Open" : "Close";
  845. cell.SetCellValue(setValueData);
  846. cell.CellStyle = GetICellStyle(workbook);
  847. }
  848. }
  849. }
  850. sheet.SetColumnWidth(0, keyValuePairs.LastOrDefault().Key.Length * 256);
  851. sheet.SetColumnWidth(3, keyValuePairs.LastOrDefault().Key.Length * 256);
  852. sheet.SetColumnWidth(4, keyValuePairs.LastOrDefault().Key.Length * 256);
  853. // Write the output to a file
  854. using (FileStream file = new FileStream(fileName, FileMode.Create, FileAccess.Write))
  855. {
  856. workbook.Write(file);
  857. }
  858. }
  859. static string CheckAndReplace(string input)
  860. {
  861. if (input.StartsWith("PM1"))
  862. {
  863. return input.Substring(4);
  864. }
  865. if (input.StartsWith("System"))
  866. {
  867. return input.Substring(7);
  868. }
  869. return input;
  870. }
  871. /// <summary>
  872. /// 取消查询。
  873. /// </summary>
  874. public void CancelQuery()
  875. {
  876. Task.Run(() =>
  877. {
  878. if (_cancellationTokenSource?.Token.CanBeCanceled == true)
  879. {
  880. _cancellationTokenSource.Cancel();
  881. }
  882. Thread.Sleep(100);
  883. //_progQueryUpdate.Report(new ProgressUpdatingEventArgs(100, 100, ""));
  884. //_progChartSuspendUpdating.Report(false);
  885. });
  886. }
  887. }
  888. }