- ✅ list.vue 页面加载成功
+
+
+
+ 教师课程评价列表
+
+
+
+
+
+
+
+
+
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/NotFound.vue b/src/components/NotFound.vue
new file mode 100644
index 0000000..97f6ace
--- /dev/null
+++ b/src/components/NotFound.vue
@@ -0,0 +1,336 @@
+
+
+
+
404
+
页面未找到
+
+ 您访问的页面不存在或已被移除
+
路径: {{ currentPath }}
+
+
+
+
+
+
+
+
您可能想访问:
+
+ - 首页
+ - 登录
+ - 注册
+ - 学生主页
+ - 教师主页
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/frontend/FrontLayout.vue b/src/frontend/FrontLayout.vue
deleted file mode 100644
index b204890..0000000
--- a/src/frontend/FrontLayout.vue
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/frontend/Header.vue b/src/frontend/Header.vue
deleted file mode 100644
index c12295c..0000000
--- a/src/frontend/Header.vue
+++ /dev/null
@@ -1,186 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/router/backend.ts b/src/router/backend.ts
index 7210c73..4b71034 100644
--- a/src/router/backend.ts
+++ b/src/router/backend.ts
@@ -31,35 +31,136 @@ const backendRouter = [
path: '/admin',
component: AdminLayout,
redirect: '/admin/dashboard',
+ meta: {
+ userType: 'admin'
+ },
children: [
- { path: 'dashboard', component: Dashboard, meta: { title: '控制台' } },
+ {
+ path: 'dashboard',
+ component: Dashboard,
+ meta: {
+ title: '控制台',
+ userType: 'admin'
+ }
+ },
// 用户管理
- { path: 'studentList', component: StudentList, meta: { title: '学生管理' } },
- { path: 'teacherList', component: TeacherList, meta: { title: '教师管理' } },
- { path: 'users/list', component: UserList, meta: { title: '用户列表' } },
- { path: 'users/status', component: Status, meta: { title: '用户状态管理' } },
+ {
+ path: 'studentList',
+ component: StudentList,
+ meta: {
+ title: '学生管理',
+ userType: 'admin'
+ }
+ },
+ {
+ path: 'teacherList',
+ component: TeacherList,
+ meta: {
+ title: '教师管理',
+ userType: 'admin'
+ }
+ },
+ {
+ path: 'users/list',
+ component: UserList,
+ meta: {
+ title: '用户列表',
+ userType: 'admin'
+ }
+ },
+ {
+ path: 'users/status',
+ component: Status,
+ meta: {
+ title: '用户状态管理',
+ userType: 'admin'
+ }
+ },
// 系部管理
- { path: 'departments/list', component: DepartmentsList, meta: { title: '系部管理' } },
- { path: 'departments/add', component: AddDepartments, meta: { title: '添加系部' } },
- { path: 'departments/required-courses', component: RequiredCourses, meta: { title: '必修课程设置' } },
+ {
+ path: 'departments/list',
+ component: DepartmentsList,
+ meta: {
+ title: '系部管理',
+ userType: 'admin'
+ }
+ },
+ {
+ path: 'departments/add',
+ component: AddDepartments,
+ meta: {
+ title: '添加系部',
+ userType: 'admin'
+ }
+ },
+ {
+ path: 'departments/required-courses',
+ component: RequiredCourses,
+ meta: {
+ title: '必修课程设置',
+ userType: 'admin'
+ }
+ },
// 课程管理
- { path: 'courses/list', component: CoursesList, meta: { title: '课程管理' } },
- { path: 'courses/add', component: AddCourse, meta: { title: '添加课程' } },
- { path: 'courses/enrollment', component: CoursesEnrollment, meta: { title: '状态管理' } },
+ {
+ path: 'courses/list',
+ component: CoursesList,
+ meta: {
+ title: '课程管理',
+ userType: 'admin'
+ }
+ },
+ {
+ path: 'courses/add',
+ component: AddCourse,
+ meta: {
+ title: '添加课程',
+ userType: 'admin'
+ }
+ },
+ {
+ path: 'courses/enrollment',
+ component: CoursesEnrollment,
+ meta: {
+ title: '状态管理',
+ userType: 'admin'
+ }
+ },
// 选课管理
- { path: 'enrollment/statistics', component: Enrollmentstatistics, meta: { title: '统计显示' } },
+ {
+ path: 'enrollment/statistics',
+ component: Enrollmentstatistics,
+ meta: {
+ title: '统计显示',
+ userType: 'admin'
+ }
+ },
// 评价显示模块
- { path: 'reviews/statistics', component: Reviewsstatistics, meta: { title: '评价显示' } },
+ {
+ path: 'reviews/statistics',
+ component: Reviewsstatistics,
+ meta: {
+ title: '评价显示',
+ userType: 'admin'
+ }
+ },
// echarts
- { path: 'statistics/overview', component: Statisticsoverview, meta: { title: '图像显示' } },
+ {
+ path: 'statistics/overview',
+ component: Statisticsoverview,
+ meta: {
+ title: '图像显示',
+ userType: 'admin'
+ }
+ },
]
}
];
-export default backendRouter;
+export default backendRouter;
\ No newline at end of file
diff --git a/src/router/frontend.ts b/src/router/frontend.ts
index ed753e0..febcde4 100644
--- a/src/router/frontend.ts
+++ b/src/router/frontend.ts
@@ -1,61 +1,112 @@
-// 根据你的实际项目结构导入文件
-import Home from '@/frontend/Home.vue';
-import MainLayout from '@/frontend/FrontLayout.vue';
+import Home from '@/views/Home.vue';
+import MainLayout from '@/views/FrontLayout.vue';
+
+// 教师后台组件
import TeacherLayout from '@/frontend/teacher/TeacherLayout.vue';
import TeacherHome from '@/frontend/teacher/TeacherHome.vue';
-import StudentHome from '@/frontend/student/StudentHome.vue';
import UList15 from '@/frontend/teacher/UList15.vue';
import UList16 from '@/frontend/teacher/UList16.vue';
import UList17 from '@/frontend/teacher/UList17.vue';
import UList13 from '@/frontend/teacher/UList13.vue';
import UList10 from '@/frontend/teacher/UList10.vue';
+// 学生后台组件
+import StudentHome from '@/frontend/student/StudentHome.vue';
+
const frontendRouter = [
{
- path: '/',
+ path: '/dashboard',
component: MainLayout,
children: [
- { path: '', name: 'Home', component: Home },
+ {
+ path: '',
+ name: 'Dashboard',
+ component: Home,
+ meta: { title: '仪表板' }
+ },
]
},
{
path: '/student',
component: MainLayout, // 学生端使用主布局
+ redirect: '/student/home',
children: [
{
path: 'home',
name: 'StudentHome',
component: StudentHome,
- meta: { userType: 'student' }
+ meta: {
+ userType: 'student',
+ title: '学生首页'
+ }
}
+ // 可以在这里添加更多学生页面路由
]
},
{
path: '/teacher',
- component: TeacherLayout,
+ component: TeacherLayout, // 教师使用专用布局
+ redirect: '/teacher/home',
+ meta: {
+ userType: 'teacher'
+ },
children: [
{
path: 'home',
name: 'TeacherHome',
component: TeacherHome,
- meta: { userType: 'teacher' }
+ meta: {
+ userType: 'teacher',
+ title: '教师首页'
+ }
},
- { path: 'ulist15', name: 'UList15', component: UList15 },
- { path: 'ulist16', name: 'UList16', component: UList16 },
- { path: 'ulist17', name: 'UList17', component: UList17 },
- { path: 'ulist10', name: 'UList10', component: UList10 }, // 改为小写
- { path: 'ulist13', name: 'UList13', component: UList13 }
+ {
+ path: 'ulist15',
+ name: 'UList15',
+ component: UList15,
+ meta: {
+ userType: 'teacher',
+ title: 'UList15'
+ }
+ },
+ {
+ path: 'ulist16',
+ name: 'UList16',
+ component: UList16,
+ meta: {
+ userType: 'teacher',
+ title: 'UList16'
+ }
+ },
+ {
+ path: 'ulist17',
+ name: 'UList17',
+ component: UList17,
+ meta: {
+ userType: 'teacher',
+ title: 'UList17'
+ }
+ },
+ {
+ path: 'ulist10',
+ name: 'UList10',
+ component: UList10,
+ meta: {
+ userType: 'teacher',
+ title: 'UList10'
+ }
+ },
+ {
+ path: 'ulist13',
+ name: 'UList13',
+ component: UList13,
+ meta: {
+ userType: 'teacher',
+ title: 'UList13'
+ }
+ }
]
- },
- // 添加重定向,方便访问
- {
- path: '/student',
- redirect: '/student/home'
- },
- {
- path: '/teacher',
- redirect: '/teacher/home'
}
-]; // 修复点:此处已正确结束数组定义
+];
export default frontendRouter;
\ No newline at end of file
diff --git a/src/router/index.ts b/src/router/index.ts
index 9e3349d..0bdf772 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -1,19 +1,151 @@
-// 从 vue-router 导入 createRouter(创建路由实例)和 createWebHistory(使用 HTML5 History 模式)
-import { createRouter, createWebHistory } from 'vue-router';
+import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router'
+import { auth } from '@/utils/auth'
-import frontendRouter from './frontend';
-import backendRouter from './backend';
+// 导入路由模块
+import frontendRouter from './frontend'
+import backendRouter from './backend'
+// 导入组件
+import Login from '@/auth/Login.vue'
+import Register from '@/auth/Register.vue'
+import NotFound from '@/components/NotFound.vue'
+import Home from '@/views/Home.vue'
+import FrontLayout from '@/views/FrontLayout.vue'
-const routes = [
- ...frontendRouter,
- ...backendRouter
-];
+// 定义基础路由
+const baseRoutes: RouteRecordRaw[] = [
+ {
+ path: '/',
+ redirect: '/home'
+ },
+ // 让首页使用布局
+ {
+ path: '/home',
+ component: FrontLayout,
+ children: [
+ {
+ path: '',
+ name: 'Home',
+ component: Home,
+ meta: {
+ public: true,
+ title: '首页'
+ }
+ }
+ ]
+ },
+ {
+ path: '/login',
+ name: 'Login',
+ component: Login,
+ meta: {
+ public: true,
+ title: '登录'
+ }
+ },
+ {
+ path: '/register',
+ name: 'Register',
+ component: Register,
+ meta: { public: true, title: '注册' }
+ }
+]
+
+// 404 路由
+const fallbackRoutes: RouteRecordRaw[] = [
+ {
+ path: '/:pathMatch(.*)*',
+ name: 'NotFound',
+ component: NotFound,
+ meta: {
+ title: '页面未找到'
+ }
+ }
+]
+
+// 合并所有路由
+const routes: RouteRecordRaw[] = [
+ ...baseRoutes,
+ ...frontendRouter,
+ ...backendRouter,
+ ...fallbackRoutes
+]
// 创建路由实例
-export const router = createRouter({
- history: createWebHistory(),
- routes
-});
+const router = createRouter({
+ history: createWebHistory(import.meta.env.BASE_URL),
+ routes,
+ scrollBehavior(to, from, savedPosition) {
+ // 路由切换时的滚动行为
+ if (savedPosition) {
+ return savedPosition
+ } else {
+ return { top: 0 }
+ }
+ }
+})
-export default router;
\ No newline at end of file
+// 全局前置守卫
+router.beforeEach(async (to, from, next) => {
+ try {
+ // 检查用户认证状态
+ const isAuthenticated = auth.isAuthenticated()
+ const isPublicPage = to.meta?.public === true
+
+ console.log(`[Router] 导航到: ${to.path}`)
+ console.log(`[Router] 认证状态: ${isAuthenticated}`)
+ console.log(`[Router] 公开页面: ${isPublicPage}`)
+
+ // 设置页面标题
+ if (to.meta?.title) {
+ document.title = `${to.meta.title} - 管理系统`
+ }
+
+ // 如果是公开页面,直接通过
+ if (isPublicPage) {
+ // 如果已登录用户访问登录页,重定向到对应的仪表板
+ if (isAuthenticated && to.path === '/login') {
+ console.log('[Router] 已登录用户访问登录页,重定向到仪表板')
+ return next(auth.getDefaultRedirectPath())
+ }
+ return next()
+ }
+
+ // 需要认证的页面
+ if (!isAuthenticated) {
+ console.log('[Router] 未认证用户访问受保护页面,重定向到登录页')
+ return next({
+ path: '/login',
+ query: { redirect: to.fullPath }
+ })
+ }
+
+ // 检查用户权限(可选)
+ const userType = auth.getUserType()
+ if (to.meta?.userType && userType !== to.meta.userType) {
+ console.log(`[Router] 用户类型不匹配: ${userType} vs ${to.meta.userType}`)
+ // 重定向到用户对应的首页
+ return next(auth.getDefaultRedirectPath())
+ }
+
+ // 认证通过,继续导航
+ next()
+
+ } catch (error) {
+ console.error('[Router] 导航守卫错误:', error)
+ // 发生错误时重定向到登录页
+ next('/login')
+ }
+})
+
+// 全局后置钩子
+router.afterEach((to, from) => {
+ console.log(`[Router] 导航完成: ${from.path} -> ${to.path}`)
+})
+
+// 路由错误处理
+router.onError((error) => {
+ console.error('[Router] 路由错误:', error)
+})
+
+export default router
\ No newline at end of file
diff --git a/src/stores/counter.ts b/src/stores/counter.ts
deleted file mode 100644
index a79803f..0000000
--- a/src/stores/counter.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-// src/stores/counter.ts
-import { defineStore } from 'pinia'
-
-export const useCounterStore = defineStore('counter', {
- state: () => ({
- count: 0
- }),
- getters: {
- doubleCount(): number {
- return this.count * 2;
- }
- },
- actions: {
- // 计数加 1(同步操作)
- increment() {
- this.count++
- },
- // 异步版本(不会卡住 UI)
- async incrementAsync() {
- const start = Date.now();
- while (Date.now() - start < 5000) {
- await new Promise(resolve => setTimeout(resolve, 0)) // 让出主线程
- }
- this.count++
- },
- // 同步阻塞版本(会卡住 5 秒,UI 无响应)
- incrementSyncBlocking() {
- const start = Date.now();
- while (Date.now() - start < 5000) {
- }
- this.count++;
- }
- }
-})
\ No newline at end of file
diff --git a/src/stores/user.ts b/src/stores/user.ts
deleted file mode 100644
index 70e422d..0000000
--- a/src/stores/user.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { defineStore } from 'pinia';
-
-// 定义用户信息的 store 类型
-interface UserState {
- username: string;
- isLoggedIn: boolean;
-}
-
-// 创建一个名为 "user" 的 store
-export const useUserStore = defineStore('user', {
- state: (): UserState => ({
- username: '',
- isLoggedIn: false,
- }),
-
- // Getters 用来计算派生状态
- getters: {
- // 获取用户登录的基本信息
- userProfile(state) {
- return state.isLoggedIn ? `用户名: ${state.username}` : '用户未登录';
- }
- },
-
- // Actions 用来修改状态,包含同步和异步操作
- actions: {
- // 用户登录
- login(username: string) {
- this.username = username;
- this.isLoggedIn = true;
- },
-
- // 用户登出
- logout() {
- this.username = '';
- this.isLoggedIn = false;
- }
- }
-});
\ No newline at end of file
diff --git a/src/utils/auth.ts b/src/utils/auth.ts
new file mode 100644
index 0000000..08e170c
--- /dev/null
+++ b/src/utils/auth.ts
@@ -0,0 +1,140 @@
+// 认证工具类
+export class Auth {
+ private tokenKey = 'token'
+ private userInfoKey = 'userInfo'
+
+ /**
+ * 检查用户是否已认证
+ */
+ isAuthenticated(): boolean {
+ const token = this.getToken()
+ return !!token && !this.isTokenExpired(token)
+ }
+
+ /**
+ * 获取存储的token
+ */
+ getToken(): string | null {
+ try {
+ return localStorage.getItem(this.tokenKey)
+ } catch (error) {
+ console.error('获取token失败:', error)
+ return null
+ }
+ }
+
+ /**
+ * 保存token
+ */
+ setToken(token: string): void {
+ try {
+ localStorage.setItem(this.tokenKey, token)
+ } catch (error) {
+ console.error('保存token失败:', error)
+ }
+ }
+
+ /**
+ * 移除token
+ */
+ removeToken(): void {
+ try {
+ localStorage.removeItem(this.tokenKey)
+ localStorage.removeItem(this.userInfoKey)
+ } catch (error) {
+ console.error('移除token失败:', error)
+ }
+ }
+
+ /**
+ * 检查token是否过期
+ */
+ private isTokenExpired(token: string): boolean {
+ try {
+ // 如果token包含JWT格式
+ if (token.includes('.')) {
+ const payload = JSON.parse(atob(token.split('.')[1]))
+ const currentTime = Math.floor(Date.now() / 1000)
+ return payload.exp ? payload.exp < currentTime : false
+ }
+ // 简单token,假设有效
+ return false
+ } catch (error) {
+ // 如果解析失败,认为token可能仍然有效(非JWT格式)
+ return false
+ }
+ }
+
+ /**
+ * 保存用户信息
+ */
+ setUserInfo(userInfo: any): void {
+ try {
+ localStorage.setItem(this.userInfoKey, JSON.stringify(userInfo))
+ } catch (error) {
+ console.error('保存用户信息失败:', error)
+ }
+ }
+
+ /**
+ * 获取用户信息
+ */
+ getUserInfo(): any {
+ try {
+ const userInfoStr = localStorage.getItem(this.userInfoKey)
+ if (userInfoStr) {
+ return JSON.parse(userInfoStr)
+ }
+
+ // 如果没有单独存储的用户信息,尝试从token解析
+ const token = this.getToken()
+ if (!token) return null
+
+ if (token.includes('.')) {
+ const payload = JSON.parse(atob(token.split('.')[1]))
+ return payload
+ }
+
+ return null
+ } catch (error) {
+ console.error('获取用户信息失败:', error)
+ return null
+ }
+ }
+
+ /**
+ * 获取用户类型
+ */
+ getUserType(): string | null {
+ const userInfo = this.getUserInfo()
+ return userInfo ? userInfo.userType || userInfo.role || null : null
+ }
+
+ /**
+ * 根据用户类型获取默认重定向路径
+ */
+ getDefaultRedirectPath(): string {
+ const userType = this.getUserType()
+ switch (userType) {
+ case 'admin':
+ return '/admin/dashboard'
+ case 'teacher':
+ return '/teacher/home'
+ case 'student':
+ return '/student/home'
+ default:
+ return '/dashboard'
+ }
+ }
+
+ /**
+ * 登出
+ */
+ logout(): void {
+ this.removeToken()
+ // 可以在这里添加其他登出逻辑,比如清除其他缓存数据
+ }
+}
+
+// 导出单例实例
+export const auth = new Auth()
\ No newline at end of file
diff --git a/src/views/FrontLayout.vue b/src/views/FrontLayout.vue
new file mode 100644
index 0000000..779c013
--- /dev/null
+++ b/src/views/FrontLayout.vue
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/views/Header.vue b/src/views/Header.vue
new file mode 100644
index 0000000..043a1a4
--- /dev/null
+++ b/src/views/Header.vue
@@ -0,0 +1,296 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/frontend/Home.vue b/src/views/Home.vue
similarity index 100%
rename from src/frontend/Home.vue
rename to src/views/Home.vue