feat: 完善权限

This commit is contained in:
chansee97 2025-09-05 00:49:41 +08:00
parent cf41abc5a5
commit f9ef71f0c7
11 changed files with 154 additions and 51 deletions

View File

@ -1,21 +1,57 @@
import type { App, Directive } from 'vue'
import { usePermission } from '@/hooks'
import { useMenuPermission, usePermission, useRolePermission } from '@/hooks'
export function install(app: App) {
const { hasPermission } = usePermission()
const { hasMenuPermission } = useMenuPermission()
const { hasRolePermission } = useRolePermission()
function updatapermission(el: HTMLElement, permission: string | string[]) {
function updatePermission(el: HTMLElement, permission: string | string[]) {
if (!permission)
throw new Error('v-permissson Directive with no explicit role attached')
throw new Error('v-permission Directive with no explicit permission attached')
if (!hasPermission(permission))
el.parentElement?.removeChild(el)
}
function updateMenuPermission(el: HTMLElement, permission: string | string[]) {
if (!permission)
throw new Error('v-menu Directive with no explicit menu permission attached')
if (!hasMenuPermission(permission))
el.parentElement?.removeChild(el)
}
function updateRolePermission(el: HTMLElement, role: string | string[]) {
if (!role)
throw new Error('v-role Directive with no explicit role attached')
if (!hasRolePermission(role))
el.parentElement?.removeChild(el)
}
// 通用权限指令(兼容旧版本)
const permissionDirective: Directive<HTMLElement, string | string[]> = {
mounted(el, binding) {
updatapermission(el, binding.value)
updatePermission(el, binding.value)
},
}
app.directive('permission', permissionDirective)
// 菜单权限指令
const menuPermissionDirective: Directive<HTMLElement, string | string[]> = {
mounted(el, binding) {
updateMenuPermission(el, binding.value)
},
}
// 角色权限指令
const rolePermissionDirective: Directive<HTMLElement, string | string[]> = {
mounted(el, binding) {
updateRolePermission(el, binding.value)
},
}
app.directive('permission', permissionDirective)
app.directive('menu', menuPermissionDirective)
app.directive('role', rolePermissionDirective)
}

View File

@ -1,6 +1,60 @@
import { useAuthStore } from '@/store'
/** 权限判断 */
/** 菜单权限判断 */
export function useMenuPermission() {
const authStore = useAuthStore()
function hasMenuPermission(
permissions?: string | string[],
) {
if (!permissions)
return true
// 确保 permissions 是数组
const permissionArray = Array.isArray(permissions) ? permissions : [permissions]
// 全部权限
if (permissionArray.includes('admin'))
return true
const { permissions: userPermissions } = authStore
return permissionArray.some(i => userPermissions.includes(i))
}
return {
hasMenuPermission,
}
}
/** 角色权限判断 */
export function useRolePermission() {
const authStore = useAuthStore()
function hasRolePermission(
roles?: string | string[],
) {
if (!roles)
return true
// 确保 roles 是数组
const roleArray = Array.isArray(roles) ? roles : [roles]
// 全部权限
if (roleArray.includes('admin'))
return true
const { roles: userRoles } = authStore
return roleArray.some(i => userRoles.includes(i))
}
return {
hasRolePermission,
}
}
/** 合并权限判断 */
export function usePermission() {
const authStore = useAuthStore()
@ -10,16 +64,20 @@ export function usePermission() {
if (!permissions)
return true
// 全部权限
if (permissions === '*:*:*')
return true
const { permissions: userPermissions } = authStore
// 确保 permissions 是数组
const permissionArray = Array.isArray(permissions) ? permissions : [permissions]
return permissionArray.some(i => userPermissions.includes(i))
// 全部权限
if (permissionArray.includes('admin'))
return true
const { permissions: userPermissions, roles: userRoles } = authStore
const hasPermission = permissionArray.some(i => userPermissions.includes(i))
if (hasPermission)
return true
return permissionArray.some(i => userRoles.includes(i))
}
return {

View File

@ -6,12 +6,14 @@ import { useTabStore } from './tab'
interface AuthStatus {
userInfo: Entity.User | Record<string, any>
roles: string[]
permissions: string[]
}
export const useAuthStore = defineStore('auth-store', {
state: (): AuthStatus => {
return {
userInfo: {},
roles: [],
permissions: [],
}
},
@ -71,6 +73,8 @@ export const useAuthStore = defineStore('auth-store', {
async updataUserInfo() {
const { data } = await fetchUserInfo()
this.userInfo = data
this.roles = data.roles.map((role: Entity.Role) => role.roleKey)
this.permissions = data.permissions
},
/* 处理登录返回的数据 */
async handleLoginInfo(data: any) {

View File

@ -33,5 +33,7 @@ namespace Entity {
roles: Entity.Role[]
/** 所属部门 */
dept: Entity.Dept
/** 用户权限, 登陆时返回该字段 */
permissions: string[]
}
}

View File

@ -8,6 +8,9 @@ const settings = ref({
<template>
<div class="space-y-4">
<n-alert type="warning" style="margin-bottom: 16px;">
示例组件实际功能未实现
</n-alert>
<!-- 邮件通知 -->
<n-card title="邮件通知" size="small">
<n-list>

View File

@ -8,12 +8,11 @@ const preferences = ref({
<template>
<div class="space-y-4">
<n-alert type="warning" style="margin-bottom: 16px;">
示例组件实际功能未实现
</n-alert>
<!-- 实验性功能 -->
<n-card title="实验性功能" size="small">
<n-alert type="warning" style="margin-bottom: 16px;">
以下功能仍在测试阶段可能会影响系统稳定性
</n-alert>
<n-list>
<n-list-item>
<n-thing>

View File

@ -86,7 +86,7 @@ onMounted(async () => {
</script>
<template>
<n-card>
<n-card class="max-w-1024px m-auto">
<n-flex :wrap="false" style="height: 100%;">
<!-- 左侧区域 -->
<div class="w-[220px] border-r border-[var(--n-border-color)] flex flex-col">

View File

@ -46,7 +46,7 @@
/>
<pro-input
title="权限标识"
tooltip="页面访问权限标识"
tooltip="后端装饰器一致,如@RequirePermissions('system:user:list')"
path="perms"
placeholder="Eg: system:user:list"
/>

View File

@ -2,7 +2,7 @@
<pro-input
required
title="权限标识"
tooltip="按钮权限唯一标识符"
tooltip="后端装饰器一致,如@RequirePermissions('system:user:add')"
path="perms"
placeholder="Eg: system:user:add"
/>

View File

@ -46,9 +46,6 @@ async function getAllRoutes(params?: MenuSearchQuery) {
parentProperty: 'parentId',
})
}
catch {
window.$message.error('获取菜单列表失败')
}
finally {
endLoading()
}

View File

@ -78,6 +78,7 @@ export function createRoleColumns(actions: RoleColumnActions): DataTableColumns<
width: 100,
render: (row) => {
return (
row.roleKey !== 'admin' && (
<NSwitch
value={row.status}
checked-value={0}
@ -87,6 +88,7 @@ export function createRoleColumns(actions: RoleColumnActions): DataTableColumns<
{{ checked: () => '启用', unchecked: () => '禁用' }}
</NSwitch>
)
)
},
},
{
@ -102,6 +104,7 @@ export function createRoleColumns(actions: RoleColumnActions): DataTableColumns<
width: 200,
render: (row) => {
return (
row.roleKey !== 'admin' && (
<NSpace justify="center">
<NButton
text
@ -124,6 +127,7 @@ export function createRoleColumns(actions: RoleColumnActions): DataTableColumns<
</NPopconfirm>
</NSpace>
)
)
},
},
]