forked from zhongyidian/super_video
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
567 lines
13 KiB
Vue
567 lines
13 KiB
Vue
<script lang="tsx" setup>
|
|
import { getBackgroundImage, getPublicPath, getStaticImage, IMAGE_PATHS } from '@/utils'
|
|
import { GuideSteps } from '@/components/Guide'
|
|
import { onBeforeUnmount, ref, computed } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
import { ImgButton } from '@/components/Button'
|
|
|
|
const router = useRouter()
|
|
|
|
const back = () => {
|
|
// 跳转设备准备
|
|
router.back()
|
|
}
|
|
const steps = ref([
|
|
{
|
|
id: 'step1',
|
|
content:
|
|
'设备准备妥当后,我们就该走进真实场景,开启实地取景的环节啦,一起去捕捉那些适合拍摄的画面吧!',
|
|
audioSrc: getPublicPath('audio/py_2_013.MP3')
|
|
}
|
|
])
|
|
|
|
const showGuide = ref(false)
|
|
const guideTriggered = ref(false)
|
|
const guideTimer = ref<ReturnType<typeof setTimeout> | null>(null)
|
|
const viewedMenuKeys = ref<Set<string>>(new Set())
|
|
const hiddenbar = ref(false)
|
|
const currentIndex = ref(0) // 当前显示的图片索引
|
|
const selectedMenuIndex = ref(0) // 当前选中的菜单项索引
|
|
|
|
type EquipmentCategoryId = 'phone' | 'phone-stabilizer' | 'wireless-lavalier-mic'
|
|
interface EquipmentProduct {
|
|
img: string
|
|
}
|
|
interface EquipmentCategory {
|
|
id: EquipmentCategoryId
|
|
name: string
|
|
disabled: boolean
|
|
titleImg: string
|
|
contentImg: string
|
|
products: EquipmentProduct[]
|
|
}
|
|
|
|
const categories = ref<EquipmentCategory[]>([
|
|
{
|
|
id: 'phone',
|
|
name: '手机',
|
|
disabled: false,
|
|
titleImg: getStaticImage('equipment/标题-苹果.png'),
|
|
contentImg: getStaticImage('equipment/内容-苹果.png'),
|
|
products: [
|
|
{ img: getStaticImage('equipment/设备-手机1.png') },
|
|
{ img: getStaticImage('equipment/设备-手机2.png') }
|
|
]
|
|
},
|
|
{
|
|
id: 'phone-stabilizer',
|
|
name: '手机稳定器',
|
|
disabled: false,
|
|
titleImg: getStaticImage('equipment/手机稳定器标题.png'),
|
|
contentImg: getStaticImage('equipment/手机稳定器图文.png'),
|
|
products: [{ img: getStaticImage('equipment/手机稳定器.png') }]
|
|
},
|
|
{
|
|
id: 'wireless-lavalier-mic',
|
|
name: '无线领夹麦克风',
|
|
disabled: false,
|
|
titleImg: getStaticImage('equipment/无线领夹麦克风标题.png'),
|
|
contentImg: getStaticImage('equipment/无线领夹麦克风图文.png'),
|
|
products: [{ img: getStaticImage('equipment/无线领夹麦克风.png') }]
|
|
}
|
|
])
|
|
|
|
categories.value = categories.value.map(c => ({
|
|
...c,
|
|
disabled: (c.products?.length ?? 0) === 0
|
|
}))
|
|
|
|
// 默认选中的菜单也算作已查看
|
|
if (categories.value[0] && !categories.value[0].disabled) {
|
|
viewedMenuKeys.value.add(categories.value[0].id)
|
|
}
|
|
|
|
const maybeTriggerGuide = () => {
|
|
if (guideTriggered.value) return
|
|
const enabledIds = categories.value.filter(c => !c.disabled).map(c => c.id)
|
|
if (enabledIds.length === 0) return
|
|
const allViewed = enabledIds.every(id => viewedMenuKeys.value.has(id))
|
|
if (!allViewed) return
|
|
guideTriggered.value = true
|
|
guideTimer.value = setTimeout(() => {
|
|
showGuide.value = true
|
|
guideTimer.value = null
|
|
}, 3000)
|
|
}
|
|
|
|
onBeforeUnmount(() => {
|
|
if (guideTimer.value) {
|
|
clearTimeout(guideTimer.value)
|
|
guideTimer.value = null
|
|
}
|
|
})
|
|
|
|
const currentCategory = computed(
|
|
() => categories.value[selectedMenuIndex.value] ?? categories.value[0]
|
|
)
|
|
const currentProducts = computed(() => currentCategory.value?.products ?? [])
|
|
const currentTitleImg = computed(() => currentCategory.value?.titleImg ?? '')
|
|
const currentContentImg = computed(() => currentCategory.value?.contentImg ?? '')
|
|
const hiddenbarclick = () => {
|
|
hiddenbar.value = !hiddenbar.value
|
|
}
|
|
|
|
// 选择菜单项
|
|
const selectMenuItem = (index: number, item: { id: string; name: string; disabled: boolean }) => {
|
|
if (item.disabled) {
|
|
return
|
|
}
|
|
selectedMenuIndex.value = index
|
|
currentIndex.value = 0
|
|
viewedMenuKeys.value.add(item.id)
|
|
maybeTriggerGuide()
|
|
}
|
|
|
|
// 下一张图片
|
|
const nextPhone = () => {
|
|
if (currentIndex.value < currentProducts.value.length - 1) {
|
|
currentIndex.value++
|
|
}
|
|
}
|
|
|
|
// 上一张图片
|
|
const prevPhone = () => {
|
|
if (currentIndex.value > 0) {
|
|
currentIndex.value--
|
|
}
|
|
}
|
|
</script>
|
|
<template>
|
|
<div class="equipment-index overflow-hidden">
|
|
<!-- 背景图片 -->
|
|
<div
|
|
class="absolute inset-0 bg-cover bg-center bg-no-repeat equipment-bg"
|
|
:style="{ backgroundImage: getBackgroundImage(IMAGE_PATHS.EQUIPMENT.BG) }"
|
|
></div>
|
|
|
|
<div class="equipment-bar">
|
|
<img src="@/assets/images/equipment/侧边导航栏.png" alt="" :hidden="hiddenbar" />
|
|
<!-- 内容列表 -->
|
|
<div class="equipment-item" :hidden="hiddenbar">
|
|
<div class="menu-list">
|
|
<div
|
|
v-for="(item, index) in categories"
|
|
:key="item.id"
|
|
class="menu-item"
|
|
:class="{
|
|
'menu-item--active': selectedMenuIndex === index,
|
|
'menu-item--disabled': item.disabled
|
|
}"
|
|
@click="selectMenuItem(index, item)"
|
|
>
|
|
<div
|
|
class="menu-item__indicator"
|
|
v-if="selectedMenuIndex === index && !item.disabled"
|
|
></div>
|
|
<span class="menu-item__text">{{ item.name }}</span>
|
|
<div class="menu-item__status" v-if="item.disabled">
|
|
<!-- <span class="status-text">未解锁</span> -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 设备准备按钮 -->
|
|
<div class="equipment-bt">
|
|
<img src="@/assets/images/equipment/按钮选中-设备准备.png" alt="" />
|
|
</div>
|
|
<div
|
|
:class="['cursor-pointer', hiddenbar ? 'equipment-unfold1' : 'equipment-unfold2']"
|
|
@click="hiddenbarclick()"
|
|
>
|
|
<img
|
|
:src="
|
|
hiddenbar
|
|
? getStaticImage('equipment/按钮-展开.png')
|
|
: getStaticImage('equipment/按钮-收缩.png')
|
|
"
|
|
alt=""
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div class="equipment-layout">
|
|
<div class="equipment-home">
|
|
<div
|
|
class="equipment-leftbutton"
|
|
@click="prevPhone"
|
|
:style="{ visibility: currentIndex > 0 ? 'visible' : 'hidden' }"
|
|
>
|
|
<img src="@/assets/images/equipment/按钮-左滑.png" alt="" />
|
|
</div>
|
|
<div class="equipment-phoneImg">
|
|
<img :src="currentProducts[currentIndex]?.img" alt="" />
|
|
</div>
|
|
<div
|
|
class="equipment-rightbutton"
|
|
@click="nextPhone"
|
|
:style="{ visibility: currentIndex < currentProducts.length - 1 ? 'visible' : 'hidden' }"
|
|
>
|
|
<img src="@/assets/images/equipment/按钮-右滑.png" alt="" />
|
|
</div>
|
|
</div>
|
|
<div class="equipment-purpose">
|
|
<div class="plate">
|
|
<img src="@/assets/images/equipment/浮空屏.png" alt="" />
|
|
</div>
|
|
|
|
<div class="title">
|
|
<img :src="currentTitleImg" alt="" />
|
|
</div>
|
|
<div class="plate-content">
|
|
<div class="text">
|
|
<img :src="currentContentImg" alt="" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<ImgButton class="absolute right-0 top-0" :image="IMAGE_PATHS.COMPONENTS.BACK" @click="back" />
|
|
<!-- 调试按钮组 -->
|
|
<!-- <div class="debug-controls">
|
|
<button @click="enableAllMenuItems" class="debug-btn">启用全部</button>
|
|
<button @click="disableAllMenuItems" class="debug-btn">禁用全部</button>
|
|
<button @click="toggleMenuItem('bluetooth-remote')" class="debug-btn">切换蓝牙遥控器</button>
|
|
</div> -->
|
|
|
|
<!-- 引导步骤 -->
|
|
<GuideSteps
|
|
:visible="showGuide"
|
|
:steps="steps"
|
|
:highlight-padding="12"
|
|
:highlight-radius="20"
|
|
position-offset-y="85%"
|
|
/>
|
|
</div>
|
|
</template>
|
|
<style lang="less" scoped>
|
|
.equipment-index {
|
|
position: relative;
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.equipment-layout {
|
|
position: relative;
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.equipment-bar {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
z-index: 10;
|
|
|
|
.equipment-bt {
|
|
position: absolute;
|
|
top: 0;
|
|
left: -135px;
|
|
width: 577px;
|
|
|
|
img {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
}
|
|
|
|
.equipment-unfold1 {
|
|
position: absolute;
|
|
top: 490px;
|
|
left: -41px;
|
|
width: 150px;
|
|
|
|
img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: contain;
|
|
}
|
|
}
|
|
|
|
.equipment-unfold2 {
|
|
position: absolute;
|
|
top: 490px;
|
|
left: 268px;
|
|
width: 150px;
|
|
|
|
img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: contain;
|
|
}
|
|
}
|
|
|
|
.equipment-item {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
padding-top: 220px;
|
|
padding-left: 20px;
|
|
|
|
.menu-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
//background: linear-gradient(135deg, #1a2a4a 0%, #0f1a2e 100%);
|
|
border-radius: 12px;
|
|
padding: 16px 12px;
|
|
// box-shadow:
|
|
// 0 0 20px rgba(64, 150, 255, 0.3),
|
|
// inset 0 0 20px rgba(64, 150, 255, 0.1);
|
|
// backdrop-filter: blur(10px);
|
|
}
|
|
|
|
.menu-item {
|
|
position: relative;
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 24px 32px;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
min-height: 44px;
|
|
|
|
&:hover {
|
|
// background: rgba(64, 150, 255, 0.1);
|
|
transform: translateX(4px);
|
|
}
|
|
|
|
&--active {
|
|
// background: rgba(64, 150, 255, 0.2);
|
|
// box-shadow: 0 0 15px rgba(64, 150, 255, 0.4);
|
|
|
|
.menu-item__text {
|
|
color: #ffffff;
|
|
text-shadow:
|
|
0 0 10px rgba(64, 150, 255, 0.8),
|
|
0 0 20px rgba(64, 150, 255, 0.6),
|
|
0 0 30px rgba(64, 150, 255, 0.4);
|
|
font-weight: 600;
|
|
}
|
|
}
|
|
|
|
&__indicator {
|
|
position: absolute;
|
|
left: 0px;
|
|
top: 45%;
|
|
transform: translateY(-50%);
|
|
width: 6px;
|
|
height: 38px;
|
|
background: #ffffff;
|
|
border-radius: 2px;
|
|
box-shadow: 0 0 16px rgba(255, 255, 255, 0.8);
|
|
}
|
|
|
|
&__text {
|
|
color: #64a5ff;
|
|
font-size: 30px;
|
|
font-weight: 800;
|
|
text-shadow: 0 0 8px rgba(64, 150, 255, 0.6);
|
|
transition: all 0.3s ease;
|
|
user-select: none;
|
|
}
|
|
|
|
&__status {
|
|
position: absolute;
|
|
right: 16px;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
|
|
.status-text {
|
|
font-size: 12px;
|
|
color: #999;
|
|
background: rgba(0, 0, 0, 0.6);
|
|
padding: 2px 8px;
|
|
border-radius: 4px;
|
|
border: 1px solid #333;
|
|
}
|
|
}
|
|
|
|
// 禁用状态样式
|
|
&--disabled {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
pointer-events: auto; // 保持可点击以显示禁用提示
|
|
|
|
&:hover {
|
|
transform: none;
|
|
// background: rgba(255, 0, 0, 0.1);
|
|
}
|
|
|
|
.menu-item__text {
|
|
color: #666;
|
|
text-shadow: none;
|
|
}
|
|
|
|
.menu-item__indicator {
|
|
display: none;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.guide-ui {
|
|
top: 80% !important;
|
|
}
|
|
|
|
.dragon-character {
|
|
top: 80% !important;
|
|
}
|
|
}
|
|
|
|
.equipment-home {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
|
|
.equipment-leftbutton {
|
|
position: absolute;
|
|
top: 511px;
|
|
left: 350px;
|
|
width: 200px;
|
|
height: 200px;
|
|
cursor: pointer;
|
|
z-index: 10;
|
|
}
|
|
|
|
.equipment-phoneImg {
|
|
position: absolute;
|
|
top: 313px;
|
|
left: 500px;
|
|
width: 446px;
|
|
height: 484px;
|
|
|
|
img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: contain;
|
|
}
|
|
}
|
|
|
|
.equipment-rightbutton {
|
|
position: absolute;
|
|
top: 511px;
|
|
right: 770px;
|
|
width: 200px;
|
|
height: 200px;
|
|
cursor: pointer;
|
|
z-index: 10;
|
|
}
|
|
}
|
|
|
|
.equipment-purpose {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
|
|
.plate {
|
|
position: absolute;
|
|
top: 30px;
|
|
left: 1200px;
|
|
width: 600px;
|
|
/* 调整为你需要的宽度 */
|
|
height: 1000px;
|
|
/* 调整为你需要的高度 */
|
|
|
|
img {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
}
|
|
|
|
.plate-content {
|
|
position: absolute;
|
|
top: 144px;
|
|
right: 100px;
|
|
width: 600px;
|
|
height: 797px;
|
|
overflow: hidden;
|
|
/* 隐藏超出部分 */
|
|
object-fit: contain;
|
|
|
|
// display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
overflow-y: auto;
|
|
/* 允许垂直滚动 */
|
|
scrollbar-width: none;
|
|
/* Firefox隐藏滚动条 */
|
|
-ms-overflow-style: none;
|
|
/* IE和Edge隐藏滚动条 */
|
|
perspective: 1000px;
|
|
|
|
&::-webkit-scrollbar {
|
|
display: none;
|
|
/* Chrome, Safari隐藏滚动条 */
|
|
}
|
|
}
|
|
|
|
.title {
|
|
// margin-top: 47px;
|
|
width: 400px;
|
|
z-index: 2;
|
|
position: absolute;
|
|
top: 36px;
|
|
left: 1304px;
|
|
}
|
|
|
|
.text {
|
|
position: absolute;
|
|
top: -9px;
|
|
left: 8px;
|
|
z-index: 2;
|
|
transform: rotate3d(0, 1, 0, -20deg);
|
|
|
|
img {
|
|
width: 100%;
|
|
height: auto;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 调试控制按钮样式
|
|
.debug-controls {
|
|
position: absolute;
|
|
top: 20px;
|
|
left: 20px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
z-index: 1000;
|
|
|
|
.debug-btn {
|
|
background: rgba(0, 0, 0, 0.8);
|
|
color: white;
|
|
border: 1px solid #333;
|
|
padding: 6px 12px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-size: 12px;
|
|
transition: background 0.3s ease;
|
|
|
|
&:hover {
|
|
background: rgba(0, 0, 0, 0.9);
|
|
}
|
|
}
|
|
}
|
|
</style>
|