mirror of
https://github.com/chansee97/nova-admin.git
synced 2025-04-06 03:57:54 +08:00
feat(hooks): 增加路由操作hook
This commit is contained in:
parent
c74023901c
commit
c9703576bc
@ -35,6 +35,12 @@ module.exports = {
|
||||
'no-debugger': 'off', // 关闭debugger警告
|
||||
'vue/multi-word-component-names': 0, // 关闭文件名多单词
|
||||
// 'import/no-unresolved': ['error', { ignore: ['~icons/*'] }],
|
||||
"@typescript-eslint/no-explicit-any": ["off"]
|
||||
"@typescript-eslint/no-explicit-any": ["off"], // 允许使用any
|
||||
'@typescript-eslint/no-empty-interface': [
|
||||
'error',
|
||||
{
|
||||
allowSingleExtends: true
|
||||
}
|
||||
],
|
||||
},
|
||||
};
|
||||
|
1
src/hook/index.ts
Normal file
1
src/hook/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './useERouter';
|
59
src/hook/useERouter.ts
Normal file
59
src/hook/useERouter.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import { useRouter, RouteLocationRaw } from 'vue-router';
|
||||
import { router as gobalRouter } from '@/router';
|
||||
|
||||
/**
|
||||
* @description: 全局路由方法,vue-router自带的useRouter,在根目录下不能用
|
||||
* @param {*} isSetup
|
||||
* @return {*}
|
||||
*/
|
||||
export function useERouter(isSetup = true) {
|
||||
const router = isSetup ? useRouter() : gobalRouter;
|
||||
const route = router.currentRoute;
|
||||
|
||||
/* 路由跳转方法 */
|
||||
function routerPush(to: RouteLocationRaw) {
|
||||
router.push(to);
|
||||
}
|
||||
|
||||
/* 路由跳转方法 */
|
||||
function routerReplace(to: RouteLocationRaw) {
|
||||
router.replace(to);
|
||||
}
|
||||
|
||||
/* 前进后退方法 */
|
||||
function routerGo(delta: number) {
|
||||
router.go(delta);
|
||||
}
|
||||
|
||||
/* 跳转根页方法 */
|
||||
function toRoot() {
|
||||
routerPush({ name: 'root' });
|
||||
}
|
||||
/* 跳转至登录页 */
|
||||
function toLogin(redirectUrl?: string) {
|
||||
const redirect = redirectUrl || route.value.fullPath;
|
||||
const targetUrl = {
|
||||
name: 'login',
|
||||
query: { redirect },
|
||||
};
|
||||
routerPush(targetUrl);
|
||||
}
|
||||
/* 跳转重定向方法 */
|
||||
function toLoginRedirect() {
|
||||
const { query } = route.value;
|
||||
if (query?.redirect) {
|
||||
routerPush(query.redirect as string);
|
||||
} else {
|
||||
toRoot();
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
routerPush,
|
||||
routerReplace,
|
||||
routerGo,
|
||||
toRoot,
|
||||
toLogin,
|
||||
toLoginRedirect,
|
||||
};
|
||||
}
|
@ -17,7 +17,7 @@ const authStore = useAuthStore();
|
||||
const options = [
|
||||
{
|
||||
label: '个人中心',
|
||||
key: 'personal center',
|
||||
key: '/presonalCenter',
|
||||
icon: renderIcon('icon-park-outline:grinning-face'),
|
||||
},
|
||||
{
|
||||
@ -26,13 +26,14 @@ const options = [
|
||||
},
|
||||
{
|
||||
label: '退出登录',
|
||||
key: 'login out',
|
||||
key: 'loginOut',
|
||||
icon: renderIcon('icon-park-outline:logout'),
|
||||
},
|
||||
];
|
||||
const handleSelect = (key: string | number) => {
|
||||
console.log('%c [key]-32', 'font-size:13px; background:pink; color:#bf2c9f;', key);
|
||||
// message.info(String(key));
|
||||
if (key === 'loginOut') {
|
||||
authStore.resetAuthStore();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@ -37,11 +37,6 @@ const menuOptions: MenuOption[] = [
|
||||
key: '/test3',
|
||||
icon: renderIcon('icon-park-outline:pic'),
|
||||
},
|
||||
{
|
||||
label: '登录页',
|
||||
key: '/login',
|
||||
icon: renderIcon('icon-park-outline:save'),
|
||||
},
|
||||
{
|
||||
label: '舞,舞,舞',
|
||||
key: 'dance-dance-dance',
|
||||
|
@ -17,6 +17,7 @@ const routes: RouteRecordRaw[] = [
|
||||
meta: {
|
||||
title: '测试1',
|
||||
icon: 'icon-park-outline:game-three',
|
||||
requiresAuth: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -26,6 +27,7 @@ const routes: RouteRecordRaw[] = [
|
||||
meta: {
|
||||
title: '测试2',
|
||||
icon: 'carbon:aperture',
|
||||
requiresAuth: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -35,6 +37,7 @@ const routes: RouteRecordRaw[] = [
|
||||
meta: {
|
||||
title: '测试3',
|
||||
icon: 'icon-park-outline:music-list',
|
||||
requiresAuth: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
71
src/router/routes/index.ts
Normal file
71
src/router/routes/index.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { BasicLayout } from '@/layouts/index';
|
||||
|
||||
export const constantRoutes: AppRoute.Route[] = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'root',
|
||||
redirect: '/test1',
|
||||
component: BasicLayout,
|
||||
children: [
|
||||
{
|
||||
path: '/test1',
|
||||
name: 'test1',
|
||||
component: () => import('~/src/views/test/test1.vue'),
|
||||
meta: {
|
||||
title: '测试1',
|
||||
icon: 'icon-park-outline:game-three',
|
||||
requiresAuth: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/test2',
|
||||
name: 'test2',
|
||||
component: () => import('~/src/views/test/test2.vue'),
|
||||
meta: {
|
||||
title: '测试2',
|
||||
icon: 'carbon:aperture',
|
||||
requiresAuth: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/test3',
|
||||
name: 'test3',
|
||||
component: () => import('~/src/views/test/test3.vue'),
|
||||
meta: {
|
||||
title: '测试3',
|
||||
icon: 'icon-park-outline:music-list',
|
||||
requiresAuth: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
component: () => import('@/views/login/index.vue'), // 注意这里要带上 文件后缀.vue
|
||||
},
|
||||
{
|
||||
path: '/no-permission',
|
||||
name: 'no-permission',
|
||||
component: () => import('@/views/inherit-page/not-permission/index.vue'),
|
||||
meta: {
|
||||
title: '无权限',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/service-error',
|
||||
name: 'service-error',
|
||||
component: () => import('@/views/inherit-page/service-error/index.vue'),
|
||||
meta: {
|
||||
title: '服务器错误',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
name: '404',
|
||||
component: () => import('@/views/inherit-page/not-found/index.vue'),
|
||||
meta: {
|
||||
title: '错误404',
|
||||
},
|
||||
},
|
||||
];
|
@ -1,7 +1,11 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { fetchLogin } from '@/service';
|
||||
import { setUserInfo, getUserInfo, getToken, setToken } from '@/utils/auth';
|
||||
import { setUserInfo, getUserInfo, getToken, setToken, clearAuthStorage } from '@/utils/auth';
|
||||
import { router } from '@/router';
|
||||
import { useERouter } from '@/hook';
|
||||
import { unref } from 'vue';
|
||||
|
||||
// const { routerPush, routerReplace } = useERouter(false);
|
||||
|
||||
export const useAuthStore = defineStore('auth-store', {
|
||||
state: () => {
|
||||
@ -18,6 +22,19 @@ export const useAuthStore = defineStore('auth-store', {
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
/* 登录退出,重置用户信息等 */
|
||||
resetAuthStore() {
|
||||
const route = unref(router.currentRoute);
|
||||
const { toLogin } = useERouter(false);
|
||||
// 清除本地缓存
|
||||
clearAuthStorage();
|
||||
// 清空pinia
|
||||
this.$reset();
|
||||
if (route.meta.requiresAuth) {
|
||||
toLogin();
|
||||
}
|
||||
},
|
||||
|
||||
/* 用户登录 */
|
||||
async login(userName: string, password: string) {
|
||||
this.loginLoading = true;
|
||||
@ -28,12 +45,17 @@ export const useAuthStore = defineStore('auth-store', {
|
||||
|
||||
this.loginLoading = false;
|
||||
},
|
||||
handleAfterLogin(data: Auth.UserInfo) {
|
||||
// 存储用户信息
|
||||
setUserInfo(data);
|
||||
setToken(data.token);
|
||||
this.userInfo = data;
|
||||
this.token = data.token;
|
||||
|
||||
/* 登录后的处理函数 */
|
||||
async handleAfterLogin(data: Auth.UserInfo) {
|
||||
// 等待数据写入完成
|
||||
const catchSuccess = await this.catchUserInfo(data);
|
||||
|
||||
// 登录写入信息成功
|
||||
if (catchSuccess) {
|
||||
// 进行重定向跳转
|
||||
const { toLoginRedirect } = useERouter(false);
|
||||
toLoginRedirect();
|
||||
|
||||
// 触发用户提示
|
||||
window.$notification?.success({
|
||||
@ -41,15 +63,24 @@ export const useAuthStore = defineStore('auth-store', {
|
||||
content: `欢迎回来,${this.userInfo.realName}!`,
|
||||
duration: 3000,
|
||||
});
|
||||
|
||||
// 进行跳转
|
||||
const route = router.currentRoute;
|
||||
const { query } = route.value;
|
||||
if (query?.redirect) {
|
||||
router.push(query.redirect as string);
|
||||
} else {
|
||||
router.push('/');
|
||||
return;
|
||||
}
|
||||
// 如果不成功写到后面
|
||||
},
|
||||
|
||||
/* 缓存用户信息 */
|
||||
async catchUserInfo(data: Auth.UserInfo) {
|
||||
let catchSuccess = false;
|
||||
|
||||
// 存储用户信息
|
||||
setUserInfo(data);
|
||||
setToken(data.token);
|
||||
this.userInfo = data;
|
||||
this.token = data.token;
|
||||
|
||||
catchSuccess = true;
|
||||
|
||||
return catchSuccess;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
44
src/types/route.d.ts
vendored
Normal file
44
src/types/route.d.ts
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
declare namespace AppRoute {
|
||||
/** 单个路由的类型结构(动态路由模式:后端返回此类型结构的路由) */
|
||||
interface Route {
|
||||
/** 路由名称(路由唯一标识) */
|
||||
name: string;
|
||||
/** 路由路径 */
|
||||
path: string;
|
||||
/** 路由重定向 */
|
||||
redirect?: string;
|
||||
/**
|
||||
* 路由组件
|
||||
* - basic: 基础布局,具有公共部分的布局
|
||||
* - blank: 空白布局
|
||||
* - multi: 多级路由布局(三级路由或三级以上时,除第一级路由和最后一级路由,其余的采用该布局)
|
||||
* - self: 作为子路由,使用自身的布局(作为最后一级路由,没有子路由)
|
||||
*/
|
||||
component?: any;
|
||||
/** 子路由 */
|
||||
children?: Route[];
|
||||
/** 路由描述 */
|
||||
meta?: RouteMeta;
|
||||
/** 路由属性 */
|
||||
// props?: boolean | Record<string, any> | ((to: any) => Record<string, any>);
|
||||
}
|
||||
/** 路由描述 */
|
||||
interface RouteMeta {
|
||||
/* 页面标题,通常必选。 */
|
||||
title?: string;
|
||||
/* 图标,一般配合菜单使用 */
|
||||
icon?: string;
|
||||
/* 是否需要登录权限。*/
|
||||
requiresAuth?: boolean;
|
||||
/* 可以访问的角色 */
|
||||
roles?: string[];
|
||||
/* 是否开启页面缓存 */
|
||||
keepAlive?: boolean;
|
||||
/* 有些路由我们并不想在菜单中显示,比如某些编辑页面。 */
|
||||
hideMenu?: boolean;
|
||||
/* 菜单排序。 */
|
||||
order?: number;
|
||||
/* 嵌套外链 */
|
||||
herf?: string;
|
||||
}
|
||||
}
|
4
src/types/router.d.ts
vendored
Normal file
4
src/types/router.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
import 'vue-router';
|
||||
declare module 'vue-router' {
|
||||
interface RouteMeta extends AppRoute.RouteMeta {}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user