add -- 流程设计添加"会签"和"或签"方式

This commit is contained in:
konbai
2022-05-12 01:46:24 +08:00
parent 9a6910be92
commit b898d3275b
3 changed files with 142 additions and 4 deletions

View File

@@ -0,0 +1,64 @@
package com.ruoyi.workflow.handler;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.flowable.common.constant.ProcessConstants;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.mapper.SysUserRoleMapper;
import lombok.AllArgsConstructor;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.stream.Collectors;
/**
* 多实例处理类
*
* @author KonBAI
*/
@AllArgsConstructor
@Component("multiInstanceHandler")
public class MultiInstanceHandler {
public HashSet<String> getUserIds(DelegateExecution execution) {
HashSet<String> candidateUserIds = new LinkedHashSet<>();
FlowElement flowElement = execution.getCurrentFlowElement();
if (ObjectUtil.isNotEmpty(flowElement) && flowElement instanceof UserTask) {
UserTask userTask = (UserTask) flowElement;
String dataType = userTask.getAttributeValue(ProcessConstants.NAMASPASE, ProcessConstants.PROCESS_CUSTOM_DATA_TYPE);
if ("USERS".equals(dataType) && CollUtil.isNotEmpty(userTask.getCandidateUsers())) {
candidateUserIds.addAll(userTask.getCandidateUsers());
} else if (CollUtil.isNotEmpty(userTask.getCandidateGroups())) {
List<String> groups = userTask.getCandidateGroups()
.stream().map(item -> item.substring(4)).collect(Collectors.toList());
if ("ROLES".equals(dataType)) {
SysUserRoleMapper userRoleMapper = SpringUtils.getBean(SysUserRoleMapper.class);
groups.forEach(item -> {
List<String> userIds = userRoleMapper.selectUserIdsByRoleId(Long.parseLong(item))
.stream().map(String::valueOf).collect(Collectors.toList());
candidateUserIds.addAll(userIds);
});
} else if ("DEPTS".equals(dataType)) {
SysUserMapper userMapper = SpringUtils.getBean(SysUserMapper.class);
LambdaQueryWrapper<SysUser> lambdaQueryWrapper = new LambdaQueryWrapper<SysUser>()
.select(SysUser::getUserId);
groups.forEach(item -> {
List<String> userIds = userMapper.selectList(lambdaQueryWrapper.eq(SysUser::getDeptId, Long.parseLong(item)))
.stream().map(k -> String.valueOf(k.getDeptId())).collect(Collectors.toList());
candidateUserIds.addAll(userIds);
});
}
}
}
return candidateUserIds;
}
}

View File

@@ -21,7 +21,7 @@
<div slot="title" class="panel-tab__title"><i class="el-icon-s-claim"></i>任务</div>
<element-task :id="elementId" :type="elementType" />
</el-collapse-item>
<el-collapse-item name="multiInstance" v-if="elementType.indexOf('Task') !== -1" key="multiInstance">
<el-collapse-item name="multiInstance" v-if="elementType.indexOf('Task') !== -1 && elementType !== 'UserTask'" key="multiInstance">
<div slot="title" class="panel-tab__title"><i class="el-icon-s-help"></i>多实例</div>
<element-multi-instance :business-object="elementBusinessObject" :type="elementType" />
</el-collapse-item>

View File

@@ -1,6 +1,7 @@
<template>
<div style="margin-top: 16px">
<div>
<el-row>
<h4><b>审批人设置</b></h4>
<el-radio-group v-model="dataType" @change="changeDataType">
<el-radio label="USERS">指定用户</el-radio>
<el-radio label="ROLES">角色</el-radio>
@@ -47,6 +48,17 @@
</tree-select>
</div>
</el-row>
<el-row>
<div v-show="showMultiFlog">
<el-divider />
<h4><b>多实例审批方式</b></h4>
<el-radio-group v-model="multiLoopType" @change="changeMultiLoopType">
<el-row><el-radio label="Null"></el-radio></el-row>
<el-row><el-radio label="SequentialMultiInstance">会签需所有审批人同意</el-radio></el-row>
<el-row><el-radio label="ParallelMultiInstance">或签一名审批人同意即可</el-radio></el-row>
</el-radio-group>
</div>
</el-row>
<!-- 候选用户弹窗 -->
<el-dialog title="候选用户" :visible.sync="userOpen" width="60%" append-to-body>
@@ -118,6 +130,15 @@ const userTaskForm = {
// priority: ''
}
const multiInstanceForm = {
completionCondition: "",
loopCardinality: "",
extensionElements: [],
asyncAfter: false,
asyncBefore: false,
exclusive: false
}
export default {
name: "UserTask",
props: {
@@ -151,7 +172,9 @@ export default {
// 查询参数
queryParams: {
deptId: undefined
}
},
showMultiFlog: false,
multiLoopType: 'Null',
};
},
watch: {
@@ -197,6 +220,7 @@ export default {
}
});
}
this.getElementLoop(bpmnElementObj);
},
updateElementTask() {
const taskAttr = Object.create(null);
@@ -298,10 +322,14 @@ export default {
userTaskForm.assignee = data.userId;
userTaskForm.text = data.nickName;
userTaskForm.candidateUsers = null;
this.showMultiFlog = false;
this.multiLoopType = 'Null';
this.changeMultiLoopType(this.multiLoopType);
} else {
userTaskForm.candidateUsers = this.selectedUserDate.map(k => k.userId).join() || null;
userTaskForm.text = this.selectedUserDate.map(k => k.nickName).join() || null;
userTaskForm.assignee = null;
this.showMultiFlog = true;
}
this.updateElementTask()
this.userOpen = false;
@@ -372,7 +400,53 @@ export default {
userTaskForm.text = "流程发起人";
}
this.updateElementTask();
}
if (val === 'ROLES' || val === 'DEPTS' || (val === 'USERS' && userTaskForm.text.indexOf(',') > 0)) {
this.showMultiFlog = true;
} else {
this.showMultiFlog = false;
}
this.multiLoopType = 'Null';
this.changeMultiLoopType(this.multiLoopType);
},
getElementLoop(businessObject) {
if (!businessObject.loopCharacteristics) {
this.multiLoopType = "Null";
return;
}
if (businessObject.loopCharacteristics.isSequential) {
this.multiLoopType = "SequentialMultiInstance";
} else {
this.multiLoopType = "ParallelMultiInstance";
}
},
changeMultiLoopType(type) {
// 取消多实例配置
if (type === "Null") {
window.bpmnInstances.modeling.updateProperties(this.bpmnElement, { loopCharacteristics: null });
return;
}
// 完成条件
let completionCondition = null;
// 会签
if (type === "SequentialMultiInstance") {
this.multiLoopInstance = window.bpmnInstances.moddle.create("bpmn:MultiInstanceLoopCharacteristics", { isSequential: true });
completionCondition = window.bpmnInstances.moddle.create("bpmn:FormalExpression", { body: '${nrOfCompletedInstances >= nrOfInstances}' });
}
// 或签
if (type === "ParallelMultiInstance") {
this.multiLoopInstance = window.bpmnInstances.moddle.create("bpmn:MultiInstanceLoopCharacteristics");
completionCondition = window.bpmnInstances.moddle.create("bpmn:FormalExpression", { body: '${nrOfCompletedInstances > 0}' });
}
// 更新多实例配置
window.bpmnInstances.modeling.updateProperties(this.bpmnElement, {
loopCharacteristics: this.multiLoopInstance
});
// 更新模块属性信息
window.bpmnInstances.modeling.updateModdleProperties(this.bpmnElement, this.multiLoopInstance, {
collection: '${multiInstanceHandler.getUserIds(execution)}',
completionCondition
});
},
}
};
</script>