feat(vap播放组件): 取消自动播放设置

This commit is contained in:
hzj 2026-05-01 22:54:19 +08:00
parent 81bf7235e5
commit a6ed1b9ff8
2 changed files with 112 additions and 40 deletions

View File

@ -1,24 +1,38 @@
<template> <template>
<div class="fullPage"> <div class="fullPage">
<!-- 预加载状态 --> <!-- 棰勫姞杞界姸鎬?-->
<div v-if="isLoading" class="loading-container"> <div v-if="isLoading" class="loading-container">
<!-- 页面背景 --> <div class="page-background-layer">
<BackgroundLayer
:useCanvas="true"
:backgroundImages="[imageUrl('bg')]"
:layerStyle="{ position: 'absolute', top: 0, left: 0, minHeight: 0, zIndex: 0 }"
/>
</div>
<!-- 椤甸潰鑳屾櫙 -->
<!-- 加载动画 --> <!-- 鍔犺浇鍔ㄧ敾 -->
<LoadingSpinner /> <LoadingSpinner />
<p>{{ t('loading') }}...</p> <p>{{ t('loading') }}...</p>
</div> </div>
<!-- 主要内容 --> <!-- 涓昏鍐呭 -->
<div class="active-game-shell scroll"> <div class="active-game-shell scroll">
<div class="active-game-stage"> <div class="active-game-stage">
<!-- 头部动画带声音 --> <!-- 澶撮儴鍔ㄧ敾锛堝甫澹伴煶锛?-->
<VapBg class="vap-background-layer" /> <VapBg class="vap-background-layer" />
<!-- 页面背景 --> <div class="page-background-layer">
<BackgroundLayer
:useCanvas="true"
:backgroundImages="[imageUrl('bg')]"
:layerStyle="{ position: 'absolute', top: 0, left: 0, minHeight: 0, zIndex: 0 }"
/>
</div>
<!-- 椤甸潰鑳屾櫙 -->
<!-- 页面内容 --> <!-- 椤甸潰鍐呭 -->
<div class="page-content"> <div class="page-content">
<!-- 累计奖励 --> <!-- 濂栧姳 -->
<itemCenter <itemCenter
style="padding: 0 3vw" style="padding: 0 3vw"
:imgUrl="imageUrl('totalRewardBg')" :imgUrl="imageUrl('totalRewardBg')"
@ -67,7 +81,7 @@
/> />
</itemCenter> </itemCenter>
<!-- 等级任务 --> <!-- 绛夌骇浠诲姟 -->
<itemCenter <itemCenter
style="" style=""
:imgUrl="imageUrl('lvTaskBg')" :imgUrl="imageUrl('lvTaskBg')"
@ -78,7 +92,7 @@ justify-content: flex-start;
gap: 8vw; gap: 8vw;
`" `"
> >
<!-- 标题 --> <!-- 鏍囬 -->
<div style="display: flex; justify-content: center; align-items: center; height: 11vw"> <div style="display: flex; justify-content: center; align-items: center; height: 11vw">
<img <img
v-smart-img v-smart-img
@ -88,9 +102,9 @@ justify-content: flex-start;
/> />
</div> </div>
<!-- 内容 --> <!-- 鍐呭 -->
<div style="width: 100%; display: flex; flex-direction: column; position: relative"> <div style="width: 100%; display: flex; flex-direction: column; position: relative">
<!-- 规则弹窗展示按钮 --> <!-- 瑙勫垯寮圭獥灞曠ず鎸夐挳 -->
<img <img
v-smart-img v-smart-img
src="/src/assets/icon/Azizi/helpWhite.png" src="/src/assets/icon/Azizi/helpWhite.png"
@ -99,9 +113,9 @@ justify-content: flex-start;
@click="openPopup('rule')" @click="openPopup('rule')"
/> />
<!-- 信息展示 --> <!-- 伅灞曠ず -->
<div style="height: 45vw; display: flex; flex-direction: column; gap: 5vw"> <div style="height: 45vw; display: flex; flex-direction: column; gap: 5vw">
<!-- 当前状态 --> <!-- 褰撳墠鐘舵?-->
<div style="display: flex; align-items: center"> <div style="display: flex; align-items: center">
<div <div
style=" style="
@ -128,7 +142,7 @@ justify-content: flex-start;
}} }}
</div> </div>
</div> </div>
<!-- 展示隐藏按钮 --> <!-- 灞曠ず闅愯棌鎸夐挳 -->
<img <img
v-smart-img v-smart-img
:src="imageUrl(amountVisible ? 'amountShowBt' : 'amountHiddenBt')" :src="imageUrl(amountVisible ? 'amountShowBt' : 'amountHiddenBt')"
@ -138,9 +152,9 @@ justify-content: flex-start;
/> />
</div> </div>
<!-- 任务详情 --> <!-- 浠诲姟璇 -->
<div style="display: flex; flex-direction: column; gap: 2vw"> <div style="display: flex; flex-direction: column; gap: 2vw">
<!-- 任务一 --> <!-- 浠诲姟涓 -->
<div :style="{ color: task1Completed ? '#1AFF00' : '#fff' }"> <div :style="{ color: task1Completed ? '#1AFF00' : '#fff' }">
{{ {{
t('active_game_task1_detail', { t('active_game_task1_detail', {
@ -156,7 +170,7 @@ justify-content: flex-start;
style="display: inline-block; width: 1em; object-fit: contain" style="display: inline-block; width: 1em; object-fit: contain"
/> />
</div> </div>
<!-- 任务二 --> <!-- 浠诲姟浜?-->
<div :style="{ color: task2Completed ? '#1AFF00' : '#fff' }"> <div :style="{ color: task2Completed ? '#1AFF00' : '#fff' }">
{{ {{
t('active_game_task2_detail', { t('active_game_task2_detail', {
@ -174,7 +188,7 @@ justify-content: flex-start;
</div> </div>
</div> </div>
<!-- 宝箱展示 --> <!-- 瀹濈灞曠ず -->
<div style="display: flex; flex-direction: column; align-items: center"> <div style="display: flex; flex-direction: column; align-items: center">
<img <img
v-smart-img v-smart-img
@ -183,12 +197,12 @@ justify-content: flex-start;
style="width: 38vw; display: block; object-fit: contain" style="width: 38vw; display: block; object-fit: contain"
/> />
<!-- 宝箱等级 --> <!-- 瀹濈绛夌骇 -->
<div style="font-size: 1.5em; font-weight: 700"> <div style="font-size: 1.5em; font-weight: 700">
{{ t('active_game_level_label', { level: currentLevel }) }} {{ t('active_game_level_label', { level: currentLevel }) }}
</div> </div>
<!-- 领取按钮 --> <!-- 棰嗗彇鎸夐挳 -->
<img <img
v-smart-img v-smart-img
:src="imageUrl(getImgName(taskRewardButtonImageName))" :src="imageUrl(getImgName(taskRewardButtonImageName))"
@ -201,7 +215,7 @@ justify-content: flex-start;
</div> </div>
</itemCenter> </itemCenter>
<!-- 等级奖励 --> <!-- 绛夌骇濂栧姳 -->
<itemCenter <itemCenter
style="" style=""
:imgUrl="imageUrl('LvRewardInfoBg')" :imgUrl="imageUrl('LvRewardInfoBg')"
@ -210,7 +224,7 @@ justify-content: flex-start;
padding: 8vw 7.5vw 14vw; padding: 8vw 7.5vw 14vw;
gap: 4vw;`" gap: 4vw;`"
> >
<!-- 标题 --> <!-- 鏍囬 -->
<div style="display: flex; justify-content: center; align-items: center; height: 11vw"> <div style="display: flex; justify-content: center; align-items: center; height: 11vw">
<img <img
v-smart-img v-smart-img
@ -220,7 +234,7 @@ justify-content: flex-start;
/> />
</div> </div>
<!-- 内容 --> <!-- 鍐呭 -->
<div <div
style=" style="
flex: 1; flex: 1;
@ -233,7 +247,7 @@ justify-content: flex-start;
position: relative; position: relative;
" "
> >
<!-- 开箱进度条 --> <!-- 绠辫繘搴 -->
<div <div
:class="[ :class="[
'scroll', 'scroll',
@ -242,9 +256,9 @@ justify-content: flex-start;
]" ]"
> >
<div :class="['chest-progress-row', { 'chest-progress-row-rtl': isRtlLayout }]"> <div :class="['chest-progress-row', { 'chest-progress-row-rtl': isRtlLayout }]">
<!-- 进度条 --> <!-- 杩涘害鏉?-->
<div class="chest-progress-track" :style="progressTrackStyle"> <div class="chest-progress-track" :style="progressTrackStyle">
<!-- 进度条图片 --> <!-- 杩涘害鏉浘鐗?-->
<div <div
:class="['chest-progress-fill', { 'chest-progress-fill-rtl': isRtlLayout }]" :class="['chest-progress-fill', { 'chest-progress-fill-rtl': isRtlLayout }]"
:style="progressFillStyle" :style="progressFillStyle"
@ -258,9 +272,9 @@ justify-content: flex-start;
</div> </div>
</div> </div>
<!-- 宝箱列表 --> <!-- 瀹濈鍒楄 -->
<div :class="['chest-progress-list', { 'chest-progress-list-rtl': isRtlLayout }]"> <div :class="['chest-progress-list', { 'chest-progress-list-rtl': isRtlLayout }]">
<!-- 开头占位 --> <!-- 澶村崰浣?-->
<div></div> <div></div>
<div <div
v-for="chest in chestProgressList" v-for="chest in chestProgressList"
@ -268,7 +282,7 @@ justify-content: flex-start;
style="width: 14vw; cursor: pointer" style="width: 14vw; cursor: pointer"
@click="selectRewardChest(chest.level)" @click="selectRewardChest(chest.level)"
> >
<!-- 未达成条件 --> <!-- 揪鎴愭潯浠?-->
<img <img
v-if="!isChestConditionReached(chest.level)" v-if="!isChestConditionReached(chest.level)"
v-smart-img v-smart-img
@ -277,7 +291,7 @@ justify-content: flex-start;
style="display: block; width: 100%; object-fit: contain" style="display: block; width: 100%; object-fit: contain"
/> />
<!-- 达成条件 --> <!-- 杈炬垚鏉 -->
<itemCenter <itemCenter
v-else v-else
style="width: 100%" style="width: 100%"
@ -296,7 +310,7 @@ justify-content: flex-start;
</div> </div>
</div> </div>
<!-- 奖励展示 --> <!-- 濂栧姳灞曠ず -->
<div class="reward-showcase"> <div class="reward-showcase">
<div v-if="mainReward" class="reward-showcase-main"> <div v-if="mainReward" class="reward-showcase-main">
<div <div
@ -427,9 +441,9 @@ justify-content: flex-start;
</itemCenter> </itemCenter>
</div> </div>
<!-- 弹窗遮罩层 --> <!-- 寮圭獥閬僵灞?-->
<maskLayer :maskLayerShow="maskLayerShow" @click="closedPopup"> <maskLayer :maskLayerShow="maskLayerShow" @click="closedPopup">
<!-- 居中弹窗 --> <!-- 灞呬腑寮圭獥 -->
<div <div
style=" style="
width: 100vw; width: 100vw;
@ -440,7 +454,7 @@ justify-content: flex-start;
" "
@click="closedPopup" @click="closedPopup"
> >
<!-- 规则弹窗 --> <!-- 瑙勫垯寮圭獥 -->
<itemCenter <itemCenter
style="" style=""
:imgUrl="imageUrl('ruleInfoBg')" :imgUrl="imageUrl('ruleInfoBg')"
@ -449,7 +463,7 @@ justify-content: flex-start;
padding: 8vw 7.5vw 5vw; padding: 8vw 7.5vw 5vw;
gap: 4vw;`" gap: 4vw;`"
> >
<!-- 标题 --> <!-- 鏍囬 -->
<div <div
style="display: flex; justify-content: center; align-items: center; height: 11vw" style="display: flex; justify-content: center; align-items: center; height: 11vw"
> >
@ -515,6 +529,7 @@ import { handleRewardImageError } from '@/utils/image/imageHandler.js'
import { formatRewardDisplay } from '@/utils/rewardFormatter.js' import { formatRewardDisplay } from '@/utils/rewardFormatter.js'
import { useThrottle } from '@/utils/useDebounce.js' import { useThrottle } from '@/utils/useDebounce.js'
import BackgroundLayer from '@/components/BackgroundLayer.vue'
import itemCenter from '@/components/itemCenter.vue' import itemCenter from '@/components/itemCenter.vue'
import maskLayer from '@/components/MaskLayer.vue' import maskLayer from '@/components/MaskLayer.vue'
import VapMp4Player from '@/components/VapMp4Player.vue' import VapMp4Player from '@/components/VapMp4Player.vue'
@ -699,6 +714,9 @@ const mainRewardRenderKey = computed(() => {
}) })
const rewardPreviewPlaying = ref(false) const rewardPreviewPlaying = ref(false)
const rewardVapPreloadElements = new Map() const rewardVapPreloadElements = new Map()
let rewardVapPreloadTimer = null
let rewardVapPreloadIdleCallbackId = null
let rewardVapPreloadStarted = false
const isLocalRewardAsset = (reward) => { const isLocalRewardAsset = (reward) => {
return Boolean(reward?.localRewardAsset) return Boolean(reward?.localRewardAsset)
@ -763,6 +781,34 @@ const preloadRewardVaps = (rewardTopList) => {
getRewardVapUrls(rewardTopList).forEach(preloadRewardVap) getRewardVapUrls(rewardTopList).forEach(preloadRewardVap)
} }
const startRewardVapPreload = () => {
if (rewardVapPreloadStarted || !activityRewards.value.length) {
return
}
rewardVapPreloadStarted = true
preloadRewardVaps(activityRewards.value)
}
const queueRewardVapPreload = () => {
if (rewardVapPreloadStarted || typeof window === 'undefined') {
return
}
if (typeof window.requestIdleCallback === 'function') {
rewardVapPreloadIdleCallbackId = window.requestIdleCallback(() => {
rewardVapPreloadIdleCallbackId = null
startRewardVapPreload()
})
return
}
rewardVapPreloadTimer = window.setTimeout(() => {
rewardVapPreloadTimer = null
startRewardVapPreload()
}, 0)
}
const getExtraRewardsByLevel = (level) => { const getExtraRewardsByLevel = (level) => {
switch (Number(level)) { switch (Number(level)) {
case 8: case 8:
@ -934,7 +980,6 @@ const getActivityRewards = async () => {
const res = await apiGetActivityResource('DAILY_RECHARGE_TASK2') const res = await apiGetActivityResource('DAILY_RECHARGE_TASK2')
if (res.status && res.body) { if (res.status && res.body) {
activityRewards.value = Array.isArray(res.body) ? appendExtraRewards(res.body) : [] activityRewards.value = Array.isArray(res.body) ? appendExtraRewards(res.body) : []
preloadRewardVaps(activityRewards.value)
} }
} }
@ -945,6 +990,7 @@ const initData = async () => {
const preloadCriticalImages = async () => { const preloadCriticalImages = async () => {
const chestImages = chestProgressList.value.map((chest) => imageUrl(getChestImageName(chest))) const chestImages = chestProgressList.value.map((chest) => imageUrl(getChestImageName(chest)))
const criticalImages = [ const criticalImages = [
imageUrl('bg'),
imageUrl('totalRewardBg'), imageUrl('totalRewardBg'),
imageUrl('lvTaskBg'), imageUrl('lvTaskBg'),
imageUrl('LvRewardInfoBg'), imageUrl('LvRewardInfoBg'),
@ -976,9 +1022,10 @@ const completePreloading = async () => {
await initData() await initData()
await preloadCriticalImages() await preloadCriticalImages()
} catch (error) { } catch (error) {
console.error('预加载过程中发生错误:', error) console.error('棰勫姞杞借繃绋嬩腑鍙戠敓閿欒:', error)
} finally { } finally {
isLoading.value = false isLoading.value = false
queueRewardVapPreload()
} }
} }
@ -993,6 +1040,18 @@ onMounted(() => {
}) })
onBeforeUnmount(() => { onBeforeUnmount(() => {
if (rewardVapPreloadTimer !== null && typeof window !== 'undefined') {
window.clearTimeout(rewardVapPreloadTimer)
rewardVapPreloadTimer = null
}
if (
rewardVapPreloadIdleCallbackId !== null &&
typeof window !== 'undefined' &&
typeof window.cancelIdleCallback === 'function'
) {
window.cancelIdleCallback(rewardVapPreloadIdleCallbackId)
rewardVapPreloadIdleCallbackId = null
}
rewardVapPreloadElements.forEach((video) => { rewardVapPreloadElements.forEach((video) => {
video.pause() video.pause()
video.removeAttribute('src') video.removeAttribute('src')
@ -1052,6 +1111,17 @@ onBeforeUnmount(() => {
pointer-events: none; pointer-events: none;
} }
.page-background-layer {
position: absolute;
top: 120vw;
left: 0;
right: 0;
bottom: 0;
z-index: 0;
overflow: hidden;
pointer-events: none;
}
.page-content { .page-content {
position: relative; position: relative;
z-index: 2; z-index: 2;
@ -1304,3 +1374,5 @@ onBeforeUnmount(() => {
} }
} }
</style> </style>

View File

@ -4,7 +4,7 @@
<script setup> <script setup>
const BACKGROUND_IMAGE_URL = const BACKGROUND_IMAGE_URL =
'http://tkm-likei.oss-accelerate.aliyuncs.com/other/manager-ef352b4f-09a3-492b-8aa6-b8cf2d73ddd1.png' 'http://tkm-likei.oss-accelerate.aliyuncs.com/other/manager-a46bf46c-5aaa-481f-9b7b-08263f68b45e.png'
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>