liyanbo il y a 10 mois
Parent
commit
dba521860d

BIN
src/assets/10互联网快速发展.mp4


BIN
src/assets/11黄金时代.mp4


BIN
src/assets/12课堂提问.mp4


BIN
src/assets/13大模型时代.mp4


BIN
src/assets/14趣味实操.mp4


BIN
src/assets/15课程总结.mp4


BIN
src/assets/1课前回顾.mp4


BIN
src/assets/2课程引入.mp4


BIN
src/assets/3图灵测试.mp4


BIN
src/assets/4课堂提问.mp4


BIN
src/assets/5达特茅斯会议.mp4


BIN
src/assets/6课堂选择.mp4


BIN
src/assets/7聊天机器人.mp4


BIN
src/assets/8专家系统.mp4


BIN
src/assets/9课堂互动.mp4


+ 1 - 1
src/router/index.js

@@ -11,7 +11,7 @@ const routes = [
     component: () => import('../views/AIGeneralCourse.vue')
   },
   // AI初体验
-   {
+  {
     path: '/ai-initial-experience',
     component: () => import('../views/AIInitialExperience.vue')
   },

+ 2 - 2
src/style.css

@@ -6,8 +6,8 @@
   font-style: normal;
 }
 :root {
-  font-family: 'SourceHanSansCN-Regular';
-  /* font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; */
+  /* font-family: 'SourceHanSansCN-Regular'; */
+  font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
   line-height: 1.5;
   font-weight: normal;
   color-scheme: light dark;

+ 0 - 3
src/utils/request.js

@@ -3,8 +3,6 @@
 import axios from 'axios'
 import router from '@/router/index.js'
 
-
-
 // 开发环境(写代码的阶段)  development
 // 生产环境(代码已经写好已经部署到服务器了) production
 // 测试环境(代码已经写好了但是还没有部署) production
@@ -31,7 +29,6 @@ request.interceptors.request.use(function (config) {
   const token = localStorage.getItem('token')
   // 2. 设置 token
   config.headers.token = token
-
   return config;
 }, function (error) {
   // 对请求错误做些什么

+ 230 - 64
src/views/AIDevelop.vue

@@ -11,26 +11,35 @@
         class="toggle-button"
       >
         课程小节
-        <!-- <el-icon><ArrowRightBold /></el-icon> -->
       </el-button>
       <el-drawer v-model="drawerVisible" direction="ltr" size="20%">
         <el-row class="tac">
           <el-col :span="12">
             <h3 class="mb-2">课程小节</h3>
             <el-menu
-            default-active="1"
+              default-active="1"
               class="el-menu-vertical-demo"
               @open="handleOpen"
               @close="handleClose"
+              @select="handleSelect"
             >
-            <el-menu-item
-                v-for="(title, index) in classTitles"
-                :key="index + 1"
-                :index="(index + 1).toString()"
-              >
-                <!-- <el-icon><icon-menu /></el-icon> -->
-                <span>{{ title }}</span>
-              </el-menu-item>
+              <template v-for="item in menuItems" :key="item.index">
+                <el-menu-item v-if="!item.children" :index="item.index">{{
+                  item.title
+                }}</el-menu-item>
+                <el-sub-menu v-else :index="item.index">
+                  <template #title>
+                    <span>{{ item.title }}</span>
+                  </template>
+                  <el-menu-item-group v-if="item.children">
+                    <template v-for="child in item.children" :key="child.index">
+                      <el-menu-item :index="child.index">{{
+                        child.title
+                      }}</el-menu-item>
+                    </template>
+                  </el-menu-item-group>
+                </el-sub-menu>
+              </template>
             </el-menu>
           </el-col>
         </el-row>
@@ -41,7 +50,7 @@
       <div class="inner-box left-box">
         <div class="box-icon" @click="goBack">
           <el-icon class="left-icon"><ArrowLeftBold /></el-icon>
-         {{boxIconTitle}}
+          {{ boxIconTitle }}
         </div>
       </div>
       <div class="inner-box right-box">
@@ -59,13 +68,20 @@
       </div>
     </div>
     <div class="box-2">
+      <!-- 课程标题 autoplay自动播放-->
+      <div class="small-title">
+        <span>{{ smallTitle }}</span>
+      </div>
       <video
         class="full-box-video"
-        @timeupdate="handleTimeUpdate"
+        :src="videoSrc"
         controls
+        autoplay
+        @ended="playNextVideo"
+        @timeupdate="handleTimeUpdate"
         ref="videoRef"
       >
-        <source :src="videoSrc" type="video/mp4">
+        <source :src="videoSrc" type="video/mp4" />
         您的浏览器不支持视频播放。
       </video>
     </div>
@@ -75,8 +91,25 @@
 <script setup>
 import { ref, onMounted } from 'vue'
 import { useRouter } from 'vue-router'
+import { ArrowDown, ArrowRightBold } from '@element-plus/icons-vue'
 import { Search, ArrowLeftBold } from '@element-plus/icons-vue'
-import firstLessonVideo from '@/assets/第一课.mp4'
+import { valueEquals } from 'element-plus'
+// 引入视频
+import video1 from '@/assets/02video/01video.mp4'
+import video2 from '@/assets/02video/02video.mp4'
+import video3 from '@/assets/02video/03video.mp4'
+import video4 from '@/assets/02video/04video.mp4'
+import video5 from '@/assets/02video/05video.mp4'
+import video6 from '@/assets/02video/06video.mp4'
+import video7 from '@/assets/02video/07video.mp4'
+import video8 from '@/assets/02video/08video.mp4'
+import video9 from '@/assets/02video/09video.mp4'
+import video10 from '@/assets/02video/10video.mp4'
+import video11 from '@/assets/02video/11video.mp4'
+import video12 from '@/assets/02video/12video.mp4'
+import video13 from '@/assets/02video/13video.mp4'
+import video14 from '@/assets/02video/14video.mp4'
+import video15 from '@/assets/02video/15video.mp4'
 
 const router = useRouter() // 获取当前路由对象
 // 搜索框
@@ -85,60 +118,160 @@ const SearchInput = ref('')
 const buttonVisible = ref(false)
 // 添加抽屉显示状态
 const drawerVisible = ref(false)
+
+// 定义映射
+const videoMap = {
+  '1-1': video1,
+  '1-2': video2,
+  '1-3': video3,
+  '1-4': video4,
+  '1-5': video5,
+  '1-6': video6,
+  '1-7': video7,
+  '1-8': video8,
+  '1-9': video9,
+  '1-10': video10,
+  '1-11': video11,
+  '1-12': video12,
+  '1-13': video13,
+  '1-14': video14,
+  '1-15': video15
+}
+// 定义视频源
+const videoSrc = ref(video1)
+
 // 返回上一页
 const goBack = () => {
-  router.go(-1) 
+  router.go(-1)
 }
-// 渲染标题
+// 渲染页面标题
 const boxIconTitle = ref('')
 onMounted(() => {
   const title = router.currentRoute.value.query.title
-  if(title){
+  if (title) {
     boxIconTitle.value = String(title)
   }
 })
-// 添加获取抽屉课节标题
-const classTitles = [
-    '课前回顾',
-    '课程引入',
-    '图灵测试',
-    '课堂提问',
-    '达特茅斯会议',
-    '课堂选择',
-    '聊天机器人',
-    '专家系统',
-    '课堂互动',
-    '互联网快速发展',
-    '黄金时代',
-    '课堂提问',
-    '大模型时代',
-    '趣味实操',
-    '课程总结'
-]
 
-//=====视频播放暂停
-//视频路径
-const videoSrc = ref(firstLessonVideo)
+// 菜单打开和关闭的处理函数
+const handleOpen = () => {}
+const handleClose = () => {}
+
+// 动态渲染树型结构
+const menuItems = ref([
+  { index: '1-1', title: '课前回顾' },
+  { index: '1-2', title: '课程引入' },
+  {
+    index: '1',
+    title: '知识讲解',
+    children: [
+      { index: '1-3', title: '图灵测试' },
+      { index: '1-4', title: '课堂提问' },
+      { index: '1-5', title: '达特茅斯会议' },
+      { index: '1-6', title: '课堂选择' },
+      { index: '1-7', title: '聊天机器人' },
+      { index: '1-8', title: '专家系统' },
+      { index: '1-9', title: '课堂互动' },
+      { index: '1-10', title: '互联网快速发展' },
+      { index: '1-11', title: '黄金时代' },
+      { index: '1-12', title: '课堂提问' },
+      { index: '1-13', title: '大模型时代' }
+    ]
+  },
+  { index: '1-14', title: '趣味实操' },
+  { index: '1-15', title: '课程总结' }
+])
+
+// 当前播放的索引
+const currentIndex = ref('1-1')
+
+// 渲染课程标题到视频上方
+const smallTitle = ref('课前回顾')
+const handleSelect = index => {
+  const findTitle = items => {
+    for (const item of items) {
+      if (item.index === index) {
+        return item.title
+      }
+      if (item.children) {
+        const result = findTitle(item.children)
+        if (result) {
+          return result
+        }
+      }
+    }
+    return null
+  }
+  const title = findTitle(menuItems.value)
+  if (title) {
+    smallTitle.value = title
+  }
+  // 根据索引切换视频
+  if (videoMap[index]) {
+    videoSrc.value = videoMap[index]
+    currentIndex.value = index
+  }
+  // 选中标题后关闭抽屉
+  drawerVisible.value = false
+}
+
+// 展平所有菜单项索引
+const flattenMenuItems = () => {
+  const indices = []
+  const traverse = items => {
+    for (const item of items) {
+      if (!item.children) {
+        indices.push(item.index)
+      } else {
+        traverse(item.children)
+      }
+    }
+  }
+  traverse(menuItems.value)
+  return indices
+}
+
+// 记录已经暂停过的时间点索引
+let pausedIndices = ref([])
+// 自动播放下一个视频
+const playNextVideo = () => {
+  const allIndices = flattenMenuItems()
+  const currentIndexInList = allIndices.indexOf(currentIndex.value)
+  if (currentIndexInList !== -1 && currentIndexInList < allIndices.length - 1) {
+    const nextIndex = allIndices[currentIndexInList + 1]
+    handleSelect(nextIndex)
+  }
+  pausedIndices = ref([])
+}
 
 // 视频 ref
 const videoRef = ref(null)
-// 定义需要暂停的时间点(单位:秒)
-const pauseTimes = ref([2, 6, 11])
-// 记录已经暂停过的时间点索引
-const pausedIndices = ref([])
+
+// 定义每个视频对应的暂停时间
+const videoPauseTimes = {
+  [video4]: [1],
+  [video6]: [3],
+  [video9]: [2],
+  [video12]: [1]
+}
+
 
 // 处理视频时间更新事件
 const handleTimeUpdate = () => {
   if (!videoRef.value) return
 
   const currentTime = videoRef.value.currentTime
-  pauseTimes.value.forEach((time, index) => {
-    // 检查是否到达时间点且还未暂停过
-    if (currentTime >= time && !pausedIndices.value.includes(index)) {
-      videoRef.value.pause()
-      pausedIndices.value.push(index)
-    }
-  })
+  const currentPauseTimes = videoPauseTimes[videoSrc.value]
+
+  if (currentPauseTimes) {
+    currentPauseTimes.forEach((time, index) => {
+      // 检查是否到达时间点且还未暂停过
+      if (currentTime >= time && !pausedIndices.value.includes(index)) {
+        videoRef.value.pause()
+        pausedIndices.value.push(index)
+      }
+    })
+  }
 }
 </script>
 
@@ -159,27 +292,50 @@ const handleTimeUpdate = () => {
   flex-direction: column;
   gap: rpx(0);
 }
-.tac .el-menu {
+.tac ::v-deep(.el-menu) {
   background-color: transparent;
   border: none;
   width: 100%;
 }
-.drawer-box ::v-deep(.el-drawer__header){
+
+/* 取消点击后的蓝色字体 el-sub-menu__title*/
+.tac ::v-deep(.el-menu-item.is-active),
+.tac ::v-deep(.el-sub-menu__title.is-active) {
+  color: black;
+}
+// 取消鼠标悬浮颜色
+.tac ::v-deep(.el-sub-menu__title) {
+  width: rpx(130);
+  height: rpx(20);
+  margin-bottom: rpx(5);
+  border-radius: rpx(6);
+}
+.el-menu ::v-deep(.el-sub-menu__title:hover),
+.el-menu ::v-deep(.el-sub-menu__title:focus),
+.el-menu ::v-deep(.el-sub-menu__title:active) {
+  background: linear-gradient(
+    to bottom,
+    #fee78a,
+    #ffce1b
+  ); /* 设置悬停、聚焦、点击状态下的背景色 */
+  background-color: transparent;
+}
+.drawer-box ::v-deep(.el-drawer__header) {
   margin-bottom: rpx(0);
 }
-.mb-2{
+.mb-2 {
   color: black;
   margin-top: rpx(1);
 }
-.el-menu-item{
+.el-menu-item {
   width: rpx(130);
   height: rpx(20);
   margin-bottom: rpx(5);
   border-radius: rpx(6);
 }
-.el-menu-item span{
+.el-menu-item span {
   color: black;
-  font-size: rpx(7);
+  font-size: rpx(8);
 }
 .el-menu ::v-deep(.el-menu-item:hover),
 .el-menu ::v-deep(.el-menu-item:focus),
@@ -199,7 +355,8 @@ const handleTimeUpdate = () => {
 .drawer-box .toggle-button {
   width: rpx(10);
   height: rpx(50);
-  background-color: rgba(165, 209, 247, 0.2);
+  font-size: rpx(7);
+  background-color: rgba(17, 23, 29, 0.2);
   border: none;
   position: relative;
   writing-mode: vertical-lr; // 文字垂直排列,从左到右
@@ -210,7 +367,7 @@ const handleTimeUpdate = () => {
 }
 // 抽屉滚动条样式
 .drawer-box ::v-deep(.el-drawer.ltr) {
-  background-color: rgb(255, 255, 255,0.7);
+  background-color: rgb(255, 255, 255, 0.7);
   box-shadow: 0 8px 8px rgba(202, 52, 52, 0.1);
 }
 .drawer-box ::v-deep(.el-drawer__body)::-webkit-scrollbar {
@@ -257,7 +414,8 @@ const handleTimeUpdate = () => {
   justify-content: flex-start;
   align-items: flex-start;
   flex: 1; // 设置左侧盒子占比为 2
-   cursor: pointer; // 添加鼠标指针样式
+  cursor: pointer; // 添加鼠标指针样式
+  // margin-top: rpx(20);
 }
 .box-icon {
   width: 100%;
@@ -276,8 +434,8 @@ const handleTimeUpdate = () => {
 
 .left-box span {
   position: absolute;
-  top: 20px;
-  left: 20px;
+  // top: 20px;
+  // left: 20px;
   font-size: rpx(11); // 默认字体大小
   color: white;
 }
@@ -288,7 +446,7 @@ const handleTimeUpdate = () => {
 }
 .top-right-box {
   position: absolute; // 添加绝对定位
-  margin-top: rpx(10); // 调整上边距离
+  margin-top: rpx(20); // 调整上边距离
   margin-right: rpx(50); // 调整右边距离
   width: 100%; // 设置盒子宽度,可按需调整
   height: 60px; // 设置盒子高度,可按需调整
@@ -314,7 +472,7 @@ const handleTimeUpdate = () => {
   }
 }
 // 搜索框
-.search-input{
+.search-input {
   width: rpx(100);
   height: rpx(15);
   font-size: rpx(7);
@@ -324,13 +482,13 @@ const handleTimeUpdate = () => {
   flex: 2;
   box-shadow: 0 4px 8px rgba(202, 52, 52, 0.1);
   box-sizing: border-box;
-  padding: 0 rpx(30); // 添加左右内边距
+  // padding: 0 rpx(30); // 添加左右内边距
   display: flex; // 确保子元素水平排列
   flex-wrap: wrap; // 允许子元素换行;
   align-content: center; // 顶部对齐;
   cursor: pointer; // 添加鼠标指针样式
   video.full-box-video {
-    width: 90%;
+    width: 85%;
     height: 90%;
     margin: auto;
     border-radius: rpx(12);
@@ -339,4 +497,12 @@ const handleTimeUpdate = () => {
     background-color: #000;
   }
 }
+.small-title {
+  width: 100%;
+  margin-top: rpx(-20);
+  height: rpx(20);
+  color: white;
+  font-size: rpx(10);
+  justify-content: center; //使子元素水平居中
+}
 </style>