1
1
<template >
2
- <div class =" flex items-center h-50px" >
2
+ <div class =" flex items-center h-50px" v-memo = " [categoryInfo.name, isCategorySorting] " >
3
3
<!-- 头部:分类名 -->
4
4
<div class =" flex items-center" >
5
5
<el-tooltip content =" 拖动排序" v-if =" isCategorySorting" >
13
13
<div class =" color-gray-600 text-16px" > ({{ categoryInfo.modelList?.length || 0 }}) </div >
14
14
</div >
15
15
<!-- 头部:操作 -->
16
- <div class =" flex-1 flex" v-if =" !isCategorySorting" >
16
+ <div class =" flex-1 flex" v-show =" !isCategorySorting" >
17
17
<div
18
18
v-if =" categoryInfo.modelList.length > 0"
19
19
class =" ml-20px flex items-center"
69
69
<el-collapse-transition >
70
70
<div v-show =" isExpand" >
71
71
<el-table
72
+ v-if =" modelList && modelList.length > 0"
72
73
:class =" categoryInfo.name"
73
74
ref =" tableRef"
74
- :header-cell-style =" { backgroundColor: isDark ? '' : '#edeff0', paddingLeft: '10px' }"
75
- :cell-style =" { paddingLeft: '10px' }"
76
- :row-style =" { height: '68px' }"
77
75
:data =" modelList"
78
76
row-key =" id"
77
+ :header-cell-style =" tableHeaderStyle"
78
+ :cell-style =" tableCellStyle"
79
+ :row-style =" { height: '68px' }"
79
80
>
80
81
<el-table-column label =" 流程名" prop =" name" min-width =" 150" >
81
- <template #default =" scope " >
82
+ <template #default =" { row } " >
82
83
<div class =" flex items-center" >
83
84
<el-tooltip content =" 拖动排序" v-if =" isModelSorting" >
84
85
<Icon
85
86
icon =" ic:round-drag-indicator"
86
87
class =" drag-icon cursor-move text-#8a909c mr-10px"
87
88
/>
88
89
</el-tooltip >
89
- <el-image :src =" scope. row.icon" class =" h-38px w-38px mr-10px rounded" />
90
- {{ scope. row.name }}
90
+ <el-image v-if = " row.icon " :src =" row.icon" class =" h-38px w-38px mr-10px rounded" />
91
+ {{ row.name }}
91
92
</div >
92
93
</template >
93
94
</el-table-column >
94
95
<el-table-column label =" 可见范围" prop =" startUserIds" min-width =" 150" >
95
- <template #default =" scope " >
96
- <el-text v-if =" !scope. row.startUsers || scope.row.startUsers. length === 0 " >
96
+ <template #default =" { row } " >
97
+ <el-text v-if =" !row.startUsers?. length" >
97
98
全部可见
98
99
</el-text >
99
- <el-text v-else-if =" scope. row.startUsers.length == 1" >
100
- {{ scope. row.startUsers[0].nickname }}
100
+ <el-text v-else-if =" row.startUsers.length = == 1" >
101
+ {{ row.startUsers[0].nickname }}
101
102
</el-text >
102
103
<el-text v-else >
103
104
<el-tooltip
104
105
class =" box-item"
105
106
effect =" dark"
106
107
placement =" top"
107
- :content =" scope. row.startUsers.map((user: any) => user.nickname).join('、')"
108
+ :content =" row.startUsers.map((user: any) => user.nickname).join('、')"
108
109
>
109
- {{ scope. row.startUsers[0].nickname }}等 {{ scope. row.startUsers.length }} 人可见
110
+ {{ row.startUsers[0].nickname }}等 {{ row.startUsers.length }} 人可见
110
111
</el-tooltip >
111
112
</el-text >
112
113
</template >
245
246
<script lang="ts" setup>
246
247
import { CategoryApi , CategoryVO } from ' @/api/bpm/category'
247
248
import Sortable from ' sortablejs'
248
- import { propTypes } from ' @/utils/propTypes'
249
249
import { formatDate } from ' @/utils/formatTime'
250
250
import * as ModelApi from ' @/api/bpm/model'
251
251
import * as FormApi from ' @/api/bpm/form'
@@ -254,15 +254,49 @@ import { BpmModelFormType } from '@/utils/constants'
254
254
import { checkPermi } from ' @/utils/permission'
255
255
import { useUserStoreWithOut } from ' @/store/modules/user'
256
256
import { useAppStore } from ' @/store/modules/app'
257
- import { cloneDeep } from ' lodash-es'
257
+ import { cloneDeep , isEqual } from ' lodash-es'
258
258
import { useTagsView } from ' @/hooks/web/useTagsView'
259
+ import { useDebounceFn } from ' @vueuse/core'
259
260
260
261
defineOptions ({ name: ' BpmModel' })
261
262
262
- const props = defineProps ({
263
- categoryInfo: propTypes .object .def ([]), // 分类后的数据
264
- isCategorySorting: propTypes .bool .def (false ) // 是否分类在排序
265
- })
263
+ // 优化 Props 类型定义
264
+ interface UserInfo {
265
+ nickname: string
266
+ [key : string ]: any
267
+ }
268
+
269
+ interface ProcessDefinition {
270
+ deploymentTime: string
271
+ version: number
272
+ suspensionState: number
273
+ }
274
+
275
+ interface ModelInfo {
276
+ id: number
277
+ name: string
278
+ icon? : string
279
+ startUsers? : UserInfo []
280
+ processDefinition? : ProcessDefinition
281
+ formType? : number
282
+ formId? : number
283
+ formName? : string
284
+ formCustomCreatePath? : string
285
+ managerUserIds? : number []
286
+ [key : string ]: any
287
+ }
288
+
289
+ interface CategoryInfoProps {
290
+ id: number
291
+ name: string
292
+ modelList: ModelInfo []
293
+ }
294
+
295
+ const props = defineProps <{
296
+ categoryInfo: CategoryInfoProps
297
+ isCategorySorting: boolean
298
+ }>()
299
+
266
300
const emit = defineEmits ([' success' ])
267
301
const message = useMessage () // 消息弹窗
268
302
const { t } = useI18n () // 国际化
@@ -271,10 +305,26 @@ const userStore = useUserStoreWithOut() // 用户信息缓存
271
305
const isDark = computed (() => useAppStore ().getIsDark ) // 是否黑暗模式
272
306
273
307
const isModelSorting = ref (false ) // 是否正处于排序状态
274
- const originalData: any = ref ([]) // 原始数据
275
- const modelList: any = ref ([]) // 模型列表
308
+ const originalData = ref < ModelInfo []> ([]) // 原始数据
309
+ const modelList = ref < ModelInfo []> ([]) // 模型列表
276
310
const isExpand = ref (false ) // 是否处于展开状态
277
311
312
+ // 使用 computed 优化表格样式计算
313
+ const tableHeaderStyle = computed (() => ({
314
+ backgroundColor: isDark .value ? ' ' : ' #edeff0' ,
315
+ paddingLeft: ' 10px'
316
+ }))
317
+
318
+ const tableCellStyle = computed (() => ({
319
+ paddingLeft: ' 10px'
320
+ }))
321
+
322
+ // 使用 computed 优化可见性判断
323
+ const isManagerUser = computed (() => {
324
+ const userId = userStore .getUser ?.id
325
+ return (row : ModelInfo ) => row .managerUserIds ?.includes (userId )
326
+ })
327
+
278
328
/** 权限校验:通过 computed 解决列表的卡顿问题 */
279
329
const hasPermiUpdate = computed (() => {
280
330
return checkPermi ([' bpm:model:update' ])
@@ -449,14 +499,15 @@ const handleModelSortCancel = () => {
449
499
450
500
/** 创建拖拽实例 */
451
501
const tableRef = ref ()
452
- const initSort = () => {
502
+ const initSort = useDebounceFn ( () => {
453
503
const table = document .querySelector (` .${props .categoryInfo .name } .el-table__body-wrapper tbody ` )
504
+ if (! table ) return
505
+
454
506
Sortable .create (table , {
455
507
group: ' shared' ,
456
508
animation: 150 ,
457
509
draggable: ' .el-table__row' ,
458
510
handle: ' .drag-icon' ,
459
- // 结束拖动事件
460
511
onEnd : ({ newDraggableIndex , oldDraggableIndex }) => {
461
512
if (oldDraggableIndex !== newDraggableIndex ) {
462
513
modelList .value .splice (
@@ -467,15 +518,18 @@ const initSort = () => {
467
518
}
468
519
}
469
520
})
470
- }
521
+ }, 200 )
471
522
472
523
/** 更新 modelList 模型列表 */
473
- const updateModeList = () => {
474
- modelList .value = cloneDeep (props .categoryInfo .modelList )
475
- if (props .categoryInfo .modelList .length > 0 ) {
476
- isExpand .value = true
524
+ const updateModeList = useDebounceFn (() => {
525
+ const newModelList = props .categoryInfo .modelList
526
+ if (! isEqual (modelList .value , newModelList )) {
527
+ modelList .value = cloneDeep (newModelList )
528
+ if (newModelList ?.length > 0 ) {
529
+ isExpand .value = true
530
+ }
477
531
}
478
- }
532
+ }, 100 )
479
533
480
534
/** 重命名弹窗确定 */
481
535
const renameCategoryVisible = ref (false )
@@ -526,14 +580,15 @@ const openModelForm = async (type: string, id?: number) => {
526
580
}
527
581
}
528
582
529
- watch (() => props .categoryInfo .modelList , updateModeList , { immediate: true })
530
- watch (
531
- () => props .isCategorySorting ,
532
- (val ) => {
533
- if (val ) isExpand .value = false
534
- },
535
- { immediate: true }
536
- )
583
+ watchEffect (() => {
584
+ if (props .categoryInfo ?.modelList ) {
585
+ updateModeList ()
586
+ }
587
+
588
+ if (props .isCategorySorting ) {
589
+ isExpand .value = false
590
+ }
591
+ })
537
592
</script >
538
593
539
594
<style lang="scss">
@@ -550,10 +605,16 @@ watch(
550
605
}
551
606
</style >
552
607
<style lang="scss" scoped>
553
- :deep() {
554
- .el-table__cell {
608
+ .category-draggable-model {
609
+ : deep ( .el-table__cell ) {
555
610
overflow : hidden ;
556
611
border-bottom : none !important ;
557
612
}
613
+
614
+ // 优化表格渲染性能
615
+ :deep(.el-table__body ) {
616
+ will-change : transform ;
617
+ transform : translateZ (0 );
618
+ }
558
619
}
559
620
</style >
0 commit comments