This commit is contained in:
yixu
2025-09-08 15:36:26 +08:00
commit 9a5cf53e3c
36 changed files with 7750 additions and 0 deletions

321
src/components/Lottery.vue Normal file
View File

@@ -0,0 +1,321 @@
<template>
<ModalTransition class="lottery" :show="show" name="opacity" position="center">
<div class="lottery-wrapper">
<div class="laohuji">
<div class="laohuji-temp" ref="tempRef"></div>
<div class="laohuji-bottom">
<div class="laohuji-list">
<div class="laohuji-item a" ref="itemaRef"></div>
<div class="laohuji-item b" ref="itembRef"></div>
<div class="laohuji-item c" ref="itemcRef"></div>
</div>
</div>
<div class="btn-kaixin" ref="btnRef" @click="handleGetLottery"></div>
<div class="laohuji-kapian" ref="kapianRef">
<div class="laohuji-kapian-bg" ref="kapianBgRef">
<div class="laohuji-kapian-cover" :class="kapianCover"></div>
</div>
</div>
<div class="laohuji-top"></div>
</div>
</div>
</ModalTransition>
</template>
<script setup>
import { gsap } from "gsap";
import Phaser from "phaser"
import { ref, watch, onMounted, onUnmounted } from "vue"
import ModalTransition from "./ModalTransition.vue"
import confetti from "canvas-confetti";
import { Howl } from 'howler';
import { Request } from "../libs/utils"
import lotterySoundUrl from '../assets/audio/lottery.mp3'
import laohujiSoundUrl from '../assets/audio/laohuji.mp3'
import { globalStore } from "@/globalstore";
const laohujiSound = new Howl({
src: [laohujiSoundUrl]
});
const lotterySoundSuccess = new Howl({
src: [lotterySoundUrl]
});
gsap.registerPlugin()
const props = defineProps({
show: false,
})
const emit = defineEmits(['close', 'address'])
const kapianRef = ref(null)
const tempRef = ref(null)
const btnRef = ref(null)
const itemaRef = ref(null)
const itembRef = ref(null)
const itemcRef = ref(null)
const kapianCover = ref('')
const kapianBgRef = ref(null)
const PRIZE_LIST = ['TJGJ','XINCHUN_WEIZUN', 'TEQU_JL_52_60Y_100ML_2', 'LZLJ_TEQU_LZH_52_100ML_2', 'HEIGAI_42_GPJ_500ML', 'DZCZ', 'DZSCZ', '66_POINTS', 'NO']
// 滚动奖品图片的高度(所有奖品)
const GRID = 165.833333
let PRIZEDATA = null
let interval = null
let gsapCtx = null
onMounted(() => {
initAnimateStyle()
})
const initAnimateStyle = () => {
interval && clearInterval(interval)
interval = null
const list = [itemaRef.value, itembRef.value, itemcRef.value]
const randomHeight = [Phaser.Math.Between(3, 8), Phaser.Math.Between(3, 8), Phaser.Math.Between(3, 8)]
gsap.set(kapianBgRef.value, { y: '-72vw' })
gsap.set(btnRef.value, { scale: 0, display: 'none' })
gsap.set(tempRef.value, { height: '63.518519vw' })
list.forEach((v, idx) => {
gsap.set(v, { y: `-${randomHeight[idx] * GRID - GRID / PRIZE_LIST.length}vw`, height: `${randomHeight[idx] * GRID}vw` })
})
}
onMounted(() => {
gsap.set(btnRef.value, { display: "none", scale: 0 })
})
watch(() => props.show, async (newVal) => {
if (!newVal) {
return
}
const lottteryResult = await Request("lottery/draw", { pool: 'game', consume_type: 'points' })
// const lottteryResult = {
// res: { status: 200 },
// json: {
// code: "HEIGAI_42_GPJ_500ML",
// prize_code: 'HEIGAI_42_GPJ_500ML'
// }
// }
if (lottteryResult.res.status !== 200) {
emit('close')
return
} else {
globalStore.consumeBingyin(globalStore.CONSUME_POINT_1_PER_DRAW)
PRIZEDATA = lottteryResult.json
// 未中奖的情况
if (lottteryResult.json.code === 204) {
PRIZEDATA = { prize_code: 'NO', coupon_type: 'NO' }
}
kapianCover.value = PRIZEDATA.prize_code === '66_POINTS' ? 'POINTS' : PRIZEDATA.prize_code
}
gsapCtx = gsap.context(() => {
initAnimateStyle()
const prizeIndex = PRIZE_LIST.findIndex(v => v === PRIZEDATA.prize_code)
const durationArr = [Phaser.Math.Between(3, 9), Phaser.Math.Between(3, 9), Phaser.Math.Between(3, 9)]
gsap.to([itemaRef.value, itembRef.value, itemcRef.value], {
y: `-${GRID / PRIZE_LIST.length * prizeIndex}vw`,
ease: "expo.out",
duration: (idx) => {
return durationArr[idx]
},
onStart: () => {
laohujiSound.play()
laohujiSound.fade(1, 0, Math.max(...durationArr)*1000)
},
delay: .4,
onComplete: () => {
lotterySoundSuccess.play()
var duration = 4 * 1000;
var animationEnd = Date.now() + duration;
var defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: 0 };
function randomInRange (min, max) {
return Math.random() * (max - min) + min;
}
interval = setInterval(function () {
var timeLeft = animationEnd - Date.now();
if (timeLeft <= 0) {
return clearInterval(interval);
}
var particleCount = 50 * (timeLeft / duration);
confetti({ ...defaults, particleCount, origin: { x: randomInRange(0.1, 0.3), y: Math.random() - 0.2 } });
confetti({ ...defaults, particleCount, origin: { x: randomInRange(0.7, 0.9), y: Math.random() - 0.2 } });
}, 250);
gsap.to(kapianBgRef.value, { y: '0', duration: 4, ease: "sine.inOut", })
gsap.to(tempRef.value, {
height: '+=90vw', duration: 4, ease: "sine.inOut", onComplete: () => {
gsap.set(btnRef.value, { display: "block" })
gsap.to(btnRef.value, { scale: 1, ease: "sine.inOut", duration: .3 })
}
})
}
})
})
})
const handleGetLottery = () => {
emit('close', { coupon_type: PRIZEDATA.coupon_type })
initAnimateStyle()
if (PRIZEDATA.coupon_type === 'scene') {
emit('address', PRIZEDATA.id)
}
}
onUnmounted(() => {
gsapCtx && gsapCtx.revert()
})
</script>
<style scoped>
.laohuji {
position: relative;
margin-top: -20vw;
}
.laohuji-temp {
width: 80.833333vw;
height: 63.518519vw;
}
.laohuji-top {
width: 80.833333vw;
height: 63.518519vw;
position: absolute;
top: 0;
left: 0;
background-image: url("../assets/images/laohuji-top.webp");
background-repeat: no-repeat;
background-size: 100% 100%;
}
.laohuji-bottom {
width: 80.833333vw;
height: 63.518519vw;
position: absolute;
top: 0;
left: 0;
background-image: url("../assets/images/laohuji-bottom.webp");
background-repeat: no-repeat;
background-size: 100% 100%;
}
.laohuji-kapian {
position: absolute;
overflow: hidden;
top: 58vw;
left: 14.4vw;
}
.laohuji-kapian-bg {
width: 51.851852vw;
clip-path: rect(0px 51.851852vw 74vw 0px);
height: 72vw;
background-image: url("../assets/images/laohuji-kapian.webp");
background-position: left bottom;
background-repeat: no-repeat;
background-size: 100% 73.333333vw;
}
.close {
position: absolute;
width: 8.148148vw;
height: 8.055556vw;
right: 5vw;
top: 0;
background-image: url("../assets/images/icon-close.webp");
background-repeat: no-repeat;
background-size: 100%;
}
.btn-kaixin {
width: 40.092593vw;
height: 15.555556vw;
position: absolute;
bottom: 0;
left: 50%;
margin-left: -20vw;
background-image: url("../assets/images/btn-kaixin.webp");
background-repeat: no-repeat;
background-size: 100%;
}
.laohuji-list {
position: absolute;
top: 31.5vw;
left: 14vw;
width: 53.6vw;
height: 18.425926vw;
background-color: #fff;
display: flex;
justify-content: space-between;
overflow: hidden;
}
.laohuji-item {
width: 16.296296vw;
height: 18.425926vw;
background-color: #ccc;
background-image: url("../assets/images/laohuji-item-1.webp");
background-repeat: repeat-y;
background-size: 16.296296vw 165.833333vw;
}
.laohuji-kapian-cover {
position: relative;
left: 3vw;
top: 13vw;
width: 45.555556vw;
height: 55.185185vw;
background-image: url("../assets/images/NO.webp");
background-repeat: no-repeat;
background-size: 100% 100%;
}
.laohuji-kapian-cover.TJGJ {
background-image: url("../assets/images/TJGJ.webp");
}
.laohuji-kapian-cover.XINCHUN_WEIZUN {
background-image: url("../assets/images/XINCHUN_WEIZUN.webp");
}
.laohuji-kapian-cover.TEQU_JL_52_60Y_100ML_2 {
background-image: url("../assets/images/TEQU_JL_52_60Y_100ML_2.webp");
}
.laohuji-kapian-cover.LZLJ_TEQU_LZH_52_100ML_2 {
background-image: url("../assets/images/LZLJ_TEQU_LZH_52_100ML_2.webp");
}
.laohuji-kapian-cover.HEIGAI_42_GPJ_500ML {
background-image: url("../assets/images/HEIGAI_42_GPJ_500ML.webp");
}
.laohuji-kapian-cover.DZCZ {
background-image: url("../assets/images/DZCZ.webp");
}
.laohuji-kapian-cover.DZSCZ {
background-image: url("../assets/images/DZSCZ.webp");
}
.laohuji-kapian-cover.POINTS {
background-image: url("../assets/images/66_POINTS.webp");
}
</style>