You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

662 regels
26 KiB

  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. // 找到与当前节点相连的线条
  287. NWFLineInfo line = null;
  288. //如果lastNode 不为空,直接执行最后一条线的绑定方法 并终止任务
  289. if (overFW)
  290. {
  291. line = wfScheme.lines.Last();
  292. }
  293. else
  294. {
  295. List<NWFLineInfo> listLine = new List<NWFLineInfo>();
  296. listLine = wfScheme.lines.Where(a => a.from == nodeId).ToList();
  297. if (listLine.Count > 1)
  298. {
  299. line = wfScheme.lines.FirstOrDefault(a => a.from == nodeId && a.agreeList == code);
  300. }
  301. else
  302. {
  303. line = listLine.FirstOrDefault();
  304. }
  305. }
  306. bool isOk = false;
  307. if (string.IsNullOrEmpty(line.strategy) || line.strategy == "1")
  308. {
  309. isOk = true;
  310. }
  311. else
  312. {
  313. var codeList = line.agreeList.Split(',');
  314. foreach (string _code in codeList)
  315. {
  316. if (_code == code)
  317. {
  318. isOk = true;
  319. break;
  320. }
  321. }
  322. }
  323. if (isOk)
  324. {
  325. if (nodesMap.ContainsKey(line.to))
  326. {
  327. //如果lastNode 不为空,直接执行最后一条线的绑定方法 并终止任务
  328. if (overFW)
  329. {
  330. nextNodes.Add(endNode);
  331. }
  332. else
  333. {
  334. nextNodes.Add(nodesMap[line.to]);
  335. }
  336. switch (line.operationType)
  337. {// 绑定的操作类型
  338. case "sql": // sql 语句
  339. if (!string.IsNullOrEmpty(line.dbId) && !string.IsNullOrEmpty(line.strSql))
  340. {
  341. lineList.Add(line);
  342. }
  343. break;
  344. case "interface": // interface 接口
  345. if (!string.IsNullOrEmpty(line.strInterface))
  346. {
  347. lineList.Add(line);
  348. }
  349. break;
  350. case "ioc": // 依赖注入
  351. if (!string.IsNullOrEmpty(line.iocName))
  352. {
  353. lineList.Add(line);
  354. }
  355. break;
  356. }
  357. }
  358. }
  359. return nextNodes;
  360. }
  361. /// <summary>
  362. /// 获取上一节点列表
  363. /// </summary>
  364. /// <param name="nodeId">当前节点Id</param>
  365. /// <returns></returns>
  366. public List<string> GetPreNodes(string nodeId)
  367. {
  368. List<string> list = new List<string>();
  369. // 找到与当前节点相连的线条
  370. foreach (var line in wfScheme.lines)
  371. {
  372. if (line.to == nodeId)
  373. {
  374. list.Add(line.from);
  375. }
  376. }
  377. return list;
  378. }
  379. /// <summary>
  380. /// 判断两节点是否连接
  381. /// </summary>
  382. /// <param name="formNodeId">开始节点</param>
  383. /// <param name="toNodeId">结束节点</param>
  384. /// <returns></returns>
  385. public bool IsToNode(string formNodeId, string toNodeId)
  386. {
  387. bool res = false;
  388. foreach (var line in wfScheme.lines)
  389. {
  390. if (line.from == formNodeId)
  391. {
  392. if (line.to == toNodeId)
  393. {
  394. res = true;
  395. break;
  396. }
  397. else
  398. {
  399. if (line.to == formNodeId || nodesMap[line.to] == null || nodesMap[line.to].type == "endround")
  400. {
  401. break;
  402. }
  403. else
  404. {
  405. if (IsToNode(line.to, toNodeId))
  406. {
  407. res = true;
  408. break;
  409. }
  410. }
  411. }
  412. }
  413. }
  414. return res;
  415. }
  416. #endregion
  417. #region 流程运行操作方法
  418. /// <summary>
  419. /// 获取配置参数信息
  420. /// </summary>
  421. /// <returns></returns>
  422. public NWFEngineParamConfig GetConfig()
  423. {
  424. return config.ParamConfig;
  425. }
  426. /// <summary>
  427. /// 获取接下来的任务节点信息
  428. /// </summary>
  429. /// <param name="beginNode">起始节点</param>
  430. /// <param name="code">节点操作码 agree 同意 disagree 不同意 lrtimeout 超时</param>
  431. /// <param name="isGetAuditors">是否获取下一节点审核人</param>
  432. /// <param name="lineList">经过的线段需要执行操作的</param>
  433. /// <returns></returns>
  434. public List<NWFNodeInfo> GetNextTaskNode(NWFNodeInfo beginNode, string code, bool isGetAuditors, List<NWFLineInfo> lineList, bool overWF = false)
  435. {
  436. List<NWFNodeInfo> list = new List<NWFNodeInfo>();
  437. List<NWFNodeInfo> nextNodeList = new List<NWFNodeInfo>();
  438. nextNodeList = GetNextNodes(beginNode.id, code, lineList, overWF);
  439. Dictionary<string, string> auditers = null;
  440. if (!string.IsNullOrEmpty(config.ParamConfig.Auditers))
  441. {
  442. auditers = config.ParamConfig.Auditers.ToObject<Dictionary<string, string>>();
  443. }
  444. foreach (var node in nextNodeList)
  445. {
  446. if (auditers != null && auditers.ContainsKey(node.id))
  447. {
  448. node.auditors = new List<NWFAuditor>();
  449. node.auditors.Add(new NWFAuditor()
  450. {
  451. type = 3,
  452. auditorId = auditers[node.id]
  453. });
  454. }
  455. switch (node.type)
  456. {
  457. case "conditionnode": // 条件节点
  458. if (!isGetAuditors)
  459. {
  460. if (CalcCondition(node))
  461. {
  462. list.AddRange(GetNextTaskNode(node, "agree", isGetAuditors, lineList));
  463. }
  464. else
  465. {
  466. list.AddRange(GetNextTaskNode(node, "disagree", isGetAuditors, lineList));
  467. }
  468. }
  469. else
  470. {
  471. list.AddRange(GetNextTaskNode(node, "agree", isGetAuditors, lineList));
  472. list.AddRange(GetNextTaskNode(node, "disagree", isGetAuditors, lineList));
  473. }
  474. break;
  475. case "confluencenode":// 会签节点
  476. if (!isGetAuditors)
  477. {
  478. int confluenceRes;
  479. if (code == "agree")
  480. {
  481. confluenceRes = CalcConfluence(node, beginNode.id, true);
  482. }
  483. else
  484. {
  485. confluenceRes = CalcConfluence(node, beginNode.id, false);
  486. }
  487. if (confluenceRes == 1)// 会签审核通过
  488. {
  489. list.AddRange(GetNextTaskNode(node, "agree", false, lineList));
  490. }
  491. else if (confluenceRes == -1)// 会签审核不通过
  492. {
  493. list.AddRange(GetNextTaskNode(node, "disagree", false, lineList));
  494. }
  495. node.confluenceRes = confluenceRes;
  496. list.Add(node);
  497. }
  498. break;
  499. case "auditornode":// 传阅节点
  500. list.Add(node);
  501. break;
  502. case "childwfnode":// 子流程节点
  503. list.Add(node);
  504. if (node.childType == "2")
  505. { // 异步的情况下直接往下走
  506. list.AddRange(GetNextTaskNode(node, "agree", isGetAuditors, lineList));
  507. }
  508. break;
  509. case "startround":// 开始节点 需要重新审核
  510. list.Add(node);
  511. config.ParamConfig.State = 1;
  512. break;
  513. case "endround":// 结束节点
  514. config.ParamConfig.State = 2;
  515. break;
  516. default: // 默认一般审核界定啊
  517. list.Add(node);
  518. break;
  519. }
  520. }
  521. return list;
  522. }
  523. /// <summary>
  524. /// 获取上一步的任务节点信息(只有审批操作码为back(退回至上一个审核节点)情况下执行)【暂定】
  525. /// </summary>
  526. /// <param name="beginNode">起始节点</param>
  527. /// <param name="code">节点操作码 agree 同意 disagree 不同意 lrtimeout 超时 back 退回至上一个审核节点</param>
  528. /// <param name="isGetAuditors">是否获取下一节点审核人</param>
  529. /// <param name="lineList">经过的线段需要执行操作的</param>
  530. /// <returns></returns>
  531. public List<NWFNodeInfo> GetPrevTaskNode(NWFNodeInfo beginNode, string code, bool isGetAuditors, List<NWFLineInfo> lineList, bool overWF = false)
  532. {
  533. List<NWFNodeInfo> list = new List<NWFNodeInfo>();
  534. List<NWFNodeInfo> nextNodeList = new List<NWFNodeInfo>();
  535. //nextNodeList = GetNextNodes(beginNode.id, code, lineList, overWF);
  536. var prevNodes = GetPreNodes(beginNode.id);
  537. foreach (var item in prevNodes)
  538. {
  539. var prevNode = GetNode(item);
  540. nextNodeList.Add(prevNode);
  541. }
  542. Dictionary<string, string> auditers = null;
  543. if (!string.IsNullOrEmpty(config.ParamConfig.Auditers))
  544. {
  545. auditers = config.ParamConfig.Auditers.ToObject<Dictionary<string, string>>();
  546. }
  547. foreach (var node in nextNodeList)
  548. {
  549. if (auditers != null && auditers.ContainsKey(node.id))
  550. {
  551. node.auditors = new List<NWFAuditor>();
  552. node.auditors.Add(new NWFAuditor()
  553. {
  554. type = 3,
  555. auditorId = auditers[node.id]
  556. });
  557. }
  558. switch (node.type)
  559. {
  560. case "conditionnode": // 条件节点
  561. if (!isGetAuditors)
  562. {
  563. if (CalcCondition(node))
  564. {
  565. list.AddRange(GetPrevTaskNode(node, "agree", isGetAuditors, lineList));
  566. }
  567. else
  568. {
  569. list.AddRange(GetPrevTaskNode(node, "disagree", isGetAuditors, lineList));
  570. }
  571. }
  572. else
  573. {
  574. list.AddRange(GetPrevTaskNode(node, "agree", isGetAuditors, lineList));
  575. list.AddRange(GetPrevTaskNode(node, "disagree", isGetAuditors, lineList));
  576. }
  577. break;
  578. case "confluencenode":// 会签节点
  579. if (!isGetAuditors)
  580. {
  581. int confluenceRes;
  582. if (code == "agree")
  583. {
  584. confluenceRes = CalcConfluence(node, beginNode.id, true);
  585. }
  586. else
  587. {
  588. confluenceRes = CalcConfluence(node, beginNode.id, false);
  589. }
  590. if (confluenceRes == 1)// 会签审核通过
  591. {
  592. list.AddRange(GetPrevTaskNode(node, "agree", false, lineList));
  593. }
  594. else if (confluenceRes == -1)// 会签审核不通过
  595. {
  596. list.AddRange(GetPrevTaskNode(node, "disagree", false, lineList));
  597. }
  598. node.confluenceRes = confluenceRes;
  599. list.Add(node);
  600. }
  601. break;
  602. case "auditornode":// 传阅节点
  603. list.Add(node);
  604. break;
  605. case "childwfnode":// 子流程节点
  606. list.Add(node);
  607. if (node.childType == "2")
  608. { // 异步的情况下直接往下走
  609. list.AddRange(GetPrevTaskNode(node, "agree", isGetAuditors, lineList));
  610. }
  611. break;
  612. case "startround":// 开始节点 需要重新审核
  613. list.Add(node);
  614. config.ParamConfig.State = 1;
  615. break;
  616. case "endround":// 结束节点
  617. config.ParamConfig.State = 2;
  618. break;
  619. default: // 默认一般审核界定啊
  620. list.Add(node);
  621. break;
  622. }
  623. }
  624. return list;
  625. }
  626. #endregion
  627. }
  628. }