forked from zhongyidian/super_video
feat: 对接各个视频数据
This commit is contained in:
1 parent
6103453e32
commit
6ab98c4764
339 files changed
+17316
-1531
No files matched your search
+210
-16
@@ -1,25 +1,29 @@
|
||||
<script lang="ts" setup>
|
||||
import { getBackgroundImage, getStaticImage, IMAGE_PATHS } from '@/utils'
|
||||
import { getBackgroundImage, IMAGE_PATHS, getStaticImage } from '@/utils'
|
||||
import { ImgButton } from '@/components/Button'
|
||||
import { ModuleSwitcher } from './components/ModuleSwitcher'
|
||||
import { computed, ref, onMounted } from 'vue'
|
||||
import { computed, ref, onMounted, onUnmounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useUserStore } from '@/stores'
|
||||
|
||||
const router = useRouter()
|
||||
const user = useUserStore()
|
||||
|
||||
// 响应式状态
|
||||
const status = ref(false)
|
||||
const guideShow = ref(false)
|
||||
const selectedModule = ref<'vlog' | 'film' | 'interview'>('vlog')
|
||||
const selectedModule = ref<'vlog' | 'film' | 'interview'>('film')
|
||||
const isImageLoading = ref(false)
|
||||
|
||||
// 预加载图片映射
|
||||
const imageMap = {
|
||||
vlog: IMAGE_PATHS.ACTION.VIDEO1,
|
||||
film: IMAGE_PATHS.ACTION.VIDEO3,
|
||||
interview: IMAGE_PATHS.ACTION.VIDEO2
|
||||
film: IMAGE_PATHS.ACTION.VIDEO2,
|
||||
interview: IMAGE_PATHS.ACTION.VIDEO3
|
||||
}
|
||||
|
||||
//获取新手导航引导状态
|
||||
const isGuideNewUser = computed(() => user.isGuideNewUser)
|
||||
|
||||
// 预加载所有图片
|
||||
const preloadImages = () => {
|
||||
const imageUrls = Object.values(imageMap).map(path => getBackgroundImage(path))
|
||||
@@ -36,7 +40,9 @@ const handleOpenGuide = () => {
|
||||
|
||||
const handleCloseGuide = () => {
|
||||
guideShow.value = false
|
||||
status.value = true
|
||||
if (isGuideNewUser.value) {
|
||||
user.setIsGuideNewUser(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleModuleChange = (module: 'vlog' | 'film' | 'interview') => {
|
||||
@@ -52,6 +58,7 @@ const handleModuleChange = (module: 'vlog' | 'film' | 'interview') => {
|
||||
}
|
||||
|
||||
const handleClick = () => {
|
||||
console.log(selectedModule.value.charAt(0).toUpperCase() + selectedModule.value.slice(1))
|
||||
router.push({
|
||||
//首字母大写
|
||||
name: selectedModule.value.charAt(0).toUpperCase() + selectedModule.value.slice(1)
|
||||
@@ -69,10 +76,86 @@ const handleSkill = () => {
|
||||
})
|
||||
}
|
||||
|
||||
// 新手导航数据
|
||||
const nodes = [
|
||||
{
|
||||
id: 1,
|
||||
num: '1',
|
||||
label: '三大基础要素',
|
||||
x: 20,
|
||||
y: 30,
|
||||
hasChildren: true,
|
||||
children: [
|
||||
{ id: 1, label: '构图', icon: 'home/action/新手导航构图', routeName: 'Composition' },
|
||||
{ id: 2, label: '光', icon: 'home/action/新手导航光', routeName: 'Light' },
|
||||
{ id: 3, label: '运镜', icon: 'home/action/新手导航运镜', routeName: 'CameraMovement' }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
num: '2',
|
||||
label: '基础拍摄技巧',
|
||||
x: 50,
|
||||
y: 60,
|
||||
hasChildren: false,
|
||||
routeName: 'BasicShootingSkills'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
num: '3',
|
||||
label: '短视频剪辑技巧',
|
||||
x: 80,
|
||||
y: 30,
|
||||
hasChildren: false,
|
||||
routeName: 'ShortVideoEditingSkills'
|
||||
}
|
||||
]
|
||||
|
||||
// 显示子节点的节点ID
|
||||
const showChildrenNodeId = ref<number | null>(null)
|
||||
|
||||
// 处理节点点击
|
||||
const handleNodeClick = (node: any, event?: MouseEvent) => {
|
||||
if (event) {
|
||||
event.stopPropagation()
|
||||
}
|
||||
|
||||
if (node.hasChildren) {
|
||||
// 如果点击的是有子节点的节点,切换显示状态
|
||||
if (showChildrenNodeId.value === node.id) {
|
||||
showChildrenNodeId.value = null
|
||||
} else {
|
||||
showChildrenNodeId.value = node.id
|
||||
}
|
||||
} else {
|
||||
// 如果点击的是没有子节点的节点,直接跳转
|
||||
if (node.routeName) {
|
||||
router.push({ name: node.routeName })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理子节点点击
|
||||
const handleChildNodeClick = (childNode: any, event: MouseEvent) => {
|
||||
event.stopPropagation()
|
||||
if (childNode.routeName) {
|
||||
router.push({ name: childNode.routeName })
|
||||
}
|
||||
}
|
||||
|
||||
// 点击外部关闭子节点
|
||||
const handleClickOutside = () => {
|
||||
showChildrenNodeId.value = null
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
preloadImages()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
// 清理工作
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -98,14 +181,14 @@ onMounted(() => {
|
||||
|
||||
<!-- 技能树 按钮 -->
|
||||
<ImgButton
|
||||
v-if="status"
|
||||
v-if="!isGuideNewUser"
|
||||
@click="handleSkill"
|
||||
:image="IMAGE_PATHS.ACTION.SKILLS_BTN"
|
||||
class="absolute bottom-0 right-0 z-30"
|
||||
/>
|
||||
|
||||
<!-- 新手指导遮罩 -->
|
||||
<div v-if="!status" class="absolute inset-0 bg-black/50 z-10"></div>
|
||||
<div v-if="isGuideNewUser" class="absolute inset-0 bg-black/50 z-10"></div>
|
||||
|
||||
<!-- 新手指导 -->
|
||||
<div
|
||||
@@ -120,20 +203,131 @@ onMounted(() => {
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="cursor-pointer absolute bottom-0 left-0 w-full h-[911px] bg-cover bg-center bg-no-repeat z-40"
|
||||
class="absolute bottom-0 left-0 w-full h-[911px] bg-cover bg-center bg-no-repeat z-40 flex flex-col items-center justify-center pt-40"
|
||||
:style="{ backgroundImage: getBackgroundImage(IMAGE_PATHS.ACTION.FOOTER_BG) }"
|
||||
v-else
|
||||
>
|
||||
<ImgButton
|
||||
:image="IMAGE_PATHS.ACTION.DOWN"
|
||||
class="absolute top-60 right-1/2 translate-x-1/2"
|
||||
class="absolute top-60 right-1/2 translate-x-1/2 z-50"
|
||||
@click="handleCloseGuide"
|
||||
/>
|
||||
<img
|
||||
class="absolute bottom-0 left-1/2 -translate-x-1/2"
|
||||
:src="getStaticImage('home/新手导航')"
|
||||
alt=""
|
||||
/>
|
||||
|
||||
<!-- 新手导航内容 -->
|
||||
<div class="relative w-[880px] h-[400px] mt-20">
|
||||
<div class="w-full h-full relative" @click="handleClickOutside">
|
||||
<!-- 标题区域 -->
|
||||
<div class="text-center mt-10 mb-8">
|
||||
<h2 class="text-5xl font-bold mb-3 text-[#7bfffd] tracking-wider drop-shadow-lg">
|
||||
新手导航
|
||||
</h2>
|
||||
<p class="text-4xl text-white font-bold drop-shadow-md">点击节点即可开始学习</p>
|
||||
</div>
|
||||
|
||||
<!-- 节点图表 -->
|
||||
<div class="absolute inset-0 top-[60px]">
|
||||
<!-- 连线 (SVG) -->
|
||||
<svg class="absolute inset-0 w-full h-full pointer-events-none">
|
||||
<!-- 左侧装饰线 -> 节点1 -->
|
||||
<line
|
||||
x1="0%"
|
||||
y1="45%"
|
||||
:x2="nodes[0].x + '%'"
|
||||
:y2="nodes[0].y + '%'"
|
||||
stroke="#7bfffd"
|
||||
stroke-width="5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<!-- 节点1 -> 节点2 -->
|
||||
<line
|
||||
:x1="nodes[0].x + '%'"
|
||||
:y1="nodes[0].y + '%'"
|
||||
:x2="nodes[1].x + '%'"
|
||||
:y2="nodes[1].y + '%'"
|
||||
stroke="#7bfffd"
|
||||
stroke-width="5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<!-- 节点2 -> 节点3 -->
|
||||
<line
|
||||
:x1="nodes[1].x + '%'"
|
||||
:y1="nodes[1].y + '%'"
|
||||
:x2="nodes[2].x + '%'"
|
||||
:y2="nodes[2].y + '%'"
|
||||
stroke="#7bfffd"
|
||||
stroke-width="5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<!-- 节点3 -> 右侧装饰线 -->
|
||||
<line
|
||||
:x1="nodes[2].x + '%'"
|
||||
:y1="nodes[2].y + '%'"
|
||||
x2="100%"
|
||||
y2="45%"
|
||||
stroke="#7bfffd"
|
||||
stroke-width="5"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<!-- 节点 -->
|
||||
<div
|
||||
v-for="node in nodes"
|
||||
:key="node.id"
|
||||
class="absolute transform -translate-x-1/2 -translate-y-1/2"
|
||||
:style="{ left: node.x + '%', top: node.y + '%' }"
|
||||
@click="handleNodeClick(node, $event)"
|
||||
>
|
||||
<div
|
||||
class="cursor-pointer flex flex-col items-center group transition-all duration-300 hover:scale-110"
|
||||
>
|
||||
<!-- 圆圈 -->
|
||||
<div
|
||||
class="w-24 h-24 rounded-full flex items-center justify-center text-5xl font-bold text-white z-10 relative transition-all duration-300 group-hover:bg-[#ff4d8c]"
|
||||
:class="
|
||||
showChildrenNodeId === node.id
|
||||
? 'bg-[#ff4d8c] shadow-[0_0_20px_rgba(255,77,140,0.6)]'
|
||||
: 'bg-[#60c8db] shadow-[0_0_20px_rgba(96, 200, 219,0.6)]'
|
||||
"
|
||||
>
|
||||
{{ node.num }}
|
||||
<!-- 选中状态的光晕 -->
|
||||
<div
|
||||
v-if="showChildrenNodeId === node.id"
|
||||
class="absolute inset-0 rounded-full border-4 border-white/20 animate-pulse"
|
||||
></div>
|
||||
</div>
|
||||
<!-- 标签 -->
|
||||
<div
|
||||
class="mt-2 text-4xl font-bold text-white tracking-wider drop-shadow-[0_2px_4px_rgba(0,0,0,0.5)] whitespace-nowrap"
|
||||
>
|
||||
{{ node.label }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 子节点图标(当点击三大基础要素时显示) -->
|
||||
<div
|
||||
v-if="node.hasChildren && showChildrenNodeId === node.id"
|
||||
class="absolute -top-40 left-1/2 transform -translate-x-1/2 flex z-20"
|
||||
>
|
||||
<div
|
||||
v-for="childNode in node.children"
|
||||
:key="childNode.id"
|
||||
class="flex flex-col items-center cursor-pointer"
|
||||
@click.stop="handleChildNodeClick(childNode, $event)"
|
||||
>
|
||||
<!-- 图标 -->
|
||||
<div
|
||||
class="w-36 flex items-center justify-center transition-all duration-300 hover:scale-110"
|
||||
>
|
||||
<img :src="getStaticImage(childNode.icon)" :alt="childNode.label" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -67,7 +67,7 @@ const moduleConfigs: ModuleConfig[] = [
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'film',
|
||||
type: 'interview',
|
||||
normalImage: IMAGE_PATHS.ACTION.MODULE_BTN2,
|
||||
selectedImage: IMAGE_PATHS.ACTION.SELECTED_BTN2,
|
||||
className: 'w-[1087px] h-[822px] left-[calc(50%+50px)] -translate-x-1/2 -bottom-4',
|
||||
@@ -86,7 +86,7 @@ const moduleConfigs: ModuleConfig[] = [
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'interview',
|
||||
type: 'film',
|
||||
normalImage: IMAGE_PATHS.ACTION.MODULE_BTN3,
|
||||
selectedImage: IMAGE_PATHS.ACTION.SELECTED_BTN3,
|
||||
className: 'w-[943px] h-[822px] right-[320px] -bottom-4',
|
||||
|
||||
Reference in new issue
Block a user