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

497 行
20 KiB

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