<script lang="ts" setup>
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
|
import { inject, nextTick, ref, watch } from 'vue';
|
|
import { confirm, useVbenModal } from '..\..\..\..\..\..\..\packages\effects\common-ui\src';
|
import { IconifyIcon } from '..\..\..\..\..\..\..\packages\icons\src';
|
import { cloneDeep } from '..\..\..\..\..\..\..\packages\utils\src';
|
|
import { Button, Divider, Form, FormItem, Input } from 'ant-design-vue';
|
|
import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
|
defineOptions({ name: 'ElementProperties' });
|
|
const props = defineProps({
|
id: {
|
type: String,
|
default: '',
|
},
|
type: {
|
type: String,
|
default: '',
|
},
|
});
|
|
const prefix = inject('prefix');
|
|
const elementPropertyList = ref<Array<{ name: string; value: string }>>([]);
|
const propertyForm = ref<{ name?: string; value?: string }>({});
|
const editingPropertyIndex = ref(-1);
|
const otherExtensionList = ref<any[]>([]);
|
const bpmnElementProperties = ref<any[]>([]);
|
const bpmnElementPropertyList = ref<any[]>([]);
|
const attributeFormRef = ref<any>();
|
const bpmnInstances = () => (window as any)?.bpmnInstances;
|
|
const resetAttributesList = () => {
|
const instances = bpmnInstances();
|
if (!instances || !instances.bpmnElement) return;
|
|
// 直接使用原始BPMN元素,避免Vue响应式代理问题
|
const bpmnElement = instances.bpmnElement;
|
const businessObject = bpmnElement.businessObject;
|
|
otherExtensionList.value = []; // 其他扩展配置
|
bpmnElementProperties.value =
|
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(
|
(current: any) => current.values,
|
);
|
elementPropertyList.value = cloneDeep(bpmnElementPropertyList.value ?? []);
|
};
|
|
const removeAttributes = (
|
_attr: { name: string; value: string },
|
index: number,
|
) => {
|
confirm({
|
title: '提示',
|
content: '确认移除该属性吗?',
|
}).then(() => {
|
elementPropertyList.value.splice(index, 1);
|
bpmnElementPropertyList.value.splice(index, 1);
|
const propertiesObject = bpmnInstances().moddle.create(
|
`${prefix}:Properties`,
|
{
|
values: bpmnElementPropertyList.value,
|
},
|
);
|
updateElementExtensions(propertiesObject);
|
resetAttributesList();
|
});
|
};
|
|
const saveAttribute = async () => {
|
try {
|
await attributeFormRef.value?.validate();
|
} catch {
|
// 校验未通过,直接返回
|
return;
|
}
|
|
const { name, value } = propertyForm.value;
|
const instances = bpmnInstances();
|
if (!instances || !instances.bpmnElement) return;
|
|
const bpmnElement = instances.bpmnElement;
|
|
if (editingPropertyIndex.value === -1) {
|
// 新建属性字段
|
const newPropertyObject = instances.moddle.create(`${prefix}:Property`, {
|
name,
|
value,
|
});
|
// 新建一个属性字段的保存列表
|
const propertiesObject = instances.moddle.create(`${prefix}:Properties`, {
|
values: [...bpmnElementPropertyList.value, newPropertyObject],
|
});
|
updateElementExtensions(propertiesObject);
|
} else {
|
instances.modeling.updateModdleProperties(
|
bpmnElement,
|
bpmnElementPropertyList.value[editingPropertyIndex.value],
|
{
|
name,
|
value,
|
},
|
);
|
}
|
fieldModalApi.close();
|
resetAttributesList();
|
};
|
|
const updateElementExtensions = (properties: any) => {
|
const instances = bpmnInstances();
|
if (!instances || !instances.bpmnElement) return;
|
|
const bpmnElement = instances.bpmnElement;
|
const extensions = instances.moddle.create('bpmn:ExtensionElements', {
|
values: [...otherExtensionList.value, properties],
|
});
|
instances.modeling.updateProperties(bpmnElement, {
|
extensionElements: extensions,
|
});
|
};
|
|
const [Grid, gridApi] = useVbenVxeGrid({
|
gridOptions: {
|
columns: [
|
{ type: 'seq', width: 50, title: '序号' },
|
{ field: 'name', title: '属性名', minWidth: 120 },
|
{ field: 'value', title: '属性值', minWidth: 120 },
|
{
|
title: '操作',
|
width: 120,
|
slots: { default: 'action' },
|
fixed: 'right',
|
},
|
],
|
border: true,
|
showOverflow: true,
|
height: 'auto',
|
toolbarConfig: {
|
enabled: false,
|
},
|
pagerConfig: {
|
enabled: false,
|
},
|
} as VxeTableGridOptions<{ name: string; value: string }>,
|
});
|
|
const [FieldModal, fieldModalApi] = useVbenModal({
|
title: '属性配置',
|
onConfirm: saveAttribute,
|
});
|
|
const openAttributesForm = (
|
attr: null | { name: string; value: string },
|
index: number,
|
) => {
|
editingPropertyIndex.value = index;
|
propertyForm.value = index === -1 ? {} : cloneDeep(attr || {});
|
fieldModalApi.open();
|
nextTick(() => {
|
if (attributeFormRef.value) attributeFormRef.value.clearValidate();
|
});
|
};
|
|
watch(
|
elementPropertyList,
|
(val) => {
|
gridApi.setGridOptions({ data: val });
|
},
|
{ deep: true },
|
);
|
|
watch(
|
() => props.id,
|
(val) => {
|
if (val && val.length > 0) {
|
resetAttributesList();
|
}
|
},
|
{ immediate: true },
|
);
|
</script>
|
|
<template>
|
<div class="-mx-2">
|
<Grid :data="elementPropertyList">
|
<template #action="{ row, rowIndex }">
|
<Button
|
size="small"
|
type="link"
|
@click="openAttributesForm(row, rowIndex)"
|
>
|
编辑
|
</Button>
|
<Divider type="vertical" />
|
<Button
|
size="small"
|
type="link"
|
danger
|
@click="removeAttributes(row, rowIndex)"
|
>
|
移除
|
</Button>
|
</template>
|
</Grid>
|
<div class="mt-1 flex w-full items-center justify-center gap-2 px-2">
|
<Button
|
class="flex flex-1 items-center justify-center"
|
type="primary"
|
size="small"
|
@click="openAttributesForm(null, -1)"
|
>
|
<template #icon>
|
<IconifyIcon icon="ep:plus" />
|
</template>
|
添加属性
|
</Button>
|
</div>
|
|
<FieldModal class="w-3/5">
|
<Form
|
:model="propertyForm"
|
ref="attributeFormRef"
|
:label-col="{ span: 5 }"
|
:wrapper-col="{ span: 17 }"
|
>
|
<FormItem
|
label="属性名:"
|
name="name"
|
:rules="[{ required: true, message: '请输入属性名' }]"
|
>
|
<Input v-model:value="propertyForm.name" allow-clear />
|
</FormItem>
|
<FormItem
|
label="属性值:"
|
name="value"
|
:rules="[{ required: true, message: '请输入属性值' }]"
|
>
|
<Input v-model:value="propertyForm.value" allow-clear />
|
</FormItem>
|
</Form>
|
</FieldModal>
|
</div>
|
</template>
|