Skip to content

Commit c083a0c

Browse files
committed
Merge branch 'feature/bpm' of https://github.com/yudaocode/yudao-ui-admin-vue3 into feature/bpm
# Conflicts: # src/components/bpmnProcessDesigner/package/penal/PropertiesPanel.vue # src/views/bpm/model/editor/index.vue
2 parents 9f0f5b0 + 9685fbf commit c083a0c

File tree

10 files changed

+1177
-166
lines changed

10 files changed

+1177
-166
lines changed

src/components/SimpleProcessDesignerV2/src/SimpleProcessDesigner.vue

Lines changed: 72 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,21 @@ import * as UserGroupApi from '@/api/bpm/userGroup'
3838
defineOptions({
3939
name: 'SimpleProcessDesigner'
4040
})
41+
4142
const emits = defineEmits(['success']) // 保存成功事件
4243
4344
const props = defineProps({
4445
modelId: {
4546
type: String,
46-
required: true
47+
required: false
48+
},
49+
modelKey: {
50+
type: String,
51+
required: false
52+
},
53+
modelName: {
54+
type: String,
55+
required: false
4756
}
4857
})
4958
@@ -69,28 +78,62 @@ const message = useMessage() // 国际化
6978
const processNodeTree = ref<SimpleFlowNode | undefined>()
7079
const errorDialogVisible = ref(false)
7180
let errorNodes: SimpleFlowNode[] = []
81+
82+
// 添加更新模型的方法
83+
const updateModel = (key?: string, name?: string) => {
84+
if (!processNodeTree.value) {
85+
processNodeTree.value = {
86+
name: name || '发起人',
87+
type: NodeType.START_USER_NODE,
88+
id: NodeId.START_USER_NODE_ID,
89+
childNode: {
90+
id: NodeId.END_EVENT_NODE_ID,
91+
name: '结束',
92+
type: NodeType.END_EVENT_NODE
93+
}
94+
}
95+
} else if (name) {
96+
// 更新现有模型的名称
97+
processNodeTree.value.name = name
98+
}
99+
}
100+
101+
// 监听属性变化
102+
watch([() => props.modelKey, () => props.modelName], ([newKey, newName]) => {
103+
if (!props.modelId && newKey && newName) {
104+
updateModel(newKey, newName)
105+
}
106+
}, { immediate: true, deep: true })
107+
72108
const saveSimpleFlowModel = async (simpleModelNode: SimpleFlowNode) => {
73109
if (!simpleModelNode) {
74110
message.error('模型数据为空')
75111
return
76112
}
77113
try {
78114
loading.value = true
79-
const data = {
80-
id: props.modelId,
81-
simpleModel: simpleModelNode
82-
}
83-
const result = await updateBpmSimpleModel(data)
84-
if (result) {
85-
message.success('修改成功')
86-
emits('success')
115+
if (props.modelId) {
116+
// 编辑模式
117+
const data = {
118+
id: props.modelId,
119+
simpleModel: simpleModelNode
120+
}
121+
const result = await updateBpmSimpleModel(data)
122+
if (result) {
123+
message.success('修改成功')
124+
emits('success')
125+
} else {
126+
message.alert('修改失败')
127+
}
87128
} else {
88-
message.alert('修改失败')
129+
// 新建模式,直接返回数据
130+
emits('success', simpleModelNode)
89131
}
90132
} finally {
91133
loading.value = false
92134
}
93135
}
136+
94137
// 校验节点设置。 暂时以 showText 为空 未节点错误配置
95138
const validateNode = (node: SimpleFlowNode | undefined, errorNodes: SimpleFlowNode[]) => {
96139
if (node) {
@@ -134,12 +177,14 @@ onMounted(async () => {
134177
try {
135178
loading.value = true
136179
// 获取表单字段
137-
const bpmnModel = await getModel(props.modelId)
138-
if (bpmnModel) {
139-
formType.value = bpmnModel.formType
140-
if (formType.value === 10) {
141-
const bpmnForm = (await getForm(bpmnModel.formId)) as unknown as FormVO
142-
formFields.value = bpmnForm?.fields
180+
if (props.modelId) {
181+
const bpmnModel = await getModel(props.modelId)
182+
if (bpmnModel) {
183+
formType.value = bpmnModel.formType
184+
if (formType.value === 10) {
185+
const bpmnForm = (await getForm(bpmnModel.formId)) as unknown as FormVO
186+
formFields.value = bpmnForm?.fields
187+
}
143188
}
144189
}
145190
// 获得角色列表
@@ -155,14 +200,18 @@ onMounted(async () => {
155200
// 获取用户组列表
156201
userGroupOptions.value = await UserGroupApi.getUserGroupSimpleList()
157202
158-
//获取 SIMPLE 设计器模型
159-
const result = await getBpmSimpleModel(props.modelId)
160-
if (result) {
161-
processNodeTree.value = result
162-
} else {
163-
// 初始值
203+
if (props.modelId) {
204+
//获取 SIMPLE 设计器模型
205+
const result = await getBpmSimpleModel(props.modelId)
206+
if (result) {
207+
processNodeTree.value = result
208+
}
209+
}
210+
211+
// 如果没有现有模型,创建初始模型
212+
if (!processNodeTree.value) {
164213
processNodeTree.value = {
165-
name: '发起人',
214+
name: props.modelName || '发起人',
166215
type: NodeType.START_USER_NODE,
167216
id: NodeId.START_USER_NODE_ID,
168217
childNode: {

src/components/UserSelectForm/index.vue

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
</Dialog>
4040
</template>
4141
<script lang="ts" setup>
42-
import { defaultProps, findTreeNode, handleTree } from '@/utils/tree'
42+
import { defaultProps, handleTree } from '@/utils/tree'
4343
import * as DeptApi from '@/api/system/dept'
4444
import * as UserApi from '@/api/system/user'
4545
@@ -50,6 +50,7 @@ const emit = defineEmits<{
5050
const { t } = useI18n() // 国际
5151
const message = useMessage() // 消息弹窗
5252
const deptTree = ref<Tree[]>([]) // 部门树形结构化
53+
const deptList = ref<any[]>([]) // 保存扁平化的部门列表数据
5354
const userList = ref<UserApi.UserVO[]>([]) // 所有用户列表
5455
const filteredUserList = ref<UserApi.UserVO[]>([]) // 当前部门过滤后的用户列表
5556
const selectedUserIdList: any = ref([]) // 选中的用户列表
@@ -79,7 +80,9 @@ const open = async (id: number, selectedList?: any[]) => {
7980
resetForm()
8081
8182
// 加载部门、用户列表
82-
deptTree.value = handleTree(await DeptApi.getSimpleDeptList())
83+
const deptData = await DeptApi.getSimpleDeptList()
84+
deptList.value = deptData // 保存扁平结构的部门数据
85+
deptTree.value = handleTree(deptData) // 转换成树形结构
8386
userList.value = await UserApi.getSimpleUserList()
8487
8588
// 初始状态下,过滤列表等于所有用户列表
@@ -88,16 +91,31 @@ const open = async (id: number, selectedList?: any[]) => {
8891
dialogVisible.value = true
8992
}
9093
94+
/** 获取指定部门及其所有子部门的ID列表 */
95+
const getChildDeptIds = (deptId: number, deptList: any[]): number[] => {
96+
const ids = [deptId]
97+
const children = deptList.filter((dept) => dept.parentId === deptId)
98+
children.forEach((child) => {
99+
ids.push(...getChildDeptIds(child.id, deptList))
100+
})
101+
return ids
102+
}
103+
91104
/** 获取部门过滤后的用户列表 */
92-
const getUserList = async (deptId?: number) => {
105+
const filterUserList = async (deptId?: number) => {
93106
formLoading.value = true
94107
try {
95-
// @ts-ignore
96-
// TODO @芋艿:替换到 simple List 暂不支持 deptId 过滤
97-
// TODO @Zqqq:这个,可以使用前端过滤么?通过 deptList 获取到 deptId 子节点,然后去 userList
98-
const data = await UserApi.getUserPage({ pageSize: 100, pageNo: 1, deptId })
99-
// 更新过滤后的用户列表
100-
filteredUserList.value = data.list
108+
if (!deptId) {
109+
// 如果没有选择部门,显示所有用户
110+
filteredUserList.value = [...userList.value]
111+
return
112+
}
113+
114+
// 直接使用已保存的部门列表数据进行过滤
115+
const deptIds = getChildDeptIds(deptId, deptList.value)
116+
117+
// 过滤出这些部门下的用户
118+
filteredUserList.value = userList.value.filter((user) => deptIds.includes(user.deptId))
101119
} finally {
102120
formLoading.value = false
103121
}
@@ -121,14 +139,15 @@ const submitForm = async () => {
121139
/** 重置表单 */
122140
const resetForm = () => {
123141
deptTree.value = []
142+
deptList.value = []
124143
userList.value = []
125144
filteredUserList.value = []
126145
selectedUserIdList.value = []
127146
}
128147
129148
/** 处理部门被点击 */
130149
const handleNodeClick = (row: { [key: string]: any }) => {
131-
getUserList(row.id)
150+
filterUserList(row.id)
132151
}
133152
134153
defineExpose({ open }) // 提供 open 方法,用于打开弹窗

src/components/bpmnProcessDesigner/package/penal/PropertiesPanel.vue

Lines changed: 77 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
2-
<div class="process-panel__container" :style="{ width: `${width}px`, maxHeight: '700px' }">
3-
<el-collapse v-model="activeTab">
2+
<div class="process-panel__container" :style="{ width: `${width}px` }">
3+
<el-collapse v-model="activeTab" v-if="isReady">
44
<el-collapse-item name="base">
55
<!-- class="panel-tab__title" -->
66
<template #title>
@@ -119,24 +119,16 @@ const elementBusinessObject = ref<any>({}) // 元素 businessObject 镜像,提
119119
const conditionFormVisible = ref(false) // 流转条件设置
120120
const formVisible = ref(false) // 表单配置
121121
const bpmnElement = ref()
122+
const isReady = ref(false)
122123
123124
provide('prefix', props.prefix)
124125
provide('width', props.width)
125-
const bpmnInstances = () => (window as any)?.bpmnInstances
126-
127-
// 监听 props.bpmnModeler 然后 initModels
128-
const unwatchBpmn = watch(
129-
() => props.bpmnModeler,
130-
() => {
131-
// 避免加载时 流程图 并未加载完成
132-
if (!props.bpmnModeler) {
133-
console.log('缺少props.bpmnModeler')
134-
return
135-
}
136126
137-
console.log('props.bpmnModeler 有值了!!!')
138-
const w = window as any
139-
w.bpmnInstances = {
127+
// 初始化 bpmnInstances
128+
const initBpmnInstances = () => {
129+
if (!props.bpmnModeler) return false
130+
try {
131+
const instances = {
140132
modeler: props.bpmnModeler,
141133
modeling: props.bpmnModeler.get('modeling'),
142134
moddle: props.bpmnModeler.get('moddle'),
@@ -148,16 +140,54 @@ const unwatchBpmn = watch(
148140
selection: props.bpmnModeler.get('selection')
149141
}
150142
151-
console.log(bpmnInstances(), 'window.bpmnInstances')
152-
getActiveElement()
153-
unwatchBpmn()
143+
// 检查所有实例是否都存在
144+
const allInstancesExist = Object.values(instances).every(instance => instance)
145+
if (allInstancesExist) {
146+
const w = window as any
147+
w.bpmnInstances = instances
148+
return true
149+
}
150+
return false
151+
} catch (error) {
152+
console.error('初始化 bpmnInstances 失败:', error)
153+
return false
154+
}
155+
}
156+
157+
const bpmnInstances = () => (window as any)?.bpmnInstances
158+
159+
// 监听 props.bpmnModeler 然后 initModels
160+
const unwatchBpmn = watch(
161+
() => props.bpmnModeler,
162+
async () => {
163+
// 避免加载时 流程图 并未加载完成
164+
if (!props.bpmnModeler) {
165+
console.log('缺少props.bpmnModeler')
166+
return
167+
}
168+
169+
try {
170+
// 等待 modeler 初始化完成
171+
await nextTick()
172+
if (initBpmnInstances()) {
173+
isReady.value = true
174+
await nextTick()
175+
getActiveElement()
176+
} else {
177+
console.error('modeler 实例未完全初始化')
178+
}
179+
} catch (error) {
180+
console.error('初始化失败:', error)
181+
}
154182
},
155183
{
156184
immediate: true
157185
}
158186
)
159187
160188
const getActiveElement = () => {
189+
if (!isReady.value || !props.bpmnModeler) return
190+
161191
// 初始第一个选中元素 bpmn:Process
162192
initFormOnChanged(null)
163193
props.bpmnModeler.on('import.done', (e) => {
@@ -175,41 +205,48 @@ const getActiveElement = () => {
175205
}
176206
})
177207
}
208+
178209
// 初始化数据
179210
const initFormOnChanged = (element) => {
211+
if (!isReady.value || !bpmnInstances()) return
212+
180213
let activatedElement = element
181214
if (!activatedElement) {
182215
activatedElement =
183216
bpmnInstances().elementRegistry.find((el) => el.type === 'bpmn:Process') ??
184217
bpmnInstances().elementRegistry.find((el) => el.type === 'bpmn:Collaboration')
185218
}
186219
if (!activatedElement) return
187-
console.log(`
188-
----------
189-
select element changed:
190-
id: ${activatedElement.id}
191-
type: ${activatedElement.businessObject.$type}
192-
----------
193-
`)
194-
console.log('businessObject: ', activatedElement.businessObject)
195-
bpmnInstances().bpmnElement = activatedElement
196-
bpmnElement.value = activatedElement
197-
elementId.value = activatedElement.id
198-
elementType.value = activatedElement.type.split(':')[1] || ''
199-
elementBusinessObject.value = JSON.parse(JSON.stringify(activatedElement.businessObject))
200-
conditionFormVisible.value = !!(
201-
elementType.value === 'SequenceFlow' &&
202-
activatedElement.source &&
203-
activatedElement.source.type.indexOf('StartEvent') === -1
204-
)
205-
formVisible.value = elementType.value === 'UserTask' || elementType.value === 'StartEvent'
220+
221+
try {
222+
console.log(`
223+
----------
224+
select element changed:
225+
id: ${activatedElement.id}
226+
type: ${activatedElement.businessObject.$type}
227+
----------
228+
`)
229+
console.log('businessObject: ', activatedElement.businessObject)
230+
bpmnInstances().bpmnElement = activatedElement
231+
bpmnElement.value = activatedElement
232+
elementId.value = activatedElement.id
233+
elementType.value = activatedElement.type.split(':')[1] || ''
234+
elementBusinessObject.value = JSON.parse(JSON.stringify(activatedElement.businessObject))
235+
conditionFormVisible.value = !!(
236+
elementType.value === 'SequenceFlow' &&
237+
activatedElement.source &&
238+
activatedElement.source.type.indexOf('StartEvent') === -1
239+
)
240+
formVisible.value = elementType.value === 'UserTask' || elementType.value === 'StartEvent'
241+
} catch (error) {
242+
console.error('初始化表单数据失败:', error)
243+
}
206244
}
207245
208246
onBeforeUnmount(() => {
209247
const w = window as any
210248
w.bpmnInstances = null
211-
console.log(props, 'props1')
212-
console.log(props.bpmnModeler, 'props.bpmnModeler1')
249+
isReady.value = false
213250
})
214251
215252
watch(

0 commit comments

Comments
 (0)