Commit 2c4b70c7 by lijiabin

【需求 23684】feat: 优化大转盘动画和抽奖音乐

parent 2582dbc9
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { LuckyWheel } from '@lucky-canvas/vue' import { LuckyWheel } from '@lucky-canvas/vue'
import ringTexture from '@/assets/img/lucky-wheel-outer-ring.svg' import ringTexture from '@/assets/img/lucky-wheel-outer-ring.svg'
import spinMusic from '@/assets/audio/lucky-wheel-happy-adventure.mp3'
import type { WheelPrizeItemDto, LuckWheelResultDto, WheelConfigDto } from '@/api' import type { WheelPrizeItemDto, LuckWheelResultDto, WheelConfigDto } from '@/api'
import { participateLuckyWheel, getWheelPrizeList } from '@/api' import { participateLuckyWheel, getWheelPrizeList } from '@/api'
...@@ -56,8 +57,8 @@ const myLucky = ref<InstanceType<typeof LuckyWheel>>() ...@@ -56,8 +57,8 @@ const myLucky = ref<InstanceType<typeof LuckyWheel>>()
const defaultConfig = { const defaultConfig = {
offsetDegree: 0, offsetDegree: 0,
speed: 20, speed: 20,
accelerationTime: 2500, accelerationTime: 1000,
decelerationTime: 2500, decelerationTime: 1000,
} }
const defaultStyle = { const defaultStyle = {
...@@ -124,18 +125,42 @@ const buttons = [ ...@@ -124,18 +125,42 @@ const buttons = [
const isSpinning = ref(false) const isSpinning = ref(false)
let resultPrize: null | LuckWheelResultDto = null let resultPrize: null | LuckWheelResultDto = null
let spinAudio: HTMLAudioElement | null = null
const startSpinMusic = () => {
stopSpinMusic()
spinAudio ||= new Audio(spinMusic)
spinAudio.loop = true
spinAudio.volume = 0.35
spinAudio.play().catch(() => {})
}
const stopSpinMusic = () => {
if (!spinAudio) return
spinAudio.pause()
spinAudio.currentTime = 0
}
const startCallback = async () => { const startCallback = async () => {
if (isSpinning.value) return if (isSpinning.value) return
isSpinning.value = true isSpinning.value = true
startSpinMusic()
myLucky.value?.play() myLucky.value?.play()
setTimeout(async () => { setTimeout(async () => {
try {
const { data } = await participateLuckyWheel() const { data } = await participateLuckyWheel()
const idx = computedPrizes.value.findIndex((item) => item.id === data.prizeId) const idx = computedPrizes.value.findIndex((item) => item.id === data.prizeId)
myLucky.value?.stop(idx) myLucky.value?.stop(idx)
yabiStore.fetchYaBiData() yabiStore.fetchYaBiData()
resultPrize = data resultPrize = data
}, 1000) } catch (error) {
console.error(error)
stopSpinMusic()
isSpinning.value = false
}
}, 600)
} }
// 获取最新的奖品列表 对比 是否更新了 // 获取最新的奖品列表 对比 是否更新了
...@@ -185,7 +210,7 @@ const endCallback = () => { ...@@ -185,7 +210,7 @@ const endCallback = () => {
setTimeout(() => { setTimeout(() => {
isSpinning.value = false isSpinning.value = false
emit('handlePrizeResult', resultPrize as LuckWheelResultDto) emit('handlePrizeResult', resultPrize as LuckWheelResultDto)
}, 500) }, 280)
} }
const initWheelPrizeList = async () => { const initWheelPrizeList = async () => {
...@@ -195,6 +220,14 @@ const initWheelPrizeList = async () => { ...@@ -195,6 +220,14 @@ const initWheelPrizeList = async () => {
onMounted(() => { onMounted(() => {
initWheelPrizeList() initWheelPrizeList()
}) })
onBeforeUnmount(() => {
stopSpinMusic()
})
defineExpose({
stopSpinMusic,
})
</script> </script>
<style scoped> <style scoped>
......
<template> <template>
<Comp :wheelConfig="wheelConfig" @handle-prize-result="handlePrizeResult" /> <Comp ref="luckyWheelRef" :wheelConfig="wheelConfig" @handle-prize-result="handlePrizeResult" />
<Teleport to="body"> <Teleport to="body">
<Transition name="result"> <Transition name="result">
<div <div
...@@ -84,7 +84,7 @@ ...@@ -84,7 +84,7 @@
<p class="blessing-caption-subtitle">抽一支好运电子签,把今天过得亮一点</p> <p class="blessing-caption-subtitle">抽一支好运电子签,把今天过得亮一点</p>
</div> </div>
<el-button class="mt-8" type="primary" @click="showResult = false">知道了</el-button> <el-button class="mt-8" type="primary" @click="closeResult">知道了</el-button>
</template> </template>
<template v-else> <template v-else>
...@@ -92,7 +92,7 @@ ...@@ -92,7 +92,7 @@
<div class="mt-6 text-white text-3xl font-bold"> <div class="mt-6 text-white text-3xl font-bold">
恭喜获得 {{ currentPrize?.prizeName }} 恭喜获得 {{ currentPrize?.prizeName }}
</div> </div>
<el-button class="mt-8" type="primary" @click="showResult = false">知道了</el-button> <el-button class="mt-8" type="primary" @click="closeResult">知道了</el-button>
</template> </template>
</div> </div>
</Transition> </Transition>
...@@ -112,6 +112,7 @@ const { wheelConfig } = defineProps<{ ...@@ -112,6 +112,7 @@ const { wheelConfig } = defineProps<{
const showResult = ref(false) const showResult = ref(false)
const currentPrize = ref<LuckWheelResultDto | null>(null) const currentPrize = ref<LuckWheelResultDto | null>(null)
const luckyWheelRef = ref<InstanceType<typeof Comp>>()
const blessingWrapRef = ref<HTMLElement | null>(null) const blessingWrapRef = ref<HTMLElement | null>(null)
const blessingGlowRef = ref<HTMLElement | null>(null) const blessingGlowRef = ref<HTMLElement | null>(null)
...@@ -305,10 +306,10 @@ const playBlessingAnimation = () => { ...@@ -305,10 +306,10 @@ const playBlessingAnimation = () => {
}) })
blessingTimeline blessingTimeline
.to(scene, { opacity: 1, y: 0, duration: 0.45 }) .to(scene, { opacity: 1, y: 0, duration: 0.35 })
.to(glow, { opacity: 0.95, scale: 1, duration: 0.7, ease: 'sine.out' }, '<') .to(glow, { opacity: 0.95, scale: 1, duration: 0.55, ease: 'sine.out' }, '<')
.to(slot, { opacity: 1, scaleX: 1, duration: 0.52 }, '-=0.3') .to(slot, { opacity: 1, scaleX: 1, duration: 0.42 }, '-=0.26')
.to(fan, { opacity: 1, y: 0, duration: 0.4 }, '<') .to(fan, { opacity: 1, y: 0, duration: 0.34 }, '<')
.to( .to(
fanItems, fanItems,
{ {
...@@ -316,10 +317,10 @@ const playBlessingAnimation = () => { ...@@ -316,10 +317,10 @@ const playBlessingAnimation = () => {
y: (_index, target) => Number(target.getAttribute('data-y') || 0), y: (_index, target) => Number(target.getAttribute('data-y') || 0),
rotate: (_index, target) => Number(target.getAttribute('data-angle') || 0), rotate: (_index, target) => Number(target.getAttribute('data-angle') || 0),
scale: (_index, target) => Number(target.getAttribute('data-scale') || 1), scale: (_index, target) => Number(target.getAttribute('data-scale') || 1),
duration: 0.9, duration: 0.7,
ease: 'back.out(1.08)', ease: 'back.out(1.08)',
stagger: { stagger: {
each: 0.055, each: 0.042,
from: 'center', from: 'center',
}, },
}, },
...@@ -329,16 +330,16 @@ const playBlessingAnimation = () => { ...@@ -329,16 +330,16 @@ const playBlessingAnimation = () => {
fanItems, fanItems,
{ {
x: (_index, target) => Number(target.getAttribute('data-x') || 0) * 0.1, x: (_index, target) => Number(target.getAttribute('data-x') || 0) * 0.1,
duration: 0.32, duration: 0.26,
ease: 'power1.inOut', ease: 'power1.inOut',
stagger: { stagger: {
each: 0.02, each: 0.016,
from: 'edges', from: 'edges',
}, },
yoyo: true, yoyo: true,
repeat: 1, repeat: 1,
}, },
'+=0.26', '+=0.18',
) )
.to( .to(
blessingTagStageRef.value, blessingTagStageRef.value,
...@@ -346,10 +347,10 @@ const playBlessingAnimation = () => { ...@@ -346,10 +347,10 @@ const playBlessingAnimation = () => {
opacity: 1, opacity: 1,
y: 0, y: 0,
filter: 'blur(0px)', filter: 'blur(0px)',
duration: 0.48, duration: 0.36,
ease: 'power2.out', ease: 'power2.out',
}, },
'+=0.02', '+=0.01',
) )
.to( .to(
tag, tag,
...@@ -358,7 +359,7 @@ const playBlessingAnimation = () => { ...@@ -358,7 +359,7 @@ const playBlessingAnimation = () => {
opacity: 0.5, opacity: 0.5,
scale: 0.97, scale: 0.97,
filter: 'blur(6px)', filter: 'blur(6px)',
duration: 0.42, duration: 0.34,
ease: 'power2.out', ease: 'power2.out',
}, },
'<', '<',
...@@ -370,10 +371,10 @@ const playBlessingAnimation = () => { ...@@ -370,10 +371,10 @@ const playBlessingAnimation = () => {
opacity: 1, opacity: 1,
scale: 1.01, scale: 1.01,
filter: 'blur(1px)', filter: 'blur(1px)',
duration: 1.08, duration: 0.82,
ease: 'power3.out', ease: 'power3.out',
}, },
'+=0.1', '+=0.08',
) )
.to( .to(
tag, tag,
...@@ -382,10 +383,10 @@ const playBlessingAnimation = () => { ...@@ -382,10 +383,10 @@ const playBlessingAnimation = () => {
rotation: -1.4, rotation: -1.4,
scale: 1.015, scale: 1.015,
filter: 'blur(0px)', filter: 'blur(0px)',
duration: 0.3, duration: 0.24,
ease: 'power2.out', ease: 'power2.out',
}, },
'-=0.18', '-=0.14',
) )
.to( .to(
tag, tag,
...@@ -394,19 +395,19 @@ const playBlessingAnimation = () => { ...@@ -394,19 +395,19 @@ const playBlessingAnimation = () => {
rotation: 0.4, rotation: 0.4,
scale: 1, scale: 1,
filter: 'blur(0px)', filter: 'blur(0px)',
duration: 0.32, duration: 0.26,
ease: 'back.out(1.5)', ease: 'back.out(1.5)',
}, },
'+=0.02', '+=0.01',
) )
.to(tagTop, { opacity: 1, duration: 0.22 }, '<') .to(tagTop, { opacity: 1, duration: 0.18 }, '<')
.to( .to(
chars, chars,
{ {
opacity: 1, opacity: 1,
y: 0, y: 0,
duration: 0.34, duration: 0.28,
stagger: 0.05, stagger: 0.035,
}, },
'-=0.08', '-=0.08',
) )
...@@ -415,7 +416,7 @@ const playBlessingAnimation = () => { ...@@ -415,7 +416,7 @@ const playBlessingAnimation = () => {
{ {
opacity: 1, opacity: 1,
y: 0, y: 0,
duration: 0.28, duration: 0.22,
}, },
'-=0.12', '-=0.12',
) )
...@@ -424,7 +425,7 @@ const playBlessingAnimation = () => { ...@@ -424,7 +425,7 @@ const playBlessingAnimation = () => {
{ {
opacity: 1, opacity: 1,
y: 0, y: 0,
duration: 0.42, duration: 0.34,
}, },
'-=0.02', '-=0.02',
) )
...@@ -461,6 +462,11 @@ const handlePrizeResult = (prize: LuckWheelResultDto) => { ...@@ -461,6 +462,11 @@ const handlePrizeResult = (prize: LuckWheelResultDto) => {
currentPrize.value = prize currentPrize.value = prize
showResult.value = true showResult.value = true
} }
const closeResult = () => {
showResult.value = false
luckyWheelRef.value?.stopSpinMusic()
}
</script> </script>
<style> <style>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment