PermissionTreeNode.vue 2.9 KB
<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
  return props.permission.children!.some(c => 
    props.selectedPermissions.includes(c.id)
  )
})
</script>

<style scoped>
/* 组件特定样式 */
</style>