瀏覽代碼

Merge remote-tracking branch 'origin/wanzi' into muzi

liyanbo 3 月之前
父節點
當前提交
c569b1d222

+ 99 - 2
src/components/Image/ImageView.vue

@@ -41,7 +41,7 @@
 </template>
 
 <script setup>
-import { defineProps, computed, ref, onMounted, onUnmounted } from 'vue'
+import { defineProps, computed, ref, onMounted, onUnmounted, defineEmits } from 'vue'
 import videoImage01 from '@/assets/icon/videoImage01.png'
 import videoImage02 from '@/assets/icon/videoImage02.png'
 // 消息提示
@@ -52,9 +52,13 @@ const props = defineProps({
   imagePath: { type: String, required: true },
   altText: { type: String, default: '课程图片' },
   autoPlay: { type: Boolean, default: true },
-  interval: { type: Number, default: 3000 }
+  interval: { type: Number, default: 3000 },
+  courseId: { type: String } // 课程ID,用于保存进度
 })
 
+// 定义emits
+const emits = defineEmits(['saveProgress'])
+
 // 计算属性:将逗号分隔的图片路径字符串转换为数组
 const images = computed(() => {
   if (!props.imagePath) return []
@@ -67,13 +71,68 @@ const currentIndex = ref(0)
 const carouselWrapper = ref(null)
 const autoplayTimer = ref(null)
 
+// 记录已经保存的进度百分比
+const savedProgress = ref([])
+// 节流时间间隔(毫秒)
+const THROTTLE_TIME = 3000
+
+// 定义节流函数
+const throttle = (fn, delay) => {
+  let lastCall = 0
+  return function (...args) {
+    const now = Date.now()
+    if (now - lastCall >= delay) {
+      lastCall = now
+      return fn.apply(this, args)
+    }
+  }
+}
+
+// 保存进度(带节流)
+const saveProgress = throttle(async (progress) => {
+  try {
+    // 保存到localStorage,下次加载续播
+    if (props.courseId) {
+      localStorage.setItem(
+        `imageProgress_${props.courseId}`,
+        JSON.stringify({
+          progress: progress,
+          currentIndex: currentIndex.value,
+          timestamp: Date.now()
+        })
+      )
+    }
+
+    // 通过emit事件通知父组件保存进度
+    emits('saveProgress', "image", progress)
+    savedProgress.value.push(progress)
+  } catch (error) {
+    console.error(`保存进度失败:`, error)
+  }
+}, THROTTLE_TIME)
+
 // 下一张图片 - 取消循环切换,在最后一张时显示提示
 const nextSlide = () => {
   if (currentIndex.value < images.value.length - 1) {
     currentIndex.value++
+    // 计算当前进度
+    const progressPercentage = Math.round(((currentIndex.value + 1) / images.value.length) * 100);
+    // 保存进度
+    saveProgress(progressPercentage);
+    // 检查是否到达最后一张图片
+    if (currentIndex.value === images.value.length - 1) {
+      // 保存100%进度
+      if (!savedProgress.value.includes(100)) {
+        saveProgress(100);
+      }
+    }
   } else {
     // 已经是最后一张图片,显示提示信息
     ElMessage.warning('已播放到最后一张图片')
+    // 确保在最后一张图片时保存100%进度
+    if (!savedProgress.value.includes(100)) {
+      saveProgress(100);
+    }
   }
 }
 
@@ -90,6 +149,17 @@ const prevSlide = () => {
 // 跳转到指定图片
 const goToSlide = (index) => {
   currentIndex.value = index
+  // 计算当前进度
+  const progressPercentage = Math.round(((currentIndex.value + 1) / images.value.length) * 100);
+  // 保存进度
+  saveProgress(progressPercentage);
+  // 检查是否到达最后一张图片
+  if (currentIndex.value === images.value.length - 1) {
+    // 保存100%进度
+    if (!savedProgress.value.includes(100)) {
+      saveProgress(100);
+    }
+  }
 }
 
 
@@ -99,6 +169,33 @@ onUnmounted(() => {
     clearInterval(autoplayTimer.value)
   }
 })
+
+// 组件挂载时
+onMounted(() => {
+  // 加载保存的进度
+  loadSavedProgress();
+})
+
+// 加载保存的进度
+const loadSavedProgress = () => {
+  if (props.courseId) {
+    try {
+      const savedData = localStorage.getItem(`imageProgress_${props.courseId}`);
+      if (savedData) {
+        const { progress, currentIndex: savedIndex } = JSON.parse(savedData);
+        if (savedIndex !== undefined && savedIndex >= 0 && savedIndex < images.value.length) {
+          currentIndex.value = savedIndex;
+          // 检查是否已有保存的进度点
+          if (progress >= 10) savedProgress.value.push(10);
+          if (progress >= 50) savedProgress.value.push(50);
+          if (progress >= 100) savedProgress.value.push(100);
+        }
+      }
+    } catch (error) {
+      console.error('读取保存的进度失败:', error);
+    }
+  }
+}
 </script>
 
 <style scoped lang="scss">

+ 95 - 1
src/components/PPT/PptView.vue

@@ -42,7 +42,7 @@
 </template>
 
 <script setup>
-import { ref, onMounted, onUnmounted, defineProps } from 'vue'
+import { ref, onMounted, onUnmounted, defineProps, defineEmits } from 'vue'
 import { ElMessage } from 'element-plus'
 // 导入图标
 import leftImg from '@/assets/icon/videoImage01.png'
@@ -58,8 +58,52 @@ const totalPages = ref(10)
 // 定义props
 const props = defineProps({
   pptPath: { type: String }, // PPT路径
+  courseId: { type: String } // 课程ID,用于保存进度
 })
 
+// 定义emits
+const emits = defineEmits(['saveProgress'])
+
+// 记录已经保存的进度百分比
+const savedProgress = ref([])
+// 节流时间间隔(毫秒)
+const THROTTLE_TIME = 3000
+
+// 定义节流函数
+const throttle = (fn, delay) => {
+  let lastCall = 0
+  return function (...args) {
+    const now = Date.now()
+    if (now - lastCall >= delay) {
+      lastCall = now
+      return fn.apply(this, args)
+    }
+  }
+}
+
+// 保存进度(带节流)
+const saveProgress = throttle(async (progress) => {
+  try {
+    // 保存到localStorage,下次加载续播
+    if (props.courseId) {
+      localStorage.setItem(
+        `pptProgress_${props.courseId}`,
+        JSON.stringify({
+          progress: progress,
+          currentPage: currentPage.value,
+          timestamp: Date.now()
+        })
+      )
+    }
+
+    // 通过emit事件通知父组件保存进度
+    emits('saveProgress', "ppt", progress)
+    savedProgress.value.push(progress)
+  } catch (error) {
+    console.error(`保存进度失败:`, error)
+  }
+}, THROTTLE_TIME)
+
 // 修改PPT渲染完成处理
 const handlePptRendered = (pptInfo) => {
   // 获取总页数
@@ -106,8 +150,23 @@ const nextPage = () => {
   if (currentPage.value < totalPages.value) {
     currentPage.value++;
     scrollToPage(currentPage.value);
+    // 计算当前进度
+    const progressPercentage = Math.round((currentPage.value / totalPages.value) * 100);
+    // 保存进度
+    saveProgress(progressPercentage);
+    // 检查是否到达最后一页
+    if (currentPage.value === totalPages.value) {
+      // 保存100%进度
+      if (!savedProgress.value.includes(100)) {
+        saveProgress(100);
+      }
+    }
   } else {
     ElMessage.warning('已播放到最后一页')
+    // 确保在最后一页时保存100%进度
+    if (!savedProgress.value.includes(100)) {
+      saveProgress(100);
+    }
   }
 }
 
@@ -125,6 +184,17 @@ const prevPage = () => {
 const goToSlide = (index) => {
   currentPage.value = index;
   scrollToPage(currentPage.value);
+  // 计算当前进度
+  const progressPercentage = Math.round((currentPage.value / totalPages.value) * 100);
+  // 保存进度
+  saveProgress(progressPercentage);
+  // 检查是否到达最后一页
+  if (currentPage.value === totalPages.value) {
+    // 保存100%进度
+    if (!savedProgress.value.includes(100)) {
+      saveProgress(100);
+    }
+  }
 }
 
 // 滚动到指定页方法
@@ -147,9 +217,33 @@ onMounted(() => {
   }
   // 初始滚动到第一页
   scrollToPage(1);
+  // 加载保存的进度
+  loadSavedProgress();
   // 添加窗口大小监听
   window.addEventListener('resize', handleResize);
 })
+
+// 加载保存的进度
+const loadSavedProgress = () => {
+  if (props.courseId) {
+    try {
+      const savedData = localStorage.getItem(`pptProgress_${props.courseId}`);
+      if (savedData) {
+        const { progress, currentPage: savedPage } = JSON.parse(savedData);
+        if (savedPage && savedPage > 0 && savedPage <= totalPages.value) {
+          currentPage.value = savedPage;
+          scrollToPage(currentPage.value);
+          // 检查是否已有保存的进度点
+          if (progress >= 10) savedProgress.value.push(10);
+          if (progress >= 50) savedProgress.value.push(50);
+          if (progress >= 100) savedProgress.value.push(100);
+        }
+      }
+    } catch (error) {
+      console.error('读取保存的进度失败:', error);
+    }
+  }
+}
 // 组件卸载时移除监听
 onUnmounted(() => {
   window.removeEventListener('resize', handleResize);

+ 13 - 17
src/views/AIPage/AIDevelop.vue

@@ -128,10 +128,19 @@
               @saveProgress="handleSaveProgress"
           />
           <!-- 图片 -->
-          <ImageView v-if="course.courseContentType === 'image'" :imagePath="course.courseImagePath" altText="课程图片"></ImageView>
+          <ImageView v-if="course.courseContentType === 'image'" 
+                     :imagePath="course.courseImagePath" 
+                     altText="课程图片"
+                     :courseId="course.id"
+                     @saveProgress="handleSaveProgress"
+          ></ImageView>
 
           <!-- PPT -->
-          <PptView v-if="course.courseContentType === 'ppt'" :pptPath="course.pptPath" ref="pptRef"></PptView>
+          <PptView v-if="course.courseContentType === 'ppt'" 
+                  :pptPath="course.pptPath" 
+                  :courseId="course.id"
+                  @saveProgress="handleSaveProgress"
+                  ref="pptRef"></PptView>
 
           <!--文生文-->
           <TextToText class="contentClass" v-if="course.courseContentType === 'aiTextToText'" ref="aiTextToText"></TextToText>
@@ -1356,9 +1365,6 @@ $text-color: #483d8b; // 文本颜色:靛蓝色
     border-radius: rpx(4); // 滑块圆角
     transition: background-color 0.3s ease; // 颜色过渡效果
 
-    &:hover {
-      //background-color: darken($primary-color, 10%); // 悬停时滑块颜色加深
-    }
   }
 
   // 滚动条轨道样式
@@ -1395,16 +1401,6 @@ $text-color: #483d8b; // 文本颜色:靛蓝色
   }
 }
 
-// 优化发送按钮样式
-.send-button {
-  //background: linear-gradient(90deg, $primary-color, $secondary-color);
-  border: none;
-  color: white;
-
-  &:hover {
-    //background: linear-gradient(90deg, darken($primary-color, 5%), darken($secondary-color, 5%));
-  }
-}
 </style>
 
 <style lang="scss">
@@ -1458,9 +1454,9 @@ $text-color: #483d8b; // 文本颜色:靛蓝色
 
 .contentClass{
   width: 70%;
-  height: 80%;
+  height: 80vh;
   margin: 0 auto;
   border-radius: rpx(15);
-  overflow: hidden;
+  overflow: auto;
 }
 </style>

+ 13 - 4
src/views/laboratory/ExperimentalInterface.vue

@@ -41,10 +41,19 @@
               v-memo="[course.id, course.courseContentType, course.courseContent]"
           />
           <!-- 图片 -->
-          <ImageView v-if="course.courseContentType === 'image'" :imagePath="course.courseContent" altText="课程图片"></ImageView>
+          <ImageView v-if="course.courseContentType === 'image'" 
+                     :imagePath="course.courseContent" 
+                     altText="课程图片"
+                     :courseId="course.id"
+                     @saveProgress="handleSaveProgress"
+          ></ImageView>
 
           <!-- PPT -->
-          <PptView v-if="course.courseContentType === 'ppt'" :pptPath="course.courseContent" ref="pptRef"></PptView>
+          <PptView v-if="course.courseContentType === 'ppt'" 
+                  :pptPath="course.courseContent" 
+                  :courseId="course.id"
+                  @saveProgress="handleSaveProgress"
+                  ref="pptRef"></PptView>
 
           <!--文生文-->
           <TextToText class="contentClass" v-if="course.courseContentType === 'aiTextToText'" ref="aiTextToText"
@@ -1100,9 +1109,9 @@ $text-color: #483d8b; // 文本颜色:靛蓝色
 
 .contentClass{
   width: 70%;
-  height: 80%;
+  height: 80vh;
   margin: 0 auto;
   border-radius: rpx(15);
-  overflow: hidden;
+  overflow: auto;
 }
 </style>

+ 13 - 4
src/views/programming/Interface.vue

@@ -39,10 +39,19 @@
               @saveProgress="handleSaveProgress"
           />
           <!-- 图片 -->
-          <ImageView v-if="course.courseContentType === 'image'" :imagePath="course.courseContent" altText="课程图片"></ImageView>
+          <ImageView v-if="course.courseContentType === 'image'" 
+                     :imagePath="course.courseContent" 
+                     altText="课程图片"
+                     :courseId="course.id"
+                     @saveProgress="handleSaveProgress"
+          ></ImageView>
 
           <!-- PPT -->
-          <PptView v-if="course.courseContentType === 'ppt'" :pptPath="course.courseContent" ref="pptRef"></PptView>
+          <PptView v-if="course.courseContentType === 'ppt'" 
+                  :pptPath="course.courseContent" 
+                  :courseId="course.id"
+                  @saveProgress="handleSaveProgress"
+                  ref="pptRef"></PptView>
 
           <!--文生文-->
           <TextToText class="contentClass" v-if="course.courseContentType === 'aiTextToText'" ref="aiTextToText"></TextToText>
@@ -1088,9 +1097,9 @@ $text-color: #483d8b; // 文本颜色:靛蓝色
 
 .contentClass{
   width: 70%;
-  height: 80%;
+  height: 80vh;
   margin: 0 auto;
   border-radius: rpx(15);
-  overflow: hidden;
+  overflow: auto;
 }
 </style>