feat(流程管理): 完善流程

1.控制动态选择人员、组。
2.修复固定人员、组数据回显错误。
3.默认配置流程发起人表达式。
4.流程审批不同类型接收人、组处理。
5.加载表单数据回显问题
approve-sys
tony 3 years ago
parent 4fc2c78210
commit 52ed572d54

@ -2,26 +2,51 @@ package com.ruoyi.common.constant;
/**
*
*
* @author Xuan xuan
* @date 2021/4/17 22:46
*/
public class ProcessConstants {
/** 动态数据 */
/**
*
*/
public static final String DATA_TYPE = "dynamic";
/** 单个审批人 */
/**
*
*/
public static final String USER_TYPE_ASSIGNEE = "assignee";
/** 候选人 */
/**
*
*/
public static final String USER_TYPE_USERS = "candidateUsers";
/** 审批组 */
/**
*
*/
public static final String USER_TYPE_ROUPS = "candidateGroups";
/** 单个审批人 */
/**
*
*/
public static final String PROCESS_APPROVAL = "approval";
/**
* nameapace
*/
public static final String NAMASPASE = "http://flowable.org/bpmn";
/**
* dataType
*/
public static final String PROCESS_CUSTOM_DATA_TYPE = "dataType";
/**
* userType
*/
public static final String PROCESS_CUSTOM_USER_TYPE = "userType";
}

@ -1,10 +1,12 @@
package com.ruoyi.flowable.controller;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.flowable.domain.dto.FlowProcDefDto;
import com.ruoyi.flowable.domain.dto.FlowSaveXmlVo;
import com.ruoyi.flowable.service.IFlowDefinitionService;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.ISysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -14,6 +16,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
@ -45,6 +48,9 @@ public class FlowDefinitionController {
@Autowired
private ISysUserService userService;
@Resource
private ISysRoleService sysRoleService;
@GetMapping(value = "/list")
@ApiOperation(value = "流程定义列表", response = FlowProcDefDto.class)
@ -173,4 +179,11 @@ public class FlowDefinitionController {
return AjaxResult.success(list);
}
@ApiOperation(value = "指定流程办理组列表")
@GetMapping("/roleList")
public AjaxResult roleList(SysRole role) {
List<SysRole> list = sysRoleService.selectRoleList(role);
return AjaxResult.success(list);
}
}

@ -1,5 +1,6 @@
package com.ruoyi.flowable.domain.dto;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import lombok.Data;
@ -19,4 +20,6 @@ public class FlowNextDto implements Serializable {
private String vars;
private List<SysUser> userList;
private List<SysRole> roleList;
}

@ -11,11 +11,14 @@ import com.ruoyi.system.domain.SysForm;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.impl.DefaultProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
@ -153,10 +156,12 @@ public class FlowDefinitionServiceImpl extends FlowServiceFactory implements IFl
try {
// 设置流程发起人Id到流程中
Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
identityService.setAuthenticatedUserId(userId.toString());
variables.put("initiator",userId);
// identityService.setAuthenticatedUserId(userId.toString());
Authentication.setAuthenticatedUserId(userId.toString());
variables.put("skip", true);
variables.put("INITIATOR",userId.toString());
variables.put("_FLOWABLE_SKIP_EXPRESSION_ENABLED", true);
runtimeService.startProcessInstanceById(procDefId, variables);
ProcessInstance processInstance = runtimeService.startProcessInstanceById(procDefId, variables);
return AjaxResult.success("流程启动成功");
} catch (Exception e) {
e.printStackTrace();

@ -105,7 +105,7 @@ public class FlowTaskServiceImpl extends FlowServiceFactory implements IFlowTask
// 设置任务审批人员
taskService.setAssignee(task.getTaskId(), userId.toString());
// 提交任务
taskService.complete(task.getTaskId(),task.getValues());
taskService.complete(task.getTaskId(), task.getValues());
}
@ -753,6 +753,9 @@ public class FlowTaskServiceImpl extends FlowServiceFactory implements IFlowTask
// 第一次申请获取初始化表单
if (StringUtils.isNotBlank(deployId)) {
SysForm sysForm = sysInstanceFormService.selectSysDeployFormByDeployId(deployId);
if (Objects.isNull(sysForm)){
return AjaxResult.error("请先配置流程表单");
}
map.put("formData", JSONObject.parseObject(sysForm.getFormContent()));
}
return AjaxResult.success(map);
@ -861,25 +864,40 @@ public class FlowTaskServiceImpl extends FlowServiceFactory implements IFlowTask
FlowElement targetFlow = sequenceFlow.getTargetFlowElement();
if (targetFlow instanceof UserTask) {
// 当流程设计时未指定任务接受人员/组时 判定为用户动态选择下一任务审批人
// 读取自定义属性 动态选择下一任务审批人
// todo 1. 读取自定义节点属性来验证是否动态选择审批人
// 2. 验证表达式
String dataType = targetFlow.getAttributeValue("http://flowable.org/bpmn", "dataType");
String userType = targetFlow.getAttributeValue("http://flowable.org/bpmn", "userType");
// Map<String, List<ExtensionAttribute>> attributes = targetFlow.getAttributes();
// List<ExtensionAttribute> extensionAttributes = attributes.get("dataType");
// for (ExtensionAttribute attribute : extensionAttributes) {
// String value = attribute.getValue();
// }
if (ProcessConstants.DATA_TYPE.equals(dataType)){
if (ProcessConstants.USER_TYPE_ASSIGNEE.equals(userType)){
String dataType = targetFlow.getAttributeValue(ProcessConstants.NAMASPASE, ProcessConstants.PROCESS_CUSTOM_DATA_TYPE);
String userType = targetFlow.getAttributeValue(ProcessConstants.NAMASPASE, ProcessConstants.PROCESS_CUSTOM_USER_TYPE);
if (ProcessConstants.DATA_TYPE.equals(dataType)) {
// 指定单个人员
if (ProcessConstants.USER_TYPE_ASSIGNEE.equals(userType)) {
List<SysUser> list = sysUserService.selectUserList(new SysUser());
flowNextDto.setVars(ProcessConstants.PROCESS_APPROVAL);
flowNextDto.setType(ProcessConstants.USER_TYPE_ASSIGNEE);
flowNextDto.setUserList(list);
}
// 候选人员(多个)
if (ProcessConstants.USER_TYPE_USERS.equals(userType)) {
List<SysUser> list = sysUserService.selectUserList(new SysUser());
flowNextDto.setVars(ProcessConstants.PROCESS_APPROVAL);
flowNextDto.setType(ProcessConstants.USER_TYPE_USERS);
flowNextDto.setUserList(list);
}
// 候选组
if (ProcessConstants.USER_TYPE_ROUPS.equals(userType)) {
List<SysRole> sysRoles = sysRoleService.selectRoleAll();
flowNextDto.setVars(ProcessConstants.PROCESS_APPROVAL);
flowNextDto.setType(ProcessConstants.USER_TYPE_ROUPS);
flowNextDto.setRoleList(sysRoles);
}
}
} else if (targetFlow instanceof EndEvent) {
return AjaxResult.success("流程已完结", null);
}
}
}

@ -44,6 +44,15 @@ export function userList(query) {
})
}
// 指定流程办理组列表
export function roleList(query) {
return request({
url: '/flowable/definition/roleList',
method: 'get',
params: query
})
}
// 读取xml文件
export function readXml(deployId) {
return request({

@ -9,6 +9,7 @@
:users="users"
:groups="groups"
:categorys="categorys"
@dataType="dataType"
/>
</div>
</template>
@ -134,6 +135,10 @@ export default {
})
}
})
},
/** 获取数据类型 */
dataType(data){
this.$emit('dataType', data)
}
}
}

@ -53,7 +53,7 @@ export default {
xType: 'select',
name: 'processCategory',
label: '流程分类',
dic: { data: _this.categorys, label: 'name', value: 'id' }
dic: { data: _this.categorys, label: 'dictLabel', value: 'dictValue' }
},
{
xType: 'input',

@ -72,7 +72,9 @@ export default {
},
watch: {
'formData.initiator': function(val) {
if (val === '') val = null
// if (val === '') val = null
//
if (val === '') val = 'INITIATOR'
this.updateProperties({ 'flowable:initiator': val })
},
'formData.formKey': function(val) {
@ -81,6 +83,7 @@ export default {
}
},
created() {
this.updateProperties({ 'flowable:initiator': 'INITIATOR' })
this.formData = commonParse(this.element)
}
}

@ -125,7 +125,8 @@ export default {
name: 'dataType',
label: '指定方式',
dic: _this.dataTypeOption,
show: !!_this.showConfig.dataType
show: !!_this.showConfig.dataType,
rules: [{ required: true, message: '请指定方式' }]
},
// {
// xType: 'input',
@ -171,7 +172,7 @@ export default {
multiple: true,
allowCreate: true,
filterable: true,
dic: { data: _this.groups, label: 'name', value: 'id' },
dic: { data: _this.groups, label: 'roleName', value: 'roleId' },
show: !!_this.showConfig.candidateGroups && _this.formData.userType === 'candidateGroups'
},
{
@ -287,9 +288,20 @@ export default {
const that = this
this.updateProperties({'flowable:dataType': val})
if (val === 'dynamic') {
debugger
this.updateProperties({'flowable:userType': that.formData.userType})
}
//
const types = ['assignee', 'candidateUsers', 'candidateGroups']
types.forEach(type => {
delete this.element.businessObject.$attrs[`flowable:${type}`]
delete this.formData[type]
})
//
const params = {
dataType: val,
userType: this.formData.userType
}
this.$emit('dataType', params)
},
'formData.assignee': function(val) {
if (this.formData.userType !== 'assignee') {

@ -41,7 +41,7 @@
<div ref="canvas" class="canvas" />
</el-main>
<el-aside style="width: 400px; min-height: 650px; background-color: #f0f2f5">
<panel v-if="modeler" :modeler="modeler" :users="users" :groups="groups" :categorys="categorys" />
<panel v-if="modeler" :modeler="modeler" :users="users" :groups="groups" :categorys="categorys" @dataType="dataType" />
</el-aside>
</el-container>
</el-container>
@ -290,6 +290,7 @@ export default {
async showXML() {
try {
const { xml } = await this.modeler.saveXML({ format: true })
debugger
this.$emit('showXML',xml)
} catch (err) {
console.log(err)
@ -329,6 +330,10 @@ export default {
a.download = filename
a.click()
window.URL.revokeObjectURL(url)
},
/** 获取数据类型 */
dataType(data){
this.$emit('dataType', data)
}
}
}

@ -122,10 +122,17 @@
<el-button
size="mini"
type="text"
icon="el-icon-video-pause"
icon="el-icon-connection"
v-if="scope.row.formId == null"
@click="handleAddForm(scope.row)"
>配置表单</el-button>
<!-- <el-button-->
<!-- size="mini"-->
<!-- type="text"-->
<!-- icon="el-icon-connection"-->
<!-- v-else-->
<!-- @click="handleAddForm(scope.row)"-->
<!-- >更换表单</el-button>-->
<el-button
size="mini"
type="text"
@ -402,6 +409,19 @@ export default {
this.formDeployTitle = "挂载表单";
})
},
// /** */
// handleEditForm(row){
// this.formDeployParam.deployId = row.deploymentId
// const queryParams = {
// pageNum: 1,
// pageSize: 10
// }
// listForm(queryParams).then(res =>{
// this.formList = res.rows;
// this.formDeployOpen = true;
// this.formDeployTitle = "";
// })
// },
/** 挂载表单 */
submitFormDeploy(){
addDeployForm(this.formDeployParam).then(res =>{

@ -9,6 +9,7 @@
:is-view="false"
@save="save"
@showXML="showXML"
@dataType="dataType"
/>
<!--在线查看xml-->
<el-dialog :title="xmlTitle" :visible.sync="xmlOpen" width="60%" append-to-body>
@ -23,11 +24,12 @@
</div>
</template>
<script>
import { readXml, saveXml, userList } from "@/api/flowable/definition";
import {readXml, roleList, saveXml, userList} from "@/api/flowable/definition";
import bpmnModeler from '@/components/Process/index'
import vkbeautify from 'vkbeautify'
import Hljs from 'highlight.js'
import 'highlight.js/styles/atom-one-dark.css'
export default {
name: "Model",
components: {
@ -49,21 +51,9 @@ export default {
xmlOpen: false,
xmlTitle: '',
xmlContent: '',
users: [
{ nickName: "#{initiator}", userId: "#{initiator}" },
{nickName: "#{approval}", userId: "#{approval}"}
// { name: "", id: "2" },
// { name: "", id: "100" },
],
groups: [
{ name: "超级管理员", id: "1" },
{ name: "普通角色", id: "2" },
{ name: "管理员", id: "100" },
],
categorys: [
{ name: "请假", id: "leave" },
{ name: "财务", id: "finance" },
],
users: [],
groups: [],
categorys: [],
};
},
created () {
@ -72,7 +62,10 @@ export default {
if (deployId) {
this.getModelDetail(deployId);
}
this.getUserList()
this.getDicts("sys_process_category").then(res => {
this.categorys = res.data;
});
this.getDataList()
},
methods: {
/** xml 文件 */
@ -89,33 +82,60 @@ export default {
category: data.process.category,
xml: data.xml
}
debugger
// saveXml(params).then(res => {
// this.$message(res.msg)
// //
// this.$store.dispatch("tagsView/delView", this.$route);
// this.$router.go(-1)
// })
saveXml(params).then(res => {
this.$message(res.msg)
//
this.$store.dispatch("tagsView/delView", this.$route);
this.$router.go(-1)
})
},
/** 指定流程办理人员列表 */
getUserList() {
getDataList() {
// todo
// const params = {
//
// }
userList().then(res =>{
res.data.forEach(val =>{
let obj = {};
obj.userId = val.userId;
obj.nickName = val.nickName;
this.users.push(obj)
val.userId = val.userId.toString();
})
})
this.users = res.data;
let arr = {nickName: "流程发起人", userId: "${INITIATOR}"}
this.users.push(arr)
});
roleList().then(res =>{
res.data.forEach(val =>{
val.roleId = val.roleId.toString();
})
this.groups = res.data;
});
},
/** 展示xml */
showXML(data){
this.xmlTitle = 'xml查看';
this.xmlOpen = true;
debugger
this.xmlContent = vkbeautify.xml(data);
},
/** 获取数据类型 */
dataType(data){
this.users = [];
this.groups = [];
if (data) {
if (data.dataType === 'dynamic') {
if (data.userType === 'assignee') {
this.users = [{nickName: "${INITIATOR}", userId: "${INITIATOR}"},
{nickName: "#{approval}", userId: "#{approval}"}
]
} else if (data.userType === 'candidateUsers') {
this.users = [ {nickName: "#{approval}", userId: "#{approval}"}]
} else {
this.groups = [{roleName: "#{approval}", roleId: "#{approval}"}]
}
} else {
this.getDataList()
}
}
}
},
};

@ -66,7 +66,6 @@
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="表单主键" align="center" prop="formId" />
<el-table-column label="表单名称" align="center" prop="formName" />
<!-- <el-table-column label="表单内容" align="center" prop="formContent" />-->
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">

@ -25,7 +25,7 @@
</el-radio-group>
</el-form-item>
<el-form-item label="任务接收" prop="targetKey" v-show="taskForm.noUserShow">
<el-radio-group v-model="taskForm.assignee">
<el-radio-group @change="handleCheckChange" v-model="assignee">
<<el-radio-button
v-for="item in userList"
:key="item.userId"
@ -33,6 +33,24 @@
>{{item.nickName}}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="候选人员" prop="targetKey" v-show="taskForm.allUserShow">
<el-checkbox-group @change="handleCheckChange" v-model="users">
<<el-checkbox
v-for="item in userList"
:key="item.userId"
:label="item.userId"
>{{item.nickName}}</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="候选组" prop="targetKey" v-show="taskForm.allGroupShow">
<el-radio-group @change="handleCheckChange" v-model="assignee">
<<el-radio-button
v-for="item in roleList"
:key="item.roleId"
:label="item.roleId"
>{{item.roleName}}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="审批意见" prop="comment" :rules="[{ required: true, message: '请输入意见', trigger: 'blur' }]">
<el-input style="width: 50%" type="textarea" v-model="taskForm.comment" placeholder="请输入意见"/>
</el-form-item>
@ -106,7 +124,7 @@
</template>
<script>
import { flowRecord } from "@/api/flowable/finished";
import {flowRecord} from "@/api/flowable/finished";
import Parser from '@/components/parser/Parser'
import {definitionStart, getProcessVariables, userList } from "@/api/flowable/definition";
import {complete, rejectTask, returnList, returnTask, getNextFlowNode} from "@/api/flowable/todo";
@ -129,16 +147,20 @@ export default {
returnTaskShow: false, // 退
defaultTaskShow: true, //
noUserShow: false, //
allUserShow: false, //
allGroupShow: false, //
comment:"", //
procInsId: "", //
instanceId: "", //
deployId: "", //
taskId: "" ,//
procDefId: "", //
assignee: null,
vars: "",
},
userList:[], //
roleList:[], //
users:[], //
assignee: null,
formConf: {}, //
formConfOpen: false, //
variables: [], //
@ -193,10 +215,23 @@ export default {
return "#b3bdbb";
}
},
handleCheckChange(val){
console.log(val)
if (val instanceof Array) {
this.taskForm.values = {
"approval": val.join(',')
}
}else {
this.taskForm.values = {
"approval": val
}
}
},
/** 流程流转记录 */
getFlowRecordList(procInsId, deployId) {
const params = {procInsId: procInsId, deployId: deployId}
flowRecord(params).then(res => {
debugger
this.flowRecordList = res.data.flowList;
//
if (res.data.formData) {
@ -210,6 +245,8 @@ export default {
if (procInsId) {
this.src = process.env.VUE_APP_BASE_API + "/flowable/task/diagram/" + procInsId;
}
}).catch(res => {
this.goBack();
})
},
fillFormData(form, data) {
@ -223,18 +260,30 @@ export default {
/** 获取流程变量内容 */
processVariables(taskId) {
if (taskId) {
//
getProcessVariables(taskId).then(res => {
// this.variables = res.data.variables;
this.variablesData = res.data.variables;
this.variableOpen = true
});
// todo
const params = {
taskId: taskId
}
getNextFlowNode(params).then(res => {
if (res.data.userList){
const data = res.data;
if (data) {
if (data.type === 'assignee') {
this.userList = res.data.userList;
this.taskForm.noUserShow = true;
} else if (data.type === 'candidateUsers') {
this.userList = res.data.userList;
this.taskForm.allUserShow = true;
} else {
this.roleList = res.data.roleList
this.taskForm.allGroupShow = true;
}
}
})
}
@ -243,10 +292,6 @@ export default {
handleComplete() {
this.$refs["taskForm"].validate(valid => {
if (valid) {
let values = {
"approval": this.taskForm.assignee
}
this.taskForm.values =values
complete(this.taskForm).then(response => {
this.msgSuccess(response.msg);
this.goBack();

@ -265,22 +265,25 @@ export default {
immediate: true
}
},
mounted() {
const formId = this.$route.query && this.$route.query.formId;
if (Array.isArray(drawingListInDB) && drawingListInDB.length > 0) {
this.drawingList = drawingListInDB
} else {
this.drawingList = drawingDefalut
}
this.activeFormItem(this.drawingList[0])
// if (formConfInDB) {
// this.formConf = formConfInDB
// }
// // if (formConfInDB) {
// // this.formConf = formConfInDB
// // }
this.drawingList = [];
const formId = this.$route.query && this.$route.query.formId;
if (formId) {
getForm(formId).then(res =>{
this.formConf = JSON.parse(res.data.formContent)
this.formConf = JSON.parse(res.data.formContent);
// this.drawingList = this.formConf.fields;
this.form = res.data;
})
}else {
if (formConfInDB) {
this.formConf = formConfInDB
@ -536,6 +539,8 @@ export default {
this.msgSuccess("新增成功");
});
}
this.drawingList = []
this.idGlobal = 100
this.open = false;
//
this.$store.dispatch("tagsView/delView", this.$route);

Loading…
Cancel
Save