mirror of
https://gitee.com/hhyykk/ipms-sjy.git
synced 2025-07-15 03:25:06 +08:00
嵌入bpmn设计流程模块
This commit is contained in:
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -0,0 +1,7 @@
|
||||
import MyPropertiesPanel from "./PropertiesPanel.vue";
|
||||
|
||||
MyPropertiesPanel.install = function(Vue) {
|
||||
Vue.component(MyPropertiesPanel.name, MyPropertiesPanel);
|
||||
};
|
||||
|
||||
export default MyPropertiesPanel;
|
@ -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>
|
@ -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>
|
@ -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>
|
||||
`
|
||||
}
|
@ -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: "表达式"
|
||||
};
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
Reference in New Issue
Block a user