瀏覽代碼

feat:前端登录通过portal

lalala 1 年之前
父節點
當前提交
a9fc526f3e

+ 4 - 0
src/apis/auth.ts

@@ -16,6 +16,10 @@ const authApis = {
         })
     },
 
+    authToken:(token: string) => {
+        return axiosInstance.get(`${AUTH_PREFIX}/token?token=${encodeURIComponent(token)}`);
+    }
+
 }
 
 export default authApis

+ 5 - 3
src/layout/Header/Header.vue

@@ -80,9 +80,11 @@ const handleSelect = (index: string) => {
 
 const handleCommand = (command: string) => {
   if (command === "logout") {
-    localStorage.clear();
-    store.clear();
-    router.push({ path: "/login" });
+    store.setUser(null);
+    store.setToken(null);
+    localStorage.setItem('Authorization', null);
+    localStorage.setItem('User', null); 
+    router.push({ path: "/" });
   } else if (command === "profile") {
     router.push({ path: "/profile" });
   }

+ 51 - 22
src/router/index.ts

@@ -1,3 +1,4 @@
+import authApis  from '@/apis/auth';
 import { createRouter, createWebHistory } from 'vue-router'
 import {useStore} from "@/store";
 
@@ -17,7 +18,11 @@ const router = createRouter({
     // 登录与注册
     {
       path: "/",
-      redirect: "/login"
+      redirect: () => {
+        window.location.href = "https://p-nju.seec.seecoder.cn/login?from=https://air.seec.seecoder.cn/";
+        // {本地门户首页地址}?from={本地eai首页地址}
+        return "/"; // 占位返回值,实际不会执行
+    },
     },
     {
       path: '/login',
@@ -178,27 +183,51 @@ const router = createRouter({
 /*
   路由守卫
  */
-router.beforeEach((to) => {
-  const store = useStore()
-  // 判断是否是登录页面,如果是则直接放行
-  if (to.path === '/login' || to.path === '/register' || to.path === '/passwordChange'|| to.path === '/admin/login') {
-    return true;
-  }
-  // 判断是否登录,未登录需要登录
-  if(!("role" in store.user)){
-    router.push('/login')
-  }
-  let role = store.user.role
-  // 1.守卫管理员权限界面
-  if(to.meta.roles != null){
-    for(let i = 0; i < to.meta.roles.length; i++){
-      if(to.meta.roles[i] == role){
-        console.log("路由权限满足")
-        return
-      }
+  router.beforeEach(async (to) => {
+    const store = useStore();
+    const publicPaths = ['/login', '/register', '/passwordChange', '/admin/login'];
+    // 1. 检查URL中的token
+    const urlToken = new URLSearchParams(window.location.search).get('token');
+    if (urlToken) {
+      try {
+        // 等待 token 验证完成
+        const res = await authApis.authToken(urlToken || store.token);
+        const data = res.data.data;
+        // 存储用户状态
+        store.setUser(data);
+        store.setToken(data?.token);
+        localStorage.setItem('Authorization', data?.token);
+        localStorage.setItem('User', JSON.stringify(data));
+        // 清除 URL 中的 token
+        if (urlToken) {
+            window.history.replaceState({}, '', to.path);
+        }
+
+        // 如果当前路径是公开路径,允许继续;否则跳转到首页
+        if (!publicPaths.includes(to.path)) {
+            return '/home';
+        }
+    } catch (error) {
+        console.error('Token验证失败:', error);
+        // 验证失败,清除无效的 token
+        store.setUser(null);
+        store.setToken(null);
+        localStorage.removeItem('Authorization');
+        localStorage.removeItem('User');
     }
-    router.push('/login')
-  }
-})
+    }
+  
+    if (publicPaths.includes(to.path)) return true;
+  
+    if (!store.user?.role) {
+      return '/login';
+    }
+  
+    if (to.meta?.roles && !to.meta.roles.includes(store.user.role)) {
+      return '/login';
+    }
+  
+    return true;
+  });
 
 export default router

+ 1 - 0
src/types/query.ts

@@ -3,6 +3,7 @@ import type {AssignmentCompletionStatus} from "@/types/enums";
 export interface CourseQuery {
     courseId:number;
     teacherId:number;
+    teacherPid:number;
     studentId:number;
     courseName:string;
     semester:string;

+ 1 - 0
src/types/user.ts

@@ -11,6 +11,7 @@ export interface IUser {
     birthday: string|null,
     phone: string|null,
     contentEmail: string|null,
+    pid:number
 }
 
 export interface ILoginUserFrom {

+ 1 - 1
src/utils/convertUtil.ts

@@ -28,7 +28,7 @@ export function convertIUserToUserUpdateDTO(user: IUser): UserUpdateDTO {
  */
 export function convertImageUrl(url: string, altText: string): string {
   // 如果url为空,生成一个课程名图片
-  if (url === null || url === "") {
+  if (url === null || url === "" || url === "null") {
     // 创建画布
     const canvas = document.createElement("canvas");
     // 绘制文字环境

+ 1 - 0
src/views/CorrectPage/CoursePage.vue

@@ -93,6 +93,7 @@
     studentId:null,
     courseName:null,
     semester:null,
+    teacherPid:store.user.pid
   })
 
   let courseName = ref('')

+ 2 - 0
src/views/CoursePage/CoursePage.vue

@@ -178,6 +178,7 @@
   const query = reactive<CourseQuery>({
     courseId:0,
     teacherId:store.user.id,
+    teacherPid:Number(store.user.pid),
     studentId:0,
     courseName:"",
     semester:"",
@@ -233,6 +234,7 @@
       Object.assign(query, {
         courseId: null,
         teacherId: store.user.id,
+        teacherPid:Number(store.user.pid),
         studentId: null,
         courseName: courseName.value,
         semester: null,

+ 2 - 1
src/views/CourseSquare/component/CourseDetails/index.vue

@@ -15,7 +15,7 @@
         </div>
         <div class="item">
           <span class="item-title">任课老师:</span>
-          {{dataForm.teacherNames?.join(",")}}
+          {{dataForm.teacherNames?.filter(Boolean).join(",")}}
         </div>
         <div class="item">
           <span class="item-title">目标学生:</span>
@@ -561,6 +561,7 @@ function isDisabled(){
 onMounted(() => {
   getCourse()
   getHomeworkList()
+
   if(role == 'student') isShowCode()
   if(role == 'teachers') isShowEdit()