sparkles: 引入菜单权限控制
This commit is contained in:
parent
566da2e791
commit
ee0525e62b
100
src/api/auth/api.d.ts
vendored
100
src/api/auth/api.d.ts
vendored
@ -1,71 +1,71 @@
|
|||||||
declare namespace auth {
|
declare namespace auth {
|
||||||
/**
|
/**
|
||||||
* AuthUser
|
* AuthUser
|
||||||
*/
|
*/
|
||||||
export interface AuthUser {
|
export interface AuthUser {
|
||||||
/** anonymous */
|
/** anonymous */
|
||||||
anonymous?: boolean;
|
anonymous?: boolean
|
||||||
|
|
||||||
/** 用户头像 */
|
/** 用户头像 */
|
||||||
avatar?: string;
|
avatar?: string
|
||||||
|
|
||||||
/** 邮箱 */
|
/** 邮箱 */
|
||||||
email?: string;
|
email?: string
|
||||||
|
|
||||||
/** extInfo */
|
/** extInfo */
|
||||||
extInfo?: auth.NutMap;
|
extInfo?: auth.NutMap
|
||||||
|
|
||||||
/** 姓名 */
|
/** 姓名 */
|
||||||
fullName: string;
|
fullName: string
|
||||||
|
|
||||||
/** 电话 */
|
/** 电话 */
|
||||||
mobile?: string;
|
mobile?: string
|
||||||
|
|
||||||
/** 密码 */
|
/** 密码 */
|
||||||
password: string;
|
password: string
|
||||||
|
|
||||||
/** 权限列表 */
|
/** 权限列表 */
|
||||||
permissions: Array<string>;
|
permissions: Array<string>
|
||||||
|
|
||||||
/** jwt refreshToken */
|
/** jwt refreshToken */
|
||||||
refreshToken: string;
|
refreshToken: string
|
||||||
|
|
||||||
/** 角色列表 */
|
/** 角色列表 */
|
||||||
roles: Array<string>;
|
roles: Array<string>
|
||||||
|
|
||||||
/** 性别 */
|
/** 性别 */
|
||||||
sex?: 'MALE' | 'FEMALE';
|
sex?: 'MALE' | 'FEMALE'
|
||||||
|
|
||||||
/** sexInfo */
|
/** sexInfo */
|
||||||
sexInfo?: auth.Codebook;
|
sexInfo?: auth.Codebook
|
||||||
|
|
||||||
/** jwt Token */
|
/** jwt Token */
|
||||||
token: string;
|
token: string
|
||||||
|
|
||||||
/** 用户名 */
|
/** 用户名 */
|
||||||
userName: string;
|
userName: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录实体
|
* 登录实体
|
||||||
*/
|
*/
|
||||||
export interface LoginDTO {
|
export interface LoginDTO {
|
||||||
/** 验证码 */
|
/** 验证码 */
|
||||||
captcha?: string;
|
captcha?: string
|
||||||
|
|
||||||
/** 手机号 */
|
/** 手机号 */
|
||||||
mobile?: string;
|
mobile?: string
|
||||||
|
|
||||||
/** 密码 */
|
/** 密码 */
|
||||||
password?: string;
|
password?: string
|
||||||
|
|
||||||
/** 登录类型 */
|
/** 登录类型 */
|
||||||
type: 'ACCOUNT' | 'WECHAT';
|
type: 'ACCOUNT' | 'WECHAT'
|
||||||
|
|
||||||
/** 用户名 */
|
/** 用户名 */
|
||||||
userName?: string;
|
userName?: string
|
||||||
|
|
||||||
/** uuid */
|
/** uuid */
|
||||||
uuid?: string;
|
uuid?: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import { RouteRecordRaw } from 'vue-router'
|
|||||||
import XEUtils from 'xe-utils'
|
import XEUtils from 'xe-utils'
|
||||||
import i18n from '@/locales'
|
import i18n from '@/locales'
|
||||||
import { routes } from '@/router'
|
import { routes } from '@/router'
|
||||||
|
import { useUserStore } from '@/stores/user'
|
||||||
const { t } = i18n.global
|
const { t } = i18n.global
|
||||||
export interface MenuNode {
|
export interface MenuNode {
|
||||||
key: string
|
key: string
|
||||||
@ -73,8 +74,8 @@ export function menuTree() {
|
|||||||
|
|
||||||
export function hasPermission(key?: string) {
|
export function hasPermission(key?: string) {
|
||||||
console.log(key)
|
console.log(key)
|
||||||
// return useUserStore().hasPermission(key);
|
return useUserStore().hasPermission(key) // 过滤菜单是否显示
|
||||||
return true
|
// return true
|
||||||
}
|
}
|
||||||
|
|
||||||
export function permissions() {
|
export function permissions() {
|
||||||
@ -91,6 +92,7 @@ export function fliteredMenus() {
|
|||||||
return !item.hidden
|
return !item.hidden
|
||||||
})
|
})
|
||||||
.filter((item) => {
|
.filter((item) => {
|
||||||
|
if (item.name === 'dashboard') return true // 首页显示
|
||||||
return hasPermission(item.keyPath)
|
return hasPermission(item.keyPath)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"index": "首页",
|
"index": "首页",
|
||||||
|
"dashboard": "仪表盘",
|
||||||
"acl": {
|
"acl": {
|
||||||
"name": "系统管理",
|
"name": "系统管理",
|
||||||
"users": "用户管理",
|
"users": "用户管理",
|
||||||
|
@ -4,6 +4,12 @@ import AdminLayout from '@/layout/admin-layout.vue'
|
|||||||
import BlankLayout from '@/layout/blank-layout.vue'
|
import BlankLayout from '@/layout/blank-layout.vue'
|
||||||
|
|
||||||
export const routes: Array<RouteRecordRaw> = [
|
export const routes: Array<RouteRecordRaw> = [
|
||||||
|
{
|
||||||
|
path: '/admin/dashboard',
|
||||||
|
meta: { title: 'menus.dashboard', icon: 'icon-dashboard', flat: true },
|
||||||
|
name: 'Dashboard',
|
||||||
|
component: () => import('../views/admin/dashboard-page.vue'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/admin/acl', // 系统管理
|
path: '/admin/acl', // 系统管理
|
||||||
name: 'ACL',
|
name: 'ACL',
|
||||||
@ -99,48 +105,93 @@ export const routes: Array<RouteRecordRaw> = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const getNewRouter = () => {
|
export default createRouter({
|
||||||
// TODO 用户store判断是否登录,登录就返回过滤的,没有登录就返回全量
|
history: createWebHashHistory(),
|
||||||
return createRouter({
|
routes: [
|
||||||
history: createWebHashHistory(),
|
{
|
||||||
routes: [
|
path: '/',
|
||||||
{
|
name: 'Index',
|
||||||
path: '/',
|
redirect: '/login',
|
||||||
name: 'Index',
|
},
|
||||||
redirect: '/login',
|
{
|
||||||
},
|
path: '/login',
|
||||||
{
|
name: 'Login',
|
||||||
path: '/login',
|
redirect: '/login/user',
|
||||||
name: 'Login',
|
component: UserLayout,
|
||||||
redirect: '/login/user',
|
children: [
|
||||||
component: UserLayout,
|
{
|
||||||
children: [
|
path: 'user',
|
||||||
{
|
name: 'LoginPage',
|
||||||
path: 'user',
|
component: () => import('../views/login/user-login.vue'),
|
||||||
name: 'LoginPage',
|
},
|
||||||
component: () => import('../views/login/user-login.vue'),
|
],
|
||||||
},
|
},
|
||||||
],
|
{
|
||||||
},
|
path: '/admin',
|
||||||
{
|
name: 'Admin',
|
||||||
path: '/admin',
|
redirect: '/admin/dashboard',
|
||||||
name: 'Admin',
|
component: AdminLayout,
|
||||||
redirect: '/admin/dashboard',
|
meta: { title: 'menus.index', icon: 'icon-home' },
|
||||||
component: AdminLayout,
|
children: routes,
|
||||||
meta: { title: 'menus.index', icon: 'icon-home' },
|
},
|
||||||
children: routes,
|
{
|
||||||
},
|
path: '/:catchAll(.*)',
|
||||||
{
|
redirect: '/message',
|
||||||
path: '/:catchAll(.*)',
|
},
|
||||||
redirect: '/message',
|
{
|
||||||
},
|
path: '/message',
|
||||||
{
|
name: 'Message',
|
||||||
path: '/message',
|
component: () => import('@/views/message/message-page.vue'),
|
||||||
name: 'Message',
|
},
|
||||||
component: () => import('@/views/message/message-page.vue'),
|
],
|
||||||
},
|
})
|
||||||
],
|
|
||||||
})
|
export const getP = (permissions: Array<string>): RouteRecordRaw => {
|
||||||
|
const newRoutes: RouteRecordRaw[] = filterRoutesByPermission(routes, permissions)
|
||||||
|
return {
|
||||||
|
path: '/admin',
|
||||||
|
name: 'Admin',
|
||||||
|
redirect: '/admin/dashboard',
|
||||||
|
component: AdminLayout,
|
||||||
|
meta: { title: 'menus.index', icon: 'icon-home' },
|
||||||
|
children: newRoutes,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default getNewRouter()
|
// 过滤路由,最多两层
|
||||||
|
const filterRoutesByPermission = (routes: RouteRecordRaw[], permissions: string[]): RouteRecordRaw[] => {
|
||||||
|
return routes
|
||||||
|
.map((route) => {
|
||||||
|
// 确保 route.name 是字符串
|
||||||
|
const parentName = typeof route.name === 'string' ? route.name : undefined
|
||||||
|
if ('Dashboard' === parentName) return route // 首页不做权限过滤
|
||||||
|
|
||||||
|
const hasParentPermission = parentName && permissions.includes(parentName)
|
||||||
|
|
||||||
|
// 如果有子路由,过滤子路由
|
||||||
|
if (Array.isArray(route.children) && route.children.length > 0) {
|
||||||
|
route.children = route.children.filter((child) => {
|
||||||
|
// 确保 child.name 是字符串
|
||||||
|
const childName = typeof child.name === 'string' ? child.name : undefined
|
||||||
|
|
||||||
|
// 拼接父级和子级的权限字符串
|
||||||
|
const fullName = parentName && childName ? `${parentName}.${childName}` : childName
|
||||||
|
|
||||||
|
// 确保 fullName 是字符串并且存在于 permissions 中
|
||||||
|
return typeof fullName === 'string' && permissions.includes(fullName)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 如果子路由中有任何一个有权限,或者父级路由本身有权限,则保留该父级路由
|
||||||
|
if (route.children.length > 0 || hasParentPermission) {
|
||||||
|
return route
|
||||||
|
}
|
||||||
|
} else if (hasParentPermission) {
|
||||||
|
// 如果没有子路由,直接检查父级路由的权限
|
||||||
|
return route
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果不符合任何条件,返回 undefined,表示该路由将被过滤掉
|
||||||
|
return undefined
|
||||||
|
})
|
||||||
|
.filter((route): route is RouteRecordRaw => route !== undefined) // 过滤掉 undefined 的项并确保类型正确
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import router from '@/router'
|
import router, { getP } from '@/router'
|
||||||
|
|
||||||
export const useUserStore = defineStore('user', {
|
export const useUserStore = defineStore('user', {
|
||||||
state: (): auth.AuthUser => ({
|
state: (): auth.AuthUser => ({
|
||||||
@ -31,10 +31,13 @@ export const useUserStore = defineStore('user', {
|
|||||||
},
|
},
|
||||||
userLogin(user: auth.AuthUser) {
|
userLogin(user: auth.AuthUser) {
|
||||||
Object.assign(this, user)
|
Object.assign(this, user)
|
||||||
// 过了路由的地址
|
// 根据权限动态添加地址
|
||||||
// router.addRoute
|
if (!this.isAdmin) {
|
||||||
|
const path = getP(this.permissions)
|
||||||
router.push({ path: '/admin/acl/users' }) // 登录后跳转到用户列表页面
|
router.addRoute(path)
|
||||||
|
// router.replace(router.currentRoute.value.fullPath)
|
||||||
|
}
|
||||||
|
router.push({ path: '/admin/dashboard' })
|
||||||
},
|
},
|
||||||
logout() {
|
logout() {
|
||||||
this.mobile = ''
|
this.mobile = ''
|
||||||
@ -47,7 +50,11 @@ export const useUserStore = defineStore('user', {
|
|||||||
this.sex = 'FEMALE'
|
this.sex = 'FEMALE'
|
||||||
this.token = ''
|
this.token = ''
|
||||||
this.refreshToken = ''
|
this.refreshToken = ''
|
||||||
router.push({ path: '/login/user' }) // 退出登录后跳转到登录页面,未实现,要清理缓存?
|
router.push({ path: '/login/user' })
|
||||||
|
},
|
||||||
|
hasPermission(permission?: string) {
|
||||||
|
if (this.isAdmin) return true
|
||||||
|
return permission !== undefined && this.permissions.includes(permission)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
persist: {
|
persist: {
|
||||||
|
4
src/views/admin/dashboard-page.vue
Normal file
4
src/views/admin/dashboard-page.vue
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<template>
|
||||||
|
<p>这是首页,欢迎使用库管系统!!</p>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts"></script>
|
Loading…
x
Reference in New Issue
Block a user