From ac72a263133400524aeb72ed078109995ecd169b Mon Sep 17 00:00:00 2001 From: wintel Date: Thu, 17 Apr 2025 00:05:49 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Infrastructure/Define.cs | 45 ++++++++++++++++-- OpenAuth.App/Flow/FlowNode.cs | 27 +---------- OpenAuth.App/Flow/FlowRuntime.cs | 50 ++++++++++---------- OpenAuth.App/FlowInstance/FlowInstanceApp.cs | 10 ++-- docs/core/flowinstanceconcept.md | 38 +++++++++------ 5 files changed, 95 insertions(+), 75 deletions(-) diff --git a/Infrastructure/Define.cs b/Infrastructure/Define.cs index 5466c212..6e3e78d2 100644 --- a/Infrastructure/Define.cs +++ b/Infrastructure/Define.cs @@ -5,6 +5,7 @@ /// public static class Define { + //Relevance关联KEY public static string USERROLE = "UserRole"; //用户角色关联KEY public const string ROLERESOURCE = "RoleResource"; //角色资源关联KEY public const string USERORG = "UserOrg"; //用户机构关联KEY @@ -14,6 +15,7 @@ public const string MODULEPRINTERPLAN = "ModulePrinterPlan"; //模块配置打印方案 public const string MODULE_FLOWSCHEME = "ModuleFlowScheme"; //模块挂载流程模板 + //数据库类型 public const string DBTYPE_SQLSERVER = "SqlServer"; //sql server public const string DBTYPE_MYSQL = "MySql"; //mysql public const string DBTYPE_PostgreSQL = "PostgreSQL"; //PostgreSQL @@ -35,17 +37,50 @@ public const string DEFAULT_FORM_INSTANCE_ID_NAME = "InstanceId"; - //流程实例知会用户 - public const string INSTANCE_NOTICE_USER = "INSTANCE_NOTICE_USER"; - //流程实例知会角色 - public const string INSTANCE_NOTICE_ROLE = "INSTANCE_NOTICE_ROLE"; - //表单类型 public const int FORM_TYPE_DYNAMIC = 0; //动态表单 public const int FORM_TYPE_DEVELOP = 1; //自定义表单 public const int FORM_TYPE_DRAG = 2; //vForm拖拽表单 public const int FORM_TYPE_URL = 3; //URL表单 + + //节点类型 + public const string NODE_TYPE_START = "start round mix"; //开始节点 + public const string NODE_TYPE_END = "end round"; //结束节点 + public const string NODE_TYPE_TASK = "node"; //任务节点 + public const string NODE_TYPE_FORK = "fork"; //网关开始 + public const string NODE_TYPE_JOIN = "join"; //网关结束 + public const string NODE_TYPE_MULTI_INSTANCE = "multiInstance"; //多实例/会签节点 + + //流程实例知会用户 + public const string INSTANCE_NOTICE_USER = "INSTANCE_NOTICE_USER"; + //流程实例知会角色 + public const string INSTANCE_NOTICE_ROLE = "INSTANCE_NOTICE_ROLE"; + + //流程节点执行权限类型 + public const string ALL_USER = "ALL_USER"; //所有用户 + public const string SPECIAL_ROLE = "SPECIAL_ROLE"; //指定角色 + public const string SPECIAL_USER = "SPECIAL_USER"; //指定用户 + public const string SPECIAL_SQL = "SPECIAL_SQL"; //指定SQL + /// + /// 连续多级直属上级 + /// 不同于钉钉的各上级部门负责人审批,OpenAuth以用户的各级直属上级审批模式 + /// + public const string RUNTIME_MANY_PARENTS = "RUNTIME_MANY_PARENTS"; + /// + /// 部门负责人 + /// + public const string RUNTIME_CHAIRMAN = "RUNTIME_CHAIRMAN"; + /// + /// 上一节点执行人的直属上级 + /// + public const string RUNTIME_PARENT = "RUNTIME_PARENT"; + + public const string RUNTIME_SPECIAL_ROLE = "RUNTIME_SPECIAL_ROLE"; //运行时指定角色 + public const string RUNTIME_SPECIAL_USER = "RUNTIME_SPECIAL_USER"; //运行时指定用户 + + + public const string API = "API_RESOURCE"; } } \ No newline at end of file diff --git a/OpenAuth.App/Flow/FlowNode.cs b/OpenAuth.App/Flow/FlowNode.cs index 478e6c9d..017809b0 100644 --- a/OpenAuth.App/Flow/FlowNode.cs +++ b/OpenAuth.App/Flow/FlowNode.cs @@ -5,11 +5,6 @@ /// public class FlowNode { - public const string START = "start round mix"; - public const string END = "end round"; - public const string NODE = "node"; - public const string FORK = "fork"; //会签开始节点 - public const string JOIN = "join"; //会签结束节点 public string id { get; set; } @@ -32,27 +27,7 @@ public class Setinfo { - public const string ALL_USER = "ALL_USER"; //所有用户 - public const string SPECIAL_ROLE = "SPECIAL_ROLE"; //指定角色 - public const string SPECIAL_USER = "SPECIAL_USER"; //指定用户 - public const string SPECIAL_SQL = "SPECIAL_SQL"; //指定SQL - /// - /// 连续多级直属上级 - /// 不同于钉钉的各上级部门负责人审批,OpenAuth以用户的各级直属上级审批模式 - /// - public const string RUNTIME_MANY_PARENTS = "RUNTIME_MANY_PARENTS"; - /// - /// 部门负责人 - /// - public const string RUNTIME_CHAIRMAN = "RUNTIME_CHAIRMAN"; - /// - /// 上一节点执行人的直属上级 - /// - public const string RUNTIME_PARENT = "RUNTIME_PARENT"; - - public const string RUNTIME_SPECIAL_ROLE = "RUNTIME_SPECIAL_ROLE"; //运行时指定角色 - public const string RUNTIME_SPECIAL_USER = "RUNTIME_SPECIAL_USER"; //运行时指定用户 - + /// /// 节点执行权限类型 /// diff --git a/OpenAuth.App/Flow/FlowRuntime.cs b/OpenAuth.App/Flow/FlowRuntime.cs index 6ab38ebe..2b9e3546 100644 --- a/OpenAuth.App/Flow/FlowRuntime.cs +++ b/OpenAuth.App/Flow/FlowRuntime.cs @@ -71,7 +71,7 @@ namespace OpenAuth.App.Flow Nodes.Add(node.id, node); } - if (node.type == FlowNode.START) + if (node.type == Define.NODE_TYPE_START) { this.startNodeId = node.id; } @@ -174,16 +174,16 @@ namespace OpenAuth.App.Flow switch (Nodes[nodeId].type) { //会签开始节点 - case FlowNode.FORK: + case Define.NODE_TYPE_FORK: return 0; //会签结束节点 - case FlowNode.JOIN: + case Define.NODE_TYPE_JOIN: return 1; //结束节点 - case FlowNode.END: + case Define.NODE_TYPE_END: return 4; //开始节点 - case FlowNode.START: + case Define.NODE_TYPE_START: return 3; default: @@ -234,7 +234,7 @@ namespace OpenAuth.App.Flow { if (tag.Taged == (int)TagState.Ok) { - if (nextNode.type == FlowNode.JOIN) //下一个节点是会签结束,则该线路结束 + if (nextNode.type == Define.NODE_TYPE_JOIN) //下一个节点是会签结束,则该线路结束 { res = GetNextNodeId(nextNode.id); } @@ -277,7 +277,7 @@ namespace OpenAuth.App.Flow } else if (tag.Taged == (int)TagState.Ok) { - if (nextNode.type == FlowNode.JOIN) //这种模式下只有坚持到【会签结束】节点之前才有意义,是否需要判定这条线所有的节点都通过,不然直接执行这个节点?? + if (nextNode.type == Define.NODE_TYPE_JOIN) //这种模式下只有坚持到【会签结束】节点之前才有意义,是否需要判定这条线所有的节点都通过,不然直接执行这个节点?? { if (forkNode.setInfo.ConfluenceOk == null) { @@ -533,7 +533,7 @@ namespace OpenAuth.App.Flow result = tag.Taged, //1:通过;2:不通过;3驳回 description = tag.Description, execTime = tag.TagedTime, - isFinish = node.type == FlowNode.END + isFinish = node.type == Define.NODE_TYPE_END }; var url = node.setInfo.ThirdPartyUrl; @@ -568,7 +568,7 @@ namespace OpenAuth.App.Flow throw new Exception("流程已结束,不能撤销"); } - if(Nodes[previousId].type == FlowNode.START) + if(Nodes[previousId].type == Define.NODE_TYPE_START) { throw new Exception("没有任何审批,不能撤销!你可以删除或召回这个流程"); } @@ -628,7 +628,7 @@ namespace OpenAuth.App.Flow { makerList = GetForkNodeMakers(nextNodeId); } - else if (nextNode.setInfo.NodeDesignate == Setinfo.RUNTIME_SPECIAL_ROLE) + else if (nextNode.setInfo.NodeDesignate == Define.RUNTIME_SPECIAL_ROLE) { //如果是运行时指定角色 if (nextNode.setInfo.NodeDesignate != request.NodeDesignateType) @@ -640,7 +640,7 @@ namespace OpenAuth.App.Flow var users = revelanceApp.Get(Define.USERROLE, false, request.NodeDesignates); makerList = GenericHelpers.ArrayToString(users, makerList); } - else if (nextNode.setInfo.NodeDesignate == Setinfo.RUNTIME_SPECIAL_USER) + else if (nextNode.setInfo.NodeDesignate == Define.RUNTIME_SPECIAL_USER) { //如果是运行时指定用户 if (nextNode.setInfo.NodeDesignate != request.NodeDesignateType) @@ -650,7 +650,7 @@ namespace OpenAuth.App.Flow makerList = GenericHelpers.ArrayToString(request.NodeDesignates, makerList); } - else if (nextNode.setInfo.NodeDesignate == Setinfo.SPECIAL_SQL) + else if (nextNode.setInfo.NodeDesignate == Define.SPECIAL_SQL) { //如果是指定SQL if (nextNode.setInfo.NodeDesignate != request.NodeDesignateType) @@ -663,8 +663,8 @@ namespace OpenAuth.App.Flow var result = sugarClient.Ado.SqlQuery(sql); makerList = GenericHelpers.ArrayToString(result, makerList); } - else if (nextNode.setInfo.NodeDesignate == Setinfo.RUNTIME_PARENT - || nextNode.setInfo.NodeDesignate == Setinfo.RUNTIME_MANY_PARENTS) + else if (nextNode.setInfo.NodeDesignate == Define.RUNTIME_PARENT + || nextNode.setInfo.NodeDesignate == Define.RUNTIME_MANY_PARENTS) { //如果是上一节点执行人的直属上级或连续多级直属上级 if (nextNode.setInfo.NodeDesignate != request.NodeDesignateType) @@ -684,7 +684,7 @@ namespace OpenAuth.App.Flow makerList = GenericHelpers.ArrayToString(new[] { parentId }, makerList); } - else if (nextNode.setInfo.NodeDesignate == Setinfo.RUNTIME_CHAIRMAN) + else if (nextNode.setInfo.NodeDesignate == Define.RUNTIME_CHAIRMAN) { //如果是发起人的部门负责人 if (nextNode.setInfo.NodeDesignate != request.NodeDesignateType) @@ -716,28 +716,28 @@ namespace OpenAuth.App.Flow public string GetNodeMarkers(FlowNode node, string flowinstanceCreateUserId = "") { string makerList = ""; - if (node.type == FlowNode.START && (!string.IsNullOrEmpty(flowinstanceCreateUserId))) //如果是开始节点,通常情况下是驳回到开始了 + 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 == Setinfo.ALL_USER) //所有成员 + node.setInfo.NodeDesignate == Define.ALL_USER) //所有成员 { makerList = "1"; } - else if (node.setInfo.NodeDesignate == Setinfo.SPECIAL_USER) //指定成员 + else if (node.setInfo.NodeDesignate == Define.SPECIAL_USER) //指定成员 { makerList = GenericHelpers.ArrayToString(node.setInfo.NodeDesignateData.datas, makerList); } - else if (node.setInfo.NodeDesignate == Setinfo.SPECIAL_ROLE) //指定角色 + 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 == Setinfo.SPECIAL_SQL) //指定SQL + else if (node.setInfo.NodeDesignate == Define.SPECIAL_SQL) //指定SQL { //如果是指定SQL,则需要执行SQL,并返回结果 var sql = ReplaceSql(node.setInfo.NodeDesignateData.datas[0]); @@ -745,8 +745,8 @@ namespace OpenAuth.App.Flow var result = sugarClient.Ado.SqlQuery(sql); makerList = GenericHelpers.ArrayToString(result, makerList); } - else if (node.setInfo.NodeDesignate == Setinfo.RUNTIME_SPECIAL_ROLE - || node.setInfo.NodeDesignate == Setinfo.RUNTIME_SPECIAL_USER) + else if (node.setInfo.NodeDesignate == Define.RUNTIME_SPECIAL_ROLE + || node.setInfo.NodeDesignate == Define.RUNTIME_SPECIAL_USER) { //如果是运行时选定的用户,则暂不处理。由上个节点审批时选定 } @@ -798,7 +798,7 @@ namespace OpenAuth.App.Flow } node = GetNextNode(node.id); - } while (node.type != FlowNode.JOIN); + } while (node.type != Define.NODE_TYPE_JOIN); return canCheckId; } @@ -837,7 +837,7 @@ namespace OpenAuth.App.Flow { if (node.setInfo != null && node.setInfo.Taged != null) { - if (node.type != FlowNode.FORK && node.setInfo.Taged != (int)TagState.Ok) //如果节点是不同意或驳回,则不用再找了 + if (node.type != Define.NODE_TYPE_FORK && node.setInfo.Taged != (int)TagState.Ok) //如果节点是不同意或驳回,则不用再找了 { break; } @@ -864,7 +864,7 @@ namespace OpenAuth.App.Flow markers += marker; break; - } while (node.type != FlowNode.JOIN); + } while (node.type != Define.NODE_TYPE_JOIN); return markers; } diff --git a/OpenAuth.App/FlowInstance/FlowInstanceApp.cs b/OpenAuth.App/FlowInstance/FlowInstanceApp.cs index e200ccf4..e628c9df 100644 --- a/OpenAuth.App/FlowInstance/FlowInstanceApp.cs +++ b/OpenAuth.App/FlowInstance/FlowInstanceApp.cs @@ -477,7 +477,7 @@ namespace OpenAuth.App } } - if (wfruntime.currentNode.setInfo.NodeDesignate == Setinfo.RUNTIME_MANY_PARENTS) + if (wfruntime.currentNode.setInfo.NodeDesignate == Define.RUNTIME_MANY_PARENTS) { List roles; if (user.Id != tag.UserId) @@ -619,8 +619,8 @@ namespace OpenAuth.App /// private void CheckNodeDesignate(NodeDesignateReq request) { - if ((request.NodeDesignateType == Setinfo.RUNTIME_SPECIAL_ROLE - || request.NodeDesignateType == Setinfo.RUNTIME_SPECIAL_USER) && request.NodeDesignates.Length == 0) + if ((request.NodeDesignateType == Define.RUNTIME_SPECIAL_ROLE + || request.NodeDesignateType == Define.RUNTIME_SPECIAL_USER) && request.NodeDesignates.Length == 0) { throw new Exception("下个节点需要选择执行人或执行角色"); } @@ -860,8 +860,8 @@ namespace OpenAuth.App var wfruntime = new FlowRuntime(flowInstance); var user = _auth.GetCurrentUser(); - if (wfruntime.nextNode.setInfo.NodeDesignate == Setinfo.RUNTIME_SPECIAL_USER - || wfruntime.nextNode.setInfo.NodeDesignate == Setinfo.RUNTIME_SPECIAL_ROLE) + if (wfruntime.nextNode.setInfo.NodeDesignate == Define.RUNTIME_SPECIAL_USER + || wfruntime.nextNode.setInfo.NodeDesignate == Define.RUNTIME_SPECIAL_ROLE) { throw new Exception("暂不支持【第二执行节点为运行时指定角色/账号执行】的流程恢复"); } diff --git a/docs/core/flowinstanceconcept.md b/docs/core/flowinstanceconcept.md index 1ce4ab14..679b6149 100644 --- a/docs/core/flowinstanceconcept.md +++ b/docs/core/flowinstanceconcept.md @@ -1,22 +1,32 @@ # 工作流中的概念 + +## 并行网关 + +并行网关处理的是流程分支和汇聚,每个分支可以是不同的业务逻辑和不同的处理人。它有以下特点: + +- 分支时:所有出口流向都会被激活(创建多条并行路径) +- 汇聚时:等待所有进入的分支完成才继续往下执行 +- 每条路径通常由不同的活动和不同的处理人完成 +- 路径之间互相独立 + +在网关开始时(即分支时),可以设置并行网关的类型,目前支持两种模式:全部通过和至少一个通过。如下: +![20240417112438](http://img.openauth.net.cn/20240417112438.png) + +全部通过:网关所有分支审批通过,节点审批通过。 + +至少一个通过:网关中任意一个分支审批通过,节点审批通过。 + +具体的审批人员或角色,需要在【网关开始】和【网关结束】之间的节点配置,如上图中的admin、test。 + ## 会签 -会签又称为联名签署,指需要得到两个或多个相关参与者的签名批准。目前支持两种模式:全部通过和至少一个通过,在【会签开始】节点进行配置。如下: -![20240417112438](http://img.openauth.net.cn/20240417112438.png) +会签又称为联名签署,处理的是同一个任务需要多人审批的情况。它的特点: -全部通过:会签中的所有人员都通过,节点审批通过。 - -至少一个通过:会签中任何一个人通过,节点即审批通过。 - -具体的会签人员或角色,需要在【会签开始】和【会签结束】之间的节点配置,如上图中的admin、test。 - -::: warning 特别注意 - -【会签开始】【会签结束】执行权限配置为所有人 - -会签不能在分支上加判断条件 -::: +- 是同一个任务的多个副本 +- 分配给多个执行人执行相同的工作 +- 可以设置完成条件(如全部通过、部分通过即可) +- 处理的是同一个业务节点,只是执行人不同 ## 加签