選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

NWFEngine.cs 26 KiB

4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
4年前
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. }