Quellcode durchsuchen

修改视频保存进度接口

丸子 vor 5 Monaten
Ursprung
Commit
1bfb5c621e

+ 20 - 0
src/api/personalized/index.js

@@ -17,4 +17,24 @@ export function getReport (data) {
     method: 'get',
     data: data
   })
+}
+
+
+// 保存记录(blockly编程)
+export function saveRecordBlockly (data) {
+  return axios({
+    url: 'blocklyReport/progress/saveReportProgress',
+    method: 'post',
+    data: data
+  })
+}
+
+
+// 获取评估报告数据(blockly编程)
+export function getReportBlockly (data) {
+  return axios({
+    url: 'blocklyReport/progress/getReportProgress',
+    method: 'get',
+    data: data
+  })
 }

+ 66 - 12
src/components/videopage/VideoPlayer.vue

@@ -54,6 +54,8 @@ import {
 import { videoPlay as Vue3VideoPlay } from 'vue3-video-play'
 import Hls from 'hls.js'
 import { ElMessage } from 'element-plus'
+// 导入全局年级id
+import { globalState } from '@/utils/globalState.js'
 // 导入图标
 import { CloseBold } from '@element-plus/icons-vue'
 
@@ -70,7 +72,7 @@ const props = defineProps({
 })
 
 // 定义emits
-const emits = defineEmits(['timeUpdate', 'videoEnded', 'switchVideo'])
+const emits = defineEmits(['timeUpdate', 'videoEnded', 'switchVideo', 'saveProgress'])
 
 // 视频引用
 const videoRef = ref(null)
@@ -78,6 +80,14 @@ const videoRef = ref(null)
 const hlsRef = ref(null)
 // 记录已经暂停过的时间点索引
 const pausedIndices = ref([])
+// 记录已经保存的进度百分比
+const savedProgress = ref([])
+// 节流时间间隔(毫秒)
+const THROTTLE_TIME = 3000
+// 上次播放进度
+const lastPlayProgress = ref(0)
+// 定义进度数组
+const targetProgresses = [10, 50, 100]
 // 章节要点标记
 const chapterMarkers = ref([])
 // 历史播放位置提示状态
@@ -87,9 +97,22 @@ const lastPlayTime = ref(0)
 // 历史播放提示位置百分比
 const historyTipPosition = ref(0)
 
-// 保存本地进度(只保存到localStorage,用于续播功能)
-const saveLocalProgress = (progress, currentTime) => {
+// 定义节流函数
+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, currentTime) => {
   try {
+    // 保存到localStorage,下次加载视频续播
     localStorage.setItem(
       `videoProgress_${props.courseId}`,
       JSON.stringify({
@@ -98,10 +121,19 @@ const saveLocalProgress = (progress, currentTime) => {
         timestamp: Date.now()
       })
     )
+    // 通过emit事件通知父组件保存进度
+    emits('saveProgress', {
+      progress,
+      currentTime,
+      gradeId: globalState.getGradeId(),
+      typeId: props.typeId,
+      courseId: props.courseId
+    })
+    savedProgress.value.push(progress)
   } catch (error) {
-    console.error(`保存本地进度失败:`, error)
+    console.error(`保存进度失败:`, error)
   }
-}
+}, THROTTLE_TIME)
 
 // 处理视频元数据加载完成
 const handleLoadedMetadata = () => {
@@ -141,9 +173,24 @@ const handleTimeUpdate = ev => {
 
   const progressPercentage =
     duration > 0 ? Math.round((currentTime / duration) * 100) : 0
-    
-  // 保存本地进度用于续播功能
-  saveLocalProgress(progressPercentage, currentTime)
+
+  // 更新最后播放进度
+  lastPlayProgress.value = progressPercentage
+
+  // 检查是否达到目标进度点且尚未保存
+  targetProgresses.some(target => {
+    const isNearTarget = Math.abs(progressPercentage - target) <= 2
+    const isNotSaved = !savedProgress.value.includes(target)
+    if (isNearTarget && isNotSaved) {
+      // 保存目标进度
+      saveProgress(target, currentTime)
+      return true
+    }
+    return false
+  })
+
+  // 使用节流保存进度
+  saveProgress(progressPercentage, currentTime)
 
   // 触发父组件的时间更新事件
   emits('timeUpdate', { currentTime, progressPercentage })
@@ -178,10 +225,11 @@ const handleSeeked = () => {
 
 // 添加视频结束事件处理
 const handleVideoEnded = () => {
-  // 保存本地100%进度用于续播功能
-  saveLocalProgress(100, videoRef.value?.duration || 0)
-  // 触发父组件的视频结束事件
-  emits('videoEnded')
+  // 视频结束时保存100%进度
+  if (!savedProgress.value.includes(100)) {
+    saveProgress(100, videoRef.value.duration)
+  }
+  // emits('videoEnded')
 }
 
 // 在视频加载完成后设置上次播放进度
@@ -194,11 +242,17 @@ const setLastPlayPosition = () => {
       if (currentTime && !isNaN(currentTime) && currentTime > 0) {
         // 存储上次播放位置但不自动跳转
         lastPlayTime.value = currentTime
+        lastPlayProgress.value = progress
         // 计算历史提示位置
         const duration = videoRef.value.duration
         historyTipPosition.value = duration > 0 ? (currentTime / duration) * 100 : 0
         showHistoryTip.value = true
         
+        // 检查是否已有保存的进度点
+        if (progress >= 10) savedProgress.value.push(10)
+        if (progress >= 50) savedProgress.value.push(50)
+        if (progress >= 100) savedProgress.value.push(100)
+        
         // 5秒后自动隐藏历史位置提示
         setTimeout(() => {
           showHistoryTip.value = false

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

@@ -125,6 +125,7 @@
               @timeUpdate="handleVideoTimeUpdate"
               @videoEnded="handleVideoEnded"
               @switchVideo="handleSelect"
+              @saveProgress="handleSaveProgress"
           />
           <!-- 图片 -->
           <ImageView v-if="course.courseContentType === 'image'" :imagePath="course.courseImagePath" altText="课程图片"></ImageView>
@@ -187,7 +188,6 @@ import isDisabledImage from '@/assets/images/permission/isDisabled.png'
 import classImages from '@/assets/icon/class.png'
 import { ClassType } from '@/api/class.js'
 import { Message } from '@/utils/message/Message.js'
-// 保存进度接口
 import { saveRecord } from '@/api/personalized/index.js'
 
 // 导入全局状态
@@ -248,15 +248,22 @@ const courseDataScope = ref([])
 // 测试账号禁用视频
 const isDisabled = ref(false)
 
-// 保存进度相关状态
-const savedProgress = ref([])
-// 节流时间间隔(毫秒)
-const THROTTLE_TIME = 3000
-// 上次播放进度
-const lastPlayProgress = ref(0)
-// 定义进度数组
-const targetProgresses = [10, 50, 100]
-
+  // 保存视频进度接口
+  const handleSaveProgress = async (progressData) => {
+    try {
+      const { progress, gradeId: brpNjId, typeId: brpCtId, courseId: brpCourseId } = progressData
+      
+      await saveRecord({
+        brpNjId: brpNjId || globalState.getGradeId(),
+        brpCtId,
+        brpCourseId,
+        brpType: 'course',
+        brpProgress: progress
+      })
+    } catch (error) {
+      console.error('保存视频进度失败:', error)
+    }
+  }
 
 //课程小节字典
 const menuDict = ref({
@@ -267,71 +274,6 @@ const menuDict = ref({
   5: '课程总结'
 })
 
-// 定义节流函数
-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, currentTime, courseId) => {
-  try {
-    // 保存到localStorage,下次加载视频续播
-    localStorage.setItem(
-      `videoProgress_${courseId}`,
-      JSON.stringify({
-        progress: progress,
-        currentTime: currentTime,
-        timestamp: Date.now()
-      })
-    )
-    // 保存视频进度接口
-    await saveRecord({
-      brpNjId: gradeId.value || globalState.getGradeId(),
-      brpCtId: typeId.value,
-      brpCourseId: courseId,
-      brpType: 'course',
-      brpProgress: progress
-    })
-    savedProgress.value.push(progress)
-  } catch (error) {
-    console.error(`保存进度失败:`, error)
-  }
-}, THROTTLE_TIME)
-
-// 检查并保存进度
-const checkAndSaveProgress = (progressPercentage, currentTime, courseId) => {
-  // 更新最后播放进度
-  lastPlayProgress.value = progressPercentage
-
-  // 检查是否达到目标进度点且尚未保存
-  targetProgresses.some(target => {
-    const isNearTarget = Math.abs(progressPercentage - target) <= 2
-    const isNotSaved = !savedProgress.value.includes(target)
-    if (isNearTarget && isNotSaved) {
-      // 保存目标进度
-      saveProgress(target, currentTime, courseId)
-      return true
-    }
-    return false
-  })
-
-  // 使用节流保存进度
-  saveProgress(progressPercentage, currentTime, courseId)
-}
-
-// 重置保存进度状态
-const resetSaveProgressState = () => {
-  savedProgress.value = []
-  lastPlayProgress.value = 0
-}
-
 // 切换抽屉显示状态的函数
 const toggleDrawer = () => {
   drawerVisible.value = !drawerVisible.value
@@ -356,8 +298,6 @@ const handleSelect = index => {
     console.log("课程id:",courseId.value)
     // 切换标题后,关闭抽屉
     drawerVisible.value = false
-    // 重置保存进度状态
-    resetSaveProgressState()
   } else {
     //视频不存在
     Message().notifyWarning('视频不存在!', true)
@@ -407,12 +347,6 @@ const playNextVideo = () => {
 // 播放结束
 const handleVideoEnded = () => {
   console.log("播放结束")
-  
-  // 如果是视频类型并且有课程ID,保存100%进度
-  if (course.value.courseContentType === 'video' && courseId.value && !savedProgress.value.includes(100)) {
-    saveProgress(100, 0, courseId.value)
-  }
-  
   // 记录当前视频ID为已观看
   if (
     course.value &&
@@ -456,11 +390,6 @@ const disableVideo = (index = course.value.key) => {
 
 // 处理视频时间更新事件
 const handleVideoTimeUpdate = ({ currentTime, progressPercentage, courseConfig: config }) => {
-  // 检查并保存视频进度
-  if (courseId.value) {
-    checkAndSaveProgress(progressPercentage, currentTime, courseId.value)
-  }
-  
   if (config) {
     questionDialogVisible.value = true
     courseConfig.value = config

+ 27 - 8
src/views/programming/Interface.vue

@@ -30,13 +30,14 @@
               :contentType="course.courseContentType"
               :videoPath="course.courseVideoPath"
               :courseId="course.id || ''"
-              :typeId="typeId"
+              :typeId="course.typeId"
               :courseConfigList="course.courseConfigList || []"
               :allIndices="flattenMenuItems()"
               :currentIndex="course.key || ''"
               @timeUpdate="handleVideoTimeUpdate"
               @videoEnded="handleVideoEnded"
               @switchVideo="switchVideo"
+              @saveProgress="handleSaveProgress"
           />
           <!-- 图片 -->
           <ImageView v-if="course.courseContentType === 'image'" :imagePath="course.courseImagePath" altText="课程图片"></ImageView>
@@ -118,7 +119,7 @@ import isDisabledImage from '@/assets/images/permission/isDisabled.png'
 
 import { ClassType } from '@/api/class.js'
 import { Message } from '@/utils/message/Message.js'
-import { saveRecord } from '@/api/personalized/index.js'
+import { saveRecordBlockly } from '@/api/personalized/index.js'
 
 // 导入全局状态
 import { globalState } from '@/utils/globalState.js'
@@ -340,13 +341,13 @@ const handleVideoTimeUpdate = ({ currentTime, progressPercentage, courseConfig:
         }
         if (config.id) {
           // 保存弹窗问题进度
-          await saveRecord({
-            brpNjId: gradeId.value,
-            brpCtId: typeId.value,
+          await saveRecordBlockly({
+            brpZtId: props.courseData.ztId,
+            brpCtId: props.courseData.typeId,
             brpCourseConfigId: config.id,
             brpCourseId: courseId.value,
             brpType: 'courseQuest',
-            brpProgress: progressPercentage
+            brpProgress: 1
           })
         } else {
           console.error('无法保存试题进度: 试题id不存在')
@@ -381,13 +382,13 @@ const initCourseDataScope = () => {
 // 处理父组件传递的课程数据
 const handleParentCourseData = (courseData = props.courseData) => {
   if (!courseData) return false;
-  console.log('从父组件接收到的课程数据:', courseData);
   // 设置返回按钮标题
   boxIconTitle.value = courseData.bcName;
   // 重新定义course接收传递过来的数据
   course.value = {
     id: courseData.id,
     courseName: courseData.bcName,
+    typeId: courseData.bcType,
     courseContentType: courseData.bcContentType,
     courseVideoPath: courseData.bcContent,
     courseConfigList: courseData.blocklyConfigList,
@@ -457,6 +458,7 @@ onMounted(async () => {
 
   // 从路由参数获取typeId
   const typeIdParam = router.currentRoute.value.query.typeId;
+  
   if (typeIdParam) {
     typeId.value = typeIdParam;
     try {
@@ -485,9 +487,26 @@ onMounted(async () => {
   }
   typeSort.value = router.currentRoute.value.query.typeSort;
   // 初始化年级ID
-  gradeId.value = globalState.initGradeId();
+  // gradeId.value = globalState.initGradeId();
 })
 
+// 保存视频进度接口
+const handleSaveProgress = async (progressData) => {
+  try {
+    const { progress, typeId, courseId } = progressData
+    
+    await saveRecordBlockly({
+      brpZtId: props.courseData.ztId,
+      brpCtId: typeId,
+      brpCourseId: courseId,
+      brpType: 'course',
+      brpProgress: progress
+    })
+  } catch (error) {
+    console.error('保存视频进度失败:', error)
+  }
+}
+
 onBeforeUnmount(() => {
   // 组件卸载时的清理
 })

+ 9 - 8
src/views/programming/ProgrammingCourset.vue

@@ -20,7 +20,7 @@
       <!-- 课程提示 -->
       <div class="top-right-box">
         <div class="top-right-inner-box">
-          <div class="course-info-box">{{ originalCourseTitle }}</div>
+          <div class="course-info-box">{{ originalCourseTitle }}000</div>
         </div>
       </div>
     </div>
@@ -83,8 +83,8 @@ const pageTitle = ref('')
 // 保存原始的课程ID和标题
 const originalCourseId = ref('')
 const originalCourseTitle = ref('')
-// 主题ID(从ProgrammingList页面传递过来)
-const topicId = ref('')
+// 类型ID(从ProgrammingList页面传递过来)
+const typeId = ref('')
 // 控制视频界面显示
 const showVideo = ref(false) 
 // 动态课程项数据
@@ -129,17 +129,17 @@ onMounted(() => {
     // 设置页面标题
     pageTitle.value = courseTitle
   }
-  // 获取当前主题ID
-  topicId.value = route.query.topicId
+  // 获取当前类型ID
+  typeId.value = route.query.typeId
   
   // 保存原始的课程ID和标题,返回时使用
   originalCourseId.value = route.query.originalCourseId
   originalCourseTitle.value = route.query.originalCourseTitle
   
   // 获取到topicId后,再调用TopicType接口
-  if (topicId.value) {
-    TopicType(topicId.value).then(res => {
-      console.log(topicId.value, res);
+  if (typeId.value) {
+    
+    TopicType(typeId.value).then(res => {
       if (res && res.data && Array.isArray(res.data)) {
         // 保存原始API返回的数据
         resData.value = res.data;
@@ -174,6 +174,7 @@ const handleCourseItemClick = (item) => {
     const fullCourseData = resData.value.find(course => course.id === item.id)
     if (fullCourseData) {
       selectedCourseData.value = fullCourseData
+      selectedCourseData.value.ztId = originalCourseId.value
     }
   }
 }

+ 8 - 8
src/views/programming/ProgrammingList.vue

@@ -30,16 +30,16 @@
           @mouseleave="handleMouseLeave"
         >
           <div 
-            v-for="(course, index) in specificCourses" 
+            v-for="(courseType, index) in specificCourses" 
             :key="index" 
             class="middle-inner-box"
-            @click="goToProgrammingList(course, index)"
+            @click="goToProgrammingList(courseType, index)"
           >
-            <div class="new-white-box" :class="{ 'active': activeButton === index }" @click="goToProgrammingList(course, index)">
-              <div class="bg-image-container" :style="{ backgroundImage: `url(${course.bgImage})` }"></div>
+            <div class="new-white-box" :class="{ 'active': activeButton === index }" @click="goToProgrammingList(courseType, index)">
+              <div class="bg-image-container" :style="{ backgroundImage: `url(${courseType.bgImage})` }"></div>
               <div class="text-container">
                 <div class="box-title">
-                  <span>{{ course.title }}</span>
+                  <span>{{ courseType.title }}</span>
                 </div>
               </div>
               <!-- unlock背景图盒子 -->
@@ -200,16 +200,16 @@ onMounted(() => {
 
 
 // 跳转到课程详情页面
-const goToProgrammingList = (course, index) => {
+const goToProgrammingList = (courseType, index) => {
   // 设置当前选中项
   activeButton.value = index;
   // 跳转ProgrammingCourset页面,并传递课程信息作为参数
   router.push({
     path: '/programmingCourset',
     query: {
-      courseTitle: course.title,
+      courseTitle: courseType.title,
       courseIndex: index,
-      topicId: course.id, // 当前主题的id,避免与课程ID混淆
+      typeId: courseType.id, // 当前类型的id,避免与课程ID混淆
       originalCourseId: categoryId.value, // 原始的课程ID
       originalCourseTitle: pageTitle.value // 原始的课程标题
     }