liyanbo 1 месяц назад
Родитель
Сommit
34a5011bd0

+ 51 - 9
src/App.vue

@@ -11,14 +11,23 @@
 </template>
 
 <script setup>
-import { ref, onMounted, onUnmounted } from 'vue'
+import { ref, onMounted, onUnmounted, watch } from 'vue'
 import { useRoute } from 'vue-router'
 
 const route = useRoute()
 const showLandscapeHint = ref(false) // 修改默认值为false
 const countdown = ref(3) // 倒计时初始值
 let countdownTimer = null
-let hasShownHint = false // 标记是否已经显示过提示
+
+// 从本地存储获取是否已经显示过提示的状态
+const getHasShownHint = () => {
+  return localStorage.getItem('landscapeHintShown') === 'true'
+}
+
+// 设置已显示提示的状态到本地存储
+const setHasShownHint = (shown) => {
+  localStorage.setItem('landscapeHintShown', shown.toString())
+}
 
 // 检测是否为移动设备
 const isMobileDevice = () => {
@@ -31,17 +40,19 @@ const isLandscape = () => {
   return window.innerWidth > window.innerHeight
 }
 
-// 检查当前路由是否为新课程页面或AI通用课程页面
+// 检查当前路由是否为父母课堂页面或AI通用课程页面
 const isNewCoursePage = () => {
-  return route.path.includes('/custom-course') || 
-         route.path.includes('/ai-develop') ||
+  return route.path.includes('/parent-mobile-course') ||
+         route.path.includes('/parent-mobile-course-detail') ||
+        route.path.includes('/login') ||
+        route.path.includes('/ai-develop') ||
          route.path.includes('/ai-general-course')
 }
 
 // 关闭横屏提示
 const closeLandscapeHint = () => {
   showLandscapeHint.value = false
-  hasShownHint = true // 设置标记,表示已经显示过提示
+  setHasShownHint(true) // 设置标记,表示已经显示过提示
   // 清理倒计时定时器
   if (countdownTimer) {
     clearInterval(countdownTimer)
@@ -68,9 +79,17 @@ const startCountdown = () => {
   }, 1000)
 }
 
-// 检查是否应该显示横屏提示(仅在页面首次加载时检查)
+// 检查是否应该显示横屏提示
 const checkLandscapeHint = () => {
-  if (!hasShownHint && isMobileDevice() && !isLandscape() && !isNewCoursePage()) {
+  // 对于新课程页面,始终不显示横屏提示
+  if (isNewCoursePage()) {
+    showLandscapeHint.value = false
+    setHasShownHint(true) // 标记为已显示,避免后续显示
+    return
+  }
+  
+  const hasShown = getHasShownHint()
+  if (!hasShown && isMobileDevice() && !isLandscape() && !isNewCoursePage()) {
     // 如果是移动设备、竖屏、不是新课程页面,且尚未显示过提示,则显示横屏提示
     showLandscapeHint.value = true
     // 开始倒计时
@@ -83,12 +102,35 @@ const handleResize = () => {
   // 如果是由于旋转导致的横屏,则关闭提示
   if (isLandscape()) {
     closeLandscapeHint()
+  } else {
+    // 如果变为竖屏,且不在新课程页面,则检查是否显示提示
+    const hasShown = getHasShownHint()
+    if (!isNewCoursePage() && isMobileDevice() && !hasShown) {
+      showLandscapeHint.value = true
+      startCountdown()
+    }
   }
 }
 
+// 监听路由变化
+watch(() => route.path, (newPath, oldPath) => {
+  // 如果进入新课程页面,立即关闭提示
+  if (isNewCoursePage()) {
+    showLandscapeHint.value = false
+    setHasShownHint(true)
+    // 清理可能存在的倒计时
+    if (countdownTimer) {
+      clearInterval(countdownTimer)
+      countdownTimer = null
+    }
+  }
+  // 每次路由变化时都检查是否应该显示横屏提示
+  checkLandscapeHint()
+}, { immediate: true })
+
 // 组件挂载时更新状态
 onMounted(() => {
-  checkLandscapeHint() // 仅在页面加载时检查一次
+  checkLandscapeHint() // 页面加载时检查
   window.addEventListener('resize', handleResize)
   
   // 监听设备方向变化(如果支持的话)

+ 0 - 60
src/components/customCourse/CustomCourse.vue

@@ -1,60 +0,0 @@
-<template>
-  <div>
-    <!-- 课程分类页面 -->
-    <CustomCourseCategory 
-      v-if="currentView === 'category'" 
-      @navigate-to-detail="handleNavigateToDetail"
-    />
-    
-    <!-- 课程详情页面 -->
-    <CustomCourseDetail 
-      v-else-if="currentView === 'detail'"
-      :course-id="courseId"
-    />
-  </div>
-</template>
-
-<script setup>
-import { ref, onMounted, watch } from 'vue'
-import { useRoute } from 'vue-router'
-import CustomCourseCategory from './CustomCourseCategory.vue'
-import CustomCourseDetail from './CustomCourseDetail.vue'
-
-const route = useRoute()
-
-// 当前视图
-const currentView = ref('category')
-
-// 当前课程ID
-const courseId = ref('')
-
-// 处理导航到详情页
-const handleNavigateToDetail = (id) => {
-  courseId.value = id
-  currentView.value = 'detail'
-}
-
-// 监听路由变化
-const handleRouteChange = () => {
-  if (route.query.courseId) {
-    courseId.value = route.query.courseId
-    currentView.value = 'detail'
-  } else {
-    currentView.value = 'category'
-  }
-}
-
-// 初始化
-onMounted(() => {
-  handleRouteChange()
-})
-
-// 监听路由变化
-watch(() => route.fullPath, () => {
-  handleRouteChange()
-})
-</script>
-
-<style scoped>
-/* 无需额外样式,使用子组件样式 */
-</style>

+ 12 - 4
src/router/index.js

@@ -110,11 +110,18 @@ const routes = [
     path: '/ai-develop',
     component: () => import('../views/AIPage/AIDevelop.vue')
   },
-  // 郝哥新课程
+
+  // 父母课堂-手机端课程列表
+  {
+    path: '/parent-mobile-course',
+    component: () => import('../views/ParentMobile/ParentMobileCourse.vue')
+  },
+  // 父母课堂-手机端课程列表详情
   {
-    path: '/custom-course-detail',
-    component: () => import('../components/customCourse/CustomCourseDetail.vue')
+    path: '/parent-mobile-course-detail',
+    component: () => import('../views/ParentMobile/ParentMobileCourseDetail.vue')
   },
+
   // 虚拟实验室
   {
     path: '/virtual-laboratory',
@@ -199,7 +206,8 @@ const homeRoutes = {
     '/smartHome',
     '/smartDeskLamp',
     '/ai-poetry',
-    '/custom-course-detail',
+    '/parent-mobile-course-detail',
+    '/parent-mobile-course',
   ]
 }
 

+ 0 - 475
src/styles/customCourse.css

@@ -1,475 +0,0 @@
-/* ============================================ */
-/* 自定义课程组件样式 */
-/* ============================================ */
-
-/* -------------------------- */
-/* 基础重置 */
-/* -------------------------- */
-
-.custom-course-container {
-  margin: 0;
-  padding: 0;
-  box-sizing: border-box;
-}
-
-/* -------------------------- */
-/* 网页端样式 (桌面端) */
-/* -------------------------- */
-
-@media screen and (min-width: 769px) {
-  .custom-course-container {
-    width: 100%;
-    min-height: 100vh;
-    background-color: #f5f5f5;
-    padding: 20px;
-  }
-
-  /* 视频播放区域 - 网页端隐藏 */
-  .custom-course-video-container {
-    display: none !important;
-  }
-
-  /* 课程详情页 - 网页端头部 */
-  .custom-course-detail-header {
-    background: linear-gradient(135deg, #44449c, #7F70C8);
-    padding: 30px;
-    color: white;
-    display: flex;
-    align-items: center;
-    gap: 24px;
-    border-radius: 12px;
-    margin-bottom: 16px;
-  }
-
-  .custom-course-detail-cover {
-    width: 180px;
-    height: 120px;
-    border-radius: 12px;
-    overflow: hidden;
-    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
-  }
-
-  .custom-course-detail-cover img {
-    width: 100%;
-    height: 100%;
-    object-fit: cover;
-  }
-
-  .custom-course-detail-info {
-    flex: 1;
-  }
-
-  .custom-course-detail-title {
-    font-size: 24px;
-    font-weight: 700;
-    margin-bottom: 8px;
-  }
-
-  .custom-course-detail-subtitle {
-    font-size: 14px;
-    opacity: 0.8;
-    margin-bottom: 16px;
-  }
-
-  .custom-course-detail-progress {
-    display: flex;
-    align-items: center;
-    gap: 12px;
-  }
-
-  .custom-course-detail-progress-bar {
-    flex: 1;
-    height: 8px;
-    background: rgba(255, 255, 255, 0.3);
-    border-radius: 4px;
-    overflow: hidden;
-  }
-
-  .custom-course-detail-progress-fill {
-    height: 100%;
-    background: white;
-    border-radius: 4px;
-  }
-
-  .custom-course-detail-progress-text {
-    font-size: 14px;
-    font-weight: 600;
-  }
-
-  .custom-course-detail-toolbar {
-    display: flex;
-    gap: 16px;
-    padding: 16px 20px;
-    background: white;
-    border-radius: 12px;
-    margin-bottom: 16px;
-    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
-  }
-
-  .custom-course-search-box {
-    flex: 1;
-    position: relative;
-  }
-
-  .custom-course-search-box input {
-    width: 100%;
-    padding: 10px 40px;
-    border: 1px solid #ddd;
-    border-radius: 20px;
-    font-size: 14px;
-  }
-
-  .custom-course-search-box .search-icon {
-    position: absolute;
-    left: 14px;
-    top: 50%;
-    transform: translateY(-50%);
-    color: #999;
-  }
-
-  .custom-course-sort-btn {
-    display: flex;
-    align-items: center;
-    gap: 8px;
-    padding: 10px 20px;
-    background: #f5f5f5;
-    border-radius: 20px;
-    cursor: pointer;
-    border: none;
-    font-size: 14px;
-  }
-
-  .custom-course-chapter-list {
-    max-width: 100%;
-    margin: 0;
-  }
-
-  .custom-course-chapter-item {
-    display: flex;
-    align-items: flex-start;
-    padding: 20px;
-    background: white;
-    border-radius: 12px;
-    margin-bottom: 12px;
-    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
-    cursor: pointer;
-    transition: box-shadow 0.2s ease;
-  }
-
-  .custom-course-chapter-item:hover {
-    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
-  }
-
-  .custom-course-chapter-lock {
-    width: 40px;
-    height: 40px;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    color: #ddd;
-    font-size: 20px;
-    flex-shrink: 0;
-  }
-
-  .custom-course-chapter-lock.locked {
-    color: #999;
-  }
-
-  .custom-course-chapter-lock.unlocked {
-    color: #4CAF50;
-  }
-
-  .custom-course-chapter-info {
-    flex: 1;
-    padding-left: 16px;
-  }
-
-  .custom-course-chapter-title {
-    font-size: 16px;
-    font-weight: 600;
-    color: #333;
-    margin-bottom: 8px;
-  }
-
-  .custom-course-chapter-desc {
-    font-size: 13px;
-    color: #999;
-    margin-bottom: 8px;
-    line-height: 1.5;
-  }
-
-  .custom-course-chapter-meta {
-    font-size: 13px;
-    color: #999;
-    display: flex;
-    gap: 12px;
-  }
-
-  .custom-course-chapter-duration {
-    display: flex;
-    align-items: center;
-    gap: 4px;
-  }
-}
-
-/* -------------------------- */
-/* 手机端样式 */
-/* -------------------------- */
-
-@media screen and (max-width: 768px) {
-  .custom-course-container {
-    width: 100%;
-    min-height: 100vh;
-    background: #ffffff;
-    padding: 0;
-    margin: 0;
-  }
-
-  /* 视频播放区域 - 手机端显示 */
-  .custom-course-video-container {
-    display: block !important;
-    width: 100%;
-    background: #000;
-    position: relative;
-  }
-
-  /* 视频头部工具栏 */
-  .custom-course-video-header {
-    display: flex !important;
-    align-items: center;
-    justify-content: space-between;
-    padding: 12px;
-    background: rgba(0, 0, 0, 0.8);
-    position: absolute;
-    top: 0;
-    left: 0;
-    right: 0;
-    z-index: 100;
-  }
-
-  .custom-course-back-btn {
-    width: 36px;
-    height: 36px;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    background: rgba(255, 255, 255, 0.2);
-    border-radius: 50%;
-    border: none;
-    color: white;
-    cursor: pointer;
-    font-size: 18px;
-  }
-
-  .custom-course-video-title {
-    flex: 1;
-    text-align: center;
-    color: white;
-    font-size: 14px;
-    font-weight: 500;
-    padding: 0 40px;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-  }
-
-  .custom-course-video-controls {
-    display: flex;
-    gap: 8px;
-  }
-
-  .custom-course-control-btn {
-    width: 36px;
-    height: 36px;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    background: rgba(255, 255, 255, 0.2);
-    border-radius: 50%;
-    border: none;
-    color: white;
-    cursor: pointer;
-    font-size: 18px;
-  }
-
-  /* 视频播放区域 */
-  .custom-course-video-wrapper {
-    width: 100%;
-    height: 220px;
-    position: relative;
-  }
-
-  .custom-course-video-placeholder {
-    width: 100%;
-    height: 100%;
-    background: linear-gradient(135deg, #44449c, #7F70C8);
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    position: relative;
-  }
-
-  .custom-course-play-icon {
-    width: 60px;
-    height: 60px;
-    color: white;
-    opacity: 0.9;
-  }
-
-  /* 课程详情页头部 - 手机端隐藏 */
-  .custom-course-detail-header {
-    display: none !important;
-  }
-
-  /* 工具栏 */
-  .custom-course-detail-toolbar {
-    display: flex;
-    flex-direction: column;
-    padding: 12px;
-    gap: 12px;
-    border-bottom: 1px solid #eee;
-    background: white;
-  }
-
-  .custom-course-search-box {
-    position: relative;
-  }
-
-  .custom-course-search-box input {
-    width: 100%;
-    padding: 12px 40px;
-    border: 1px solid #ddd;
-    border-radius: 25px;
-    font-size: 14px;
-    box-sizing: border-box;
-  }
-
-  .custom-course-search-box .search-icon {
-    position: absolute;
-    left: 14px;
-    top: 50%;
-    transform: translateY(-50%);
-    color: #999;
-  }
-
-  .custom-course-sort-btn {
-    padding: 12px;
-    border-radius: 25px;
-    justify-content: center;
-    background: #f5f5f5;
-    border: none;
-    font-size: 14px;
-    cursor: pointer;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-  }
-
-  /* 章节列表 */
-  .custom-course-chapter-list {
-    margin: 0;
-    padding: 12px;
-    background: #f8f8f8;
-  }
-
-  .custom-course-chapter-item {
-    display: flex;
-    align-items: flex-start;
-    padding: 16px;
-    background: white;
-    border-radius: 16px;
-    margin-bottom: 10px;
-    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
-    cursor: pointer;
-  }
-
-  .custom-course-chapter-lock {
-    width: 36px;
-    height: 36px;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    font-size: 18px;
-    flex-shrink: 0;
-  }
-
-  .custom-course-chapter-lock.locked {
-    color: #ccc;
-  }
-
-  .custom-course-chapter-lock.unlocked {
-    color: #4CAF50;
-  }
-
-  .custom-course-chapter-info {
-    flex: 1;
-    padding-left: 12px;
-  }
-
-  .custom-course-chapter-title {
-    font-size: 15px;
-    font-weight: 600;
-    color: #333;
-    margin-bottom: 6px;
-    display: flex;
-    align-items: center;
-    gap: 6px;
-  }
-
-  .custom-course-chapter-desc {
-    font-size: 12px;
-    color: #999;
-    margin-bottom: 6px;
-    line-height: 1.5;
-    display: -webkit-box;
-    -webkit-line-clamp: 2;
-    -webkit-box-orient: vertical;
-    overflow: hidden;
-  }
-
-  .custom-course-chapter-meta {
-    font-size: 12px;
-    color: #999;
-    gap: 10px;
-    display: flex;
-    align-items: center;
-  }
-
-  .custom-course-chapter-duration {
-    display: flex;
-    align-items: center;
-    gap: 4px;
-  }
-}
-
-/* -------------------------- */
-/* 空状态样式 */
-/* -------------------------- */
-
-.custom-course-empty {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-  padding: 60px 20px;
-  text-align: center;
-}
-
-.custom-course-empty-icon {
-  width: 80px;
-  height: 80px;
-  border-radius: 50%;
-  background: #f0f0f0;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  margin-bottom: 20px;
-  font-size: 40px;
-  color: #ccc;
-}
-
-.custom-course-empty-text {
-  font-size: 16px;
-  color: #999;
-  margin-bottom: 20px;
-}

+ 16 - 16
src/styles/customCourseList.css → src/styles/parentMobileCourse.css

@@ -1,5 +1,5 @@
 /* ============================================ */
-/* 课程列表样式 */
+/* 父母课堂-手机端课程列表样式 */
 /* 包含电脑端和移动端适配 */
 /* ============================================ */
 
@@ -8,12 +8,12 @@
 /* -------------------------- */
 
 /* 默认隐藏移动端容器 */
-.custom-mobile-container {
+.parent-mobile-container {
   display: none !important;
 }
 
 /* 默认显示电脑端课程项 */
-.custom-course-item {
+.parent-mobile-course-item {
   display: flex !important;
 }
 
@@ -23,12 +23,12 @@
 
 @media screen and (max-width: 768px) {
   /* 隐藏电脑端课程项 */
-  .custom-course-item {
+  .parent-mobile-course-item {
     display: none !important;
   }
   
   /* 显示移动端容器 */
-  .custom-mobile-container {
+  .parent-mobile-container {
     display: block !important;
     width: 100%;
     max-width: 100vw; /* 最大宽度不超过视口宽度 */
@@ -38,7 +38,7 @@
   }
   
   /* 移动端课程项 */
-  .custom-mobile-item {
+  .parent-mobile-item {
     display: flex;
     align-items: center;
     background: #fff;
@@ -54,12 +54,12 @@
     max-width: 100%;
   }
   
-  .custom-mobile-item:active {
+  .parent-mobile-item:active {
     box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
   }
   
   /* 左侧图片 */
-  .custom-mobile-image {
+  .parent-mobile-image {
     width: 80px;
     height: 60px;
     border-radius: 8px;
@@ -67,14 +67,14 @@
     flex-shrink: 0;
   }
   
-  .custom-mobile-image img {
+  .parent-mobile-image img {
     width: 100%;
     height: 100%;
     object-fit: cover;
   }
   
   /* 中间内容 */
-  .custom-mobile-content {
+  .parent-mobile-content {
     flex: 1;
     padding: 0 12px 0 16px; /* 增加左边距,距离图片更远 */
     display: flex;
@@ -84,7 +84,7 @@
     align-items: flex-start; /* 居左显示 */
   }
   
-  .custom-mobile-title {
+  .parent-mobile-title {
     font-size: 14px;
     font-weight: 600;
     color: #333;
@@ -95,13 +95,13 @@
     word-break: break-all;
   }
   
-  .custom-mobile-index {
+  .parent-mobile-index {
     margin-right: 6px;
     color: #999;
     font-weight: normal;
   }
   
-  .custom-mobile-desc {
+  .parent-mobile-desc {
     font-size: 12px;
     color: #999;
     overflow: hidden;
@@ -110,7 +110,7 @@
   }
   
   /* 右侧三点按钮 */
-  .custom-mobile-more {
+  .parent-mobile-more {
     width: 36px;
     height: 36px;
     display: flex;
@@ -127,12 +127,12 @@
 
 @media screen and (min-width: 769px) {
   /* 确保移动端容器隐藏 */
-  .custom-mobile-container {
+  .parent-mobile-container {
     display: none !important;
   }
   
   /* 确保电脑端课程项显示 */
-  .custom-course-item {
+  .parent-mobile-course-item {
     display: flex !important;
   }
 }

+ 5 - 0
src/utils/loginUtils.js

@@ -217,6 +217,11 @@ const loginLogic = async (loginForm, tenantId, isAuthorized, router) => {
       // 获取角色路由数据
       await refreshRoleRouteData();
 
+      if (res.data.tenantId === 1) {
+        router.push("/parent-mobile-course")
+        return true
+      }
+
       // 登录成功后,跳转到指定的页面
       router.push(managementRoutes.home)
 

+ 24 - 24
src/views/AIPage/AIGeneralCourse.vue

@@ -127,11 +127,11 @@
         <SelfDirectedLearning v-if="currentOpenedMenu === menuConfigTemp[3].id"
                               @refreshData="refreshData" />
 
-        <!-- 新课程分类 - 与其他课程保持一致的样式 -->
-        <template v-else-if="currentOpenedMenu === '/custom'">
+        <!-- 父母课堂-手机端 - 与其他课程保持一致的样式 -->
+        <template v-else-if="currentOpenedMenu === '/parent-mobile'">
           <!-- 电脑端样式:与原课程相同的布局结构 -->
           <div
-              class="small-box custom-course-item"
+              class="small-box parent-mobile-course-item"
               v-for="(course, index) in currentCourseData"
               :key="course.id"
           >
@@ -141,7 +141,7 @@
                 backgroundImage: `url(${course.ctTypeImage})`,
                 backgroundSize: 'cover'
               }"
-                @click="goToCustomCourse(course)"
+                @click="goToParentMobileCourse(course)"
             ></div>
             <div class="additional-text">
               {{ course.ctTypeSort }} {{ course.ctType }}
@@ -149,24 +149,24 @@
           </div>
 
           <!-- 移动端样式 -->
-          <div class="custom-mobile-container">
+          <div class="parent-mobile-container">
             <div
-                class="custom-mobile-item"
+                class="parent-mobile-item"
                 v-for="(course, index) in currentCourseData"
                 :key="course.id"
-                @click="goToCustomCourse(course)"
+                @click="goToParentMobileCourse(course)"
             >
               <!-- 左侧图片 -->
-              <div class="custom-mobile-image">
+              <div class="parent-mobile-image">
                 <img :src="course.ctTypeImage" :alt="course.title" />
               </div>
               <!-- 右侧内容 -->
-              <div class="custom-mobile-content">
-                <div class="custom-mobile-title">
-                  <span class="custom-mobile-index">{{ course.ctTypeSort }}</span>
+              <div class="parent-mobile-content">
+                <div class="parent-mobile-title">
+                  <span class="parent-mobile-index">{{ course.ctTypeSort }}</span>
                   {{ course.ctType }}
                 </div>
-                <div class="custom-mobile-desc">{{ course.ctTypeDescribe || '' }}</div>
+                <div class="parent-mobile-desc">{{ course.ctTypeDescribe || '' }}</div>
               </div>
             </div>
           </div>
@@ -225,7 +225,7 @@ import SelfDirectedLearning from '@/components/study/SelfDirectedLearning.vue'
 import DialogContent from "@/views/AIPage/aiGenerate/DialogContent.vue";
 import {teacherList} from "@/api/teachers.js";
 import { CONFIG } from '@/utils/roleUtils.js'
-import '@/styles/customCourseList.css'
+import '@/styles/parentMobileCourse.css'
 
 
 const router = useRouter() // 获取当前路由对象
@@ -247,8 +247,8 @@ const generalCourseData = ref([])
 const practicalCourseData = ref([])
 const aiCourseData = ref([])
 
-// 新课程列表数据(模拟数据)
-const customCourseList = ref([])
+// 父母课堂-手机端列表数据(模拟数据)
+const parentMobileCourseList = ref([])
 const selfStudyCourseData = ref([])
 
 // 菜单配置
@@ -257,8 +257,8 @@ const menuConfigTemp = [
   { id: '/practical', title: 'AI实操课', type: '2', data: practicalCourseData },
   { id: '/poetry', title: 'AI古诗词', type: '3', data: aiCourseData },
   { id: '/selfstudy', title: 'AI自主学习', type: '4', data: selfStudyCourseData },
-  // 自定义课程分类(独立数据处理)
-  { id: '/custom', title: '新课程', type: '5', data: ref([]), isCustom: true }
+  // 父母课堂-手机端(独立数据处理)
+  { id: '/parent-mobile', title: '父母课堂', type: '5', data: ref([]) }
 ]
 
 
@@ -280,10 +280,10 @@ const menuList = computed(() => {
 const roleRouteMenuSet = computed(() => {
   try {
     const roleRouteMenuStr = localStorage.getItem(CONFIG.USER_ROLE_ROUTE_MENU_KEY)
-    const roleRouteMenu = JSON.parse(roleRouteMenuStr)
-    roleRouteMenu.push('/custom')
-    return roleRouteMenu
-    // return roleRouteMenuStr ? JSON.parse(roleRouteMenuStr) : []
+    // const roleRouteMenu = JSON.parse(roleRouteMenuStr)
+    // roleRouteMenu.push('/parent-mobile')
+    // return roleRouteMenu
+    return roleRouteMenuStr ? JSON.parse(roleRouteMenuStr) : []
   } catch (error) {
     console.error('Error parsing roleRouteMenuSet:', error)
     return []
@@ -537,8 +537,8 @@ const goToAIExperience = outlineData => {
   })
 }
 
-// 新课程跳转方法
-const goToCustomCourse = (outlineData) => {
+// 父母课堂-手机端跳转方法
+const goToParentMobileCourse = (outlineData) => {
   const menuId = currentOpenedMenu.value
   const menu = menuConfig.value.find(m => m.id === menuId)
   const currentData = menu ? menu.data.value : []
@@ -550,7 +550,7 @@ const goToCustomCourse = (outlineData) => {
   }
 
   router.push({
-    path: '/custom-course-detail',
+    path: '/parent-mobile-course-detail',
     state: { typeId: outlineData.id, typeName: outlineData.ctType, typeSort: outlineData.ctTypeSort }
   })
 }

+ 395 - 0
src/views/ParentMobile/ParentMobileCourse.vue

@@ -0,0 +1,395 @@
+<template>
+  <!-- 父母课堂-手机端页面 -->
+  <div class="parent-mobile-course-container">
+    <!-- 页面标题和返回按钮 -->
+    <div class="page-header">
+      <h1 class="page-title">父母课堂</h1>
+    </div>
+    
+    <!-- 搜索框 -->
+    <div class="search-section">
+      <el-autocomplete
+          v-model="SearchInput"
+          :fetch-suggestions="querySearch"
+          placeholder="搜索课程"
+          @select="handleSearchSelect"
+          class="search-input"
+          value-key="ctType"
+          :trigger-on-focus="false"
+          :key="searchKey"
+      >
+        <template #prefix>
+          <el-icon class="el-input__icon"><Search /></el-icon>
+        </template>
+        <!-- 下拉项模板 -->
+        <template #default="{ item }">
+          <div class="scrollbar">
+            <!-- 序号和标题 -->
+            {{ item.ctTypeSort }} {{ item.ctType }}
+          </div>
+        </template>
+      </el-autocomplete>
+    </div>
+
+    <!-- 课程列表 -->
+    <div class="course-list">
+      <!-- 电脑端样式:与原课程相同的布局结构 -->
+      <div
+          class="small-box parent-mobile-course-item"
+          v-for="(course, index) in parentMobileCourseData"
+          :key="course.id"
+      >
+        <div
+            class="nested-box"
+            :style="{
+              backgroundImage: `url(${course.ctTypeImage})`,
+              backgroundSize: 'cover'
+            }"
+            @click="goToParentMobileCourse(course)"
+        ></div>
+        <div class="additional-text">
+          {{ course.ctTypeSort }} {{ course.ctType }}
+        </div>
+      </div>
+
+      <!-- 移动端样式 -->
+      <div class="parent-mobile-container">
+        <div
+            class="parent-mobile-item"
+            v-for="(course, index) in parentMobileCourseData"
+            :key="course.id"
+            @click="goToParentMobileCourse(course)"
+        >
+          <!-- 左侧图片 -->
+          <div class="parent-mobile-image">
+            <img :src="course.ctTypeImage" :alt="course.title" />
+          </div>
+          <!-- 右侧内容 -->
+          <div class="parent-mobile-content">
+            <div class="parent-mobile-title">
+              <span class="parent-mobile-index">{{ course.ctTypeSort }}</span>
+              {{ course.ctType }}
+            </div>
+            <div class="parent-mobile-desc">{{ course.ctTypeDescribe || '' }}</div>
+          </div>
+        </div>
+      </div>
+
+      <!-- 空状态 -->
+      <div v-if="parentMobileCourseData.length === 0" class="empty-state" style="width: 100%; text-align: center; padding: 40px;">
+        <p>暂无课程</p>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, onMounted } from 'vue'
+import { useRouter } from 'vue-router'
+import { ClassList, ClassOutline } from '@/api/class.js'
+import { Search, ArrowLeftBold } from '@element-plus/icons-vue'
+import { Message } from '@/utils/message/Message.js'
+import { CONFIG } from '@/utils/roleUtils.js'
+import '@/styles/parentMobileCourse.css'
+
+const router = useRouter()
+
+// 搜索框
+const SearchInput = ref('')
+// 用于强制重新渲染搜索组件的key
+const searchKey = ref(Date.now())
+
+// 父母课堂-手机端数据
+const parentMobileCourseData = ref([])
+
+// 检测是否为移动设备
+const isMobile = ref(false)
+
+const checkIsMobile = () => {
+  if (typeof window !== 'undefined') {
+    // 使用多种方式检测移动设备
+    return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ||
+        window.innerWidth <= 768; // 或者使用屏幕宽度作为判断标准
+  }
+  return false;
+}
+
+// 获取父母课堂-手机端数据
+const fetchParentMobileCourseData = async () => {
+  try {
+    // 获取年级数据
+    const classResponse = await ClassList()
+    if (classResponse.code === 0) {
+      const classData = classResponse.data
+      
+      // 获取到数据,优先从localStorage读取选中值
+      const savedGrade = localStorage.getItem('selectedGrade')
+      const selectedGrade = savedGrade || (classData.length > 0 ? classData[0].ctType : '')
+      
+      // 查找对应的年级ID
+      const selectedItem = classData.find(item => item.ctType === selectedGrade) || classData[0]
+      if (selectedItem) {
+        // 获取该年级下的课程大纲数据(父母课堂-手机端类型,根据原页面配置)
+        const outlineRes = await ClassOutline(selectedItem.id, '5')
+        if (outlineRes.code === 0) {
+          // 处理课程数据,添加序号
+          parentMobileCourseData.value = outlineRes.data.map((item, index) => {
+            item.ctTypeSort = index + 1
+            item.ctTypeSort = item.ctTypeSort > 9 ? item.ctTypeSort : "0" + item.ctTypeSort
+            return item
+          })
+        }
+      }
+    }
+  } catch (error) {
+    console.error('获取父母课堂-手机端数据失败:', error)
+    Message().notifyWarning('获取课程数据失败', true)
+  }
+}
+
+// 搜索建议查询方法
+const querySearch = (queryString, cb) => {
+  const results = queryString
+      ? parentMobileCourseData.value.filter(item => {
+        // 课程标题和序号查询
+        return item.ctType.toLowerCase().includes(queryString.toLowerCase()) ||
+            // 类型检查,确保ctTypeSort是字符串类型
+            (item.ctTypeSort && item.ctTypeSort.toString().includes(queryString))
+      })
+      : parentMobileCourseData.value
+  cb(results)
+}
+
+// 搜索选择处理方法
+const handleSearchSelect = item => {
+  goToParentMobileCourse(item)
+  // 清空输入框
+  SearchInput.value = '';
+}
+
+// 返回首页
+const goBack = () => {
+  router.push('/home')
+}
+
+// 跳转到父母课堂-手机端详情页
+const goToParentMobileCourse = (outlineData) => {
+  router.push({
+    path: '/parent-mobile-course-detail',
+    state: { typeId: outlineData.id, typeName: outlineData.ctType, typeSort: outlineData.ctTypeSort }
+  })
+}
+
+onMounted(() => {
+  // 检测是否为移动设备
+  isMobile.value = checkIsMobile();
+  
+  // 获取父母课堂-手机端数据
+  fetchParentMobileCourseData()
+})
+</script>
+
+<style scoped lang="scss">
+@use 'sass:math';
+
+// 定义rpx转换函数
+@function rpx($px) {
+  @return math.div($px, 750) * 100vw;
+}
+
+.parent-mobile-course-container {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  display: flex;
+  flex-direction: column;
+  background: linear-gradient(
+          to bottom,
+          #e2ddfc,
+          #f1effd
+  );
+  padding: rpx(20);
+  box-sizing: border-box;
+  overflow-y: auto;
+}
+
+.page-header {
+  align-items: center;
+  margin-bottom: rpx(30);
+  padding-bottom: rpx(20);
+  border-bottom: 1px solid #dcdcff;
+}
+
+.page-title {
+  font-size: rpx(36);
+  color: #44449c;
+  margin: 0;
+  text-align: center;
+}
+
+.search-section {
+  margin-bottom: rpx(30);
+}
+
+.search-input {
+  width: 100%;
+  max-width: rpx(600);
+}
+
+.course-list {
+  display: flex;
+  flex-wrap: wrap;
+  gap: rpx(20);
+  justify-content: flex-start;
+}
+
+.small-box {
+  width: calc(25% - rpx(15)); /* 每行4个 */
+  aspect-ratio: 1 / 1;
+  position: relative;
+  border-radius: rpx(10);
+  overflow: hidden;
+  cursor: pointer;
+  transition: transform 0.3s ease, box-shadow 0.3s ease;
+
+  &:hover {
+    transform: translateY(rpx(-5));
+    box-shadow: 0 rpx(10) rpx(20) rgba(0, 0, 0, 0.1);
+  }
+}
+
+.nested-box {
+  width: 100%;
+  height: 100%;
+  transition: all 0.3s ease;
+  cursor: pointer;
+
+  &:hover {
+    transform: scale(1.05);
+  }
+}
+
+.additional-text {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  background: rgba(0, 0, 0, 0.6);
+  color: white;
+  padding: rpx(10);
+  text-align: center;
+  font-size: rpx(24);
+  backdrop-filter: blur(rpx(5));
+}
+
+/* 移动端样式 */
+.parent-mobile-container {
+  display: none;
+  flex-direction: column;
+  gap: rpx(20);
+  width: 100%;
+}
+
+.parent-mobile-item {
+  display: flex;
+  align-items: center;
+  background: white;
+  border-radius: rpx(15);
+  padding: rpx(20);
+  box-shadow: 0 rpx(5) rpx(15) rgba(0, 0, 0, 0.05);
+  cursor: pointer;
+  transition: transform 0.2s ease, box-shadow 0.2s ease;
+
+  &:hover {
+    transform: translateY(rpx(-2));
+    box-shadow: 0 rpx(8) rpx(20) rgba(0, 0, 0, 0.1);
+  }
+}
+
+.parent-mobile-image {
+  width: rpx(120);
+  height: rpx(120);
+  border-radius: rpx(10);
+  overflow: hidden;
+  margin-right: rpx(20);
+
+  img {
+    width: 100%;
+    height: 100%;
+    object-fit: cover;
+  }
+}
+
+.parent-mobile-content {
+  flex: 1;
+}
+
+.parent-mobile-title {
+  font-size: rpx(28);
+  font-weight: 500;
+  color: #333;
+  margin-bottom: rpx(10);
+  display: flex;
+  align-items: center;
+  gap: rpx(10);
+}
+
+.parent-mobile-index {
+  background: #44449c;
+  color: white;
+  width: rpx(30);
+  height: rpx(30);
+  border-radius: rpx(5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: rpx(20);
+}
+
+.parent-mobile-desc {
+  font-size: rpx(24);
+  color: #666;
+  line-height: rpx(32);
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  .parent-mobile-course-container {
+    padding: rpx(15);
+  }
+
+  .page-header {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: rpx(15);
+  }
+
+  .small-box {
+    width: calc(50% - rpx(10)); /* 移动端每行2个 */
+  }
+
+  .parent-mobile-container {
+    display: flex;
+  }
+
+  .course-list {
+    justify-content: center;
+  }
+}
+
+@media (max-width: 480px) {
+  .small-box {
+    width: 100%; /* 超小屏幕上每行1个 */
+  }
+}
+
+.empty-state {
+  width: 100%;
+  text-align: center;
+  padding: rpx(40);
+  color: #999;
+  font-size: rpx(28);
+}
+</style>

+ 88 - 10
src/components/customCourse/CustomCourseDetail.vue → src/views/ParentMobile/ParentMobileCourseDetail.vue

@@ -93,7 +93,7 @@
 </template>
 
 <script setup>
-import { ref, computed, onMounted } from 'vue'
+import { ref, computed, onMounted, onUnmounted } from 'vue'
 import { useRouter, useRoute } from 'vue-router'
 import {
   Search,
@@ -171,7 +171,7 @@ const handleSaveProgress = async (type, progress) => {
 }
 
 const goBack = () => {
-  router.push('/ai-general-course')
+  router.go(-1)
 }
 
 const handleSelect = (index) => {
@@ -244,7 +244,27 @@ const handleFullscreenChange = (isFullscreenNow) => {
   isFullscreen.value = isFullscreenNow
 }
 
+// 监听设备方向变化
+const handleOrientationChange = () => {
+  // 在全屏状态下,设备方向改变时强制重新调整视频容器尺寸
+  if (isFullscreen.value) {
+    // 使用setTimeout确保DOM更新完成后再执行
+    setTimeout(() => {
+      // 触发一次强制重绘
+      const videoArea = document.querySelector('.mobile-video-area');
+      if (videoArea) {
+        videoArea.style.display = 'none';
+        void videoArea.offsetWidth; // 强制重排
+        videoArea.style.display = '';
+      }
+    }, 100);
+  }
+};
+
 onMounted(async () => {
+  // 监听设备方向变化事件
+  window.addEventListener('orientationchange', handleOrientationChange);
+  
   const typeIdParam = history.state?.typeId || router.currentRoute.value.query.typeId
   if (typeIdParam) {
     typeId.value = typeIdParam
@@ -294,6 +314,11 @@ onMounted(async () => {
 
   gradeId.value = globalState.initGradeId()
 })
+
+onUnmounted(() => {
+  // 移除设备方向变化事件监听器
+  window.removeEventListener('orientationchange', handleOrientationChange);
+});
 </script>
 
 <style scoped lang="scss">
@@ -395,14 +420,24 @@ onMounted(async () => {
   overflow: hidden;
 }
 
+/* 修复全屏模式下的视频显示问题 */
 .mobile-container.fullscreen-active .mobile-video-area {
-  position: fixed;
-  top: 0;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  z-index: 9999;
-  margin-top: 0;
+  position: fixed !important;
+  top: 0 !important;
+  left: 0 !important;
+  right: 0 !important;
+  bottom: 0 !important;
+  z-index: 9999 !important;
+  margin-top: 0 !important;
+  /* 使用视口单位确保在设备方向改变时适应屏幕 */
+  width: 100vw !important;
+  height: 100vh !important;
+  min-height: 100vh !important;
+  max-height: 100vh !important;
+  /* 确保视频容器占据全部可用空间 */
+  display: flex !important;
+  align-items: center !important;
+  justify-content: center !important;
 }
 
 .mobile-container.fullscreen-active .mobile-header {
@@ -450,16 +485,40 @@ onMounted(async () => {
 .mobile-video-area :deep(.full-box-video),
 .mobile-video-area :deep(.ppt-container) {
   border-radius: 0 !important;
+  width: 100% !important;
+  height: 100% !important;
+  max-width: 100% !important;
+  max-height: 100% !important;
 }
 
 .mobile-video-area :deep(*) {
   width: 100% !important;
   height: 100% !important;
+  max-width: 100% !important;
   max-height: 100% !important;
-  object-fit: cover !important;
+  object-fit: contain !important; /* 使用contain确保视频完全可见 */
   border-radius: 0 !important;
 }
 
+/* 特别处理全屏模式下的视频播放器 */
+.mobile-container.fullscreen-active .mobile-video-area :deep(.d-player-wrap),
+.mobile-container.fullscreen-active .mobile-video-area :deep(.full-box-video),
+.mobile-container.fullscreen-active .mobile-video-area :deep(.ppt-container) {
+  width: 100% !important;
+  height: 100% !important;
+  max-width: 100% !important;
+  max-height: 100% !important;
+  position: relative !important;
+}
+
+.mobile-container.fullscreen-active .mobile-video-area :deep(video) {
+  object-fit: contain !important;
+  width: 100% !important;
+  height: 100% !important;
+  max-width: 100% !important;
+  max-height: 100% !important;
+}
+
 .mobile-chapter-list {
   flex: 1;
   padding: 0;
@@ -609,4 +668,23 @@ onMounted(async () => {
   color: #ccc;
   font-size: 16px;
 }
+
+/* 处理设备方向变化时的全屏视频 */
+@media screen and (orientation: landscape) {
+  .mobile-container.fullscreen-active .mobile-video-area {
+    width: 100vw !important;
+    height: 100vh !important;
+    min-height: 100vh !important;
+    max-height: 100vh !important;
+  }
+}
+
+@media screen and (orientation: portrait) {
+  .mobile-container.fullscreen-active .mobile-video-area {
+    width: 100vw !important;
+    height: 100vh !important;
+    min-height: 100vh !important;
+    max-height: 100vh !important;
+  }
+}
 </style>