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
This commit is contained in:
YunaiV
2024-12-15 16:28:33 +08:00
10 changed files with 1178 additions and 167 deletions

View File

@@ -38,12 +38,21 @@ import * as UserGroupApi from '@/api/bpm/userGroup'
defineOptions({
name: 'SimpleProcessDesigner'
})
const emits = defineEmits(['success']) // 保存成功事件
const props = defineProps({
modelId: {
type: String,
required: true
required: false
},
modelKey: {
type: String,
required: false
},
modelName: {
type: String,
required: false
}
})
@@ -69,6 +78,33 @@ const message = useMessage() // 国际化
const processNodeTree = ref<SimpleFlowNode | undefined>()
const errorDialogVisible = ref(false)
let errorNodes: SimpleFlowNode[] = []
// 添加更新模型的方法
const updateModel = (key?: string, name?: string) => {
if (!processNodeTree.value) {
processNodeTree.value = {
name: name || '发起人',
type: NodeType.START_USER_NODE,
id: NodeId.START_USER_NODE_ID,
childNode: {
id: NodeId.END_EVENT_NODE_ID,
name: '结束',
type: NodeType.END_EVENT_NODE
}
}
} else if (name) {
// 更新现有模型的名称
processNodeTree.value.name = name
}
}
// 监听属性变化
watch([() => props.modelKey, () => props.modelName], ([newKey, newName]) => {
if (!props.modelId && newKey && newName) {
updateModel(newKey, newName)
}
}, { immediate: true, deep: true })
const saveSimpleFlowModel = async (simpleModelNode: SimpleFlowNode) => {
if (!simpleModelNode) {
message.error('模型数据为空')
@@ -76,21 +112,28 @@ const saveSimpleFlowModel = async (simpleModelNode: SimpleFlowNode) => {
}
try {
loading.value = true
const data = {
id: props.modelId,
simpleModel: simpleModelNode
}
const result = await updateBpmSimpleModel(data)
if (result) {
message.success('修改成功')
emits('success')
if (props.modelId) {
// 编辑模式
const data = {
id: props.modelId,
simpleModel: simpleModelNode
}
const result = await updateBpmSimpleModel(data)
if (result) {
message.success('修改成功')
emits('success')
} else {
message.alert('修改失败')
}
} else {
message.alert('修改失败')
// 新建模式,直接返回数据
emits('success', simpleModelNode)
}
} finally {
loading.value = false
}
}
// 校验节点设置。 暂时以 showText 为空 未节点错误配置
const validateNode = (node: SimpleFlowNode | undefined, errorNodes: SimpleFlowNode[]) => {
if (node) {
@@ -134,12 +177,14 @@ onMounted(async () => {
try {
loading.value = true
// 获取表单字段
const bpmnModel = await getModel(props.modelId)
if (bpmnModel) {
formType.value = bpmnModel.formType
if (formType.value === 10) {
const bpmnForm = (await getForm(bpmnModel.formId)) as unknown as FormVO
formFields.value = bpmnForm?.fields
if (props.modelId) {
const bpmnModel = await getModel(props.modelId)
if (bpmnModel) {
formType.value = bpmnModel.formType
if (formType.value === 10) {
const bpmnForm = (await getForm(bpmnModel.formId)) as unknown as FormVO
formFields.value = bpmnForm?.fields
}
}
}
// 获得角色列表
@@ -155,14 +200,18 @@ onMounted(async () => {
// 获取用户组列表
userGroupOptions.value = await UserGroupApi.getUserGroupSimpleList()
//获取 SIMPLE 设计器模型
const result = await getBpmSimpleModel(props.modelId)
if (result) {
processNodeTree.value = result
} else {
// 初始值
if (props.modelId) {
//获取 SIMPLE 设计器模型
const result = await getBpmSimpleModel(props.modelId)
if (result) {
processNodeTree.value = result
}
}
// 如果没有现有模型,创建初始模型
if (!processNodeTree.value) {
processNodeTree.value = {
name: '发起人',
name: props.modelName || '发起人',
type: NodeType.START_USER_NODE,
id: NodeId.START_USER_NODE_ID,
childNode: {

View File

@@ -39,7 +39,7 @@
</Dialog>
</template>
<script lang="ts" setup>
import { defaultProps, findTreeNode, handleTree } from '@/utils/tree'
import { defaultProps, handleTree } from '@/utils/tree'
import * as DeptApi from '@/api/system/dept'
import * as UserApi from '@/api/system/user'
@@ -50,6 +50,7 @@ const emit = defineEmits<{
const { t } = useI18n() // 国际
const message = useMessage() // 消息弹窗
const deptTree = ref<Tree[]>([]) // 部门树形结构化
const deptList = ref<any[]>([]) // 保存扁平化的部门列表数据
const userList = ref<UserApi.UserVO[]>([]) // 所有用户列表
const filteredUserList = ref<UserApi.UserVO[]>([]) // 当前部门过滤后的用户列表
const selectedUserIdList: any = ref([]) // 选中的用户列表
@@ -79,7 +80,9 @@ const open = async (id: number, selectedList?: any[]) => {
resetForm()
// 加载部门、用户列表
deptTree.value = handleTree(await DeptApi.getSimpleDeptList())
const deptData = await DeptApi.getSimpleDeptList()
deptList.value = deptData // 保存扁平结构的部门数据
deptTree.value = handleTree(deptData) // 转换成树形结构
userList.value = await UserApi.getSimpleUserList()
// 初始状态下,过滤列表等于所有用户列表
@@ -88,16 +91,31 @@ const open = async (id: number, selectedList?: any[]) => {
dialogVisible.value = true
}
/** 获取指定部门及其所有子部门的ID列表 */
const getChildDeptIds = (deptId: number, deptList: any[]): number[] => {
const ids = [deptId]
const children = deptList.filter((dept) => dept.parentId === deptId)
children.forEach((child) => {
ids.push(...getChildDeptIds(child.id, deptList))
})
return ids
}
/** 获取部门过滤后的用户列表 */
const getUserList = async (deptId?: number) => {
const filterUserList = async (deptId?: number) => {
formLoading.value = true
try {
// @ts-ignore
// TODO @芋艿:替换到 simple List 暂不支持 deptId 过滤
// TODO @Zqqq这个可以使用前端过滤么通过 deptList 获取到 deptId 子节点,然后去 userList
const data = await UserApi.getUserPage({ pageSize: 100, pageNo: 1, deptId })
// 更新过滤后的用户列表
filteredUserList.value = data.list
if (!deptId) {
// 如果没有选择部门,显示所有用户
filteredUserList.value = [...userList.value]
return
}
// 直接使用已保存的部门列表数据进行过滤
const deptIds = getChildDeptIds(deptId, deptList.value)
// 过滤出这些部门下的用户
filteredUserList.value = userList.value.filter((user) => deptIds.includes(user.deptId))
} finally {
formLoading.value = false
}
@@ -121,6 +139,7 @@ const submitForm = async () => {
/** 重置表单 */
const resetForm = () => {
deptTree.value = []
deptList.value = []
userList.value = []
filteredUserList.value = []
selectedUserIdList.value = []
@@ -128,7 +147,7 @@ const resetForm = () => {
/** 处理部门被点击 */
const handleNodeClick = (row: { [key: string]: any }) => {
getUserList(row.id)
filterUserList(row.id)
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗

View File

@@ -1,6 +1,6 @@
<template>
<div class="process-panel__container" :style="{ width: `${width}px`, maxHeight: '700px' }">
<el-collapse v-model="activeTab">
<div class="process-panel__container" :style="{ width: `${width}px` }">
<el-collapse v-model="activeTab" v-if="isReady">
<el-collapse-item name="base">
<!-- class="panel-tab__title" -->
<template #title>
@@ -119,24 +119,16 @@ const elementBusinessObject = ref<any>({}) // 元素 businessObject 镜像,提
const conditionFormVisible = ref(false) // 流转条件设置
const formVisible = ref(false) // 表单配置
const bpmnElement = ref()
const isReady = ref(false)
provide('prefix', props.prefix)
provide('width', props.width)
const bpmnInstances = () => (window as any)?.bpmnInstances
// 监听 props.bpmnModeler 然后 initModels
const unwatchBpmn = watch(
() => props.bpmnModeler,
() => {
// 避免加载时 流程图 并未加载完成
if (!props.bpmnModeler) {
console.log('缺少props.bpmnModeler')
return
}
console.log('props.bpmnModeler 有值了!!!')
const w = window as any
w.bpmnInstances = {
// 初始化 bpmnInstances
const initBpmnInstances = () => {
if (!props.bpmnModeler) return false
try {
const instances = {
modeler: props.bpmnModeler,
modeling: props.bpmnModeler.get('modeling'),
moddle: props.bpmnModeler.get('moddle'),
@@ -148,9 +140,45 @@ const unwatchBpmn = watch(
selection: props.bpmnModeler.get('selection')
}
console.log(bpmnInstances(), 'window.bpmnInstances')
getActiveElement()
unwatchBpmn()
// 检查所有实例是否都存在
const allInstancesExist = Object.values(instances).every(instance => instance)
if (allInstancesExist) {
const w = window as any
w.bpmnInstances = instances
return true
}
return false
} catch (error) {
console.error('初始化 bpmnInstances 失败:', error)
return false
}
}
const bpmnInstances = () => (window as any)?.bpmnInstances
// 监听 props.bpmnModeler 然后 initModels
const unwatchBpmn = watch(
() => props.bpmnModeler,
async () => {
// 避免加载时 流程图 并未加载完成
if (!props.bpmnModeler) {
console.log('缺少props.bpmnModeler')
return
}
try {
// 等待 modeler 初始化完成
await nextTick()
if (initBpmnInstances()) {
isReady.value = true
await nextTick()
getActiveElement()
} else {
console.error('modeler 实例未完全初始化')
}
} catch (error) {
console.error('初始化失败:', error)
}
},
{
immediate: true
@@ -158,6 +186,8 @@ const unwatchBpmn = watch(
)
const getActiveElement = () => {
if (!isReady.value || !props.bpmnModeler) return
// 初始第一个选中元素 bpmn:Process
initFormOnChanged(null)
props.bpmnModeler.on('import.done', (e) => {
@@ -175,8 +205,11 @@ const getActiveElement = () => {
}
})
}
// 初始化数据
const initFormOnChanged = (element) => {
if (!isReady.value || !bpmnInstances()) return
let activatedElement = element
if (!activatedElement) {
activatedElement =
@@ -184,32 +217,36 @@ const initFormOnChanged = (element) => {
bpmnInstances().elementRegistry.find((el) => el.type === 'bpmn:Collaboration')
}
if (!activatedElement) return
console.log(`
----------
select element changed:
id: ${activatedElement.id}
type: ${activatedElement.businessObject.$type}
----------
`)
console.log('businessObject: ', activatedElement.businessObject)
bpmnInstances().bpmnElement = activatedElement
bpmnElement.value = activatedElement
elementId.value = activatedElement.id
elementType.value = activatedElement.type.split(':')[1] || ''
elementBusinessObject.value = JSON.parse(JSON.stringify(activatedElement.businessObject))
conditionFormVisible.value = !!(
elementType.value === 'SequenceFlow' &&
activatedElement.source &&
activatedElement.source.type.indexOf('StartEvent') === -1
)
formVisible.value = elementType.value === 'UserTask' || elementType.value === 'StartEvent'
try {
console.log(`
----------
select element changed:
id: ${activatedElement.id}
type: ${activatedElement.businessObject.$type}
----------
`)
console.log('businessObject: ', activatedElement.businessObject)
bpmnInstances().bpmnElement = activatedElement
bpmnElement.value = activatedElement
elementId.value = activatedElement.id
elementType.value = activatedElement.type.split(':')[1] || ''
elementBusinessObject.value = JSON.parse(JSON.stringify(activatedElement.businessObject))
conditionFormVisible.value = !!(
elementType.value === 'SequenceFlow' &&
activatedElement.source &&
activatedElement.source.type.indexOf('StartEvent') === -1
)
formVisible.value = elementType.value === 'UserTask' || elementType.value === 'StartEvent'
} catch (error) {
console.error('初始化表单数据失败:', error)
}
}
onBeforeUnmount(() => {
const w = window as any
w.bpmnInstances = null
console.log(props, 'props1')
console.log(props.bpmnModeler, 'props.bpmnModeler1')
isReady.value = false
})
watch(