forked from zhongyidian/super_video
feat: 完善课程学习与技能树体验
完善课程资源、学习进度与技能树解锁体验,统一视频播放与引导相关交互。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
1 parent
6f289959be
commit
3e258b87d9
314 files changed
+7020
-3386
No files matched your search
+78
-14
@@ -1,4 +1,4 @@
|
||||
import { computed, defineComponent, ref } from 'vue'
|
||||
import { computed, defineComponent, onUnmounted, ref } from 'vue'
|
||||
import {
|
||||
getBackgroundImage,
|
||||
getPublicPath,
|
||||
@@ -6,7 +6,8 @@ import {
|
||||
IMAGE_PATHS,
|
||||
} from '@/utils'
|
||||
import { ImgButton } from '@/components/Button'
|
||||
import { GuideSteps, ImagePreview, Video } from '@/components'
|
||||
import { CourseGuidePopup, CourseFrameworkPopup, GuideSteps, Video } from '@/components'
|
||||
import Loading from './components/Loading.vue'
|
||||
import { useScale } from '@/composables/useScale'
|
||||
import { useBasicElementsStore } from '@/stores/modules/basic-elements'
|
||||
|
||||
@@ -89,10 +90,7 @@ export default defineComponent({
|
||||
const { scale, offsetX, offsetY } = useScale()
|
||||
|
||||
// 首次进入的视频播放序列
|
||||
const introVideos = computed(() => [
|
||||
getPublicPath('video/campus life.mp4'),
|
||||
getPublicPath('video/new/xsdh_CapCut_Tutorial.mp4'),
|
||||
])
|
||||
const introVideos = computed(() => [getPublicPath('video/start.mp4')])
|
||||
const introVideoIndex = ref(0)
|
||||
const showIntroVideo = ref(isFirstVisit)
|
||||
const currentIntroSrc = computed(
|
||||
@@ -116,10 +114,64 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
|
||||
// Loading 加载状态
|
||||
const showLoading = ref(isFirstVisit)
|
||||
const loadingProgress = ref(0)
|
||||
let progressTimer: ReturnType<typeof setInterval> | null = null
|
||||
let loadingFallbackTimer: ReturnType<typeof setTimeout> | null = null
|
||||
|
||||
if (isFirstVisit) {
|
||||
progressTimer = setInterval(() => {
|
||||
if (loadingProgress.value < 99) {
|
||||
loadingProgress.value += 1
|
||||
}
|
||||
}, 60)
|
||||
loadingFallbackTimer = setTimeout(() => {
|
||||
finishLoading()
|
||||
}, 8000)
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
if (progressTimer) clearInterval(progressTimer)
|
||||
if (loadingFallbackTimer) clearTimeout(loadingFallbackTimer)
|
||||
})
|
||||
|
||||
const finishLoading = () => {
|
||||
if (!showLoading.value) return
|
||||
if (progressTimer) {
|
||||
clearInterval(progressTimer)
|
||||
progressTimer = null
|
||||
}
|
||||
if (loadingFallbackTimer) {
|
||||
clearTimeout(loadingFallbackTimer)
|
||||
loadingFallbackTimer = null
|
||||
}
|
||||
loadingProgress.value = 100
|
||||
setTimeout(() => {
|
||||
showLoading.value = false
|
||||
}, 200)
|
||||
}
|
||||
|
||||
const handleIntroVideoPlay = () => {
|
||||
finishLoading()
|
||||
}
|
||||
|
||||
const handleIntroVideoLoaded = () => {
|
||||
finishLoading()
|
||||
}
|
||||
|
||||
const openMindMap = () => {
|
||||
ImagePreview({
|
||||
images: [getStaticImage('maps/dt')],
|
||||
maskClosable: true,
|
||||
CourseFrameworkPopup({
|
||||
getScaleMetrics: () => ({
|
||||
scale: scale.value,
|
||||
offsetX: offsetX.value,
|
||||
offsetY: offsetY.value,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
const openCourseGuide = () => {
|
||||
CourseGuidePopup({
|
||||
getScaleMetrics: () => ({
|
||||
scale: scale.value,
|
||||
offsetX: offsetX.value,
|
||||
@@ -142,19 +194,25 @@ export default defineComponent({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="absolute right-20 bottom-36 kecheng-wrapper">
|
||||
<div class="absolute right-20 bottom-10 space-y-3">
|
||||
<ImgButton
|
||||
class={['kecheng-wrapper']}
|
||||
image={IMAGE_PATHS.BUTTONS.COURSE_FRAME}
|
||||
onClick={openMindMap}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="absolute right-20 bottom-10 zhiying-wrapper">
|
||||
<ImgButton image={IMAGE_PATHS.BUTTONS.OPERATE_GUIDE} />
|
||||
<ImgButton
|
||||
class={['zhiying-wrapper']}
|
||||
image={IMAGE_PATHS.BUTTONS.OPERATE_GUIDE}
|
||||
onClick={openCourseGuide}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{showIntroVideo.value && (
|
||||
<div class="absolute inset-0 z-[10000] bg-black flex items-center justify-center">
|
||||
<Loading
|
||||
visible={showLoading.value}
|
||||
progress={loadingProgress.value}
|
||||
/>
|
||||
<Video
|
||||
src={currentIntroSrc.value}
|
||||
autoplay={true}
|
||||
@@ -162,6 +220,12 @@ export default defineComponent({
|
||||
controls={true}
|
||||
volume={1}
|
||||
fit="contain"
|
||||
onPlay={handleIntroVideoPlay}
|
||||
// onLoadedmetadata={handleIntroVideoLoaded}
|
||||
// onLoadeddata={handleIntroVideoLoaded}
|
||||
// onCanplay={handleIntroVideoLoaded}
|
||||
onCanplaythrough={handleIntroVideoLoaded}
|
||||
onPlayfailed={finishLoading}
|
||||
onEnded={handleIntroVideoEnded}
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user