Преглед на файлове

更新路由守卫:
1、只保留一个登录入口
2、加入平台入口(用来管理权限限制)
3、优化缓存username和nickname

liyanbo преди 1 месец
родител
ревизия
5fc9497a1e

+ 4 - 12
src/components/user/UserInfoPopover.vue

@@ -98,6 +98,7 @@ const handleVisibleChange = (visible) => {
 // 获取用户信息
 const fetchUserInfo = async () => {
   userInfo.value.userName = localStorage.getItem('userName') || import.meta.env.VITE_APP_DEFAULT_LOGIN_USERNAME
+  userInfo.value.nickname = localStorage.getItem('nickName')
 
   try {
     const userId = localStorage.getItem('userId');
@@ -118,8 +119,9 @@ const fetchUserInfo = async () => {
         userInfo.value.blocklyExpireTime = formatLocalDateTime(user.blocklyExpireTime);
         userInfo.value.aiCourseExpireTime = formatLocalDateTime(user.aiCourseExpireTime);
       }
-      localStorage.setItem('userName', user.nickname || user.userName);
-      localStorage.setItem('userInfo', user.nickname || user.userName);
+
+      localStorage.setItem('userName', user.username);
+      localStorage.setItem('nickName', user.nickname);
 
       //缓存用户角色路由
       setCacheWithExpiry(CONFIG.USER_ROLE_ROUTE_KEY, user.roleRouteSet);
@@ -168,18 +170,8 @@ const handleActivation = () => {
 onMounted(() => {
   // 获取用户信息
   fetchUserInfo()
-  // storage事件监听器,监听其他标签页对localStorage的修改
-  window.addEventListener('storage', (e) => {
-    if (e.key === 'userName') {
-      updateUserName()
-    }
-  })
 })
 
-
-
-
-
 </script>
 
 <style scoped lang="scss">

+ 49 - 47
src/router/index.js

@@ -5,30 +5,22 @@ import {refreshAllDictData} from "@/utils/dictUtils.js";
 
 
 const routes = [
-  {
-    path: '/',
-    redirect: () => {
-      // 判断域名,返回对应路由
-      if (window.location.hostname === 'blockly.learn-ai.com.cn') {
-        return '/blockly-login';
-      } else {
-        return '/login';
-      }
-    }
-  },
+  { path: '/', component: () => import('../views/Login.vue') },
   { path: '/login', component: () => import('../views/Login.vue') },
+
   // 免登录
-  { path: '/quick-login', component: () => import('../views/QuickLogin.vue') },
-  { path: '/promotion-login', component: () => import('../views/PromotionLogin.vue') },
-  //【AI实验课】登录
-  { path: '/ai-login', component: () => import('../views/AiCourseLogin.vue') },
-  //【blockly编程课】免租户登录
-  { path: '/blockly-login', meta: {TENANT: '内部测试租户'}, component: () => import('../views/BlocklyLogin.vue') },
+  // { path: '/quick-login', component: () => import('../views/QuickLogin.vue') },
+  // { path: '/promotion-login', component: () => import('../views/PromotionLogin.vue') },
+  // //【AI实验课】登录
+  // { path: '/ai-login', component: () => import('../views/AiCourseLogin.vue') },
+  // //【blockly编程课】免租户登录
+  // { path: '/blockly-login', meta: {TENANT: '内部测试租户'}, component: () => import('../views/BlocklyLogin.vue') },
   // 网页版登录注册页
   {
     path: '/register-login',
     component: () => import('../views/RegisterLogin.vue')
   },
+
   // 管理界面
   {
     path: '/management-interface',
@@ -198,8 +190,7 @@ const homeRoutes = {
     '/ai-grandcanal',
     '/ai-plantexperts',
     '/virtual-laboratory',
-    '/ai-poetry',
-    '/management-interface',
+    '/ai-poetry'
   ]
 }
 
@@ -229,14 +220,19 @@ const aiCourseRoutes = {
   ]
 }
 
+// 管理界面路由配置
+const managementRoutes = {
+  home: '/management-interface',
+  login: '/login',
+  role: 'management',
+  children: [
+    '/management-interface'
+  ]
+}
+
 // 定义登录页面与主页的映射关系
 const loginToHomeMap = {
-  '/login': homeRoutes.home,
-  '/quick-login': homeRoutes.home,
-  '/promotion-login': homeRoutes.home,
-  '/blockly-login': blocklyRoutes.home,
-  '/ai-login': aiCourseRoutes.home,
-   '/register-login': homeRoutes.home
+  '/login': managementRoutes.home
 }
 
 const router = createRouter({
@@ -247,6 +243,24 @@ const router = createRouter({
 // 导航守卫
 router.beforeEach(async (to, from, next) => {
 
+  // 检查登录状态
+  const isLoggedIn = localStorage.getItem('isLoggedIn') === 'true'
+  
+  // 注册页面始终允许访问,不需要登录状态
+  if (to.path === '/register-login') {
+    next()
+    return
+  }
+  
+  // 允许未登录用户访问的页面列表
+  const allowedPages = Object.keys(loginToHomeMap)
+  
+  // 如果未登录且不是允许访问的页面,重定向到登录页
+  if (!isLoggedIn && !allowedPages.includes(to.path)) {
+    next('/login')
+    return
+  }
+
   if (to.path === "/"){
     await refreshAllDictData()
     await refreshRoleRoute()
@@ -263,6 +277,8 @@ router.beforeEach(async (to, from, next) => {
     return
   }
 
+  // 注册页面已经在前面处理过,这里不需要再处理
+
   // 获取当前登录类型
   const loginPath = localStorage.getItem('loginPath')
 
@@ -276,26 +292,12 @@ router.beforeEach(async (to, from, next) => {
   const hasHomePermission = roleRouteSet.includes(homeRoutes.role)
   const hasBlocklyPermission = roleRouteSet.includes(blocklyRoutes.role)
   const hasAiCoursePermission = roleRouteSet.includes(aiCourseRoutes.role)
+  const hasManagementPermission = true // 管理界面默认允许所有登录用户访问
 
-  // 如果用户没有当前登录类型对应的权限,切换到用户有权限的主页
-  if (!((allowedHome === homeRoutes.home && hasHomePermission) ||
-      (allowedHome === blocklyRoutes.home && hasBlocklyPermission) ||
-      (allowedHome === aiCourseRoutes.home && hasAiCoursePermission))) {
-    // 找到用户有权限的主页
-    if (hasAiCoursePermission) {
-      allowedHome = aiCourseRoutes.home
-    } else if (hasBlocklyPermission) {
-      allowedHome = blocklyRoutes.home
-    } else if (hasHomePermission) {
-      allowedHome = homeRoutes.home
-    } else {
-      // 如果没有任何权限,可以考虑重定向到登录页面或其他公共页面
-      next(loginPath)
-      return
-    }
-  }
   // 检查目标路由是否在允许的范围内
-  if ((to.path === homeRoutes.home || homeRoutes.children.includes(to.path)) && hasHomePermission) {
+  if ((to.path === managementRoutes.home || managementRoutes.children.includes(to.path)) && hasManagementPermission) {
+    isAllowed = true
+  } else if ((to.path === homeRoutes.home || homeRoutes.children.includes(to.path)) && hasHomePermission) {
     isAllowed = true
   } else if ((to.path === blocklyRoutes.home || blocklyRoutes.children.includes(to.path)) && hasBlocklyPermission) {
     isAllowed = true
@@ -306,11 +308,11 @@ router.beforeEach(async (to, from, next) => {
   if (isAllowed) {
     next()
   } else {
-    // 不允许访问时,重定向到用户有权限的主页
-    if (to.path !== "/")Message().warning('您没有权限访问该页面,已自动切换到您有权限的主页!', true);
-    next(allowedHome)
+    // 不允许访问时,重定向到管理界面
+    if (to.path !== "/")Message().warning('您没有权限访问该页面,已自动切换到管理界面!', true);
+    next(managementRoutes.home)
   }
 })
 export default router;
 
-export { homeRoutes, blocklyRoutes, aiCourseRoutes };
+export { homeRoutes, blocklyRoutes, aiCourseRoutes, managementRoutes };

+ 8 - 6
src/utils/loginUtils.js

@@ -13,7 +13,7 @@ import CryptoJS from 'crypto-js';
 // 消息工具
 import {Message} from './message/Message.js';
 import {CONFIG, refreshRoleRoute} from "@/utils/roleUtils.js";
-import {homeRoutes} from "@/router/index.js";
+import {homeRoutes, managementRoutes} from "@/router/index.js";
 
 // 加密密钥 (从环境变量获取)
 const SECRET_KEY = import.meta.env.VITE_SECRET_KEY;
@@ -144,7 +144,7 @@ const getTenantId = async (tenantName) => {
 }
 
 // 登录逻辑
-const loginLogic = async (loginForm, tenantId, isAuthorized, router, redirectPath) => {
+const loginLogic = async (loginForm, tenantId, isAuthorized, router) => {
   const loginLoading = ref(false)
   const loading = ref()
   const isLoggedIn = ref(false)
@@ -191,10 +191,12 @@ const loginLogic = async (loginForm, tenantId, isAuthorized, router, redirectPat
 
       // 总是存储用户名和租户名称
       localStorage.setItem('tenantName', res.data.tenantName)
+
       // 存储记住我状态
       localStorage.setItem('rememberMe', loginForm.rememberMe)
-      
+
       if (loginForm.rememberMe) {
+        localStorage.setItem('userName', loginForm.username)
         // 保存加密后的密码
         localStorage.setItem('password', encryptPassword(loginForm.password))
       } else {
@@ -214,7 +216,7 @@ const loginLogic = async (loginForm, tenantId, isAuthorized, router, redirectPat
       await refreshRoleRouteData();
 
       // 登录成功后,跳转到指定的页面
-      router.push(redirectPath)
+      router.push(managementRoutes.home)
 
       return true
     } else if (res.code === 1002000009) {
@@ -260,7 +262,7 @@ const loadLoginData = (loginData) => {
 }
 
 // 检查登录状态
-const checkLoginStatus = (router, redirectPath) => {
+const checkLoginStatus = (router) => {
   const storedStatus = localStorage.getItem('isLoggedIn')
   if (storedStatus === 'true') {
 
@@ -270,7 +272,7 @@ const checkLoginStatus = (router, redirectPath) => {
     // 获取角色路由数据
     refreshRoleRouteData();
 
-    router.push(redirectPath)
+    router.push(managementRoutes.home)
     return true
   }
   return false

+ 5 - 5
src/views/AiCourseLogin.vue

@@ -17,7 +17,7 @@
             label-width="0px"
             class="input-item"
         >
-          <el-form-item prop="tenantName" v-show="tenantOpen">
+          <el-form-item prop="tenantName" v-if="tenantOpen">
             <el-input v-model="loginData.loginForm.tenantName"
                       :prefix-icon="HomeFilled"
                       placeholder="学校"
@@ -109,7 +109,7 @@ import {
   checkLoginStatus,
   generateRules
 } from '@/utils/loginUtils.js'
-import {aiCourseRoutes} from "@/router/index.js";
+import {aiCourseRoutes, managementRoutes} from "@/router/index.js";
 
 const router = useRouter()
 
@@ -174,7 +174,7 @@ const handleLogin = async () => {
       }
 
       // 调用登录逻辑
-      await loginLogic(loginData.value.loginForm, tenantId, isAuthorized, router, aiCourseRoutes.home)
+      await loginLogic(loginData.value.loginForm, tenantId, isAuthorized, router)
     }
   })
 }
@@ -190,8 +190,8 @@ onMounted(() => {
     router.replace(aiCourseRoutes.login)
   }
 
-  // 检查登录状态,如果已登录则直接跳转到首页
-  checkLoginStatus(router, aiCourseRoutes.home)
+  // 检查登录状态,如果已登录则直接跳转到管理界面
+  checkLoginStatus(router)
 
   const handleKeyPress = (event) => {
     // 检查是否按下回车键(keyCode 13)

+ 5 - 5
src/views/BlocklyLogin.vue

@@ -17,7 +17,7 @@
             label-width="0px"
             class="input-item"
         >
-          <el-form-item prop="tenantName" v-show="tenantOpen">
+          <el-form-item prop="tenantName" v-if="tenantOpen">
             <el-input v-show="!tenantNameQuery"
                       v-model="loginData.loginForm.tenantName"
                       :prefix-icon="HomeFilled"
@@ -110,7 +110,7 @@ import {
   checkLoginStatus,
   generateRules
 } from '@/utils/loginUtils.js'
-import {blocklyRoutes} from "@/router/index.js";
+import {blocklyRoutes, managementRoutes} from "@/router/index.js";
 
 const router = useRouter()
 
@@ -178,7 +178,7 @@ const handleLogin = async () => {
       }
 
       // 调用登录逻辑
-      await loginLogic(loginData.value.loginForm, tenantId, isAuthorized, router, blocklyRoutes.home)
+      await loginLogic(loginData.value.loginForm, tenantId, isAuthorized, router)
     }
   })
 }
@@ -197,8 +197,8 @@ onMounted(() => {
     router.replace(blocklyRoutes.login)
   }
 
-  // 检查登录状态,如果已登录则直接跳转到首页
-  checkLoginStatus(router, blocklyRoutes.home)
+  // 检查登录状态,如果已登录则直接跳转到管理界面
+  checkLoginStatus(router)
 
   const handleKeyPress = (event) => {
     // 检查是否按下回车键(keyCode 13)

+ 5 - 5
src/views/Login.vue

@@ -17,7 +17,7 @@
             label-width="0px"
             class="input-item"
         >
-          <el-form-item prop="tenantName" v-show="tenantOpen">
+          <el-form-item prop="tenantName" v-if="tenantOpen">
             <el-input
                 v-model="loginData.loginForm.tenantName"
                 :prefix-icon="HomeFilled"
@@ -110,7 +110,7 @@ import {
   checkLoginStatus,
   generateRules
 } from '@/utils/loginUtils.js'
-import {homeRoutes} from "@/router/index.js";
+import {homeRoutes, managementRoutes} from "@/router/index.js";
 
 const router = useRouter()
 
@@ -173,7 +173,7 @@ const handleLogin = async () => {
       }
 
       // 调用登录逻辑
-      await loginLogic(loginData.value.loginForm, tenantId, isAuthorized, router, homeRoutes.home)
+      await loginLogic(loginData.value.loginForm, tenantId, isAuthorized, router)
     }
   })
 }
@@ -188,8 +188,8 @@ onMounted(() => {
     router.replace(homeRoutes.login)
   }
 
-  // 检查登录状态,如果已登录则直接跳转到首页
-  checkLoginStatus(router, homeRoutes.home)
+  // 检查登录状态,如果已登录则直接跳转到管理界面
+  checkLoginStatus(router)
 
   const handleKeyPress = (event) => {
     // 检查是否按下回车键(keyCode 13)

+ 102 - 3
src/views/ManagementInterface.vue

@@ -10,23 +10,78 @@
         </div>
       </div>
     </div>
+    <div class="main-content">
+      <div class="home-buttons">
+        <el-button 
+          v-if="hasHomePermission" 
+          type="primary" 
+          @click="navigateToHome(homeRoutes.home)"
+          class="home-button"
+        >
+          通识课首页
+        </el-button>
+        <el-button 
+          v-if="hasBlocklyPermission" 
+          type="success" 
+          @click="navigateToHome(blocklyRoutes.home)"
+          class="home-button"
+        >
+          Blockly编程课首页
+        </el-button>
+        <el-button 
+          v-if="hasAiCoursePermission" 
+          type="warning" 
+          @click="navigateToHome(aiCourseRoutes.home)"
+          class="home-button"
+        >
+          AI实验课首页
+        </el-button>
+      </div>
+    </div>
   </div>
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, computed } from 'vue'
 import { useRouter } from 'vue-router'
 import UserInfoPopover from '@/components/user/UserInfoPopover.vue'
+import { homeRoutes, blocklyRoutes, aiCourseRoutes, managementRoutes } from '@/router'
+import { CONFIG } from '@/utils/roleUtils.js'
+import { Message } from '@/utils/message/Message.js'
 
 // 平台标题响应式变量
 const platformTitle = ref(import.meta.env.VITE_APP_TITLE)
+// 获取当前路由对象
+const router = useRouter()
+
+// 计算用户权限
+const hasHomePermission = computed(() => {
+  const roleRouteStr = localStorage.getItem(CONFIG.USER_ROLE_ROUTE_KEY)
+  const roleRouteSet = roleRouteStr ? JSON.parse(roleRouteStr) : []
+  return roleRouteSet.includes(homeRoutes.role)
+})
+
+const hasBlocklyPermission = computed(() => {
+  const roleRouteStr = localStorage.getItem(CONFIG.USER_ROLE_ROUTE_KEY)
+  const roleRouteSet = roleRouteStr ? JSON.parse(roleRouteStr) : []
+  return roleRouteSet.includes(blocklyRoutes.role)
+})
+
+const hasAiCoursePermission = computed(() => {
+  const roleRouteStr = localStorage.getItem(CONFIG.USER_ROLE_ROUTE_KEY)
+  const roleRouteSet = roleRouteStr ? JSON.parse(roleRouteStr) : []
+  return roleRouteSet.includes(aiCourseRoutes.role)
+})
+
 // 更新平台标题
 const updatePlatformTitle = () => {
   platformTitle.value = localStorage.getItem('tenantName') || import.meta.env.VITE_APP_DEFAULT_LOGIN_TENANT
 }
 
-// 获取当前路由对象
-const router = useRouter()
+// 导航到对应首页
+const navigateToHome = (path) => {
+  router.push(path)
+}
 
 onMounted(() => {
   // 初始化平台标题
@@ -64,6 +119,50 @@ window.updateTenantName = (newName) => {
   flex-direction: column;
 }
 
+.main-content {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  padding: rpx(40);
+}
+
+.main-content h2 {
+  color: white;
+  font-size: rpx(24);
+  margin-bottom: rpx(60);
+  text-align: center;
+}
+
+.home-buttons {
+  display: flex;
+  flex-direction: column;
+  gap: rpx(20);
+  width: 100%;
+  max-width: rpx(400);
+}
+
+.home-button {
+  width: 100%;
+  height: rpx(60);
+  font-size: rpx(18);
+  border-radius: rpx(8);
+}
+
+@media (min-width: 768px) {
+  .home-buttons {
+    flex-direction: row;
+    justify-content: center;
+    flex-wrap: wrap;
+  }
+  
+  .home-button {
+    width: rpx(200);
+    margin: 0 rpx(10);
+  }
+}
+
 .box-1 {
   width: 100%;
   min-height: rpx(50);

+ 2 - 2
src/views/laboratory/ExperimentalTheme.vue

@@ -105,7 +105,7 @@ import UserInfoPopover from '@/components/user/UserInfoPopover.vue'
 import { removeLocalStorageKey} from '@/utils/loginUtils.js'
 // 实验课主题接口
 import { getThemeExperimentList } from '@/api/laboratory/index.js'
-import {aiCourseRoutes, homeRoutes} from "@/router/index.js";
+import { managementRoutes} from "@/router/index.js";
 import {scrollToCenter} from "@/utils/pageCss/scrollToCenter.js";
 
 // 常量定义
@@ -247,7 +247,7 @@ const goToProgrammingList = (experiment, index) => {
 const goToHomePage = () => {
   localStorage.removeItem(blocklyActiveButton.value)
 
-   router.push({path: homeRoutes.home})
+   router.push({path: managementRoutes.home})
 }
 onMounted(() => {
   // 获取实验主题列表

+ 2 - 2
src/views/programming/ProgrammingGame.vue

@@ -89,7 +89,7 @@ import UserInfoPopover from '@/components/user/UserInfoPopover.vue'
 
 // 退出登录
 import { removeLocalStorageKey} from '@/utils/loginUtils.js'
-import {blocklyRoutes, homeRoutes} from "@/router/index.js";
+import { managementRoutes} from "@/router/index.js";
 import {scrollToCenter} from "@/utils/pageCss/scrollToCenter.js";
 
 
@@ -212,7 +212,7 @@ const goToHomePage = () => {
   localStorage.removeItem(blocklyActiveButton.value)
 
   router.push({
-    path: homeRoutes.home
+    path: managementRoutes.home
   })
 }