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 中的命名空间
*/
String NAMESPACE = "http://flowable.org/bpmn";
String NAMESPACE = null;
/**
* BPMN UserTask 的扩展属性用于标记候选人策略

View File

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

View File

@ -21,11 +21,12 @@
替代提供更好的表单设计功能
</el-collapse-item>
<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>
<element-task :id="elementId" :type="elementType" />
<div slot="title" class="panel-tab__title"><i class="el-icon-s-claim"></i>任务审批人</div>
<!-- <element-task :id="elementId" :type="elementType" />-->
<new-element-task :id="elementId" :type="elementType" />
</el-collapse-item>
<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" />
</el-collapse-item>
<el-collapse-item name="listeners" key="listeners">
@ -51,6 +52,7 @@
import ElementBaseInfo from "./base/ElementBaseInfo";
import ElementOtherConfig from "./other/ElementOtherConfig";
import ElementTask from "./task/ElementTask";
import NewElementTask from "./task/NewElementTask";
import ElementMultiInstance from "./multi-instance/ElementMultiInstance";
import FlowCondition from "./flow-condition/FlowCondition";
import SignalAndMassage from "./signal-message/SignalAndMessage";
@ -75,6 +77,7 @@ export default {
FlowCondition,
ElementMultiInstance,
ElementTask,
NewElementTask,
ElementOtherConfig,
ElementBaseInfo
},

View File

@ -1,30 +1,35 @@
<template>
<div class="panel-tab__content">
<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">
<!--bpmn:MultiInstanceLoopCharacteristics-->
<el-option label="并行多重事件" value="ParallelMultiInstance" />
<el-option label="时序多重事件" value="SequentialMultiInstance" />
<!--bpmn:StandardLoopCharacteristics-->
<el-option label="循环事件" value="StandardLoop" />
<!-- <el-option label="循环事件" value="StandardLoop" />-->
<el-option label="无" value="Null" />
</el-select>
</el-form-item>
<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-form-item>
<el-form-item label="集合" key="collection" v-show="false">
<el-input v-model="loopInstanceForm.collection" clearable @change="updateLoopBase" />
</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-form-item>
<el-form-item label="完成条件" key="completionCondition">
<el-input v-model="loopInstanceForm.completionCondition" clearable @change="updateLoopCondition" />
</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.asyncAfter" label="异步后" @change="updateLoopAsync('asyncAfter')" />
<el-checkbox
@ -54,6 +59,8 @@ export default {
},
data() {
return {
bpmnElement:null,
multiLoopInstance:null,
loopCharacteristics: "",
//
defaultLoopInstanceForm: {
@ -77,7 +84,22 @@ export default {
}
},
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) {
console.log(this.bpmnElement.businessObject.loopCharacteristics)
console.log(businessObject.loopCharacteristics)
if (!businessObject.loopCharacteristics) {
this.loopCharacteristics = "Null";
this.loopInstanceForm = {};
@ -114,24 +136,34 @@ export default {
changeLoopCharacteristicsType(type) {
// this.loopInstanceForm = { ...this.defaultLoopInstanceForm }; //
//
if (type === "Null") {
window.bpmnInstances.modeling.updateProperties(this.bpmnElement, { loopCharacteristics: null });
return;
if (type === 'Null') {
window.bpmnInstances.modeling.updateProperties(this.bpmnElement, {
loopCharacteristics: null
});
return
}
//
if (type === "StandardLoop") {
const loopCharacteristicsObject = window.bpmnInstances.moddle.create("bpmn:StandardLoopCharacteristics");
if (type === 'StandardLoop') {
const loopCharacteristicsObject = window.bpmnInstances.moddle.create(
'bpmn:StandardLoopCharacteristics'
)
window.bpmnInstances.modeling.updateProperties(this.bpmnElement, {
loopCharacteristics: loopCharacteristicsObject
});
this.multiLoopInstance = null;
return;
this.multiLoopInstance = null
return
}
//
if (type === "SequentialMultiInstance") {
this.multiLoopInstance = window.bpmnInstances.moddle.create("bpmn:MultiInstanceLoopCharacteristics", { isSequential: true });
if (type === 'SequentialMultiInstance') {
this.multiLoopInstance = window.bpmnInstances.moddle.create(
'bpmn:MultiInstanceLoopCharacteristics',
{ isSequential: true }
)
} 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, {
loopCharacteristics: this.multiLoopInstance
@ -139,19 +171,35 @@ export default {
},
//
updateLoopCardinality(cardinality) {
let loopCardinality = null;
let loopCardinality = null
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) {
let completionCondition = null;
let completionCondition = null
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) {

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_TASK_ASSIGN_SCRIPT: "bpm_task_assign_script",
BPM_OA_LEAVE_TYPE: "bpm_oa_leave_type",
BPM_TASK_CANDIDATE_STRATEGY: 'bpm_task_candidate_strategy',
// ========== PAY 模块 ==========
PAY_CHANNEL_WECHAT_VERSION: "pay_channel_wechat_version", // 微信渠道版本

View File

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

View File

@ -1,13 +1,5 @@
<template>
<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-item label="流程标识" prop="key">
@ -98,8 +90,8 @@
v-hasPermi="['bpm:model:update']">修改流程</el-button>
<el-button size="mini" type="text" icon="el-icon-setting" @click="handleDesign(scope.row)"
v-hasPermi="['bpm:model:update']">设计流程</el-button>
<el-button size="mini" type="text" icon="el-icon-s-custom" @click="handleAssignRule(scope.row)"
v-hasPermi="['bpm:task-assign-rule:query']">分配规则</el-button>
<!-- <el-button size="mini" type="text" icon="el-icon-s-custom" @click="handleAssignRule(scope.row)"-->
<!-- v-hasPermi="['bpm:task-assign-rule:query']">分配规则</el-button>-->
<el-button size="mini" type="text" icon="el-icon-thumb" @click="handleDeploy(scope.row)"
v-hasPermi="['bpm:model:deploy']">发布流程</el-button>
<el-button size="mini" type="text" icon="el-icon-ice-cream-round" @click="handleDefinitionList(scope.row)"