赞
踩
更多ruoyi-nbcio功能请看演示系统
gitee源代码地址
前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio
演示地址:RuoYi-Nbcio后台管理系统
1、前端代码,主要修改下面这个文件,如下:
说明几点:
1.1 增加界面
1.2 增加自定义条件的逻辑与保存
- <template>
- <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>
- <el-radio label="DEPTS">部门</el-radio>
- <el-radio label="INITIATOR">发起人</el-radio>
- <el-radio label="MANAGER">部门经理</el-radio>
- </el-radio-group>
- </el-row>
- <el-row>
- <div v-if="dataType === 'USERS'">
- <el-tag v-for="userText in selectedUser.text" :key="userText" effect="plain">
- {{userText}}
- </el-tag>
- <div class="element-drawer__button">
- <el-button size="mini" type="primary" icon="el-icon-plus" @click="onSelectUsers()">添加用户</el-button>
- </div>
- </div>
- <div v-if="dataType === 'ROLES'">
- <el-select v-model="roleIds" multiple size="mini" placeholder="请选择 角色" @change="changeSelectRoles">
- <el-option
- v-for="item in roleOptions"
- :key="item.roleId"
- :label="item.roleName"
- :value="`ROLE${item.roleId}`"
- :disabled="item.status === 1">
- </el-option>
- </el-select>
- </div>
- <div v-if="dataType === 'DEPTS'">
- <tree-select
- :width="320"
- :height="400"
- size="mini"
- :data="deptTreeData"
- :defaultProps="deptProps"
- multiple
- clearable
- checkStrictly
- nodeKey="id"
- :checkedKeys="deptIds"
- @change="checkedDeptChange">
- </tree-select>
- </div>
- </el-row>
- <el-row>
- <div v-show="showMultiFlog">
- <el-divider />
- <h4><b>多实例审批方式</b></h4>
- <el-row>
- <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-row><el-radio label="CustomMultiInstance">自定义会签条件</el-radio></el-row>
- </el-radio-group>
- </el-row>
- <el-row v-if="multiLoopType === 'CustomMultiInstance'">
- <el-input v-model="CustomCompletionCondition" clearable @change="updateLoopCondition" />
- </el-row>
- <el-row v-if="multiLoopType !== 'Null'">
- <el-tooltip content="开启后,实例需按顺序轮流审批" placement="top-start" @click.stop.prevent>
- <i class="header-icon el-icon-info"></i>
- </el-tooltip>
- <span class="custom-label">顺序审批:</span>
- <el-switch v-model="isSequential" @change="changeMultiLoopType()" />
- </el-row>
- </div>
- </el-row>
-
- <!-- 候选用户弹窗 -->
- <el-dialog title="候选用户" :visible.sync="userOpen" width="60%" append-to-body>
- <el-row type="flex" :gutter="20">
- <!--部门数据-->
- <el-col :span="7">
- <el-card shadow="never" style="height: 100%">
- <div slot="header">
- <span>部门列表</span>
- </div>
- <div class="head-container">
- <el-input
- v-model="deptName"
- placeholder="请输入部门名称"
- clearable
- size="small"
- prefix-icon="el-icon-search"
- style="margin-bottom: 20px"
- />
- <el-tree
- :data="deptOptions"
- :props="deptProps"
- :expand-on-click-node="false"
- :filter-node-method="filterNode"
- ref="tree"
- default-expand-all
- @node-click="handleNodeClick"
- />
- </div>
- </el-card>
- </el-col>
- <el-col :span="17">
- <el-table ref="multipleTable" height="600" :data="userTableList" border @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="50" align="center" />
- <el-table-column label="用户名" align="center" prop="nickName" />
- <el-table-column label="部门" align="center" prop="dept.deptName" />
- </el-table>
- <pagination
- :total="userTotal"
- :page.sync="queryParams.pageNum"
- :limit.sync="queryParams.pageSize"
- @pagination="getUserList"
- />
- </el-col>
- </el-row>
- <div slot="footer" class="dialog-footer">
- <el-button type="primary" @click="handleTaskUserComplete">确 定</el-button>
- <el-button @click="userOpen = false">取 消</el-button>
- </div>
- </el-dialog>
- </div>
-
- </template>
-
- <script>
- import { listUser, deptTreeSelect } from "@/api/system/user";
- import { listRole } from "@/api/system/role";
- import TreeSelect from "@/components/TreeSelect";
-
- const userTaskForm = {
- dataType: '',
- assignee: '',
- candidateUsers: '',
- candidateGroups: '',
- text: '',
- // dueDate: '',
- // followUpDate: '',
- // priority: ''
- }
-
- export default {
- name: "UserTask",
- props: {
- id: String,
- type: String
- },
- components: { TreeSelect },
- data() {
- return {
- loading: false,
- dataType: 'USERS',
- selectedUser: {
- ids: [],
- text: []
- },
- userOpen: false,
- deptName: undefined,
- deptOptions: [],
- deptProps: {
- children: "children",
- label: "label"
- },
- deptTempOptions: [],
- userTableList: [],
- userTotal: 0,
- selectedUserDate: [],
- roleOptions: [],
- roleIds: [],
- deptTreeData: [],
- deptIds: [],
- // 查询参数
- queryParams: {
- deptId: undefined
- },
- showMultiFlog: false,
- isSequential: false,
- multiLoopType: 'Null',
- CustomCompletionCondition: '${nrOfCompletedInstances/nrOfInstances>=1}',
- };
- },
- watch: {
- id: {
- immediate: true,
- handler() {
- this.bpmnElement = window.bpmnInstances.bpmnElement;
- this.$nextTick(() => this.resetTaskForm());
- }
- },
- // 根据名称筛选部门树
- deptName(val) {
- this.$refs.tree.filter(val);
- }
- },
- beforeDestroy() {
- this.bpmnElement = null;
- },
- methods: {
- resetTaskForm() {
- const bpmnElementObj = this.bpmnElement?.businessObject;
- if (!bpmnElementObj) {
- return;
- }
- this.clearOptionsData()
- this.dataType = bpmnElementObj['dataType'];
- if (this.dataType === 'USERS') {
- let userIdData = bpmnElementObj['candidateUsers'] || bpmnElementObj['assignee'];
- let userText = bpmnElementObj['text'] || [];
- if (userIdData && userIdData.toString().length > 0 && userText && userText.length > 0) {
- this.selectedUser.ids = userIdData?.toString().split(',');
- this.selectedUser.text = userText?.split(',');
- }
- if (this.selectedUser.ids.length > 1) {
- this.showMultiFlog = true;
- }
- } else if (this.dataType === 'ROLES') {
- this.getRoleOptions();
- let roleIdData = bpmnElementObj['candidateGroups'] || [];
- if (roleIdData && roleIdData.length > 0) {
- this.roleIds = roleIdData.split(',')
- }
- this.showMultiFlog = true;
- } else if (this.dataType === 'DEPTS') {
- this.getDeptTreeData();
- let deptIdData = bpmnElementObj['candidateGroups'] || [];
- if (deptIdData && deptIdData.length > 0) {
- this.deptIds = deptIdData.split(',');
- }
- this.showMultiFlog = true;
- }
- this.getElementLoop(bpmnElementObj);
- },
- /**
- * 清空选项数据
- */
- clearOptionsData() {
- this.selectedUser.ids = [];
- this.selectedUser.text = [];
- this.roleIds = [];
- this.deptIds = [];
- },
- // 完成条件
- updateLoopCondition(condition) {
- },
- /**
- * 更新节点数据
- */
- updateElementTask() {
- const taskAttr = Object.create(null);
- for (let key in userTaskForm) {
- taskAttr[key] = userTaskForm[key];
- }
- window.bpmnInstances.modeling.updateProperties(this.bpmnElement, taskAttr);
- },
- /**
- * 查询部门下拉树结构
- */
- getDeptOptions() {
- return new Promise((resolve, reject) => {
- if (!this.deptOptions || this.deptOptions.length <= 0) {
- deptTreeSelect().then(response => {
- this.deptTempOptions = response.data;
- this.deptOptions = response.data;
- resolve()
- })
- } else {
- reject()
- }
- });
- },
- /**
- * 查询部门下拉树结构(含部门前缀)
- */
- getDeptTreeData() {
- function refactorTree(data) {
- return data.map(node => {
- let treeData = { id: `DEPT${node.id}`, label: node.label, parentId: node.parentId, weight: node.weight };
- if (node.children && node.children.length > 0) {
- treeData.children = refactorTree(node.children);
- }
- return treeData;
- });
- }
- return new Promise((resolve, reject) => {
- if (!this.deptTreeData || this.deptTreeData.length <= 0) {
- this.getDeptOptions().then(() => {
- this.deptTreeData = refactorTree(this.deptOptions);
- resolve()
- }).catch(() => {
- reject()
- })
- } else {
- resolve()
- }
- })
- },
- /**
- * 查询部门下拉树结构
- */
- getRoleOptions() {
- if (!this.roleOptions || this.roleOptions.length <= 0) {
- listRole().then(response => this.roleOptions = response.rows);
- }
- },
- /** 查询用户列表 */
- getUserList() {
- listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
- this.userTableList = response.rows;
- this.userTotal = response.total;
- });
- },
- // 筛选节点
- filterNode(value, data) {
- if (!value) return true;
- return data.label.indexOf(value) !== -1;
- },
- // 节点单击事件
- handleNodeClick(data) {
- this.queryParams.deptId = data.id;
- this.getUserList();
- },
- // 关闭标签
- handleClose(tag) {
- this.selectedUserDate.splice(this.selectedUserDate.indexOf(tag), 1);
- this.$refs.multipleTable.toggleRowSelection(tag);
- },
- // 多选框选中数据
- handleSelectionChange(selection) {
- this.selectedUserDate = selection;
- },
- onSelectUsers() {
- this.selectedUserDate = []
- this.$refs.multipleTable?.clearSelection();
- this.getDeptOptions();
- this.userOpen = true;
- },
- handleTaskUserComplete() {
- if (!this.selectedUserDate || this.selectedUserDate.length <= 0) {
- this.$modal.msgError('请选择用户');
- return;
- }
- userTaskForm.dataType = 'USERS';
- this.selectedUser.text = this.selectedUserDate.map(k => k.nickName) || [];
- if (this.selectedUserDate.length === 1) {
- let data = this.selectedUserDate[0];
- userTaskForm.assignee = data.userName;
- userTaskForm.text = data.nickName;
- userTaskForm.candidateUsers = null;
- this.showMultiFlog = false;
- this.multiLoopType = 'Null';
- this.changeMultiLoopType();
- } else {
- userTaskForm.candidateUsers = this.selectedUserDate.map(k => k.userName).join() || null;
- userTaskForm.text = this.selectedUserDate.map(k => k.nickName).join() || null;
- userTaskForm.assignee = null;
- this.showMultiFlog = true;
- }
- this.updateElementTask()
- this.userOpen = false;
- },
- changeSelectRoles(val) {
- let groups = null;
- let text = null;
- if (val && val.length > 0) {
- userTaskForm.dataType = 'ROLES';
- groups = val.join() || null;
- let textArr = this.roleOptions.filter(k => val.indexOf(`ROLE${k.roleId}`) >= 0);
- text = textArr?.map(k => k.roleName).join() || null;
- } else {
- userTaskForm.dataType = null;
- this.multiLoopType = 'Null';
- }
- userTaskForm.candidateGroups = groups;
- userTaskForm.text = text;
- this.updateElementTask();
- this.changeMultiLoopType();
- },
- checkedDeptChange(checkedIds) {
- let groups = null;
- let text = null;
- this.deptIds = checkedIds;
- if (checkedIds && checkedIds.length > 0) {
- userTaskForm.dataType = 'DEPTS';
- groups = checkedIds.join() || null;
- let textArr = []
- let treeStarkData = JSON.parse(JSON.stringify(this.deptTreeData));
- checkedIds.forEach(id => {
- let stark = []
- stark = stark.concat(treeStarkData);
- while(stark.length) {
- let temp = stark.shift();
- if(temp.children) {
- stark = temp.children.concat(stark);
- }
- if(id === temp.id) {
- textArr.push(temp);
- }
- }
- })
- text = textArr?.map(k => k.label).join() || null;
- } else {
- userTaskForm.dataType = null;
- this.multiLoopType = 'Null';
- }
- userTaskForm.candidateGroups = groups;
- userTaskForm.text = text;
- this.updateElementTask();
- this.changeMultiLoopType();
- },
- changeDataType(val) {
- if (val === 'ROLES' || val === 'DEPTS' || (val === 'USERS' && this.selectedUser.ids.length > 1)) {
- this.showMultiFlog = true;
- } else {
- this.showMultiFlog = false;
- }
- this.multiLoopType = 'Null';
- this.changeMultiLoopType();
- // 清空 userTaskForm 所有属性值
- Object.keys(userTaskForm).forEach(key => userTaskForm[key] = null);
- userTaskForm.dataType = val;
- console.log("changeDataType this.selectedUser",this.selectedUser);
- if (val === 'USERS') {
- if (this.selectedUser && this.selectedUser.ids && this.selectedUser.ids.length > 0) {
- if (this.selectedUser.ids.length === 1) {
- userTaskForm.assignee = this.selectedUser.ids[0];
- } else {
- userTaskForm.candidateUsers = this.selectedUser.ids.join()
- }
- userTaskForm.text = this.selectedUser.text?.join() || null
- }
- } else if (val === 'ROLES') {
- this.getRoleOptions();
- if (this.roleIds && this.roleIds.length > 0) {
- userTaskForm.candidateGroups = this.roleIds.join() || null;
- let textArr = this.roleOptions.filter(k => this.roleIds.indexOf(`ROLE${k.roleId}`) >= 0);
- userTaskForm.text = textArr?.map(k => k.roleName).join() || null;
- }
- } else if (val === 'DEPTS') {
- this.getDeptTreeData();
- if (this.deptIds && this.deptIds.length > 0) {
- userTaskForm.candidateGroups = this.deptIds.join() || null;
- let textArr = []
- let treeStarkData = JSON.parse(JSON.stringify(this.deptTreeData));
- this.deptIds.forEach(id => {
- let stark = []
- stark = stark.concat(treeStarkData);
- while(stark.length) {
- let temp = stark.shift();
- if(temp.children) {
- stark = temp.children.concat(stark);
- }
- if(id === temp.id) {
- textArr.push(temp);
- }
- }
- })
- userTaskForm.text = textArr?.map(k => k.label).join() || null;
- }
- } else if (val === 'MANAGER') {
- userTaskForm.assignee = "${DepManagerHandler.getUser(execution)}";
- userTaskForm.text = "部门经理";
- } else if (val === 'INITIATOR') {
- userTaskForm.assignee = "${initiator}";
- userTaskForm.text = "流程发起人";
- }
- this.updateElementTask();
- },
- getElementLoop(businessObject) {
- if (!businessObject.loopCharacteristics) {
- this.multiLoopType = "Null";
- return;
- }
- this.isSequential = businessObject.loopCharacteristics.isSequential;
- if (businessObject.loopCharacteristics.completionCondition) {
- if (businessObject.loopCharacteristics.completionCondition.body === "${nrOfCompletedInstances >= nrOfInstances}") {
- this.multiLoopType = "SequentialMultiInstance";
- } else if (businessObject.loopCharacteristics.completionCondition.body === "${nrOfCompletedInstances > 0}") {
- this.multiLoopType = "ParallelMultiInstance";
- } else {
- this.multiLoopType = "CustomMultiInstance";
- }
- }
- },
- changeMultiLoopType() {
- // 取消多实例配置
- if (this.multiLoopType === "Null") {
- window.bpmnInstances.modeling.updateProperties(this.bpmnElement, { loopCharacteristics: null, assignee: null });
- return;
- }
- this.multiLoopInstance = window.bpmnInstances.moddle.create("bpmn:MultiInstanceLoopCharacteristics", { isSequential: this.isSequential });
- // 更新多实例配置
- window.bpmnInstances.modeling.updateProperties(this.bpmnElement, {
- loopCharacteristics: this.multiLoopInstance,
- assignee: '${assignee}'
- });
- // 完成条件
- let completionCondition = null;
- // 会签
- if (this.multiLoopType === "SequentialMultiInstance") {
- completionCondition = window.bpmnInstances.moddle.create("bpmn:FormalExpression", { body: "${nrOfCompletedInstances >= nrOfInstances}" });
- }
- // 或签
- if (this.multiLoopType === "ParallelMultiInstance") {
- completionCondition = window.bpmnInstances.moddle.create("bpmn:FormalExpression", { body: "${nrOfCompletedInstances > 0}" });
- }
- // 自定义会签
- if (this.multiLoopType === "CustomMultiInstance") {
- completionCondition = window.bpmnInstances.moddle.create("bpmn:FormalExpression", { body: this.CustomCompletionCondition });
- }
- // 更新模块属性信息
- window.bpmnInstances.modeling.updateModdleProperties(this.bpmnElement, this.multiLoopInstance, {
- collection: '${multiInstanceHandler.getUserNames(execution)}',
- elementVariable: 'assignee',
- completionCondition
- });
- },
- }
- };
- </script>
- <style scoped lang="scss">
- .el-row .el-radio-group {
- margin-bottom: 15px;
- .el-radio {
- line-height: 28px;
- }
- }
- .el-tag {
- margin-bottom: 10px;
- + .el-tag {
- margin-left: 10px;
- }
- }
- .custom-label {
- padding-left: 5px;
- font-weight: 500;
- font-size: 14px;
- color: #606266;
- }
- </style>
2、增加一个方法通过多ids来获取userNames,因为现在流程都是通过userName来执行流转
- @Override
- public List<String> selectUserNames(List<Long> userIds) {
- List<SysUser> listuser = baseMapper.selectBatchIds(userIds);
- List<String> userNames = new ArrayList<>();
- for(SysUser sysuser: listuser) {
- userNames.add(sysuser.getUserName());
- }
- return userNames;
-
- }
- }
3、多实例处理类修改如下
- /**
- * 多实例处理类
- *
- * @author nbacheng
- */
- @AllArgsConstructor
- @Component("multiInstanceHandler")
- public class MultiInstanceHandler {
-
- public Set<String> getUserNames(DelegateExecution execution) {
- Set<String> candidateUserNames = 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())) {
- // 添加候选用户
- candidateUserNames.addAll(userTask.getCandidateUsers());
- } else if (CollUtil.isNotEmpty(userTask.getCandidateGroups())) {
- // 获取组的ID,角色ID集合或部门ID集合
- List<Long> groups = userTask.getCandidateGroups().stream()
- .map(item -> Long.parseLong(item.substring(4)))
- .collect(Collectors.toList());
- List<Long> userIds = new ArrayList<>();
- List<String> userNames = new ArrayList<>();
- if ("ROLES".equals(dataType)) {
- // 通过角色id,获取所有用户id集合
- LambdaQueryWrapper<SysUserRole> lqw = Wrappers.lambdaQuery(SysUserRole.class).select(SysUserRole::getUserId).in(SysUserRole::getRoleId, groups);
- userIds = SimpleQuery.list(lqw, SysUserRole::getUserId);
- } else if ("DEPTS".equals(dataType)) {
- // 通过部门id,获取所有用户id集合
- LambdaQueryWrapper<SysUser> lqw = Wrappers.lambdaQuery(SysUser.class).select(SysUser::getUserId).in(SysUser::getDeptId, groups);
- userIds = SimpleQuery.list(lqw, SysUser::getUserId);
- }
- // 添加候选用户
- ISysUserService sysUserService = SpringContextUtils.getBean(ISysUserService.class);
- userNames = sysUserService.selectUserNames(userIds);
- userNames.forEach(userName -> candidateUserNames.add(userName));
- }
- }
- return candidateUserNames;
- }
- }
4、效果图如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。