using Infrastructure; using Newtonsoft.Json.Linq; using OpenAuth.Repository.Domain; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Text; using Castle.Core.Internal; using Infrastructure.Const; using Infrastructure.Extensions; using Infrastructure.Extensions.AutofacManager; using Infrastructure.Helpers; using OpenAuth.App.Interface; using OpenAuth.App.Request; using SqlSugar; using Microsoft.Extensions.Configuration; namespace OpenAuth.App.Flow { /// /// 一个正在运行中的流程实例 /// 该类只能通过new实例化,禁止通过容器获取 /// public class FlowRuntime { public FlowRuntime(FlowInstance instance) { flowInstance = instance; dynamic schemeContentJson = instance.SchemeContent.ToJson(); //获取工作流模板内容的json对象; InitLines(schemeContentJson); InitNodes(schemeContentJson); currentNodeId = instance.ActivityId == "" ? startNodeId : instance.ActivityId; FrmData = instance.FrmData; title = schemeContentJson.title; initNum = schemeContentJson.initNum ?? 0; previousId = instance.PreviousId; flowInstanceId = instance.Id; //网关开始节点和流程结束节点没有下一步 if (GetCurrentNodeType() == Define.NODE_TYPE_FORK || GetCurrentNodeType() == Define.NODE_TYPE_END) { nextNodeId = "-1"; } else { nextNodeId = GetNextNodeId(); //下一个节点 } } #region 私有方法 /// /// 获取工作流节点的字典列表:key节点id /// /// /// private void InitNodes(dynamic schemeContentJson) { Nodes = new Dictionary(); foreach (JObject item in schemeContentJson.nodes) { var node = item.ToObject(); if (!Nodes.ContainsKey(node.id)) { Nodes.Add(node.id, node); } if (node.type == Define.NODE_TYPE_START) { this.startNodeId = node.id; } } } private void InitLines(dynamic schemeContentJson) { Lines = new List(); FromNodeLines = new Dictionary>(); ToNodeLines = new Dictionary>(); foreach (JObject item in schemeContentJson.lines) { var line = item.ToObject(); Lines.Add(line); if (!FromNodeLines.ContainsKey(line.from)) { List d = new List { line }; FromNodeLines.Add(line.from, d); } else { FromNodeLines[line.from].Add(line); } if (!ToNodeLines.ContainsKey(line.to)) { List d = new List { line }; ToNodeLines.Add(line.to, d); } else { ToNodeLines[line.to].Add(line); } } } /// /// 获取下一个节点 /// private string GetNextNodeId(string nodeId = null) { var lines = nodeId == null ? FromNodeLines[currentNodeId] : FromNodeLines[nodeId]; if (lines.Count == 0) { throw new Exception("无法寻找到下一个节点"); } //URL表单暂时不支持URL表单 if(flowInstance.FrmType == Define.FORM_TYPE_URL) return lines[0].to; if (FrmData == "" || FrmData == "{}") return lines[0].to; FrmData = FrmData.ToLower(); //统一转小写 var frmDataJson = FrmData.ToJObject(); //获取数据内容 foreach (var l in lines) { if (!l.Compares.IsNullOrEmpty() && l.Compare(frmDataJson)) { return l.to; } } return lines[0].to; } #endregion 私有方法 #region 共有方法 /// /// 判断流程是否完成 /// public bool IsFinish() { return GetNextNodeType() == Define.NODE_TYPE_END; } //获取下一个节点 public FlowNode GetNextNode(string nodeId = null) { return Nodes[GetNextNodeId(nodeId)]; } /// /// 获取实例接下来运行的节点类型 /// public string GetNextNodeType() { if (nextNodeId != "-1") { return GetNodeType(nextNodeId); } return Define.NODE_TYPE_END; } /// /// 获取节点类型 /// /// /// public string GetNodeType(string nodeId) { return Nodes[nodeId].type; } /// /// 获取当前节点类型 /// /// public string GetCurrentNodeType() { return GetNodeType(currentNodeId); } /// /// 审批网关开始节点 /// /// currentNodeId是网关开始节点。这个表示当前正在处理的节点 /// /// -1不通过,1等待,其它通过 public string VerifyGatewayStart(HttpClient httpClient, Tag tag) { var user = AutofacContainerModule.GetService().GetCurrentUser().User; //审批网关时的【当前节点】一直是网关开始节点 //TODO: 标记网关节点的状态,这个地方感觉怪怪的 MakeTagNode(currentNodeId, tag); string canCheckId = ""; //寻找当前登录用户可审核的节点Id foreach (string fromForkStartNodeId in FromNodeLines[currentNodeId] .Select(u => u.to)) { var fromForkStartNode = Nodes[fromForkStartNodeId]; //与网关开始节点直接连接的节点 canCheckId = GetOneForkLineCanCheckNodeId(fromForkStartNode, tag); if (!string.IsNullOrEmpty(canCheckId)) break; } if (canCheckId == "") { throw new Exception("审核异常,找不到审核节点"); } var content = $"{user.Account}-{DateTime.Now:yyyy-MM-dd HH:mm}审批了【{Nodes[canCheckId].name}】" + $"结果:{(tag.Taged == 1 ? "同意" : "不同意")},备注:{tag.Description}"; SaveOperationHis(content); MakeTagNode(canCheckId, tag); //标记审核节点状态 var forkNode = Nodes[currentNodeId]; //网关开始节点 FlowNode nextNode = GetNextNode(canCheckId); //获取当前处理的下一个节点 int forkNumber = FromNodeLines[currentNodeId].Count; //直接与网关节点连接的点,即网关分支数目 string gatewayResult = string.Empty; //记录网关审批的的结果,为空表示仍然在网关内部处理 if (forkNode.setInfo.NodeConfluenceType == "one") //有一个步骤通过即可 { if (tag.Taged == (int)TagState.Ok) { if (nextNode.type == Define.NODE_TYPE_JOIN) //下一个节点是网关结束,则该线路结束 { gatewayResult = GetNextNodeId(nextNode.id); } } else if (tag.Taged == (int)TagState.No) { if (forkNode.setInfo.ConfluenceNo == null) { forkNode.setInfo.ConfluenceNo = 1; } else if (forkNode.setInfo.ConfluenceNo == (forkNumber - 1)) { gatewayResult = TagState.No.ToString("D"); } else { bool isFirst = true; //是不是从网关开始到现在第一个 var preNode = GetPreNode(canCheckId); while (preNode.id != forkNode.id) //反向一直到网关开始节点 { if (preNode.setInfo != null && preNode.setInfo.Taged == (int)TagState.No) { isFirst = false; break; } } if (isFirst) { forkNode.setInfo.ConfluenceNo++; } } } } else //所有步骤通过 { if (tag.Taged == (int)TagState.No) //只要有一个不同意,那么流程就结束 { gatewayResult = TagState.No.ToString("D"); } else if (tag.Taged == (int)TagState.Ok) { if (nextNode.type == Define.NODE_TYPE_JOIN) //这种模式下只有坚持到【网关结束】节点之前才有意义,是否需要判定这条线所有的节点都通过,不然直接执行这个节点?? { if (forkNode.setInfo.ConfluenceOk == null) { forkNode.setInfo.ConfluenceOk = 1; } else if (forkNode.setInfo.ConfluenceOk == (forkNumber - 1)) //网关成功 { gatewayResult = GetNextNodeId(nextNode.id); } else { forkNode.setInfo.ConfluenceOk++; } } } } if (gatewayResult == TagState.No.ToString("D")) { tag.Taged = (int)TagState.No; MakeTagNode(nextNode.id, tag); } else if (!string.IsNullOrEmpty(gatewayResult)) //网关结束,标记合流节点 { tag.Taged = (int)TagState.Ok; MakeTagNode(nextNode.id, tag); nextNodeId = gatewayResult; } else { nextNodeId = nextNode.id; } if (!string.IsNullOrEmpty(gatewayResult)) //网关结束节点配置了回调,则发起通知 { NotifyThirdParty(httpClient, nextNode, tag); } return gatewayResult; } //获取上一个节点 private FlowNode GetPreNode(string nodeId = null) { var lines = nodeId == null ? ToNodeLines[currentNodeId] : ToNodeLines[nodeId]; if (lines.Count == 0) { throw new Exception("无法找到上一个点"); } return Nodes[lines[0].from]; } /// /// 驳回 /// /// public void RejectNode(HttpClient client, VerificationReq reqest) { //默认驳回到指定节点 string rejectNode = reqest.NodeRejectStep; //如果不是指定到节点 if (string.IsNullOrEmpty(rejectNode)) { string rejectType = reqest.NodeRejectType; dynamic node = Nodes[currentNodeId]; if (node.setInfo != null && string.IsNullOrEmpty(reqest.NodeRejectType)) { rejectType = node.setInfo.NodeRejectType; } if (rejectType == "0") //前一步 { rejectNode = previousId; } if (rejectType == "1") //第一步 { rejectNode = GetNextNodeId(startNodeId); } } var user = AutofacContainerModule.GetService().GetCurrentUser().User; var tag = new Tag { Description = reqest.VerificationOpinion, Taged = (int)TagState.Reject, UserId = user.Id, UserName = user.Name }; MakeTagNode(currentNodeId, tag); flowInstance.IsFinish = FlowInstanceStatus.Rejected; //4表示驳回(需要申请者重新提交表单) if (rejectNode != "") { flowInstance.PreviousId = flowInstance.ActivityId; flowInstance.ActivityId = rejectNode; flowInstance.ActivityName = Nodes[rejectNode].name; flowInstance.MakerList = GetNodeMarkers(Nodes[rejectNode], flowInstance.CreateUserId); SaveTransitionHis(); } flowInstance.SchemeContent = JsonHelper.Instance.Serialize(ToSchemeObj()); var sugarClient = AutofacContainerModule.GetService(); sugarClient.Updateable(flowInstance).ExecuteCommand(); SaveOperationHis( $"{user.Account}-{DateTime.Now.ToString("yyyy-MM-dd HH:mm")}驳回了【{currentNode.name}】"); NotifyThirdParty(client, currentNode, tag); } /// /// 撤销流程,清空所有节点 /// public void ReCall(RecallFlowInstanceReq request) { foreach (var item in Nodes) { item.Value.setInfo = null; } flowInstance.IsFinish = FlowInstanceStatus.Draft; flowInstance.PreviousId = flowInstance.ActivityId; flowInstance.ActivityId = startNodeId; flowInstance.ActivityName = Nodes[startNodeId].name; flowInstance.MakerList = GetNodeMarkers(Nodes[startNodeId], flowInstance.CreateUserId); SaveTransitionHis(); var sugarClient = AutofacContainerModule.GetService(); sugarClient.Updateable(flowInstance).ExecuteCommand(); SaveOperationHis($"【撤回】备注:{request.Description}"); sugarClient.Ado.CommitTran(); } /// /// 标记节点1通过,-1不通过,0驳回 /// /// public void MakeTagNode(string nodeId, Tag tag) { foreach (var item in Nodes) { if (item.Key == nodeId) { if (item.Value.setInfo == null) { item.Value.setInfo = new Setinfo(); } item.Value.setInfo.Taged = tag.Taged; item.Value.setInfo.UserId = tag.UserId; item.Value.setInfo.UserName = tag.UserName; item.Value.setInfo.Description = tag.Description; item.Value.setInfo.TagedTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm"); break; } } } public object ToSchemeObj() { return new { title = this.title, initNum = this.initNum, lines = Lines, nodes = Nodes.Select(u => u.Value), areas = new string[0] }; } public void SaveOperationHis(string userId, string userName, string opHis) { FlowInstanceOperationHistory flowInstanceOperationHistory = new FlowInstanceOperationHistory { InstanceId = flowInstanceId, CreateUserId = userId, CreateUserName = userName, CreateDate = DateTime.Now, Content = opHis }; //操作记录 var SugarClient = AutofacContainerModule.GetService(); SugarClient.Insertable(flowInstanceOperationHistory).ExecuteCommand(); } /// /// 添加工作流实例操作记录 /// 操作人为当前的登录用户 /// /// public void SaveOperationHis(string opHis) { var user = AutofacContainerModule.GetService().GetCurrentUser().User; SaveOperationHis(user.Id, user.Name, opHis); } /// /// 保存本次扭转记录 /// /// public void SaveTransitionHis() { var user = AutofacContainerModule.GetService().GetCurrentUser().User; var SugarClient = AutofacContainerModule.GetService(); var transitionHistory = new FlowInstanceTransitionHistory { InstanceId = flowInstanceId, CreateUserId = user.Id, CreateUserName = user.Name, FromNodeId = currentNodeId, FromNodeName = currentNode.name, FromNodeType = GetCurrentNodeType(), ToNodeId = nextNodeId, ToNodeName = nextNode?.name, ToNodeType = GetNextNodeType(), IsFinish = IsFinish() ? FlowInstanceStatus.Finished : FlowInstanceStatus.Running, TransitionSate = 0 }; SugarClient.Insertable(transitionHistory).ExecuteCommand(); } /// /// 通知三方系统,节点执行情况 /// public void NotifyThirdParty(HttpClient client, FlowNode node, Tag tag) { if (node.setInfo == null || string.IsNullOrEmpty(node.setInfo.ThirdPartyUrl)) { return; } var postData = new { flowInstanceId, businessId = flowInstance.BusinessId, nodeName = node.name, nodeId = node.id, userId = tag.UserId, userName = tag.UserName, result = tag.Taged, //1:通过;2:不通过;3驳回 description = tag.Description, execTime = tag.TagedTime, isFinish = node.type == Define.NODE_TYPE_END }; var url = node.setInfo.ThirdPartyUrl; // 如果是相对路径,需要获取当前应用的基础URL if (!url.StartsWith("http://") && !url.StartsWith("https://")) { var appConfig = AutofacContainerModule.GetService(); var baseUrl = appConfig.GetValue("AppSetting:HttpHost")?.TrimEnd('/'); if (string.IsNullOrEmpty(baseUrl)) { return; } url = $"{baseUrl}/{url.TrimStart('/')}"; } using (HttpContent httpContent = new StringContent(JsonHelper.Instance.Serialize(postData), Encoding.UTF8)) { httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); client.PostAsync(url, httpContent); } } /// /// 撤销当前节点的审批 /// public void UndoVerification() { // 已结束的流程不能撤销 if (flowInstance.IsFinish == FlowInstanceStatus.Finished || flowInstance.IsFinish == FlowInstanceStatus.Rejected) { throw new Exception("流程已结束,不能撤销"); } if(Nodes[previousId].type == Define.NODE_TYPE_START) { throw new Exception("没有任何审批,不能撤销!你可以删除或召回这个流程"); } // 恢复到上一个节点 currentNodeId = flowInstance.PreviousId; flowInstance.ActivityId = currentNodeId; flowInstance.ActivityName = Nodes[currentNodeId].name; //向前查找ActivityId的前一个结点,即连线指向ActivityId的节点 flowInstance.PreviousId = GetPreNode().id; flowInstance.MakerList = GetNodeMarkers(Nodes[currentNodeId]); // 清除当前节点的审批状态 currentNode.setInfo.Taged = null; currentNode.setInfo.UserId = ""; currentNode.setInfo.UserName = ""; currentNode.setInfo.Description = ""; currentNode.setInfo.TagedTime = ""; //删除当前节点的扭转记录 var user = AutofacContainerModule.GetService().GetCurrentUser().User; var SugarClient = AutofacContainerModule.GetService(); SugarClient.Deleteable().Where(u => u.InstanceId == flowInstanceId && u.CreateUserId == user.Id && u.FromNodeId == currentNodeId).ExecuteCommand(); //删除当前节点的审批记录(只删除最新的一条) var latestRecord = SugarClient.Queryable() .Where(u => u.InstanceId == flowInstanceId && u.CreateUserId == user.Id) .OrderByDescending(u => u.CreateDate) .First(); if (latestRecord != null) { SugarClient.Deleteable() .Where(u => u.Id == latestRecord.Id) .ExecuteCommand(); } } #endregion 共有方法 #region 获取节点审批人 /// /// 寻找下一步的执行人 /// 一般用于本节点审核完成后,修改流程实例的当前执行人,可以做到通知等功能 /// /// public string GetNextMakers(NodeDesignateReq request = null) { string makerList = ""; if (nextNodeId == "-1") { throw new Exception("无法寻找到下一个节点"); } if (GetNextNodeType() == Define.NODE_TYPE_FORK) //如果是网关节点 { makerList = GetForkNodeMakers(nextNodeId); } else if (GetNextNodeType() == Define.NODE_TYPE_MULTI_INSTANCE) //如果是多实例、会签节点 { makerList = GetMultiInstanceNodeMakers(nextNodeId); } else if (nextNode.setInfo.NodeDesignate == Define.RUNTIME_SPECIAL_ROLE) { //如果是运行时指定角色 if (nextNode.setInfo.NodeDesignate != request.NodeDesignateType) { throw new Exception("前端提交的节点权限类型异常,请检查流程"); } var revelanceApp = AutofacContainerModule.GetService(); var users = revelanceApp.Get(Define.USERROLE, false, request.NodeDesignates); makerList = GenericHelpers.ArrayToString(users, makerList); } else if (nextNode.setInfo.NodeDesignate == Define.RUNTIME_SPECIAL_USER) { //如果是运行时指定用户 if (nextNode.setInfo.NodeDesignate != request.NodeDesignateType) { throw new Exception("前端提交的节点权限类型异常,请检查流程"); } makerList = GenericHelpers.ArrayToString(request.NodeDesignates, makerList); } else if (nextNode.setInfo.NodeDesignate == Define.SPECIAL_SQL) { //如果是指定SQL if (nextNode.setInfo.NodeDesignate != request.NodeDesignateType) { throw new Exception("前端提交的节点权限类型异常,请检查流程"); } var sql = ReplaceSql(nextNode.setInfo.NodeDesignateData.datas[0]); var sugarClient = AutofacContainerModule.GetService(); var result = sugarClient.Ado.SqlQuery(sql); makerList = GenericHelpers.ArrayToString(result, makerList); } else if (nextNode.setInfo.NodeDesignate == Define.RUNTIME_PARENT || nextNode.setInfo.NodeDesignate == Define.RUNTIME_MANY_PARENTS) { //如果是上一节点执行人的直属上级或连续多级直属上级 if (nextNode.setInfo.NodeDesignate != request.NodeDesignateType) { throw new Exception("前端提交的节点权限类型异常,请检查流程"); } //当创建流程时,肯定执行的开始节点,登录用户就是创建用户 //当审批流程时,能进到这里,表明当前登录用户已经有审批当前节点的权限,完全可以直接用登录用户的直接上级 var userManagerApp = AutofacContainerModule.GetService(); var user = AutofacContainerModule.GetService().GetCurrentUser().User; var parentId = userManagerApp.GetParent(user.Id); if (StringExtension.IsNullOrEmpty(parentId)) { throw new Exception("无法找到当前用户的直属上级"); } makerList = GenericHelpers.ArrayToString(new[] { parentId }, makerList); } else if (nextNode.setInfo.NodeDesignate == Define.RUNTIME_CHAIRMAN) { //如果是发起人的部门负责人 if (nextNode.setInfo.NodeDesignate != request.NodeDesignateType) { throw new Exception("前端提交的节点权限类型异常,请检查流程"); } var orgManagerApp = AutofacContainerModule.GetService(); var chairmanIds = orgManagerApp.GetChairmanId(nextNode.setInfo.NodeDesignateData.datas); makerList = GenericHelpers.ArrayToString(chairmanIds, makerList); } else { makerList = GetNodeMarkers(nextNode); if (string.IsNullOrEmpty(makerList)) { throw new Exception("无法寻找到节点的审核者,请查看流程设计是否有问题!"); } } return makerList; } /// /// 计算多实例、会签节点的执行人 /// /// /// private string GetMultiInstanceNodeMakers(string nodeId) { if(GetNodeType(nodeId) != Define.NODE_TYPE_MULTI_INSTANCE) { throw new Exception("当前节点不是会签节点,请联系管理员"); } var node = Nodes[nodeId]; string[] makerList = Array.Empty(); // 执行人列表 var sugarClient = AutofacContainerModule.GetService(); if (node.setInfo.NodeDesignate == Define.SPECIAL_USER) //指定成员 { makerList = node.setInfo.NodeDesignateData.datas; } else if (node.setInfo.NodeDesignate == Define.SPECIAL_ROLE) //指定角色 { var revelanceApp = AutofacContainerModule.GetService(); makerList = revelanceApp.Get(Define.USERROLE, false, node.setInfo.NodeDesignateData.datas).ToArray(); } else if (node.setInfo.NodeDesignate == Define.SPECIAL_SQL) //指定SQL { //如果是指定SQL,则需要执行SQL,并返回结果 var sql = ReplaceSql(node.setInfo.NodeDesignateData.datas[0]); makerList = sugarClient.Ado.SqlQuery(sql).ToArray(); } else { throw new Exception("会签节点,不支持该类型,请重新设计流程模板"); } //写入到FlowApprover var users = sugarClient.Queryable().Where(u => makerList.Contains(u.Id)).ToList(); int order = 1; foreach (var user in users) { var flowApprover = new FlowApprover { InstanceId = flowInstanceId, ActivityId = nodeId, ApproverId = user.Id, ApproverName = user.Name, OrderNo = order++, ApproveType = node.setInfo.NodeConfluenceType, ReturnToSignNode = false, Reason = "", CreateDate = DateTime.Now }; sugarClient.Insertable(flowApprover).ExecuteCommand(); } return GenericHelpers.ArrayToString(makerList, ""); } /// /// 计算节点执行人 /// /// /// public string GetNodeMarkers(FlowNode node, string flowinstanceCreateUserId = "") { string makerList = ""; if (node.type == Define.NODE_TYPE_START && (!string.IsNullOrEmpty(flowinstanceCreateUserId))) //如果是开始节点,通常情况下是驳回到开始了 { makerList = flowinstanceCreateUserId; } else if (node.setInfo != null) { if (string.IsNullOrEmpty(node.setInfo.NodeDesignate) || node.setInfo.NodeDesignate == Define.ALL_USER) //所有成员 { makerList = "1"; } else if (node.setInfo.NodeDesignate == Define.SPECIAL_USER) //指定成员 { makerList = GenericHelpers.ArrayToString(node.setInfo.NodeDesignateData.datas, makerList); } else if (node.setInfo.NodeDesignate == Define.SPECIAL_ROLE) //指定角色 { var revelanceApp = AutofacContainerModule.GetService(); var users = revelanceApp.Get(Define.USERROLE, false, node.setInfo.NodeDesignateData.datas); makerList = GenericHelpers.ArrayToString(users, makerList); } else if (node.setInfo.NodeDesignate == Define.SPECIAL_SQL) //指定SQL { //如果是指定SQL,则需要执行SQL,并返回结果 var sql = ReplaceSql(node.setInfo.NodeDesignateData.datas[0]); var sugarClient = AutofacContainerModule.GetService(); var result = sugarClient.Ado.SqlQuery(sql); makerList = GenericHelpers.ArrayToString(result, makerList); } else if (node.setInfo.NodeDesignate == Define.RUNTIME_SPECIAL_ROLE || node.setInfo.NodeDesignate == Define.RUNTIME_SPECIAL_USER) { //如果是运行时选定的用户,则暂不处理。由上个节点审批时选定 } } else //如果没有设置节点信息,默认所有人都可以审核 { makerList = "1"; } return makerList; } /// /// 替换SQL中的权限占位符 /// 如当前用户的全部下属:select id from sysuser where parentId = {loginUser} /// 替换后:select id from sysuser where parentId = '123' /// 如登录用户同部门的人:select id from sysuser where id in (select firstid from relevance where secondid in ({loginOrg}) and relkey = 'UserOrg') /// 替换后: select id from sysuser where id in (select firstid from relevance where secondid in ('123','456') and relkey = 'UserOrg') /// /// /// private string ReplaceSql(string sql){ var loginUser = AutofacContainerModule.GetService().GetCurrentUser(); var res = sql.Replace(Define.DATAPRIVILEGE_LOGINUSER, $"'{loginUser.User.Id}'"); res = res.Replace(Define.DATAPRIVILEGE_LOGINROLE, string.Join(',', loginUser.Roles.Select(u => $"'{u.Id}'"))); res = res.Replace(Define.DATAPRIVILEGE_LOGINORG, string.Join(',', loginUser.Orgs.Select(u => $"'{u.Id}'"))); return res; } /// /// 网关时,获取一条网关分支上面是否有用户可审核的节点 /// /// /// /// public string GetOneForkLineCanCheckNodeId(FlowNode fromForkStartNode, Tag tag) { string canCheckId = ""; var node = fromForkStartNode; do //沿一条分支线路执行,直到遇到网关结束节点 { var makerList = GetNodeMarkers(node); if (node.setInfo.Taged == null && !string.IsNullOrEmpty(makerList) && makerList.Split(',').Any(one => tag.UserId == one)) { canCheckId = node.id; break; } node = GetNextNode(node.id); } while (node.type != Define.NODE_TYPE_JOIN); return canCheckId; } /// /// 获取网关开始节点的所有可执行者 /// /// 网关开始节点 /// public string GetForkNodeMakers(string forkNodeId) { string makerList = ""; foreach (string fromForkStartNodeId in FromNodeLines[forkNodeId].Select(u => u.to)) { var fromForkStartNode = Nodes[fromForkStartNodeId]; //与网关开始节点直接连接的节点 if (makerList != "") { makerList += ","; } makerList += GetOneForkLineMakers(fromForkStartNode); } return makerList; } /// /// 获取网关一条线上的审核者,该审核者应该是已审核过的节点的下一个人 /// /// 与网关开始节点直接连接的节点 private string GetOneForkLineMakers(FlowNode fromForkStartNode) { string markers = ""; var node = fromForkStartNode; do //沿一条分支线路执行,直到遇到第一个没有审核的节点 { if (node.setInfo != null && node.setInfo.Taged != null) { if (node.type != Define.NODE_TYPE_FORK && node.setInfo.Taged != (int)TagState.Ok) //如果节点是不同意或驳回,则不用再找了 { break; } node = GetNextNode(node.id); //下一个节点 continue; } var marker = GetNodeMarkers(node); if (marker == "") { throw new Exception($"节点{node.name}没有审核者,请检查!"); } if (marker == "1") { throw new Exception($"节点{node.name}是网关节点,不能用所有人,请检查!"); } if (markers != "") { markers += ","; } markers += marker; break; } while (node.type != Define.NODE_TYPE_JOIN); return markers; } #endregion #region 属性 private FlowInstance flowInstance { get; set; } private string title { get; set; } private int initNum { get; set; } /// /// 运行实例的Id /// private string flowInstanceId { get; set; } /// /// 上一个节点 /// private string previousId { get; set; } /// /// 实例节点集合 /// private Dictionary Nodes { get; set; } /// /// 流程实例中所有的线段 /// private List Lines { get; set; } /// /// 从节点发出的线段集合 /// private Dictionary> FromNodeLines { get; set; } /// /// 到达节点的线段集合 /// private Dictionary> ToNodeLines { get; set; } /// /// 表单数据 /// private string FrmData { get; set; } /// /// 开始节点的ID /// private string startNodeId { get; set; } /// /// 当前节点的ID /// public string currentNodeId { get; set; } /// /// 当前节点的对象 /// public FlowNode currentNode => Nodes[currentNodeId]; /// /// 下一个节点 /// public string nextNodeId { get; set; } /// /// 下一个节点对象 /// public FlowNode nextNode => nextNodeId != "-1" ? Nodes[nextNodeId] : null; #endregion 属性 } }