添加动态权限控制

This commit is contained in:
xie7654
2025-07-02 21:54:13 +08:00
parent eace8a524d
commit 78b9f9e832
12 changed files with 186 additions and 24 deletions

View File

@@ -15,6 +15,7 @@ import { initComponentAdapter } from './adapter/component';
import { initSetupVbenForm } from './adapter/form';
import App from './app.vue';
import { router } from './router';
import { registerPermissionDirective } from './utils/permission';
async function bootstrap(namespace: string) {
// 初始化组件适配器
@@ -48,6 +49,8 @@ async function bootstrap(namespace: string) {
// 安装权限指令
registerAccessDirective(app);
// 注册自定义v-permission指令
registerPermissionDirective(app);
// 初始化 tippy
const { initTippy } = await import('@vben/common-ui/es/tippy');

View File

@@ -13,9 +13,12 @@ import { defineStore } from 'pinia';
import { getAccessCodesApi, getUserInfoApi, loginApi, logoutApi } from '#/api';
import { $t } from '#/locales';
import { usePermissionStore } from './permission';
export const useAuthStore = defineStore('auth', () => {
const accessStore = useAccessStore();
const userStore = useUserStore();
const permissionStore = usePermissionStore();
const router = useRouter();
const loginLoading = ref(false);
@@ -62,7 +65,7 @@ export const useAuthStore = defineStore('auth', () => {
if (userInfo?.realName) {
notification.success({
description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.realName}`,
description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.username}`,
duration: 3,
message: $t('authentication.loginSuccess'),
});
@@ -101,6 +104,11 @@ export const useAuthStore = defineStore('auth', () => {
let userInfo: null | UserInfo = null;
userInfo = await getUserInfoApi();
userStore.setUserInfo(userInfo);
// 设置权限
if (userInfo && Array.isArray(userInfo.permissions)) {
permissionStore.setPermissions(userInfo.permissions);
}
return userInfo;
}

View File

@@ -0,0 +1,30 @@
import { ref } from 'vue';
import { defineStore } from 'pinia';
export const usePermissionStore = defineStore('permission', () => {
// 权限码列表
const permissions = ref<string[]>([]);
// 设置权限码
function setPermissions(perms: string[]) {
permissions.value = perms || [];
}
// 判断是否有某个权限
function hasPermission(code: string): boolean {
return permissions.value.includes(code);
}
// 重置
function $reset() {
permissions.value = [];
}
return {
permissions,
setPermissions,
hasPermission,
$reset,
};
})

View File

@@ -0,0 +1,48 @@
import type { App, DirectiveBinding } from 'vue';
import { usePermissionStore } from '#/store/permission';
/**
* 权限按钮option生成工具
* @param code 权限码
* @param option 按钮option或字符串
* @returns 有权限返回option无权限返回false
*/
export function op(code: string, option: any) {
const permissionStore = usePermissionStore();
return permissionStore.hasPermission(code) ? option : false;
}
/**
* 全局权限判断函数适用于模板v-if
*/
export function hasPermission(code: string): boolean {
const permissionStore = usePermissionStore();
return permissionStore.hasPermission(code);
}
/**
* v-permission 自定义指令
* 用法v-permission="'system:user:create'"
* 或 v-permission="['system:user:create', 'system:user:update']"
*/
const permissionDirective = {
mounted(el: HTMLElement, binding: DirectiveBinding<string | string[]>) {
const codes = Array.isArray(binding.value)
? binding.value
: [binding.value];
const permissionStore = usePermissionStore();
const has = codes.some((code) => permissionStore.hasPermission(code));
if (!has) {
el.parentNode && el.remove();
}
},
};
/**
* 注册全局权限指令
* @param app Vue App 实例
*/
export function registerPermissionDirective(app: App) {
app.directive('permission', permissionDirective);
}

View File

@@ -8,6 +8,8 @@ import { z } from '#/adapter/form';
import { getDeptList } from '#/api/system/dept';
import { $t } from '#/locales';
import { format_datetime } from '#/utils/date';
import { op } from '#/utils/permission';
/**
* 获取编辑表单的字段配置。如果没有使用多语言可以直接export一个数组常量
*/
@@ -137,18 +139,15 @@ export function useColumns(
},
name: 'CellOperation',
options: [
{
code: 'append',
text: '新增下级',
},
'edit', // 默认的编辑按钮
{
code: 'delete', // 默认的删除按钮
op('system:dept:create', { code: 'append', text: '新增下级' }),
op('system:dept:edit', 'edit'),
op('system:dept:delete', {
code: 'delete',
disabled: (row: SystemDeptApi.SystemDept) => {
return !!(row.children && row.children.length > 0);
},
},
],
}),
].filter(Boolean),
},
field: 'operation',
fixed: 'right',

View File

@@ -133,7 +133,11 @@ function refreshGrid() {
<FormModal @success="refreshGrid" />
<Grid table-title="部门列表">
<template #toolbar-tools>
<Button type="primary" @click="onCreate">
<Button
type="primary"
@click="onCreate"
v-permission="'system:dept:create'"
>
<Plus class="size-5" />
{{ $t('ui.actionTitle.create', [$t('system.dept.name')]) }}
</Button>

View File

@@ -15,7 +15,8 @@ interface UserInfo extends BasicUserInfo {
* accessToken
*/
token: string;
roles: [];
roles?: string[];
permissions?: string[];
}
export type { UserInfo };