Activiti 工作流会签开发设计思路

本文介绍使用Activiti工作流引擎实现动态会签的方法,包括串行与并行会签的设计思路,以及如何通过节点多实例特性实现灵活的会签规则设定。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Activiti 工作流会签开发设计思路

 

在流程业务管理中,任务是通常都是由一个人去处理的,而多个人同时处理一个任务,这种任务我们称之为会签任务。这种业务需求也很常见,如一个请款单,领导审批环节中,就需要多个部门领导签字。在流程业务中,我们可以把每个领导签字的环节都定义为任务,但若这样,这个流程业务有一点是固定的,就是签批人是固定的。而任务是由一个领导签完再到另一领导,当然也可以由多个领导同时签字。

传统的用流程业务来解决可以采用以下的做法:

 
串行会签
串行会签
 
并行会签
 
 

 

前者在流程业务中,叫串行会签,也即是由一个领导签完再至另一领导签。后者我们称之为并行会签,表示几个领导同时进行签发,而不清楚最终是谁先签。

 

以上的解决方式有两大业务需求下是不能满足的,若会签的领导不是固定的,即可以由上一任务审批人提交前随意进行选择,另一种是对于会签业务中,要求若其中一部分领导审批通过,即直接往下走,不需要全部领导进行审批。另外,对于这种情况下,统计最终领导会签的结果也是比较困难的,即对审批单的意见是同意还是否决没有办法清楚。以上两种业务需求也是很常见的日常需求,但我们若采用了固定的流程节点,则不能实现。在这里,可以采用Activiti的节点多实例来处理,以上流程则可以简化为下:

 
activiti会签流程设计
 
何谓多任务实例节点?在Activiti5上的解析则为动态的多任务节点,可以根据传入的动态人员数进行动态生成任务。生成的任务数则不固定,可以进行并行会签,也可以进行串行会签。会签任务最终是否需要往下执行,由会签设置的规则来进行约束。如我们可以常规去设置“一票通过”、“一票否决”、“少数服务多数”等会签规则。因此,我们需要在会签节点上绑定我们的设计规则。会签规则设置界面如下:
 
会签规则设计
 
通过会签设计规则,可以清楚最终会签人员的投票结果。其数据结构如下所示:
会签规则表
 
会签任务的定义本身已经由Activiti来实现了,但需要动态传入动态的人员数
 
<userTask activiti:assignee="${assignee}" id="SignTask1" name="领导会签">
<extensionElements>
<activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskSignCreateListener" event="create"/>
<activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskAssignListener" event="assignment"/>
<activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskCompleteListener" event="complete"/>
</extensionElements>
<multiInstanceLoopCharacteristics activiti:elementVariable="assignee" isSequential="false" activiti:collection="${taskUserAssignService.getSignUser(execution)}">
<completionCondition>${signComplete.isComplete(execution)}</completionCondition>
</multiInstanceLoopCharacteristics>
</userTask>
 其中,isSequential为true则为串行会签,若为false则为并行会签,而activiti:collection可以来自我们Spring容器中的接口及方法,表示获取会签用户集合,taskUserAssignService.getSignUser(execution)。其获取会签的用户值来自两个方面,一个在界面中指定的会签人员,另一个在后台会签节点上配置的人员。
 
会签人员设置
后台会签节点人员设置
 
会签人员设置2
任务审批面上选择下一任务会签人员
 
<completeCondition>为完成会签的条件signComplete.isComplete(execution),可以在这里根据我们的会签规则及目前的会签情况,决定会签是否完成。其实现如下所示:
 
最终实现逻辑:
	@Override
	public boolean isComplete(ActivityExecution execution) {
		
		logger.debug("entert the SignComplete isComplete method...");
		
		String nodeId=execution.getActivity().getId();
		String actInstId=execution.getProcessInstanceId();
		
		ProcessDefinition processDefinition=bpmService.getProcessDefinitionByProcessInanceId(actInstId);
		//取得会签设置的规则
		BpmNodeSign bpmNodeSign=bpmNodeSignService.getByDefIdAndNodeId(processDefinition.getId(), nodeId);
		//完成会签的次数
		Integer completeCounter=(Integer)execution.getVariable("nrOfCompletedInstances");
		//总循环次数
		Integer instanceOfNumbers=(Integer)execution.getVariable("nrOfInstances");
		//计算投票结果。
		VoteResult voteResult=calcResult(bpmNodeSign, actInstId, nodeId, completeCounter,instanceOfNumbers);
		
		String signResult=voteResult.getSignResult();
		boolean isCompleted=voteResult.getIsComplete();
		
		/**
		* 会签完成做的动作。
		* 1.删除会签的流程变量。
		* 2.将会签数据更新为完成。
		* 3.设置会签结果变量。
		* 4.更新会签节点结果。
		* 5.清除会签用户。
		*/
		if(isCompleted){
			//删除会签的变量。
			//删除 assignee,loopCounter变量。
			bpmService.delLoopAssigneeVars(execution.getId());
			logger.debug("set the sign result + " + signResult);
			//将会签数据更新为完成。
			taskSignDataService.batchUpdateCompleted(actInstId, nodeId);
			//设置会签的结果
			execution.setVariable("signResult_" + nodeId , signResult);
			//更新会签节点的状态。
			Short status=TaskOpinion.STATUS_PASSED;
			if(signResult.equals(SIGN_RESULT_REFUSE)){
				status=TaskOpinion.STATUS_NOT_PASSED;
			}
			//更新会签节点的状态。
			bpmProStatusDao.updStatus(actInstId, nodeId,status);
			//清除会签用户。
			taskUserAssignService.clearSignUser();
		}
		
		return isCompleted;
	}

/**
	 * 根据会签规则计算投票结果。
	 * <pre>
	 * 1.如果会签规则为空,那么需要所有的人同意通过会签,否则不通过。
	 * 2.否则按照规则计算投票结果。
	 * </pre>
	 * @param bpmNodeSign		会签规则
	 * @param actInstId			流程实例ID
	 * @param nodeId			节点id名称
	 * @param completeCounter		循环次数
	 * @param instanceOfNumbers		总的会签次数。
	 * @return
	 */
	private VoteResult calcResult(BpmNodeSign bpmNodeSign,String actInstId,String nodeId,Integer completeCounter,Integer instanceOfNumbers){
		VoteResult voteResult=new VoteResult();
		//没有会签实例
		if(instanceOfNumbers==0){
			return voteResult;
		}
		//投同意票数
		Integer agreeVotesCounts=taskSignDataService.getAgreeVoteCount(actInstId, nodeId);
		//没有设置会签规则
		//(那么得全部会签通过才通过,否则不通过)
		if(bpmNodeSign==null){
			//还没有完成可以退出。
			if(completeCounter<instanceOfNumbers){
				return voteResult;
			}
			else{
				//完成了 (全部同意才通过)
				if(agreeVotesCounts.equals(instanceOfNumbers)){
					return new VoteResult(SIGN_RESULT_PASS,true);
				}
				else{
					return new VoteResult(SIGN_RESULT_REFUSE,true);
				}
			}
		}
		
		//投反对票数
		Integer refuseVotesCounts=taskSignDataService.getRefuseVoteCount(actInstId, nodeId);
		
		//检查投票是否完成
		if(BpmNodeSign.VOTE_TYPE_PERCENT.equals(bpmNodeSign.getVoteType())){
			float percents=0;
			//按同意票数进行决定
			if(BpmNodeSign.DECIDE_TYPE_PASS.equals(bpmNodeSign.getDecideType())){
				percents=agreeVotesCounts/instanceOfNumbers;
				//投票同意票符合条件
				if(percents>=bpmNodeSign.getVoteAmount()){
					voteResult=new VoteResult(SIGN_RESULT_PASS, true);
				}
				//投票已经全部完成
				else if(completeCounter.equals(instanceOfNumbers)){
					voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);
				}
			}
			//按反对票数进行决定
			else{
				percents=refuseVotesCounts/instanceOfNumbers;
				//投票
				if(percents>=bpmNodeSign.getVoteAmount()){
					voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);
				}
				//投票已经全部完成
				else if(completeCounter.equals(instanceOfNumbers)){
					voteResult=new VoteResult(SIGN_RESULT_PASS, true);
				}
			}
		}
		//按绝对票数投票
		else{
			//按同意票数进行决定
			if(BpmNodeSign.DECIDE_TYPE_PASS.equals(bpmNodeSign.getDecideType())){
				//投票同意票符合条件
				if(agreeVotesCounts>=bpmNodeSign.getVoteAmount()){
					voteResult=new VoteResult(SIGN_RESULT_PASS, true);
				}
				//投票已经全部完成
				else if(completeCounter.equals(instanceOfNumbers)){
					voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);
				}
			}
			//按反对票数进行决定
			else{
				//投票
				if(refuseVotesCounts>=bpmNodeSign.getVoteAmount()){
					voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);
				}
				//投票已经全部完成
				else if(completeCounter.equals(instanceOfNumbers)){
					voteResult=new VoteResult(SIGN_RESULT_PASS, true);
				}
			}
		}
		return voteResult;
	}
 
 

想部署及学习了解,可参考本人新的博客获得下载源代码。

 

http://redxun.iteye.com/blog/2406509

 
 

 

<think>好的,用户想找基于Vue的工作流管理软件推荐或者如何用Vue开发这样的系统。首先,我需要回忆一下常见的Vue开源项目,特别是和工作流相关的。可能有一些现成的解决方案,比如基于Vue和Element UI或Ant Design Vue的,或者结合BPMN.js的。 然后,用户可能不只是需要现成的软件,可能还想自己开发,所以得考虑开发流程。需要分步骤来,比如技术选型、流程设计器、后端集成、权限管理等部分。技术栈方面,前端用Vue3组合式API,UI框架选Element Plus或者Ant Design Vue都不错。流程设计器可能需要BPMN.js,这个库专门用来做BPMN 2.0的建模,比较专业。 然后后端部分,可能需要Spring Boot或者Node.js,比如NestJS,这些和Vue搭配起来比较常见。数据库的话,MySQL或PostgreSQL适合业务数据,流程实例可能需要用Activiti或Camunda,不过这些是Java系的,如果用户想用Node.js,可以考虑自己设计流程引擎或者用一些轻量级的库。 权限管理方面,Vue通常会用Vue Router做路由权限,结合RBAC模型,后端用JWT或者OAuth2来管理。状态管理用Pinia比较合适,替代Vuex,因为更轻量。 然后,用户可能需要参考现有的项目,比如上面提到的那个软件项目开发管理系统,里面提到简化了管理方式,所以可以强调系统的模块化设计,比如流程设计器、任务处理、监控等模块。需要提到具体的实现步骤,比如如何集成BPMN.js,如何后端API交互,如何处理流程实例的状态。 另外,用户可能关心优化和扩展性,比如如何提高渲染性能,如何支持复杂的流程,或者如何集成第三方服务。可能还需要考虑移动端适配,使用Vant等UI框架。 最后,安全问题也很重要,比如XSS防护,接口的鉴权,数据加密等。这些都是在开发过程中需要注意的点。 现在需要把这些思路整理成结构化的回答,分点推荐现成的解决方案,再详细说明开发步骤,最后给出相关的问题扩展。同时,要确保提到的引用正确,比如那个参考的软件项目管理系统是基于Vue的,所以可以作为例子说明优势。</think>### 基于Vue的工作流管理解决方案推荐开发指南 #### 一、现有基于Vue的工作流管理软件推荐 1. **KFormDesign(开源流程设计器)** - 基于Vue3+Element Plus的可视化表单/流程设计工具 - 支持拖拽式节点配置和条件分支设置 - 配套运行时解析引擎可实现完整流程执行 2. **bpmn-js + Vue集成方案** - 使用BPMN 2.0标准规范开发流程设计器 $$ \text{BPMN元素} = \{\text{Task}, \text{Gateway}, \text{Event}, ...\} $$ - 通过`bpmn-js-properties-panel`扩展属性配置功能 - 适合需要高度定制化的企业级流程管理[^1] 3. **JVS低代码平台(企业级方案)** - 包含智能表单设计器+可视化流程引擎 - 支持会签、并行审批等复杂场景 - 提供API网关实现第三方系统集成 #### 二、Vue工作流管理系统开发步骤 **1. 技术选型建议** - 前端框架:Vue3 + TypeScript + Pinia - UI组件库:Element Plus / Ant Design Vue - 流程引擎:bpmn-js + 自研解析器 或 Activiti/Flowable集成 - 后端技术:Spring Boot / NestJS + MySQL/PostgreSQL **2. 核心功能实现** **(1) 流程设计器开发** ```javascript // BPMN初始化示例 import BpmnModeler from 'bpmn-js/lib/Modeler'; const modeler = new BpmnModeler({ container: '#canvas', propertiesPanel: { parent: '#properties' } }); ``` - 通过`moddleExtensions`扩展自定义元素属性 - 使用`min-dash`实现命令栈管理 **(2) 流程执行引擎** - 定义流程实例状态机: $$ \text{状态转移矩阵} = \begin{bmatrix} \text{待处理} & \rightarrow & \text{进行中} \\ \text{进行中} & \rightarrow & \text{已完成/退回} \end{bmatrix} $$ - 实现会签逻辑: ```javascript const needSignCount = nodes.filter(n => n.type === '会签').length; ``` **3. 典型系统架构** ``` 前端层(Vue) 网关层 后端服务层 ├─流程设计器 ←→ API Gateway ←→ 流程引擎服务 ├─任务中心 ←→ 权限服务 └─监控看板 ←→ 数据分析服务 ``` 该架构支持高并发场景下的流程处理,符合现代微服务架构设计原则[^1] **4. 关键优化点** - 使用Web Worker处理复杂流程计算 - 通过Vue的keep-alive缓存高频访问视图 - 采用IndexedDB存储本地流程草稿 - 实现增量式流程定义更新策略
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值