add -- 流程设计添加"会签"和"或签"方式
This commit is contained in:
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
<div slot="title" class="panel-tab__title"><i class="el-icon-s-claim"></i>任务</div>
|
<div slot="title" class="panel-tab__title"><i class="el-icon-s-claim"></i>任务</div>
|
||||||
<element-task :id="elementId" :type="elementType" />
|
<element-task :id="elementId" :type="elementType" />
|
||||||
</el-collapse-item>
|
</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>
|
<div slot="title" class="panel-tab__title"><i class="el-icon-s-help"></i>多实例</div>
|
||||||
<element-multi-instance :business-object="elementBusinessObject" :type="elementType" />
|
<element-multi-instance :business-object="elementBusinessObject" :type="elementType" />
|
||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="margin-top: 16px">
|
<div>
|
||||||
<el-row>
|
<el-row>
|
||||||
|
<h4><b>审批人设置</b></h4>
|
||||||
<el-radio-group v-model="dataType" @change="changeDataType">
|
<el-radio-group v-model="dataType" @change="changeDataType">
|
||||||
<el-radio label="USERS">指定用户</el-radio>
|
<el-radio label="USERS">指定用户</el-radio>
|
||||||
<el-radio label="ROLES">角色</el-radio>
|
<el-radio label="ROLES">角色</el-radio>
|
||||||
@@ -47,6 +48,17 @@
|
|||||||
</tree-select>
|
</tree-select>
|
||||||
</div>
|
</div>
|
||||||
</el-row>
|
</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>
|
<el-dialog title="候选用户" :visible.sync="userOpen" width="60%" append-to-body>
|
||||||
@@ -118,6 +130,15 @@ const userTaskForm = {
|
|||||||
// priority: ''
|
// priority: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const multiInstanceForm = {
|
||||||
|
completionCondition: "",
|
||||||
|
loopCardinality: "",
|
||||||
|
extensionElements: [],
|
||||||
|
asyncAfter: false,
|
||||||
|
asyncBefore: false,
|
||||||
|
exclusive: false
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "UserTask",
|
name: "UserTask",
|
||||||
props: {
|
props: {
|
||||||
@@ -151,7 +172,9 @@ export default {
|
|||||||
// 查询参数
|
// 查询参数
|
||||||
queryParams: {
|
queryParams: {
|
||||||
deptId: undefined
|
deptId: undefined
|
||||||
}
|
},
|
||||||
|
showMultiFlog: false,
|
||||||
|
multiLoopType: 'Null',
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -197,6 +220,7 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
this.getElementLoop(bpmnElementObj);
|
||||||
},
|
},
|
||||||
updateElementTask() {
|
updateElementTask() {
|
||||||
const taskAttr = Object.create(null);
|
const taskAttr = Object.create(null);
|
||||||
@@ -298,10 +322,14 @@ export default {
|
|||||||
userTaskForm.assignee = data.userId;
|
userTaskForm.assignee = data.userId;
|
||||||
userTaskForm.text = data.nickName;
|
userTaskForm.text = data.nickName;
|
||||||
userTaskForm.candidateUsers = null;
|
userTaskForm.candidateUsers = null;
|
||||||
|
this.showMultiFlog = false;
|
||||||
|
this.multiLoopType = 'Null';
|
||||||
|
this.changeMultiLoopType(this.multiLoopType);
|
||||||
} else {
|
} else {
|
||||||
userTaskForm.candidateUsers = this.selectedUserDate.map(k => k.userId).join() || null;
|
userTaskForm.candidateUsers = this.selectedUserDate.map(k => k.userId).join() || null;
|
||||||
userTaskForm.text = this.selectedUserDate.map(k => k.nickName).join() || null;
|
userTaskForm.text = this.selectedUserDate.map(k => k.nickName).join() || null;
|
||||||
userTaskForm.assignee = null;
|
userTaskForm.assignee = null;
|
||||||
|
this.showMultiFlog = true;
|
||||||
}
|
}
|
||||||
this.updateElementTask()
|
this.updateElementTask()
|
||||||
this.userOpen = false;
|
this.userOpen = false;
|
||||||
@@ -372,7 +400,53 @@ export default {
|
|||||||
userTaskForm.text = "流程发起人";
|
userTaskForm.text = "流程发起人";
|
||||||
}
|
}
|
||||||
this.updateElementTask();
|
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>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user