mirror of
https://github.com/chansee97/nova-admin.git
synced 2025-09-17 19:29:58 +08:00
feat: 完善权限
This commit is contained in:
parent
cf41abc5a5
commit
f9ef71f0c7
@ -1,21 +1,57 @@
|
|||||||
import type { App, Directive } from 'vue'
|
import type { App, Directive } from 'vue'
|
||||||
import { usePermission } from '@/hooks'
|
import { useMenuPermission, usePermission, useRolePermission } from '@/hooks'
|
||||||
|
|
||||||
export function install(app: App) {
|
export function install(app: App) {
|
||||||
const { hasPermission } = usePermission()
|
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)
|
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))
|
if (!hasPermission(permission))
|
||||||
el.parentElement?.removeChild(el)
|
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[]> = {
|
const permissionDirective: Directive<HTMLElement, string | string[]> = {
|
||||||
mounted(el, binding) {
|
mounted(el, binding) {
|
||||||
updatapermission(el, binding.value)
|
updatePermission(el, binding.value)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 菜单权限指令
|
||||||
|
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('permission', permissionDirective)
|
||||||
|
app.directive('menu', menuPermissionDirective)
|
||||||
|
app.directive('role', rolePermissionDirective)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,60 @@
|
|||||||
import { useAuthStore } from '@/store'
|
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() {
|
export function usePermission() {
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
|
|
||||||
@ -10,16 +64,20 @@ export function usePermission() {
|
|||||||
if (!permissions)
|
if (!permissions)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
// 全部权限
|
|
||||||
if (permissions === '*:*:*')
|
|
||||||
return true
|
|
||||||
|
|
||||||
const { permissions: userPermissions } = authStore
|
|
||||||
|
|
||||||
// 确保 permissions 是数组
|
// 确保 permissions 是数组
|
||||||
const permissionArray = Array.isArray(permissions) ? permissions : [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 {
|
return {
|
||||||
|
@ -6,12 +6,14 @@ import { useTabStore } from './tab'
|
|||||||
|
|
||||||
interface AuthStatus {
|
interface AuthStatus {
|
||||||
userInfo: Entity.User | Record<string, any>
|
userInfo: Entity.User | Record<string, any>
|
||||||
|
roles: string[]
|
||||||
permissions: string[]
|
permissions: string[]
|
||||||
}
|
}
|
||||||
export const useAuthStore = defineStore('auth-store', {
|
export const useAuthStore = defineStore('auth-store', {
|
||||||
state: (): AuthStatus => {
|
state: (): AuthStatus => {
|
||||||
return {
|
return {
|
||||||
userInfo: {},
|
userInfo: {},
|
||||||
|
roles: [],
|
||||||
permissions: [],
|
permissions: [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -71,6 +73,8 @@ export const useAuthStore = defineStore('auth-store', {
|
|||||||
async updataUserInfo() {
|
async updataUserInfo() {
|
||||||
const { data } = await fetchUserInfo()
|
const { data } = await fetchUserInfo()
|
||||||
this.userInfo = data
|
this.userInfo = data
|
||||||
|
this.roles = data.roles.map((role: Entity.Role) => role.roleKey)
|
||||||
|
this.permissions = data.permissions
|
||||||
},
|
},
|
||||||
/* 处理登录返回的数据 */
|
/* 处理登录返回的数据 */
|
||||||
async handleLoginInfo(data: any) {
|
async handleLoginInfo(data: any) {
|
||||||
|
2
src/typings/entities/user.d.ts
vendored
2
src/typings/entities/user.d.ts
vendored
@ -33,5 +33,7 @@ namespace Entity {
|
|||||||
roles: Entity.Role[]
|
roles: Entity.Role[]
|
||||||
/** 所属部门 */
|
/** 所属部门 */
|
||||||
dept: Entity.Dept
|
dept: Entity.Dept
|
||||||
|
/** 用户权限, 登陆时返回该字段 */
|
||||||
|
permissions: string[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,9 @@ const settings = ref({
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
|
<n-alert type="warning" style="margin-bottom: 16px;">
|
||||||
|
示例组件,实际功能未实现
|
||||||
|
</n-alert>
|
||||||
<!-- 邮件通知 -->
|
<!-- 邮件通知 -->
|
||||||
<n-card title="邮件通知" size="small">
|
<n-card title="邮件通知" size="small">
|
||||||
<n-list>
|
<n-list>
|
||||||
|
@ -8,12 +8,11 @@ const preferences = ref({
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
|
<n-alert type="warning" style="margin-bottom: 16px;">
|
||||||
|
示例组件,实际功能未实现
|
||||||
|
</n-alert>
|
||||||
<!-- 实验性功能 -->
|
<!-- 实验性功能 -->
|
||||||
<n-card title="实验性功能" size="small">
|
<n-card title="实验性功能" size="small">
|
||||||
<n-alert type="warning" style="margin-bottom: 16px;">
|
|
||||||
以下功能仍在测试阶段,可能会影响系统稳定性
|
|
||||||
</n-alert>
|
|
||||||
|
|
||||||
<n-list>
|
<n-list>
|
||||||
<n-list-item>
|
<n-list-item>
|
||||||
<n-thing>
|
<n-thing>
|
||||||
|
@ -86,7 +86,7 @@ onMounted(async () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<n-card>
|
<n-card class="max-w-1024px m-auto">
|
||||||
<n-flex :wrap="false" style="height: 100%;">
|
<n-flex :wrap="false" style="height: 100%;">
|
||||||
<!-- 左侧区域 -->
|
<!-- 左侧区域 -->
|
||||||
<div class="w-[220px] border-r border-[var(--n-border-color)] flex flex-col">
|
<div class="w-[220px] border-r border-[var(--n-border-color)] flex flex-col">
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
/>
|
/>
|
||||||
<pro-input
|
<pro-input
|
||||||
title="权限标识"
|
title="权限标识"
|
||||||
tooltip="页面访问权限标识"
|
tooltip="后端装饰器一致,如@RequirePermissions('system:user:list')"
|
||||||
path="perms"
|
path="perms"
|
||||||
placeholder="Eg: system:user:list"
|
placeholder="Eg: system:user:list"
|
||||||
/>
|
/>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<pro-input
|
<pro-input
|
||||||
required
|
required
|
||||||
title="权限标识"
|
title="权限标识"
|
||||||
tooltip="按钮权限唯一标识符"
|
tooltip="后端装饰器一致,如@RequirePermissions('system:user:add')"
|
||||||
path="perms"
|
path="perms"
|
||||||
placeholder="Eg: system:user:add"
|
placeholder="Eg: system:user:add"
|
||||||
/>
|
/>
|
||||||
|
@ -46,9 +46,6 @@ async function getAllRoutes(params?: MenuSearchQuery) {
|
|||||||
parentProperty: 'parentId',
|
parentProperty: 'parentId',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
catch {
|
|
||||||
window.$message.error('获取菜单列表失败')
|
|
||||||
}
|
|
||||||
finally {
|
finally {
|
||||||
endLoading()
|
endLoading()
|
||||||
}
|
}
|
||||||
|
@ -78,14 +78,16 @@ export function createRoleColumns(actions: RoleColumnActions): DataTableColumns<
|
|||||||
width: 100,
|
width: 100,
|
||||||
render: (row) => {
|
render: (row) => {
|
||||||
return (
|
return (
|
||||||
<NSwitch
|
row.roleKey !== 'admin' && (
|
||||||
value={row.status}
|
<NSwitch
|
||||||
checked-value={0}
|
value={row.status}
|
||||||
unchecked-value={1}
|
checked-value={0}
|
||||||
onUpdateValue={(value: 0 | 1) => actions.onStatusChange(row.id, value)}
|
unchecked-value={1}
|
||||||
>
|
onUpdateValue={(value: 0 | 1) => actions.onStatusChange(row.id, value)}
|
||||||
{{ checked: () => '启用', unchecked: () => '禁用' }}
|
>
|
||||||
</NSwitch>
|
{{ checked: () => '启用', unchecked: () => '禁用' }}
|
||||||
|
</NSwitch>
|
||||||
|
)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -102,27 +104,29 @@ export function createRoleColumns(actions: RoleColumnActions): DataTableColumns<
|
|||||||
width: 200,
|
width: 200,
|
||||||
render: (row) => {
|
render: (row) => {
|
||||||
return (
|
return (
|
||||||
<NSpace justify="center">
|
row.roleKey !== 'admin' && (
|
||||||
<NButton
|
<NSpace justify="center">
|
||||||
text
|
<NButton
|
||||||
type="primary"
|
text
|
||||||
onClick={() => actions.onEdit(row)}
|
type="primary"
|
||||||
>
|
onClick={() => actions.onEdit(row)}
|
||||||
编辑
|
>
|
||||||
</NButton>
|
编辑
|
||||||
<NPopconfirm
|
</NButton>
|
||||||
onPositiveClick={() => actions.onDelete(row.id)}
|
<NPopconfirm
|
||||||
>
|
onPositiveClick={() => actions.onDelete(row.id)}
|
||||||
{{
|
>
|
||||||
default: () => '确认删除该角色?',
|
{{
|
||||||
trigger: () => (
|
default: () => '确认删除该角色?',
|
||||||
<NButton text type="error">
|
trigger: () => (
|
||||||
删除
|
<NButton text type="error">
|
||||||
</NButton>
|
删除
|
||||||
),
|
</NButton>
|
||||||
}}
|
),
|
||||||
</NPopconfirm>
|
}}
|
||||||
</NSpace>
|
</NPopconfirm>
|
||||||
|
</NSpace>
|
||||||
|
)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user