解決 vue3 + vite + ts + pinia 權(quán)限問題方案

關(guān)于 vue3 + vite + ts + pinia 解決權(quán)限問題方案

1.目標(biāo)

使用 pinia 保存服務(wù)器返回的權(quán)限列表生成路由列表數(shù)據(jù)和左側(cè)導(dǎo)航列表數(shù)據(jù)

2.問題描述

在使用?vue3 + pinia 實現(xiàn)此功能時产场,遇到了很多坑伯复,如:

1.登錄后獲取權(quán)限添加到路由帖鸦,但還未添加好路由時實際上已經(jīng)出發(fā)了 next()漆弄,就跳轉(zhuǎn)到 404 頁面?

2.在 router.ts 中使用 pinia,pinia 報錯噪漾,后面查了才知道是路由初始化時 pinia 還未完成初始化??

3.路由請求成功并保存在本地后刷新頁面 頁面路由丟失然后就 404,是因為刷新后路由不會保存,需要重新拿到本地保存的權(quán)限列表添加到路由然后再next() ,但此處不能直接 next(),如果直接next()凄杯,還是會執(zhí)行到 404,因為當(dāng)你刷新時進入到404秉宿,此時的 to.path 就是 404戒突,就算你添加了路由,

next()還是會進入 404描睦,所以就需要保存除404以外最后一次跳轉(zhuǎn)的路徑膊存,即代碼中的?next({ path: menuStore.currentPath })

4.登錄后如果權(quán)限成功設(shè)置,如果此時我們退出登錄并且不刷新頁面忱叭,那么路由就會保存在本地隔崎,當(dāng)我們換一個權(quán)限不同的用戶登錄時,路由里面則會添加個用戶的權(quán)限韵丑,就可以通過 url 訪問別人的權(quán)限爵卒,那么我們不可能強制刷新,這樣會影響用戶體驗撵彻,所以只能靜態(tài)刪除權(quán)限技潘,退出時遍歷本地權(quán)限列表,刪除路由中的權(quán)限??router.removeRoute(‘此處是權(quán)限的name’)

以下是我的解決方案

router.ts

import "element-plus/theme-chalk/el-notification.css"

import { ElNotification } from "element-plus"

import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router"

import { useMenuStore } from '@/store/modules/menu'

import {

? ? getAllPremission,

? ? getRouterList

} from "@/utils/tools"

import errorRouter from './modules/error'

const LOGIN_NAME = '/login'

/* 導(dǎo)入路由文件模板 */

export let routerArray: RouteRecordRaw[] = errorRouter

// export let routerArray: RouteRecordRaw[] = getAllPremission()

const routes: Array<RouteRecordRaw> = [

? ? {

? ? ? ? path: '/login',

? ? ? ? name: 'login',

? ? ? ? component: () => import('@/view/login/index.vue')

? ? },

? ? { path: '/', redirect: { name: 'login' } },

? ? ...routerArray,

? ? {

? ? ? ? // 找不到路由重定向到404頁面

? ? ? ? name: "NotFont",

? ? ? ? path: "/:pathMatch(.*)",

? ? ? ? redirect: { name: "404" }

? ? }

]

const router = createRouter({

? ? history: createWebHashHistory(),

? ? routes,

? ? strict: false,

? ? // 切換頁面千康,滾動到最頂部

? ? scrollBehavior: () => ({ left: 0, top: 0 })

})

let initAddRoute = true // 是否是初始化添加路由

// 路由攔截

router.beforeEach(async (to, from, next) => {

? ? const token = localStorage.getItem('token')

? ? if (to.path === LOGIN_NAME) {

? ? ? ? // 此處添加初始化字段重置,因為如果退出后不刷新然后登錄不同的用戶铲掐,權(quán)限不一樣拾弃,會直接添加進路由,這樣新的用戶

? ? ? ? // 就可以通過 url 訪問前一個用戶的權(quán)限摆霉,所以退出時必須清空路由豪椿,此處重置字段用于重新獲取權(quán)限數(shù)據(jù)

? ? ? ? initAddRoute = true

? ? ? ? next()

? ? } else {

? ? ? ? if (!token) {

? ? ? ? ? ? ElNotification({

? ? ? ? ? ? ? ? title: '登錄提示',

? ? ? ? ? ? ? ? duration: 2000,

? ? ? ? ? ? ? ? message: '登錄過期,請重新登錄111携栋!',

? ? ? ? ? ? ? ? type: 'warning',

? ? ? ? ? ? })

? ? ? ? ? ? next(LOGIN_NAME)

? ? ? ? } else {

? ? ? ? ? ? const menuStore = useMenuStore()

? ? ? ? ? ? // 如果當(dāng)前跳轉(zhuǎn)的不是 404 頁面搭盾,則保存要跳轉(zhuǎn)的頁面名稱

? ? ? ? ? ? if (to.path !== "/404") {

? ? ? ? ? ? ? ? menuStore.setCurrentPath(to.path)

? ? ? ? ? ? }

? ? ? ? ? ? // 獲取保存的路由菜單并生成符合路由數(shù)據(jù)結(jié)構(gòu)的列表的

? ? ? ? ? ? let routeList: Menu.MenuOptions[] = getRouterList(menuStore.routeList)

? ? ? ? ? ? // 登錄時獲取權(quán)限

? ? ? ? ? ? if (initAddRoute && from.name === "login") {

? ? ? ? ? ? ? ? let list = await menuStore.getPermiList()// 獲取權(quán)限

? ? ? ? ? ? ? ? routeList = await getRouterList(list)// 格式化權(quán)限

? ? ? ? ? ? }

? ? ? ? ? ? // 判斷當(dāng)前是否是 初始化/刷新 =》添加路由,如果是并且本地保存了路由菜單婉支,則添加進路由

? ? ? ? ? ? if (initAddRoute && routeList.length > 0) {

? ? ? ? ? ? ? ? routeList.forEach((item: any) => {

? ? ? ? ? ? ? ? ? ? router.addRoute(item)

? ? ? ? ? ? ? ? })

? ? ? ? ? ? ? ? initAddRoute = false

? ? ? ? ? ? ? ? // 初次進入時路由還未初始化好鸯隅,如果直接執(zhí)行 next(),會跳轉(zhuǎn)到本地的路由 404,

? ? ? ? ? ? ? ? // 所以登錄或刷新時判斷當(dāng)前是登錄并且跳轉(zhuǎn)的是 404蝌以,則重新觸發(fā)一次路由守衛(wèi)炕舵,此時路由已初始化完,

? ? ? ? ? ? ? ? // 然后再執(zhí)行 next()

? ? ? ? ? ? ? ? if (from.name === "login" && to.name === "404") {

? ? ? ? ? ? ? ? ? ? next({ path: './configAdmin' })// 重新觸發(fā)導(dǎo)航守衛(wèi)并保存路徑

? ? ? ? ? ? ? ? } else {

? ? ? ? ? ? ? ? ? ? next({ path: menuStore.currentPath })// 重新觸發(fā)導(dǎo)航守衛(wèi)一次

? ? ? ? ? ? ? ? }

? ? ? ? ? ? } else {

? ? ? ? ? ? ? ? next()

? ? ? ? ? ? }

? ? ? ? ? ? // next()

? ? ? ? }

? ? }

})

export default router


menu.ts

import { defineStore } from "pinia"

import { MenuState } from '../interface'

import piniaPersistConfig from '@/config/piniaPersist'

import {

? ? getPermissionList,

} from '@/api/public'

import {

? ? getMenuList

} from "@/utils/tools"

// useMenuStore

export const useMenuStore = defineStore({

? ? id: "MenuState",

? ? state: (): MenuState => ({

? ? ? ? // menu collapse

? ? ? ? isCollapse: false,

? ? ? ? // routeList

? ? ? ? routeList: [],

? ? ? ? // menuList

? ? ? ? menuList: [],

? ? ? ? currentPath: ''

? ? }),

? ? getters: {},

? ? actions: {

? ? ? ? setCollapse() {

? ? ? ? ? ? this.isCollapse = !this.isCollapse

? ? ? ? },

? ? ? ? setRouteList(routeList: any) {

? ? ? ? ? ? this.routeList = routeList

? ? ? ? },

? ? ? ? setMenuList(menuList: any) {

? ? ? ? ? ? this.menuList = menuList

? ? ? ? },

? ? ? ? setCurrentPath(currentPath: string) {

? ? ? ? ? ? this.currentPath = currentPath

? ? ? ? },

? ? ? ? // 獲取權(quán)限列表

? ? ? ? async getPermiList() {

? ? ? ? ? ? const res: any = await getPermissionList()

? ? ? ? ? ? if (res.code === 200) {

? ? ? ? ? ? ? ? this.routeList = res.data

? ? ? ? ? ? ? ? this.menuList = getMenuList(res.data)

? ? ? ? ? ? }

? ? ? ? ? ? return res.data

? ? ? ? },

? ? },

? ? persist: piniaPersistConfig("MenuState")

})

utils/tools.ts

數(shù)據(jù)格式化方法跟畅,可根據(jù)自己業(yè)務(wù)的數(shù)據(jù)結(jié)構(gòu)自行更改 :

// 獲取本地所有權(quán)限列表

export const getAllPremission = () => {

? ? const metaRouters = import.meta.glob("../router/modules/*.ts", { import: 'default', eager: true })

? ? let routerArray: any[] = []

? ? Object.values(metaRouters).forEach((item: any) => {

? ? ? ? item.map((val: any) => {

? ? ? ? ? ? routerArray.push(val)

? ? ? ? })

? ? })

? ? return routerArray

}

// 封裝 動態(tài)獲取到的權(quán)限 數(shù)據(jù)結(jié)構(gòu) => 路由

export const getRouterList = (list: Menu.RequestRouteItem[]) => {

? ? if (!list.length) return []

? ? let routeList: Menu.MenuOptions[] = getAllPremission().map(routeItem => {

? ? ? ? routeItem.children?.forEach((childrenItem: any) => {

? ? ? ? ? ? childrenItem.hasPermission = list.some((listItem: Menu.RequestRouteItem) => {

? ? ? ? ? ? ? ? if (listItem.children.length) {

? ? ? ? ? ? ? ? ? ? return listItem.children.some(child => {

? ? ? ? ? ? ? ? ? ? ? ? return childrenItem.meta!.title == child.permissionName

? ? ? ? ? ? ? ? ? ? })

? ? ? ? ? ? ? ? } else {

? ? ? ? ? ? ? ? ? ? return childrenItem.meta!.title == listItem.permissionName

? ? ? ? ? ? ? ? }

? ? ? ? ? ? })

? ? ? ? ? ? if (childrenItem.meta!.title === '測試模版') {

? ? ? ? ? ? ? ? childrenItem.hasPermission = true

? ? ? ? ? ? }

? ? ? ? })

? ? ? ? return routeItem

? ? })

? ? // 生成最終權(quán)限路由列表

? ? routeList = routeList.map(item => {

? ? ? ? item.children = item.children?.filter(child => {

? ? ? ? ? ? return child.hasPermission

? ? ? ? })

? ? ? ? return item

? ? })

? ? return routeList

}


項目結(jié)構(gòu)圖
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末咽筋,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子徊件,更是在濱河造成了極大的恐慌奸攻,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件虱痕,死亡現(xiàn)場離奇詭異睹耐,居然都是意外死亡,警方通過查閱死者的電腦和手機皆疹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進店門疏橄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人略就,你說我怎么就攤上這事捎迫。” “怎么了表牢?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵窄绒,是天一觀的道長。 經(jīng)常有香客問我崔兴,道長彰导,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任敲茄,我火速辦了婚禮位谋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘堰燎。我一直安慰自己掏父,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布秆剪。 她就那樣靜靜地躺著赊淑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪仅讽。 梳的紋絲不亂的頭發(fā)上陶缺,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天,我揣著相機與錄音洁灵,去河邊找鬼饱岸。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的伶贰。 我是一名探鬼主播蛛砰,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼黍衙!你這毒婦竟也來了泥畅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤琅翻,失蹤者是張志新(化名)和其女友劉穎位仁,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體方椎,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡聂抢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了棠众。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片琳疏。...
    茶點故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖闸拿,靈堂內(nèi)的尸體忽然破棺而出空盼,到底是詐尸還是另有隱情,我是刑警寧澤新荤,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布揽趾,位于F島的核電站,受9級特大地震影響苛骨,放射性物質(zhì)發(fā)生泄漏篱瞎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一痒芝、第九天 我趴在偏房一處隱蔽的房頂上張望俐筋。 院中可真熱鬧,春花似錦严衬、人聲如沸校哎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至腰奋,卻和暖如春单起,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背劣坊。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工嘀倒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓测蘑,卻偏偏與公主長得像灌危,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子碳胳,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,494評論 2 348

推薦閱讀更多精彩內(nèi)容