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.
 
 
 
 
 
 

548 regels
21 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. //如果lastNode 不为空,直接执行最后一条线的绑定方法 并终止任务
  287. List<NWFLineInfo> lineList1 = new List<NWFLineInfo>();
  288. if (overFW)
  289. {
  290. var lastLine = wfScheme.lines.FirstOrDefault(a => !String.IsNullOrEmpty(a.iocName));
  291. if (lastLine == null)
  292. {
  293. lineList1.Add(wfScheme.lines.Last());
  294. }
  295. else
  296. {
  297. lineList1.Add(lastLine);
  298. }
  299. }
  300. else
  301. {
  302. lineList1 = wfScheme.lines;
  303. }
  304. // 找到与当前节点相连的线条
  305. foreach (var line in lineList1)
  306. {
  307. if (line.from == nodeId || overFW)
  308. {
  309. bool isOk = false;
  310. if (string.IsNullOrEmpty(line.strategy) || line.strategy == "1")
  311. {
  312. isOk = true;
  313. }
  314. else
  315. {
  316. var codeList = line.agreeList.Split(',');
  317. foreach (string _code in codeList)
  318. {
  319. if (_code == code)
  320. {
  321. isOk = true;
  322. break;
  323. }
  324. }
  325. }
  326. if (isOk)
  327. {
  328. if (nodesMap.ContainsKey(line.to))
  329. {
  330. nextNodes.Add(nodesMap[line.to]);
  331. switch (line.operationType)
  332. {// 绑定的操作类型
  333. case "sql": // sql 语句
  334. if (!string.IsNullOrEmpty(line.dbId) && !string.IsNullOrEmpty(line.strSql))
  335. {
  336. lineList.Add(line);
  337. }
  338. break;
  339. case "interface": // interface 接口
  340. if (!string.IsNullOrEmpty(line.strInterface))
  341. {
  342. lineList.Add(line);
  343. }
  344. break;
  345. case "ioc": // 依赖注入
  346. if (!string.IsNullOrEmpty(line.iocName))
  347. {
  348. lineList.Add(line);
  349. }
  350. break;
  351. }
  352. }
  353. }
  354. }
  355. }
  356. return nextNodes;
  357. }
  358. /// <summary>
  359. /// 获取上一节点列表
  360. /// </summary>
  361. /// <param name="nodeId">当前节点Id</param>
  362. /// <returns></returns>
  363. public List<string> GetPreNodes(string nodeId)
  364. {
  365. List<string> list = new List<string>();
  366. // 找到与当前节点相连的线条
  367. foreach (var line in wfScheme.lines)
  368. {
  369. if (line.to == nodeId)
  370. {
  371. list.Add(line.from);
  372. }
  373. }
  374. return list;
  375. }
  376. /// <summary>
  377. /// 判断两节点是否连接
  378. /// </summary>
  379. /// <param name="formNodeId">开始节点</param>
  380. /// <param name="toNodeId">结束节点</param>
  381. /// <returns></returns>
  382. public bool IsToNode(string formNodeId, string toNodeId)
  383. {
  384. bool res = false;
  385. foreach (var line in wfScheme.lines)
  386. {
  387. if (line.from == formNodeId)
  388. {
  389. if (line.to == toNodeId)
  390. {
  391. res = true;
  392. break;
  393. }
  394. else
  395. {
  396. if (line.to == formNodeId || nodesMap[line.to] == null || nodesMap[line.to].type == "endround")
  397. {
  398. break;
  399. }
  400. else
  401. {
  402. if (IsToNode(line.to, toNodeId))
  403. {
  404. res = true;
  405. break;
  406. }
  407. }
  408. }
  409. }
  410. }
  411. return res;
  412. }
  413. #endregion
  414. #region 流程运行操作方法
  415. /// <summary>
  416. /// 获取配置参数信息
  417. /// </summary>
  418. /// <returns></returns>
  419. public NWFEngineParamConfig GetConfig()
  420. {
  421. return config.ParamConfig;
  422. }
  423. /// <summary>
  424. /// 获取接下来的任务节点信息
  425. /// </summary>
  426. /// <param name="beginNode">起始节点</param>
  427. /// <param name="code">节点操作码 agree 同意 disagree 不同意 lrtimeout 超时</param>
  428. /// <param name="isGetAuditors">是否获取下一节点审核人</param>
  429. /// <param name="lineList">经过的线段需要执行操作的</param>
  430. /// <returns></returns>
  431. public List<NWFNodeInfo> GetNextTaskNode(NWFNodeInfo beginNode, string code, bool isGetAuditors, List<NWFLineInfo> lineList, bool overWF = false)
  432. {
  433. List<NWFNodeInfo> list = new List<NWFNodeInfo>();
  434. List<NWFNodeInfo> nextNodeList = new List<NWFNodeInfo>();
  435. nextNodeList = GetNextNodes(beginNode.id, code, lineList, overWF);
  436. Dictionary<string, string> auditers = null;
  437. if (!string.IsNullOrEmpty(config.ParamConfig.Auditers))
  438. {
  439. auditers = config.ParamConfig.Auditers.ToObject<Dictionary<string, string>>();
  440. }
  441. foreach (var node in nextNodeList)
  442. {
  443. if (auditers != null && auditers.ContainsKey(node.id))
  444. {
  445. node.auditors = new List<NWFAuditor>();
  446. node.auditors.Add(new NWFAuditor()
  447. {
  448. type = 3,
  449. auditorId = auditers[node.id]
  450. });
  451. }
  452. switch (node.type)
  453. {
  454. case "conditionnode": // 条件节点
  455. if (!isGetAuditors)
  456. {
  457. if (CalcCondition(node))
  458. {
  459. list.AddRange(GetNextTaskNode(node, "agree", isGetAuditors, lineList));
  460. }
  461. else
  462. {
  463. list.AddRange(GetNextTaskNode(node, "disagree", isGetAuditors, lineList));
  464. }
  465. }
  466. else
  467. {
  468. list.AddRange(GetNextTaskNode(node, "agree", isGetAuditors, lineList));
  469. list.AddRange(GetNextTaskNode(node, "disagree", isGetAuditors, lineList));
  470. }
  471. break;
  472. case "confluencenode":// 会签节点
  473. if (!isGetAuditors)
  474. {
  475. int confluenceRes;
  476. if (code == "agree")
  477. {
  478. confluenceRes = CalcConfluence(node, beginNode.id, true);
  479. }
  480. else
  481. {
  482. confluenceRes = CalcConfluence(node, beginNode.id, false);
  483. }
  484. if (confluenceRes == 1)// 会签审核通过
  485. {
  486. list.AddRange(GetNextTaskNode(node, "agree", false, lineList));
  487. }
  488. else if (confluenceRes == -1)// 会签审核不通过
  489. {
  490. list.AddRange(GetNextTaskNode(node, "disagree", false, lineList));
  491. }
  492. node.confluenceRes = confluenceRes;
  493. list.Add(node);
  494. }
  495. break;
  496. case "auditornode":// 传阅节点
  497. list.Add(node);
  498. break;
  499. case "childwfnode":// 子流程节点
  500. list.Add(node);
  501. if (node.childType == "2")
  502. { // 异步的情况下直接往下走
  503. list.AddRange(GetNextTaskNode(node, "agree", isGetAuditors, lineList));
  504. }
  505. break;
  506. case "startround":// 开始节点 需要重新审核
  507. list.Add(node);
  508. config.ParamConfig.State = 1;
  509. break;
  510. case "endround":// 结束节点
  511. config.ParamConfig.State = 2;
  512. break;
  513. default: // 默认一般审核界定啊
  514. list.Add(node);
  515. break;
  516. }
  517. }
  518. return list;
  519. }
  520. #endregion
  521. }
  522. }