using learun.util; using System; using System.Collections.Generic; using System.Data; using System.Threading.Tasks; namespace learun.workflow { /// /// 版 本 EasyCode EC管理后台 /// Copyright (c) 2019-present EC管理有限公司 /// 创建人:tobin /// 日 期:2019.11.22 /// 描 述:工作流引擎 /// public class NWFEngine : NWFIEngine { #region 构造函数 /// /// /// /// public NWFEngine(NWFEngineConfig nWFEngineConfig) { // 初始化模板数据 config = nWFEngineConfig; wfScheme = config.ParamConfig.Scheme.ToObject(); nodesMap = new Dictionary(); foreach (var node in wfScheme.nodes) { if (!nodesMap.ContainsKey(node.id)) { nodesMap.Add(node.id, node); } if (node.type == "startround") { startNode = node; } } } #endregion 构造函数 #region 模板数据信息 private NWFEngineConfig config; private NWFScheme wfScheme = null; private Dictionary nodesMap = null; private NWFNodeInfo startNode = null; #endregion 模板数据信息 #region 私有方法 /// /// 计算条件 /// /// 节点信息 /// private async Task CalcCondition(NWFNodeInfo node) { bool res = true; if (node.conditions.Count > 0) { #region 字段条件判断 foreach (var condition in node.conditions) { if (!string.IsNullOrEmpty(condition.dbId) && !string.IsNullOrEmpty(condition.table) && !string.IsNullOrEmpty(condition.field1) && !string.IsNullOrEmpty(condition.field2)) { string sql = "select " + condition.field2 + " from " + condition.table + " where " + condition.field1 + " =@processId "; DataTable dataTable = await config.DbFindTable(condition.dbId, sql, new { processId = config.ParamConfig.ProcessId }); if (dataTable.Rows.Count > 0) { string value = dataTable.Rows[0][0].ToString(); if (string.IsNullOrEmpty(value)) { return false; } switch (condition.compareType)//比较类型1.等于2.不等于3.大于4.大于等于5.小于6.小于等于7.包含8.不包含9.包含于10.不包含于 { case 1:// 等于 if (value != condition.value) { res = false; } break; case 2:// 不等于 if (value == condition.value) { res = false; } break; case 3:// 大于 if (Convert.ToDecimal(value) <= Convert.ToDecimal(condition.value)) { res = false; } break; case 4:// 大于等于 if (Convert.ToDecimal(value) < Convert.ToDecimal(condition.value)) { res = false; } break; case 5:// 小于 if (Convert.ToDecimal(value) >= Convert.ToDecimal(condition.value)) { res = false; } break; case 6:// 小于等于 if (Convert.ToDecimal(value) > Convert.ToDecimal(condition.value)) { res = false; } break; case 7:// 包含 if (!value.Contains(condition.value)) { res = false; } break; case 8:// 不包含 if (value.Contains(condition.value)) { res = false; } break; case 9:// 包含于 if (!condition.value.Contains(value)) { res = false; } break; case 10:// 不包含于 if (condition.value.Contains(value)) { res = false; } break; } } else { res = false; } } if (!res) { break; } } #endregion 字段条件判断 } else if (!string.IsNullOrEmpty(node.conditionSql)) { res = false; // 流程进程ID string conditionSql = node.conditionSql.Replace("{processId}", "@processId"); // 流程创建人用户 conditionSql = conditionSql.Replace("{userId}", "@userId"); conditionSql = conditionSql.Replace("{userAccount}", "@userAccount"); conditionSql = conditionSql.Replace("{companyId}", "@companyId"); conditionSql = conditionSql.Replace("{departmentId}", "@departmentId"); var param = new { processId = config.ParamConfig.ProcessId, userId = config.ParamConfig.CreateUser.Id, userAccount = config.ParamConfig.CreateUser.Account, companyId = config.ParamConfig.CreateUser.CompanyId, departmentId = config.ParamConfig.CreateUser.DepartmentId, }; DataTable dataTable = await config.DbFindTable(node.dbConditionId, conditionSql, param); if (dataTable.Rows.Count > 0) { res = true; } } else { res = true; } return res; } /// /// 计算会签 /// /// 节点信息 /// 上一节点Id /// 同意 /// 0 不做处理 1 通过 -1 不通过 private async Task CalcConfluence(NWFNodeInfo wfNodeInfo, string preNodeId, bool isAgree) { int res = 0; int agreeNum = await config.GetAgreeNum(config.ParamConfig.ProcessId, wfNodeInfo.id); int disAgreeNum = await config.GetDisAgreeNum(config.ParamConfig.ProcessId, wfNodeInfo.id); List preNodeList = GetPreNodes(wfNodeInfo.id); switch (wfNodeInfo.confluenceType)//会签策略1-所有步骤通过,2-一个步骤通过即可,3-按百分比计算 { case 1://所有步骤通过 if (isAgree) { if (preNodeList.Count == agreeNum + 1) { res = 1; } } else { res = -1; } break; case 2: if (isAgree) { res = 1; } else if (preNodeList.Count == disAgreeNum + 1) { res = -1; } break; case 3: if (isAgree) { if ((agreeNum + 1) * 100 / preNodeList.Count >= Convert.ToDecimal(wfNodeInfo.confluenceRate)) { res = 1; } } else { if ((preNodeList.Count - disAgreeNum - 1) * 100 / preNodeList.Count < Convert.ToDecimal(wfNodeInfo.confluenceRate)) { res = -1; } } break; } return res; } #endregion 私有方法 #region 流程模板操作方法 /// /// 获取流程模板 /// /// public string GetScheme() { return config.ParamConfig.Scheme; } /// /// 获取流程模板 /// /// public NWFScheme GetSchemeObj() { return wfScheme; } /// /// 获取开始节点 /// /// 节点信息 public NWFNodeInfo GetStartNode() { return startNode; } /// /// 获取节点 /// /// 流程处理节点ID /// 节点信息 public NWFNodeInfo GetNode(string nodeId) { if (nodesMap.ContainsKey(nodeId)) { return nodesMap[nodeId]; } else { return null; } } /// /// 获取两节点间的线条 /// /// 开始节点 /// 结束节点 /// 线条列表 /// public bool GetLines(string fromNodeId, string toNodeId, List list, Dictionary nodes = null) { bool res = false; if (nodes == null) { nodes = new Dictionary(); } foreach (var line in wfScheme.lines) { if (line.from == fromNodeId) { if (line.to == toNodeId) { list.Add(line); return true; } else { if (line.to == fromNodeId || nodesMap[line.to] == null || nodesMap[line.to].type == "endround") { } else if (!nodes.ContainsKey(line.to)) { nodes.Add(line.to, "1"); res = GetLines(line.to, toNodeId, list, nodes); } } if (res) { list.Add(line); return true; } } } return res; } /// /// 获取下一节点 /// /// 当前节点Id /// 节点操作码 agree 同意 disagree 不同意 lrtimeout 超时 /// /// 节点信息列表 public List GetNextNodes(string nodeId, string code, List lineList) { List nextNodes = new List(); // 找到与当前节点相连的线条 foreach (var line in wfScheme.lines) { if (line.from == nodeId) { bool isOk = false; if (string.IsNullOrEmpty(line.strategy) || line.strategy == "1") { isOk = true; } else { var codeList = line.agreeList.Split(','); foreach (string _code in codeList) { if (_code == code) { isOk = true; break; } } } if (isOk) { if (nodesMap.ContainsKey(line.to)) { nextNodes.Add(nodesMap[line.to]); switch (line.operationType) {// 绑定的操作类型 case "sql": // sql 语句 if (!string.IsNullOrEmpty(line.dbId) && !string.IsNullOrEmpty(line.strSql)) { lineList.Add(line); } break; case "interface": // interface 接口 if (!string.IsNullOrEmpty(line.strInterface)) { lineList.Add(line); } break; case "ioc": // 依赖注入 if (!string.IsNullOrEmpty(line.iocName)) { lineList.Add(line); } break; } } } } } return nextNodes; } /// /// 获取上一节点列表 /// /// 当前节点Id /// public List GetPreNodes(string nodeId) { List list = new List(); // 找到与当前节点相连的线条 foreach (var line in wfScheme.lines) { if (line.to == nodeId) { list.Add(line.from); } } return list; } /// /// 判断两节点是否连接 /// /// 开始节点 /// 结束节点 /// public bool IsToNode(string formNodeId, string toNodeId) { bool res = false; foreach (var line in wfScheme.lines) { if (line.from == formNodeId) { if (line.to == toNodeId) { res = true; break; } else { if (line.to == formNodeId || nodesMap[line.to] == null || nodesMap[line.to].type == "endround") { break; } else { if (IsToNode(line.to, toNodeId)) { res = true; break; } } } } } return res; } #endregion 流程模板操作方法 #region 流程运行操作方法 /// /// 获取配置参数信息 /// /// public NWFEngineParamConfig GetConfig() { return config.ParamConfig; } /// /// 获取接下来的任务节点信息 /// /// 起始节点 /// 节点操作码 agree 同意 disagree 不同意 lrtimeout 超时 /// 是否获取下一节点审核人 /// 经过的线段需要执行操作的 /// public async Task> GetNextTaskNode(NWFNodeInfo beginNode, string code, bool isGetAuditors, List lineList) { List list = new List(); List nextNodeList = GetNextNodes(beginNode.id, code, lineList); Dictionary auditers = null; if (!string.IsNullOrEmpty(config.ParamConfig.Auditers)) { auditers = config.ParamConfig.Auditers.ToObject>(); } foreach (var node in nextNodeList) { if (auditers != null && auditers.ContainsKey(node.id)) { node.auditors = new List(); node.auditors.Add(new NWFAuditor() { type = 3, auditorId = auditers[node.id] }); } switch (node.type) { case "conditionnode": // 条件节点 if (!isGetAuditors) { if (await CalcCondition(node)) { list.AddRange(await GetNextTaskNode(node, "agree", isGetAuditors, lineList)); } else { list.AddRange(await GetNextTaskNode(node, "disagree", isGetAuditors, lineList)); } } else { list.AddRange(await GetNextTaskNode(node, "agree", isGetAuditors, lineList)); list.AddRange(await GetNextTaskNode(node, "disagree", isGetAuditors, lineList)); } break; case "confluencenode":// 会签节点 if (!isGetAuditors) { int confluenceRes; if (code == "agree") { confluenceRes = await CalcConfluence(node, beginNode.id, true); } else { confluenceRes = await CalcConfluence(node, beginNode.id, false); } if (confluenceRes == 1)// 会签审核通过 { list.AddRange(await GetNextTaskNode(node, "agree", false, lineList)); } else if (confluenceRes == -1)// 会签审核不通过 { list.AddRange(await GetNextTaskNode(node, "disagree", false, lineList)); } node.confluenceRes = confluenceRes; list.Add(node); } break; case "auditornode":// 传阅节点 list.Add(node); break; case "childwfnode":// 子流程节点 list.Add(node); if (node.childType == "2") { // 异步的情况下直接往下走 list.AddRange(await GetNextTaskNode(node, "agree", isGetAuditors, lineList)); } break; case "startround":// 开始节点 需要重新审核 list.Add(node); config.ParamConfig.State = 1; break; case "endround":// 结束节点 config.ParamConfig.State = 2; break; default: // 默认一般审核界定啊 list.Add(node); break; } } return list; } #endregion 流程运行操作方法 } }