Files
super_video/src/views/film/after-editing/editing/index.vue
T
2026-09-21 10:30:13 +08:00

248 lines
6.4 KiB
Vue

<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import {
getBackgroundImage,
getPublicPath,
getStaticImage,
IMAGE_PATHS,
} from '@/utils'
import { ImgButton } from '@/components/Button'
import { GuideSteps, type GuideStep } from '@/components/Guide'
import { useFilmStore } from '@/stores'
const router = useRouter()
const film = useFilmStore()
const isEditingUnlocked = computed(
() => film.editingVideosWatched.start === true,
)
const isEditingItemLocked = (videoKey: string) =>
videoKey !== 'start' && !isEditingUnlocked.value
const completionIcon = (completed: boolean) =>
getStaticImage(`midterm/${completed ? '完成' : '未完成'}.png`)
const editingItems = computed(() => [
{
image: 'film/after-editing/剪辑初始',
videoKey: 'start',
onClick: goStart,
iconClass: 'right-14 top-9',
class:
'absolute left-[0px] bottom-[42%] translate-y-1/2 bg-cover bg-center bg-no-repeat',
},
{
image: 'film/after-editing/img/节奏型剪辑',
textImage: 'film/after-editing/text/节奏型剪辑',
videoKey: 'rhythm',
onClick: goRhythm,
class: 'absolute right-[215px] top-[170px] bg-cover bg-center bg-no-repeat',
},
{
image: 'film/after-editing/img/声音转场',
textImage: 'film/after-editing/text/声音转场',
videoKey: 'soundTransition',
onClick: goSoundTransition,
class: 'absolute right-[215px] top-[420px] bg-cover bg-center bg-no-repeat',
},
{
image: 'film/after-editing/img/快切',
textImage: 'film/after-editing/text/快切',
videoKey: 'cut',
onClick: goCut,
class: 'absolute right-[620px] top-[560px] bg-cover bg-center bg-no-repeat',
},
{
image: 'film/after-editing/img/关联剪辑',
textImage: 'film/after-editing/text/关联剪辑',
videoKey: 'association',
onClick: goAssociation,
class:
'absolute right-[215px] bottom-[290px] bg-cover bg-center bg-no-repeat',
},
{
image: 'film/after-editing/img/连续剪辑',
textImage: 'film/after-editing/text/连续剪辑',
videoKey: 'continuity',
onClick: goContinuity,
class:
'absolute right-[215px] bottom-[35px] bg-cover bg-center bg-no-repeat',
},
])
const handleClose = () => {
router.back()
}
const goStart = () => {
router.push({ name: 'FilmEditingStart' })
}
const goRhythm = () => {
router.push({ name: 'FilmEditingRhythm' })
}
const goSoundTransition = () => {
router.push({ name: 'FilmEditingSoundTransition' })
}
const goCut = () => {
router.push({ name: 'FilmEditingCut' })
}
const goAssociation = () => {
router.push({ name: 'FilmEditingAssociation' })
}
const goContinuity = () => {
router.push({ name: 'FilmEditingContinuity' })
}
const goEditingItem = (item: (typeof editingItems.value)[number]) => {
if (isEditingItemLocked(item.videoKey)) return
item.onClick()
}
// 6 个剪辑子视频学习完成后的一次性引导
const editingCompleteSteps: GuideStep[] = [
{
id: 'editing-complete-step1',
content:
'刚才我们提到的剪辑方式,并不是孤立存在的技巧,而是针对不同问题的解决方案。所以,理解剪辑逻辑才是最重要的!',
audioSrc: getPublicPath('audio/py_4_018.MP3'),
},
]
const showEditingCompleteGuide = ref(false)
watch(
() => film.allEditingVideosWatched,
(watched) => {
if (watched && film.isGuideFilmEditingComplete) {
showEditingCompleteGuide.value = true
}
},
{ immediate: true },
)
const handleEditingCompleteGuideDone = () => {
showEditingCompleteGuide.value = false
film.setIsGuideFilmEditingComplete(false)
}
</script>
<template>
<div class="relative w-full h-full overflow-hidden">
<!-- 背景 -->
<div
class="absolute inset-0 bg-cover bg-center bg-no-repeat"
:style="{
backgroundImage: getBackgroundImage(
isEditingUnlocked
? 'film/after-editing/剪辑底图亮'
: 'film/after-editing/剪辑底图灰',
),
}"
></div>
<!-- 标题 -->
<img
class="absolute left-0 top-6"
:src="getStaticImage('film/after-editing/剪辑标题')"
alt=""
/>
<div
v-for="item in editingItems"
:key="item.videoKey"
:class="item.class"
>
<div
:class="[
'relative transition-all duration-200',
isEditingItemLocked(item.videoKey)
? 'opacity-40 pointer-events-none'
: 'hover:scale-105 hover:cursor-pointer hover:brightness-125',
]"
@click="goEditingItem(item)"
>
<!-- img -->
<img :src="getStaticImage(item.image)" />
<!-- 点击提示 -->
<img
v-if="item.videoKey === 'start' && !isEditingUnlocked"
class="pointer-events-none absolute right-6 -bottom-40 z-20 start-click-hint"
:src="getStaticImage('film/after-editing/点击此处开始')"
alt=""
/>
<!-- 文本 -->
<img
class="absolute right-0 bottom-6 translate-x-[64%] translate-y-1/2 z-10"
:src="getStaticImage(item.textImage ?? '')"
alt=""
/>
<!-- 完成图标 -->
<img
:class="[
'pointer-events-none absolute z-10 w-16',
item.iconClass ?? '-right-6 -top-6',
]"
:src="
completionIcon(film.editingVideosWatched[item.videoKey] === true)
"
alt=""
/>
</div>
</div>
<!-- 关闭 -->
<ImgButton
class="absolute right-0 top-0 z-20"
:image="IMAGE_PATHS.COMPONENTS.BACK"
@click="handleClose"
/>
<!-- 6 个剪辑视频学完后的一次性引导 -->
<GuideSteps
v-if="showEditingCompleteGuide"
:steps="editingCompleteSteps"
position-offset-y="85%"
@complete="handleEditingCompleteGuideDone"
/>
</div>
</template>
<style scoped>
.start-click-hint {
animation: start-click-hint 1.2s ease-in-out infinite;
}
@keyframes start-click-hint {
0%,
100% {
transform: translateY(0) scale(1);
}
50% {
transform: translateY(-14px) scale(1.05);
}
}
.onsite-btn {
@apply relative flex flex-col items-start backdrop-blur-md rounded-2xl px-10 py-8 text-left bg-white/5 hover:bg-white/10 border border-white/10 hover:border-white/30 transition-all duration-200 cursor-pointer;
}
.onsite-btn-title {
@apply text-4xl font-bold mb-4;
}
.onsite-btn-desc {
@apply text-2xl leading-9 opacity-80;
}
</style>