diff --git a/src/api/modules/system.ts b/src/api/modules/system.ts new file mode 100644 index 0000000..fd85873 --- /dev/null +++ b/src/api/modules/system.ts @@ -0,0 +1,32 @@ +import { request } from '../request' +import type { ApiResponse } from '../types' + +export interface SystemSettings { + siteEnabled: boolean + maintenanceTitle: string + maintenanceMessage: string + maintenanceStartTime?: string + maintenanceEndTime?: string +} + +export const SystemApi = { + // 获取系统设置 + getSystemSettings(): Promise> { + return request.get('/aiol/system/settings') + }, + + // 更新系统设置 + updateSystemSettings(settings: Partial): Promise> { + return request.put('/aiol/system/settings', settings) + }, + + // 检查网站状态 + checkSiteStatus(): Promise> { + return request.get('/aiol/system/status') + }, + + // 切换网站状态 + toggleSiteStatus(enabled: boolean): Promise> { + return request.post('/aiol/system/toggle', { enabled }) + } +} diff --git a/src/router/index.ts b/src/router/index.ts index 2e4863b..1bfe7b2 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -717,6 +717,25 @@ const routes: RouteRecordRaw[] = [ meta: { title: '本地视频播放演示' } }, + // 网站维护页面 + { + path: '/maintenance', + name: 'Maintenance', + component: () => import('@/views/Maintenance.vue'), + meta: { title: '网站维护中' } + }, + + // 系统管理页面 + { + path: '/admin/system-maintenance', + name: 'SystemMaintenance', + component: () => import('@/views/admin/SystemMaintenance.vue'), + meta: { + title: '系统维护管理', + requiresAuth: true + } + }, + // 404 路由 { path: '/:pathMatch(.*)*', @@ -740,22 +759,33 @@ const router = createRouter({ }) // ========== 路由守卫 ========== -router.beforeEach((to, _from, next) => { +import { maintenanceGuard } from '@/utils/maintenanceGuard' + +router.beforeEach((to, from, next) => { // 设置页面标题 if (to.meta.title) { document.title = `${to.meta.title} - 在线学习平台` } - // 检查是否需要登录 - if (to.meta.requiresAuth) { - const token = localStorage.getItem('token') - if (!token) { - next('/') + // 检查网站维护状态 + maintenanceGuard(to, from, (route?: any) => { + if (route) { + // 如果维护守卫返回了重定向路由 + next(route) return } - } - next() + // 检查是否需要登录 + if (to.meta.requiresAuth) { + const token = localStorage.getItem('token') + if (!token) { + next('/') + return + } + } + + next() + }) }) export default router \ No newline at end of file diff --git a/src/utils/maintenanceGuard.ts b/src/utils/maintenanceGuard.ts new file mode 100644 index 0000000..d8adca5 --- /dev/null +++ b/src/utils/maintenanceGuard.ts @@ -0,0 +1,62 @@ +/** + * 网站维护状态检查工具 + */ + +// 本地存储键名 +const STORAGE_KEYS = { + SITE_STATUS: 'system_site_enabled' +} + +// 管理员路由白名单(这些路由在维护模式下仍可访问) +const ADMIN_ROUTES = [ + '/admin', + '/admin/system-maintenance', + '/login', + '/maintenance' +] + +/** + * 检查网站是否启用 + */ +export const isSiteEnabled = (): boolean => { + const status = localStorage.getItem(STORAGE_KEYS.SITE_STATUS) + // 默认为启用状态 + return status === null || status === 'true' +} + +/** + * 检查当前路由是否为管理员路由 + */ +export const isAdminRoute = (path: string): boolean => { + return ADMIN_ROUTES.some(route => path.startsWith(route)) +} + +/** + * 路由守卫:检查网站维护状态 + */ +export const maintenanceGuard = (to: any, from: any, next: any) => { + const siteEnabled = isSiteEnabled() + const isAdmin = isAdminRoute(to.path) + + console.log('🔍 维护状态检查:', { + path: to.path, + siteEnabled, + isAdmin + }) + + // 如果网站已关闭且不是管理员路由,重定向到维护页面 + if (!siteEnabled && !isAdmin) { + console.log('🚫 网站维护中,重定向到维护页面') + next('/maintenance') + return + } + + // 如果网站已开启但访问维护页面,重定向到首页 + if (siteEnabled && to.path === '/maintenance') { + console.log('✅ 网站已开启,重定向到首页') + next('/') + return + } + + next() +} diff --git a/src/views/Home.vue b/src/views/Home.vue index 8b65447..44169bd 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -90,8 +90,9 @@
{{ course.studentsCount }}{{ t('home.popularCourses.studentsEnrolled') }} - +
@@ -602,15 +603,23 @@ const goToCourseDetail = async (courseId: string) => { } } -// 处理课程报名 -const handleEnrollCourse = async (courseId: string | number, event?: Event) => { +// 处理课程报名或学习 +const handleEnrollCourse = async (course: any, event?: Event) => { // 阻止事件冒泡,避免触发卡片点击事件 if (event) { event.stopPropagation() } - console.log('🎯 点击报名按钮,课程ID:', courseId) + console.log('🎯 点击按钮,课程:', course) + // 如果已经报名,直接跳转到学习页面 + if (course.isEnrolled) { + console.log('✅ 用户已报名,跳转到学习页面') + router.push(`/course/${course.id}/exchanged`) + return + } + + // 未报名,执行报名流程 try { // 检查用户是否已登录 if (!userStore.isLoggedIn) { @@ -620,7 +629,7 @@ const handleEnrollCourse = async (courseId: string | number, event?: Event) => { } // 调用报名API - const response = await CourseApi.enrollCourse(String(courseId)) + const response = await CourseApi.enrollCourse(String(course.id)) if (response.code === 200 || response.code === 0) { console.log('✅ 报名成功:', response.data) @@ -628,7 +637,7 @@ const handleEnrollCourse = async (courseId: string | number, event?: Event) => { message.success('报名成功!') // 报名成功后跳转到课程详情页 - router.push(`/course/${courseId}/exchanged`) + router.push(`/course/${course.id}/exchanged`) } else { console.error('❌ 报名失败:', response.message) message.error(response.message || '报名失败,请稍后重试') @@ -701,12 +710,12 @@ const handleScroll = () => { documentHeight, scrollableHeight, scrollPercentage: scrollPercentage.toFixed(2) + '%', - shouldShow: scrollPercentage >= 50, + shouldShow: scrollPercentage >= 40, currentShow: showFixedButtons.value }) // 当滚动超过50%时显示固定按钮组 - const shouldShow = scrollPercentage >= 50 + const shouldShow = scrollPercentage >= 40 if (shouldShow !== showFixedButtons.value) { showFixedButtons.value = shouldShow console.log(shouldShow ? '🟢 显示固定按钮组' : '🔴 隐藏固定按钮组') @@ -778,7 +787,8 @@ const popularCourses = computed(() => { studentsCount: course.studentsCount, rating: course.rating, price: course.price, - originalPrice: course.originalPrice + originalPrice: course.originalPrice, + isEnrolled: course.isEnrolled || false // 添加报名状态字段 })) }) diff --git a/src/views/Maintenance.vue b/src/views/Maintenance.vue new file mode 100644 index 0000000..5d6cc66 --- /dev/null +++ b/src/views/Maintenance.vue @@ -0,0 +1,294 @@ + + + + + diff --git a/src/views/admin/SystemMaintenance.vue b/src/views/admin/SystemMaintenance.vue new file mode 100644 index 0000000..173e27e --- /dev/null +++ b/src/views/admin/SystemMaintenance.vue @@ -0,0 +1,413 @@ + + + + +