From 6b988bd582bfcd17fee48c476a5a6e5cc172b0d5 Mon Sep 17 00:00:00 2001 From: baoshiwei <baoshiwei@shlanbao.cn> Date: 星期三, 12 三月 2025 10:08:33 +0800 Subject: [PATCH] dev-2 --- src/bpmn/panel/property/ExecutionListener.vue | 308 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 308 insertions(+), 0 deletions(-) diff --git a/src/bpmn/panel/property/ExecutionListener.vue b/src/bpmn/panel/property/ExecutionListener.vue new file mode 100644 index 0000000..3c584cb --- /dev/null +++ b/src/bpmn/panel/property/ExecutionListener.vue @@ -0,0 +1,308 @@ +<template> + <div> + <vxe-toolbar> + <template #buttons> + <el-button type="primary" link size="small" @click="insertEvent">鏂板</el-button> + <el-button type="primary" link size="small" @click="removeSelectRowEvent">鍒犻櫎</el-button> + </template> + </vxe-toolbar> + <vxe-table + ref="tableRef" + size="mini" + height="100px" + border + show-overflow + keep-source + :data="tableData" + :menu-config="menuConfig" + @cell-dblclick="cellDBLClickEvent" + @menu-click="contextMenuClickEvent" + > + <vxe-column type="checkbox" width="40"></vxe-column> + <vxe-column type="seq" width="40"></vxe-column> + <vxe-column field="event" title="浜嬩欢" min-width="100px"> + <template #default="slotParams"> + <span>{{ eventSelect.find((e) => e.value === slotParams.row.event)?.label }}</span> + </template> + </vxe-column> + <vxe-column field="type" title="绫诲瀷" min-width="100px"> + <template #default="slotParams"> + <span>{{ typeSelect.find((e) => e.value === slotParams.row.type)?.label }}</span> + </template> + </vxe-column> + <vxe-column field="className" title="Java 绫诲悕" min-width="100px"> </vxe-column> + </vxe-table> + + <el-dialog + v-model="formDialog.visible.value" + :title="formDialog.title.value" + width="600px" + :close-on-click-modal="false" + :close-on-press-escape="false" + :show-close="false" + append-to-body + > + <el-form ref="formRef" :model="formData" :rules="tableRules" label-width="100px"> + <el-form-item label="浜嬩欢" prop="event"> + <el-select v-model="formData.event"> + <el-option v-for="item in eventSelect" :key="item.id" :value="item.value" :label="item.label"></el-option> + </el-select> + </el-form-item> + <el-form-item label="绫诲瀷" prop="type"> + <template #label> + <span> + 绫诲瀷 + <el-tooltip placement="top"> + <el-icon><QuestionFilled /></el-icon> + <template #content> + 绫伙細绀轰緥 com.company.MyCustomListener锛岃嚜瀹氫箟绫诲繀椤诲疄鐜� org.flowable.engine.delegate.TaskListener 鎺ュ彛<br /> + 琛ㄨ揪寮忥細绀轰緥 ${myObject.callMethod(task, task.eventName)}<br /> + 濮旀墭琛ㄨ揪寮忥細绀轰緥 ${myListenerSpringBean} 锛岃 springBean 闇�瑕佸疄鐜� org.flowable.engine.delegate.TaskListener 鎺ュ彛 + </template> + </el-tooltip> + </span> + </template> + <el-select v-model="formData.type"> + <el-option v-for="item in typeSelect" :key="item.id" :value="item.value" :label="item.label"></el-option> + </el-select> + </el-form-item> + <el-form-item + :label="typeSelect.filter((e) => e.value === formData.type)[0] ? typeSelect.filter((e) => e.value === formData.type)[0]?.label : '琛ㄨ揪寮�'" + prop="className" + > + <el-input v-model="formData.className" type="text"></el-input> + </el-form-item> + </el-form> + <el-tabs type="border-card"> + <el-tab-pane label="鍙傛暟"> + <ListenerParam ref="listenerParamRef" :table-data="formData.params" /> + </el-tab-pane> + </el-tabs> + <template #footer> + <div class="dialog-footer"> + <el-button @click="formDialog.closeDialog">鍙� 娑�</el-button> + <el-button type="primary" @click="submitEvent">纭� 瀹�</el-button> + </div> + </template> + </el-dialog> + </div> +</template> +<script setup lang="ts"> +import ListenerParam from './ListenerParam.vue'; +import { VxeTableEvents, VxeTableInstance, VxeTablePropTypes } from 'vxe-table'; +import type { ExecutionListenerVO } from 'bpmnDesign'; +import type { Moddle, Modeler, ModdleElement } from 'bpmn'; + +import usePanel from '../../hooks/usePanel'; +import useDialog from '@/hooks/useDialog'; +import useModelerStore from '@/store/modules/modeler'; + +const emit = defineEmits(['close']); +interface PropType { + element: ModdleElement; +} +const props = withDefaults(defineProps<PropType>(), {}); + +const { proxy } = getCurrentInstance() as ComponentInternalInstance; + +const selectRow = ref<ExecutionListenerVO | null>(); +const formDialog = useDialog({ + title: selectRow.value ? '缂栬緫&淇濆瓨' : '鏂板&淇濆瓨' +}); + +const { showConfig, elementType, updateProperties } = usePanel({ + element: toRaw(props.element) +}); +const { getModdle } = useModelerStore(); +const moddle = getModdle(); + +const listenerParamRef = ref<InstanceType<typeof ListenerParam>>(); +const tableRef = ref<VxeTableInstance<ExecutionListenerVO>>(); +const formRef = ref<ElFormInstance>(); + +const initData: ExecutionListenerVO = { + event: '', + type: '', + className: '', + params: [] +}; +const formData = ref<ExecutionListenerVO>({ ...initData }); +const tableData = ref<ExecutionListenerVO[]>([]); +const tableRules = ref<ElFormRules>({ + event: [{ required: true, message: '璇烽�夋嫨', trigger: 'blur' }], + type: [{ required: true, message: '璇烽�夋嫨', trigger: 'blur' }], + className: [{ required: true, message: '璇疯緭鍏�', trigger: 'blur' }] +}); + +const submitEvent = async () => { + const error = await listenerParamRef.value.validate(); + await formRef.value.validate((validate) => { + if (validate && !error) { + const $table = tableRef.value; + if ($table) { + formData.value.params = listenerParamRef.value.getTableData(); + if (selectRow.value) { + Object.assign(selectRow.value, formData.value); + } else { + $table.insertAt({ ...formData.value }, -1); + } + updateElement(); + formDialog.closeDialog(); + } + } + }); +}; + +const removeSelectRowEvent = async () => { + const $table = tableRef.value; + if ($table) { + const selectCount = $table.getCheckboxRecords().length; + if (selectCount === 0) { + proxy?.$modal.msgWarning('璇烽�夋嫨琛�'); + } else { + await $table.removeCheckboxRow(); + updateElement(); + } + } +}; +const insertEvent = async () => { + Object.assign(formData.value, initData); + selectRow.value = null; + formDialog.openDialog(); +}; + +const editEvent = (row: ExecutionListenerVO) => { + Object.assign(formData.value, row); + selectRow.value = row; + formDialog.openDialog(); +}; + +const removeEvent = async (row: ExecutionListenerVO) => { + await proxy?.$modal.confirm('鎮ㄧ‘瀹氳鍒犻櫎璇ユ暟鎹�?'); + const $table = tableRef.value; + if ($table) { + await $table.remove(row); + updateElement(); + } +}; +const updateElement = () => { + const $table = tableRef.value; + const data = $table.getTableData().fullData; + if (data.length) { + let extensionElements = props.element.businessObject.get('extensionElements'); + if (!extensionElements) { + extensionElements = moddle.create('bpmn:ExtensionElements'); + } + // 娓呴櫎鏃у�� + extensionElements.values = extensionElements.values?.filter((item) => item.$type !== 'flowable:ExecutionListener') ?? []; + data.forEach((item) => { + const executionListener = moddle.create('flowable:ExecutionListener'); + executionListener['event'] = item.event; + executionListener[item.type] = item.className; + if (item.params && item.params.length) { + item.params.forEach((field) => { + const fieldElement = moddle.create('flowable:Field'); + fieldElement['name'] = field.name; + fieldElement[field.type] = field.value; + executionListener.get('fields').push(fieldElement); + }); + } + extensionElements.get('values').push(executionListener); + }); + updateProperties({ extensionElements: extensionElements }); + } else { + const extensionElements = props.element.businessObject[`extensionElements`]; + if (extensionElements) { + extensionElements.values = extensionElements.values?.filter((item) => item.$type !== 'flowable:ExecutionListener') ?? []; + } + } +}; + +const cellDBLClickEvent: VxeTableEvents.CellDblclick<ExecutionListenerVO> = ({ row }) => { + editEvent(row); +}; + +const menuConfig = reactive<VxeTablePropTypes.MenuConfig<ExecutionListenerVO>>({ + body: { + options: [ + [ + { code: 'edit', name: '缂栬緫', prefixIcon: 'vxe-icon-edit', disabled: false }, + { code: 'remove', name: '鍒犻櫎', prefixIcon: 'vxe-icon-delete', disabled: false } + ] + ] + }, + visibleMethod({ options, column }) { + const isDisabled = !column; + options.forEach((list) => { + list.forEach((item) => { + item.disabled = isDisabled; + }); + }); + return true; + } +}); +const contextMenuClickEvent: VxeTableEvents.MenuClick<ExecutionListenerVO> = ({ menu, row, column }) => { + const $table = tableRef.value; + if ($table) { + switch (menu.code) { + case 'edit': + editEvent(row); + break; + case 'remove': + removeEvent(row); + break; + } + } +}; + +const initTableData = () => { + tableData.value = + props.element.businessObject.extensionElements?.values + .filter((item) => item.$type === 'flowable:ExecutionListener') + .map((item) => { + let type; + if ('class' in item) type = 'class'; + if ('expression' in item) type = 'expression'; + if ('delegateExpression' in item) type = 'delegateExpression'; + return { + event: item.event, + type: type, + className: item[type], + params: + item.fields?.map((field) => { + let fieldType; + if ('stringValue' in field) fieldType = 'stringValue'; + if ('expression' in field) fieldType = 'expression'; + return { + name: field.name, + type: fieldType, + value: field[fieldType] + }; + }) ?? [] + }; + }) ?? []; +}; + +onMounted(() => { + initTableData(); +}); + +const typeSelect = [ + { id: '742fdeb7-23b4-416b-ac66-cd4ec8b901b7', label: '绫�', value: 'class' }, + { id: '660c9c46-8fae-4bae-91a0-0335420019dc', label: '琛ㄨ揪寮�', value: 'expression' }, + { id: '4b8135ab-6bc3-4a0f-80be-22f58bc6c5fd', label: '濮旀墭琛ㄨ揪寮�', value: 'delegateExpression' } +]; +const eventSelect = [ + { id: 'e6e0a51a-2d5d-4dc4-b847-b5c14f43a6ab', label: '寮�濮�', value: 'start' }, + { id: '6da97c1e-15fc-4445-8943-75d09f49778e', label: '缁撴潫', value: 'end' }, + { id: '6a2cbcec-e026-4f11-bef7-fff0b5c871e2', label: '鍚敤', value: 'take' } +]; +</script> + +<style scoped lang="scss"> +.el-badge { + :deep(.el-badge__content) { + top: 10px; + } +} +</style> -- Gitblit v1.9.3