DepRecipeViewModel.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. using Aitex.Core.RT.DataCenter;
  2. using Aitex.Core.RT.Log;
  3. using Aitex.Core.UI.Dialog;
  4. using Aitex.Core.UI.MVVM;
  5. using Aitex.Core.Utilities;
  6. using Caliburn.Micro.Core;
  7. using PunkHPX8_Core;
  8. using PunkHPX8_MainPages.PMs;
  9. using PunkHPX8_Themes.UserControls;
  10. using MECF.Framework.Common.DataCenter;
  11. using MECF.Framework.Common.RecipeCenter;
  12. using MECF.Framework.Common.Utilities;
  13. using Prism.Mvvm;
  14. using System;
  15. using System.Collections.Generic;
  16. using System.Collections.ObjectModel;
  17. using System.ComponentModel;
  18. using System.Linq;
  19. using System.Reflection;
  20. using System.Text;
  21. using System.Threading.Tasks;
  22. using System.Windows;
  23. using System.Windows.Controls;
  24. using System.Windows.Input;
  25. namespace PunkHPX8_MainPages.ViewModels
  26. {
  27. public class DepRecipeViewModel : BindableBase
  28. {
  29. #region 常量
  30. private const string ENGINEERING = "Engineering";
  31. private const string DEP = "dep";
  32. #endregion
  33. #region 内部变量
  34. /// <summary>
  35. /// Recipe节点字典
  36. /// </summary>
  37. private Dictionary<string, RecipeNode> _recipeNodeDic = new Dictionary<string, RecipeNode>();
  38. /// <summary>
  39. /// 属性检验结果字典
  40. /// </summary>
  41. private Dictionary<string, bool> _propertyValidResultDic = new Dictionary<string, bool>();
  42. /// <summary>
  43. /// Recipe节点集合
  44. /// </summary>
  45. private ObservableCollection<RecipeNode> _recipeNodes;
  46. /// <summary>
  47. /// uiRecipeManager
  48. /// </summary>
  49. private UiRecipeManager _uiRecipeManager = new UiRecipeManager();
  50. /// <summary>
  51. /// recipe
  52. /// </summary>
  53. private DepRecipe _recipe;
  54. /// <summary>
  55. /// 编辑可用性
  56. /// </summary>
  57. private bool _editEnable;
  58. /// <summary>
  59. /// 创建可用性
  60. /// </summary>
  61. private bool _createEnable;
  62. /// <summary>
  63. /// 当前节点
  64. /// </summary>
  65. private RecipeNode _currentNode;
  66. /// <summary>
  67. /// 是否可用
  68. /// </summary>
  69. private bool _enable = false;
  70. /// <summary>
  71. /// 是否为编辑(true-Edit,false-add)
  72. /// </summary>
  73. private bool _isEdit = false;
  74. /// <summary>
  75. /// 化学液集合
  76. /// </summary>
  77. private List<string> _chemistryList = new List<string>();
  78. /// <summary>
  79. /// 显示MultiZone列
  80. /// </summary>
  81. private bool _multiZoneShow = false;
  82. /// <summary>
  83. /// 显示SingleZone列
  84. /// </summary>
  85. private bool _singleZoneShow = false;
  86. /// <summary>
  87. /// 选择AnodeType
  88. /// </summary>
  89. private string _selectAnodeType;
  90. /// <summary>
  91. /// Ramp DataGrid选择索引
  92. /// </summary>
  93. private int _selectedRampIndex = -1;
  94. /// <summary>
  95. /// Pulse DataGrid选择索引
  96. /// </summary>
  97. private int _selectedPulseIndex = -1;
  98. #endregion
  99. #region 属性
  100. public ObservableCollection<RecipeNode> RecipeNodes
  101. {
  102. get { return _recipeNodes; }
  103. set { SetProperty(ref _recipeNodes, value); }
  104. }
  105. /// <summary>
  106. /// Recipe
  107. /// </summary>
  108. public DepRecipe Recipe
  109. {
  110. get { return _recipe; }
  111. set { SetProperty(ref _recipe, value); }
  112. }
  113. /// <summary>
  114. /// 创建可用性
  115. /// </summary>
  116. public bool CreateEnable
  117. {
  118. get { return _createEnable; }
  119. set { SetProperty(ref _createEnable, value);}
  120. }
  121. /// <summary>
  122. /// 编辑可用性
  123. /// </summary>
  124. public bool EditEnable
  125. {
  126. get { return _editEnable; }
  127. set { SetProperty(ref _editEnable, value);}
  128. }
  129. /// <summary>
  130. /// 当前节点
  131. /// </summary>
  132. public RecipeNode CurrentNode
  133. {
  134. get { return _currentNode; }
  135. set { SetProperty(ref _currentNode, value);}
  136. }
  137. /// <summary>
  138. /// 可用性
  139. /// </summary>
  140. public bool Enable
  141. {
  142. get { return _enable; }
  143. set { SetProperty(ref _enable, value); }
  144. }
  145. /// <summary>
  146. /// 属性数据检验结果
  147. /// </summary>
  148. public Dictionary<string, bool> PropertyValidResultDic
  149. {
  150. get { return _propertyValidResultDic; }
  151. set { SetProperty(ref _propertyValidResultDic, value); }
  152. }
  153. /// <summary>
  154. /// 化学液集合
  155. /// </summary>
  156. public List<string> ChemistryList
  157. {
  158. get { return _chemistryList; }
  159. set { SetProperty(ref _chemistryList, value); }
  160. }
  161. /// <summary>
  162. /// MultiZone 显示
  163. /// </summary>
  164. public bool MultiZoneShow
  165. {
  166. get { return _multiZoneShow; }
  167. set
  168. {
  169. SetProperty(ref _multiZoneShow, value);
  170. SingleZoneShow = !value;
  171. }
  172. }
  173. /// <summary>
  174. /// SingleZone显示列
  175. /// </summary>
  176. public bool SingleZoneShow
  177. {
  178. get { return _singleZoneShow; }
  179. set { SetProperty(ref _singleZoneShow, value);}
  180. }
  181. /// <summary>
  182. /// DataGrid 索引
  183. /// </summary>
  184. public int SelectedRampIndex
  185. {
  186. get { return _selectedRampIndex; }
  187. set { SetProperty(ref _selectedRampIndex, value);}
  188. }
  189. /// <summary>
  190. /// Pulse Datagrid选择索引
  191. /// </summary>
  192. public int SelectedPulseIndex
  193. {
  194. get { return _selectedPulseIndex; }
  195. set { SetProperty(ref _selectedPulseIndex, value); }
  196. }
  197. #endregion
  198. #region 指令
  199. [IgnorePropertyChange]
  200. public ICommand OperationCommand
  201. {
  202. get;
  203. private set;
  204. }
  205. [IgnorePropertyChange]
  206. public ICommand CreateCommand { get; private set; }
  207. [IgnorePropertyChange]
  208. public ICommand EditCommand { get; private set; }
  209. [IgnorePropertyChange]
  210. public ICommand SaveRecipeCommand { get; private set; }
  211. [IgnorePropertyChange]
  212. public ICommand SaveAsRecipeCommand { get; private set; }
  213. [IgnorePropertyChange]
  214. public ICommand AddBelowCommand { get;private set; }
  215. [IgnorePropertyChange]
  216. public ICommand AddAboveCommand { get; private set; }
  217. [IgnorePropertyChange]
  218. public ICommand MoveUpCommand { get; private set; }
  219. [IgnorePropertyChange]
  220. public ICommand MoveDownCommand { get; private set; }
  221. [IgnorePropertyChange]
  222. public ICommand DeleteCommand { get;private set; }
  223. #endregion
  224. /// <summary>
  225. /// 构造函数
  226. /// </summary>
  227. public DepRecipeViewModel()
  228. {
  229. OperationCommand = new DelegateCommand<object>(SelectionChangedAction);
  230. CreateCommand = new DelegateCommand<object>(CreateAction);
  231. EditCommand = new DelegateCommand<object>(EditAction);
  232. SaveRecipeCommand = new DelegateCommand<object>(SaveAction);
  233. SaveAsRecipeCommand = new DelegateCommand<object>(SaveAsAction);
  234. AddBelowCommand = new DelegateCommand<object>(AddBelowAction);
  235. AddAboveCommand = new DelegateCommand<object>(AddAboveAction);
  236. MoveUpCommand=new DelegateCommand<object>(MoveUpAction);
  237. MoveDownCommand=new DelegateCommand<object>(MoveDownAction);
  238. DeleteCommand=new DelegateCommand<object>(DeleteAction);
  239. string chemistryContent = QueryDataClient.Instance.Service.GetConfig($"System.ChemistryList").ToString();
  240. if (!string.IsNullOrEmpty(chemistryContent))
  241. {
  242. ChemistryList = chemistryContent.Split(',').ToList();
  243. }
  244. InitializeProprtyValidResultDictionary();
  245. }
  246. /// <summary>
  247. /// 初始化属性数据检验结果字典
  248. /// </summary>
  249. private void InitializeProprtyValidResultDictionary()
  250. {
  251. PropertyValidResultDic["EntrySpinSpeed"] = false;
  252. PropertyValidResultDic["EntryZoffset"] = false;
  253. PropertyValidResultDic["PlatingDelay"] = false;
  254. PropertyValidResultDic["EntryCurrent"] = false;
  255. PropertyValidResultDic["EntryVoltage"] = false;
  256. PropertyValidResultDic["DepCurrentWarning"] = false;
  257. PropertyValidResultDic["DepCurrentFault"] = false;
  258. PropertyValidResultDic["DepMaxVoltageWarning"] = false;
  259. PropertyValidResultDic["DepMaxVoltageFault"] = false;
  260. PropertyValidResultDic["DepZoffset"] = false;
  261. PropertyValidResultDic["Section1Speed"] = false;
  262. PropertyValidResultDic["Section2Speed"] = false;
  263. PropertyValidResultDic["NormalSpeed"] = false;
  264. PropertyValidResultDic["ReclaimSpeed"] = false;
  265. PropertyValidResultDic["ReclaimTime"] = false;
  266. PropertyValidResultDic["ReclaimZoffset"] = false;
  267. PropertyValidResultDic["RinseSpeed"] = false;
  268. PropertyValidResultDic["RinseTime"] = false;
  269. PropertyValidResultDic["RinseZoffset"] = false;
  270. PropertyValidResultDic["DrySpeed"] = false;
  271. PropertyValidResultDic["DryTime"] = false;
  272. PropertyValidResultDic["DryZoffset"] = false;
  273. PropertyValidResultDic["IntervalRinseSpeed"] = false;
  274. PropertyValidResultDic["IntervalRinseTime"] = false;
  275. PropertyValidResultDic["IntervalRinseZoffset"] = false;
  276. }
  277. /// <summary>
  278. /// 加载数据
  279. /// </summary>
  280. public void LoadRecipeData()
  281. {
  282. RecipeNodes = _uiRecipeManager.GetRecipesByType(DEP);
  283. _recipeNodeDic.Clear();
  284. InitializeDictionary(RecipeNodes);
  285. }
  286. /// <summary>
  287. /// 初始化字典
  288. /// </summary>
  289. /// <param name="nodes"></param>
  290. private void InitializeDictionary(ObservableCollection<RecipeNode> nodes)
  291. {
  292. if (nodes != null)
  293. {
  294. foreach (var node in nodes)
  295. {
  296. if (node.NodeType == RecipeNodeType.File)
  297. {
  298. _recipeNodeDic[node.Name] = node;
  299. }
  300. InitializeDictionary(node.Children);
  301. }
  302. }
  303. }
  304. /// <summary>
  305. /// 操作
  306. /// </summary>
  307. /// <param name="param"></param>
  308. private void SelectionChangedAction(object param)
  309. {
  310. if(_recipeNodeDic.ContainsKey(param.ToString()))
  311. {
  312. CurrentNode = _recipeNodeDic[param.ToString()];
  313. if(CurrentNode.NodeType==RecipeNodeType.File)
  314. {
  315. if (CurrentNode.RecipeLocation == ENGINEERING)
  316. {
  317. EditEnable = true;
  318. CreateEnable = true;
  319. }
  320. else
  321. {
  322. EditEnable= false;
  323. CreateEnable = false;
  324. }
  325. }
  326. Recipe = _uiRecipeManager.LoadRecipe<DepRecipe>(CurrentNode.RecipeFullFileName);
  327. if(Recipe==null)
  328. {
  329. MessageBox.Show("Invalid Recipe", "Load Recipe", MessageBoxButton.OK, MessageBoxImage.Error);
  330. EditEnable = false;
  331. CreateEnable = false;
  332. }
  333. Enable = false;
  334. }
  335. else
  336. {
  337. if(param.ToString()==ENGINEERING)
  338. {
  339. CreateEnable= true;
  340. }
  341. else
  342. {
  343. CreateEnable = false;
  344. }
  345. CurrentNode = null;
  346. Recipe = null;
  347. EditEnable = false;
  348. Enable = false;
  349. }
  350. }
  351. #region Action
  352. /// <summary>
  353. /// 创建
  354. /// </summary>
  355. /// <param name="param"></param>
  356. private void CreateAction(object param)
  357. {
  358. RecipeNameDialog recipeNameDialog = new RecipeNameDialog();
  359. if (recipeNameDialog.ShowDialog().Value)
  360. {
  361. Recipe = new DepRecipe();
  362. Recipe.CreateDate = DateTime.Now;
  363. Recipe.Ppid = recipeNameDialog.RecipeName;
  364. Recipe.Description=recipeNameDialog.RecipeDescription;
  365. Recipe.DepSteps = new ObservableCollection<CurrentRampProfile>();
  366. Enable = true;
  367. _isEdit = false;
  368. }
  369. }
  370. /// <summary>
  371. /// 编辑
  372. /// </summary>
  373. /// <param name="param"></param>
  374. private void EditAction(object param)
  375. {
  376. Enable = true;
  377. _isEdit= false;
  378. }
  379. /// <summary>
  380. /// 保存
  381. /// </summary>
  382. /// <param name="param"></param>
  383. private void SaveAction(object param)
  384. {
  385. if (CheckValid(_isEdit))
  386. {
  387. Recipe.SaveDate = DateTime.Now;
  388. int platingsteps = 0;
  389. int totaltime = 0;
  390. double totalcurrent = 0;
  391. foreach(var obj in Recipe.DepSteps)
  392. {
  393. totaltime += obj.DurartionSeconds;
  394. totalcurrent += (obj.CurrentValue * obj.DurartionSeconds);
  395. platingsteps++;
  396. }
  397. //计算Deposition PlatingSteps
  398. Recipe.DepStepCount = platingsteps;
  399. //计算Deposition Totaltimes
  400. string date = string.Empty;
  401. var seconds = (int)(totaltime % 60);
  402. var minutes = (int)(totaltime / 60) % 60;
  403. var hours = (int)(totaltime / 3600) % 60;
  404. date = string.Format("{0:00}:{1:00}:{2:00}", hours + "h", minutes + "m", seconds + "s");
  405. Recipe.DepStepTotalTime = date;
  406. //计算Deposition TotalCurrent
  407. Recipe.DepStepTotalCurrent = totalcurrent / 3600;
  408. //计算TotalTime
  409. Recipe.TotalTime = totaltime + Recipe.PlatingDelay +
  410. Recipe.ReclaimTime + Recipe.RinseTime + Recipe.DryTime + Recipe.IntervalRinseTime;
  411. try
  412. {
  413. _uiRecipeManager.SaveRecipe<DepRecipe>(ENGINEERING, Recipe.Ppid,"dep", Recipe);
  414. LoadRecipeData();
  415. MessageBox.Show("Save Recipe Success", "Save Recipe", MessageBoxButton.OK, MessageBoxImage.Information);
  416. Enable = false;
  417. }
  418. catch (Exception ex)
  419. {
  420. MessageBox.Show(ex.Message, "Save Recipe", MessageBoxButton.OK, MessageBoxImage.Error);
  421. }
  422. }
  423. }
  424. /// <summary>
  425. /// 另存为
  426. /// </summary>
  427. /// <param name="param"></param>
  428. private void SaveAsAction(object param)
  429. {
  430. if (Recipe == null)
  431. {
  432. MessageBox.Show("Select a Recipe first", "SaveAs Recipe", MessageBoxButton.OK, MessageBoxImage.Error);
  433. return;
  434. }
  435. DepRecipe recipe = new DepRecipe();
  436. if (CheckValid(_isEdit))
  437. {
  438. RecipeNameDialog recipeNameDialog = new RecipeNameDialog();
  439. if (recipeNameDialog.ShowDialog().Value)
  440. {
  441. if (!CheckNameExist(recipeNameDialog.RecipeName))
  442. {
  443. recipe = new DepRecipe();
  444. recipe = (DepRecipe)PropertyUtil.Clone(Recipe);
  445. recipe.CreateDate = DateTime.Now;
  446. recipe.Ppid = recipeNameDialog.RecipeName;
  447. recipe.Description = recipeNameDialog.RecipeDescription;
  448. }
  449. else if (recipeNameDialog.RecipeName != null)
  450. {
  451. MessageBox.Show("Name can not be Null", "Create Recipe", MessageBoxButton.OK, MessageBoxImage.Error);
  452. return;
  453. }
  454. else
  455. {
  456. return;
  457. }
  458. }
  459. try
  460. {
  461. _uiRecipeManager.SaveRecipe<DepRecipe>(ENGINEERING, recipe.Ppid, "dep", recipe);
  462. LoadRecipeData();
  463. MessageBox.Show("Save As Recipe Success", "SaveAs Recipe", MessageBoxButton.OK, MessageBoxImage.Information);
  464. Enable = false;
  465. }
  466. catch (Exception ex)
  467. {
  468. MessageBox.Show(ex.Message, "Save As Recipe", MessageBoxButton.OK, MessageBoxImage.Error);
  469. }
  470. }
  471. }
  472. /// <summary>
  473. /// 检验名称是否已经存在
  474. /// </summary>
  475. /// <param name="name"></param>
  476. /// <returns></returns>
  477. private bool CheckNameExist(string name)
  478. {
  479. foreach (string item in _recipeNodeDic.Keys)
  480. {
  481. if (item == name)
  482. {
  483. MessageBox.Show($"{name} is exsit", "Save Recipe", MessageBoxButton.OK, MessageBoxImage.Error);
  484. return true;
  485. }
  486. }
  487. return false;
  488. }
  489. /// <summary>
  490. /// 检验合法性
  491. /// </summary>
  492. /// <param name="editType"></param>
  493. /// <returns></returns>
  494. private bool CheckValid(bool editType)
  495. {
  496. foreach(string key in _propertyValidResultDic.Keys)
  497. {
  498. bool valid = _propertyValidResultDic[key];
  499. if(!valid)
  500. {
  501. MessageBox.Show($"{key} data invalid", "Save Recipe", MessageBoxButton.OK, MessageBoxImage.Error);
  502. return false;
  503. }
  504. }
  505. if(Recipe.EntryCurrent > 0 && Recipe.EntryVoltage > 0)
  506. {
  507. MessageBox.Show($"Entry Current and Entry Voltage can not both larger than 0", "Save Recipe", MessageBoxButton.OK, MessageBoxImage.Error);
  508. return false;
  509. }
  510. return true;
  511. }
  512. #region Ramp按钮
  513. /// <summary>
  514. /// 增加
  515. /// </summary>
  516. /// <param name="param"></param>
  517. private void AddBelowAction(object param)
  518. {
  519. if (Recipe != null)
  520. {
  521. CurrentRampProfile currentRampProfile = new CurrentRampProfile();
  522. Recipe.DepSteps.Insert(SelectedRampIndex + 1, currentRampProfile);
  523. SelectedRampIndex++;
  524. }
  525. }
  526. /// <summary>
  527. /// 增加
  528. /// </summary>
  529. /// <param name="param"></param>
  530. private void AddAboveAction(object param)
  531. {
  532. if (Recipe != null)
  533. {
  534. CurrentRampProfile currentRampProfile = new CurrentRampProfile();
  535. if (SelectedRampIndex == -1)
  536. {
  537. Recipe.DepSteps.Add(currentRampProfile);
  538. SelectedRampIndex = 0;
  539. }
  540. else
  541. {
  542. Recipe.DepSteps.Insert(SelectedRampIndex, currentRampProfile);
  543. SelectedRampIndex--;
  544. }
  545. }
  546. }
  547. /// <summary>
  548. /// 上移
  549. /// </summary>
  550. /// <param name="param"></param>
  551. private void MoveUpAction(object param)
  552. {
  553. if (Recipe != null)
  554. {
  555. if(SelectedRampIndex>0)
  556. {
  557. int currentIndex = SelectedRampIndex;
  558. CurrentRampProfile currentRampProfile = Recipe.DepSteps[SelectedRampIndex];
  559. Recipe.DepSteps.RemoveAt(SelectedRampIndex);
  560. Recipe.DepSteps.Insert(currentIndex - 1,currentRampProfile);
  561. SelectedRampIndex = currentIndex - 1;
  562. }
  563. }
  564. }
  565. /// <summary>
  566. /// 下移
  567. /// </summary>
  568. /// <param name="param"></param>
  569. private void MoveDownAction(object param)
  570. {
  571. if (Recipe != null)
  572. {
  573. if (SelectedRampIndex>=0&&SelectedRampIndex <Recipe.DepSteps.Count-1 &&Recipe.DepSteps.Count>1)
  574. {
  575. int currentIndex = SelectedRampIndex;
  576. CurrentRampProfile currentRampProfile = Recipe.DepSteps[SelectedRampIndex];
  577. Recipe.DepSteps.RemoveAt(SelectedRampIndex);
  578. Recipe.DepSteps.Insert(currentIndex + 1, currentRampProfile);
  579. SelectedRampIndex = currentIndex + 1;
  580. }
  581. }
  582. }
  583. /// <summary>
  584. /// 删除
  585. /// </summary>
  586. /// <param name="param"></param>
  587. private void DeleteAction(object param)
  588. {
  589. if (SelectedRampIndex != -1)
  590. {
  591. if (Recipe != null && Recipe.DepSteps.Count > SelectedRampIndex)
  592. {
  593. Recipe.DepSteps.RemoveAt(SelectedRampIndex);
  594. }
  595. }
  596. }
  597. #endregion
  598. #endregion
  599. }
  600. }