Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

NWFEngine.cs 26 KiB

vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
vor 4 Jahren
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. using Learun.Util;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Data;
  5. using System.Linq;
  6. namespace Learun.Workflow.Engine
  7. {
  8. /// <summary>
  9. /// 版 本 Learun-ADMS V7.0.3 力软敏捷开发框架
  10. /// Copyright (c) 2013-2018 上海力软信息技术有限公司
  11. /// 创建人:力软-框架开发组
  12. /// 日 期:2018.12.10
  13. /// 描 述:工作流引擎
  14. /// </summary>
  15. public class NWFEngine : NWFIEngine
  16. {
  17. #region 构造函数
  18. public NWFEngine(NWFEngineConfig nWFEngineConfig)
  19. {
  20. // 初始化模板数据
  21. config = nWFEngineConfig;
  22. wfScheme = config.ParamConfig.Scheme.ToObject<NWFScheme>();
  23. nodesMap = new Dictionary<string, NWFNodeInfo>();
  24. foreach (var node in wfScheme.nodes)
  25. {
  26. if (!nodesMap.ContainsKey(node.id))
  27. {
  28. nodesMap.Add(node.id, node);
  29. }
  30. if (node.type == "startround")
  31. {
  32. startNode = node;
  33. }
  34. if (node.type == "endround")
  35. {
  36. endNode = node;
  37. }
  38. }
  39. }
  40. #endregion
  41. #region 模板数据信息
  42. private NWFEngineConfig config;
  43. private NWFScheme wfScheme = null;
  44. private Dictionary<string, NWFNodeInfo> nodesMap = null;
  45. private NWFNodeInfo startNode = null;
  46. private NWFNodeInfo endNode = null;
  47. #endregion
  48. #region 私有方法
  49. /// <summary>
  50. /// 计算条件
  51. /// </summary>
  52. /// <param name="node">节点信息</param>
  53. /// <returns></returns>
  54. private bool CalcCondition(NWFNodeInfo node)
  55. {
  56. bool res = true;
  57. if (node.conditions.Count > 0)
  58. {
  59. #region 字段条件判断
  60. foreach (var condition in node.conditions)
  61. {
  62. if (!string.IsNullOrEmpty(condition.dbId) && !string.IsNullOrEmpty(condition.table) && !string.IsNullOrEmpty(condition.field1) && !string.IsNullOrEmpty(condition.field2))
  63. {
  64. string sql = "select " + condition.field2 + " from " + condition.table + " where " + condition.field1 + " =@processId ";
  65. DataTable dataTable = config.DbFindTable(condition.dbId, sql, new { processId = config.ParamConfig.ProcessId });
  66. if (dataTable.Rows.Count > 0)
  67. {
  68. string value = dataTable.Rows[0][0].ToString();
  69. if (string.IsNullOrEmpty(value))
  70. {
  71. return false;
  72. }
  73. switch (condition.compareType)//比较类型1.等于2.不等于3.大于4.大于等于5.小于6.小于等于7.包含8.不包含9.包含于10.不包含于
  74. {
  75. case 1:// 等于
  76. if (value != condition.value)
  77. {
  78. res = false;
  79. }
  80. break;
  81. case 2:// 不等于
  82. if (value == condition.value)
  83. {
  84. res = false;
  85. }
  86. break;
  87. case 3:// 大于
  88. if (Convert.ToDecimal(value) <= Convert.ToDecimal(condition.value))
  89. {
  90. res = false;
  91. }
  92. break;
  93. case 4:// 大于等于
  94. if (Convert.ToDecimal(value) < Convert.ToDecimal(condition.value))
  95. {
  96. res = false;
  97. }
  98. break;
  99. case 5:// 小于
  100. if (Convert.ToDecimal(value) >= Convert.ToDecimal(condition.value))
  101. {
  102. res = false;
  103. }
  104. break;
  105. case 6:// 小于等于
  106. if (Convert.ToDecimal(value) > Convert.ToDecimal(condition.value))
  107. {
  108. res = false;
  109. }
  110. break;
  111. case 7:// 包含
  112. if (!value.Contains(condition.value))
  113. {
  114. res = false;
  115. }
  116. break;
  117. case 8:// 不包含
  118. if (value.Contains(condition.value))
  119. {
  120. res = false;
  121. }
  122. break;
  123. case 9:// 包含于
  124. if (!condition.value.Contains(value))
  125. {
  126. res = false;
  127. }
  128. break;
  129. case 10:// 不包含于
  130. if (condition.value.Contains(value))
  131. {
  132. res = false;
  133. }
  134. break;
  135. }
  136. }
  137. else
  138. {
  139. res = false;
  140. }
  141. }
  142. if (!res)
  143. {
  144. break;
  145. }
  146. }
  147. #endregion
  148. }
  149. else if (!string.IsNullOrEmpty(node.conditionSql))
  150. {
  151. // 流程进程ID
  152. string conditionSql = node.conditionSql.Replace("{processId}", "@processId");
  153. // 流程创建人用户
  154. conditionSql = conditionSql.Replace("{userId}", "@userId");
  155. conditionSql = conditionSql.Replace("{userAccount}", "@userAccount");
  156. conditionSql = conditionSql.Replace("{companyId}", "@companyId");
  157. conditionSql = conditionSql.Replace("{departmentId}", "@departmentId");
  158. var param = new
  159. {
  160. processId = config.ParamConfig.ProcessId,
  161. userId = config.ParamConfig.CreateUser.Id,
  162. userAccount = config.ParamConfig.CreateUser.Account,
  163. companyId = config.ParamConfig.CreateUser.CompanyId,
  164. departmentId = config.ParamConfig.CreateUser.DepartmentId,
  165. };
  166. DataTable dataTable = config.DbFindTable(node.dbConditionId, conditionSql, param);
  167. if (dataTable.Rows.Count > 0)
  168. {
  169. res = true;
  170. }
  171. }
  172. else
  173. {
  174. res = true;
  175. }
  176. return res;
  177. }
  178. /// <summary>
  179. /// 计算会签
  180. /// </summary>
  181. /// <param name="wfNodeInfo">节点信息</param>
  182. /// <param name="preNodeId">上一节点Id</param>
  183. /// <param name="isAgree">同意</param>
  184. /// <returns>0 不做处理 1 通过 -1 不通过</returns>
  185. private int CalcConfluence(NWFNodeInfo wfNodeInfo, string preNodeId, bool isAgree)
  186. {
  187. int res = 0;
  188. int agreeNum = config.GetAgreeNum(config.ParamConfig.ProcessId, wfNodeInfo.id);
  189. int disAgreeNum = config.GetDisAgreeNum(config.ParamConfig.ProcessId, wfNodeInfo.id);
  190. List<string> preNodeList = GetPreNodes(wfNodeInfo.id);
  191. switch (wfNodeInfo.confluenceType)//会签策略1-所有步骤通过,2-一个步骤通过即可,3-按百分比计算
  192. {
  193. case 1://所有步骤通过
  194. if (isAgree)
  195. {
  196. if (preNodeList.Count == agreeNum + 1)
  197. {
  198. res = 1;
  199. }
  200. }
  201. else
  202. {
  203. res = -1;
  204. }
  205. break;
  206. case 2:
  207. if (isAgree)
  208. {
  209. res = 1;
  210. }
  211. else if (preNodeList.Count == disAgreeNum + 1)
  212. {
  213. res = -1;
  214. }
  215. break;
  216. case 3:
  217. if (isAgree)
  218. {
  219. if ((agreeNum + 1) * 100 / preNodeList.Count >= Convert.ToDecimal(wfNodeInfo.confluenceRate))
  220. {
  221. res = 1;
  222. }
  223. }
  224. else
  225. {
  226. if ((preNodeList.Count - disAgreeNum - 1) * 100 / preNodeList.Count < Convert.ToDecimal(wfNodeInfo.confluenceRate))
  227. {
  228. res = -1;
  229. }
  230. }
  231. break;
  232. }
  233. return res;
  234. }
  235. #endregion
  236. #region 流程模板操作方法
  237. /// <summary>
  238. /// 获取流程模板
  239. /// </summary>
  240. /// <returns></returns>
  241. public string GetScheme()
  242. {
  243. return config.ParamConfig.Scheme;
  244. }
  245. /// <summary>
  246. /// 获取流程模板
  247. /// </summary>
  248. /// <returns></returns>
  249. public NWFScheme GetSchemeObj()
  250. {
  251. return wfScheme;
  252. }
  253. /// <summary>
  254. /// 获取开始节点
  255. /// </summary>
  256. /// <returns>节点信息</returns>
  257. public NWFNodeInfo GetStartNode()
  258. {
  259. return startNode;
  260. }
  261. /// <summary>
  262. /// 获取节点
  263. /// </summary>
  264. /// <param name="nodeId">流程处理节点ID</param>
  265. /// <returns>节点信息</returns>
  266. public NWFNodeInfo GetNode(string nodeId)
  267. {
  268. if (nodesMap.ContainsKey(nodeId))
  269. {
  270. return nodesMap[nodeId];
  271. }
  272. else
  273. {
  274. return null;
  275. }
  276. }
  277. /// <summary>
  278. /// 获取下一节点
  279. /// </summary>
  280. /// <param name="nodeId">当前节点Id</param>
  281. /// <param name="code">节点操作码 agree 同意 disagree 不同意 lrtimeout 超时</param>
  282. /// <returns>节点信息列表</returns>
  283. public List<NWFNodeInfo> GetNextNodes(string nodeId, string code, List<NWFLineInfo> lineList, bool overFW = false)
  284. {
  285. List<NWFNodeInfo> nextNodes = new List<NWFNodeInfo>();
  286. //如果lastNode 不为空,直接执行最后一条线的绑定方法 并终止任务
  287. List<NWFLineInfo> lineList1=new List<NWFLineInfo>();
  288. if (overFW)
  289. {
  290. lineList1.Add(wfScheme.lines.Last());
  291. }
  292. else
  293. {
  294. lineList1 = wfScheme.lines;
  295. }
  296. // 找到与当前节点相连的线条
  297. foreach (var line in lineList1)
  298. {
  299. if (line.from == nodeId)
  300. {
  301. bool isOk = false;
  302. if (string.IsNullOrEmpty(line.strategy) || line.strategy == "1")
  303. {
  304. isOk = true;
  305. }
  306. else
  307. {
  308. var codeList = line.agreeList.Split(',');
  309. foreach (string _code in codeList)
  310. {
  311. if (_code == code)
  312. {
  313. isOk = true;
  314. break;
  315. }
  316. }
  317. }
  318. if (isOk)
  319. {
  320. if (nodesMap.ContainsKey(line.to))
  321. {
  322. nextNodes.Add(nodesMap[line.to]);
  323. switch (line.operationType)
  324. {// 绑定的操作类型
  325. case "sql": // sql 语句
  326. if (!string.IsNullOrEmpty(line.dbId) && !string.IsNullOrEmpty(line.strSql))
  327. {
  328. lineList.Add(line);
  329. }
  330. break;
  331. case "interface": // interface 接口
  332. if (!string.IsNullOrEmpty(line.strInterface))
  333. {
  334. lineList.Add(line);
  335. }
  336. break;
  337. case "ioc": // 依赖注入
  338. if (!string.IsNullOrEmpty(line.iocName))
  339. {
  340. lineList.Add(line);
  341. }
  342. break;
  343. }
  344. }
  345. }
  346. }
  347. }
  348. return nextNodes;
  349. }
  350. /// <summary>
  351. /// 获取上一节点列表
  352. /// </summary>
  353. /// <param name="nodeId">当前节点Id</param>
  354. /// <returns></returns>
  355. public List<string> GetPreNodes(string nodeId)
  356. {
  357. List<string> list = new List<string>();
  358. // 找到与当前节点相连的线条
  359. foreach (var line in wfScheme.lines)
  360. {
  361. if (line.to == nodeId)
  362. {
  363. list.Add(line.from);
  364. }
  365. }
  366. return list;
  367. }
  368. /// <summary>
  369. /// 判断两节点是否连接
  370. /// </summary>
  371. /// <param name="formNodeId">开始节点</param>
  372. /// <param name="toNodeId">结束节点</param>
  373. /// <returns></returns>
  374. public bool IsToNode(string formNodeId, string toNodeId)
  375. {
  376. bool res = false;
  377. foreach (var line in wfScheme.lines)
  378. {
  379. if (line.from == formNodeId)
  380. {
  381. if (line.to == toNodeId)
  382. {
  383. res = true;
  384. break;
  385. }
  386. else
  387. {
  388. if (line.to == formNodeId || nodesMap[line.to] == null || nodesMap[line.to].type == "endround")
  389. {
  390. break;
  391. }
  392. else
  393. {
  394. if (IsToNode(line.to, toNodeId))
  395. {
  396. res = true;
  397. break;
  398. }
  399. }
  400. }
  401. }
  402. }
  403. return res;
  404. }
  405. #endregion
  406. #region 流程运行操作方法
  407. /// <summary>
  408. /// 获取配置参数信息
  409. /// </summary>
  410. /// <returns></returns>
  411. public NWFEngineParamConfig GetConfig()
  412. {
  413. return config.ParamConfig;
  414. }
  415. /// <summary>
  416. /// 获取接下来的任务节点信息
  417. /// </summary>
  418. /// <param name="beginNode">起始节点</param>
  419. /// <param name="code">节点操作码 agree 同意 disagree 不同意 lrtimeout 超时</param>
  420. /// <param name="isGetAuditors">是否获取下一节点审核人</param>
  421. /// <param name="lineList">经过的线段需要执行操作的</param>
  422. /// <returns></returns>
  423. public List<NWFNodeInfo> GetNextTaskNode(NWFNodeInfo beginNode, string code, bool isGetAuditors, List<NWFLineInfo> lineList, bool overWF = false)
  424. {
  425. List<NWFNodeInfo> list = new List<NWFNodeInfo>();
  426. List<NWFNodeInfo> nextNodeList = new List<NWFNodeInfo>();
  427. nextNodeList = GetNextNodes(beginNode.id, code, lineList, overWF);
  428. Dictionary<string, string> auditers = null;
  429. if (!string.IsNullOrEmpty(config.ParamConfig.Auditers))
  430. {
  431. auditers = config.ParamConfig.Auditers.ToObject<Dictionary<string, string>>();
  432. }
  433. foreach (var node in nextNodeList)
  434. {
  435. if (auditers != null && auditers.ContainsKey(node.id))
  436. {
  437. node.auditors = new List<NWFAuditor>();
  438. node.auditors.Add(new NWFAuditor()
  439. {
  440. type = 3,
  441. auditorId = auditers[node.id]
  442. });
  443. }
  444. switch (node.type)
  445. {
  446. case "conditionnode": // 条件节点
  447. if (!isGetAuditors)
  448. {
  449. if (CalcCondition(node))
  450. {
  451. list.AddRange(GetNextTaskNode(node, "agree", isGetAuditors, lineList));
  452. }
  453. else
  454. {
  455. list.AddRange(GetNextTaskNode(node, "disagree", isGetAuditors, lineList));
  456. }
  457. }
  458. else
  459. {
  460. list.AddRange(GetNextTaskNode(node, "agree", isGetAuditors, lineList));
  461. list.AddRange(GetNextTaskNode(node, "disagree", isGetAuditors, lineList));
  462. }
  463. break;
  464. case "confluencenode":// 会签节点
  465. if (!isGetAuditors)
  466. {
  467. int confluenceRes;
  468. if (code == "agree")
  469. {
  470. confluenceRes = CalcConfluence(node, beginNode.id, true);
  471. }
  472. else
  473. {
  474. confluenceRes = CalcConfluence(node, beginNode.id, false);
  475. }
  476. if (confluenceRes == 1)// 会签审核通过
  477. {
  478. list.AddRange(GetNextTaskNode(node, "agree", false, lineList));
  479. }
  480. else if (confluenceRes == -1)// 会签审核不通过
  481. {
  482. list.AddRange(GetNextTaskNode(node, "disagree", false, lineList));
  483. }
  484. node.confluenceRes = confluenceRes;
  485. list.Add(node);
  486. }
  487. break;
  488. case "auditornode":// 传阅节点
  489. list.Add(node);
  490. break;
  491. case "childwfnode":// 子流程节点
  492. list.Add(node);
  493. if (node.childType == "2")
  494. { // 异步的情况下直接往下走
  495. list.AddRange(GetNextTaskNode(node, "agree", isGetAuditors, lineList));
  496. }
  497. break;
  498. case "startround":// 开始节点 需要重新审核
  499. list.Add(node);
  500. config.ParamConfig.State = 1;
  501. break;
  502. case "endround":// 结束节点
  503. config.ParamConfig.State = 2;
  504. break;
  505. default: // 默认一般审核界定啊
  506. list.Add(node);
  507. break;
  508. }
  509. }
  510. return list;
  511. }
  512. /// <summary>
  513. /// 获取上一步的任务节点信息(只有审批操作码为back(退回至上一个审核节点)情况下执行)【暂定】
  514. /// </summary>
  515. /// <param name="beginNode">起始节点</param>
  516. /// <param name="code">节点操作码 agree 同意 disagree 不同意 lrtimeout 超时 back 退回至上一个审核节点</param>
  517. /// <param name="isGetAuditors">是否获取下一节点审核人</param>
  518. /// <param name="lineList">经过的线段需要执行操作的</param>
  519. /// <returns></returns>
  520. public List<NWFNodeInfo> GetPrevTaskNode(NWFNodeInfo beginNode, string code, bool isGetAuditors, List<NWFLineInfo> lineList, bool overWF = false)
  521. {
  522. List<NWFNodeInfo> list = new List<NWFNodeInfo>();
  523. List<NWFNodeInfo> nextNodeList = new List<NWFNodeInfo>();
  524. //nextNodeList = GetNextNodes(beginNode.id, code, lineList, overWF);
  525. var prevNodes = GetPreNodes(beginNode.id);
  526. foreach (var item in prevNodes)
  527. {
  528. var prevNode = GetNode(item);
  529. nextNodeList.Add(prevNode);
  530. }
  531. Dictionary<string, string> auditers = null;
  532. if (!string.IsNullOrEmpty(config.ParamConfig.Auditers))
  533. {
  534. auditers = config.ParamConfig.Auditers.ToObject<Dictionary<string, string>>();
  535. }
  536. foreach (var node in nextNodeList)
  537. {
  538. if (auditers != null && auditers.ContainsKey(node.id))
  539. {
  540. node.auditors = new List<NWFAuditor>();
  541. node.auditors.Add(new NWFAuditor()
  542. {
  543. type = 3,
  544. auditorId = auditers[node.id]
  545. });
  546. }
  547. switch (node.type)
  548. {
  549. case "conditionnode": // 条件节点
  550. if (!isGetAuditors)
  551. {
  552. if (CalcCondition(node))
  553. {
  554. list.AddRange(GetPrevTaskNode(node, "agree", isGetAuditors, lineList));
  555. }
  556. else
  557. {
  558. list.AddRange(GetPrevTaskNode(node, "disagree", isGetAuditors, lineList));
  559. }
  560. }
  561. else
  562. {
  563. list.AddRange(GetPrevTaskNode(node, "agree", isGetAuditors, lineList));
  564. list.AddRange(GetPrevTaskNode(node, "disagree", isGetAuditors, lineList));
  565. }
  566. break;
  567. case "confluencenode":// 会签节点
  568. if (!isGetAuditors)
  569. {
  570. int confluenceRes;
  571. if (code == "agree")
  572. {
  573. confluenceRes = CalcConfluence(node, beginNode.id, true);
  574. }
  575. else
  576. {
  577. confluenceRes = CalcConfluence(node, beginNode.id, false);
  578. }
  579. if (confluenceRes == 1)// 会签审核通过
  580. {
  581. list.AddRange(GetPrevTaskNode(node, "agree", false, lineList));
  582. }
  583. else if (confluenceRes == -1)// 会签审核不通过
  584. {
  585. list.AddRange(GetPrevTaskNode(node, "disagree", false, lineList));
  586. }
  587. node.confluenceRes = confluenceRes;
  588. list.Add(node);
  589. }
  590. break;
  591. case "auditornode":// 传阅节点
  592. list.Add(node);
  593. break;
  594. case "childwfnode":// 子流程节点
  595. list.Add(node);
  596. if (node.childType == "2")
  597. { // 异步的情况下直接往下走
  598. list.AddRange(GetPrevTaskNode(node, "agree", isGetAuditors, lineList));
  599. }
  600. break;
  601. case "startround":// 开始节点 需要重新审核
  602. list.Add(node);
  603. config.ParamConfig.State = 1;
  604. break;
  605. case "endround":// 结束节点
  606. config.ParamConfig.State = 2;
  607. break;
  608. default: // 默认一般审核界定啊
  609. list.Add(node);
  610. break;
  611. }
  612. }
  613. return list;
  614. }
  615. #endregion
  616. }
  617. }