fix: 【bpm】bpmn设计器: 组件部分属性第一次失去焦点丢失数据问题 #204 【同步自 vue3 + element-plus】

This commit is contained in:
YunaiV
2025-12-07 12:26:03 +08:00
parent cc375100cb
commit 7366b948a3
4 changed files with 91 additions and 51 deletions

View File

@@ -52,7 +52,6 @@ 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();
@@ -60,13 +59,19 @@ const listenerFieldFormRef = ref();
const bpmnInstances = () => (window as any)?.bpmnInstances;
const resetListenersList = () => {
bpmnElement.value = bpmnInstances().bpmnElement;
const instances = bpmnInstances();
if (!instances || !instances.bpmnElement) return;
// 直接使用原始BPMN元素避免Vue响应式代理问题
const bpmnElement = instances.bpmnElement;
const businessObject = bpmnElement.businessObject;
otherExtensionList.value =
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
businessObject?.extensionElements?.values?.filter(
(ex: any) => ex.$type !== `${prefix}:ExecutionListener`,
) ?? []; // 保留非监听器类型的扩展属性避免移除监听器时清空其他配置如审批人等。相关案例https://gitee.com/yudaocode/yudao-ui-admin-vue3/issues/ICMSYC
bpmnElementListeners.value =
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
businessObject?.extensionElements?.values?.filter(
(ex: any) => ex.$type === `${prefix}:ExecutionListener`,
) ?? [];
elementListenersList.value = bpmnElementListeners.value.map((listener: any) =>
@@ -162,9 +167,12 @@ const removeListener = (index: number) => {
okText: '确 认',
cancelText: '取 消',
onOk() {
const instances = bpmnInstances();
if (!instances || !instances.bpmnElement) return;
bpmnElementListeners.value.splice(index, 1);
elementListenersList.value.splice(index, 1);
updateElementExtensions(bpmnElement.value, [
updateElementExtensions(instances.bpmnElement, [
...otherExtensionList.value,
...bpmnElementListeners.value,
]);
@@ -179,11 +187,17 @@ const saveListenerConfig = async () => {
// debugger
const validateStatus = await listenerFormRef.value.validate();
if (!validateStatus) return; // 验证不通过直接返回
const instances = bpmnInstances();
if (!instances || !instances.bpmnElement) return;
const bpmnElement = instances.bpmnElement;
const listenerObject = createListenerObject(
listenerForm.value,
false,
prefix,
);
if (editingListenerIndex.value === -1) {
bpmnElementListeners.value.push(listenerObject);
elementListenersList.value.push(listenerForm.value);
@@ -201,10 +215,10 @@ const saveListenerConfig = async () => {
}
// 保存其他配置
otherExtensionList.value =
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
bpmnElement.businessObject?.extensionElements?.values?.filter(
(ex: any) => ex.$type !== `${prefix}:ExecutionListener`,
) ?? [];
updateElementExtensions(bpmnElement.value, [
updateElementExtensions(bpmnElement, [
...otherExtensionList.value,
...bpmnElementListeners.value,
]);
@@ -219,6 +233,10 @@ const openProcessListenerDialog = async () => {
processListenerDialogRef.value.open('execution');
};
const selectProcessListener = (listener: any) => {
const instances = bpmnInstances();
if (!instances || !instances.bpmnElement) return;
const bpmnElement = instances.bpmnElement;
const listenerForm = initListenerForm2(listener);
const listenerObject = createListenerObject(listenerForm, false, prefix);
bpmnElementListeners.value.push(listenerObject);
@@ -226,10 +244,10 @@ const selectProcessListener = (listener: any) => {
// 保存其他配置
otherExtensionList.value =
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
bpmnElement.businessObject?.extensionElements?.values?.filter(
(ex: any) => ex.$type !== `${prefix}:ExecutionListener`,
) ?? [];
updateElementExtensions(bpmnElement.value, [
updateElementExtensions(bpmnElement, [
...otherExtensionList.value,
...bpmnElementListeners.value,
]);

View File

@@ -48,7 +48,6 @@ const fieldsListOfListener = ref<any[]>([]);
const editingListenerIndex = ref(-1);
const editingListenerFieldIndex = ref<any>(-1);
const listenerFieldForm = ref<any>({});
const bpmnElement = ref<any>();
const bpmnElementListeners = ref<any[]>([]);
const otherExtensionList = ref<any[]>([]);
const listenerFormRef = ref<any>({});
@@ -57,13 +56,19 @@ const listenerFieldFormRef = ref<any>({});
const bpmnInstances = () => (window as any)?.bpmnInstances;
const resetListenersList = () => {
bpmnElement.value = bpmnInstances()?.bpmnElement;
const instances = bpmnInstances();
if (!instances || !instances.bpmnElement) return;
// 直接使用原始BPMN元素避免Vue响应式代理问题
const bpmnElement = instances.bpmnElement;
const businessObject = bpmnElement.businessObject;
otherExtensionList.value =
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
businessObject?.extensionElements?.values?.filter(
(ex: any) => ex.$type !== `${prefix}:TaskListener`,
) ?? [];
bpmnElementListeners.value =
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
businessObject?.extensionElements?.values?.filter(
(ex: any) => ex.$type === `${prefix}:TaskListener`,
) ?? [];
elementListenersList.value = bpmnElementListeners.value.map((listener) =>
@@ -99,9 +104,12 @@ const removeListener = (_: any, index: number) => {
title: '提示',
content: '确认移除该监听器吗?',
}).then(() => {
const instances = bpmnInstances();
if (!instances || !instances.bpmnElement) return;
bpmnElementListeners.value.splice(index, 1);
elementListenersList.value.splice(index, 1);
updateElementExtensions(bpmnElement.value, [
updateElementExtensions(instances.bpmnElement, [
...otherExtensionList.value,
...bpmnElementListeners.value,
]);
@@ -114,7 +122,13 @@ async function saveListenerConfig() {
} catch {
return;
}
const instances = bpmnInstances();
if (!instances || !instances.bpmnElement) return;
const bpmnElement = instances.bpmnElement;
const listenerObject = createListenerObject(listenerForm.value, true, prefix);
if (editingListenerIndex.value === -1) {
bpmnElementListeners.value.push(listenerObject);
elementListenersList.value.push(listenerForm.value);
@@ -131,10 +145,10 @@ async function saveListenerConfig() {
);
}
otherExtensionList.value =
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
bpmnElement.businessObject?.extensionElements?.values?.filter(
(ex: any) => ex.$type !== `${prefix}:TaskListener`,
) ?? [];
updateElementExtensions(bpmnElement.value, [
updateElementExtensions(bpmnElement, [
...otherExtensionList.value,
...bpmnElementListeners.value,
]);
@@ -229,17 +243,21 @@ const openProcessListenerDialog = async () => {
processListenerDialogRef.value.open('task');
};
const selectProcessListener = (listener: any) => {
const instances = bpmnInstances();
if (!instances || !instances.bpmnElement) return;
const bpmnElement = instances.bpmnElement;
const listenerForm = initListenerForm2(listener);
const listenerObject = createListenerObject(listenerForm, true, prefix);
bpmnElementListeners.value.push(listenerObject);
elementListenersList.value.push(listenerForm);
otherExtensionList.value =
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
bpmnElement.businessObject?.extensionElements?.values?.filter(
(ex: any) => ex.$type !== `${prefix}:TaskListener`,
) ?? [];
updateElementExtensions(
bpmnElement.value,
bpmnElement,
otherExtensionList.value?.concat(bpmnElementListeners.value),
);
};

View File

@@ -1,5 +1,5 @@
<script lang="ts" setup>
import { inject, nextTick, ref, toRaw, watch } from 'vue';
import { inject, nextTick, ref, watch } from 'vue';
import { IconifyIcon } from '@vben/icons';
import { cloneDeep } from '@vben/utils';
@@ -35,7 +35,6 @@ const elementPropertyList = ref<Array<{ name: string; value: string }>>([]);
const propertyForm = ref<{ name?: string; value?: string }>({});
const editingPropertyIndex = ref(-1);
const propertyFormModelVisible = ref(false);
const bpmnElement = ref<any>();
const otherExtensionList = ref<any[]>([]);
const bpmnElementProperties = ref<any[]>([]);
const bpmnElementPropertyList = ref<any[]>([]);
@@ -43,18 +42,21 @@ const attributeFormRef = ref<any>();
const bpmnInstances = () => (window as any)?.bpmnInstances;
const resetAttributesList = () => {
bpmnElement.value = bpmnInstances().bpmnElement;
const instances = bpmnInstances();
if (!instances || !instances.bpmnElement) return;
// 直接使用原始BPMN元素避免Vue响应式代理问题
const bpmnElement = instances.bpmnElement;
const businessObject = bpmnElement.businessObject;
otherExtensionList.value = []; // 其他扩展配置
bpmnElementProperties.value =
// bpmnElement.value.businessObject?.extensionElements?.filter((ex) => {
bpmnElement.value.businessObject?.extensionElements?.values?.filter(
(ex: any) => {
if (ex.$type !== `${prefix}:Properties`) {
otherExtensionList.value.push(ex);
}
return ex.$type === `${prefix}:Properties`;
},
) ?? [];
businessObject?.extensionElements?.values?.filter((ex: any) => {
if (ex.$type !== `${prefix}:Properties`) {
otherExtensionList.value.push(ex);
}
return ex.$type === `${prefix}:Properties`;
}) ?? [];
// 保存所有的 扩展属性字段
bpmnElementPropertyList.value = bpmnElementProperties.value.flatMap(
@@ -108,27 +110,26 @@ const removeAttributes = (
const saveAttribute = () => {
// console.log(propertyForm.value, 'propertyForm.value');
const { name, value } = propertyForm.value;
const instances = bpmnInstances();
if (!instances || !instances.bpmnElement) return;
const bpmnElement = instances.bpmnElement;
if (editingPropertyIndex.value === -1) {
// 新建属性字段
const newPropertyObject = bpmnInstances().moddle.create(
`${prefix}:Property`,
{
name,
value,
},
);
const newPropertyObject = instances.moddle.create(`${prefix}:Property`, {
name,
value,
});
// 新建一个属性字段的保存列表
const propertiesObject = bpmnInstances().moddle.create(
`${prefix}:Properties`,
{
values: [...bpmnElementPropertyList.value, newPropertyObject],
},
);
const propertiesObject = instances.moddle.create(`${prefix}:Properties`, {
values: [...bpmnElementPropertyList.value, newPropertyObject],
});
updateElementExtensions(propertiesObject);
} else {
bpmnInstances().modeling.updateModdleProperties(
toRaw(bpmnElement.value),
toRaw(bpmnElementPropertyList.value)[toRaw(editingPropertyIndex.value)],
instances.modeling.updateModdleProperties(
bpmnElement,
bpmnElementPropertyList.value[editingPropertyIndex.value],
{
name,
value,
@@ -140,10 +141,14 @@ const saveAttribute = () => {
};
const updateElementExtensions = (properties: any) => {
const extensions = bpmnInstances().moddle.create('bpmn:ExtensionElements', {
const instances = bpmnInstances();
if (!instances || !instances.bpmnElement) return;
const bpmnElement = instances.bpmnElement;
const extensions = instances.moddle.create('bpmn:ExtensionElements', {
values: [...otherExtensionList.value, properties],
});
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
instances.modeling.updateProperties(bpmnElement, {
extensionElements: extensions,
});
};

View File

@@ -1,5 +1,3 @@
import { toRaw } from 'vue';
const bpmnInstances = () => (window as any)?.bpmnInstances;
// 创建监听器实例
export function createListenerObject(options, isTask, prefix) {
@@ -76,7 +74,8 @@ export function updateElementExtensions(element, extensionList) {
const extensions = bpmnInstances().moddle.create('bpmn:ExtensionElements', {
values: extensionList,
});
bpmnInstances().modeling.updateProperties(toRaw(element), {
// 直接使用原始元素对象不需要toRaw包装
bpmnInstances().modeling.updateProperties(element, {
extensionElements: extensions,
});
}