嵌入bpmn设计流程模块

This commit is contained in:
gexinzhineng/gxzn27
2023-01-28 09:53:43 +08:00
parent 2253ba069f
commit 89c366be68
60 changed files with 10057 additions and 15 deletions

View File

@ -0,0 +1,204 @@
<template>
<div class="process-panel__container" :style="{ width: `${width}px` }">
<el-collapse v-model="activeTab">
<el-collapse-item name="base">
<!-- class="panel-tab__title" -->
<template #title>
<Icon icon="ep:info-filled" />
常规</template
>
<ElementBaseInfo
:id-edit-disabled="idEditDisabled"
:business-object="elementBusinessObject"
:type="elementType"
:model="model"
/>
</el-collapse-item>
<el-collapse-item name="condition" v-if="elementType === 'Process'" key="message">
<template #title><Icon icon="ep:comment" />消息与信号</template>
<signal-and-massage />
</el-collapse-item>
<el-collapse-item name="condition" v-if="conditionFormVisible" key="condition">
<template #title><Icon icon="ep:promotion" />流转条件</template>
<flow-condition :business-object="elementBusinessObject" :type="elementType" />
</el-collapse-item>
<el-collapse-item name="condition" v-if="formVisible" key="form">
<template #title><Icon icon="ep:list" />表单</template>
<!-- <element-form :id="elementId" :type="elementType" /> -->
友情提示使用
<router-link :to="{ path: '/bpm/manager/form' }"
><el-link type="danger">流程表单</el-link>
</router-link>
替代提供更好的表单设计功能
</el-collapse-item>
<el-collapse-item name="task" v-if="elementType.indexOf('Task') !== -1" key="task">
<template #title><Icon icon="ep:checked" />任务</template>
<element-task :id="elementId" :type="elementType" />
</el-collapse-item>
<el-collapse-item
name="multiInstance"
v-if="elementType.indexOf('Task') !== -1"
key="multiInstance"
>
<template #title><Icon icon="ep:help-filled" />多实例</template>
<element-multi-instance :business-object="elementBusinessObject" :type="elementType" />
</el-collapse-item>
<el-collapse-item name="listeners" key="listeners">
<template #title><Icon icon="ep:bell-filled" />执行监听器</template>
<element-listeners :id="elementId" :type="elementType" />
</el-collapse-item>
<el-collapse-item name="taskListeners" v-if="elementType === 'UserTask'" key="taskListeners">
<template #title><Icon icon="ep:bell-filled" />任务监听器</template>
<user-task-listeners :id="elementId" :type="elementType" />
</el-collapse-item>
<el-collapse-item name="extensions" key="extensions">
<template #title><Icon icon="ep:circle-plus-filled" />扩展属性</template>
<element-properties :id="elementId" :type="elementType" />
</el-collapse-item>
<el-collapse-item name="other" key="other">
<template #title><Icon icon="ep:promotion" />其他</template>
<element-other-config :id="elementId" />
</el-collapse-item>
</el-collapse>
</div>
</template>
<script setup lang="ts" name="MyPropertiesPanel">
import ElementBaseInfo from './base/ElementBaseInfo.vue'
import ElementOtherConfig from './other/ElementOtherConfig.vue'
import ElementTask from './task/ElementTask.vue'
import ElementMultiInstance from './multi-instance/ElementMultiInstance.vue'
import FlowCondition from './flow-condition/FlowCondition.vue'
import SignalAndMassage from './signal-message/SignalAndMessage.vue'
import ElementListeners from './listeners/ElementListeners.vue'
import ElementProperties from './properties/ElementProperties.vue'
// import ElementForm from './form/ElementForm.vue'
import UserTaskListeners from './listeners/UserTaskListeners.vue'
import { provide, ref, watch, onBeforeUnmount, onMounted } from 'vue'
import { ElCollapse, ElCollapseItem, ElLink } from 'element-plus'
/**
* 侧边栏
* @Author MiyueFE
* @Home https://github.com/miyuesc
* @Date 2021年3月31日18:57:51
*/
const props = defineProps({
bpmnModeler: Object,
prefix: {
type: String,
default: 'camunda'
},
width: {
type: Number,
default: 480
},
idEditDisabled: {
type: Boolean,
default: false
},
model: Object // 流程模型的数据
})
const activeTab = ref('base')
const elementId = ref('')
const elementType = ref('')
const elementBusinessObject = ref({}) // 元素 businessObject 镜像,提供给需要做判断的组件使用
const conditionFormVisible = ref(false) // 流转条件设置
const formVisible = ref(false) // 表单配置
const bpmnElement = ref()
const timer = ref()
provide('prefix', props.prefix)
provide('width', props.width)
const initModels = () => {
// console.log(props, 'props')
// console.log(props.bpmnModeler, 'sakdjjaskdsajdkasdjkadsjk')
// 初始化 modeler 以及其他 moddle
// nextTick(() => {
if (!props.bpmnModeler) {
// 避免加载时 流程图 并未加载完成
timer.value = setTimeout(() => initModels(), 10)
return
}
if (timer.value) {
clearTimeout(timer.value)
window.bpmnInstances = {
modeler: props.bpmnModeler,
modeling: props.bpmnModeler.get('modeling'),
moddle: props.bpmnModeler.get('moddle'),
eventBus: props.bpmnModeler.get('eventBus'),
bpmnFactory: props.bpmnModeler.get('bpmnFactory'),
elementFactory: props.bpmnModeler.get('elementFactory'),
elementRegistry: props.bpmnModeler.get('elementRegistry'),
replace: props.bpmnModeler.get('replace'),
selection: props.bpmnModeler.get('selection')
}
}
console.log(window.bpmnInstances, 'window.bpmnInstances')
getActiveElement()
// })
}
const getActiveElement = () => {
// 初始第一个选中元素 bpmn:Process
initFormOnChanged(null)
props.bpmnModeler.on('import.done', (e) => {
console.log(e, 'eeeee')
initFormOnChanged(null)
})
// 监听选择事件,修改当前激活的元素以及表单
props.bpmnModeler.on('selection.changed', ({ newSelection }) => {
initFormOnChanged(newSelection[0] || null)
})
props.bpmnModeler.on('element.changed', ({ element }) => {
// 保证 修改 "默认流转路径" 类似需要修改多个元素的事件发生的时候,更新表单的元素与原选中元素不一致。
if (element && element.id === elementId.value) {
initFormOnChanged(element)
}
})
}
// 初始化数据
const initFormOnChanged = (element) => {
let activatedElement = element
if (!activatedElement) {
activatedElement =
window.bpmnInstances.elementRegistry.find((el) => el.type === 'bpmn:Process') ??
window.bpmnInstances.elementRegistry.find((el) => el.type === 'bpmn:Collaboration')
}
if (!activatedElement) return
console.log(`
----------
select element changed:
id: ${activatedElement.id}
type: ${activatedElement.businessObject.$type}
----------
`)
console.log('businessObject: ', activatedElement.businessObject)
window.bpmnInstances.bpmnElement = activatedElement
bpmnElement.value = activatedElement
elementId.value = activatedElement.id
elementType.value = activatedElement.type.split(':')[1] || ''
elementBusinessObject.value = JSON.parse(JSON.stringify(activatedElement.businessObject))
conditionFormVisible.value = !!(
elementType.value === 'SequenceFlow' &&
activatedElement.source &&
activatedElement.source.type.indexOf('StartEvent') === -1
)
formVisible.value = elementType.value === 'UserTask' || elementType.value === 'StartEvent'
}
onMounted(() => {
setTimeout(() => {
initModels()
}, 100)
})
onBeforeUnmount(() => {
window.bpmnInstances = null
console.log(props, 'props1')
console.log(props.bpmnModeler, 'props.bpmnModeler1')
})
watch(
() => elementId.value,
() => {
activeTab.value = 'base'
}
)
</script>

View File

@ -0,0 +1,162 @@
<template>
<div class="panel-tab__content">
<el-form label-width="90px" :model="needProps" :rules="rules">
<div v-if="elementBaseInfo == 'bpmn:Process'">
<!-- 如果是 Process 信息的时候使用自定义表单 -->
<el-link
href="https://doc.iocoder.cn/bpm/#_3-%E6%B5%81%E7%A8%8B%E5%9B%BE%E7%A4%BA%E4%BE%8B"
type="danger"
target="_blank"
>如何实现实现会签或签</el-link
>
<el-form-item label="流程标识" prop="key">
<el-input
v-model="needProps.key"
placeholder="请输入流标标识"
:disabled="needProps.id !== undefined && needProps.id.length > 0"
@change="handleKeyUpdate"
/>
</el-form-item>
<el-form-item label="流程名称" prop="name">
<el-input
v-model="needProps.name"
placeholder="请输入流程名称"
clearable
@change="handleNameUpdate"
/>
</el-form-item>
</div>
<div v-else>
<el-form-item label="ID">
<el-input v-model="elementBaseInfo.id" clearable @change="updateBaseInfo('id')" />
</el-form-item>
<el-form-item label="名称">
<el-input v-model="elementBaseInfo.name" clearable @change="updateBaseInfo('name')" />
</el-form-item>
</div>
</el-form>
</div>
</template>
<script setup lang="ts" name="ElementBaseInfo">
import { ref, reactive, watch, nextTick, onMounted, onBeforeUnmount } from 'vue'
import { ElLink, ElForm, ElFormItem, ElInput } from 'element-plus'
const props = defineProps({
businessObject: Object,
model: Object // 流程模型的数据
})
const needProps = ref()
const bpmnElement = ref()
const elementBaseInfo = ref({})
// 流程表单的下拉框的数据
// const forms = ref([])
// 流程模型的校验
const rules = reactive({
key: [{ required: true, message: '流程标识不能为空', trigger: 'blur' }],
name: [{ required: true, message: '流程名称不能为空', trigger: 'blur' }]
})
const resetBaseInfo = () => {
console.log(window, 'window')
console.log(bpmnElement, 'bpmnElement')
bpmnElement.value = window?.bpmnInstances?.bpmnElement
console.log(bpmnElement.value, 'resetBaseInfo')
elementBaseInfo.value = bpmnElement.value.businessObject
// elementBaseInfo.value = JSON.parse(JSON.stringify(bpmnElement.value.businessObject))
console.log(elementBaseInfo.value, 'elementBaseInfo')
}
const handleKeyUpdate = (value) => {
// 校验 value 的值,只有 XML NCName 通过的情况下,才进行赋值。否则,会导致流程图报错,无法绘制的问题
if (!value) {
return
}
if (!value.match(/[a-zA-Z_][\-_.0-9a-zA-Z$]*/)) {
console.log('key 不满足 XML NCName 规则,所以不进行赋值')
return
}
console.log('key 满足 XML NCName 规则,所以进行赋值')
// 在 BPMN 的 XML 中,流程标识 key其实对应的是 id 节点
elementBaseInfo.value['id'] = value
updateBaseInfo('id')
}
const handleNameUpdate = (value) => {
console.log(elementBaseInfo, 'elementBaseInfo')
if (!value) {
return
}
elementBaseInfo.value['name'] = value
updateBaseInfo('name')
}
// const handleDescriptionUpdate=(value)=> {
// TODO 芋艿documentation 暂时无法修改,后续在看看
// this.elementBaseInfo['documentation'] = value;
// this.updateBaseInfo('documentation');
// }
const updateBaseInfo = (key) => {
console.log(key, 'key')
// 触发 elementBaseInfo 对应的字段
const attrObj = Object.create(null)
// console.log(attrObj, 'attrObj')
attrObj[key] = elementBaseInfo.value[key]
// console.log(attrObj, 'attrObj111')
// const attrObj = {
// id: elementBaseInfo.value[key]
// // di: { id: `${elementBaseInfo.value[key]}_di` }
// }
if (key === 'id') {
console.log('jinru')
window.bpmnInstances.modeling.updateProperties(bpmnElement.value, {
id: elementBaseInfo.value[key],
di: { id: `${elementBaseInfo.value[key]}_di` }
})
} else {
console.log(attrObj, 'attrObj')
window.bpmnInstances.modeling.updateProperties(bpmnElement.value, attrObj)
}
}
onMounted(() => {
// 针对上传的 bpmn 流程图时,需要延迟 1 秒的时间,保证 key 和 name 的更新
setTimeout(() => {
console.log(props.model, 'props.model')
handleKeyUpdate(props.model.key)
handleNameUpdate(props.model.name)
console.log(props, 'propsssssssssssssssssssss')
}, 1000)
})
watch(
() => props.businessObject,
(val) => {
console.log(val, 'val11111111111111111111')
if (val) {
nextTick(() => {
resetBaseInfo()
})
}
}
)
// watch(
// () => ({ ...props }),
// (oldVal, newVal) => {
// console.log(oldVal, 'oldVal')
// console.log(newVal, 'newVal')
// if (newVal) {
// needProps.value = newVal
// }
// },
// {
// immediate: true
// }
// )
// 'model.key': {
// immediate: false,
// handler: function (val) {
// this.handleKeyUpdate(val)
// }
// }
onBeforeUnmount(() => {
bpmnElement.value = null
})
</script>

View File

@ -0,0 +1,188 @@
<template>
<div class="panel-tab__content">
<el-form :model="flowConditionForm" label-width="90px" size="mini">
<el-form-item label="流转类型">
<el-select v-model="flowConditionForm.type" @change="updateFlowType">
<el-option label="普通流转路径" value="normal" />
<el-option label="默认流转路径" value="default" />
<el-option label="条件流转路径" value="condition" />
</el-select>
</el-form-item>
<el-form-item label="条件格式" v-if="flowConditionForm.type === 'condition'" key="condition">
<el-select v-model="flowConditionForm.conditionType">
<el-option label="表达式" value="expression" />
<el-option label="脚本" value="script" />
</el-select>
</el-form-item>
<el-form-item
label="表达式"
v-if="flowConditionForm.conditionType && flowConditionForm.conditionType === 'expression'"
key="express"
>
<el-input
v-model="flowConditionForm.body"
style="width: 192px"
clearable
@change="updateFlowCondition"
/>
</el-form-item>
<template
v-if="flowConditionForm.conditionType && flowConditionForm.conditionType === 'script'"
>
<el-form-item label="脚本语言" key="language">
<el-input v-model="flowConditionForm.language" clearable @change="updateFlowCondition" />
</el-form-item>
<el-form-item label="脚本类型" key="scriptType">
<el-select v-model="flowConditionForm.scriptType">
<el-option label="内联脚本" value="inlineScript" />
<el-option label="外部脚本" value="externalScript" />
</el-select>
</el-form-item>
<el-form-item
label="脚本"
v-if="flowConditionForm.scriptType === 'inlineScript'"
key="body"
>
<el-input
v-model="flowConditionForm.body"
type="textarea"
clearable
@change="updateFlowCondition"
/>
</el-form-item>
<el-form-item
label="资源地址"
v-if="flowConditionForm.scriptType === 'externalScript'"
key="resource"
>
<el-input v-model="flowConditionForm.resource" clearable @change="updateFlowCondition" />
</el-form-item>
</template>
</el-form>
</div>
</template>
<script setup lang="ts" name="FlowCondition">
import { ref, nextTick, watch, onBeforeUnmount } from 'vue'
import { ElSelect, ElForm, ElFormItem, ElInput, ElOption } from 'element-plus'
const props = defineProps({
businessObject: Object,
type: String
})
const flowConditionForm = ref({})
const bpmnElement = ref()
const bpmnElementSource = ref()
const bpmnElementSourceRef = ref()
const flowConditionRef = ref()
const resetFlowCondition = () => {
bpmnElement.value = window.bpmnInstances.bpmnElement
bpmnElementSource.value = bpmnElement.value.source
bpmnElementSourceRef.value = bpmnElement.value.businessObject.sourceRef
if (
bpmnElementSourceRef.value &&
bpmnElementSourceRef.value.default &&
bpmnElementSourceRef.value.default.id === this.bpmnElement.id
) {
// 默认
flowConditionForm.value = { type: 'default' }
} else if (!bpmnElement.value.businessObject.conditionExpression) {
// 普通
flowConditionForm.value = { type: 'normal' }
} else {
// 带条件
const conditionExpression = bpmnElement.value.businessObject.conditionExpression
flowConditionForm.value = { ...conditionExpression, type: 'condition' }
// resource 可直接标识 是否是外部资源脚本
if (flowConditionForm.value.resource) {
// this.$set(this.flowConditionForm, "conditionType", "script");
// this.$set(this.flowConditionForm, "scriptType", "externalScript");
flowConditionForm.value['conditionType'] = 'script'
flowConditionForm.value['scriptType'] = 'externalScript'
return
}
if (conditionExpression.language) {
// this.$set(this.flowConditionForm, "conditionType", "script");
// this.$set(this.flowConditionForm, "scriptType", "inlineScript");
flowConditionForm.value['conditionType'] = 'script'
flowConditionForm.value['scriptType'] = 'inlineScript'
return
}
// this.$set(this.flowConditionForm, "conditionType", "expression");
flowConditionForm.value['conditionType'] = 'expression'
}
}
const updateFlowType = (flowType) => {
// 正常条件类
if (flowType === 'condition') {
flowConditionRef.value = window.bpmnInstances.moddle.create('bpmn:FormalExpression')
window.bpmnInstances.modeling.updateProperties(bpmnElement.value, {
conditionExpression: flowConditionRef.value
})
return
}
// 默认路径
if (flowType === 'default') {
window.bpmnInstances.modeling.updateProperties(bpmnElement.value, {
conditionExpression: null
})
window.bpmnInstances.modeling.updateProperties(bpmnElementSource.value, {
default: bpmnElement.value
})
return
}
// 正常路径,如果来源节点的默认路径是当前连线时,清除父元素的默认路径配置
if (
bpmnElementSourceRef.value.default &&
bpmnElementSourceRef.value.default.id === bpmnElement.value.id
) {
window.bpmnInstances.modeling.updateProperties(bpmnElementSource.value, {
default: null
})
}
window.bpmnInstances.modeling.updateProperties(bpmnElement.value, {
conditionExpression: null
})
}
const updateFlowCondition = () => {
let { conditionType, scriptType, body, resource, language } = flowConditionForm.value
let condition
if (conditionType === 'expression') {
condition = window.bpmnInstances.moddle.create('bpmn:FormalExpression', { body })
} else {
if (scriptType === 'inlineScript') {
condition = window.bpmnInstances.moddle.create('bpmn:FormalExpression', { body, language })
// this.$set(this.flowConditionForm, "resource", "");
flowConditionForm.value['resource'] = ''
} else {
// this.$set(this.flowConditionForm, "body", "");
flowConditionForm.value['body'] = ''
condition = window.bpmnInstances.moddle.create('bpmn:FormalExpression', {
resource,
language
})
}
}
window.bpmnInstances.modeling.updateProperties(bpmnElement.value, {
conditionExpression: condition
})
}
onBeforeUnmount(() => {
bpmnElement.value = null
bpmnElementSource.value = null
bpmnElementSourceRef.value = null
})
watch(
() => props.businessObject,
(val) => {
if (val) {
nextTick(() => {
resetFlowCondition()
})
}
}
)
</script>

View File

@ -0,0 +1,456 @@
<template>
<div class="panel-tab__content">
<el-form label-width="80px">
<el-form-item label="表单标识">
<el-input v-model="formKey" clearable @change="updateElementFormKey" />
</el-form-item>
<el-form-item label="业务标识">
<el-select v-model="businessKey" @change="updateElementBusinessKey">
<el-option v-for="i in fieldList" :key="i.id" :value="i.id" :label="i.label" />
<el-option label="无" value="" />
</el-select>
</el-form-item>
</el-form>
<!--字段列表-->
<div class="element-property list-property">
<el-divider><Icon icon="ep:coin" /> 表单字段</el-divider>
<el-table :data="fieldList" max-height="240" border fit>
<el-table-column label="序号" type="index" width="50px" />
<el-table-column label="字段名称" prop="label" min-width="80px" show-overflow-tooltip />
<el-table-column
label="字段类型"
prop="type"
min-width="80px"
:formatter="(row) => fieldType[row.type] || row.type"
show-overflow-tooltip
/>
<el-table-column
label="默认值"
prop="defaultValue"
min-width="80px"
show-overflow-tooltip
/>
<el-table-column label="操作" width="90px">
<template #default="scope">
<el-button type="text" @click="openFieldForm(scope, scope.$index)">编辑</el-button>
<el-divider direction="vertical" />
<el-button type="text" style="color: #ff4d4f" @click="removeField(scope, scope.$index)"
>移除</el-button
>
</template>
</el-table-column>
</el-table>
</div>
<div class="element-drawer__button">
<XButton type="primary" proIcon="ep:plus" title="添加字段" @click="openFieldForm(null, -1)" />
</div>
<!--字段配置侧边栏-->
<el-drawer
v-model="fieldModelVisible"
title="字段配置"
:size="`${width}px`"
append-to-body
destroy-on-close
>
<el-form :model="formFieldForm" label-width="90px">
<el-form-item label="字段ID">
<el-input v-model="formFieldForm.id" clearable />
</el-form-item>
<el-form-item label="类型">
<el-select
v-model="formFieldForm.typeType"
placeholder="请选择字段类型"
clearable
@change="changeFieldTypeType"
>
<el-option v-for="(value, key) of fieldType" :label="value" :value="key" :key="key" />
</el-select>
</el-form-item>
<el-form-item label="类型名称" v-if="formFieldForm.typeType === 'custom'">
<el-input v-model="formFieldForm.type" clearable />
</el-form-item>
<el-form-item label="名称">
<el-input v-model="formFieldForm.label" clearable />
</el-form-item>
<el-form-item label="时间格式" v-if="formFieldForm.typeType === 'date'">
<el-input v-model="formFieldForm.datePattern" clearable />
</el-form-item>
<el-form-item label="默认值">
<el-input v-model="formFieldForm.defaultValue" clearable />
</el-form-item>
</el-form>
<!-- 枚举值设置 -->
<template v-if="formFieldForm.type === 'enum'">
<el-divider key="enum-divider" />
<p class="listener-filed__title" key="enum-title">
<span><Icon icon="ep:menu" />枚举值列表</span>
<el-button type="primary" @click="openFieldOptionForm(null, -1, 'enum')"
>添加枚举值</el-button
>
</p>
<el-table :data="fieldEnumList" key="enum-table" max-height="240" border fit>
<el-table-column label="序号" width="50px" type="index" />
<el-table-column label="枚举值编号" prop="id" min-width="100px" show-overflow-tooltip />
<el-table-column label="枚举值名称" prop="name" min-width="100px" show-overflow-tooltip />
<el-table-column label="操作" width="90px">
<template #default="scope">
<el-button type="text" @click="openFieldOptionForm(scope, scope.$index, 'enum')"
>编辑</el-button
>
<el-divider direction="vertical" />
<el-button
type="text"
style="color: #ff4d4f"
@click="removeFieldOptionItem(scope, scope.$index, 'enum')"
>移除</el-button
>
</template>
</el-table-column>
</el-table>
</template>
<!-- 校验规则 -->
<el-divider key="validation-divider" />
<p class="listener-filed__title" key="validation-title">
<span><Icon icon="ep:menu" />约束条件列表</span>
<el-button type="primary" @click="openFieldOptionForm(null, -1, 'constraint')"
>添加约束</el-button
>
</p>
<el-table :data="fieldConstraintsList" key="validation-table" max-height="240" border fit>
<el-table-column label="序号" width="50px" type="index" />
<el-table-column label="约束名称" prop="name" min-width="100px" show-overflow-tooltip />
<el-table-column label="约束配置" prop="config" min-width="100px" show-overflow-tooltip />
<el-table-column label="操作" width="90px">
<template #default="scope">
<el-button type="text" @click="openFieldOptionForm(scope, scope.$index, 'constraint')"
>编辑</el-button
>
<el-divider direction="vertical" />
<el-button
type="text"
style="color: #ff4d4f"
@click="removeFieldOptionItem(scope, scope.$index, 'constraint')"
>移除</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 表单属性 -->
<el-divider key="property-divider" />
<p class="listener-filed__title" key="property-title">
<span><Icon icon="ep:menu" />字段属性列表</span>
<el-button type="primary" @click="openFieldOptionForm(null, -1, 'property')"
>添加属性</el-button
>
</p>
<el-table :data="fieldPropertiesList" key="property-table" max-height="240" border fit>
<el-table-column label="序号" width="50px" type="index" />
<el-table-column label="属性编号" prop="id" min-width="100px" show-overflow-tooltip />
<el-table-column label="属性值" prop="value" min-width="100px" show-overflow-tooltip />
<el-table-column label="操作" width="90px">
<template #default="scope">
<el-button type="text" @click="openFieldOptionForm(scope, scope.$index, 'property')"
>编辑</el-button
>
<el-divider direction="vertical" />
<el-button
type="text"
style="color: #ff4d4f"
@click="removeFieldOptionItem(scope, scope.$index, 'property')"
>移除</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 底部按钮 -->
<div class="element-drawer__button">
<el-button> </el-button>
<el-button type="primary" @click="saveField"> </el-button>
</div>
</el-drawer>
<el-dialog
v-model="fieldOptionModelVisible"
:title="optionModelTitle"
width="600px"
append-to-body
destroy-on-close
>
<el-form :model="fieldOptionForm" label-width="96px">
<el-form-item label="编号/ID" v-if="fieldOptionType !== 'constraint'" key="option-id">
<el-input v-model="fieldOptionForm.id" clearable />
</el-form-item>
<el-form-item label="名称" v-if="fieldOptionType !== 'property'" key="option-name">
<el-input v-model="fieldOptionForm.name" clearable />
</el-form-item>
<el-form-item label="配置" v-if="fieldOptionType === 'constraint'" key="option-config">
<el-input v-model="fieldOptionForm.config" clearable />
</el-form-item>
<el-form-item label="值" v-if="fieldOptionType === 'property'" key="option-value">
<el-input v-model="fieldOptionForm.value" clearable />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="fieldOptionModelVisible = false"> </el-button>
<el-button type="primary" @click="saveFieldOption"> </el-button>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="ElementForm">
import { ref, inject, watch, nextTick } from 'vue'
import {
ElDialog,
ElForm,
ElFormItem,
ElSelect,
ElOption,
ElDivider,
ElTable,
ElTableColumn,
ElButton,
ElDrawer,
ElInput
} from 'element-plus'
const props = defineProps({
id: String,
type: String
})
const prefix = inject('prefix')
const width = inject('width')
const formKey = ref('')
const businessKey = ref('')
const optionModelTitle = ref('')
const fieldList = ref([])
const formFieldForm = ref({})
const fieldType = ref({
long: '长整型',
string: '字符串',
boolean: '布尔类',
date: '日期类',
enum: '枚举类',
custom: '自定义类型'
})
const formFieldIndex = ref(-1) // 编辑中的字段, -1 为新增
const formFieldOptionIndex = ref(-1) // 编辑中的字段配置项, -1 为新增
const fieldModelVisible = ref(false)
const fieldOptionModelVisible = ref(false)
const fieldOptionForm = ref({}) // 当前激活的字段配置项数据
const fieldOptionType = ref('') // 当前激活的字段配置项弹窗 类型
const fieldEnumList = ref([]) // 枚举值列表
const fieldConstraintsList = ref([]) // 约束条件列表
const fieldPropertiesList = ref([]) // 绑定属性列表
const bpmnELement = ref()
const elExtensionElements = ref()
const formData = ref()
const otherExtensions = ref()
const resetFormList = () => {
bpmnELement.value = window.bpmnInstances.bpmnElement
formKey.value = bpmnELement.value.businessObject.formKey
// 获取元素扩展属性 或者 创建扩展属性
elExtensionElements.value =
bpmnELement.value.businessObject.get('extensionElements') ||
window.bpmnInstances.moddle.create('bpmn:ExtensionElements', { values: [] })
// 获取元素表单配置 或者 创建新的表单配置
formData.value =
elExtensionElements.value.values.filter((ex) => ex.$type === `${prefix}:FormData`)?.[0] ||
window.bpmnInstances.moddle.create(`${prefix}:FormData`, { fields: [] })
// 业务标识 businessKey 绑定在 formData 中
businessKey.value = formData.value.businessKey
// 保留剩余扩展元素,便于后面更新该元素对应属性
otherExtensions.value = elExtensionElements.value.values.filter(
(ex) => ex.$type !== `${prefix}:FormData`
)
// 复制原始值,填充表格
fieldList.value = JSON.parse(JSON.stringify(formData.value.fields || []))
// 更新元素扩展属性,避免后续报错
updateElementExtensions()
}
const updateElementFormKey = () => {
window.bpmnInstances.modeling.updateProperties(bpmnELement.value, { formKey: formKey.value })
}
const updateElementBusinessKey = () => {
window.bpmnInstances.modeling.updateModdleProperties(bpmnELement.value, formData.value, {
businessKey: businessKey.value
})
}
// 根据类型调整字段type
const changeFieldTypeType = (type) => {
// this.$set(this.formFieldForm, "type", type === "custom" ? "" : type);
formFieldForm.value['type'] = type === 'custom' ? '' : type
}
// 打开字段详情侧边栏
const openFieldForm = (field, index) => {
formFieldIndex.value = index
if (index !== -1) {
const FieldObject = formData.value.fields[index]
formFieldForm.value = JSON.parse(JSON.stringify(field))
// 设置自定义类型
// this.$set(this.formFieldForm, "typeType", !this.fieldType[field.type] ? "custom" : field.type);
formFieldForm.value['typeType'] = !fieldType.value[field.type] ? 'custom' : field.type
// 初始化枚举值列表
field.type === 'enum' &&
(fieldEnumList.value = JSON.parse(JSON.stringify(FieldObject?.values || [])))
// 初始化约束条件列表
fieldConstraintsList.value = JSON.parse(
JSON.stringify(FieldObject?.validation?.constraints || [])
)
// 初始化自定义属性列表
fieldPropertiesList.value = JSON.parse(JSON.stringify(FieldObject?.properties?.values || []))
} else {
formFieldForm.value = {}
// 初始化枚举值列表
fieldEnumList.value = []
// 初始化约束条件列表
fieldConstraintsList.value = []
// 初始化自定义属性列表
fieldPropertiesList.value = []
}
fieldModelVisible.value = true
}
// 打开字段 某个 配置项 弹窗
const openFieldOptionForm = (option, index, type) => {
fieldOptionModelVisible.value = true
fieldOptionType.value = type
formFieldOptionIndex.value = index
if (type === 'property') {
fieldOptionForm.value = option ? JSON.parse(JSON.stringify(option)) : {}
return (optionModelTitle.value = '属性配置')
}
if (type === 'enum') {
fieldOptionForm.value = option ? JSON.parse(JSON.stringify(option)) : {}
return (optionModelTitle.value = '枚举值配置')
}
fieldOptionForm.value = option ? JSON.parse(JSON.stringify(option)) : {}
return (optionModelTitle.value = '约束条件配置')
}
// 保存字段 某个 配置项
const saveFieldOption = () => {
if (formFieldOptionIndex.value === -1) {
if (fieldOptionType.value === 'property') {
fieldPropertiesList.value.push(fieldOptionForm.value)
}
if (fieldOptionType.value === 'constraint') {
fieldConstraintsList.value.push(fieldOptionForm.value)
}
if (fieldOptionType.value === 'enum') {
fieldEnumList.value.push(fieldOptionForm.value)
}
} else {
fieldOptionType.value === 'property' &&
fieldPropertiesList.value.splice(formFieldOptionIndex.value, 1, fieldOptionForm.value)
fieldOptionType.value === 'constraint' &&
fieldConstraintsList.value.splice(formFieldOptionIndex.value, 1, fieldOptionForm.value)
fieldOptionType.value === 'enum' &&
fieldEnumList.value.splice(formFieldOptionIndex.value, 1, fieldOptionForm.value)
}
fieldOptionModelVisible.value = false
fieldOptionForm.value = {}
}
// 保存字段配置
const saveField = () => {
const { id, type, label, defaultValue, datePattern } = formFieldForm.value
const Field = window.bpmnInstances.moddle.create(`${prefix}:FormField`, { id, type, label })
defaultValue && (Field.defaultValue = defaultValue)
datePattern && (Field.datePattern = datePattern)
// 构建属性
if (fieldPropertiesList.value && fieldPropertiesList.value.length) {
const fieldPropertyList = fieldPropertiesList.value.map((fp) => {
return window.bpmnInstances.moddle.create(`${prefix}:Property`, {
id: fp.id,
value: fp.value
})
})
Field.properties = window.bpmnInstances.moddle.create(`${this.prefix}:Properties`, {
values: fieldPropertyList
})
}
// 构建校验规则
if (fieldConstraintsList.value && fieldConstraintsList.value.length) {
const fieldConstraintList = fieldConstraintsList.value.map((fc) => {
return window.bpmnInstances.moddle.create(`${prefix}:Constraint`, {
name: fc.name,
config: fc.config
})
})
Field.validation = window.bpmnInstances.moddle.create(`${prefix}:Validation`, {
constraints: fieldConstraintList
})
}
// 构建枚举值
if (fieldEnumList.value && fieldEnumList.value.length) {
Field.values = fieldEnumList.value.map((fe) => {
return window.bpmnInstances.moddle.create(`${prefix}:Value`, { name: fe.name, id: fe.id })
})
}
// 更新数组 与 表单配置实例
if (formFieldIndex.value === -1) {
fieldList.value.push(formFieldForm.value)
formData.value.fields.push(Field)
} else {
fieldList.value.splice(formFieldIndex.value, 1, formFieldForm.value)
formData.value.fields.splice(formFieldIndex.value, 1, Field)
}
updateElementExtensions()
fieldModelVisible.value = false
}
// 移除某个 字段的 配置项
const removeFieldOptionItem = (option, index, type) => {
console.log(option, 'option')
if (type === 'property') {
fieldPropertiesList.value.splice(index, 1)
return
}
if (type === 'enum') {
fieldEnumList.value.splice(index, 1)
return
}
fieldConstraintsList.value.splice(index, 1)
}
// 移除 字段
const removeField = (field, index) => {
console.log(field, 'field')
fieldList.value.splice(index, 1)
formData.value.fields.splice(index, 1)
updateElementExtensions()
}
const updateElementExtensions = () => {
// 更新回扩展元素
const newElExtensionElements = window.bpmnInstances.moddle.create(`bpmn:ExtensionElements`, {
values: otherExtensions.value.concat(formData.value)
})
// 更新到元素上
window.bpmnInstances.modeling.updateProperties(bpmnELement.value, {
extensionElements: newElExtensionElements
})
}
watch(
() => props.id,
(val) => {
val &&
val.length &&
nextTick(() => {
resetFormList()
})
},
{ immediate: true }
)
</script>

View File

@ -0,0 +1,7 @@
import MyPropertiesPanel from "./PropertiesPanel.vue";
MyPropertiesPanel.install = function(Vue) {
Vue.component(MyPropertiesPanel.name, MyPropertiesPanel);
};
export default MyPropertiesPanel;

View File

@ -0,0 +1,415 @@
<template>
<div class="panel-tab__content">
<el-table :data="elementListenersList" size="mini" border>
<el-table-column label="序号" width="50px" type="index" />
<el-table-column label="事件类型" min-width="100px" prop="event" />
<el-table-column
label="监听器类型"
min-width="100px"
show-overflow-tooltip
:formatter="(row) => listenerTypeObject[row.listenerType]"
/>
<el-table-column label="操作" width="90px">
<template #default="scope">
<el-button size="mini" type="text" @click="openListenerForm(scope, scope.$index)"
>编辑</el-button
>
<el-divider direction="vertical" />
<el-button
size="mini"
type="text"
style="color: #ff4d4f"
@click="removeListener(scope, scope.$index)"
>移除</el-button
>
</template>
</el-table-column>
</el-table>
<div class="element-drawer__button">
<XButton
size="mini"
type="primary"
preIcon="ep:plus"
title="添加监听器"
@click="openListenerForm(null)"
/>
</div>
<!-- 监听器 编辑/创建 部分 -->
<el-drawer
v-model="listenerFormModelVisible"
title="执行监听器"
:size="`${width}px`"
append-to-body
destroy-on-close
>
<el-form :model="listenerForm" label-width="96px" ref="listenerFormRef">
<el-form-item
label="事件类型"
prop="event"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-select v-model="listenerForm.event">
<el-option label="start" value="start" />
<el-option label="end" value="end" />
</el-select>
</el-form-item>
<el-form-item
label="监听器类型"
prop="listenerType"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-select v-model="listenerForm.listenerType">
<el-option
v-for="i in Object.keys(listenerTypeObject)"
:key="i"
:label="listenerTypeObject[i]"
:value="i"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="listenerForm.listenerType === 'classListener'"
label="Java类"
prop="class"
key="listener-class"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-input v-model="listenerForm.class" clearable />
</el-form-item>
<el-form-item
v-if="listenerForm.listenerType === 'expressionListener'"
label="表达式"
prop="expression"
key="listener-expression"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-input v-model="listenerForm.expression" clearable />
</el-form-item>
<el-form-item
v-if="listenerForm.listenerType === 'delegateExpressionListener'"
label="代理表达式"
prop="delegateExpression"
key="listener-delegate"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-input v-model="listenerForm.delegateExpression" clearable />
</el-form-item>
<template v-if="listenerForm.listenerType === 'scriptListener'">
<el-form-item
label="脚本格式"
prop="scriptFormat"
key="listener-script-format"
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本格式' }"
>
<el-input v-model="listenerForm.scriptFormat" clearable />
</el-form-item>
<el-form-item
label="脚本类型"
prop="scriptType"
key="listener-script-type"
:rules="{ required: true, trigger: ['blur', 'change'], message: '请选择脚本类型' }"
>
<el-select v-model="listenerForm.scriptType">
<el-option label="内联脚本" value="inlineScript" />
<el-option label="外部脚本" value="externalScript" />
</el-select>
</el-form-item>
<el-form-item
v-if="listenerForm.scriptType === 'inlineScript'"
label="脚本内容"
prop="value"
key="listener-script"
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本内容' }"
>
<el-input v-model="listenerForm.value" clearable />
</el-form-item>
<el-form-item
v-if="listenerForm.scriptType === 'externalScript'"
label="资源地址"
prop="resource"
key="listener-resource"
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写资源地址' }"
>
<el-input v-model="listenerForm.resource" clearable />
</el-form-item>
</template>
</el-form>
<el-divider />
<p class="listener-filed__title">
<span><Icon icon="ep:menu" />注入字段</span>
<el-button type="primary" @click="openListenerFieldForm(null)">添加字段</el-button>
</p>
<el-table
:data="fieldsListOfListener"
size="mini"
max-height="240"
border
fit
style="flex: none"
>
<el-table-column label="序号" width="50px" type="index" />
<el-table-column label="字段名称" min-width="100px" prop="name" />
<el-table-column
label="字段类型"
min-width="80px"
show-overflow-tooltip
:formatter="(row) => fieldTypeObject[row.fieldType]"
/>
<el-table-column
label="字段值/表达式"
min-width="100px"
show-overflow-tooltip
:formatter="(row) => row.string || row.expression"
/>
<el-table-column label="操作" width="100px">
<template #default="scope">
<el-button size="mini" type="text" @click="openListenerFieldForm(scope, scope.$index)"
>编辑</el-button
>
<el-divider direction="vertical" />
<el-button
size="mini"
type="text"
style="color: #ff4d4f"
@click="removeListenerField(scope, scope.$index)"
>移除</el-button
>
</template>
</el-table-column>
</el-table>
<div class="element-drawer__button">
<el-button size="mini" @click="listenerFormModelVisible = false"> </el-button>
<el-button size="mini" type="primary" @click="saveListenerConfig"> </el-button>
</div>
</el-drawer>
<!-- 注入西段 编辑/创建 部分 -->
<el-dialog
title="字段配置"
v-model="listenerFieldFormModelVisible"
width="600px"
append-to-body
destroy-on-close
>
<el-form
:model="listenerFieldForm"
label-width="96spx"
ref="listenerFieldFormRef"
style="height: 136px"
>
<el-form-item
label="字段名称:"
prop="name"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-input v-model="listenerFieldForm.name" clearable />
</el-form-item>
<el-form-item
label="字段类型:"
prop="fieldType"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-select v-model="listenerFieldForm.fieldType">
<el-option
v-for="i in Object.keys(fieldTypeObject)"
:key="i"
:label="fieldTypeObject[i]"
:value="i"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="listenerFieldForm.fieldType === 'string'"
label="字段值:"
prop="string"
key="field-string"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-input v-model="listenerFieldForm.string" clearable />
</el-form-item>
<el-form-item
v-if="listenerFieldForm.fieldType === 'expression'"
label="表达式:"
prop="expression"
key="field-expression"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-input v-model="listenerFieldForm.expression" clearable />
</el-form-item>
</el-form>
<template #footer>
<el-button size="mini" @click="listenerFieldFormModelVisible = false"> </el-button>
<el-button size="mini" type="primary" @click="saveListenerFiled"> </el-button>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="ElementListeners">
import { ref, inject, watch, nextTick } from 'vue'
import {
ElMessageBox,
ElTable,
ElTableColumn,
ElDivider,
ElOption,
ElSelect,
ElInput,
ElDrawer,
ElDialog,
ElForm,
ElFormItem
} from 'element-plus'
import { createListenerObject, updateElementExtensions } from '../../utils'
import { initListenerType, initListenerForm, listenerType, fieldType } from './utilSelf'
const props = defineProps({
id: String,
type: String
})
const prefix = inject('prefix')
const width = inject('width')
const elementListenersList = ref([]) // 监听器列表
const listenerForm = ref({}) // 监听器详情表单
const listenerFormModelVisible = ref(false) // 监听器 编辑 侧边栏显示状态
const fieldsListOfListener = ref([])
const listenerFieldForm = ref({}) // 监听器 注入字段 详情表单
const listenerFieldFormModelVisible = ref(false) // 监听器 注入字段表单弹窗 显示状态
const editingListenerIndex = ref(-1) // 监听器所在下标,-1 为新增
const editingListenerFieldIndex = ref(-1) // 字段所在下标,-1 为新增
const listenerTypeObject = ref(listenerType)
const fieldTypeObject = ref(fieldType)
const bpmnElement = ref()
const otherExtensionList = ref()
const bpmnElementListeners = ref()
const listenerFormRef = ref()
const listenerFieldFormRef = ref()
const resetListenersList = () => {
bpmnElement.value = window.bpmnInstances.bpmnElement
otherExtensionList.value = []
bpmnElementListeners.value =
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
(ex) => ex.$type === `${prefix}:ExecutionListener`
) ?? []
elementListenersList.value = bpmnElementListeners.value.map((listener) =>
initListenerType(listener)
)
}
// 打开 监听器详情 侧边栏
const openListenerForm = (listener, index) => {
if (listener) {
listenerForm.value = initListenerForm(listener)
editingListenerIndex.value = index
} else {
listenerForm.value = {}
editingListenerIndex.value = -1 // 标记为新增
}
if (listener && listener.fields) {
fieldsListOfListener.value = listener.fields.map((field) => ({
...field,
fieldType: field.string ? 'string' : 'expression'
}))
} else {
fieldsListOfListener.value = []
listenerForm.value['fields'] = []
}
// 打开侧边栏并清楚验证状态
listenerFormModelVisible.value = true
nextTick(() => {
if (listenerFormRef.value) listenerFormRef.value.clearValidate()
})
}
// 打开监听器字段编辑弹窗
const openListenerFieldForm = (field, index) => {
listenerFieldForm.value = field ? JSON.parse(JSON.stringify(field)) : {}
editingListenerFieldIndex.value = field ? index : -1
listenerFieldFormModelVisible.value = true
nextTick(() => {
if (listenerFieldFormRef.value) listenerFieldFormRef.value.clearValidate()
})
}
// 保存监听器注入字段
const saveListenerFiled = async () => {
let validateStatus = await listenerFieldFormRef.value.validate()
if (!validateStatus) return // 验证不通过直接返回
if (editingListenerFieldIndex.value === -1) {
fieldsListOfListener.value.push(listenerFieldForm.value)
listenerForm.value.fields.push(listenerFieldForm.value)
} else {
fieldsListOfListener.value.splice(editingListenerFieldIndex.value, 1, listenerFieldForm.value)
listenerForm.value.fields.splice(editingListenerFieldIndex.value, 1, listenerFieldForm.value)
}
listenerFieldFormModelVisible.value = false
nextTick(() => {
listenerFieldForm.value = {}
})
}
// 移除监听器字段
const removeListenerField = (field, index) => {
console.log(field, 'field')
ElMessageBox.confirm('确认移除该字段吗?', '提示', {
confirmButtonText: '确 认',
cancelButtonText: '取 消'
})
.then(() => {
fieldsListOfListener.value.splice(index, 1)
listenerForm.value.fields.splice(index, 1)
})
.catch(() => console.info('操作取消'))
}
// 移除监听器
const removeListener = (listener, index) => {
console.log(listener, 'listener')
ElMessageBox.confirm('确认移除该监听器吗?', '提示', {
confirmButtonText: '确 认',
cancelButtonText: '取 消'
})
.then(() => {
bpmnElementListeners.value.splice(index, 1)
elementListenersList.value.splice(index, 1)
updateElementExtensions(
bpmnElement.value,
otherExtensionList.value.concat(bpmnElementListeners.value)
)
})
.catch(() => console.info('操作取消'))
}
// 保存监听器配置
const saveListenerConfig = async () => {
let validateStatus = await listenerFormRef.value.validate()
if (!validateStatus) return // 验证不通过直接返回
const listenerObject = createListenerObject(listenerForm.value, false, prefix)
if (editingListenerIndex.value === -1) {
bpmnElementListeners.value.push(listenerObject)
elementListenersList.value.push(listenerForm.value)
} else {
bpmnElementListeners.value.splice(editingListenerIndex.value, 1, listenerObject)
elementListenersList.value.splice(editingListenerIndex.value, 1, listenerForm.value)
}
// 保存其他配置
otherExtensionList.value =
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
(ex) => ex.$type !== `${prefix}:ExecutionListener`
) ?? []
updateElementExtensions(
bpmnElement.value,
otherExtensionList.value.concat(bpmnElementListeners.value)
)
// 4. 隐藏侧边栏
listenerFormModelVisible.value = false
listenerForm.value = {}
}
watch(
() => props.id,
(val) => {
val &&
val.length &&
nextTick(() => {
resetListenersList()
})
},
{ immediate: true }
)
</script>

View File

@ -0,0 +1,456 @@
<template>
<div class="panel-tab__content">
<el-table :data="elementListenersList" size="mini" border>
<el-table-column label="序号" width="50px" type="index" />
<el-table-column
label="事件类型"
min-width="80px"
show-overflow-tooltip
:formatter="(row) => listenerEventTypeObject[row.event]"
/>
<el-table-column label="事件id" min-width="80px" prop="id" show-overflow-tooltip />
<el-table-column
label="监听器类型"
min-width="80px"
show-overflow-tooltip
:formatter="(row) => listenerTypeObject[row.listenerType]"
/>
<el-table-column label="操作" width="90px">
<template #default="scope">
<el-button size="mini" type="text" @click="openListenerForm(scope, scope.$index)"
>编辑</el-button
>
<el-divider direction="vertical" />
<el-button
size="mini"
type="text"
style="color: #ff4d4f"
@click="removeListener(scope, scope.$index)"
>移除</el-button
>
</template>
</el-table-column>
</el-table>
<div class="element-drawer__button">
<XButton
size="mini"
type="primary"
preIcon="ep:plus"
title="添加监听器"
@click="openListenerForm(null)"
/>
</div>
<!-- 监听器 编辑/创建 部分 -->
<el-drawer
v-model="listenerFormModelVisible"
title="任务监听器"
:size="`${width}px`"
append-to-body
destroy-on-close
>
<el-form size="mini" :model="listenerForm" label-width="96px" ref="listenerFormRef">
<el-form-item
label="事件类型"
prop="event"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-select v-model="listenerForm.event">
<el-option
v-for="i in Object.keys(listenerEventTypeObject)"
:key="i"
:label="listenerEventTypeObject[i]"
:value="i"
/>
</el-select>
</el-form-item>
<el-form-item
label="监听器ID"
prop="id"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-input v-model="listenerForm.id" clearable />
</el-form-item>
<el-form-item
label="监听器类型"
prop="listenerType"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-select v-model="listenerForm.listenerType">
<el-option
v-for="i in Object.keys(listenerTypeObject)"
:key="i"
:label="listenerTypeObject[i]"
:value="i"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="listenerForm.listenerType === 'classListener'"
label="Java类"
prop="class"
key="listener-class"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-input v-model="listenerForm.class" clearable />
</el-form-item>
<el-form-item
v-if="listenerForm.listenerType === 'expressionListener'"
label="表达式"
prop="expression"
key="listener-expression"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-input v-model="listenerForm.expression" clearable />
</el-form-item>
<el-form-item
v-if="listenerForm.listenerType === 'delegateExpressionListener'"
label="代理表达式"
prop="delegateExpression"
key="listener-delegate"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-input v-model="listenerForm.delegateExpression" clearable />
</el-form-item>
<template v-if="listenerForm.listenerType === 'scriptListener'">
<el-form-item
label="脚本格式"
prop="scriptFormat"
key="listener-script-format"
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本格式' }"
>
<el-input v-model="listenerForm.scriptFormat" clearable />
</el-form-item>
<el-form-item
label="脚本类型"
prop="scriptType"
key="listener-script-type"
:rules="{ required: true, trigger: ['blur', 'change'], message: '请选择脚本类型' }"
>
<el-select v-model="listenerForm.scriptType">
<el-option label="内联脚本" value="inlineScript" />
<el-option label="外部脚本" value="externalScript" />
</el-select>
</el-form-item>
<el-form-item
v-if="listenerForm.scriptType === 'inlineScript'"
label="脚本内容"
prop="value"
key="listener-script"
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本内容' }"
>
<el-input v-model="listenerForm.value" clearable />
</el-form-item>
<el-form-item
v-if="listenerForm.scriptType === 'externalScript'"
label="资源地址"
prop="resource"
key="listener-resource"
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写资源地址' }"
>
<el-input v-model="listenerForm.resource" clearable />
</el-form-item>
</template>
<template v-if="listenerForm.event === 'timeout'">
<el-form-item label="定时器类型" prop="eventDefinitionType" key="eventDefinitionType">
<el-select v-model="listenerForm.eventDefinitionType">
<el-option label="日期" value="date" />
<el-option label="持续时长" value="duration" />
<el-option label="循环" value="cycle" />
<el-option label="无" value="null" />
</el-select>
</el-form-item>
<el-form-item
v-if="!!listenerForm.eventDefinitionType && listenerForm.eventDefinitionType !== 'null'"
label="定时器"
prop="eventTimeDefinitions"
key="eventTimeDefinitions"
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写定时器配置' }"
>
<el-input v-model="listenerForm.eventTimeDefinitions" clearable />
</el-form-item>
</template>
</el-form>
<el-divider />
<p class="listener-filed__title">
<span><Icon icon="ep:menu" />注入字段</span>
<el-button size="mini" type="primary" @click="openListenerFieldForm(null)"
>添加字段</el-button
>
</p>
<el-table
:data="fieldsListOfListener"
size="mini"
max-height="240"
border
fit
style="flex: none"
>
<el-table-column label="序号" width="50px" type="index" />
<el-table-column label="字段名称" min-width="100px" prop="name" />
<el-table-column
label="字段类型"
min-width="80px"
show-overflow-tooltip
:formatter="(row) => fieldTypeObject[row.fieldType]"
/>
<el-table-column
label="字段值/表达式"
min-width="100px"
show-overflow-tooltip
:formatter="(row) => row.string || row.expression"
/>
<el-table-column label="操作" width="100px">
<template #default="scope">
<el-button size="mini" type="text" @click="openListenerFieldForm(scope, scope.$index)"
>编辑</el-button
>
<el-divider direction="vertical" />
<el-button
size="mini"
type="text"
style="color: #ff4d4f"
@click="removeListenerField(scope, scope.$index)"
>移除</el-button
>
</template>
</el-table-column>
</el-table>
<div class="element-drawer__button">
<el-button size="mini" @click="listenerFormModelVisible = false"> </el-button>
<el-button size="mini" type="primary" @click="saveListenerConfig"> </el-button>
</div>
</el-drawer>
<!-- 注入西段 编辑/创建 部分 -->
<el-dialog
title="字段配置"
v-model="listenerFieldFormModelVisible"
width="600px"
append-to-body
destroy-on-close
>
<el-form
:model="listenerFieldForm"
size="mini"
label-width="96px"
ref="listenerFieldFormRef"
style="height: 136px"
>
<el-form-item
label="字段名称:"
prop="name"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-input v-model="listenerFieldForm.name" clearable />
</el-form-item>
<el-form-item
label="字段类型:"
prop="fieldType"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-select v-model="listenerFieldForm.fieldType">
<el-option
v-for="i in Object.keys(fieldTypeObject)"
:key="i"
:label="fieldTypeObject[i]"
:value="i"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="listenerFieldForm.fieldType === 'string'"
label="字段值:"
prop="string"
key="field-string"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-input v-model="listenerFieldForm.string" clearable />
</el-form-item>
<el-form-item
v-if="listenerFieldForm.fieldType === 'expression'"
label="表达式:"
prop="expression"
key="field-expression"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-input v-model="listenerFieldForm.expression" clearable />
</el-form-item>
</el-form>
<template #footer>
<el-button size="mini" @click="listenerFieldFormModelVisible = false"> </el-button>
<el-button size="mini" type="primary" @click="saveListenerFiled"> </el-button>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup name="UserTaskListeners">
import { ref, inject, watch, nextTick } from 'vue'
import {
ElDialog,
ElForm,
ElFormItem,
ElSelect,
ElOption,
ElDivider,
ElTable,
ElTableColumn,
ElMessageBox,
ElButton,
ElDrawer
} from 'element-plus'
import { createListenerObject, updateElementExtensions } from '../../utils'
import { initListenerForm, initListenerType, eventType, listenerType, fieldType } from './utilSelf'
const props = defineProps({
id: String,
type: String
})
const prefix = inject('prefix')
const width = inject('width')
const elementListenersList = ref([])
const listenerEventTypeObject = ref(eventType)
const listenerTypeObject = ref(listenerType)
const listenerFormModelVisible = ref(false)
const listenerForm = ref({})
const fieldTypeObject = ref(fieldType)
const fieldsListOfListener = ref([])
const listenerFieldFormModelVisible = ref(false) // 监听器 注入字段表单弹窗 显示状态
const editingListenerIndex = ref(-1) // 监听器所在下标,-1 为新增
const editingListenerFieldIndex = ref(-1) // 字段所在下标,-1 为新增
const listenerFieldForm = ref({}) // 监听器 注入字段 详情表单
const bpmnElement = ref()
const bpmnElementListeners = ref()
const otherExtensionList = ref()
const listenerFormRef = ref()
const listenerFieldFormRef = ref()
const resetListenersList = () => {
bpmnElement.value = window.bpmnInstances.bpmnElement
otherExtensionList.value = []
bpmnElementListeners.value =
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
(ex) => ex.$type === `${prefix}:TaskListener`
) ?? []
elementListenersList.value = bpmnElementListeners.value.map((listener) =>
initListenerType(listener)
)
}
const openListenerForm = (listener, index) => {
if (listener) {
listenerForm.value = initListenerForm(listener)
editingListenerIndex.value = index
} else {
listenerForm.value = {}
editingListenerIndex.value = -1 // 标记为新增
}
if (listener && listener.fields) {
fieldsListOfListener.value = listener.fields.map((field) => ({
...field,
fieldType: field.string ? 'string' : 'expression'
}))
} else {
fieldsListOfListener.value = []
listenerForm.value['fields'] = []
}
// 打开侧边栏并清楚验证状态
listenerFormModelVisible.value = true
nextTick(() => {
if (listenerFormRef.value) listenerFormRef.value.clearValidate()
})
}
// 移除监听器
const removeListener = (listener, index) => {
console.log(listener, 'listener')
ElMessageBox.confirm('确认移除该监听器吗?', '提示', {
confirmButtonText: '确 认',
cancelButtonText: '取 消'
})
.then(() => {
bpmnElementListeners.value.splice(index, 1)
elementListenersList.value.splice(index, 1)
updateElementExtensions(
bpmnElement.value,
otherExtensionList.value.concat(bpmnElementListeners.value)
)
})
.catch(() => console.info('操作取消'))
}
// 保存监听器
const saveListenerConfig = async () => {
let validateStatus = await listenerFormRef.value.validate()
if (!validateStatus) return // 验证不通过直接返回
const listenerObject = createListenerObject(listenerForm.value, true, prefix)
if (editingListenerIndex.value === -1) {
bpmnElementListeners.value.push(listenerObject)
elementListenersList.value.push(listenerForm.value)
} else {
bpmnElementListeners.value.splice(editingListenerIndex.value, 1, listenerObject)
elementListenersList.value.splice(editingListenerIndex.value, 1, listenerForm.value)
}
// 保存其他配置
otherExtensionList.value =
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
(ex) => ex.$type !== `${prefix}:TaskListener`
) ?? []
updateElementExtensions(
bpmnElement.value,
otherExtensionList.value.concat(bpmnElementListeners.value)
)
// 4. 隐藏侧边栏
listenerFormModelVisible.value = false
listenerForm.value = {}
}
// 打开监听器字段编辑弹窗
const openListenerFieldForm = (field, index) => {
listenerFieldForm.value = field ? JSON.parse(JSON.stringify(field)) : {}
editingListenerFieldIndex.value = field ? index : -1
listenerFieldFormModelVisible.value = true
nextTick(() => {
if (listenerFieldFormRef.value) listenerFieldFormRef.value.clearValidate()
})
}
// 保存监听器注入字段
const saveListenerFiled = async () => {
let validateStatus = await listenerFieldFormRef.value.validate()
if (!validateStatus) return // 验证不通过直接返回
if (editingListenerFieldIndex.value === -1) {
fieldsListOfListener.value.push(listenerFieldForm.value)
listenerForm.value.fields.push(listenerFieldForm.value)
} else {
fieldsListOfListener.value.splice(editingListenerFieldIndex.value, 1, listenerFieldForm.value)
listenerForm.value.fields.splice(editingListenerFieldIndex.value, 1, listenerFieldForm.value)
}
listenerFieldFormModelVisible.value = false
nextTick(() => {
listenerFieldForm.value = {}
})
}
// 移除监听器字段
const removeListenerField = (field, index) => {
console.log(field, 'field')
ElMessageBox.confirm('确认移除该字段吗?', '提示', {
confirmButtonText: '确 认',
cancelButtonText: '取 消'
})
.then(() => {
fieldsListOfListener.value.splice(index, 1)
listenerForm.value.fields.splice(index, 1)
})
.catch(() => console.info('操作取消'))
}
watch(
() => props.id,
(val) => {
val &&
val.length &&
nextTick(() => {
resetListenersList()
})
},
{ immediate: true }
)
</script>

View File

@ -0,0 +1,177 @@
export const template = isTaskListener => {
return `
<div class="panel-tab__content">
<el-table :data="elementListenersList" size="mini" border>
<el-table-column label="序号" width="50px" type="index" />
<el-table-column label="事件类型" min-width="100px" prop="event" />
<el-table-column label="监听器类型" min-width="100px" show-overflow-tooltip :formatter="row => listenerTypeObject[row.listenerType]" />
<el-table-column label="操作" width="90px">
<template #default="scope">
<el-button size="mini" type="text" @click="openListenerForm(scope, scope.$index)">编辑</el-button>
<el-divider direction="vertical" />
<el-button size="mini" type="text" style="color: #ff4d4f" @click="removeListener(scope, scope.$index)">移除</el-button>
</template>
</el-table-column>
</el-table>
<div class="element-drawer__button">
<el-button size="mini" type="primary" icon="el-icon-plus" @click="openListenerForm(null)">添加监听器</el-button>
</div>
<!-- 监听器 编辑/创建 部分 -->
<el-drawer :visible.sync="listenerFormModelVisible" title="执行监听器" :size="width + 'px'" append-to-body destroy-on-close>
<el-form size="mini" :model="listenerForm" label-width="96px" ref="listenerFormRef" @submit.native.prevent>
<el-form-item label="事件类型" prop="event" :rules="{ required: true, trigger: ['blur', 'change'] }">
<el-select v-model="listenerForm.event">
<el-option label="start" value="start" />
<el-option label="end" value="end" />
</el-select>
</el-form-item>
<el-form-item label="监听器类型" prop="listenerType" :rules="{ required: true, trigger: ['blur', 'change'] }">
<el-select v-model="listenerForm.listenerType">
<el-option v-for="i in Object.keys(listenerTypeObject)" :key="i" :label="listenerTypeObject[i]" :value="i" />
</el-select>
</el-form-item>
<el-form-item
v-if="listenerForm.listenerType === 'classListener'"
label="Java类"
prop="class"
key="listener-class"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-input v-model="listenerForm.class" clearable />
</el-form-item>
<el-form-item
v-if="listenerForm.listenerType === 'expressionListener'"
label="表达式"
prop="expression"
key="listener-expression"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-input v-model="listenerForm.expression" clearable />
</el-form-item>
<el-form-item
v-if="listenerForm.listenerType === 'delegateExpressionListener'"
label="代理表达式"
prop="delegateExpression"
key="listener-delegate"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-input v-model="listenerForm.delegateExpression" clearable />
</el-form-item>
<template v-if="listenerForm.listenerType === 'scriptListener'">
<el-form-item
label="脚本格式"
prop="scriptFormat"
key="listener-script-format"
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本格式' }"
>
<el-input v-model="listenerForm.scriptFormat" clearable />
</el-form-item>
<el-form-item
label="脚本类型"
prop="scriptType"
key="listener-script-type"
:rules="{ required: true, trigger: ['blur', 'change'], message: '请选择脚本类型' }"
>
<el-select v-model="listenerForm.scriptType">
<el-option label="内联脚本" value="inlineScript" />
<el-option label="外部脚本" value="externalScript" />
</el-select>
</el-form-item>
<el-form-item
v-if="listenerForm.scriptType === 'inlineScript'"
label="脚本内容"
prop="value"
key="listener-script"
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本内容' }"
>
<el-input v-model="listenerForm.value" clearable />
</el-form-item>
<el-form-item
v-if="listenerForm.scriptType === 'externalScript'"
label="资源地址"
prop="resource"
key="listener-resource"
:rules="{ required: true, trigger: ['blur', 'change'], message: '请填写资源地址' }"
>
<el-input v-model="listenerForm.resource" clearable />
</el-form-item>
</template>
${isTaskListener
? "<el-form-item label='定时器类型' prop='eventDefinitionType' key='eventDefinitionType'>" +
"<el-select v-model='listenerForm.eventDefinitionType'>" +
"<el-option label='日期' value='date' />" +
"<el-option label='持续时长' value='duration' />" +
"<el-option label='循环' value='cycle' />" +
"<el-option label='无' value='' />" +
"</el-select>" +
"</el-form-item>" +
"<el-form-item v-if='!!listenerForm.eventDefinitionType' label='定时器' prop='eventDefinitions' key='eventDefinitions'>" +
"<el-input v-model='listenerForm.eventDefinitions' clearable />" +
"</el-form-item>"
: ""
}
</el-form>
<el-divider />
<p class="listener-filed__title">
<span><i class="el-icon-menu"></i>注入字段:</span>
<el-button size="mini" type="primary" @click="openListenerFieldForm(null)">添加字段</el-button>
</p>
<el-table :data="fieldsListOfListener" size="mini" max-height="240" border fit style="flex: none">
<el-table-column label="序号" width="50px" type="index" />
<el-table-column label="字段名称" min-width="100px" prop="name" />
<el-table-column label="字段类型" min-width="80px" show-overflow-tooltip :formatter="row => fieldTypeObject[row.fieldType]" />
<el-table-column label="字段值/表达式" min-width="100px" show-overflow-tooltip :formatter="row => row.string || row.expression" />
<el-table-column label="操作" width="100px">
<template #default="scope">
<el-button size="mini" type="text" @click="openListenerFieldForm(scope, scope.$index)">编辑</el-button>
<el-divider direction="vertical" />
<el-button size="mini" type="text" style="color: #ff4d4f" @click="removeListenerField(scope, scope.$index)">移除</el-button>
</template>
</el-table-column>
</el-table>
<div class="element-drawer__button">
<el-button size="mini" @click="listenerFormModelVisible = false">取 消</el-button>
<el-button size="mini" type="primary" @click="saveListenerConfig">保 存</el-button>
</div>
</el-drawer>
<!-- 注入西段 编辑/创建 部分 -->
<el-dialog title="字段配置" :visible.sync="listenerFieldFormModelVisible" width="600px" append-to-body destroy-on-close>
<el-form :model="listenerFieldForm" size="mini" label-width="96px" ref="listenerFieldFormRef" style="height: 136px" @submit.native.prevent>
<el-form-item label="字段名称:" prop="name" :rules="{ required: true, trigger: ['blur', 'change'] }">
<el-input v-model="listenerFieldForm.name" clearable />
</el-form-item>
<el-form-item label="字段类型:" prop="fieldType" :rules="{ required: true, trigger: ['blur', 'change'] }">
<el-select v-model="listenerFieldForm.fieldType">
<el-option v-for="i in Object.keys(fieldTypeObject)" :key="i" :label="fieldTypeObject[i]" :value="i" />
</el-select>
</el-form-item>
<el-form-item
v-if="listenerFieldForm.fieldType === 'string'"
label="字段值:"
prop="string"
key="field-string"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-input v-model="listenerFieldForm.string" clearable />
</el-form-item>
<el-form-item
v-if="listenerFieldForm.fieldType === 'expression'"
label="表达式:"
prop="expression"
key="field-expression"
:rules="{ required: true, trigger: ['blur', 'change'] }"
>
<el-input v-model="listenerFieldForm.expression" clearable />
</el-form-item>
</el-form>
<template #footer>
<el-button size="mini" @click="listenerFieldFormModelVisible = false">取 消</el-button>
<el-button size="mini" type="primary" @click="saveListenerFiled">确 定</el-button>
</template>
</el-dialog>
</div>
`
}

View File

@ -0,0 +1,62 @@
// 初始化表单数据
export function initListenerForm(listener) {
let self = {
...listener
};
if (listener.script) {
self = {
...listener,
...listener.script,
scriptType: listener.script.resource ? "externalScript" : "inlineScript"
};
}
if (listener.event === "timeout" && listener.eventDefinitions) {
if (listener.eventDefinitions.length) {
let k = "";
for (let key in listener.eventDefinitions[0]) {
console.log(listener.eventDefinitions, key);
if (key.indexOf("time") !== -1) {
k = key;
self.eventDefinitionType = key.replace("time", "").toLowerCase();
}
}
console.log(k);
self.eventTimeDefinitions = listener.eventDefinitions[0][k].body;
}
}
return self;
}
export function initListenerType(listener) {
let listenerType;
if (listener.class) listenerType = "classListener";
if (listener.expression) listenerType = "expressionListener";
if (listener.delegateExpression) listenerType = "delegateExpressionListener";
if (listener.script) listenerType = "scriptListener";
return {
...JSON.parse(JSON.stringify(listener)),
...(listener.script ?? {}),
listenerType: listenerType
};
}
export const listenerType = {
classListener: "Java 类",
expressionListener: "表达式",
delegateExpressionListener: "代理表达式",
scriptListener: "脚本"
};
export const eventType = {
create: "创建",
assignment: "指派",
complete: "完成",
delete: "删除",
update: "更新",
timeout: "超时"
};
export const fieldType = {
string: "字符串",
expression: "表达式"
};

View File

@ -0,0 +1,237 @@
<template>
<div class="panel-tab__content">
<el-form label-width="90px">
<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="Null" />
</el-select>
</el-form-item>
<template
v-if="
loopCharacteristics === 'ParallelMultiInstance' ||
loopCharacteristics === 'SequentialMultiInstance'
"
>
<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-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-checkbox
v-model="loopInstanceForm.asyncBefore"
label="异步前"
@change="updateLoopAsync('asyncBefore')"
/>
<el-checkbox
v-model="loopInstanceForm.asyncAfter"
label="异步后"
@change="updateLoopAsync('asyncAfter')"
/>
<el-checkbox
v-model="loopInstanceForm.exclusive"
v-if="loopInstanceForm.asyncAfter || loopInstanceForm.asyncBefore"
label="排除"
@change="updateLoopAsync('exclusive')"
/>
</el-form-item>
<el-form-item
label="重试周期"
prop="timeCycle"
v-if="loopInstanceForm.asyncAfter || loopInstanceForm.asyncBefore"
key="timeCycle"
>
<el-input v-model="loopInstanceForm.timeCycle" clearable @change="updateLoopTimeCycle" />
</el-form-item>
</template>
</el-form>
</div>
</template>
<script setup lang="ts" name="ElementMultiInstance">
import { inject, ref, onBeforeUnmount, watch } from 'vue'
import { ElForm, ElFormItem, ElSelect, ElOption, ElCheckbox, ElInput } from 'element-plus'
const props = defineProps({
businessObject: Object,
type: String
})
const prefix = inject('prefix')
const loopCharacteristics = ref('')
//默认配置用来覆盖原始不存在的选项避免报错
const defaultLoopInstanceForm = ref({
completionCondition: '',
loopCardinality: '',
extensionElements: [],
asyncAfter: false,
asyncBefore: false,
exclusive: false
})
const loopInstanceForm = ref({})
const bpmnElement = ref()
const multiLoopInstance = ref()
const getElementLoop = (businessObject) => {
if (!businessObject.loopCharacteristics) {
loopCharacteristics.value = 'Null'
loopInstanceForm.value = {}
return
}
if (businessObject.loopCharacteristics.$type === 'bpmn:StandardLoopCharacteristics') {
loopCharacteristics.value = 'StandardLoop'
loopInstanceForm.value = {}
return
}
if (businessObject.loopCharacteristics.isSequential) {
loopCharacteristics.value = 'SequentialMultiInstance'
} else {
loopCharacteristics.value = 'ParallelMultiInstance'
}
// 合并配置
loopInstanceForm.value = {
...defaultLoopInstanceForm.value,
...businessObject.loopCharacteristics,
completionCondition: businessObject.loopCharacteristics?.completionCondition?.body ?? '',
loopCardinality: businessObject.loopCharacteristics?.loopCardinality?.body ?? ''
}
// 保留当前元素 businessObject 上的 loopCharacteristics 实例
multiLoopInstance.value = window.bpmnInstances.bpmnElement.businessObject.loopCharacteristics
// 更新表单
if (
businessObject.loopCharacteristics.extensionElements &&
businessObject.loopCharacteristics.extensionElements.values &&
businessObject.loopCharacteristics.extensionElements.values.length
) {
loopInstanceForm.value['timeCycle'] =
businessObject.loopCharacteristics.extensionElements.values[0].body
}
}
const changeLoopCharacteristicsType = (type) => {
// this.loopInstanceForm = { ...this.defaultLoopInstanceForm }; // 切换类型取消原表单配置
// 取消多实例配置
if (type === 'Null') {
window.bpmnInstances.modeling.updateProperties(bpmnElement.value, { loopCharacteristics: null })
return
}
// 配置循环
if (type === 'StandardLoop') {
const loopCharacteristicsObject = window.bpmnInstances.moddle.create(
'bpmn:StandardLoopCharacteristics'
)
window.bpmnInstances.modeling.updateProperties(bpmnElement.value, {
loopCharacteristics: loopCharacteristicsObject
})
multiLoopInstance.value = null
return
}
// 时序
if (type === 'SequentialMultiInstance') {
multiLoopInstance.value = window.bpmnInstances.moddle.create(
'bpmn:MultiInstanceLoopCharacteristics',
{ isSequential: true }
)
} else {
multiLoopInstance.value = window.bpmnInstances.moddle.create(
'bpmn:MultiInstanceLoopCharacteristics',
{ collection: '${coll_userList}' }
)
}
window.bpmnInstances.modeling.updateProperties(bpmnElement.value, {
loopCharacteristics: multiLoopInstance.value
})
}
// 循环基数
const updateLoopCardinality = (cardinality) => {
let loopCardinality = null
if (cardinality && cardinality.length) {
loopCardinality = window.bpmnInstances.moddle.create('bpmn:FormalExpression', {
body: cardinality
})
}
window.bpmnInstances.modeling.updateModdleProperties(bpmnElement.value, multiLoopInstance.value, {
loopCardinality
})
}
// 完成条件
const updateLoopCondition = (condition) => {
let completionCondition = null
if (condition && condition.length) {
completionCondition = window.bpmnInstances.moddle.create('bpmn:FormalExpression', {
body: condition
})
}
window.bpmnInstances.modeling.updateModdleProperties(bpmnElement.value, multiLoopInstance.value, {
completionCondition
})
}
// 重试周期
const updateLoopTimeCycle = (timeCycle) => {
const extensionElements = window.bpmnInstances.moddle.create('bpmn:ExtensionElements', {
values: [
window.bpmnInstances.moddle.create(`${prefix}:FailedJobRetryTimeCycle`, {
body: timeCycle
})
]
})
window.bpmnInstances.modeling.updateModdleProperties(bpmnElement.value, multiLoopInstance.value, {
extensionElements
})
}
// 直接更新的基础信息
const updateLoopBase = () => {
window.bpmnInstances.modeling.updateModdleProperties(bpmnElement.value, multiLoopInstance.value, {
collection: loopInstanceForm.value.collection || null,
elementVariable: loopInstanceForm.value.elementVariable || null
})
}
// 各异步状态
const updateLoopAsync = (key) => {
const { asyncBefore, asyncAfter } = loopInstanceForm.value
let asyncAttr = Object.create(null)
if (!asyncBefore && !asyncAfter) {
// this.$set(this.loopInstanceForm, "exclusive", false);
loopInstanceForm.value['exclusive'] = false
asyncAttr = { asyncBefore: false, asyncAfter: false, exclusive: false, extensionElements: null }
} else {
asyncAttr[key] = loopInstanceForm.value[key]
}
window.bpmnInstances.modeling.updateModdleProperties(
bpmnElement.value,
multiLoopInstance.value,
asyncAttr
)
}
onBeforeUnmount(() => {
multiLoopInstance.value = null
bpmnElement.value = null
})
watch(
() => props.type,
(val) => {
bpmnElement.value = window.bpmnInstances.bpmnElement
getElementLoop(val)
},
{ immediate: true }
)
</script>

View File

@ -0,0 +1,55 @@
<template>
<div class="panel-tab__content">
<div class="element-property input-property">
<div class="element-property__label">元素文档</div>
<div class="element-property__value">
<el-input
type="textarea"
v-model="documentation"
resize="vertical"
:autosize="{ minRows: 2, maxRows: 4 }"
@input="updateDocumentation"
@blur="updateDocumentation"
/>
</div>
</div>
</div>
</template>
<script setup lang="ts" name="ElementOtherConfig">
import { ref, watch, nextTick, onBeforeUnmount } from 'vue'
import { ElInput } from 'element-plus'
const props = defineProps({
id: String
})
const documentation = ref('')
const bpmnElement = ref()
const updateDocumentation = () => {
;(bpmnElement.value && bpmnElement.value.id === props.id) ||
(bpmnElement.value = window.bpmnInstances.elementRegistry.get(props.id))
const documentation = window.bpmnInstances.bpmnFactory.create('bpmn:Documentation', {
text: documentation.value
})
window.bpmnInstances.modeling.updateProperties(bpmnElement.value, {
documentation: [documentation]
})
}
onBeforeUnmount(() => {
bpmnElement.value = null
})
watch(
() => props.id,
(id) => {
if (id && id.length) {
nextTick(() => {
const documentations = window.bpmnInstances.bpmnElement.businessObject?.documentation
documentation.value = documentations && documentations.length ? documentations[0].text : ''
})
} else {
documentation.value = ''
}
},
{ immediate: true }
)
</script>

View File

@ -0,0 +1,172 @@
<template>
<div class="panel-tab__content">
<el-table :data="elementPropertyList" max-height="240" border fit>
<el-table-column label="序号" width="50px" type="index" />
<el-table-column label="属性名" prop="name" min-width="100px" show-overflow-tooltip />
<el-table-column label="属性值" prop="value" min-width="100px" show-overflow-tooltip />
<el-table-column label="操作" width="90px">
<template #default="scope">
<el-button type="text" @click="openAttributesForm(scope, scope.$index)">编辑</el-button>
<el-divider direction="vertical" />
<el-button
type="text"
style="color: #ff4d4f"
@click="removeAttributes(scope, scope.$index)"
>移除</el-button
>
</template>
</el-table-column>
</el-table>
<div class="element-drawer__button">
<XButton
type="primary"
preIcon="ep:plus"
title="添加属性"
@click="openAttributesForm(null, -1)"
/>
</div>
<el-dialog
v-model="propertyFormModelVisible"
title="属性配置"
width="600px"
append-to-body
destroy-on-close
>
<el-form :model="propertyForm" label-width="80px" ref="attributeFormRef">
<el-form-item label="属性名:" prop="name">
<el-input v-model="propertyForm.name" clearable />
</el-form-item>
<el-form-item label="属性值:" prop="value">
<el-input v-model="propertyForm.value" clearable />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="propertyFormModelVisible = false"> </el-button>
<el-button type="primary" @click="saveAttribute"> </el-button>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="ElementProperties">
import { ref, inject, nextTick, watch } from 'vue'
import {
ElMessageBox,
ElDialog,
ElButton,
ElForm,
ElFormItem,
ElTable,
ElTableColumn,
ElDivider,
ElInput
} from 'element-plus'
const props = defineProps({
id: String,
type: String
})
const prefix = inject('prefix')
// const width = inject('width')
const elementPropertyList = ref([])
const propertyForm = ref({})
const editingPropertyIndex = ref(-1)
const propertyFormModelVisible = ref(false)
const bpmnElement = ref()
const otherExtensionList = ref()
const bpmnElementProperties = ref()
const bpmnElementPropertyList = ref()
const attributeFormRef = ref()
const resetAttributesList = () => {
bpmnElement.value = window.bpmnInstances.bpmnElement
otherExtensionList.value = [] // 其他扩展配置
bpmnElementProperties.value =
bpmnElement.value.businessObject?.extensionElements?.values?.filter((ex) => {
if (ex.$type !== `${prefix.value}:Properties`) {
otherExtensionList.value.push(ex)
}
return ex.$type === `${prefix.value}:Properties`
}) ?? []
// 保存所有的 扩展属性字段
bpmnElementPropertyList.value = bpmnElementProperties.value.reduce(
(pre, current) => pre.concat(current.values),
[]
)
// 复制 显示
elementPropertyList.value = JSON.parse(JSON.stringify(bpmnElementPropertyList.value ?? []))
}
const openAttributesForm = (attr, index) => {
editingPropertyIndex.value = index
propertyForm.value = index === -1 ? {} : JSON.parse(JSON.stringify(attr))
propertyFormModelVisible.value = true
nextTick(() => {
if (attributeFormRef.value) attributeFormRef.value.clearValidate()
})
}
const removeAttributes = (attr, index) => {
console.log(attr, 'attr')
ElMessageBox.confirm('确认移除该属性吗?', '提示', {
confirmButtonText: '确 认',
cancelButtonText: '取 消'
})
.then(() => {
elementPropertyList.value.splice(index, 1)
bpmnElementPropertyList.value.splice(index, 1)
// 新建一个属性字段的保存列表
const propertiesObject = window.bpmnInstances.moddle.create(`${prefix.value}:Properties`, {
values: bpmnElementPropertyList.value
})
updateElementExtensions(propertiesObject)
resetAttributesList()
})
.catch(() => console.info('操作取消'))
}
const saveAttribute = () => {
const { name, value } = propertyForm.value
console.log(bpmnElementPropertyList.value)
if (editingPropertyIndex.value !== -1) {
window.bpmnInstances.modeling.updateModdleProperties(
bpmnElement.value,
bpmnElementPropertyList.value[editingPropertyIndex.value],
{
name,
value
}
)
} else {
// 新建属性字段
const newPropertyObject = window.bpmnInstances.moddle.create(`${prefix.value}:Property`, {
name,
value
})
// 新建一个属性字段的保存列表
const propertiesObject = window.bpmnInstances.moddle.create(`${prefix.value}:Properties`, {
values: bpmnElementPropertyList.value.concat([newPropertyObject])
})
updateElementExtensions(propertiesObject)
}
propertyFormModelVisible.value = false
resetAttributesList()
}
const updateElementExtensions = (properties) => {
const extensions = window.bpmnInstances.moddle.create('bpmn:ExtensionElements', {
values: otherExtensionList.value.concat([properties])
})
window.bpmnInstances.modeling.updateProperties(bpmnElement.value, {
extensionElements: extensions
})
}
watch(
() => props.id,
(val) => {
if (val) {
val && val.length && resetAttributesList()
}
},
{ immediate: true }
)
</script>

View File

@ -0,0 +1,120 @@
<template>
<div class="panel-tab__content">
<div class="panel-tab__content--title">
<span><Icon icon="ep:menu" style="margin-right: 8px; color: #555555" />消息列表</span>
<XButton type="primary" title="创建新消息" preIcon="ep:plus" @click="openModel('message')" />
</div>
<el-table :data="messageList" border>
<el-table-column type="index" label="序号" width="60px" />
<el-table-column label="消息ID" prop="id" max-width="300px" show-overflow-tooltip />
<el-table-column label="消息名称" prop="name" max-width="300px" show-overflow-tooltip />
</el-table>
<div
class="panel-tab__content--title"
style="padding-top: 8px; margin-top: 8px; border-top: 1px solid #eeeeee"
>
<span><Icon icon="ep:menu" style="margin-right: 8px; color: #555555" />信号列表</span>
<XButton type="primary" title="创建新信号" preIcon="ep:plus" @click="openModel('signal')" />
</div>
<el-table :data="signalList" border>
<el-table-column type="index" label="序号" width="60px" />
<el-table-column label="信号ID" prop="id" max-width="300px" show-overflow-tooltip />
<el-table-column label="信号名称" prop="name" max-width="300px" show-overflow-tooltip />
</el-table>
<el-dialog
v-model="modelVisible"
:title="modelConfig.title"
:close-on-click-modal="false"
width="400px"
append-to-body
destroy-on-close
>
<el-form :model="modelObjectForm" label-width="90px">
<el-form-item :label="modelConfig.idLabel">
<el-input v-model="modelObjectForm.id" clearable />
</el-form-item>
<el-form-item :label="modelConfig.nameLabel">
<el-input v-model="modelObjectForm.name" clearable />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="modelVisible = false"> </el-button>
<el-button type="primary" @click="addNewObject"> </el-button>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="SignalAndMassage">
import {
ElMessage,
ElDialog,
ElForm,
ElFormItem,
ElTable,
ElTableColumn,
ElButton,
ElInput
} from 'element-plus'
import { ref, computed, onMounted } from 'vue'
const signalList = ref([])
const messageList = ref([])
const modelVisible = ref(false)
const modelType = ref('')
const modelObjectForm = ref({})
const rootElements = ref()
const messageIdMap = ref()
const signalIdMap = ref()
const modelConfig = computed(() => {
if (modelType.value === 'message') {
return { title: '创建消息', idLabel: '消息ID', nameLabel: '消息名称' }
} else {
return { title: '创建信号', idLabel: '信号ID', nameLabel: '信号名称' }
}
})
const initDataList = () => {
console.log(window, 'window')
rootElements.value = window.bpmnInstances.modeler.getDefinitions().rootElements
messageIdMap.value = {}
signalIdMap.value = {}
messageList.value = []
signalList.value = []
rootElements.value.forEach((el) => {
if (el.$type === 'bpmn:Message') {
messageIdMap.value[el.id] = true
messageList.value.push({ ...el })
}
if (el.$type === 'bpmn:Signal') {
signalIdMap.value[el.id] = true
signalList.value.push({ ...el })
}
})
}
const openModel = (type) => {
modelType.value = type
modelObjectForm.value = {}
modelVisible.value = true
}
const addNewObject = () => {
if (modelType.value === 'message') {
if (messageIdMap.value[modelObjectForm.value.id]) {
ElMessage.error('该消息已存在请修改id后重新保存')
}
const messageRef = window.bpmnInstances.moddle.create('bpmn:Message', modelObjectForm.value)
rootElements.value.push(messageRef)
} else {
if (signalIdMap.value[modelObjectForm.value.id]) {
ElMessage.error('该信号已存在请修改id后重新保存')
}
const signalRef = window.bpmnInstances.moddle.create('bpmn:Signal', modelObjectForm.value)
rootElements.value.push(signalRef)
}
modelVisible.value = false
initDataList()
}
onMounted(() => {
initDataList()
})
</script>

View File

@ -0,0 +1,85 @@
<template>
<div class="panel-tab__content">
<el-form size="mini" label-width="90px">
<el-form-item label="异步延续">
<el-checkbox
v-model="taskConfigForm.asyncBefore"
label="异步前"
@change="changeTaskAsync"
/>
<el-checkbox v-model="taskConfigForm.asyncAfter" label="异步后" @change="changeTaskAsync" />
<el-checkbox
v-model="taskConfigForm.exclusive"
v-if="taskConfigForm.asyncAfter || taskConfigForm.asyncBefore"
label="排除"
@change="changeTaskAsync"
/>
</el-form-item>
<component :is="witchTaskComponent" v-bind="$props" />
</el-form>
</div>
</template>
<script setup lang="ts" name="ElementTaskConfig">
import { ref, watch, shallowRef } from 'vue'
import { ElForm, ElFormItem, ElCheckbox } from 'element-plus'
import UserTask from './task-components/UserTask.vue'
import ScriptTask from './task-components/ScriptTask.vue'
import ReceiveTask from './task-components/ReceiveTask.vue'
const props = defineProps({
id: String,
type: String
})
const taskConfigForm = ref({
asyncAfter: false,
asyncBefore: false,
exclusive: false
})
const witchTaskComponent = shallowRef()
const installedComponent = ref({
// 手工任务与普通任务一致,不需要其他配置
// 接收消息任务,需要在全局下插入新的消息实例,并在该节点下的 messageRef 属性绑定该实例
// 发送任务、服务任务、业务规则任务共用一个相同配置
UserTask: 'UserTask', // 用户任务配置
ScriptTask: 'ScriptTask', // 脚本任务配置
ReceiveTask: 'ReceiveTask' // 消息接收任务
})
const bpmnElement = ref()
const changeTaskAsync = () => {
if (!taskConfigForm.value.asyncBefore && !taskConfigForm.value.asyncAfter) {
taskConfigForm.value.exclusive = false
}
window.bpmnInstances.modeling.updateProperties(window.bpmnInstances.bpmnElement, {
...taskConfigForm.value
})
}
watch(
() => props.id,
() => {
bpmnElement.value = window.bpmnInstances.bpmnElement
taskConfigForm.value.asyncBefore = bpmnElement.value?.businessObject?.asyncBefore
taskConfigForm.value.asyncAfter = bpmnElement.value?.businessObject?.asyncAfter
taskConfigForm.value.exclusive = bpmnElement.value?.businessObject?.exclusive
},
{ immediate: true }
)
watch(
() => props.type,
() => {
// witchTaskComponent.value = installedComponent.value[props.type]
if (props.type == installedComponent.value.UserTask) {
witchTaskComponent.value = UserTask
}
if (props.type == installedComponent.value.ScriptTask) {
witchTaskComponent.value = ScriptTask
}
if (props.type == installedComponent.value.ReceiveTask) {
witchTaskComponent.value = ReceiveTask
}
},
{ immediate: true }
)
</script>

View File

@ -0,0 +1,123 @@
<template>
<div style="margin-top: 16px">
<el-form-item label="消息实例">
<div
style="
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: nowrap;
"
>
<el-select v-model="bindMessageId" @change="updateTaskMessage">
<el-option
v-for="id in Object.keys(messageMap)"
:value="id"
:label="messageMap[id]"
:key="id"
/>
</el-select>
<XButton
size="mini"
type="primary"
preIcon="ep:plus"
style="margin-left: 8px"
@click="openMessageModel"
/>
</div>
</el-form-item>
<el-dialog
v-model="messageModelVisible"
:close-on-click-modal="false"
title="创建新消息"
width="400px"
append-to-body
destroy-on-close
>
<el-form :model="newMessageForm" size="mini" label-width="90px">
<el-form-item label="消息ID">
<el-input v-model="newMessageForm.id" clearable />
</el-form-item>
<el-form-item label="消息名称">
<el-input v-model="newMessageForm.name" clearable />
</el-form-item>
</el-form>
<template #footer>
<el-button size="mini" type="primary" @click="createNewMessage"> </el-button>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="ReceiveTask">
import { ref, watch, onBeforeUnmount, onMounted, nextTick } from 'vue'
import { ElMessage, ElFormItem, ElDialog, ElForm, ElSelect, ElOption } from 'element-plus'
const props = defineProps({
id: String,
type: String
})
const bindMessageId = ref('')
const newMessageForm = ref({})
const messageMap = ref({})
const messageModelVisible = ref(false)
const bpmnElement = ref()
const bpmnMessageRefsMap = ref()
const bpmnRootElements = ref()
const getBindMessage = () => {
bpmnElement.value = window.bpmnInstances.bpmnElement
bindMessageId.value = bpmnElement.value.businessObject?.messageRef?.id || '-1'
}
const openMessageModel = () => {
messageModelVisible.value = true
newMessageForm.value = {}
}
const createNewMessage = () => {
if (messageMap.value[newMessageForm.value.id]) {
ElMessage.error('该消息已存在请修改id后重新保存')
return
}
const newMessage = window.bpmnInstances.moddle.create('bpmn:Message', newMessageForm.value)
bpmnRootElements.value.push(newMessage)
messageMap.value[newMessageForm.value.id] = newMessageForm.value.name
bpmnMessageRefsMap.value[newMessageForm.value.id] = newMessage
messageModelVisible.value = false
}
const updateTaskMessage = (messageId) => {
if (messageId === '-1') {
window.bpmnInstances.modeling.updateProperties(bpmnElement.value, {
messageRef: null
})
} else {
window.bpmnInstances.modeling.updateProperties(bpmnElement.value, {
messageRef: bpmnMessageRefsMap.value[messageId]
})
}
}
onMounted(() => {
bpmnMessageRefsMap.value = Object.create(null)
bpmnRootElements.value = window.bpmnInstances.modeler.getDefinitions().rootElements
bpmnRootElements.value
.filter((el) => el.$type === 'bpmn:Message')
.forEach((m) => {
bpmnMessageRefsMap.value[m.id] = m
messageMap.value[m.id] = m.name
})
messageMap.value['-1'] = '无'
})
onBeforeUnmount(() => {
bpmnElement.value = null
})
watch(
() => props.id,
() => {
bpmnElement.value = window.bpmnInstances.bpmnElement
nextTick(() => {
getBindMessage()
})
},
{ immediate: true }
)
</script>

View File

@ -0,0 +1,98 @@
<template>
<div style="margin-top: 16px">
<el-form-item label="脚本格式">
<el-input
v-model="scriptTaskForm.scriptFormat"
clearable
@input="updateElementTask()"
@change="updateElementTask()"
/>
</el-form-item>
<el-form-item label="脚本类型">
<el-select v-model="scriptTaskForm.scriptType">
<el-option label="内联脚本" value="inline" />
<el-option label="外部资源" value="external" />
</el-select>
</el-form-item>
<el-form-item label="脚本" v-show="scriptTaskForm.scriptType === 'inline'">
<el-input
v-model="scriptTaskForm.script"
type="textarea"
resize="vertical"
:autosize="{ minRows: 2, maxRows: 4 }"
clearable
@input="updateElementTask()"
@change="updateElementTask()"
/>
</el-form-item>
<el-form-item label="资源地址" v-show="scriptTaskForm.scriptType === 'external'">
<el-input
v-model="scriptTaskForm.resource"
clearable
@input="updateElementTask()"
@change="updateElementTask()"
/>
</el-form-item>
<el-form-item label="结果变量">
<el-input
v-model="scriptTaskForm.resultVariable"
clearable
@input="updateElementTask()"
@change="updateElementTask()"
/>
</el-form-item>
</div>
</template>
<script setup lang="ts" name="ScriptTask">
import { ref, watch, nextTick, onBeforeUnmount } from 'vue'
import { ElInput, ElFormItem } from 'element-plus'
const props = defineProps({
id: String,
type: String
})
const defaultTaskForm = ref({
scriptFormat: '',
script: '',
resource: '',
resultVariable: ''
})
const scriptTaskForm = ref({})
const bpmnElement = ref()
const resetTaskForm = () => {
for (let key in defaultTaskForm.value) {
let value = bpmnElement.value?.businessObject[key] || defaultTaskForm.value[key]
scriptTaskForm.value[key] = value
}
scriptTaskForm.value.scriptType = scriptTaskForm.value.script ? 'inline' : 'external'
}
const updateElementTask = () => {
let taskAttr = Object.create(null)
taskAttr.scriptFormat = scriptTaskForm.value.scriptFormat || null
taskAttr.resultVariable = scriptTaskForm.value.resultVariable || null
if (scriptTaskForm.value.scriptType === 'inline') {
taskAttr.script = scriptTaskForm.value.script || null
taskAttr.resource = null
} else {
taskAttr.resource = scriptTaskForm.value.resource || null
taskAttr.script = null
}
window.bpmnInstances.modeling.updateProperties(bpmnElement.value, taskAttr)
}
onBeforeUnmount(() => {
bpmnElement.value = null
})
watch(
() => props.id,
() => {
bpmnElement.value = window.bpmnInstances.bpmnElement
nextTick(() => {
resetTaskForm()
})
},
{ immediate: true }
)
</script>

View File

@ -0,0 +1,97 @@
<template>
<div style="margin-top: 16px">
<!-- <el-form-item label="处理用户">-->
<!-- <el-select v-model="userTaskForm.assignee" @change="updateElementTask('assignee')">-->
<!-- <el-option v-for="ak in mockData" :key="'ass-' + ak" :label="`用户${ak}`" :value="`user${ak}`" />-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="候选用户">-->
<!-- <el-select v-model="userTaskForm.candidateUsers" multiple collapse-tags @change="updateElementTask('candidateUsers')">-->
<!-- <el-option v-for="uk in mockData" :key="'user-' + uk" :label="`用户${uk}`" :value="`user${uk}`" />-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="候选分组">-->
<!-- <el-select v-model="userTaskForm.candidateGroups" multiple collapse-tags @change="updateElementTask('candidateGroups')">-->
<!-- <el-option v-for="gk in mockData" :key="'ass-' + gk" :label="`分组${gk}`" :value="`group${gk}`" />-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<el-form-item label="到期时间">
<el-input v-model="userTaskForm.dueDate" clearable @change="updateElementTask('dueDate')" />
</el-form-item>
<el-form-item label="跟踪时间">
<el-input
v-model="userTaskForm.followUpDate"
clearable
@change="updateElementTask('followUpDate')"
/>
</el-form-item>
<el-form-item label="优先级">
<el-input v-model="userTaskForm.priority" clearable @change="updateElementTask('priority')" />
</el-form-item>
友情提示任务的分配规则使用
<router-link target="_blank" :to="{ path: '/bpm/manager/model' }"
><el-link type="danger">流程模型</el-link>
</router-link>
下的分配规则替代提供指定角色部门负责人部门成员岗位工作组自定义脚本等 7
种维护的任务分配维度更加灵活
</div>
</template>
<script setup lang="ts" name="UserTask">
import { ref, watch, nextTick, onBeforeUnmount } from 'vue'
import { ElLink, ElFormItem, ElInput } from 'element-plus'
const props = defineProps({
id: String,
type: String
})
const defaultTaskForm = ref({
assignee: '',
candidateUsers: [],
candidateGroups: [],
dueDate: '',
followUpDate: '',
priority: ''
})
const userTaskForm = ref({})
// const mockData=ref([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
const bpmnElement = ref()
const resetTaskForm = () => {
for (let key in defaultTaskForm.value) {
let value
if (key === 'candidateUsers' || key === 'candidateGroups') {
value = bpmnElement.value?.businessObject[key]
? bpmnElement.value.businessObject[key].split(',')
: []
} else {
value = bpmnElement.value?.businessObject[key] || defaultTaskForm.value[key]
}
userTaskForm.value[key] = value
}
}
const updateElementTask = (key) => {
const taskAttr = Object.create(null)
if (key === 'candidateUsers' || key === 'candidateGroups') {
taskAttr[key] =
userTaskForm.value[key] && userTaskForm.value[key].length
? userTaskForm.value[key].join()
: null
} else {
taskAttr[key] = userTaskForm.value[key] || null
}
window.bpmnInstances.modeling.updateProperties(bpmnElement.value, taskAttr)
}
watch(
() => props.id,
() => {
bpmnElement.value = window.bpmnInstances.bpmnElement
nextTick(() => {
resetTaskForm()
})
},
{ immediate: true }
)
onBeforeUnmount(() => {
bpmnElement.value = null
})
</script>