forked from zhongyidian/super_video
feat: 完善视频学习进度缓存
完善新手导航和三大创作模块的视频完成缓存、未完成提示与学习进度计算,确保进度按实际学习资源完成情况更新。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
1f8723aabd
commit
6f289959be
63 files changed
+3139
-1126
No files matched your search
@@ -1,9 +1,10 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, nextTick, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { onBeforeRouteLeave, useRouter } from 'vue-router'
|
||||
import ImgButton from '@/components/Button/ImgButton.vue'
|
||||
import { GuideSteps, GuideStepsItem } from '@/components/Guide'
|
||||
import StepNavigation from '@/components/Guide/StepNavigation.vue'
|
||||
import UnfinishedLearningPrompt from '@/components/UnfinishedLearningPrompt'
|
||||
import { Video } from '@/components'
|
||||
import QuestionQuiz, {
|
||||
type Question,
|
||||
@@ -79,11 +80,35 @@ const navigationSteps = ref(rawSteps)
|
||||
|
||||
// 步骤导航相关状态
|
||||
const showStepNavigation = ref(false)
|
||||
const showUnfinishedPrompt = ref(false)
|
||||
const pendingLeavePath = ref<string | null>(null)
|
||||
const allowRouteLeave = ref(false)
|
||||
const currentNavigationStep = ref(0) // 对应视频索引,从0开始
|
||||
|
||||
// 视频列表
|
||||
const currentVideoIndex = ref(0)
|
||||
|
||||
const getLearningVideoKey = (index: number) =>
|
||||
`basic-shooting-skills:${navigationSteps.value[index]?.id ?? index}`
|
||||
|
||||
const completedNavigationSteps = computed(() =>
|
||||
navigationSteps.value.map(
|
||||
(_, index) =>
|
||||
basicElementsStore.learningVideosWatched[getLearningVideoKey(index)] ===
|
||||
true,
|
||||
),
|
||||
)
|
||||
|
||||
const hasUnfinishedLearningVideos = computed(() =>
|
||||
completedNavigationSteps.value.some((completed) => !completed),
|
||||
)
|
||||
|
||||
const markCurrentLearningVideoWatched = () => {
|
||||
basicElementsStore.markLearningVideoWatched(
|
||||
getLearningVideoKey(currentVideoIndex.value),
|
||||
)
|
||||
}
|
||||
|
||||
//按顺序播放
|
||||
const currentVideo = computed(
|
||||
() => navigationSteps.value[currentVideoIndex.value].videoUrl,
|
||||
@@ -101,7 +126,7 @@ const getQuestionsForVideo = (index: number): Question[] => {
|
||||
id: 1,
|
||||
title: '',
|
||||
description:
|
||||
'(单选)如果你想让观众“看清环境、理解空间关系”,更适合用哪种镜头?',
|
||||
'【单选题】如果你想让观众“看清环境、理解空间关系”,更适合用哪种镜头?',
|
||||
options: [
|
||||
{
|
||||
id: 'a',
|
||||
@@ -129,7 +154,7 @@ const getQuestionsForVideo = (index: number): Question[] => {
|
||||
id: 2,
|
||||
title: '',
|
||||
description:
|
||||
'(多选题)下面这些拍摄场景中,哪些更适合使用"慢动作"来表现?',
|
||||
'【多选题】下面这些拍摄场景中,哪些更适合使用"慢动作"来表现?',
|
||||
options: [
|
||||
{
|
||||
id: 'a',
|
||||
@@ -163,7 +188,8 @@ const getQuestionsForVideo = (index: number): Question[] => {
|
||||
{
|
||||
id: 3,
|
||||
title: '',
|
||||
description: '(单选)你觉得下面哪句话,更接近“新手拍视频的正确思路”?',
|
||||
description:
|
||||
'【单选题】你觉得下面哪句话,更接近“新手拍视频的正确思路”?',
|
||||
options: [
|
||||
{
|
||||
id: 'a',
|
||||
@@ -209,6 +235,8 @@ const handleClose = () => {
|
||||
const handlePlay = () => {}
|
||||
|
||||
const onEnded = () => {
|
||||
markCurrentLearningVideoWatched()
|
||||
|
||||
// 在指定视频结束时弹出答题
|
||||
if (
|
||||
currentVideoIndex.value === 1 ||
|
||||
@@ -250,6 +278,25 @@ const handleQuestionsComplete = () => {
|
||||
// 答题完成后继续播放下一个视频
|
||||
handleVideoChange()
|
||||
}
|
||||
|
||||
const handleContinueLearning = () => {
|
||||
showUnfinishedPrompt.value = false
|
||||
pendingLeavePath.value = null
|
||||
}
|
||||
|
||||
const handleConfirmLeave = () => {
|
||||
if (!pendingLeavePath.value) return
|
||||
allowRouteLeave.value = true
|
||||
showUnfinishedPrompt.value = false
|
||||
router.push(pendingLeavePath.value)
|
||||
}
|
||||
|
||||
onBeforeRouteLeave((to) => {
|
||||
if (allowRouteLeave.value || !hasUnfinishedLearningVideos.value) return true
|
||||
pendingLeavePath.value = to.fullPath
|
||||
showUnfinishedPrompt.value = true
|
||||
return false
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -313,10 +360,17 @@ const handleQuestionsComplete = () => {
|
||||
:background-image="getStaticImage('work/vlog背景全屏待定')"
|
||||
:steps="navigationSteps"
|
||||
:current-step-index="currentNavigationStep"
|
||||
:completed-steps="completedNavigationSteps"
|
||||
@step-click="handleStepClick"
|
||||
@close="handleStepNavigationClose"
|
||||
/>
|
||||
|
||||
<UnfinishedLearningPrompt
|
||||
:visible="showUnfinishedPrompt"
|
||||
@continue="handleContinueLearning"
|
||||
@leave="handleConfirmLeave"
|
||||
/>
|
||||
|
||||
<GuideSteps
|
||||
:visible="showIntroGuide"
|
||||
position-offset-y="85%"
|
||||
@@ -326,7 +380,7 @@ const handleQuestionsComplete = () => {
|
||||
欢迎来到基础拍摄训练区!
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem :audio-src="getPublicPath('audio/py_1_019.MP3')">
|
||||
我会带你依次认识手机摄像头、看懂景别、用好慢动作与延时。
|
||||
我会带你认识手机摄像头、看懂景别、了解慢动作与延迟摄影。
|
||||
</GuideStepsItem>
|
||||
<GuideStepsItem :audio-src="getPublicPath('audio/py_1_020.MP3')">
|
||||
还会教你拍出更稳的微距和更亮的夜景。
|
||||
|
||||
Reference in new issue
Block a user