Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/layouts/components/MenuContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type ListItemType = MenuRoute;
const { navData } = defineProps({
navData: {
type: Array as PropType<MenuRoute[]>,
default: () => [],
default: (): MenuRoute[] => [],
},
});

Expand Down Expand Up @@ -80,7 +80,7 @@ const getMenuList = (list: MenuRoute[], basePath?: string): ListItemType[] => {
redirect: item.redirect,
};
})
.filter((item) => item.meta && item.meta.hidden !== true);
.filter((item) => item.meta && item.meta.hidden !== true && item.meta.title);
};

const getHref = (item: MenuRoute) => {
Expand Down
37 changes: 18 additions & 19 deletions src/permission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import 'nprogress/nprogress.css'; // progress bar style

import NProgress from 'nprogress'; // progress bar
import { MessagePlugin } from 'tdesign-vue-next';
import type { RouteRecordRaw } from 'vue-router';

import router from '@/router';
// import type { RouteRecordRaw } from 'vue-router';
import router, { whiteListRoutePath } from '@/router';
import { getPermissionStore, useUserStore } from '@/store';
import { PAGE_NOT_FOUND_ROUTE } from '@/utils/route/constant';

Expand All @@ -13,9 +13,6 @@ NProgress.configure({ showSpinner: false });
router.beforeEach(async (to, from, next) => {
NProgress.start();

const permissionStore = getPermissionStore();
const { whiteListRouters } = permissionStore;

const userStore = useUserStore();

if (userStore.token) {
Expand All @@ -25,14 +22,12 @@ router.beforeEach(async (to, from, next) => {
}
try {
await userStore.getUserInfo();
const permissionStore = getPermissionStore();

// 后端权限控制
const { asyncRoutes } = permissionStore;

if (asyncRoutes && asyncRoutes.length === 0) {
const routeList = await permissionStore.buildAsyncRoutes();
routeList.forEach((item: RouteRecordRaw) => {
router.addRoute(item);
});
await permissionStore.buildAsyncRoutes();

if (to.name === PAGE_NOT_FOUND_ROUTE.name) {
// 动态添加路由后,此处应当重定向到fullPath,否则会加载404页面内容
Expand All @@ -43,11 +38,16 @@ router.beforeEach(async (to, from, next) => {
return;
}
}
if (router.hasRoute(to.name)) {
next();
} else {
next(`/`);
}

// 前端权限控制
// const { routers } = permissionStore;
// if (routers.length === 0) {
// await permissionStore.initRoutes(userStore.roles);
// next({ ...to, replace: true });
// return;
// }

next();
} catch (error) {
MessagePlugin.error(error.message);
next({
Expand All @@ -57,8 +57,7 @@ router.beforeEach(async (to, from, next) => {
NProgress.done();
}
} else {
/* white list router */
if (whiteListRouters.includes(to.path)) {
if (whiteListRoutePath.includes(to.path)) {
next();
} else {
next({
Expand All @@ -73,9 +72,9 @@ router.beforeEach(async (to, from, next) => {
router.afterEach((to) => {
if (to.path === '/login') {
const userStore = useUserStore();
const permissionStore = getPermissionStore();

userStore.logout();

const permissionStore = getPermissionStore();
permissionStore.restoreRoutes();
}
NProgress.done();
Expand Down
8 changes: 3 additions & 5 deletions src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,14 @@ const defaultRouterList: Array<RouteRecordRaw> = [
name: 'login',
component: () => import('@/pages/login/index.vue'),
},
{
path: '/',
redirect: '/dashboard/base',
},
];

// 存放固定路由
export const homepageRouterList: Array<RouteRecordRaw> = mapModuleRouterList(homepageModules);
export const fixedRouterList: Array<RouteRecordRaw> = mapModuleRouterList(fixedModules);

export const allRoutes = [...homepageRouterList, ...fixedRouterList, ...defaultRouterList];
export const whiteListRoutePath = uniq(defaultRouterList.map((item) => item.path));

// 固定路由模块转换为路由
export function mapModuleRouterList(modules: Record<string, unknown>): Array<RouteRecordRaw> {
Expand Down Expand Up @@ -83,7 +81,7 @@ export const getActive = (maxLevel = 3): string => {

const router = createRouter({
history: createWebHistory(env === 'site' ? '/starter/vue-next/' : import.meta.env.VITE_BASE_URL),
routes: allRoutes,
routes: defaultRouterList,
scrollBehavior() {
return {
el: '#app',
Expand Down
4 changes: 4 additions & 0 deletions src/router/modules/homepage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import type { RouteRecordRaw } from 'vue-router';
import Layout from '@/layouts/index.vue';

export default [
{
path: '/',
redirect: '/dashboard/base',
},
{
path: '/dashboard',
component: Layout,
Expand Down
72 changes: 33 additions & 39 deletions src/store/modules/permission-fe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,63 +5,57 @@ import cloneDeep from 'lodash/cloneDeep';
import { defineStore } from 'pinia';
import type { RouteRecordRaw } from 'vue-router';

import router, { allRoutes } from '@/router';
import router, { fixedRouterList, homepageRouterList } from '@/router';
import { store } from '@/store';

function filterPermissionsRouters(routes: Array<RouteRecordRaw>, roles: Array<unknown>) {
const res: Array<RouteRecordRaw> = [];
const removeRoutes: Array<RouteRecordRaw> = [];
// 严格模式 true: 路由无roleCode不可访问 false: 路由无roleCode可访问
const CHECK_ROLE_STRICT = false;
function filterPermissionsRouters(routes: Array<RouteRecordRaw>, roles: Array<string>): Array<RouteRecordRaw> {
if (routes.length === 0) return [];
const accessedRouters: Array<RouteRecordRaw> = [];
routes.forEach((route) => {
const children: Array<RouteRecordRaw> = [];
route.children?.forEach((childRouter) => {
const roleCode = childRouter.meta?.roleCode || childRouter.name;
if (roles.includes(roleCode)) {
children.push(childRouter);
} else {
removeRoutes.push(childRouter);
}
});
if (children.length > 0) {
route.children = children;
res.push(route);
const roleCode = route.meta?.roleCode;
const hasPermission = CHECK_ROLE_STRICT ? roles.includes(roleCode) : !roleCode || roles.includes(roleCode);
if (!hasPermission) {
return;
}
if (!route.children || route.children.length === 0) {
accessedRouters.push(route);
return;
}
const accessedChildren = filterPermissionsRouters(route.children, roles);
route.children = accessedChildren;
accessedRouters.push(route);
});
return { accessedRouters: res, removeRoutes };
return accessedRouters;
}

const removeRouteFnSet = new Set<() => void>();
export const usePermissionStore = defineStore('permission', {
state: () => ({
whiteListRouters: ['/login'],
routers: [],
removeRoutes: [],
}),
actions: {
async initRoutes(roles: Array<unknown>) {
let accessedRouters = [];

let removeRoutes: Array<RouteRecordRaw> = [];
async initRoutes(roles: Array<string>) {
let accessedRouters: Array<RouteRecordRaw> = [];
const allRoutes = cloneDeep([...homepageRouterList, ...fixedRouterList]);
// special token
if (roles.includes('all')) {
accessedRouters = cloneDeep(allRoutes);
accessedRouters = allRoutes;
} else {
const res = filterPermissionsRouters(allRoutes, roles);
accessedRouters = res.accessedRouters;
removeRoutes = res.removeRoutes;
accessedRouters = filterPermissionsRouters(allRoutes, roles);
}
for (const route of accessedRouters) {
removeRouteFnSet.add(router.addRoute(route));
}

this.routers = accessedRouters;
this.removeRoutes = removeRoutes;

removeRoutes.forEach((item: RouteRecordRaw) => {
if (router.hasRoute(item.name)) {
router.removeRoute(item.name);
}
});
},
async restore() {
this.removeRoutes.forEach((item: RouteRecordRaw) => {
router.addRoute(item);
});
async restoreRoutes() {
for (const removeRoute of removeRouteFnSet) {
removeRoute();
}
removeRouteFnSet.clear();
this.routers = [];
},
},
});
Expand Down
21 changes: 12 additions & 9 deletions src/store/modules/permission.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
import cloneDeep from 'lodash/cloneDeep';
import { defineStore } from 'pinia';
import type { RouteRecordRaw } from 'vue-router';

import type { RouteItem } from '@/api/model/permissionModel';
import { getMenuList } from '@/api/permission';
import router, { fixedRouterList, homepageRouterList } from '@/router';
import { store } from '@/store';
import { transformObjectToRoute } from '@/utils/route';

const removeRouteFnSet = new Set<() => void>();

export const usePermissionStore = defineStore('permission', {
state: () => ({
whiteListRouters: ['/login'],
routers: [],
removeRoutes: [],
asyncRoutes: [],
}),
actions: {
async initRoutes() {
const accessedRouters = this.asyncRoutes;

const allRoutes = [...homepageRouterList, ...fixedRouterList, ...accessedRouters];
for (const route of allRoutes) {
removeRouteFnSet.add(router.addRoute(route));
}
// 在菜单展示全部路由
this.routers = cloneDeep([...homepageRouterList, ...accessedRouters, ...fixedRouterList]);
this.routers = cloneDeep(allRoutes);
// 在菜单只展示动态路由和首页
// this.routers = [...homepageRouterList, ...accessedRouters];
// 在菜单只展示动态路由
Expand All @@ -39,11 +42,11 @@ export const usePermissionStore = defineStore('permission', {
},
async restoreRoutes() {
// 不需要在此额外调用initRoutes更新侧边导肮内容,在登录后asyncRoutes为空会调用
this.asyncRoutes.forEach((item: RouteRecordRaw) => {
if (item.name) {
router.removeRoute(item.name);
}
});
for (const removeRoute of removeRouteFnSet) {
removeRoute();
}
removeRouteFnSet.clear();
this.routers = [];
this.asyncRoutes = [];
},
},
Expand Down
7 changes: 1 addition & 6 deletions src/store/modules/user.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { defineStore } from 'pinia';

import { usePermissionStore } from '@/store';
import type { UserInfo } from '@/types/interface';

const InitUserInfo: UserInfo = {
Expand Down Expand Up @@ -64,7 +63,7 @@ export const useUserStore = defineStore('user', {
}
return {
name: 'td_dev',
roles: ['UserIndex', 'DashboardBase', 'login'], // 前端权限模型使用 如果使用请配置modules/permission-fe.ts使用
roles: ['dev'], // 前端权限模型使用 如果使用请配置modules/permission-fe.ts使用
};
};
const res = await mockRemoteUserInfo(this.token);
Expand All @@ -77,10 +76,6 @@ export const useUserStore = defineStore('user', {
},
},
persist: {
afterRestore: () => {
const permissionStore = usePermissionStore();
permissionStore.initRoutes();
},
key: 'user',
paths: ['token'],
},
Expand Down
2 changes: 1 addition & 1 deletion src/types/router.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ declare module 'vue-router' {
keepAlive?: boolean;
frameSrc?: string;
frameBlank?: boolean;
// roleCode?: string; // 前端 roles 控制菜单权限
roleCode?: string; // 前端 roles 控制菜单权限
}
}
9 changes: 6 additions & 3 deletions src/utils/route/constant.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import type { RouteRecordRaw } from 'vue-router';

export const LAYOUT = () => import('@/layouts/index.vue');
export const BLANK_LAYOUT = () => import('@/layouts/blank.vue');
export const IFRAME = () => import('@/layouts/components/FrameBlank.vue');
export const EXCEPTION_COMPONENT = () => import('@/pages/result/500/index.vue');
export const PAGE_NOT_FOUND_COMPONENT = () => import('@/pages/result/404/index.vue');
export const PARENT_LAYOUT = () =>
new Promise((resolve) => {
resolve({ name: 'ParentLayout' });
});

export const PAGE_NOT_FOUND_ROUTE = {
path: '/:w+',
export const PAGE_NOT_FOUND_ROUTE: RouteRecordRaw = {
path: '/:pathMatch(.*)*',
name: '404Page',
redirect: '/result/404',
component: PAGE_NOT_FOUND_COMPONENT,
};