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