admin后台权限使用设计

91 阅读2分钟

1、hook函数

1.1、hasPermission 函数 api

参数字段类型说明
valuestring | string[]权限字符串,支持数组
andboolean权限字符串多个情况下,and 为 true 即都需要满足,默认为 false

1.2、hook 示例

import { computed } from 'vue'
import { usePermission } from '@/hooks/web/usePermission'

const { hasPermission } = usePermission()
const available1 = computed(() => hasPermission('p:bb'))

// 满足其中一个权限即可用
const available2 = computed(() => hasPermission(['p:aa', 'p:bb']))

// 必须满足所有权限项才可用
const available3 = computed(() => hasPermission(['p:aa', 'p:bb'], true))

1.2、hook函数代码

import { intersection } from 'lodash-es'
import { isArray } from '@/utils/is'
import { useUserStoreWithOut } from '@/store/modules/user'

// 全部权限
export const AllPermissions = ['*.*.*']

export function usePermission() {
  const userStore = useUserStoreWithOut()

  const hasPermission = (value: string | string[], and = false): boolean => {
    // TODO,前后端联调前 需要将默认值改为[]
    const permissions = userStore.getUserInfo?.authority?.permissions || ['p:aa', 'p:bb']
    if (permissions.length === 0) {
      return false
    }
    if (!value) {
      throw new Error('permission.hasPermission')
    }
    if (!isArray(value)) {
      return permissions.includes(value)
    }
    if (AllPermissions[0] === permissions[0]) {
      return true
    }
    if (and) {
      return !value.some((itemValue) => !permissions.includes(itemValue))
    }
    return (intersection(value, permissions) as string[]).length > 0
  }

  return {
    hasPermission
  }
}

2. 组件

2.1、组件 props

prop类型说明
valuestring | string[]权限字符串,支持数组
andboolean权限字符串多个情况下,and 为 true 即都需要满足,默认为 false
customboolean自定义权限控制逻辑,默认情况为false,没权限,组件及后代元素都不展示;如果设置true,你可以自定义控制组件具体的后代元素的展示逻辑

2.2、组件示例

<Permission value="p:aa">
  <div>permission child text</div>
</Permission>
<Permission :value="['p:aa', 'p:bb']">
  <div>permission child text</div>
</Permission>
<Permission :value="['p:bb', 'p:xx']" :and="true" :custom="true" v-slot="{ hasPermission }">
  <div v-if="hasPermission">权限控制内容</div>
  <ElButton type="primary" :disabled="!hasPermission">操作按钮</ElButton>
  <div>非权限控制内容</div>
</Permission>

2.3、组件代码

<template>
  <slot v-if="custom || hasPerm" :hasPermission="hasPerm" v-bind="attrs"></slot>
</template>

<script setup lang="ts">
import { defineProps, computed, useAttrs } from 'vue'
import { usePermission } from '@/hooks/web/usePermission'

interface IProps {
  value: string | string[]
  and?: boolean
  custom?: boolean
}

const attrs = useAttrs()
const { hasPermission } = usePermission()
const props = withDefaults(defineProps<IProps>(), {
  and: false,
  custom: false
})

const hasPerm = computed(() => hasPermission(props.value, props.and))
</script>

3. 指令

3.1、示例

<div v-hasPermission="permissionValue">指令使用</div>
<div v-hasPermission="permissionValue2">不带修饰符and 指令使用</div>
<div v-hasPermission.and="permissionValue2">带修饰符and 指令使用</div>
import { ref } from 'vue'
const permissionValue = ref<string | string[]>('p:aa')
const permissionValue2 = ref<string | string[]>(['p:aa', 'p:xx'])

3.1、指令代码实现

import type { App, Directive, DirectiveBinding } from 'vue'
import { usePermission } from '@/hooks/web/usePermission'

const permissionDirective: Directive = {
  mounted(el: Element, binding: DirectiveBinding<any>) {
    const { hasPermission } = usePermission()
    const value = binding.value

    const flag = hasPermission(value, binding.modifiers.and)
    if (!flag) {
      el.parentNode?.removeChild(el)
    }
  }
}

export const setupPermissionDirective = (app: App<Element>) => {
  app.directive('hasPermission', permissionDirective)
}

export default permissionDirective