You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

356 lines
9.9 KiB

<template>
<div class="choujiang-main">
<Lottery3D ref="lottery3DRef" />
<PrizePanel :prizes="dataManager.state.basicData.prizes" />
<ControlBar
:lottery-state="lotteryState"
:is-disabled="isDisabled"
@lottery-click="handleLotteryClick"
@reset="handleReset"
@export="handleExport"
/>
<MusicPlayer ref="musicPlayerRef" />
<Mascot />
<!-- 透明弹窗 -->
<div v-if="showPrizeExhaustedModal" class="prize-exhausted-modal">
<div class="modal-content">
<p class="modal-text">该礼品已抽取完毕,请揭秘下一个礼品</p>
</div>
</div>
<div v-if="showPrizeExhaustedModal1" class="prize-exhausted-modal">
<div class="modal-content">
<p class="modal-text">请先揭秘一个礼品</p>
</div>
</div>
<!-- <UserList
:lucky-users="
dataManager.state.basicData.luckyUsers[
dataManager.state.currentPrize?.type
] || []
"
:left-users="dataManager.state.basicData.leftUsers"
/> -->
<!-- <Qipao :text="qipaoText" :show="showQipao" /> -->
</div>
</template>
<script setup>
import Lottery3D from "./lottery/Lottery3D.vue";
import PrizePanel from "./lottery/PrizePanel.vue";
import ControlBar from "./lottery/ControlBar.vue";
import MusicPlayer from "./lottery/MusicPlayer.vue";
import Qipao from "./lottery/Qipao.vue";
import UserList from "./lottery/UserList.vue";
import Mascot from "./lottery/Mascot.vue";
import { ref, onMounted, nextTick, computed, watch } from "vue";
import { useDataManager } from "./lottery/dataManager.js";
import { useLotteryEngine } from "./lottery/lotteryEngine.js";
import { useLotteryStore } from "../../store/lottery"; // 路径根据实际情况调整
import { drawLottery } from "../../api/API";
const qipaoText = ref("");
const showQipao = ref(false);
const showPrizeExhaustedModal = ref(false);
const showPrizeExhaustedModal1 = ref(false);
// const lotteryState = ref('idle'); // idle, ready, rotating, result
// 新增
const lotteryStore = useLotteryStore();
const lotteryState = computed({
get: () => lotteryStore.lotteryState,
set: (val) => lotteryStore.setLotteryState(val),
});
const lastRevealed = computed({
get: () => lotteryStore.lastRevealedIdx,
set: (val) => lotteryStore.setLastRevealedIdx(val),
});
const waitingForNextReveal = computed({
get: () => lotteryStore.waitingForNextReveal,
set: (val) => lotteryStore.setWaitingForNextReveal(val),
});
const winnerList = computed({
get: () => lotteryStore.winnerList,
set: (val) => lotteryStore.setWinnerList(val),
});
const isDisabled = ref(false);
watch(isDisabled, (newVal, oldVal) => {
console.log("isDisabled 变化:", oldVal, "->", newVal);
});
// 数据与抽奖主流程
const dataManager = useDataManager();
let lottery3DRef = ref(null);
let musicPlayerRef = ref(null);
const lotteryEngine = useLotteryEngine(dataManager, {
resetCard: (...args) => lottery3DRef.value?.resetCard?.(...args),
addHighlight: (...args) => lottery3DRef.value?.addHighlight?.(...args),
switchScreen: (...args) => lottery3DRef.value?.switchScreen?.(...args),
rotateBallStart: (...args) => lottery3DRef.value?.rotateBallStart?.(...args),
rotateBallStop: (...args) => lottery3DRef.value?.rotateBallStop?.(...args),
selectCard: (...args) => lottery3DRef.value?.selectCard?.(...args),
});
onMounted(async () => {
isDisabled.value = true;
setTimeout(() => {
isDisabled.value = false;
}, 3800);
await dataManager.getBasicData();
await dataManager.getUsers();
// 将 dataManager 挂载到 window 对象,供子组件使用
window.dataManager = dataManager;
// 延迟一点时间确保音乐播放器组件已经加载完成
setTimeout(() => {
if (musicPlayerRef.value && !musicPlayerRef.value.isPlaying()) {
// 触发音乐播放
musicPlayerRef.value.toggleMusic();
}
}, 1000);
});
function showLotteryQipao() {
const luckys = dataManager.state.currentLuckys;
const prize = dataManager.state.currentPrize;
if (!luckys || luckys.length === 0) return;
// 适配新的数据格式,支持 jwcode 和 username
const names = luckys
.map((item) => item.username || item[1] || item.jwcode || "")
.join("、");
qipaoText.value = `恭喜${names}获得${prize?.title || ""}`;
showQipao.value = true;
setTimeout(() => {
showQipao.value = false;
}, 3000);
}
async function handleLotteryClick() {
if (isDisabled.value) return; // 2秒内不能重复点击
isDisabled.value = true;
// setTimeout(() => {
// isDisabled.value = false;
// }, 2000);
switch (lotteryState.value) {
case "idle":
setTimeout(() => {
isDisabled.value = false;
}, 2000);
// 先切换到球体布局
await lottery3DRef.value?.switchScreen?.("lottery");
console.log("lotteryState 变更前:", lotteryState.value, "-> ready");
// await new Promise((resolve) => setTimeout(resolve, 2000));
lotteryState.value = "ready";
console.log("lotteryState 变更后:", lotteryState.value);
break;
case "ready":
if (waitingForNextReveal.value) {
console.log("waitingForNextReveal.value", waitingForNextReveal.value);
// 显示弹窗提示
showPrizeExhaustedModal.value = true;
setTimeout(() => {
showPrizeExhaustedModal.value = false;
}, 1000);
isDisabled.value = false;
break;
}
if (lastRevealed.value === -1) {
console.log("lastRevealed.value", lastRevealed.value);
showPrizeExhaustedModal1.value = true;
setTimeout(() => {
showPrizeExhaustedModal1.value = false;
}, 1000);
isDisabled.value = false;
break;
}
console.log("lotteryState 变更前:", lotteryState.value, "-> rotating");
lotteryState.value = "rotating";
console.log("lotteryState 变更后:", lotteryState.value);
const prize = dataManager.state.basicData.prizes[lastRevealed.value];
console.log("准备调用 drawLottery,prize:", prize);
console.log("lastRevealed.value:", lastRevealed.value);
// 先让球转起来,不等它结束
const rotatePromise = lottery3DRef.value?.rotateBallStart?.();
// 同时请求接口
try {
winnerList.value = await drawLottery({
perWin: prize.perWin,
remainNum: prize.remainNum,
gradeId: prize.gradeId,
prizeId: prize.prizeId,
});
setTimeout(() => {
isDisabled.value = false;
}, 2000);
console.log("drawLottery 调用成功,结果:", winnerList.value);
} catch (error) {
console.error("drawLottery 调用失败:", error);
}
// 如果你还需要等球转完再做别的,可以 await rotatePromise
break;
case "rotating":
setTimeout(() => {
isDisabled.value = false;
}, 2000);
// 停止转动并开奖
// const prize = dataManager.state.basicData.prizes[lastRevealed.value];
// console.log("准备调用 drawLottery,prize:", prize);
// console.log("lastRevealed.value:", lastRevealed.value);
// try {
// winnerList.value = await drawLottery({
// perWin: prize.perWin,
// remainNum: prize.remainNum,
// gradeId: prize.gradeId,
// prizeId: prize.prizeId,
// });
// console.log("drawLottery 调用成功,结果:", winnerList.value);
// } catch (error) {
// console.error("drawLottery 调用失败:", error);
// }
await lottery3DRef.value?.rotateBallStop?.();
await lotteryEngine.executeLottery();
await nextTick();
showLotteryQipao();
console.log("lotteryState 变更前:", lotteryState.value, "-> idle");
lotteryState.value = "result";
console.log("lotteryState 变更后:", lotteryState.value);
break;
case "result":
setTimeout(() => {
isDisabled.value = false;
}, 2000);
// result 状态下点击不做任何事,或者你可以加提示
await lottery3DRef.value?.switchScreen?.("lottery");
await new Promise((resolve) => setTimeout(resolve, 2500));
// 去除高光
lottery3DRef.value?.changeCard1?.();
//延迟2秒
lotteryState.value = "ready";
break;
default:
break;
}
}
function handleReset() {
lotteryEngine.resetLottery();
}
function handleExport() {
dataManager.exportData();
}
function handlePrevPrize() {
if (dataManager.state.currentPrizeIndex > 0) {
dataManager.state.currentPrizeIndex--;
dataManager.state.currentPrize =
dataManager.state.basicData.prizes[dataManager.state.currentPrizeIndex];
}
}
function handleNextPrize() {
if (
dataManager.state.currentPrizeIndex <
dataManager.state.basicData.prizes.length - 1
) {
dataManager.state.currentPrizeIndex++;
dataManager.state.currentPrize =
dataManager.state.basicData.prizes[dataManager.state.currentPrizeIndex];
}
}
</script>
<style scoped>
.choujiang-main {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
overflow: hidden;
/* 添加背景图片 */
background: url("../../assets/bg@2x.png");
background-size: 1920px 980px;
}
/* 透明弹窗样式 */
.prize-exhausted-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: flex-start;
padding-top: 20vh;
z-index: 9999;
pointer-events: none;
}
.modal-content {
background: transparent;
padding: 20px 30px;
border-radius: 10px;
animation: fadeInOut 1s ease-in-out;
}
.modal-text {
color: #ff0000;
font-size: 18px;
font-weight: bold;
text-align: center;
margin: 0;
white-space: nowrap;
}
@keyframes fadeInOut {
0% {
opacity: 0;
transform: translateY(-20px);
}
20% {
opacity: 1;
transform: translateY(0);
}
80% {
opacity: 1;
transform: translateY(0);
}
100% {
opacity: 0;
transform: translateY(-20px);
}
}
</style>