更多nbcio-boot功能请看演示系统
gitee源代码地址
后端代码: https://gitee.com/nbacheng/nbcio-boot
前端代码:https://gitee.com/nbacheng/nbcio-vue.git
在线演示(包括H5) : http://122.227.135.243:9888
今天我们实现nbcio-boot的flowable的流程加签功能。
一、加签的几个概念
1、向前加签
任务在 A 这里,A 这个时候需要 B 核对一下,等 B 核对之后又回到 A 这里,这时 A 才能继续自己的任务
2、向后加签
任务在 A 这里,A 这个时候需要 B 处理这个事情,处理完毕之后就不用管了,继续后面的审批环节
3、多实例加签
任务只能对多实例任务进行加签,其它无效
二、前端实现
界面代码如下:
<!--加签流程--> <a-modal :z-index="100" :title="addSignTitle" @cancel="addSignOpen = false" :visible.sync="addSignOpen" :width="'40%'" append-to-body> <el-form ref="addSignForm" :model="addSignForm" label-width="160px"> <el-form-item label="加签类型" prop="addSignType" :rules="[{ required: true, message: '请选择加签类型', trigger: 'blur' }]"> <el-radio-group v-model="addSignForm.addSignType" @change="changeAddSignType"> <el-radio :label="0">前加签</el-radio> <el-radio :label="1">后加签</el-radio> <el-radio :label="2">多实例加签</el-radio> </el-radio-group> </el-form-item> <el-form-item label="用户选择" prop="addSignUsers" :rules="[{ required: true, message: '请选择用户', trigger: 'blur' }]"> <j-select-user-by-dep v-model="addSignForm.addSignUsers" /> </el-form-item> <el-form-item label="处理意见" prop="comment" :rules="[{ required: true, message: '请输入处理意见', trigger: 'blur' }]"> <el-input type="textarea" v-model="addSignForm.comment" placeholder="请输入处理意见" /> </el-form-item> <el-form-item label="附件" prop="commentFileDto.fileurl"> <j-upload v-model="addSignForm.commentFileDto.fileurl" ></j-upload> </el-form-item> </el-form> <span slot="footer" class="dialog-footer"> <el-button @click="addSignOpen = false">取 消</el-button> <el-button type="primary" @click="addSignComplete(true)">确 定</el-button> </span> </a-modal>
加签实现代码如下:
/** 加签 */ handleAddSign() { this.addSignOpen = true; this.addSignTitle = "前加签流程"; }, changeAddSignType(val) { this.addSignForm.addSignType = val; if(this.addSignForm.addSignType === 0) { this.addSignTitle = "前加签流程"; } if(this.addSignForm.addSignType === 1) { this.addSignTitle = "后加签流程"; } if(this.addSignForm.addSignType === 2) { this.addSignTitle = "多实例加签流程"; } console.log("changeAddSignType =",val); console.log("this.addSignTitle =",this.addSignTitle); }, /** 加签任务 */ addSignComplete() { if (!this.addSignForm.addSignUsers ) { this.$message.error("请选择用户"); return; } // 流程信息 this.addSignForm.deployId = this.$route.query && this.$route.query.deployId; this.addSignForm.taskId = this.$route.query && this.$route.query.taskId; this.addSignForm.procInsId = this.$route.query && this.$route.query.procInsId; this.addSignForm.instanceId = this.$route.query && this.$route.query.procInsId; // 初始化表单 this.addSignForm.procDefId = this.$route.query && this.$route.query.procDefId; this.addSignForm.businessKey = this.$route.query && this.$route.query.businessKey; this.addSignForm.category = this.$route.query && this.$route.query.category; this.addSignForm.dataId = this.$route.query && this.$route.query.businessKey; //节点类型 this.addSignForm.nodeType = this.$route.query && this.$route.query.nodeType; //online表单id和数据id this.addSignForm.onlineId = this.$route.query && this.$route.query.onlineId; if (this.addSignForm.category === 'online') { this.addSignForm.onlineDataId = this.$route.query && this.$route.query.businessKey; } //对formdesigner后续加签审批的时候需要用到 this.addSignForm.values = this.taskForm.values; console.log("this.addSignForm=",this.addSignForm); if(this.addSignForm.addSignType === 2) { multiInstanceAddSignTask(this.addSignForm).then(response => { this.$message.success(response.message); this.addSignOpen = false; this.goBack(); }); } else { addSignTask(this.addSignForm).then(response => { this.$message.success(response.message); this.addSignOpen = false; this.goBack(); }); } },
实现效果图如下:
三、后端主要代码
@Override public void addTasksBefore(String processInstanceId, String assignee, Set<String> assignees, String description) { addTask(processInstanceId, assignee, assignees, description, Boolean.FALSE); } @Override public void addTasksAfter(String processInstanceId, String assignee, Set<String> assignees, String description) { addTask(processInstanceId, assignee, assignees, description, Boolean.TRUE); } @Override @Transactional(rollbackFor = Exception.class) public void addTask(String processInstanceId, String assignee, Set<String> assignees, String description, Boolean flag) { TaskEntityImpl task = (TaskEntityImpl) taskService.createTaskQuery().processInstanceId(processInstanceId).taskAssignee(assignee).singleResult(); Assert.notNull(task, String.format("分配人 [%s] 没有待处理任务", assignee)); //如果是加签再加签 String parentTaskId = task.getParentTaskId(); if (StrUtil.isBlank(parentTaskId)) { task.setOwner(assignee); task.setAssignee(null); task.setCountEnabled(true); if (flag) { task.setScopeType("after"); } else { task.setScopeType("before"); } // 设置任务为空执行者 taskService.saveTask(task); } //添加加签数据 this.createSignSubTasks(assignee, assignees, task); //添加审批意见 String type = flag ? FlowComment.HJQ.getType() : FlowComment.QJQ.getType(); taskService.addComment(task.getId(), processInstanceId, type, description); } /** * 创建加签子任务 * @param assignees 被加签人 * @param assignee 加签人 * @param taskEntity 父任务 */ private void createSignSubTasks(String assignee, Set<String> assignees, TaskEntity taskEntity) { if (CollectionUtil.isNotEmpty(assignees)) { //1.创建被加签人的任务列表 assignees.forEach(userId -> { if (StrUtil.isNotBlank(userId)) { this.createSubTask(taskEntity, taskEntity.getId(), userId); } }); String parentTaskId = taskEntity.getParentTaskId(); if (StrUtil.isBlank(parentTaskId)) { parentTaskId = taskEntity.getId(); } String finalParentTaskId = parentTaskId; //2.创建加签人的任务并执行完毕 String taskId = taskEntity.getId(); if (StrUtil.isBlank(taskEntity.getParentTaskId())) { Task task = this.createSubTask(taskEntity, finalParentTaskId, assignee); taskId = task.getId(); } Task taskInfo = taskService.createTaskQuery().taskId(taskId).singleResult(); if (ObjectUtil.isNotNull(taskInfo)) { taskService.complete(taskId); } //如果是候选人,需要删除运行时候选不中的数据。 long candidateCount = taskService.createTaskQuery().taskId(parentTaskId).taskCandidateUser(assignee).count(); if (candidateCount > 0) { taskService.deleteCandidateUser(parentTaskId, assignee); } } } public String getMultiInstanceActAssigneeParam(String processDefinitionId, String actId) { AtomicReference<String> resultParam = new AtomicReference<>(); ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() .processDefinitionId(processDefinitionId).singleResult(); //获取bpmnModel并转为modelNode BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId()); //获取主流程 Process mainProcess = bpmnModel.getMainProcess(); //获取用户任务节点类型,深入子流程 mainProcess.findFlowElementsOfType(UserTask.class, true).forEach(userTask -> { String userTaskId = userTask.getId(); if (userTaskId.equals(actId)) { Object behavior = userTask.getBehavior(); if (ObjectUtil.isNotNull(behavior)) { //并行多实例节点 if (behavior instanceof ParallelMultiInstanceBehavior) { ParallelMultiInstanceBehavior parallelMultiInstanceBehavior = (ParallelMultiInstanceBehavior) behavior; String collectionElementVariable = parallelMultiInstanceBehavior .getCollectionElementVariable(); if (ObjectUtil.isNotEmpty(collectionElementVariable)) { resultParam.set(collectionElementVariable); } } //串行多实例节点 if (behavior instanceof SequentialMultiInstanceBehavior) { SequentialMultiInstanceBehavior sequentialMultiInstanceBehavior = (SequentialMultiInstanceBehavior) behavior; String collectionElementVariable = sequentialMultiInstanceBehavior .getCollectionElementVariable(); if (ObjectUtil.isNotEmpty(collectionElementVariable)) { resultParam.set(collectionElementVariable); } } } } }); return resultParam.get(); }
四、实际效果图如下: