PermissionTreeNode.vue
3.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
<template>
<div class="space-y-1">
<div
:class="`permission-tree-node flex items-center gap-2 p-2 rounded ${level > 0 ? 'ml-6' : ''}`">
<!-- 展开/收起按钮 -->
<button
v-if="hasChildren"
@click="$emit('toggleExpand', permission.id)"
class="p-1 hover:bg-neutral-200 rounded flex items-center justify-center w-6 h-6"
>
<el-icon class="text-neutral-600">
<ArrowDown v-if="isExpanded" />
<ArrowRight v-else />
</el-icon>
</button>
<div v-else class="w-6" />
<!-- 复选框 -->
<el-checkbox
:model-value="isSelected"
@change="$emit('togglePermission', permission.id)"
:indeterminate="isIndeterminate"
/>
<!-- 权限信息 -->
<div class="flex-1">
<div class="flex items-center gap-2">
<span class="text-neutral-900">{{ permission.name }}</span>
<!-- <el-tag
type="info"
effect="plain"
size="small"
class="text-xs"
>
{{ permission.code }}
</el-tag> -->
</div>
<!-- <p v-if="permission.description" class="text-xs text-neutral-500 mt-1">
{{ permission.description }}
</p> -->
</div>
</div>
<!-- 子权限 -->
<div v-if="hasChildren && isExpanded" class="ml-4 border-l-2 border-neutral-200">
<PermissionTreeNode
v-for="child in permission.children"
:key="child.id"
:permission="child"
:selected-permissions="selectedPermissions"
:expanded-permissions="expandedPermissions"
:level="level + 1"
@toggle-permission="$emit('togglePermission', $event)"
@toggle-expand="$emit('toggleExpand', $event)"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { ArrowDown, ArrowRight } from '@element-plus/icons-vue'
// 类型定义
interface Permission {
id: string
name: string
code: string
description?: string
parentId?: string
children?: Permission[]
}
// Props
interface Props {
permission: Permission
selectedPermissions: string[]
expandedPermissions: Set<string>
level: number
}
const props = defineProps<Props>()
// Emits
defineEmits<{
togglePermission: [permissionId: string]
toggleExpand: [permissionId: string]
}>()
// 计算属性
const hasChildren = computed(() =>
props.permission.children && props.permission.children.length > 0
)
const isExpanded = computed(() =>
props.expandedPermissions.has(props.permission.id)
)
const isSelected = computed(() =>
props.selectedPermissions.includes(props.permission.id)
)
const isIndeterminate = computed(() => {
if (isSelected.value || !hasChildren.value) return false
// 获取所有子权限ID
const getAllChildIds = (children: Permission[]): string[] => {
const ids: string[] = []
for (const child of children) {
ids.push(child.id)
if (child.children) {
ids.push(...getAllChildIds(child.children))
}
}
return ids
}
const allChildIds = getAllChildIds(props.permission.children!)
if (allChildIds.length === 0) return false
// 检查是否所有子权限都被选中
const allSelected = allChildIds.every(id => props.selectedPermissions.includes(id))
if (allSelected) return false
// 检查是否有部分子权限被选中
const someSelected = allChildIds.some(id => props.selectedPermissions.includes(id))
return someSelected
})
</script>
<style scoped>
/* 组件特定样式 */
</style>