ChartingBaseViewModel.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using Npgsql;
  6. using System.Data;
  7. using Aitex.UI.Charting.Model;
  8. using Abt.Controls.SciChart;
  9. using System.Windows.Media;
  10. using System.Threading;
  11. using System.Text.RegularExpressions;
  12. using DataAnalysisControl.Core;
  13. using Aitex.DataAnalysis.Core;
  14. namespace Aitex.UI.Charting.ViewModel
  15. {
  16. public class ChartingBaseViewModel : BaseViewModel
  17. {
  18. #region put protected database operations here
  19. private static object _dbLocker = new object();
  20. private static NpgsqlConnection _conn = null;
  21. public static string ServerName
  22. {
  23. get
  24. {
  25. string ip = RegEdit.ReadRegedit("Aitex", "Database_IP");
  26. if (string.IsNullOrEmpty(ip))
  27. {
  28. //创建默认注册表
  29. RegEdit.WriteRegedit("Aitex", "Database_Ip", "127.0.0.1");
  30. RegEdit.WriteRegedit("Aitex", "Database_Port", "5432");
  31. RegEdit.WriteRegedit("Aitex", "Database_User", "postgres");
  32. RegEdit.WriteRegedit("Aitex", "Database_Pwd", "123456");
  33. RegEdit.WriteRegedit("Aitex", "Database_Name", "postgres");
  34. }
  35. ip = RegEdit.ReadRegedit("Aitex", "Database_IP");
  36. string port = RegEdit.ReadRegedit("Aitex", "Database_Port");
  37. string user = RegEdit.ReadRegedit("Aitex", "Database_User");
  38. string pwd = RegEdit.ReadRegedit("Aitex", "Database_Pwd");
  39. string db = RegEdit.ReadRegedit("Aitex", "Database_Name");
  40. return String.Format("Server={0};Port={1};User Id={2};Password={3};Database={4};Enlist=true;CommandTimeout=10;Timeout=10;", ip, port, user, pwd, db);
  41. //return CONTEXT.GetDBConnString();
  42. }
  43. }
  44. /// <summary>
  45. /// 创建数据库连接
  46. /// </summary>
  47. /// <param name="reason"></param>
  48. /// <returns>True:创建成功 False:创建失败</returns>
  49. protected static bool CreateConnection(out string reason)
  50. {
  51. lock (_dbLocker)
  52. {
  53. CONTEXT.WriteLog("Charting工具开始创建Charting工具的数据库连接");
  54. reason = string.Empty;
  55. if (_conn != null)
  56. {
  57. _conn.Close();
  58. _conn = null;
  59. }
  60. string connectionString = ServerName;
  61. if (string.IsNullOrWhiteSpace(connectionString))
  62. {
  63. throw new ArgumentNullException("ConnectionString");
  64. }
  65. try
  66. {
  67. var conn = new NpgsqlConnection(connectionString);
  68. conn.Open();
  69. _conn = conn;
  70. }
  71. catch (Exception ex)
  72. {
  73. reason = ex.Message;
  74. CONTEXT.WriteLog(ex, string.Format("Charting工具创建PostgreSQL数据库连接失败,连接字段: 【{0}】", connectionString));
  75. return false;
  76. }
  77. return true;
  78. }
  79. }
  80. /// <summary>
  81. /// 执行无需返回的sql语句
  82. /// </summary>
  83. /// <param name="cmdText"></param>
  84. public static void ExecuteNonQuery(string cmdText)
  85. {
  86. string reason;
  87. if (_conn == null && !CreateConnection(out reason))
  88. return;
  89. lock (_dbLocker)
  90. {
  91. if (_conn.State != ConnectionState.Open)
  92. _conn.Open();
  93. using (NpgsqlCommand command = new NpgsqlCommand(cmdText, _conn))
  94. {
  95. command.ExecuteNonQuery();
  96. }
  97. }
  98. }
  99. /// <summary>
  100. /// 执行SQL语句
  101. /// </summary>
  102. /// <param name="cmdText"></param>
  103. /// <param name="p"></param>
  104. /// <returns></returns>
  105. public static DataSet ExecuteDataset(string cmdText, params object[] p)
  106. {
  107. DeviceTimer tm = new DeviceTimer();
  108. tm.Start(0);
  109. string reason;
  110. if (_conn == null && !CreateConnection(out reason))
  111. return null;
  112. DataSet ds = new DataSet();
  113. lock (_dbLocker)
  114. {
  115. using (NpgsqlCommand command = new NpgsqlCommand())
  116. {
  117. try
  118. {
  119. if (_conn.State != ConnectionState.Open)
  120. _conn.Open();
  121. command.Parameters.Clear();
  122. command.Connection = _conn;
  123. command.CommandText = cmdText;
  124. command.CommandType = CommandType.Text;
  125. if (p != null)
  126. {
  127. foreach (object parm in p)
  128. command.Parameters.AddWithValue(string.Empty, parm);
  129. }
  130. using (NpgsqlDataAdapter da = new NpgsqlDataAdapter(command))
  131. {
  132. da.Fill(ds);
  133. }
  134. }
  135. catch (Exception ex)
  136. {
  137. //如果是Table不存在,则跳过该天的数据查询
  138. if (ex is Npgsql.NpgsqlException &&
  139. 0 == String.Compare((ex as Npgsql.NpgsqlException).Code, "42P01"/*未定义的表(UNDEFINED TABLE)*/, true))
  140. {
  141. string errMsg = string.Format("执行SQL:【{0}】 发生Table不存在", cmdText);
  142. CONTEXT.WriteLog(errMsg);
  143. }
  144. else
  145. {
  146. CreateConnection(out reason);
  147. string errMsg = string.Format("执行SQL:【{0}】 发生异常,重新创建数据库连接", cmdText);
  148. CONTEXT.WriteLog(ex, errMsg);
  149. //throw new Exception(errMsg);
  150. }
  151. }
  152. }
  153. }
  154. return ds;
  155. }
  156. #endregion
  157. #region get recipe information
  158. /// <summary>
  159. /// 获取指定石墨盘的工艺程序运行每一步的时间信息+步骤名称
  160. /// </summary>
  161. /// <param name="susceptorId"></param>
  162. /// <returns></returns>
  163. public List<RecipeSyncPoint> GetRecipeStepInfo(string recipeRunGuid)
  164. {
  165. var Ret = new List<RecipeSyncPoint>();
  166. try
  167. {
  168. string sql = string.Format("SELECT * FROM \"SusceptorData\" where \"SusceptorId\"= '{0}' and \"ItemType\" = '{1}' order by \"Time\" asc;",
  169. recipeRunGuid, "RecipeStepStart");
  170. Ret.Add(new RecipeSyncPoint() { StepTime = DateTime.MinValue, StepName = "NULL" });
  171. var ds = ExecuteDataset(sql);
  172. if (ds != null && ds.Tables != null && ds.Tables.Count >= 0)
  173. {
  174. for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
  175. {
  176. var row = ds.Tables[0].Rows[i];
  177. var stepTime = Convert.ToDateTime(row["Time"].ToString());
  178. var stepDesc = row["ItemRemark"].ToString();
  179. if (stepDesc.StartsWith("工艺运行中:开始"))
  180. stepDesc = stepDesc.Replace("工艺运行中:开始", string.Empty);
  181. Ret.Add(new RecipeSyncPoint() { StepTime = stepTime, StepName = stepDesc });
  182. }
  183. }
  184. }
  185. catch (Exception ex)
  186. {
  187. CONTEXT.WriteLog(ex, string.Format("获取工艺Run编号{0}的工艺处理数据发生异常", recipeRunGuid));
  188. }
  189. return Ret;
  190. }
  191. #endregion
  192. #region get susceptor list
  193. /// <summary>
  194. /// 石墨盘数据模型
  195. /// </summary>
  196. public class SusceptorDataModel
  197. {
  198. public string RecipeRunGuid { get; set; }
  199. public string SusceptorId { get; set; }
  200. public string UserDefinedId { get; set; }
  201. public string RecipeName { get; set; }
  202. /// <summary>
  203. /// 仅用于界面显示,em. 20131219131415_LED001-(2) 简化为 LED001-(2)
  204. /// </summary>
  205. public string RecipeShortName
  206. {
  207. get
  208. {
  209. if (!string.IsNullOrEmpty(RecipeName) && Regex.IsMatch(RecipeName, @"^\d\d\d\d\d\d\d\d\d\d\d\d\d\d_*") && RecipeName.Length > 15)
  210. return RecipeName.Substring(15);
  211. return RecipeName;
  212. }
  213. }
  214. //public string CreateTime { get; set; }
  215. //public string DeleteTime { get; set; }
  216. public string ProcessBeginTime { get; set; }
  217. public string ProcessEndTime { get; set; }
  218. public string ProcessIn { get; set; }
  219. public string SusceptorStatus { get; set; }
  220. public string WaferOnSusceptor { get; set; }
  221. public string Description { get; set; }
  222. }
  223. /// <summary>
  224. /// get susceptor list
  225. /// </summary>
  226. /// <param name="begin"></param>
  227. /// <param name="end"></param>
  228. /// <param name="processIn"></param>
  229. /// <returns></returns>
  230. public List<SusceptorDataModel> GetSusceptorList(DateTime begin, DateTime end, string processIn)
  231. {
  232. return GetSusceptorList(begin, end, processIn, "", "", "");
  233. }
  234. /// <summary>
  235. /// get susceptor list
  236. /// </summary>
  237. /// <param name="begin"></param>
  238. /// <param name="end"></param>
  239. /// <param name="processIn"></param>
  240. /// <param name="recipeName"></param>
  241. /// <param name="description"></param>
  242. /// <param name="userDefinedId"></param>
  243. /// <returns></returns>
  244. public List<SusceptorDataModel> GetSusceptorList(DateTime begin, DateTime end, string processIn, string recipeName, string description, string userDefinedId)
  245. {
  246. var ret = new List<SusceptorDataModel>();
  247. try
  248. {
  249. string sql = string.Format("SELECT * FROM \"RecipeRunHistory\" where \"ProcessBeginTime\" >= '{0}' and \"ProcessBeginTime\" <= '{1}' {2} {3} {4} {5} order by \"ProcessBeginTime\" asc;",
  250. begin.ToString("yyyy/MM/dd HH:mm:ss.fff"), end.ToString("yyyy/MM/dd HH:mm:ss.fff"),
  251. string.IsNullOrEmpty(processIn) ? "" : string.Format(" and \"ProcessIn\" = '{0}'", processIn),
  252. string.IsNullOrEmpty(recipeName) ? "" : string.Format(" and \"RecipeName\" = '{0}'", recipeName),
  253. string.IsNullOrEmpty(description) ? "" : string.Format(" and \"Description\" = '{0}'", description),
  254. string.IsNullOrEmpty(userDefinedId) ? "" : string.Format(" and \"UserDefinedId\" = '{0}'", userDefinedId));
  255. using (var dataSet = ExecuteDataset(sql))
  256. {
  257. for(int i = 0; i < dataSet.Tables[0].Rows.Count;i++)
  258. {
  259. var row = dataSet.Tables[0].Rows[i];
  260. string susceptorStatusString = row["SusceptorStatus"].ToString();
  261. //SusceptorStatus eSt;
  262. //bool isSucc = Enum.TryParse<SusceptorStatus>(susceptorStatusString, out eSt);
  263. //if (isSucc) susceptorStatusString = Common.Utilities.Converter.SusceptorStatus(eSt);
  264. ret.Add(new SusceptorDataModel()
  265. {
  266. RecipeRunGuid = row["RecipeRunGuid"].ToString(),
  267. //CreateTime = row["CreateTime"].ToString(),
  268. //DeleteTime = row["DeleteTime"].ToString(),
  269. Description = row["Description"].ToString(),
  270. ProcessBeginTime = row["ProcessBeginTime"].ToString(),
  271. ProcessEndTime = row["ProcessEndTime"].ToString(),
  272. ProcessIn = row["ProcessIn"].ToString(),
  273. RecipeName = row["RecipeName"].ToString(),
  274. SusceptorId = row["SusceptorId"].ToString(),
  275. UserDefinedId = row["UserDefinedId"].ToString(),
  276. SusceptorStatus = susceptorStatusString,
  277. WaferOnSusceptor = row["WafersOnSusceptor"].ToString()
  278. });
  279. }
  280. }
  281. }
  282. catch (Exception ex)
  283. {
  284. CONTEXT.WriteLog(ex, string.Format("获取{0}~{1}期间,{2}处理,工艺程序为{3}的石墨盘记录发生错误", begin, end, processIn, recipeName));
  285. }
  286. return ret;
  287. }
  288. #endregion
  289. #region get equipment data from database
  290. /// <summary>
  291. /// get data from PostgreSQL database
  292. /// </summary>
  293. /// <param name="chamId"></param>
  294. /// <param name="from"></param>
  295. /// <param name="to"></param>
  296. /// <param name="dataIdList"></param>
  297. /// <param name="returnDatas"></param>
  298. /// <returns></returns>
  299. public bool GetDbData(string chamId, DateTime from, DateTime to, IEnumerable<string> dataIdList, out Dictionary<string, DataItem> returnDatas)
  300. {
  301. returnDatas = new Dictionary<string, DataItem>();
  302. for (DateTime dfrom = new DateTime(from.Year, from.Month, from.Day);
  303. dfrom < to; dfrom += new TimeSpan(1, 0, 0, 0))
  304. {
  305. DateTime begin = (dfrom.Year == from.Year && dfrom.Month == from.Month && dfrom.Day == from.Day) ? from : new DateTime(dfrom.Year, dfrom.Month, dfrom.Day, 0, 0, 0, 0);
  306. DateTime end = (dfrom.Date == to.Date) ? to : new DateTime(dfrom.Year, dfrom.Month, dfrom.Day, 23, 59, 59, 999);
  307. //if (begin.Date > DateTime.Today)
  308. // continue;
  309. try
  310. {
  311. string sql = "select time AS InternalTimeStamp";
  312. foreach (var dataId in dataIdList)
  313. {
  314. if (!returnDatas.Keys.Contains(dataId) && !dataId.Contains("PM.VirtualDevice"))
  315. {
  316. returnDatas.Add(dataId, new DataItem() { DataName = dataId, RawData = new List<float>(), TimeStamp = new List<DateTime>() });
  317. sql += "," + string.Format("\"{0}\"", dataId);
  318. }
  319. }
  320. sql += string.Format(" from \"{0}\" where time > {1} and time <= {2} order by time asc;",
  321. begin.ToString("yyyyMMdd") + "." + chamId.ToString(), begin.Ticks, end.Ticks);
  322. using (var dataSet = ExecuteDataset(sql))
  323. {
  324. if (dataSet.Tables.Count == 0 || dataSet.Tables[0].Rows.Count == 0)
  325. continue;
  326. DateTime dt = new DateTime();
  327. Dictionary<int, string> colName = new Dictionary<int, string>();
  328. for (int colNo = 0; colNo < dataSet.Tables[0].Columns.Count; colNo++)
  329. colName.Add(colNo, dataSet.Tables[0].Columns[colNo].ColumnName);
  330. for(int rowNo = 0 ; rowNo < dataSet.Tables[0].Rows.Count; rowNo++)
  331. {
  332. var row = dataSet.Tables[0].Rows[rowNo];
  333. for (int i = 0; i < dataSet.Tables[0].Columns.Count; i++)
  334. {
  335. if (i == 0)
  336. {
  337. long ticks = (long)row[i];
  338. dt = new DateTime(ticks);
  339. }
  340. else
  341. {
  342. string dataId = colName[i];
  343. if (row[i] is DBNull || row[i] == null)
  344. {
  345. returnDatas[dataId].RawData.Add(0);// ds.Data[].Add(new KeyValuePair<DateTime,float>(dt, 0));
  346. returnDatas[dataId].TimeStamp.Add(dt);
  347. }
  348. else if (row[i] is bool)
  349. {
  350. //ds.Data[reader.GetName(i)].Add(new KeyValuePair<DateTime, float>(dt, (bool)reader[i] ? 1 : 0));
  351. returnDatas[dataId].RawData.Add((bool)row[i] ? 1 : 0);
  352. returnDatas[dataId].TimeStamp.Add(dt);
  353. }
  354. else
  355. {
  356. //ds.Data[reader.GetName(i)].Add(new KeyValuePair<DateTime, float>(dt, float.Parse(reader[i].ToString())));
  357. returnDatas[dataId].RawData.Add(float.Parse(row[i].ToString()));
  358. returnDatas[dataId].TimeStamp.Add(dt);
  359. }
  360. }
  361. }
  362. }
  363. dataSet.Clear();
  364. GC.Collect();
  365. }
  366. }
  367. catch (Exception ex)
  368. {
  369. CONTEXT.WriteLog(ex);
  370. return false;
  371. }
  372. }
  373. return true;
  374. }
  375. /// <summary>
  376. /// Read data name list from database
  377. /// </summary>
  378. /// <param name="beginTime"></param>
  379. /// <param name="whichCham"></param>
  380. /// <param name="reason"></param>
  381. /// <returns></returns>
  382. public void ReadDbDataNameList(DateTime beginTime, string whichCham, out string reason, out List<string> dataList, out Dictionary<string, Tuple<string, List<string>>> virtualDeviceList)
  383. {
  384. dataList = new List<string>();
  385. virtualDeviceList = new Dictionary<string, Tuple<string, List<string>>>();
  386. reason = string.Empty;
  387. try
  388. {
  389. string tblName = beginTime.ToString("yyyyMMdd.") + whichCham;
  390. //query if table already exist?
  391. string sqlTblDefine = string.Format("select cols.column_name, (select pg_catalog.obj_description(oid) from pg_catalog.pg_class c where c.relname=cols.table_name) as table_comment ,(select pg_catalog.col_description(oid,cols.ordinal_position::int) from pg_catalog.pg_class c where c.relname=cols.table_name) as column_comment from information_schema.columns cols where cols.table_name='{0}';", tblName);
  392. using (var dataSet = ExecuteDataset(sqlTblDefine))
  393. {
  394. for(int i= 0; i < dataSet.Tables[0].Rows.Count;i++)
  395. dataList.Add(dataSet.Tables[0].Rows[i]["column_name"].ToString());
  396. }
  397. //if table exists, add virtual device datas
  398. if (dataList.Count > 0)
  399. {
  400. string sqlVirtualTblDefine = string.Format("SELECT \"DeviceName\", \"FunctionBlock\" FROM \"VirtualDevice\" where \"ChamberID\" = '{0}';", whichCham);
  401. bool isAny = false;
  402. using (var dataSet = ExecuteDataset(sqlVirtualTblDefine))
  403. {
  404. for (int i = 0; i < dataSet.Tables[0].Rows.Count; i++)
  405. {
  406. var virtualDeviceName = "PM.VirtualDevice." + dataSet.Tables[0].Rows[i]["DeviceName"].ToString();
  407. var functionBlock = dataSet.Tables[0].Rows[i]["FunctionBlock"].ToString();
  408. var varList = new List<string>();
  409. var collection = Regex.Matches(functionBlock, @"PM(\.\w+)+");
  410. foreach(var item in collection)
  411. {
  412. varList.Add(item.ToString());
  413. }
  414. isAny = true;
  415. dataList.Add(virtualDeviceName);
  416. virtualDeviceList.Add(virtualDeviceName, new Tuple<string, List<string>>(functionBlock, varList));
  417. }
  418. }
  419. if (!isAny)
  420. {
  421. dataList.Add("PM.VirtualDevice");
  422. }
  423. }
  424. }
  425. catch (Exception ex)
  426. {
  427. reason = ex.Message;
  428. CONTEXT.WriteLog(ex, string.Format("获取{0} {1}数据库变量名列表发生异常", whichCham, beginTime.ToString("yyyy/MM/dd HH:mm:ss")));
  429. }
  430. }
  431. #region 获取wafer显示顺序
  432. /// <summary>
  433. /// 获取wafer显示顺序
  434. /// </summary>
  435. /// <returns></returns>
  436. public string GetWaferDisplayIndex(DateTime startTime, string ProcessIn)
  437. {
  438. string result = string.Empty;
  439. try
  440. {
  441. string sql = string.Format("SELECT \"DisplayIndex\" FROM \"WaferDisplayIndex\" WHERE \"Id\" =( SELECT \"RecipeRunGuid\" FROM \"RecipeRunHistory\" where to_char(\"ProcessBeginTime\",'yyyy-MM-DD HH24:MI:SS') = '{0}' and \"ProcessIn\"='{1}');",
  442. startTime.ToString("yyyy-MM-dd HH:mm:ss"), ProcessIn);
  443. using (var dataSet = ExecuteDataset(sql))
  444. {
  445. if (dataSet.Tables[0].Rows.Count > 0)
  446. { result = dataSet.Tables[0].Rows[0]["DisplayIndex"].ToString(); }
  447. }
  448. }
  449. catch (System.Exception ex)
  450. {
  451. CONTEXT.WriteLog(ex, "数据库读取wafer排序信息失败");
  452. //result = "60,61,62,63,64,65,66,47,48,49,50,51,52,53,54,55,56,57,58,59,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26";
  453. }
  454. return result;
  455. }
  456. /// <summary>
  457. /// 获取wafer映射表
  458. /// </summary>
  459. public string WaferDisplayIndex { get; set; }
  460. #endregion
  461. #endregion
  462. }
  463. }