workflow-bpmn-modeler-andtv-vue3 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/LICENSE +21 -0
- package/dist/demo.html +9 -0
- package/dist/fonts/bpmn.5d33bee4.eot +0 -0
- package/dist/fonts/bpmn.67058807.woff2 +0 -0
- package/dist/fonts/bpmn.b5c9250d.ttf +0 -0
- package/dist/fonts/bpmn.e9e7d076.woff +0 -0
- package/dist/img/bpmn.74eea12b.svg +224 -0
- package/dist/workflow-bpmn-modeler-andtv-vue3.common.js +5617 -0
- package/dist/workflow-bpmn-modeler-andtv-vue3.umd.js +5628 -0
- package/dist/workflow-bpmn-modeler-andtv-vue3.umd.min.js +5628 -0
- package/package/BpmData.js +68 -0
- package/package/PropertyPanel.vue +342 -0
- package/package/common/customTranslate.js +20 -0
- package/package/common/mixinExecutionListener.js +24 -0
- package/package/common/mixinPanel.js +70 -0
- package/package/common/mixinXcrud.js +22 -0
- package/package/common/parseElement.js +53 -0
- package/package/components/custom/customContextPad.vue +24 -0
- package/package/components/nodePanel/gateway.vue +165 -0
- package/package/components/nodePanel/process.vue +201 -0
- package/package/components/nodePanel/property/executionListener.vue +240 -0
- package/package/components/nodePanel/property/listenerParam.vue +137 -0
- package/package/components/nodePanel/property/multiInstance.vue +177 -0
- package/package/components/nodePanel/property/signal.vue +178 -0
- package/package/components/nodePanel/property/taskListener.vue +242 -0
- package/package/components/nodePanel/sequenceFlow.vue +180 -0
- package/package/components/nodePanel/startEnd.vue +174 -0
- package/package/components/nodePanel/task.vue +452 -0
- package/package/flowable/flowable.json +1218 -0
- package/package/flowable/init.js +24 -0
- package/package/flowable/showConfig.js +51 -0
- package/package/index.js +8 -0
- package/package/index.ts +9 -0
- package/package/index.vue +730 -0
- package/package/lang/zh.js +227 -0
- package/package/types/components.d.ts +35 -0
- package/package.json +73 -0
@@ -0,0 +1,242 @@
|
|
1
|
+
<template>
|
2
|
+
<div>
|
3
|
+
<a-modal
|
4
|
+
v-model:open="dialogVisible"
|
5
|
+
title="任务监听器"
|
6
|
+
width="900px"
|
7
|
+
:mask-closable="false"
|
8
|
+
:keyboard="false"
|
9
|
+
:closable="false"
|
10
|
+
@cancel="$emit('close')"
|
11
|
+
>
|
12
|
+
<a-form ref="formRef" :model="formData" layout="vertical">
|
13
|
+
<a-tabs>
|
14
|
+
<a-tab-pane key="taskListener" tab="任务监听器">
|
15
|
+
<div style="margin-bottom: 16px;">
|
16
|
+
<a-button type="primary" size="small" @click="addTaskListener">
|
17
|
+
<template #icon><PlusOutlined /></template>
|
18
|
+
添加任务监听器
|
19
|
+
</a-button>
|
20
|
+
</div>
|
21
|
+
|
22
|
+
<a-table
|
23
|
+
:columns="columns"
|
24
|
+
:data-source="formData.taskListener"
|
25
|
+
:pagination="false"
|
26
|
+
size="small"
|
27
|
+
>
|
28
|
+
<template #bodyCell="{ column, record, index }">
|
29
|
+
<template v-if="column.key === 'event'">
|
30
|
+
<a-select v-model:value="record.event" size="small" style="width: 100%">
|
31
|
+
<a-select-option value="create">create</a-select-option>
|
32
|
+
<a-select-option value="assignment">assignment</a-select-option>
|
33
|
+
<a-select-option value="complete">complete</a-select-option>
|
34
|
+
<a-select-option value="delete">delete</a-select-option>
|
35
|
+
</a-select>
|
36
|
+
</template>
|
37
|
+
<template v-if="column.key === 'type'">
|
38
|
+
<a-select v-model:value="record.type" size="small" style="width: 100%">
|
39
|
+
<a-select-option value="class">class</a-select-option>
|
40
|
+
<a-select-option value="expression">expression</a-select-option>
|
41
|
+
<a-select-option value="delegateExpression">delegateExpression</a-select-option>
|
42
|
+
</a-select>
|
43
|
+
</template>
|
44
|
+
<template v-if="column.key === 'className'">
|
45
|
+
<a-input v-model:value="record.className" size="small" placeholder="请输入类名" />
|
46
|
+
</template>
|
47
|
+
<template v-if="column.key === 'params'">
|
48
|
+
<a-badge :count="record.params ? record.params.length : 0">
|
49
|
+
<a-button size="small" @click="configParam(index)">配置</a-button>
|
50
|
+
</a-badge>
|
51
|
+
</template>
|
52
|
+
<template v-if="column.key === 'action'">
|
53
|
+
<a-button type="link" danger size="small" @click="removeTaskListener(index)">删除</a-button>
|
54
|
+
</template>
|
55
|
+
</template>
|
56
|
+
</a-table>
|
57
|
+
</a-tab-pane>
|
58
|
+
</a-tabs>
|
59
|
+
</a-form>
|
60
|
+
|
61
|
+
<template #footer>
|
62
|
+
<a-button type="primary" @click="closeDialog">确 定</a-button>
|
63
|
+
</template>
|
64
|
+
</a-modal>
|
65
|
+
|
66
|
+
<listenerParam v-if="showParamDialog && nowIndex !== null" :value="formData.taskListener[nowIndex]?.params" @close="finishConfigParam" />
|
67
|
+
</div>
|
68
|
+
</template>
|
69
|
+
|
70
|
+
<script setup lang="ts">
|
71
|
+
import { ref, onMounted, nextTick } from 'vue'
|
72
|
+
import { FormInstance } from 'ant-design-vue'
|
73
|
+
import { PlusOutlined } from '@ant-design/icons-vue'
|
74
|
+
import listenerParam from './listenerParam.vue'
|
75
|
+
import Modeler from 'bpmn-js/lib/Modeler'
|
76
|
+
|
77
|
+
defineOptions({
|
78
|
+
name: 'TaskListenerDialog'
|
79
|
+
})
|
80
|
+
|
81
|
+
interface Props {
|
82
|
+
element: any
|
83
|
+
modeler: Modeler
|
84
|
+
}
|
85
|
+
|
86
|
+
const props = defineProps<Props>()
|
87
|
+
const emit = defineEmits<{
|
88
|
+
close: []
|
89
|
+
}>()
|
90
|
+
|
91
|
+
const formRef = ref<FormInstance>()
|
92
|
+
const dialogVisible = ref(true)
|
93
|
+
const showParamDialog = ref(false)
|
94
|
+
const nowIndex = ref<number | null>(null)
|
95
|
+
const formData = ref({
|
96
|
+
taskListener: [] as any[]
|
97
|
+
})
|
98
|
+
|
99
|
+
const columns = [
|
100
|
+
{
|
101
|
+
title: '事件',
|
102
|
+
dataIndex: 'event',
|
103
|
+
key: 'event',
|
104
|
+
width: 120
|
105
|
+
},
|
106
|
+
{
|
107
|
+
title: '类型',
|
108
|
+
dataIndex: 'type',
|
109
|
+
key: 'type',
|
110
|
+
width: 150
|
111
|
+
},
|
112
|
+
{
|
113
|
+
title: 'Java类名',
|
114
|
+
dataIndex: 'className',
|
115
|
+
key: 'className'
|
116
|
+
},
|
117
|
+
{
|
118
|
+
title: '参数',
|
119
|
+
key: 'params',
|
120
|
+
width: 100
|
121
|
+
},
|
122
|
+
{
|
123
|
+
title: '操作',
|
124
|
+
key: 'action',
|
125
|
+
width: 80
|
126
|
+
}
|
127
|
+
]
|
128
|
+
|
129
|
+
const updateProperties = (properties: Record<string, any>) => {
|
130
|
+
nextTick(() => {
|
131
|
+
try {
|
132
|
+
const modeling = props.modeler.get('modeling')
|
133
|
+
modeling.updateProperties(props.element, properties)
|
134
|
+
} catch (error) {
|
135
|
+
console.warn('Update properties error:', error)
|
136
|
+
}
|
137
|
+
})
|
138
|
+
}
|
139
|
+
|
140
|
+
const addTaskListener = () => {
|
141
|
+
formData.value.taskListener.push({
|
142
|
+
event: 'create',
|
143
|
+
type: 'class',
|
144
|
+
className: '',
|
145
|
+
params: []
|
146
|
+
})
|
147
|
+
}
|
148
|
+
|
149
|
+
const removeTaskListener = (index: number) => {
|
150
|
+
formData.value.taskListener.splice(index, 1)
|
151
|
+
}
|
152
|
+
|
153
|
+
const configParam = (index: number) => {
|
154
|
+
nowIndex.value = index
|
155
|
+
const nowObj = formData.value.taskListener[index]
|
156
|
+
if (!nowObj.params) {
|
157
|
+
nowObj.params = []
|
158
|
+
}
|
159
|
+
showParamDialog.value = true
|
160
|
+
}
|
161
|
+
|
162
|
+
const finishConfigParam = (param: any) => {
|
163
|
+
showParamDialog.value = false
|
164
|
+
if (nowIndex.value !== null) {
|
165
|
+
const cache = formData.value.taskListener[nowIndex.value]
|
166
|
+
cache.params = param
|
167
|
+
formData.value.taskListener[nowIndex.value] = { ...cache }
|
168
|
+
}
|
169
|
+
nowIndex.value = null
|
170
|
+
}
|
171
|
+
|
172
|
+
const updateElement = () => {
|
173
|
+
if (formData.value.taskListener?.length) {
|
174
|
+
let extensionElements = props.element.businessObject.get('extensionElements')
|
175
|
+
if (!extensionElements) {
|
176
|
+
extensionElements = props.modeler.get('moddle').create('bpmn:ExtensionElements')
|
177
|
+
}
|
178
|
+
// 清除旧值
|
179
|
+
extensionElements.values = extensionElements.values?.filter((item: any) => item.$type !== 'flowable:TaskListener') ?? []
|
180
|
+
formData.value.taskListener.forEach((item: any) => {
|
181
|
+
const taskListener = props.modeler.get('moddle').create('flowable:TaskListener')
|
182
|
+
taskListener['event'] = item.event
|
183
|
+
taskListener[item.type] = item.className
|
184
|
+
if (item.params && item.params.length) {
|
185
|
+
item.params.forEach((field: any) => {
|
186
|
+
const fieldElement = props.modeler.get('moddle').create('flowable:Field')
|
187
|
+
fieldElement['name'] = field.name
|
188
|
+
fieldElement[field.type] = field.value
|
189
|
+
taskListener.get('fields').push(fieldElement)
|
190
|
+
})
|
191
|
+
}
|
192
|
+
extensionElements.get('values').push(taskListener)
|
193
|
+
})
|
194
|
+
updateProperties({ extensionElements: extensionElements })
|
195
|
+
} else {
|
196
|
+
const extensionElements = props.element.businessObject[`extensionElements`]
|
197
|
+
if (extensionElements) {
|
198
|
+
extensionElements.values = extensionElements.values?.filter((item: any) => item.$type !== 'flowable:TaskListener') ?? []
|
199
|
+
}
|
200
|
+
}
|
201
|
+
}
|
202
|
+
|
203
|
+
const closeDialog = () => {
|
204
|
+
updateElement()
|
205
|
+
dialogVisible.value = false
|
206
|
+
emit('close')
|
207
|
+
}
|
208
|
+
|
209
|
+
onMounted(() => {
|
210
|
+
if (props.element?.businessObject?.extensionElements?.values) {
|
211
|
+
formData.value.taskListener = props.element.businessObject.extensionElements.values
|
212
|
+
.filter((item: any) => item.$type === 'flowable:TaskListener')
|
213
|
+
.map((item: any) => {
|
214
|
+
let type
|
215
|
+
if ('class' in item) type = 'class'
|
216
|
+
if ('expression' in item) type = 'expression'
|
217
|
+
if ('delegateExpression' in item) type = 'delegateExpression'
|
218
|
+
return {
|
219
|
+
event: item.event,
|
220
|
+
type: type,
|
221
|
+
className: type ? item[type] : '',
|
222
|
+
params: item.fields?.map((field: any) => {
|
223
|
+
let fieldType
|
224
|
+
if ('stringValue' in field) fieldType = 'stringValue'
|
225
|
+
if ('expression' in field) fieldType = 'expression'
|
226
|
+
return {
|
227
|
+
name: field.name,
|
228
|
+
type: fieldType,
|
229
|
+
value: fieldType ? field[fieldType] : ''
|
230
|
+
}
|
231
|
+
}) ?? []
|
232
|
+
}
|
233
|
+
})
|
234
|
+
}
|
235
|
+
})
|
236
|
+
</script>
|
237
|
+
|
238
|
+
<style scoped>
|
239
|
+
.flow-containers .ant-badge {
|
240
|
+
margin-right: 8px;
|
241
|
+
}
|
242
|
+
</style>
|
@@ -0,0 +1,180 @@
|
|
1
|
+
<template>
|
2
|
+
<div>
|
3
|
+
<a-form ref="formRef" :model="formData" layout="horizontal">
|
4
|
+
<a-form-item label="节点 id" name="id" :rules="[{ required: true, message: 'Id 不能为空' }]">
|
5
|
+
<a-input v-model:value="formData.id" />
|
6
|
+
</a-form-item>
|
7
|
+
|
8
|
+
<a-form-item label="节点名称" name="name">
|
9
|
+
<a-input v-model:value="formData.name" />
|
10
|
+
</a-form-item>
|
11
|
+
|
12
|
+
<a-form-item label="节点描述" name="documentation">
|
13
|
+
<a-textarea v-model:value="formData.documentation" />
|
14
|
+
</a-form-item>
|
15
|
+
|
16
|
+
<a-form-item label="执行监听器">
|
17
|
+
<a-badge :count="executionListenerLength">
|
18
|
+
<a-button size="small" @click="dialogName = 'executionListenerDialog'">编辑</a-button>
|
19
|
+
</a-badge>
|
20
|
+
</a-form-item>
|
21
|
+
|
22
|
+
<a-form-item label="跳转条件" name="conditionExpression">
|
23
|
+
<a-input v-model:value="formData.conditionExpression" />
|
24
|
+
</a-form-item>
|
25
|
+
|
26
|
+
<a-form-item label="跳过表达式" name="skipExpression">
|
27
|
+
<a-input v-model:value="formData.skipExpression" />
|
28
|
+
</a-form-item>
|
29
|
+
</a-form>
|
30
|
+
|
31
|
+
<executionListenerDialog
|
32
|
+
v-if="dialogName === 'executionListenerDialog'"
|
33
|
+
:element="element"
|
34
|
+
:modeler="modeler"
|
35
|
+
@close="finishExecutionListener"
|
36
|
+
/>
|
37
|
+
</div>
|
38
|
+
</template>
|
39
|
+
|
40
|
+
<script setup lang="ts">
|
41
|
+
import { ref, computed, watch, onMounted, nextTick } from 'vue'
|
42
|
+
import { FormInstance } from 'ant-design-vue'
|
43
|
+
import executionListenerDialog from './property/executionListener.vue'
|
44
|
+
import { commonParse, conditionExpressionParse } from '../../common/parseElement'
|
45
|
+
import showConfigData from '../../flowable/showConfig'
|
46
|
+
import Modeler from 'bpmn-js/lib/Modeler'
|
47
|
+
|
48
|
+
defineOptions({
|
49
|
+
name: 'SequenceFlowPanel'
|
50
|
+
})
|
51
|
+
|
52
|
+
interface Props {
|
53
|
+
modeler: Modeler
|
54
|
+
element: any
|
55
|
+
}
|
56
|
+
|
57
|
+
const props = defineProps<Props>()
|
58
|
+
|
59
|
+
const formRef = ref<FormInstance>()
|
60
|
+
const dialogName = ref('')
|
61
|
+
const executionListenerLength = ref(0)
|
62
|
+
const formData = ref<Record<string, any>>({})
|
63
|
+
|
64
|
+
const elementType = computed(() => {
|
65
|
+
const bizObj = props.element.businessObject
|
66
|
+
return bizObj.eventDefinitions
|
67
|
+
? bizObj.eventDefinitions[0].$type
|
68
|
+
: bizObj.$type
|
69
|
+
})
|
70
|
+
|
71
|
+
const showConfig = computed(() => (showConfigData as any)[elementType.value] || {})
|
72
|
+
|
73
|
+
const updateProperties = (properties: Record<string, any>) => {
|
74
|
+
nextTick(() => {
|
75
|
+
try {
|
76
|
+
const modeling = props.modeler.get('modeling')
|
77
|
+
modeling.updateProperties(props.element, properties)
|
78
|
+
} catch (error) {
|
79
|
+
console.warn('Update properties error:', error)
|
80
|
+
}
|
81
|
+
})
|
82
|
+
}
|
83
|
+
|
84
|
+
const computedExecutionListenerLength = () => {
|
85
|
+
if (props.element?.businessObject?.extensionElements?.values) {
|
86
|
+
executionListenerLength.value = props.element.businessObject.extensionElements.values
|
87
|
+
.filter((item: any) => item.$type === 'flowable:ExecutionListener').length
|
88
|
+
} else {
|
89
|
+
executionListenerLength.value = 0
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
const finishExecutionListener = () => {
|
94
|
+
if (dialogName.value === 'executionListenerDialog') {
|
95
|
+
computedExecutionListenerLength()
|
96
|
+
}
|
97
|
+
dialogName.value = ''
|
98
|
+
}
|
99
|
+
|
100
|
+
// Watch for form data changes
|
101
|
+
watch(() => formData.value.conditionExpression, (val) => {
|
102
|
+
if (val && props.modeler?.get('moddle')) {
|
103
|
+
const newCondition = props.modeler.get('moddle').create('bpmn:FormalExpression', { body: val })
|
104
|
+
updateProperties({ conditionExpression: newCondition })
|
105
|
+
} else {
|
106
|
+
updateProperties({ conditionExpression: null })
|
107
|
+
}
|
108
|
+
})
|
109
|
+
|
110
|
+
watch(() => formData.value.skipExpression, (val) => {
|
111
|
+
if (val === '') val = null
|
112
|
+
updateProperties({ 'flowable:skipExpression': val })
|
113
|
+
})
|
114
|
+
|
115
|
+
watch(() => formData.value.id, (val) => {
|
116
|
+
updateProperties({ id: val })
|
117
|
+
})
|
118
|
+
|
119
|
+
watch(() => formData.value.name, (val) => {
|
120
|
+
updateProperties({ name: val })
|
121
|
+
})
|
122
|
+
|
123
|
+
watch(() => formData.value.documentation, (val) => {
|
124
|
+
if (!val) {
|
125
|
+
updateProperties({ documentation: [] })
|
126
|
+
return
|
127
|
+
}
|
128
|
+
if (props.modeler?.get('moddle')) {
|
129
|
+
const documentationElement = props.modeler.get('moddle').create('bpmn:Documentation', { text: val })
|
130
|
+
updateProperties({ documentation: [documentationElement] })
|
131
|
+
}
|
132
|
+
})
|
133
|
+
|
134
|
+
onMounted(() => {
|
135
|
+
if (props.element) {
|
136
|
+
let cache = commonParse(props.element)
|
137
|
+
cache = conditionExpressionParse(cache)
|
138
|
+
formData.value = cache
|
139
|
+
computedExecutionListenerLength()
|
140
|
+
}
|
141
|
+
})
|
142
|
+
</script>
|
143
|
+
|
144
|
+
<style scoped>
|
145
|
+
.flow-containers {
|
146
|
+
padding: 0;
|
147
|
+
background: transparent;
|
148
|
+
min-height: 100%;
|
149
|
+
}
|
150
|
+
|
151
|
+
.flow-containers :deep(.ant-form-item) {
|
152
|
+
margin-bottom: 16px;
|
153
|
+
}
|
154
|
+
|
155
|
+
.flow-containers :deep(.ant-form-item-label) {
|
156
|
+
font-weight: 500;
|
157
|
+
color: #262626;
|
158
|
+
}
|
159
|
+
|
160
|
+
.flow-containers :deep(.ant-input),
|
161
|
+
.flow-containers :deep(.ant-select),
|
162
|
+
.flow-containers :deep(.ant-textarea) {
|
163
|
+
border-radius: 6px;
|
164
|
+
transition: all 0.3s;
|
165
|
+
}
|
166
|
+
|
167
|
+
.flow-containers :deep(.ant-button) {
|
168
|
+
border-radius: 6px;
|
169
|
+
font-weight: 500;
|
170
|
+
}
|
171
|
+
|
172
|
+
.flow-containers :deep(.ant-badge) {
|
173
|
+
margin-right: 8px;
|
174
|
+
}
|
175
|
+
|
176
|
+
.flow-containers :deep(.ant-badge .ant-badge-count) {
|
177
|
+
background: linear-gradient(135deg, #ff4d4f 0%, #ff7875 100%);
|
178
|
+
box-shadow: 0 2px 4px rgba(255, 77, 79, 0.3);
|
179
|
+
}
|
180
|
+
</style>
|
@@ -0,0 +1,174 @@
|
|
1
|
+
<template>
|
2
|
+
<div>
|
3
|
+
<a-form ref="formRef" :model="formData" layout="horizontal">
|
4
|
+
<a-form-item label="节点 id" name="id" :rules="[{ required: true, message: 'Id 不能为空' }]">
|
5
|
+
<a-input v-model:value="formData.id" />
|
6
|
+
</a-form-item>
|
7
|
+
|
8
|
+
<a-form-item label="节点名称" name="name">
|
9
|
+
<a-input v-model:value="formData.name" />
|
10
|
+
</a-form-item>
|
11
|
+
|
12
|
+
<a-form-item label="节点描述" name="documentation">
|
13
|
+
<a-textarea v-model:value="formData.documentation" />
|
14
|
+
</a-form-item>
|
15
|
+
|
16
|
+
<a-form-item label="执行监听器">
|
17
|
+
<a-badge :count="executionListenerLength">
|
18
|
+
<a-button size="small" @click="dialogName = 'executionListenerDialog'">编辑</a-button>
|
19
|
+
</a-badge>
|
20
|
+
</a-form-item>
|
21
|
+
|
22
|
+
<a-form-item v-if="showConfig.initiator" label="发起人" name="initiator">
|
23
|
+
<a-input v-model:value="formData.initiator" />
|
24
|
+
</a-form-item>
|
25
|
+
|
26
|
+
<a-form-item v-if="showConfig.formKey" label="表单标识key" name="formKey">
|
27
|
+
<a-input v-model:value="formData.formKey" />
|
28
|
+
</a-form-item>
|
29
|
+
</a-form>
|
30
|
+
|
31
|
+
<executionListenerDialog
|
32
|
+
v-if="dialogName === 'executionListenerDialog'"
|
33
|
+
:element="element"
|
34
|
+
:modeler="modeler"
|
35
|
+
@close="finishExecutionListener"
|
36
|
+
/>
|
37
|
+
</div>
|
38
|
+
</template>
|
39
|
+
|
40
|
+
<script setup lang="ts">
|
41
|
+
import { ref, computed, watch, onMounted, nextTick } from 'vue'
|
42
|
+
import { FormInstance } from 'ant-design-vue'
|
43
|
+
import executionListenerDialog from './property/executionListener.vue'
|
44
|
+
import { commonParse } from '../../common/parseElement'
|
45
|
+
import showConfigData from '../../flowable/showConfig'
|
46
|
+
import Modeler from 'bpmn-js/lib/Modeler'
|
47
|
+
|
48
|
+
defineOptions({
|
49
|
+
name: 'StartEndPanel'
|
50
|
+
})
|
51
|
+
|
52
|
+
interface Props {
|
53
|
+
modeler: Modeler
|
54
|
+
element: any
|
55
|
+
}
|
56
|
+
|
57
|
+
const props = defineProps<Props>()
|
58
|
+
|
59
|
+
const formRef = ref<FormInstance>()
|
60
|
+
const dialogName = ref('')
|
61
|
+
const executionListenerLength = ref(0)
|
62
|
+
const formData = ref<Record<string, any>>({})
|
63
|
+
|
64
|
+
const elementType = computed(() => {
|
65
|
+
const bizObj = props.element.businessObject
|
66
|
+
return bizObj.eventDefinitions
|
67
|
+
? bizObj.eventDefinitions[0].$type
|
68
|
+
: bizObj.$type
|
69
|
+
})
|
70
|
+
|
71
|
+
const showConfig = computed(() => (showConfigData as any)[elementType.value] || {})
|
72
|
+
|
73
|
+
const updateProperties = (properties: Record<string, any>) => {
|
74
|
+
nextTick(() => {
|
75
|
+
try {
|
76
|
+
const modeling = props.modeler.get('modeling')
|
77
|
+
modeling.updateProperties(props.element, properties)
|
78
|
+
} catch (error) {
|
79
|
+
console.warn('Update properties error:', error)
|
80
|
+
}
|
81
|
+
})
|
82
|
+
}
|
83
|
+
|
84
|
+
const computedExecutionListenerLength = () => {
|
85
|
+
if (props.element?.businessObject?.extensionElements?.values) {
|
86
|
+
executionListenerLength.value = props.element.businessObject.extensionElements.values
|
87
|
+
.filter((item: any) => item.$type === 'flowable:ExecutionListener').length
|
88
|
+
} else {
|
89
|
+
executionListenerLength.value = 0
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
const finishExecutionListener = () => {
|
94
|
+
if (dialogName.value === 'executionListenerDialog') {
|
95
|
+
computedExecutionListenerLength()
|
96
|
+
}
|
97
|
+
dialogName.value = ''
|
98
|
+
}
|
99
|
+
|
100
|
+
// Watch for form data changes
|
101
|
+
watch(() => formData.value.initiator, (val) => {
|
102
|
+
if (val === '') val = null
|
103
|
+
updateProperties({ 'flowable:initiator': val })
|
104
|
+
})
|
105
|
+
|
106
|
+
watch(() => formData.value.formKey, (val) => {
|
107
|
+
if (val === '') val = null
|
108
|
+
updateProperties({ 'flowable:formKey': val })
|
109
|
+
})
|
110
|
+
|
111
|
+
watch(() => formData.value.id, (val) => {
|
112
|
+
updateProperties({ id: val })
|
113
|
+
})
|
114
|
+
|
115
|
+
watch(() => formData.value.name, (val) => {
|
116
|
+
updateProperties({ name: val })
|
117
|
+
})
|
118
|
+
|
119
|
+
watch(() => formData.value.documentation, (val) => {
|
120
|
+
if (!val) {
|
121
|
+
updateProperties({ documentation: [] })
|
122
|
+
return
|
123
|
+
}
|
124
|
+
if (props.modeler?.get('moddle')) {
|
125
|
+
const documentationElement = props.modeler.get('moddle').create('bpmn:Documentation', { text: val })
|
126
|
+
updateProperties({ documentation: [documentationElement] })
|
127
|
+
}
|
128
|
+
})
|
129
|
+
|
130
|
+
onMounted(() => {
|
131
|
+
if (props.element) {
|
132
|
+
formData.value = commonParse(props.element)
|
133
|
+
computedExecutionListenerLength()
|
134
|
+
}
|
135
|
+
})
|
136
|
+
</script>
|
137
|
+
|
138
|
+
<style scoped>
|
139
|
+
.flow-containers {
|
140
|
+
padding: 0;
|
141
|
+
background: transparent;
|
142
|
+
min-height: 100%;
|
143
|
+
}
|
144
|
+
|
145
|
+
.flow-containers :deep(.ant-form-item) {
|
146
|
+
margin-bottom: 16px;
|
147
|
+
}
|
148
|
+
|
149
|
+
.flow-containers :deep(.ant-form-item-label) {
|
150
|
+
font-weight: 500;
|
151
|
+
color: #262626;
|
152
|
+
}
|
153
|
+
|
154
|
+
.flow-containers :deep(.ant-input),
|
155
|
+
.flow-containers :deep(.ant-select),
|
156
|
+
.flow-containers :deep(.ant-textarea) {
|
157
|
+
border-radius: 6px;
|
158
|
+
transition: all 0.3s;
|
159
|
+
}
|
160
|
+
|
161
|
+
.flow-containers :deep(.ant-button) {
|
162
|
+
border-radius: 6px;
|
163
|
+
font-weight: 500;
|
164
|
+
}
|
165
|
+
|
166
|
+
.flow-containers :deep(.ant-badge) {
|
167
|
+
margin-right: 8px;
|
168
|
+
}
|
169
|
+
|
170
|
+
.flow-containers :deep(.ant-badge .ant-badge-count) {
|
171
|
+
background: linear-gradient(135deg, #ff4d4f 0%, #ff7875 100%);
|
172
|
+
box-shadow: 0 2px 4px rgba(255, 77, 79, 0.3);
|
173
|
+
}
|
174
|
+
</style>
|