Compare commits

..

2 Commits

Author SHA1 Message Date
acddc78560 Merge branch 'master' into zjw 2024-09-04 14:14:18 +08:00
fa8e535483 工作流修改 2024-09-04 10:35:23 +08:00
8 changed files with 319 additions and 43 deletions

View File

@ -12,7 +12,7 @@ public interface BpmnModelConstants {
/** /**
* BPMN 中的命名空间 * BPMN 中的命名空间
*/ */
String NAMESPACE = "http://flowable.org/bpmn"; String NAMESPACE = null;
/** /**
* BPMN UserTask 的扩展属性用于标记候选人策略 * BPMN UserTask 的扩展属性用于标记候选人策略

View File

@ -18,7 +18,7 @@ export function getProcessDefinitionList(query) {
export function getProcessDefinitionBpmnXML(id) { export function getProcessDefinitionBpmnXML(id) {
return request({ return request({
url: '/bpm/process-definition/get-bpmn-xml?id=' + id, url: '/bpm/process-definition/get?id=' + id,
method: 'get' method: 'get'
}) })
} }

View File

@ -21,11 +21,12 @@
替代提供更好的表单设计功能 替代提供更好的表单设计功能
</el-collapse-item> </el-collapse-item>
<el-collapse-item name="task" v-if="elementType.indexOf('Task') !== -1" key="task"> <el-collapse-item name="task" v-if="elementType.indexOf('Task') !== -1" key="task">
<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" />-->
<new-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" 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>
<el-collapse-item name="listeners" key="listeners"> <el-collapse-item name="listeners" key="listeners">
@ -51,6 +52,7 @@
import ElementBaseInfo from "./base/ElementBaseInfo"; import ElementBaseInfo from "./base/ElementBaseInfo";
import ElementOtherConfig from "./other/ElementOtherConfig"; import ElementOtherConfig from "./other/ElementOtherConfig";
import ElementTask from "./task/ElementTask"; import ElementTask from "./task/ElementTask";
import NewElementTask from "./task/NewElementTask";
import ElementMultiInstance from "./multi-instance/ElementMultiInstance"; import ElementMultiInstance from "./multi-instance/ElementMultiInstance";
import FlowCondition from "./flow-condition/FlowCondition"; import FlowCondition from "./flow-condition/FlowCondition";
import SignalAndMassage from "./signal-message/SignalAndMessage"; import SignalAndMassage from "./signal-message/SignalAndMessage";
@ -75,6 +77,7 @@ export default {
FlowCondition, FlowCondition,
ElementMultiInstance, ElementMultiInstance,
ElementTask, ElementTask,
NewElementTask,
ElementOtherConfig, ElementOtherConfig,
ElementBaseInfo ElementBaseInfo
}, },

View File

@ -1,30 +1,35 @@
<template> <template>
<div class="panel-tab__content"> <div class="panel-tab__content">
<el-form size="mini" label-width="90px" @submit.native.prevent> <el-form size="mini" label-width="90px" @submit.native.prevent>
<el-form-item label="回路特性"> <el-form-item label="快捷配置">
<el-button size="small" @click="changeConfig('依次审批')">依次审批</el-button>
<el-button size="small" @click="changeConfig('会签')">会签</el-button>
<el-button size="small" @click="changeConfig('或签')">或签</el-button>
</el-form-item>
<el-form-item label="会签类型">
<el-select v-model="loopCharacteristics" @change="changeLoopCharacteristicsType"> <el-select v-model="loopCharacteristics" @change="changeLoopCharacteristicsType">
<!--bpmn:MultiInstanceLoopCharacteristics--> <!--bpmn:MultiInstanceLoopCharacteristics-->
<el-option label="并行多重事件" value="ParallelMultiInstance" /> <el-option label="并行多重事件" value="ParallelMultiInstance" />
<el-option label="时序多重事件" value="SequentialMultiInstance" /> <el-option label="时序多重事件" value="SequentialMultiInstance" />
<!--bpmn:StandardLoopCharacteristics--> <!--bpmn:StandardLoopCharacteristics-->
<el-option label="循环事件" value="StandardLoop" /> <!-- <el-option label="循环事件" value="StandardLoop" />-->
<el-option label="无" value="Null" /> <el-option label="无" value="Null" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<template v-if="loopCharacteristics === 'ParallelMultiInstance' || loopCharacteristics === 'SequentialMultiInstance'"> <template v-if="loopCharacteristics === 'ParallelMultiInstance' || loopCharacteristics === 'SequentialMultiInstance'">
<el-form-item label="循环数" key="loopCardinality"> <el-form-item label="循环" key="loopCardinality">
<el-input v-model="loopInstanceForm.loopCardinality" clearable @change="updateLoopCardinality" /> <el-input v-model="loopInstanceForm.loopCardinality" clearable @change="updateLoopCardinality" />
</el-form-item> </el-form-item>
<el-form-item label="集合" key="collection" v-show="false"> <el-form-item label="集合" key="collection" v-show="false">
<el-input v-model="loopInstanceForm.collection" clearable @change="updateLoopBase" /> <el-input v-model="loopInstanceForm.collection" clearable @change="updateLoopBase" />
</el-form-item> </el-form-item>
<el-form-item label="元素变量" key="elementVariable"> <el-form-item label="元素变量" key="elementVariable" style="display: none">
<el-input v-model="loopInstanceForm.elementVariable" clearable @change="updateLoopBase" /> <el-input v-model="loopInstanceForm.elementVariable" clearable @change="updateLoopBase" />
</el-form-item> </el-form-item>
<el-form-item label="完成条件" key="completionCondition"> <el-form-item label="完成条件" key="completionCondition">
<el-input v-model="loopInstanceForm.completionCondition" clearable @change="updateLoopCondition" /> <el-input v-model="loopInstanceForm.completionCondition" clearable @change="updateLoopCondition" />
</el-form-item> </el-form-item>
<el-form-item label="异步状态" key="async"> <el-form-item label="异步状态" key="async" style="display: none">
<el-checkbox v-model="loopInstanceForm.asyncBefore" label="异步前" @change="updateLoopAsync('asyncBefore')" /> <el-checkbox v-model="loopInstanceForm.asyncBefore" label="异步前" @change="updateLoopAsync('asyncBefore')" />
<el-checkbox v-model="loopInstanceForm.asyncAfter" label="异步后" @change="updateLoopAsync('asyncAfter')" /> <el-checkbox v-model="loopInstanceForm.asyncAfter" label="异步后" @change="updateLoopAsync('asyncAfter')" />
<el-checkbox <el-checkbox
@ -54,6 +59,8 @@ export default {
}, },
data() { data() {
return { return {
bpmnElement:null,
multiLoopInstance:null,
loopCharacteristics: "", loopCharacteristics: "",
// //
defaultLoopInstanceForm: { defaultLoopInstanceForm: {
@ -77,7 +84,22 @@ export default {
} }
}, },
methods: { methods: {
changeConfig(type){
if (type === '依次审批') {
this.changeLoopCharacteristicsType('SequentialMultiInstance')
this.updateLoopCardinality('1')
this.updateLoopCondition('${ nrOfCompletedInstances >= nrOfInstances }')
} else if (type === '会签') {
this.changeLoopCharacteristicsType('ParallelMultiInstance')
this.updateLoopCondition('${ nrOfCompletedInstances >= nrOfInstances }')
} else if (type === '或签') {
this.changeLoopCharacteristicsType('ParallelMultiInstance')
this.updateLoopCondition('${ nrOfCompletedInstances > 0 }')
}
},
getElementLoop(businessObject) { getElementLoop(businessObject) {
console.log(this.bpmnElement.businessObject.loopCharacteristics)
console.log(businessObject.loopCharacteristics)
if (!businessObject.loopCharacteristics) { if (!businessObject.loopCharacteristics) {
this.loopCharacteristics = "Null"; this.loopCharacteristics = "Null";
this.loopInstanceForm = {}; this.loopInstanceForm = {};
@ -114,24 +136,34 @@ export default {
changeLoopCharacteristicsType(type) { changeLoopCharacteristicsType(type) {
// this.loopInstanceForm = { ...this.defaultLoopInstanceForm }; // // this.loopInstanceForm = { ...this.defaultLoopInstanceForm }; //
// //
if (type === "Null") { if (type === 'Null') {
window.bpmnInstances.modeling.updateProperties(this.bpmnElement, { loopCharacteristics: null }); window.bpmnInstances.modeling.updateProperties(this.bpmnElement, {
return; loopCharacteristics: null
});
return
} }
// //
if (type === "StandardLoop") { if (type === 'StandardLoop') {
const loopCharacteristicsObject = window.bpmnInstances.moddle.create("bpmn:StandardLoopCharacteristics"); const loopCharacteristicsObject = window.bpmnInstances.moddle.create(
'bpmn:StandardLoopCharacteristics'
)
window.bpmnInstances.modeling.updateProperties(this.bpmnElement, { window.bpmnInstances.modeling.updateProperties(this.bpmnElement, {
loopCharacteristics: loopCharacteristicsObject loopCharacteristics: loopCharacteristicsObject
}); });
this.multiLoopInstance = null; this.multiLoopInstance = null
return; return
} }
// //
if (type === "SequentialMultiInstance") { if (type === 'SequentialMultiInstance') {
this.multiLoopInstance = window.bpmnInstances.moddle.create("bpmn:MultiInstanceLoopCharacteristics", { isSequential: true }); this.multiLoopInstance = window.bpmnInstances.moddle.create(
'bpmn:MultiInstanceLoopCharacteristics',
{ isSequential: true }
)
} else { } else {
this.multiLoopInstance = window.bpmnInstances.moddle.create("bpmn:MultiInstanceLoopCharacteristics", { collection: "${coll_userList}" }); this.multiLoopInstance = window.bpmnInstances.moddle.create(
'bpmn:MultiInstanceLoopCharacteristics',
{ collection: '${coll_userList}' }
)
} }
window.bpmnInstances.modeling.updateProperties(this.bpmnElement, { window.bpmnInstances.modeling.updateProperties(this.bpmnElement, {
loopCharacteristics: this.multiLoopInstance loopCharacteristics: this.multiLoopInstance
@ -139,19 +171,35 @@ export default {
}, },
// //
updateLoopCardinality(cardinality) { updateLoopCardinality(cardinality) {
let loopCardinality = null; let loopCardinality = null
if (cardinality && cardinality.length) { if (cardinality && cardinality.length) {
loopCardinality = window.bpmnInstances.moddle.create("bpmn:FormalExpression", { body: cardinality }); loopCardinality = window.bpmnInstances.moddle.create('bpmn:FormalExpression', {
body: cardinality
})
} }
window.bpmnInstances.modeling.updateModdleProperties(this.bpmnElement, this.multiLoopInstance, { loopCardinality }); window.bpmnInstances.modeling.updateModdleProperties(
this.bpmnElement,
this.multiLoopInstance,
{
loopCardinality
}
)
}, },
// //
updateLoopCondition(condition) { updateLoopCondition(condition) {
let completionCondition = null; let completionCondition = null
if (condition && condition.length) { if (condition && condition.length) {
completionCondition = window.bpmnInstances.moddle.create("bpmn:FormalExpression", { body: condition }); completionCondition = window.bpmnInstances.moddle.create('bpmn:FormalExpression', {
body: condition
})
} }
window.bpmnInstances.modeling.updateModdleProperties(this.bpmnElement, this.multiLoopInstance, { completionCondition }); window.bpmnInstances.modeling.updateModdleProperties(
this.bpmnElement,
this.multiLoopInstance,
{
completionCondition
}
)
}, },
// //
updateLoopTimeCycle(timeCycle) { updateLoopTimeCycle(timeCycle) {

View File

@ -0,0 +1,232 @@
<template>
<div class="panel-tab__content">
<el-form size="mini" label-width="90px" @submit.native.prevent>
<el-form-item label="规则类型" prop="candidateStrategy">
<el-select v-model="userTaskForm.candidateStrategy" placeholder="请选择规则类型" @change="changeCandidateStrategy">
<el-option v-for="dict in taskAssignRuleTypeDictData"
:key="dict.value" :label="dict.label" :value="parseInt(dict.value)"/>
</el-select>
</el-form-item>
<el-form-item label="指定角色" prop="candidateParam" v-if="userTaskForm.candidateStrategy === 10">
<el-select
v-model="userTaskForm.candidateParam"
clearable
multiple
style="width: 100%"
@change="updateElementTask"
>
<el-option v-for="item in roleOptions" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item
v-if="userTaskForm.candidateStrategy === 20 || userTaskForm.candidateStrategy === 21"
label="指定部门"
prop="candidateParam"
span="24"
>
<treeselect
@input="updateElementTask"
v-model="userTaskForm.candidateParam"
:options="deptTreeOptions"
:normalizer="normalizer"
noOptionsText="暂无数据"
placeholder="请选择部门"
:appendToBody="true"
multiple
:disable-branch-nodes="true">
</treeselect>
</el-form-item>
<el-form-item
v-if="userTaskForm.candidateStrategy === 22"
label="指定岗位"
prop="candidateParam"
span="24"
>
<el-select
v-model="userTaskForm.candidateParam"
clearable
multiple
style="width: 100%"
@change="updateElementTask"
>
<el-option v-for="item in postOptions" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item
v-if="userTaskForm.candidateStrategy === 30"
label="指定用户"
prop="candidateParam"
span="24"
>
<el-select
v-model="userTaskForm.candidateParam"
clearable
multiple
style="width: 100%"
@change="updateElementTask"
>
<el-option
v-for="item in userOptions"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="userTaskForm.candidateStrategy === 40"
label="指定用户组"
prop="candidateParam"
>
<el-select
v-model="userTaskForm.candidateParam"
clearable
multiple
style="width: 100%"
@change="updateElementTask"
>
<el-option
v-for="item in userGroupOptions"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="userTaskForm.candidateStrategy === 60"
label="流程表达式"
prop="candidateParam"
>
<el-input
type="textarea"
v-model="userTaskForm.candidateParam[0]"
clearable
style="width: 72%"
@change="updateElementTask"
/>
</el-form-item>
</el-form>
</div>
</template>
<script>
import {DICT_TYPE, getDictDatas} from "@/utils/dict";
import {createTaskAssignRule, getTaskAssignRuleList, updateTaskAssignRule} from "@/api/bpm/taskAssignRule";
import {listSimpleRoles} from "@/api/system/role";
import {listSimpleDepts} from "@/api/system/dept";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import {listSimplePosts} from "@/api/system/post";
import {listSimpleUsers} from "@/api/system/user";
import {listSimpleUserGroups} from "@/api/bpm/userGroup";
import { nextTick } from 'vue'
export default {
components: { Treeselect },
props: {
id: String
},
data() {
return {
bpmnElement:null,
userTaskForm: {
candidateStrategy: undefined,//
candidateParam: [] //
},
defaultProps:{
children: 'children',
label: 'name'
},
//
roleOptions: [],
deptTreeOptions: [],
postOptions: [],
userOptions: [],
userGroupOptions: [],
taskAssignRuleTypeDictData: getDictDatas(DICT_TYPE.BPM_TASK_CANDIDATE_STRATEGY),
};
},
created() {
this.initSelection();
},
watch: {
id: {
immediate: true,
handler() {
this.bpmnElement = window.bpmnInstances.bpmnElement;
nextTick(() => {
this.resetTaskForm();
});
}
},
},
methods: {
resetTaskForm(){
if (this.bpmnElement.businessObject.$attrs.candidateStrategy !== undefined) {
this.userTaskForm.candidateStrategy = parseInt(this.bpmnElement.businessObject.$attrs.candidateStrategy)
} else {
this.userTaskForm.candidateStrategy = undefined
}
if (this.bpmnElement.businessObject.$attrs.candidateParam && this.bpmnElement.businessObject.$attrs.candidateParam.length > 0) {
if (this.userTaskForm.candidateStrategy === 60) {
// input
this.userTaskForm.candidateParam = [this.bpmnElement.businessObject.$attrs.candidateParam]
} else {
this.userTaskForm.candidateParam = this.bpmnElement.businessObject.$attrs.candidateParam
.split(',')
.map((item) => +item)
}
} else {
this.userTaskForm.candidateParam = []
}
},
changeCandidateStrategy(){
this.userTaskForm.candidateParam = [];
this.updateElementTask();
},
updateElementTask(){
window.bpmnInstances.modeling.updateProperties(this.bpmnElement, {
candidateStrategy: this.userTaskForm.candidateStrategy,
candidateParam: this.userTaskForm.candidateParam.join(',')
});
},
initSelection() {
//
this.roleOptions = [];
listSimpleRoles().then(response => {
this.roleOptions.push(...response.data);
});
//
this.deptTreeOptions = [];
listSimpleDepts().then(response => {
this.deptTreeOptions.push(...this.handleTree(response.data, "id"));
});
//
this.postOptions = [];
listSimplePosts().then(response => {
this.postOptions.push(...response.data);
});
//
this.userOptions = [];
listSimpleUsers().then(response => {
this.userOptions.push(...response.data);
});
//
this.userGroupOptions = [];
listSimpleUserGroups().then(response => {
this.userGroupOptions.push(...response.data);
});
},
//
normalizer(node) {
return {
id: node.id,
label: node.name,
children: node.children
}
}
}
};
</script>

View File

@ -64,6 +64,7 @@ export const DICT_TYPE = {
BPM_PROCESS_INSTANCE_RESULT: "bpm_process_instance_result", BPM_PROCESS_INSTANCE_RESULT: "bpm_process_instance_result",
BPM_TASK_ASSIGN_SCRIPT: "bpm_task_assign_script", BPM_TASK_ASSIGN_SCRIPT: "bpm_task_assign_script",
BPM_OA_LEAVE_TYPE: "bpm_oa_leave_type", BPM_OA_LEAVE_TYPE: "bpm_oa_leave_type",
BPM_TASK_CANDIDATE_STRATEGY: 'bpm_task_candidate_strategy',
// ========== PAY 模块 ========== // ========== PAY 模块 ==========
PAY_CHANNEL_WECHAT_VERSION: "pay_channel_wechat_version", // 微信渠道版本 PAY_CHANNEL_WECHAT_VERSION: "pay_channel_wechat_version", // 微信渠道版本

View File

@ -45,13 +45,13 @@
<span>{{ parseTime(scope.row.deploymentTime) }}</span> <span>{{ parseTime(scope.row.deploymentTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="定义描述" align="center" prop="description" width="300" show-overflow-tooltip /> <el-table-column label="定义描述" align="center" prop="description" width="450" show-overflow-tooltip />
<el-table-column label="操作" align="center" width="150" fixed="right"> <!-- <el-table-column label="操作" align="center" width="150" fixed="right">-->
<template v-slot="scope"> <!-- <template v-slot="scope">-->
<el-button size="mini" type="text" icon="el-icon-s-custom" @click="handleAssignRule(scope.row)" <!-- <el-button size="mini" type="text" icon="el-icon-s-custom" @click="handleAssignRule(scope.row)"-->
v-hasPermi="['bpm:task-assign-rule:update']">分配规则</el-button> <!-- v-hasPermi="['bpm:task-assign-rule:update']">分配规则</el-button>-->
</template> <!-- </template>-->
</el-table-column> <!-- </el-table-column>-->
</el-table> </el-table>
<!-- 流程表单配置详情 --> <!-- 流程表单配置详情 -->

View File

@ -1,13 +1,5 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<doc-alert title="流程设计器BPMN" url="https://doc.iocoder.cn/bpm/model-designer-dingding/" />
<doc-alert
title="流程设计器(钉钉、飞书)"
url="https://doc.iocoder.cn/bpm/model-designer-bpmn/"
/>
<doc-alert title="选择审批人、发起人自选" url="https://doc.iocoder.cn/bpm/assignee/" />
<doc-alert title="会签、或签、依次审批" url="https://doc.iocoder.cn/bpm/multi-instance/" />
<!-- 搜索工作栏 --> <!-- 搜索工作栏 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="流程标识" prop="key"> <el-form-item label="流程标识" prop="key">
@ -98,8 +90,8 @@
v-hasPermi="['bpm:model:update']">修改流程</el-button> v-hasPermi="['bpm:model:update']">修改流程</el-button>
<el-button size="mini" type="text" icon="el-icon-setting" @click="handleDesign(scope.row)" <el-button size="mini" type="text" icon="el-icon-setting" @click="handleDesign(scope.row)"
v-hasPermi="['bpm:model:update']">设计流程</el-button> v-hasPermi="['bpm:model:update']">设计流程</el-button>
<el-button size="mini" type="text" icon="el-icon-s-custom" @click="handleAssignRule(scope.row)" <!-- <el-button size="mini" type="text" icon="el-icon-s-custom" @click="handleAssignRule(scope.row)"-->
v-hasPermi="['bpm:task-assign-rule:query']">分配规则</el-button> <!-- v-hasPermi="['bpm:task-assign-rule:query']">分配规则</el-button>-->
<el-button size="mini" type="text" icon="el-icon-thumb" @click="handleDeploy(scope.row)" <el-button size="mini" type="text" icon="el-icon-thumb" @click="handleDeploy(scope.row)"
v-hasPermi="['bpm:model:deploy']">发布流程</el-button> v-hasPermi="['bpm:model:deploy']">发布流程</el-button>
<el-button size="mini" type="text" icon="el-icon-ice-cream-round" @click="handleDefinitionList(scope.row)" <el-button size="mini" type="text" icon="el-icon-ice-cream-round" @click="handleDefinitionList(scope.row)"