WF_Runtime.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using LeaRun.Util;
  5. using LeaRun.Util.Extension;
  6. namespace LeaRun.Util.FlowWork
  7. {
  8. /// <summary>
  9. /// 版 本 6.1
  10. /// Copyright (c) 2013-2016 上海力软信息技术有限公司
  11. /// 创建人:陈彬彬
  12. /// 日 期:2016.03.04 16:58
  13. /// 描 述:工作流流程流转操作类
  14. /// </summary>
  15. public class WF_Runtime : IWF_Runtime
  16. {
  17. private WF_RuntimeModel _runtimeModel = null;
  18. private GetFrmData _getFrmData = null;
  19. /// <summary>
  20. /// 构造函数
  21. /// </summary>
  22. /// <param name="schemeContent">流程模板</param>
  23. /// <param name="currentNodeId">当前节点</param>
  24. /// <param name="frmData">表单数据</param>
  25. public WF_Runtime(WF_RuntimeInitModel wfRuntimeInitModel,GetFrmData getFrmData = null)
  26. {
  27. _runtimeModel = new WF_RuntimeModel();
  28. _getFrmData = getFrmData;
  29. dynamic schemeContentJson = wfRuntimeInitModel.schemeContent.ToJson();//获取工作流模板内容的json对象;
  30. _runtimeModel.schemeContentJson = schemeContentJson;//模板流程json对象
  31. _runtimeModel.nodeDictionary = GetNodeDictionary(schemeContentJson);//节点集合
  32. _runtimeModel.lineDictionary = GetLineDictionary(schemeContentJson);//线条集合
  33. _runtimeModel.currentNodeId = (wfRuntimeInitModel.currentNodeId == "" ? _runtimeModel.startNodeId : wfRuntimeInitModel.currentNodeId);
  34. _runtimeModel.currentNodeType = GetNodeStatus(_runtimeModel.currentNodeId);
  35. _runtimeModel.frmData = wfRuntimeInitModel.frmData;
  36. if (getFrmData != null)
  37. {
  38. _runtimeModel.frmType = 1;
  39. wfRuntimeInitModel.frmData = GetNodeFrmData(getFrmData);
  40. }
  41. else
  42. {
  43. _runtimeModel.frmType = 0;
  44. }
  45. if (_runtimeModel.currentNodeType == 0 || _runtimeModel.currentNodeType == 4)
  46. {
  47. _runtimeModel.nextNodeId = "-1";//下一个节点
  48. _runtimeModel.nextNodeType = -1;
  49. }
  50. else
  51. {
  52. _runtimeModel.nextNodeId = GetNextNode(wfRuntimeInitModel.frmData);//下一个节点
  53. _runtimeModel.nextNodeType = GetNodeStatus(_runtimeModel.nextNodeId);
  54. }
  55. _runtimeModel.previousId = wfRuntimeInitModel.previousId;
  56. _runtimeModel.processId = wfRuntimeInitModel.processId;
  57. _runtimeModel.sqlFrm = SqlBuider(schemeContentJson, wfRuntimeInitModel.frmData, wfRuntimeInitModel.processId);
  58. }
  59. #region 私有方法
  60. /// <summary>
  61. /// 获取工作流节点的字典列表:key节点id
  62. /// </summary>
  63. /// <param name="schemeContentJson"></param>
  64. /// <returns></returns>
  65. private Dictionary<string, dynamic> GetNodeDictionary(dynamic schemeContentJson)
  66. {
  67. Dictionary<string, dynamic> nodeDictionary = new Dictionary<string, dynamic>();
  68. foreach (var item in schemeContentJson.Flow.nodes)
  69. {
  70. if (!nodeDictionary.ContainsKey(item.id.Value))
  71. {
  72. nodeDictionary.Add(item.id.Value, item);
  73. }
  74. if (item.type == "startround")
  75. {
  76. this._runtimeModel.startNodeId = item.id.Value;
  77. }
  78. }
  79. return nodeDictionary;
  80. }
  81. /// <summary>
  82. /// 获取工作流线段的字典列表:key开始节点id,value线条实体列表
  83. /// </summary>
  84. /// <param name="schemeContentJson"></param>
  85. /// <returns></returns>
  86. private Dictionary<string, List<dynamic>> GetLineDictionary(dynamic schemeContentJson)
  87. {
  88. Dictionary<string, List<dynamic>> lineDictionary = new Dictionary<string, List<dynamic>>();
  89. foreach (var item in schemeContentJson.Flow.lines)
  90. {
  91. if (!lineDictionary.ContainsKey(item.from.Value))
  92. {
  93. List<dynamic> d = new List<dynamic>();
  94. d.Add(item);
  95. lineDictionary.Add(item.from.Value, d);
  96. }
  97. else
  98. {
  99. lineDictionary[item.from.Value].Add(item);
  100. }
  101. }
  102. return lineDictionary;
  103. }
  104. /// <summary>
  105. /// 获取工作流线段的字典列表:key开始节点id,value线条实体列表
  106. /// </summary>
  107. /// <param name="schemeContentJson"></param>
  108. /// <returns></returns>
  109. private Dictionary<string, List<dynamic>> GetToLineDictionary(dynamic schemeContentJson)
  110. {
  111. Dictionary<string, List<dynamic>> lineDictionary = new Dictionary<string, List<dynamic>>();
  112. foreach (var item in schemeContentJson.Flow.lines)
  113. {
  114. if (!lineDictionary.ContainsKey(item.to.Value))
  115. {
  116. List<dynamic> d = new List<dynamic>();
  117. d.Add(item);
  118. lineDictionary.Add(item.to.Value, d);
  119. }
  120. else
  121. {
  122. lineDictionary[item.to.Value].Add(item);
  123. }
  124. }
  125. return lineDictionary;
  126. }
  127. /// <summary>
  128. /// 工作流流转条件比较函数
  129. /// </summary>
  130. /// <param name="frmvalue">表单数据</param>
  131. /// <param name="operation"></param>
  132. /// <param name="paramValue"></param>
  133. /// <returns></returns>
  134. private bool LineCompared(string frmvalue, string operation, string paramValue)
  135. {
  136. bool res = false;
  137. switch (operation)
  138. {
  139. case "Equal"://等于
  140. if (decimal.Parse(frmvalue) == decimal.Parse(paramValue))
  141. {
  142. res = true;
  143. }
  144. break;
  145. case "NotEqual"://不等于
  146. if (decimal.Parse(frmvalue) != decimal.Parse(paramValue))
  147. {
  148. res = true;
  149. }
  150. break;
  151. case "Greater"://大于
  152. if (decimal.Parse(frmvalue) > decimal.Parse(paramValue))
  153. {
  154. res = true;
  155. }
  156. break;
  157. case "GreaterThan"://大于等于
  158. if (decimal.Parse(frmvalue) >= decimal.Parse(paramValue))
  159. {
  160. res = true;
  161. }
  162. break;
  163. case "Less"://小于
  164. if (decimal.Parse(frmvalue) < decimal.Parse(paramValue))
  165. {
  166. res = true;
  167. }
  168. break;
  169. case "LessThan"://小于等于
  170. if (decimal.Parse(frmvalue) <= decimal.Parse(paramValue))
  171. {
  172. res = true;
  173. }
  174. break;
  175. case "Null"://为空
  176. if (string.IsNullOrEmpty(frmvalue))
  177. {
  178. res = true;
  179. }
  180. break;
  181. case "NotNull"://不为空
  182. if (!string.IsNullOrEmpty(frmvalue))
  183. {
  184. res = true;
  185. }
  186. break;
  187. case "Like"://包含
  188. if (frmvalue.IndexOf(paramValue) != -1)
  189. {
  190. res = true;
  191. }
  192. break;
  193. case "NotLike"://不包含
  194. if (frmvalue.IndexOf(paramValue) == -1)
  195. {
  196. res = true;
  197. }
  198. break;
  199. }
  200. return res;
  201. }
  202. /// <summary>
  203. /// 获取SQL语句
  204. /// </summary>
  205. /// <param name="tablename"></param>
  206. /// <param name="frmData"></param>
  207. /// <returns></returns>
  208. private string SqlBuider(dynamic schemeContentJson, string frmData, string keyValue)
  209. {
  210. try
  211. {
  212. if (schemeContentJson.Frm.isSystemTable.Value == 1)
  213. {
  214. var strSql = new StringBuilder();
  215. var frmDataParam = frmData.ToJObject();
  216. string sqlname = schemeContentJson.Frm.FrmTableId.Value, sqlvalues = "'" + keyValue + "'";
  217. foreach (var item in frmDataParam)
  218. {
  219. if (item.Key != "__RequestVerificationToken")
  220. {
  221. sqlname += "," + item.Key;
  222. if (item.Value.Type.ToString() == "String")
  223. {
  224. sqlvalues += ",'" + item.Value + "'";
  225. }
  226. else
  227. {
  228. sqlvalues += "," + item.Value;
  229. }
  230. }
  231. }
  232. strSql.Append(string.Format("insert into " + schemeContentJson.Frm.FrmTable.Value + " ({0})values({1})", sqlname, sqlvalues));
  233. return strSql.ToString();
  234. }
  235. else
  236. {
  237. return "";
  238. }
  239. }
  240. catch
  241. {
  242. throw;
  243. }
  244. }
  245. /// <summary>
  246. /// 系统表单获取表单数据
  247. /// </summary>
  248. /// <param name="getFrmData"></param>
  249. /// <param name="nodeId"></param>
  250. /// <returns></returns>
  251. private string GetNodeFrmData(GetFrmData getFrmData,string nodeId = null)
  252. {
  253. try
  254. {
  255. string _nodeId = (nodeId == null ? _runtimeModel.currentNodeId : nodeId);
  256. dynamic _node = _runtimeModel.nodeDictionary[_nodeId];
  257. if (_node.setInfo != null)
  258. {
  259. return getFrmData(_node.setInfo.NodeDataBase.Value, _node.setInfo.NodeTable.Value, _node.setInfo.NodePram.Value, _runtimeModel.processId);
  260. }
  261. else
  262. {
  263. return "";
  264. }
  265. }
  266. catch
  267. {
  268. throw;
  269. }
  270. }
  271. /// <summary>
  272. /// 获取下一个节点
  273. /// </summary>
  274. /// <param name="frmData">表单数据(用于判断流转条件)</param>
  275. private string GetNextNode(string frmData,string nodeId = null)
  276. {
  277. try
  278. {
  279. List<dynamic> LineList = null;
  280. if (nodeId == null)
  281. {
  282. LineList = runtimeModel.lineDictionary[runtimeModel.currentNodeId];
  283. }
  284. else
  285. {
  286. LineList = runtimeModel.lineDictionary[nodeId];
  287. }
  288. if (LineList.Count == 1)
  289. {
  290. return LineList[0].to.Value;
  291. }
  292. else if (frmData != "")
  293. {
  294. frmData = frmData.ToLower();//统一转小写
  295. var frmDataJson = frmData.ToJObject();//获取数据内容
  296. bool flag = false;
  297. foreach (var item in LineList)//轮训该节点所有连接的线路
  298. {
  299. if (item.setInfo == null)//表示该线路没有设置条件,所以流转到下一个节点
  300. {
  301. return item.to.Value;
  302. }
  303. foreach (var _item in item.setInfo.ConditionValueJson)//轮询该线条上的所有条件
  304. {
  305. if (!string.IsNullOrEmpty(frmDataJson[_item.ParamName.Value.ToLower()].Value))
  306. {
  307. string frmvalue = frmDataJson[_item.ParamName.Value.ToLower()].ToString();
  308. string operation = _item.Operation.Value;
  309. string paramValue = _item.ParamValue.Value;
  310. bool compareValue = LineCompared(frmvalue, operation, paramValue);
  311. if (_item.Operation.Value == "AND")
  312. {
  313. flag = compareValue;
  314. if (!compareValue)
  315. {
  316. break;
  317. }
  318. }
  319. else
  320. {
  321. if (compareValue)
  322. {
  323. flag = compareValue;
  324. }
  325. }
  326. }
  327. }
  328. if (flag)//如果满足条件,
  329. {
  330. return item.to.Value;
  331. }
  332. }
  333. }
  334. return "-1";//表示寻找不到节点
  335. }
  336. catch
  337. {
  338. throw;
  339. }
  340. }
  341. #endregion
  342. #region 工作流实例流转API
  343. /// <summary>
  344. /// 工作流实例运行信息
  345. /// </summary>
  346. /// <returns></returns>
  347. public WF_RuntimeModel runtimeModel
  348. {
  349. get { return _runtimeModel; }
  350. }
  351. /// <summary>
  352. /// 获取实例接下来运行的状态
  353. /// </summary>
  354. /// <returns>-1无法运行,0会签开始,1会签结束,2一般节点,4流程运行结束</returns>
  355. public int GetStatus()
  356. {
  357. if (_runtimeModel.nextNodeId != "-1")
  358. {
  359. if (_runtimeModel.nextNode.type == "shuntnode")//会签开始节点
  360. {
  361. return 0;
  362. }
  363. else if (_runtimeModel.nextNode.type == "confluencenode")//会签结束节点
  364. {
  365. return 1;
  366. }
  367. else if (_runtimeModel.nextNode.type == "endround")//结束节点
  368. {
  369. return 4;
  370. }
  371. else
  372. {
  373. return 2;
  374. }
  375. }
  376. else
  377. {
  378. return -1;
  379. }
  380. }
  381. /// <summary>
  382. /// 获取节点类型 0会签开始,1会签结束,2一般节点,开始节点,4流程运行结束
  383. /// </summary>
  384. /// <param name="nodeId"></param>
  385. /// <returns></returns>
  386. public int GetNodeStatus(string nodeId)
  387. {
  388. if (_runtimeModel.nodeDictionary[nodeId].type == "shuntnode")//会签开始节点
  389. {
  390. return 0;
  391. }
  392. else if (_runtimeModel.nodeDictionary[nodeId].type == "confluencenode")//会签结束节点
  393. {
  394. return 1;
  395. }
  396. else if (_runtimeModel.nodeDictionary[nodeId].type == "endround")//结束节点
  397. {
  398. return 4;
  399. }
  400. else if (_runtimeModel.nodeDictionary[nodeId].type == "startround")//开始节点
  401. {
  402. return 3;
  403. }
  404. else
  405. {
  406. return 2;
  407. }
  408. }
  409. /// <summary>
  410. /// 获取会签下面需要审核的ID列表
  411. /// </summary>
  412. /// <param name="shuntnodeId"></param>
  413. /// <returns></returns>
  414. public List<string> GetCountersigningNodeIdList(string shuntnodeId)
  415. {
  416. try
  417. {
  418. List<string> list = new List<string>();
  419. List<dynamic> listline = _runtimeModel.lineDictionary[shuntnodeId];
  420. foreach (var item in listline)
  421. {
  422. list.Add(item.to.Value);
  423. }
  424. return list;
  425. }
  426. catch
  427. {
  428. throw;
  429. }
  430. }
  431. /// <summary>
  432. /// 通过节点Id获取下一个节点Id
  433. /// </summary>
  434. /// <param name="nodeId"></param>
  435. /// <returns></returns>
  436. public string GetNextNodeByNodeId(string nodeId)
  437. {
  438. try
  439. {
  440. string frmData = "";
  441. if (_runtimeModel.frmType == 0)
  442. {
  443. frmData = _runtimeModel.frmData;
  444. }
  445. else
  446. {
  447. frmData = GetNodeFrmData(_getFrmData, nodeId);
  448. }
  449. return GetNextNode(frmData, nodeId);
  450. }
  451. catch
  452. {
  453. throw;
  454. }
  455. }
  456. /// <summary>
  457. /// 节点会签审核
  458. /// </summary>
  459. /// <param name="nodeId"></param>
  460. /// <param name="flag"></param>
  461. /// <returns>-1不通过,1等待,其它通过</returns>
  462. public string NodeConfluence(string nodeId, bool flag,string userId, string description = "")
  463. {
  464. string res = "-1";
  465. try
  466. {
  467. if (flag)
  468. {
  469. MakeTagNode(nodeId, 1, userId, description);
  470. }
  471. else
  472. {
  473. MakeTagNode(nodeId, -1, userId, description);
  474. }
  475. string _nextNodeId = GetNextNodeByNodeId(nodeId);//获取下一个节点
  476. if (_nextNodeId != "-1")
  477. {
  478. Dictionary<string, List<dynamic>> toLines = GetToLineDictionary(_runtimeModel.schemeContentJson);
  479. int allnum = toLines[_nextNodeId].Count;
  480. int i = 0;
  481. foreach (var item in _runtimeModel.schemeContentJson.Flow.nodes)
  482. {
  483. if (item.id.Value == _nextNodeId)
  484. {
  485. if(item.setInfo.NodeConfluenceType.Value == "0")//0所有步骤通过
  486. {
  487. if(flag)
  488. {
  489. if (item.setInfo.ConfluenceOk == null)
  490. {
  491. _runtimeModel.schemeContentJson.Flow.nodes[i].setInfo.ConfluenceOk = 1;
  492. res = "1";
  493. }
  494. else if (item.setInfo.ConfluenceOk.Value == (allnum - 1))
  495. {
  496. res = GetNextNodeByNodeId(_nextNodeId);
  497. if (res == "-1")
  498. {
  499. throw (new Exception("会签成功寻找不到下一个节点"));
  500. }
  501. }
  502. else
  503. {
  504. _runtimeModel.schemeContentJson.Flow.nodes[i].setInfo.ConfluenceOk++;
  505. res = "1";
  506. }
  507. }
  508. }
  509. else if(item.setInfo.NodeConfluenceType.Value == "1")//1一个步骤通过即可
  510. {
  511. if (flag)
  512. {
  513. res = GetNextNodeByNodeId(_nextNodeId);
  514. if (res == "-1")
  515. {
  516. throw (new Exception("会签成功寻找不到下一个节点"));
  517. }
  518. }
  519. else
  520. {
  521. if (item.setInfo.ConfluenceNo == null)
  522. {
  523. _runtimeModel.schemeContentJson.Flow.nodes[i].setInfo.ConfluenceNo = 1;
  524. res = "1";
  525. }
  526. else if (item.setInfo.ConfluenceNo.Value == (allnum - 1))
  527. {
  528. res = "-1";
  529. }
  530. else
  531. {
  532. _runtimeModel.schemeContentJson.Flow.nodes[i].setInfo.ConfluenceNo++;
  533. res = "1";
  534. }
  535. }
  536. }
  537. else//2按百分比计算
  538. {
  539. if (flag)
  540. {
  541. if (item.setInfo.ConfluenceOk == null)
  542. {
  543. _runtimeModel.schemeContentJson.Flow.nodes[i].setInfo.ConfluenceOk = 1;
  544. }
  545. else
  546. {
  547. _runtimeModel.schemeContentJson.Flow.nodes[i].setInfo.ConfluenceOk++;
  548. }
  549. }
  550. else
  551. {
  552. if (item.setInfo.ConfluenceNo == null)
  553. {
  554. _runtimeModel.schemeContentJson.Flow.nodes[i].setInfo.ConfluenceNo = 1;
  555. }
  556. else
  557. {
  558. _runtimeModel.schemeContentJson.Flow.nodes[i].setInfo.ConfluenceNo++;
  559. }
  560. }
  561. if ((item.setInfo.ConfluenceNo.Value + item.setInfo.ConfluenceOk.Value) / allnum * 100 > int.Parse(item.setInfo.NodeConfluenceRate.Value))
  562. {
  563. res = GetNextNodeByNodeId(_nextNodeId);
  564. if (res == "-1")
  565. {
  566. throw (new Exception("会签成功寻找不到下一个节点"));
  567. }
  568. }
  569. else if ((item.setInfo.ConfluenceNo.Value + item.setInfo.ConfluenceOk.Value) == allnum)
  570. {
  571. res = "-1";
  572. }
  573. else
  574. {
  575. res = "1";
  576. }
  577. }
  578. break;
  579. }
  580. i++;
  581. }
  582. if (res == "-1")
  583. {
  584. MakeTagNode(_nextNodeId, -1, userId);
  585. }
  586. else if (res != "1")
  587. {
  588. MakeTagNode(_nextNodeId, 1, userId);
  589. }
  590. else
  591. {
  592. _runtimeModel.nextNodeId = res;
  593. _runtimeModel.nextNodeType = GetNodeStatus(res);
  594. }
  595. return res;
  596. }
  597. else
  598. {
  599. throw (new Exception("寻找不到会签下合流节点"));
  600. }
  601. }
  602. catch
  603. {
  604. throw;
  605. }
  606. }
  607. /// <summary>
  608. /// 驳回节点0"前一步"1"第一步"2"某一步" 3"不处理"
  609. /// </summary>
  610. /// <returns></returns>
  611. public string RejectNode()
  612. {
  613. return RejectNode(_runtimeModel.currentNodeId);
  614. }
  615. /// <summary>
  616. /// 驳回节点0"前一步"1"第一步"2"某一步" 3"不处理"
  617. /// </summary>
  618. /// <param name="nodeId"></param>
  619. /// <returns></returns>
  620. public string RejectNode(string nodeId)
  621. {
  622. try
  623. {
  624. dynamic _node = _runtimeModel.nodeDictionary[nodeId];
  625. if (_node.setInfo != null)
  626. {
  627. if (_node.setInfo.NodeRejectType.Value == "0")
  628. {
  629. return _runtimeModel.previousId;
  630. }
  631. else if (_node.setInfo.NodeRejectType.Value == "1")
  632. {
  633. return GetNextNodeByNodeId(_runtimeModel.startNodeId);
  634. }
  635. else if (_node.setInfo.NodeRejectType.Value == "2")
  636. {
  637. return _node.setInfo.NodeRejectStep.Value;
  638. }
  639. else
  640. {
  641. return "";
  642. }
  643. }
  644. else//前一步
  645. {
  646. return _runtimeModel.previousId;
  647. }
  648. }
  649. catch
  650. {
  651. throw;
  652. }
  653. }
  654. /// 标记节点1通过,-1不通过,0驳回
  655. /// </summary>
  656. /// <param name="nodeId"></param>
  657. /// <param name="flag"></param>
  658. /// <param name="userId"></param>
  659. /// <param name="description"></param>
  660. public void MakeTagNode(string nodeId, int flag, string userId, string description = "")
  661. {
  662. int i = 0;
  663. foreach (var item in _runtimeModel.schemeContentJson.Flow.nodes)
  664. {
  665. if (item.id.Value == nodeId)
  666. {
  667. _runtimeModel.schemeContentJson.Flow.nodes[i].setInfo.Taged = flag;
  668. _runtimeModel.schemeContentJson.Flow.nodes[i].setInfo.UserId = userId;
  669. _runtimeModel.schemeContentJson.Flow.nodes[i].setInfo.description = description;
  670. _runtimeModel.schemeContentJson.Flow.nodes[i].setInfo.TagedTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm");
  671. break;
  672. }
  673. i++;
  674. }
  675. }
  676. #endregion
  677. }
  678. }