Merge pull request #106 from GoldenZqqq/feature/bpm

工作流模块优化与bug修复
pull/594/head
芋道源码 2024-11-21 19:34:57 +08:00 committed by GitHub
commit 738289bc06
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 101 additions and 24 deletions

View File

@ -162,9 +162,11 @@ const getApprovalDetail = async (row: any) => {
startUserSelectTasks.value = data.activityNodes?.filter( startUserSelectTasks.value = data.activityNodes?.filter(
(node: ApprovalNodeInfo) => CandidateStrategy.START_USER_SELECT === node.candidateStrategy (node: ApprovalNodeInfo) => CandidateStrategy.START_USER_SELECT === node.candidateStrategy
) )
if (startUserSelectTasks.value?.length > 0) {
for (const node of startUserSelectTasks.value) { for (const node of startUserSelectTasks.value) {
startUserSelectAssignees.value[node.id] = [] startUserSelectAssignees.value[node.id] = []
} }
}
// Timeline // Timeline
activityNodes.value = data.activityNodes activityNodes.value = data.activityNodes

View File

@ -22,7 +22,7 @@
<el-col :span="5"> <el-col :span="5">
<div class="flex flex-col"> <div class="flex flex-col">
<div <div
v-for="category in categoryList" v-for="category in availableCategories"
:key="category.code" :key="category.code"
class="flex items-center p-10px cursor-pointer text-14px rounded-md" class="flex items-center p-10px cursor-pointer text-14px rounded-md"
:class="categoryActive.code === category.code ? 'text-#3e7bff bg-#e8eeff' : ''" :class="categoryActive.code === category.code ? 'text-#3e7bff bg-#e8eeff' : ''"
@ -33,7 +33,7 @@
</div> </div>
</el-col> </el-col>
<el-col :span="19"> <el-col :span="19">
<el-scrollbar ref="scrollWrapper" height="700"> <el-scrollbar ref="scrollWrapper" height="700" @scroll="handleScroll">
<div <div
class="mb-20px pl-10px" class="mb-20px pl-10px"
v-for="(definitions, categoryCode) in processDefinitionGroup" v-for="(definitions, categoryCode) in processDefinitionGroup"
@ -137,10 +137,6 @@ const getCategoryList = async () => {
try { try {
// //
categoryList.value = await CategoryApi.getCategorySimpleList() categoryList.value = await CategoryApi.getCategorySimpleList()
//
if (categoryList.value.length > 0) {
categoryActive.value = categoryList.value[0]
}
} finally { } finally {
} }
} }
@ -154,6 +150,11 @@ const getProcessDefinitionList = async () => {
}) })
// //
filteredProcessDefinitionList.value = processDefinitionList.value filteredProcessDefinitionList.value = processDefinitionList.value
//
if (availableCategories.value.length > 0 && !categoryActive.value?.code) {
categoryActive.value = availableCategories.value[0]
}
} finally { } finally {
} }
} }
@ -220,10 +221,62 @@ const handleSelect = async (row, formVariables?) => {
processDefinitionDetailRef.value?.initProcessInfo(row, formVariables) processDefinitionDetailRef.value?.initProcessInfo(row, formVariables)
} }
/** 处理滚动事件 */
const handleScroll = (e) => {
// 使
const scrollTop = e.scrollTop
//
const categoryPositions = categoryList.value
.map((category) => {
const categoryRef = proxy.$refs[`category-${category.code}`]
if (categoryRef?.[0]) {
return {
code: category.code,
offsetTop: categoryRef[0].offsetTop,
height: categoryRef[0].offsetHeight
}
}
return null
})
.filter(Boolean)
//
let currentCategory = categoryPositions[0]
for (const position of categoryPositions) {
// 50px
if (scrollTop >= position.offsetTop - 50) {
currentCategory = position
} else {
break
}
}
// active
if (currentCategory && categoryActive.value.code !== currentCategory.code) {
categoryActive.value = categoryList.value.find((c) => c.code === currentCategory.code)
}
}
/** 初始化 */ /** 初始化 */
onMounted(() => { onMounted(() => {
getList() getList()
}) })
/** 过滤出有流程的分类列表 */
const availableCategories = computed(() => {
if (!categoryList.value?.length || !processDefinitionGroup.value) {
return []
}
//
const availableCategoryCodes = Object.keys(processDefinitionGroup.value)
//
return categoryList.value.filter(category =>
availableCategoryCodes.includes(category.code)
)
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -40,14 +40,22 @@ watch(
} }
) )
</script> </script>
<style> <style lang="scss" scoped>
.box-card { .box-card {
height: 100%;
width: 100%; width: 100%;
margin-bottom: 20px; margin-bottom: 0;
:deep(.el-card__body) {
height: 100%;
padding: 0;
} }
:deep(.process-viewer) { :deep(.process-viewer) {
height: 100% !important; height: 100% !important;
min-height: 500px; min-height: 100%;
width: 100%;
overflow: auto;
}
} }
</style> </style>

View File

@ -1,5 +1,5 @@
<template> <template>
<div v-loading="loading" class="mb-20px"> <div v-loading="loading" class="process-viewer-container">
<SimpleProcessViewer <SimpleProcessViewer
:flow-node="simpleModel" :flow-node="simpleModel"
:tasks="tasks" :tasks="tasks"
@ -154,8 +154,15 @@ const setSimpleModelNodeTaskStatus = (
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.process-viewer-container {
height: 100%;
width: 100%;
:deep(.process-viewer) { :deep(.process-viewer) {
height: 100% !important; height: 100% !important;
min-height: 500px; min-height: 100%;
width: 100%;
overflow: auto;
}
} }
</style> </style>

View File

@ -16,10 +16,10 @@
<img class="w-full h-full" :src="getApprovalNodeImg(activity.nodeType)" alt="" /> <img class="w-full h-full" :src="getApprovalNodeImg(activity.nodeType)" alt="" />
<div <div
v-if="showStatusIcon" v-if="showStatusIcon"
class="position-absolute top-17px left-17px rounded-full flex items-center p-2px" class="position-absolute top-17px left-17px rounded-full flex items-center p-1px border-2 border-white border-solid"
:style="{ backgroundColor: getApprovalNodeColor(activity.status) }" :style="{ backgroundColor: getApprovalNodeColor(activity.status) }"
> >
<el-icon :size="12" color="#fff"> <el-icon :size="11" color="#fff">
<component :is="getApprovalNodeIcon(activity.status, activity.nodeType)" /> <component :is="getApprovalNodeIcon(activity.status, activity.nodeType)" />
</el-icon> </el-icon>
</div> </div>
@ -106,10 +106,10 @@
<!-- 信息任务 ICON --> <!-- 信息任务 ICON -->
<div <div
v-if="showStatusIcon && onlyStatusIconShow.includes(task.status)" v-if="showStatusIcon && onlyStatusIconShow.includes(task.status)"
class="position-absolute top-19px left-23px rounded-full flex items-center p-2px" class="position-absolute top-19px left-23px rounded-full flex items-center p-1px border-2 border-white border-solid"
:style="{ backgroundColor: statusIconMap2[task.status]?.color }" :style="{ backgroundColor: statusIconMap2[task.status]?.color }"
> >
<Icon :size="12" :icon="statusIconMap2[task.status]?.icon" color="#FFFFFF" /> <Icon :size="11" :icon="statusIconMap2[task.status]?.icon" color="#FFFFFF" />
</div> </div>
</div> </div>
</div> </div>
@ -140,10 +140,10 @@
<!-- 信息任务 ICON --> <!-- 信息任务 ICON -->
<div <div
v-if="showStatusIcon" v-if="showStatusIcon"
class="position-absolute top-19px left-23px rounded-full flex items-center p-2px" class="position-absolute top-20px left-24px rounded-full flex items-center p-1px border-2 border-white border-solid"
:style="{ backgroundColor: statusIconMap2['-1']?.color }" :style="{ backgroundColor: statusIconMap2['-1']?.color }"
> >
<Icon :size="12" :icon="statusIconMap2['-1']?.icon" color="#FFFFFF" /> <Icon :size="11" :icon="statusIconMap2['-1']?.icon" color="#FFFFFF" />
</div> </div>
</div> </div>
</div> </div>

View File

@ -128,6 +128,7 @@ import { formatDate } from '@/utils/formatTime'
import { DICT_TYPE } from '@/utils/dict' import { DICT_TYPE } from '@/utils/dict'
import { BpmModelType } from '@/utils/constants' import { BpmModelType } from '@/utils/constants'
import { setConfAndFields2 } from '@/utils/formCreate' import { setConfAndFields2 } from '@/utils/formCreate'
import { registerComponent } from '@/utils/routerHelper'
import type { ApiAttrs } from '@form-create/element-ui/types/config' import type { ApiAttrs } from '@form-create/element-ui/types/config'
import * as ProcessInstanceApi from '@/api/bpm/processInstance' import * as ProcessInstanceApi from '@/api/bpm/processInstance'
import * as UserApi from '@/api/system/user' import * as UserApi from '@/api/system/user'
@ -228,6 +229,9 @@ const getApprovalDetail = async () => {
}) })
} }
}) })
} else {
// data.processDefinition.formCustomViewPath /crm/contract/detail/index.vue
BusinessFormComponent.value = registerComponent(data.processDefinition.formCustomViewPath)
} }
// Timeline // Timeline
@ -319,9 +323,12 @@ $process-header-height: 194px;
$process-header-height - 40px $process-header-height - 40px
); );
overflow: auto; overflow: auto;
display: flex;
flex-direction: column;
:deep(.box-card) { :deep(.box-card) {
height: 100%; height: 100%;
flex: 1;
.el-card__body { .el-card__body {
height: 100%; height: 100%;