feat: ✨ 添加自定义权限指令,工作台模块添加权限控制
This commit is contained in:
@@ -153,10 +153,10 @@ export interface UserInfo {
|
||||
avatar?: string;
|
||||
|
||||
/** 角色 */
|
||||
roles: string[];
|
||||
roles?: string[];
|
||||
|
||||
/** 权限 */
|
||||
perms: string[];
|
||||
perms?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
10
src/directive/index.ts
Normal file
10
src/directive/index.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import type { App } from "vue";
|
||||
|
||||
import { hasPerm, hasRole } from "./permission";
|
||||
|
||||
// 全局注册 directive
|
||||
export function setupDirective(app: App<Element>) {
|
||||
// 使 v-hasPerm 在所有组件中都可用
|
||||
app.directive("hasPerm", hasPerm);
|
||||
app.directive("hasRole", hasRole);
|
||||
}
|
||||
69
src/directive/permission/index.ts
Normal file
69
src/directive/permission/index.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import type { Directive, DirectiveBinding } from "vue";
|
||||
|
||||
import { useUserStore } from "@/store";
|
||||
|
||||
/**
|
||||
* 按钮权限
|
||||
*/
|
||||
export const hasPerm: Directive = {
|
||||
mounted(el: HTMLElement, binding: DirectiveBinding) {
|
||||
const requiredPerms = binding.value;
|
||||
|
||||
console.log("requiredPerms", requiredPerms);
|
||||
if (!requiredPerms) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 校验传入的权限值是否合法
|
||||
if (!requiredPerms || (typeof requiredPerms !== "string" && !Array.isArray(requiredPerms))) {
|
||||
throw new Error(
|
||||
"需要提供权限标识!例如:v-has-perm=\"'sys:user:add'\" 或 v-has-perm=\"['sys:user:add', 'sys:user:edit']\""
|
||||
);
|
||||
}
|
||||
|
||||
const { roles = [], perms = [] } = useUserStore().userInfo || {};
|
||||
|
||||
// 超级管理员拥有所有权限
|
||||
if (roles?.includes("ROOT")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查权限
|
||||
const hasAuth = Array.isArray(requiredPerms)
|
||||
? requiredPerms.some((perm) => perms.includes(perm))
|
||||
: perms.includes(requiredPerms);
|
||||
|
||||
// 如果没有权限,移除该元素
|
||||
if (!hasAuth && el.parentNode) {
|
||||
el.parentNode.removeChild(el);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 角色权限指令
|
||||
*/
|
||||
export const hasRole: Directive = {
|
||||
mounted(el: HTMLElement, binding: DirectiveBinding) {
|
||||
const requiredRoles = binding.value;
|
||||
|
||||
// 校验传入的角色值是否合法
|
||||
if (!requiredRoles || (typeof requiredRoles !== "string" && !Array.isArray(requiredRoles))) {
|
||||
throw new Error(
|
||||
"需要提供角色标识!例如:v-has-role=\"'ADMIN'\" 或 v-has-role=\"['ADMIN', 'TEST']\""
|
||||
);
|
||||
}
|
||||
|
||||
const { roles = [] } = useUserStore().userInfo || {};
|
||||
|
||||
// 检查是否有对应角色权限
|
||||
const hasAuth = Array.isArray(requiredRoles)
|
||||
? requiredRoles.some((role) => roles.includes(role))
|
||||
: roles.includes(requiredRoles);
|
||||
|
||||
// 如果没有权限,移除元素
|
||||
if (!hasAuth && el.parentNode) {
|
||||
el.parentNode.removeChild(el);
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -1,5 +1,7 @@
|
||||
import { createSSRApp } from "vue";
|
||||
import App from "./App.vue";
|
||||
import setupPlugins from "@/plugins";
|
||||
|
||||
import "uno.css";
|
||||
|
||||
import { setupStore } from "@/store";
|
||||
@@ -8,7 +10,7 @@ export function createApp() {
|
||||
const app = createSSRApp(App);
|
||||
|
||||
setupStore(app);
|
||||
|
||||
app.use(setupPlugins);
|
||||
return {
|
||||
app,
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<wd-grid-item
|
||||
v-for="(child, index) in item.children"
|
||||
:key="index"
|
||||
v-has-perm="child.prem"
|
||||
use-slot
|
||||
link-type="navigateTo"
|
||||
:url="child.url"
|
||||
@@ -30,36 +31,34 @@ const gridList = reactive([
|
||||
icon: "/static/icons/user.png",
|
||||
title: "用户管理",
|
||||
url: "/pages/work/user/index",
|
||||
prem: "sys:user:query",
|
||||
},
|
||||
|
||||
{
|
||||
icon: "/static/icons/role.png",
|
||||
title: "角色管理",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/menu.png",
|
||||
title: "菜单管理",
|
||||
prem: "sys:role:query",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/dept.png",
|
||||
title: "部门管理",
|
||||
prem: "sys:dept:query",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/dict.png",
|
||||
title: "字典管理",
|
||||
prem: "sys:dict:query",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/config.png",
|
||||
title: "系统配置",
|
||||
url: "/pages/work/system/config/config",
|
||||
url: "/pages/work/config",
|
||||
prem: "sys:config:query",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/notice.png",
|
||||
title: "通知公告",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/more.png",
|
||||
title: "更多模块",
|
||||
prem: "sys:notice:query",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -74,15 +73,12 @@ const gridList = reactive([
|
||||
icon: "/static/icons/log.png",
|
||||
title: "日志管理",
|
||||
url: "/pages/work/log/index",
|
||||
prem: "sys:log:query",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/performance.png",
|
||||
title: "性能监控",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/more.png",
|
||||
title: "更多模块",
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
9
src/plugins/index.ts
Normal file
9
src/plugins/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import type { App } from "vue";
|
||||
|
||||
import { setupDirective } from "@/directive";
|
||||
export default {
|
||||
install(app: App<Element>) {
|
||||
// 自定义指令(directive)
|
||||
setupDirective(app);
|
||||
},
|
||||
};
|
||||
@@ -4,7 +4,7 @@ import UserAPI, { type UserInfo } from "@/api/system/user";
|
||||
import { setToken, getUserInfo, setUserInfo, clearAll } from "@/utils/cache";
|
||||
|
||||
export const useUserStore = defineStore("user", () => {
|
||||
const userInfo = ref<UserInfo | null>(getUserInfo());
|
||||
const userInfo = ref<UserInfo | undefined>(getUserInfo());
|
||||
|
||||
// 登录
|
||||
const login = (data: LoginFormData) => {
|
||||
@@ -45,7 +45,7 @@ export const useUserStore = defineStore("user", () => {
|
||||
console.error("登出失败", error);
|
||||
} finally {
|
||||
clearAll(); // 清除本地的 token 和用户信息缓存
|
||||
userInfo.value = null; // 清空用户信息
|
||||
userInfo.value = undefined; // 清空用户信息
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user