From 4acb525777798374f1061158b1e2096e839f73ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98chen=2Ehome=E2=80=99?= <1147347984@qq.com> Date: Sun, 14 Aug 2022 18:05:43 +0800 Subject: [PATCH] =?UTF-8?q?feat(projects):=20=E6=B7=BB=E5=8A=A0=E8=B7=AF?= =?UTF-8?q?=E7=94=B1=E6=8B=A6=E6=88=AA=E5=88=A4=E6=96=AD=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mock/module/user.ts | 2 +- src/main.ts | 4 ++-- src/router/guard/index.ts | 27 ++++++++++--------------- src/router/guard/permission.ts | 37 ++++++++++++++++++++++++++++++++++ src/router/index.ts | 2 +- src/router/routes/index.ts | 12 +++++++++-- src/store/modules/auth.ts | 13 +++++------- src/store/modules/index.ts | 1 + src/store/modules/route.ts | 25 ++++++++++++++++------- src/types/business.d.ts | 2 +- src/types/route.d.ts | 4 +++- 11 files changed, 90 insertions(+), 39 deletions(-) create mode 100644 src/router/guard/permission.ts diff --git a/mock/module/user.ts b/mock/module/user.ts index c6503b2..150fb23 100644 --- a/mock/module/user.ts +++ b/mock/module/user.ts @@ -13,7 +13,7 @@ const userInfo = { role: 'admin', password: '123456', token, - permissions: [ + userRoutes: [ { name: 'dashboard', path: '/dashboard', diff --git a/src/main.ts b/src/main.ts index 9ec7a20..6c0897c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -9,10 +9,10 @@ async function setupApp() { setupAssets(); // 创建vue实例 const app = createApp(App); - // 安装router - await setupRouter(app); // 安装pinia全局状态库 setupStore(app); + // 安装router + await setupRouter(app); // 挂载 app.mount('#app'); } diff --git a/src/router/guard/index.ts b/src/router/guard/index.ts index a192c0b..0beed5d 100644 --- a/src/router/guard/index.ts +++ b/src/router/guard/index.ts @@ -1,25 +1,20 @@ import type { Router } from 'vue-router'; -import { getToken } from '@/utils/auth'; + +import { createPermissionGuard } from './permission'; const appTitle = import.meta.env.VITE_APP_TITLE; export function setupRouterGuard(router: Router) { - const isLogin = Boolean(getToken()); - - router.beforeEach((to, _from, next) => { - // 登录鉴权 - if (!isLogin) { - if (to.name === 'login') { - next(); - } else { - const redirect = to.fullPath; - next({ path: '/login', query: { redirect } }); - } - return false; - } + router.beforeEach(async (to, from, next) => { + // 开始 loadingBar + window.$loadingBar?.start(); + // 权限操作 + await createPermissionGuard(to, from, next); + }); + router.afterEach((to) => { // 修改网页标题 document.title = `${to.meta.title}——${appTitle}`; - next(); + // 结束 loadingBar + window.$loadingBar?.finish(); }); - // router.afterEach((_to) => {}); } diff --git a/src/router/guard/permission.ts b/src/router/guard/permission.ts new file mode 100644 index 0000000..cce6fd4 --- /dev/null +++ b/src/router/guard/permission.ts @@ -0,0 +1,37 @@ +import { RouteLocationNormalized, NavigationGuardNext } from 'vue-router'; +import { getToken } from '@/utils/auth'; +import { useRouteStore, useAuthStore } from '@/store'; + +export async function createPermissionGuard( + to: RouteLocationNormalized, + from: RouteLocationNormalized, + next: NavigationGuardNext, +) { + const isLogin = Boolean(getToken()); + const routeStore = useRouteStore(); + + // 判断路由有无进行初始化 + if (!routeStore.isInitAuthRoute) { + // 没有初始化路由 => 登录鉴权 + // 登录鉴权 + if (!isLogin) { + if (to.name === 'login') { + next(); + } else { + const redirect = to.fullPath; + next({ path: '/login', query: { redirect } }); + } + return false; + } + + // 有登录但是没有路由,初始化路由等 + await routeStore.initAuthRoute(); + } + // 权限路由已经加载,仍然未找到,重定向到not-found + // if (to.name === 'not-found-page') { + // next({ name: 'not-found-page', replace: true }); + // } + + // next({ name: 'root' }); + next(); +} diff --git a/src/router/index.ts b/src/router/index.ts index 0f48b7d..04a1de6 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -8,7 +8,7 @@ const routes: RouteRecordRaw[] = [ { path: '/', name: 'root', - redirect: '/test1', + redirect: '/test/test1', component: BasicLayout, children: [ { diff --git a/src/router/routes/index.ts b/src/router/routes/index.ts index aad7424..914c147 100644 --- a/src/router/routes/index.ts +++ b/src/router/routes/index.ts @@ -1,6 +1,14 @@ // import { BasicLayout } from '@/layouts/index'; export const constantRoutes = [ + { + path: '/no-found', + name: 'not-found', + component: () => import('@/views/inherit-page/not-found/index.vue'), + meta: { + title: '找不到页面', + }, + }, { path: '/no-permission', name: 'no-permission', @@ -19,10 +27,10 @@ export const constantRoutes = [ }, { path: '/:pathMatch(.*)*', - name: '404', + name: 'not-found-page', component: () => import('@/views/inherit-page/not-found/index.vue'), meta: { - title: '错误404', + title: '找不到页面', }, }, ]; diff --git a/src/store/modules/auth.ts b/src/store/modules/auth.ts index f96149f..f9f5336 100644 --- a/src/store/modules/auth.ts +++ b/src/store/modules/auth.ts @@ -50,7 +50,8 @@ export const useAuthStore = defineStore('auth-store', { // 等待数据写入完成 const catchSuccess = await this.catchUserInfo(data); // 初始化侧边菜单 - await this.setRouterStore(data.permissions); + const { setMenus } = useRouteStore(); + await setMenus(); // 登录写入信息成功 if (catchSuccess) { // 进行重定向跳转 @@ -65,7 +66,9 @@ export const useAuthStore = defineStore('auth-store', { }); return; } - // 如果不成功写到后面 + + // 如果不成功则重置存储 + this.resetAuthStore(); }, /* 缓存用户信息 */ @@ -82,11 +85,5 @@ export const useAuthStore = defineStore('auth-store', { return catchSuccess; }, - - /* 将路由表等信息推送到routeStore */ - async setRouterStore(permissions: Auth.UserInfoPermissions[]) { - const { setMenus } = useRouteStore(); - setMenus(permissions); - }, }, }); diff --git a/src/store/modules/index.ts b/src/store/modules/index.ts index 8bb08fd..bf5ca14 100644 --- a/src/store/modules/index.ts +++ b/src/store/modules/index.ts @@ -1,2 +1,3 @@ export * from './app'; export * from './auth'; +export * from './route'; diff --git a/src/store/modules/route.ts b/src/store/modules/route.ts index 16fdb73..94f0fd9 100644 --- a/src/store/modules/route.ts +++ b/src/store/modules/route.ts @@ -1,23 +1,29 @@ import { defineStore } from 'pinia'; -import { renderIcon } from '@/utils/icon'; +import { renderIcon, getUserInfo } from '@/utils'; import type { MenuOption } from 'naive-ui'; +// import { useAuthStore } from './auth'; -interface RuutesStatus { +// const authStore = useAuthStore(); + +interface RoutesStatus { + isInitAuthRoute: boolean; menus: any; } export const useRouteStore = defineStore('route-store', { - state: (): RuutesStatus => { + state: (): RoutesStatus => { return { + isInitAuthRoute: false, menus: [], }; }, actions: { - setMenus(data: Auth.UserInfoPermissions[]) { - this.menus = this.transformAuthRoutesToMenus(data); + async setMenus() { + const { userRoutes } = getUserInfo(); + this.menus = this.transformAuthRoutesToMenus(userRoutes); }, // 将返回的路由表渲染成侧边栏 - transformAuthRoutesToMenus(data: Auth.UserInfoPermissions[]): MenuOption[] { - return data.map((item) => { + transformAuthRoutesToMenus(userRoutes: Auth.UserInfoPermissions[]): MenuOption[] { + return userRoutes.map((item) => { const target: MenuOption = { label: item.meta.title, key: item.path, @@ -33,5 +39,10 @@ export const useRouteStore = defineStore('route-store', { return target; }); }, + + async initAuthRoute() { + await this.setMenus(); + this.isInitAuthRoute = true; + }, }, }); diff --git a/src/types/business.d.ts b/src/types/business.d.ts index bad0e5a..15fbf78 100644 --- a/src/types/business.d.ts +++ b/src/types/business.d.ts @@ -26,7 +26,7 @@ declare namespace Auth { /* token */ token: string; /* 权限路由 */ - permissions: UserInfoPermissions[]; + userRoutes: UserInfoPermissions[]; } interface UserInfoPermissions { name: string; diff --git a/src/types/route.d.ts b/src/types/route.d.ts index 185ffed..fcfe4cf 100644 --- a/src/types/route.d.ts +++ b/src/types/route.d.ts @@ -35,10 +35,12 @@ declare namespace AppRoute { /* 是否开启页面缓存 */ keepAlive?: boolean; /* 有些路由我们并不想在菜单中显示,比如某些编辑页面。 */ - hideMenu?: boolean; + hide?: boolean; /* 菜单排序。 */ order?: number; /* 嵌套外链 */ herf?: string; + /** 当前路由需要选中的菜单项(用于跳转至不在左侧菜单显示的路由且需要高亮某个菜单的情况) */ + activeMenu?: RouteKey; } }