Procházet zdrojové kódy

修复路由守卫逻辑,增加无权限访问页面及权限相关功能,优化路由获取方式,移除冗余代码,新增NoPer.vue组件。

张涛 před 1 rokem
rodič
revize
5da719d8b5

+ 24 - 55
src/router/guard.js

@@ -1,58 +1,27 @@
 import router from './index';
-import { localST_RoutesList, kuky_Authorization } from '../base/storage';
-
-import { formatRoutes } from '../utils/permission';
-
-import Intelligent from '../views/Intelligent.vue';
-
-/** 是否已经生成过路由表 */
-let hasRouteFlag = false;
-export const resetHasRouteFlag = () => {
-  hasRouteFlag = false;
-};
+import { kuky_Authorization } from '../base/storage';
+import { firstPage, accessRoutes } from '../utils/permission';
 
 // /** 免登录白名单 */
-// const whiteList = ['/login', '/reg'];
-// router.beforeEach((to, from, next) => {
-//   if (kuky_Authorization.get()) {
-//     next();
-//     if (to.path === '/login') {
-//       // 如果已经登录,并准备进入 Login 页面,则重定向到主页
-//       next();
-//     } else {
-//       // if (!hasRouteFlag) {
-//       //   try {
-//       //     const routesList = JSON.parse(localST_RoutesList.getItem());
-//       //     const accessRoutes = formatRoutes(routesList);
-//       //     console.log('111', 111);
-//       //     router.addRoute({ path: '/intelligent', component: Intelligent });
-//       //     // TODO 动态路由添加失败
-//       //     // accessRoutes.forEach((route) => {
-//       //     //   if (route.path && route.component) {
-//       //     //     console.log('route', route);
-//       //     //     router.addRoute(route);
-//       //     //   }
-//       //     // });
-//       //     console.log('accessRoutes', accessRoutes);
-//       //     hasRouteFlag = true;
-//       //     // 确保添加路由已完成
-//       //     // 设置 replace: true, 因此导航将不会留下历史记录
-//       //     next({ ...to, replace: true });
-//       //   } catch (error) {
-//       //     console.log('error', error);
-//       //   }
-//       // } else {
-//       //   next();
-//       // }
-//     }
-//   } else {
-//     // 如果没有 Token
-//     if (whiteList.includes(to.path)) {
-//       // 如果在免登录的白名单中,则直接进入
-//       next();
-//     } else {
-//       // 其他没有访问权限的页面将被重定向到登录页面
-//       next('/login');
-//     }
-//   }
-// });
+const whiteList = ['/login', '/reg'];
+router.beforeEach((to, from, next) => {
+  if (kuky_Authorization.get()) {
+    if (to.path === '/login') {
+      next({ path: firstPage });
+    } else if (accessRoutes.some((route) => route.path === to.path)) {
+      next();
+    } else {
+      console.log('无权限访问');
+      next({ path: '/noPer' }); // 如果访问的路由不在accessRoutes中,则去无权限页面
+    }
+  } else {
+    // 如果没有 Token
+    if (whiteList.includes(to.path)) {
+      // 如果在免登录的白名单中,则允许进入
+      next();
+    } else {
+      // 其他没有访问权限的页面将被重定向到登录页面
+      next('/login');
+    }
+  }
+});

+ 2 - 7
src/router/index.js

@@ -1,14 +1,9 @@
 import { createRouter, createWebHashHistory } from 'vue-router';
 import { systemRoutes } from './route';
-import { formatRoutes } from '../utils/permission';
-import { localST_RoutesList } from '../base/storage';
-
-const routesList = JSON.parse(localST_RoutesList.getItem());
-const accessRoutes = formatRoutes(routesList);
-
+import { accessRoutes } from '../utils/permission';
 const router = createRouter({
   history: createWebHashHistory(),
-  routes: [...systemRoutes],
+  routes: [...systemRoutes, ...accessRoutes],
   scrollBehavior: () => ({ left: 0, top: 0 })
 });
 

+ 42 - 41
src/router/route.js

@@ -6,47 +6,48 @@ import Home from '../views/Home.vue';
 export const systemRoutes = [
   { path: '/', component: Home, redirect: '/chat/qa' },
 
-  // 登录与注册
+  // 登录与注册 白名单页面
   { path: '/login', component: () => import('../views/Login.vue') },
   { path: '/reg', component: () => import('../views/Register.vue') },
-
-  // 会话
-  { path: '/chat', component: () => import('../views/Conversation.vue') },
-  { path: '/chat/qa', component: () => import('../views/ConversationQA.vue') },
-  { path: '/chat/history', component: () => import('../views/ConversationHistory.vue') },
-  { path: '/chat/board', component: () => import('../views/ConversationBoard.vue') },
-
-  // 知识库
-  { path: '/knowledge', component: () => import('../views/Knowledge.vue') },
-  { path: '/knowledge/detail', component: () => import('../views/KnowledgeDetail.vue') },
-  // 模型
-  { path: '/model', component: () => import('../views/Model.vue') },
-  // Agent
-  { path: '/agent', component: () => import('../views/Agent.vue') },
-  // 智能体
-  { path: '/intelligent', component: () => import('../views/Intelligent.vue') },
-  // dify智能体详情
-  { path: '/intelligent/detail', component: () => import('../views/difyDetail.vue') },
-
-  // 权限管理
-  {
-    path: '/permission',
-    component: () => import('../views/layout/LayoutPermission.vue'),
-    children: [
-      { path: '/permission/account', component: () => import('../views/PermissionAccount.vue') },
-      { path: '/permission/org', component: () => import('../views/PermissionOrganization.vue') },
-      { path: '/permission/resource', component: () => import('../views/PermissionResource.vue') },
-      { path: '/permission/role', component: () => import('../views/PermissionRole.vue') },
-      { path: '/permission/group', component: () => import('../views/PermissionGroup.vue') }
-    ]
-  },
-
-  // 个人中心
-  { path: '/profile', component: () => import('../views/Profiles.vue') },
-  { path: '/setting', component: () => import('../views/Settings.vue') },
-
-  { path: '/xiaoshu', component: () => import('../views/Xiaoshu.vue') },
-
-  { path: '/ragchat', component: () => import('../views/RagFlowChat.vue') },
-  { path: '/about', component: () => import('../views/About.vue') }
+  { path: '/noPer', component: () => import('../views/NoPer.vue') }
+
+  // // 会话
+  // { path: '/chat', component: () => import('../views/Conversation.vue') },
+  // { path: '/chat/qa', component: () => import('../views/ConversationQA.vue') },
+  // { path: '/chat/history', component: () => import('../views/ConversationHistory.vue') },
+  // { path: '/chat/board', component: () => import('../views/ConversationBoard.vue') },
+
+  // // 知识库
+  // { path: '/knowledge', component: () => import('../views/Knowledge.vue') },
+  // { path: '/knowledge/detail', component: () => import('../views/KnowledgeDetail.vue') },
+  // // 模型
+  // { path: '/model', component: () => import('../views/Model.vue') },
+  // // Agent
+  // { path: '/agent', component: () => import('../views/Agent.vue') },
+  // // 智能体
+  // { path: '/intelligent', component: () => import('../views/Intelligent.vue') },
+  // // dify智能体详情
+  // { path: '/intelligent/detail', component: () => import('../views/difyDetail.vue') },
+
+  // // 权限管理
+  // {
+  //   path: '/permission',
+  //   component: () => import('../views/layout/LayoutPermission.vue'),
+  //   children: [
+  //     { path: '/permission/account', component: () => import('../views/PermissionAccount.vue') },
+  //     { path: '/permission/org', component: () => import('../views/PermissionOrganization.vue') },
+  //     { path: '/permission/resource', component: () => import('../views/PermissionResource.vue') },
+  //     { path: '/permission/role', component: () => import('../views/PermissionRole.vue') },
+  //     { path: '/permission/group', component: () => import('../views/PermissionGroup.vue') }
+  //   ]
+  // },
+
+  // // 个人中心
+  // { path: '/profile', component: () => import('../views/Profiles.vue') },
+  // { path: '/setting', component: () => import('../views/Settings.vue') },
+
+  // { path: '/xiaoshu', component: () => import('../views/Xiaoshu.vue') },
+
+  // { path: '/ragchat', component: () => import('../views/RagFlowChat.vue') },
+  // { path: '/about', component: () => import('../views/About.vue') }
 ];

+ 37 - 22
src/utils/permission.js

@@ -1,6 +1,5 @@
-import { localST_UserInfo } from '../base/storage';
+import { localST_UserInfo, localST_RoutesList } from '../base/storage';
 
-import Intelligent from '../views/Intelligent.vue';
 // 判断是否有该权限
 export const hasPermission = (str) => {
   const { permissions } = JSON.parse(localST_UserInfo.getItem());
@@ -11,28 +10,33 @@ export const hasPermission = (str) => {
 export const formatRoutes = (data) => {
   const routes = [];
 
-  // 正确写法
-  let modules = import.meta.glob('../views/*.vue'); // 获取到所有组件的路径
-
   function convertRoute(item) {
-    if (modules[`../views/${item.component}.vue`]) {
-      // 过滤为-的节点
-      const route = {
-        path: item.path != '-' ? item.path : '/',
-        component: () => modules[`../views/${item.component}.vue`]
-      };
-
-      if (item.children && item.children.length > 0) {
-        route.children = item.children.map((child) => convertRoute(child));
-      }
-
-      return route;
+    // 如果没有地址或者没有组件,则直接过滤
+    if (item.path === '-' || item.component === '-') {
+      return null;
+    }
+
+    const route = {
+      path: item.path,
+      // 判断是layout还是view
+      component: item.component.split('layout/')[1]
+        ? () => import(`../views/layout/${item.component.split('layout/')[1]}.vue`)
+        : () => import(`../views/${item.component}.vue`)
+    };
+
+    if (item.children && item.children.length > 0) {
+      route.children = item.children.map((child) => convertRoute(child)).filter((childRoute) => childRoute !== null);
     }
+
+    // 只返回非null的route对象
+    return route;
   }
 
   function addRoutes(item) {
     const formattedRoute = convertRoute(item);
-    routes.push(formattedRoute);
+    if (formattedRoute !== null) {
+      routes.push(formattedRoute);
+    }
   }
 
   data.forEach((item) => {
@@ -41,9 +45,20 @@ export const formatRoutes = (data) => {
 
   return routes;
 };
+// 获取有权限的路由
+const routesList = JSON.parse(localST_RoutesList.getItem());
+const formattedRoutes = formatRoutes(routesList);
+export const accessRoutes = formattedRoutes;
 
-const menuData = [];
-
-const formattedRoutes = formatRoutes(menuData);
+// 获取有权限的第一个路由
+const firstRoute = (() => {
+  let page;
+  if (accessRoutes.length > 0) {
+    // 检查第一个路由是否有children
+    const firstPage = accessRoutes[0];
+    page = firstPage.children && firstPage.children.length > 0 ? firstPage.children[0].path : firstPage.path;
+  }
+  return page;
+})();
 
-console.log(JSON.stringify(formattedRoutes, null, 2));
+export const firstPage = firstRoute;

+ 23 - 0
src/views/NoPer.vue

@@ -0,0 +1,23 @@
+<template>
+  <a-result status="warning" title="抱歉,您无权限访问此页面">
+    <template #subtitle>
+      您没有权限访问此页面,请联系管理员
+    </template>
+
+    <template #extra>
+      <a-space>
+        <a-button type='primary' @click="handleBack">返回</a-button>
+      </a-space>
+    </template>
+  </a-result>
+</template>
+
+<script setup>
+import { useRouter } from 'vue-router';
+
+const router = useRouter();
+
+const handleBack = () => {
+  router.back();
+}
+</script>

+ 0 - 2
src/views/common/header-btns/ModalLogout.vue

@@ -10,7 +10,6 @@
 import { computed } from 'vue';
 import { useRouter } from 'vue-router';
 import { kuky_Authorization } from '../../../base/storage';
-import { resetHasRouteFlag } from '../../../router/guard';
 const props = defineProps({
   visible: {
     type: Boolean,
@@ -24,7 +23,6 @@ const showModal = computed(() => props.visible);
 const handleOk = () => {
   kuky_Authorization.remove();
   // 重置路由守卫标志位
-  resetHasRouteFlag();
   router.push({ path: '/login', replace: true });
   emit('update:visible', false);
 };