yfs/components/detail-lucky/detail-lucky.vue
2025-05-20 00:29:56 +08:00

1113 lines
31 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="content-container detail-lucky" v-if="isVisible && isInitialized">
<view class="slot-container">
<view class="slot-icon">
<image src="https://image.zfunbox.cn/static/image/lucky/icon.png" mode="widthFix"
style="height: 90rpx; width: 249rpx"></image>
</view>
<view class="slot-view" :class="'slot-view-' + currentMode">
<!-- 抽奖特效组件 -->
<SlotMachine ref="myLucky" :width="windowWidth" :height="slotHeight" :blocks="blocks" :slots="slots"
:prizes="prizes" :defaultConfig="defaultConfig" @start="startCallBack" @end="endCallBack">
</SlotMachine>
</view>
<view style="color: #484848;font-size: 19rpx;text-align: center;padding-top: 20rpx;">
动画结果因设备差异可能会显示异常,获得赏品以(恭喜获得)结果为准</view>
<view class="skip-animation" @click="skipAnimation" :style="[skipButtonStyle()]">跳过动画</view>
</view>
<DetailGrandPrize ref="detailGrandPrize" @end="onLuckyEnd1" />
</view>
</template>
<script>
// 导入抽奖特效组件
import SlotMachine from "@/components/@lucky-canvas/uni/slot-machine";
//超神特效
import DetailGrandPrize from "@/components/detail-lucky/detail-grand-prize.vue";
import { sleep } from '@/common/util'
function shuffle(array) {
for (let i = array.length - 1; i > 0; i--) {
// 生成一个 0 到 i 之间的随机整数
const j = Math.floor(Math.random() * (i + 1));
// 交换 array[i] 和 array[j]
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
export default {
components: {
SlotMachine,
DetailGrandPrize
},
props: {
// 抽奖特效模式: 1, 3, 5, 10 (分别代表1列、3列、5列、10列分两批)
mode: {
type: [Number, String],
default: 1,
validator: function (value) {
return [1, 3, 5, 10, '1', '3', '5', '10'].includes(value);
}
}
},
data() {
return {
isVisible: false, // 控制组件显示/隐藏
isInitialized: false, // 控制是否已初始化
windowWidth: "0px",
blocks: [],
slots: [],
prizes: [],
prizeList: [], // 移到data中
defaultConfig: {
mode: "horizontal", // 水平模式
rowSpacing: "10px", // 行间距
colSpacing: "10px", // 列间距
accelerationTime: 1500,
},
luckyMessage: "恭喜您获得奖品",
luckyPrize: null,
currentPrizeIndex: -1,
internalMode: 1, // 内部存储模式的状态
skipButtonOpacity: 0, // 跳过按钮的透明度
isSkip: false,
isBatchMode: false, // 是否为批次模式
batchCount: 0, // 当前批次
batchResults: [], // 保存批次结果
batchCallback: null, // 批次模式回调
batchIndices: [], // 批次索引
chaoShenIndex: -1,
timers: {
skipButton: null, // 控制跳过按钮渐显的定时器
firstBatch: null, // 第一批次抽奖的定时器,用于控制第一批次停止时间
secondBatch: null, // 第二批次抽奖的定时器,用于控制第二批次停止时间
drawResult: null, // 抽奖结果显示的定时器,用于延迟显示抽奖结果
showDelay: null, // 组件显示延迟的定时器用于确保DOM渲染完成
playDelay: null // 开始播放抽奖动画的延迟定时器
},
};
},
computed: {
// 计算抽奖项尺寸
lotteryItemSize() {
let height = uni.upx2px(220);
let width = uni.upx2px(170);
return [width, height];
},
// 计算当前模式
currentMode() {
// 当internalMode为10时显示模式为5
return this.internalMode === 10 ? 5 : parseInt(this.internalMode);
},
// 根据模式计算高度
slotHeight() {
const modeMap = {
1: "160rpx",
3: "480rpx",
5: "800rpx",
10: "800rpx" // 模式10使用与模式5相同的高度
};
// 使用计算后的currentMode而不是直接使用internalMode
console.log(modeMap[this.currentMode], "modeMap[this.currentMode]");
return modeMap[this.currentMode] || "480rpx";
},
// 根据模式获取背景图
backgroundImage() {
const modeMap = {
1: "di_5.png",
3: "di_3.png",
5: "di_5.png",
10: "di_5.png" // 模式10使用与模式5相同的背景
};
// 使用计算后的currentMode而不是直接使用internalMode
return modeMap[this.currentMode] || "di_3.png";
},
// 跳过按钮样式
skipButtonStyle() {
return () => {
return {
opacity: this.skipButtonOpacity,
transition: 'opacity 0.5s ease'
};
};
}
},
methods: {
onLuckyEnd1() {
// 发送中奖信息到父组件
this.$emit("end", []);
// 调用startDrawWithResult方法中保存的回调函数
if (this.drawResultCallback && typeof this.drawResultCallback === 'function') {
this.drawResultCallback([]);
// 清除回调,避免重复调用
this.drawResultCallback = null;
}
},
// 初始化抽奖特效组件
init(prizeList, mode) {
// 如果传入了模式,更新当前模式
if (mode !== undefined && [1, 3, 5, 10].includes(parseInt(mode))) {
this.internalMode = parseInt(mode);
} else {
// 没有传入模式时使用props中的mode初始化内部模式
this.internalMode = parseInt(this.mode);
}
console.log("初始化模式:", this.internalMode, "显示模式:", this.currentMode);
// 设置奖品列表
if (prizeList && Array.isArray(prizeList) && prizeList.length > 0) {
this.prizeList = prizeList;
} else {
this.prizeList = this.getDefaultPrizes();
}
let windowWidth = uni.getSystemInfoSync().windowWidth;
let t = this.prizeList;
let prizes = [];
for (let i = 0; i < t.length; i++) {
prizes.push({
imgs: [{
src: t[i].imgurl,
width: "152.78rpx",
height: "152.78rpx",
},],
background: "#ffffff",
data: t[i], // 将原始数据保存到prize中方便后续使用
});
}
// 根据当前模式创建slots
const arr = Array.from({
length: t.length
}, (_, i) => i);
let slots = [];
// 根据模式创建对应数量的列
// 模式10也只创建5列因为显示模式是5
const slotColumns = this.currentMode;
for (let i = 0; i < slotColumns; i++) {
slots.push({
order: shuffle([...arr]),
speed: 20
});
}
this.windowWidth = windowWidth + "px";
this.slots = slots;
this.prizes = prizes;
// 标记为已初始化
this.isInitialized = true;
return this; // 返回this以支持链式调用
},
// 显示抽奖特效组件
show() {
if (!this.isInitialized) {
console.error("抽奖特效尚未初始化请先调用init方法");
return this;
}
this.isVisible = true;
return this;
},
// 隐藏抽奖特效组件
hide() {
this.isVisible = false;
return this;
},
// 获取默认奖品列表
getDefaultPrizes() {
return [{
id: 1128,
title: "兹琪露娜提亚斯",
imgurl: "https://image.zfunbox.cn/topic/20250515/2986e27e673ef675e02771cdebd9b822.jpg",
price: "350.00",
real_pro: "0.02000",
goods_type: 1,
doubling: 1,
is_lingzhu: 0,
},
{
id: 1129,
title: "月岗恋钟",
imgurl: "https://image.zfunbox.cn/topic/20250515/2c5ed2097716db6bef01da718bc3c091.jpg",
price: "132.00",
real_pro: "0.02000",
goods_type: 1,
doubling: 3,
is_lingzhu: 0,
},
{
id: 1130,
title: "BANDAI万代拼装模型 1/100 MG 机动战士高达 倒A 逆A-15岁以上",
imgurl: "https://image.zfunbox.cn/topic/20250515/e35da49b4976f156f2f98dec002274a5.png",
price: "305.00",
real_pro: "0.03000",
goods_type: 1,
doubling: 1,
is_lingzhu: 0,
},
{
id: 1131,
title: "BANDAI 万代拼装模型 MG 主天使-15岁以上",
imgurl: "https://image.zfunbox.cn/topic/20250515/77302c6f1ea9ea6a8516cc1208174aee.png",
price: "289.00",
real_pro: "0.03000",
goods_type: 1,
doubling: 1,
is_lingzhu: 0,
},
{
id: 1132,
title: "BANDAI万代 HG00 09 1/144 座天使高达一型-15岁以上",
imgurl: "https://image.zfunbox.cn/topic/20250515/55e816c93b5e4103a30682c586816b11.jpg",
price: "114.00",
real_pro: "0.50000",
goods_type: 1,
doubling: 3,
is_lingzhu: 0,
},
{
id: 1133,
title: "BANDAI万代拼装模型 HGUC 130 机动战士高达 杰斯塔-15岁以上",
imgurl: "https://image.zfunbox.cn/topic/20250515/aeb6bfb8b4aa8a29796b242e4f5d56d9.png",
price: "113.00",
real_pro: "1.50000",
goods_type: 1,
doubling: 1,
is_lingzhu: 0,
},
{
id: 1134,
title: "BANDAI万代拼装模型HG26 1/144 凯列班高达 异灵高达-15岁以上",
imgurl: "https://image.zfunbox.cn/topic/20250515/329e3a7e21772a63cea03d31f948345d.png",
price: "112.00",
real_pro: "1.00000",
goods_type: 1,
doubling: 2,
is_lingzhu: 0,
},
{
id: 1135,
title: "梦幻",
imgurl: "https://image.zfunbox.cn/topic/20250515/d2c7e48515d393084000595074209042.jpg",
price: "41.00",
real_pro: "2.50000",
goods_type: 1,
doubling: 2,
is_lingzhu: 0,
},
{
id: 1136,
title: "谜拟丘",
imgurl: "https://image.zfunbox.cn/topic/20250515/6031827bc455cbf86ff778d74ddffbd3.jpg",
price: "38.00",
real_pro: "1.50000",
goods_type: 1,
doubling: 1,
is_lingzhu: 0,
},
{
id: 1137,
title: "小提琴模型1个",
imgurl: "https://image.zfunbox.cn/topic/20250515/22846dea5a933ab314998afc51abb7bb.jpg",
price: "13.80",
real_pro: "92.90000",
goods_type: 1,
doubling: 1,
is_lingzhu: 0,
},
];
},
// 抽奖特效开始回调
startCallBack() {
console.log("开始抽奖");
this.$emit("start");
},
// 抽奖结束回调
endCallBack(prize) {
try {
console.log("[批次抽奖] endCallBack 被调用,批次模式:", this.isBatchMode, "当前模式:", this.internalMode, "批次计数:", this
.batchCount);
if (this.isSkip) {
return;
}
// 准备中奖信息
const prizeData =
this.prizes[this.currentPrizeIndex]?.data || this.prizes[0]?.data;
if (!prizeData) {
console.error("无法获取奖品数据");
return;
}
// 获取所有中奖奖品
let allPrizes = [];
// 检查prize是否是数组如果是则使用map否则只使用当前prize
if (Array.isArray(prize)) {
allPrizes = prize
.map((item) => {
const index = typeof item.index === "number" ? item.index : 0;
return this.prizes[index]?.data || this.prizes[0]?.data;
})
.filter((item) => !!item);
} else if (prize && typeof prize.index === "number") {
// 如果prize是单个对象
const index = prize.index;
const itemData = this.prizes[index]?.data;
if (itemData) {
allPrizes.push(itemData);
}
} else {
// 都不符合则使用当前索引的奖品
allPrizes.push(prizeData);
}
// 准备返回结果
const result = {
prize: prize,
prizeData: prizeData, // 主要奖品数据
allPrizes: allPrizes, // 所有中奖奖品数据
message: `恭喜您获得 ${prizeData.title}`,
prizeInfo: {
name: prizeData.title,
image: prizeData.imgurl,
description: `价值:${prizeData.price}`,
data: prizeData,
},
};
// 批次模式处理
if (this.isBatchMode && this.internalMode === 10) {
this.batchCount++;
// 添加到批次结果
this.batchResults.push(...allPrizes);
console.log("[批次抽奖] 批次抽奖完成", this.batchCount, "共", this.batchResults.length, "个奖品");
if (this.batchCount < 2) {
// 第一批次完成,延时开始第二批次
console.log("[批次抽奖] 第一批次完成,准备开始第二批次");
this.timers.firstBatch = setTimeout(() => {
console.log("[批次抽奖] 即将调用startSecondBatch");
this.startSecondBatch();
}, 800);
return;
} else {
// 两批次都完成
console.log("[批次抽奖] 两批次都完成,返回最终结果");
const batchResult = {
prize: prize,
prizeData: prizeData,
allPrizes: this.batchResults,
message: `恭喜您获得 ${this.batchResults.length} 件奖品`,
prizeInfo: {
name: "批次抽奖",
image: prizeData.imgurl,
description: `共获得 ${this.batchResults.length} 件奖品`,
data: this.batchResults,
},
};
this.bgmCtx.slotBgm.stop();
if (this.chaoShenIndex != -1) {
// 重置批次状态
this.isBatchMode = false;
this.batchCount = 0;
this.batchResults = [];
this.$refs.detailGrandPrize.init();
this.$refs.detailGrandPrize.show();
return;
}
this.timers.drawResult = setTimeout(() => {
// 发送中奖信息到父组件
this.$emit("end", batchResult);
// 调用保存的批次回调
if (this.batchCallback && typeof this.batchCallback === 'function') {
console.log("[批次抽奖] 调用批次回调函数");
this.batchCallback(batchResult);
this.batchCallback = null;
}
// 重置批次状态
this.isBatchMode = false;
this.batchCount = 0;
this.batchResults = [];
}, 800);
return;
}
}
this.bgmCtx.slotBgm.stop();
if (this.chaoShenIndex != -1) {
this.$refs.detailGrandPrize.init();
this.$refs.detailGrandPrize.show();
return;
}
this.timers.drawResult = setTimeout(() => {
// 发送中奖信息到父组件
this.$emit("end", result);
// 调用startDrawWithResult方法中保存的回调函数
if (this.drawResultCallback && typeof this.drawResultCallback === 'function') {
this.drawResultCallback(result);
// 清除回调,避免重复调用
this.drawResultCallback = null;
}
}, 800);
} catch (error) {
console.error("[批次抽奖] 处理抽奖结果时出错:", error);
this.hide();
// 如果有回调,通知调用者处理出错
if (this.drawResultCallback && typeof this.drawResultCallback === 'function') {
this.drawResultCallback({
success: false,
error: error.message || "处理抽奖结果时出错"
});
this.drawResultCallback = null;
}
// 批次模式错误处理
if (this.isBatchMode && this.batchCallback) {
this.batchCallback({
success: false,
error: error.message || "批次抽奖出错"
});
this.isBatchMode = false;
this.batchCount = 0;
this.batchResults = [];
this.batchCallback = null;
}
}
},
// 强制结束抽奖
forceEndDraw() {
if (!this.isInitialized) {
console.error("抽奖特效尚未初始化请先调用init方法");
return this;
}
if (this.bgmCtx && this.bgmCtx.slotBgm) {
this.bgmCtx.slotBgm.stop();
}
console.log("[跳过动画] 批次模式:", this.isBatchMode, "当前模式:", this.internalMode, "批次计数:", this.batchCount);
this.hide();
let stopIndex = 0;
if (this.internalMode > 1) {
stopIndex = [];
let maxIndex = this.internalMode;
if (maxIndex > 5) {
maxIndex = 5;
}
for (let i = 0; i < maxIndex; i++) {
stopIndex.push(0);
}
}
// 调用stop方法停止旋转
this.$refs.myLucky.stop(stopIndex);
// 发送事件到父组件
this.$emit("end", []);
return this; // 返回this以支持链式调用
},
// 跳过动画
skipAnimation() {
this.isSkip = true;
// 清理所有定时器
Object.values(this.timers).forEach(timer => {
if (timer) {
clearTimeout(timer);
}
});
// 强制结束抽奖
this.forceEndDraw();
},
// 开始抽奖方法
startDraw(callback) {
// 检查是否已初始化
if (!this.isInitialized) {
console.error("抽奖特效尚未初始化请先调用init方法");
return this;
}
if (this.isSkip) {
this.isSkip = false;
}
// 保存回调函数
this.drawResultCallback = typeof callback === 'function' ? callback : null;
// 重置跳过按钮透明度
this.skipButtonOpacity = 0;
// 如果是模式10启用批次模式
if (this.internalMode === 10) {
console.log("[批次抽奖] 检测到模式10启用批次模式");
this.isBatchMode = true;
this.batchCount = 0;
this.batchResults = [];
this.batchCallback = this.drawResultCallback; // 保存批次回调
this.drawResultCallback = null; // 清空普通回调
// 为批次模式生成随机索引
this.batchIndices = [];
for (let i = 0; i < 10; i++) {
this.batchIndices.push(Math.floor(Math.random() * this.prizes.length));
}
console.log("[批次抽奖] 生成随机索引:", this.batchIndices);
}
// 显示抽奖特效
this.show();
setTimeout(() => {
// 确保DOM已渲染完成后再调用play方法
this.$nextTick(() => {
// 检查组件是否已初始化
if (this.$refs.myLucky) {
// 开始旋转
this.$refs.myLucky.play();
if (this.bgmCtx && this.bgmCtx.slotBgm) {
this.bgmCtx.slotBgm.seek(0);
this.bgmCtx.slotBgm.play();
}
// 渐显跳过按钮
this.timers.skipButton = setTimeout(() => {
this.skipButtonOpacity = 1;
}, 1000);
// 批次模式下自动停止第一批次
if (this.isBatchMode && this.internalMode === 10) {
console.log("[批次抽奖] 设置2秒后自动停止第一批次");
this.timers.firstBatch = setTimeout(() => {
// 使用前5个索引作为第一批次结果
const firstBatchIndices = this.batchIndices.slice(0, 5);
console.log("[批次抽奖] 停止第一批次抽奖,使用索引:", firstBatchIndices);
this.stopDraw(firstBatchIndices);
}, 2000);
}
if (typeof callback === "function" && !this.isBatchMode) {
callback();
}
} else {
console.error("抽奖特效组件未初始化");
}
});
}, 100);
return this; // 返回this以支持链式调用
},
// 停止抽奖并指定中奖索引
stopDraw(prizeIndices) {
console.log("stopDraw", prizeIndices);
// 检查是否已初始化
if (!this.isInitialized) {
console.error("抽奖特效尚未初始化请先调用init方法");
return this;
}
if (!this.$refs.myLucky) {
console.error("抽奖特效组件未初始化");
return this;
}
// 如果是批次模式,添加日志
if (this.isBatchMode && this.internalMode === 10) {
console.log("[批次抽奖] 停止抽奖,批次:", this.batchCount + 1, "索引:", prizeIndices);
}
// 如果没有传入奖品索引数组或传入的不是数组
if (
!prizeIndices ||
!Array.isArray(prizeIndices) ||
prizeIndices.length === 0
) {
// 生成与当前模式对应数量的随机索引
const randomIndices = [];
for (let i = 0; i < this.currentMode; i++) {
randomIndices.push(Math.floor(Math.random() * this.prizes.length));
}
this.currentPrizeIndex = randomIndices[0]; // 使用第一个作为主要中奖索引
this.$refs.myLucky.stop(randomIndices);
return this;
}
// 如果传入的数组长度不够当前模式需要的数量,补足
let indices = [...prizeIndices];
while (indices.length < this.currentMode) {
indices.push(indices[indices.length - 1] || 0);
}
// 确保所有索引都在有效范围内
indices = indices.map((index) => {
if (index < 0 || index >= this.prizes.length) {
return Math.floor(Math.random() * this.prizes.length);
}
return index;
});
// 记录第一个索引作为主要中奖索引
this.currentPrizeIndex = indices[0];
// 如果传入的索引超过当前模式只使用前currentMode个
if (indices.length > this.currentMode) {
indices = indices.slice(0, this.currentMode)
}
// 调用stop方法停止旋转
this.$refs.myLucky.stop(indices);
return this;
},
// 重置组件状态
reset() {
this.isInitialized = false;
this.isVisible = false;
this.slots = [];
this.prizes = [];
this.prizeList = [];
this.currentPrizeIndex = -1;
this.isSkip = false;
return this;
},
/**
* 开始抽奖并传入抽奖结果2秒后自动停止
* @param {Array} resultIndices 抽奖结果索引数组
* @param {Function} callback 抽奖结束后的回调函数
* @return {Object} this 返回组件实例,支持链式调用
*/
async startDrawWithResult(resultIndices, callback, chaoShenIndex = -1) {
// 检查是否已初始化
if (!this.isInitialized) {
console.error("抽奖特效尚未初始化请先调用init方法");
return this;
}
if (this.isSkip) {
this.isSkip = false;
}
// 重置跳过按钮透明度
this.skipButtonOpacity = 0;
// 检查参数
if (!resultIndices || !Array.isArray(resultIndices)) {
console.error("抽奖结果必须是数组");
return this;
}
this.chaoShenIndex = chaoShenIndex;
// 模式10特殊处理批次模式
if (this.internalMode === 10) {
// 检查是否有足够的索引
if (resultIndices.length < 10) {
console.error("模式10需要至少10个索引当前只有", resultIndices.length);
// 自动补足到10个
const originalLength = resultIndices.length;
for (let i = originalLength; i < 10; i++) {
resultIndices.push(Math.floor(Math.random() * this.prizes.length));
}
console.log("[批次抽奖] 自动补足索引到10个:", resultIndices);
}
console.log("[批次抽奖] 检测到模式10启用批次模式共", resultIndices.length, "个索引");
// 保存回调函数
this.drawResultCallback = null;
this.batchCallback = typeof callback === 'function' ? callback : null;
// 初始化批次模式
this.isBatchMode = true;
this.batchCount = 0;
this.batchResults = [];
this.batchIndices = resultIndices;
// 重置跳过按钮透明度
// this.skipButtonOpacity = 0;
// 显示抽奖特效
this.show();
let that = this;
setTimeout(() => {
// 确保DOM已渲染完成后再调用play方法
this.$nextTick(() => {
// 检查组件是否已初始化
if (this.$refs.myLucky) {
console.log("[批次抽奖] 开始第一批次抽奖");
// 开始第一批次抽奖
this.$refs.myLucky.play();
// 播放抽奖音乐
if (that.bgmCtx && that.bgmCtx.slotBgm) {
console.log("[批次抽奖] 播放第一批次抽奖音乐");
that.bgmCtx.slotBgm.seek(0);
that.bgmCtx.slotBgm.play();
} else {
console.log("[批次抽奖] 未找到音乐上下文,无法播放音乐");
}
// 渐显跳过按钮
this.timers.skipButton = setTimeout(() => {
this.skipButtonOpacity = 1;
}, 1000);
// 2秒后停止第一批次抽奖
this.timers.firstBatch = setTimeout(() => {
// 使用前5个索引作为第一批次结果
const firstBatchIndices = resultIndices.slice(0, 5);
console.log("[批次抽奖] 停止第一批次抽奖,使用索引:", firstBatchIndices);
this.stopDraw(firstBatchIndices);
}, 2000);
} else {
console.error("[批次抽奖] 抽奖特效组件未初始化");
if (this.batchCallback) {
this.batchCallback({
success: false,
error: "抽奖特效组件未初始化"
});
this.batchCallback = null;
}
this.isBatchMode = false;
}
});
}, 200);
return this; // 返回this以支持链式调用
}
// 非批次模式的普通处理(原有逻辑)
// 保存回调函数
this.drawResultCallback = typeof callback === 'function' ? callback : null;
// 重置跳过按钮透明度
this.skipButtonOpacity = 0;
// 显示抽奖特效
this.show();
try {
await sleep(500);
// 确保DOM已渲染完成后再调用play方法
this.$nextTick(() => {
// 检查组件是否已初始化
if (this.$refs.myLucky) {
// 开始旋转
this.$refs.myLucky.play();
// 播放抽奖音乐
if (this.bgmCtx && this.bgmCtx.slotBgm) {
console.log("播放抽奖音乐");
this.bgmCtx.slotBgm.seek(0);
this.bgmCtx.slotBgm.play();
} else {
console.log("未找到音乐上下文,无法播放音乐");
}
// 渐显跳过按钮
this.timers.skipButton = setTimeout(() => {
this.skipButtonOpacity = 1;
}, 1000);
// 2秒后自动停止抽奖
this.timers.drawResult = setTimeout(() => {
// 停止抽奖并显示结果
this.stopDraw(resultIndices);
}, 2000);
} else {
console.error("抽奖特效组件未初始化");
// 如果有回调,通知调用者初始化失败
if (this.drawResultCallback) {
this.drawResultCallback({
success: false,
error: "抽奖特效组件未初始化"
});
this.drawResultCallback = null;
}
}
});
} catch (error) {
sleep(500);
// 确保DOM已渲染完成后再调用play方法
this.$nextTick(() => {
// 检查组件是否已初始化
if (this.$refs.myLucky) {
// 开始旋转
this.$refs.myLucky.play();
// 播放抽奖音乐
if (this.bgmCtx && this.bgmCtx.slotBgm) {
console.log("播放抽奖音乐");
this.bgmCtx.slotBgm.seek(0);
this.bgmCtx.slotBgm.play();
} else {
console.log("未找到音乐上下文,无法播放音乐");
}
// 渐显跳过按钮
this.timers.skipButton = setTimeout(() => {
this.skipButtonOpacity = 1;
}, 1000);
// 2秒后自动停止抽奖
this.timers.drawResult = setTimeout(() => {
// 停止抽奖并显示结果
this.stopDraw(resultIndices);
}, 2000);
} else {
console.error("抽奖特效组件未初始化");
// 如果有回调,通知调用者初始化失败
if (this.drawResultCallback) {
this.drawResultCallback({
success: false,
error: "抽奖特效组件未初始化"
});
this.drawResultCallback = null;
}
}
});
}
return this; // 返回this以支持链式调用
},
// 开始第二批次抽奖
startSecondBatch() {
console.log("[批次抽奖] 尝试开始第二批次,批次模式:", this.isBatchMode, "当前模式:", this.internalMode);
if (!this.isBatchMode || this.internalMode !== 10) {
console.error("[批次抽奖] 不是批次模式或模式不是10无法开始第二批次");
return;
}
console.log("[批次抽奖] 开始第二批次抽奖");
// 重置跳过按钮透明度
this.skipButtonOpacity = 0;
// 重新准备抽奖特效组件状态
try {
// 重置抽奖特效状态,为第二次抽奖准备
console.log("[批次抽奖] 重置抽奖特效状态,准备第二批次抽奖");
// 重新生成随机排序的抽奖列
const arr = Array.from({
length: this.prizes.length
}, (_, i) => i);
let slots = [];
// 根据模式创建对应数量的列
const slotColumns = this.currentMode;
for (let i = 0; i < slotColumns; i++) {
slots.push({
order: shuffle([...arr]),
speed: 20
});
}
// 更新slots
this.slots = slots;
} catch (error) {
console.error("[批次抽奖] 重置抽奖特效状态失败:", error);
}
this.$nextTick(() => {
if (this.$refs.myLucky) {
// 开始第二批次抽奖
console.log("[批次抽奖] 调用play方法开始第二批次");
this.$refs.myLucky.play();
// 播放抽奖音乐
if (this.bgmCtx && this.bgmCtx.slotBgm) {
console.log("[批次抽奖] 播放第二批次抽奖音乐");
this.bgmCtx.slotBgm.seek(0);
this.bgmCtx.slotBgm.play();
} else {
console.log("[批次抽奖] 未找到音乐上下文,无法播放音乐");
}
// 渐显跳过按钮
this.timers.skipButton = setTimeout(() => {
this.skipButtonOpacity = 1;
}, 1000);
// 2秒后停止第二批次抽奖
this.timers.secondBatch = setTimeout(() => {
// 为第二批次生成随机索引或使用预设索引
let indices = [];
if (this.batchIndices && this.batchIndices.length > 5) {
// 使用预设的第二批次索引
indices = this.batchIndices.slice(5, 10);
console.log("[批次抽奖] 使用预设的第二批次索引", indices);
} else {
// 生成随机索引
for (let i = 0; i < 5; i++) {
indices.push(Math.floor(Math.random() * this.prizes.length));
}
console.log("[批次抽奖] 生成随机第二批次索引", indices);
}
this.stopDraw(indices);
}, 2000);
} else {
console.error("[批次抽奖] 第二批次无法启动,抽奖特效组件未找到");
// 如果组件未找到,直接结束批次并返回结果
if (this.batchCallback && typeof this.batchCallback === 'function') {
const result = {
allPrizes: this.batchResults,
message: `第二批次抽奖失败,返回已有结果`,
error: "抽奖特效组件未找到",
success: false
};
this.batchCallback(result);
this.batchCallback = null;
// 重置批次状态
this.isBatchMode = false;
this.batchCount = 0;
this.batchResults = [];
}
}
});
},
},
beforeDestroy() {
// 清理所有定时器
Object.values(this.timers).forEach(timer => {
if (timer) {
clearTimeout(timer);
}
});
},
mounted() {
// 不再自动初始化
},
watch: {
// 监听外部mode变化同步到内部状态
mode: {
immediate: true,
handler(newVal) {
if ([1, 3, 5, 10, '1', '3', '5', '10'].includes(newVal)) {
this.internalMode = parseInt(newVal);
}
}
}
}
};
</script>
<style lang="scss" scoped>
// 内容容器样式
.content-container {
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
background-image: url($imgurl + "common/slot_bg.webp");
background-size: cover;
background-position: center;
position: fixed;
top: 0;
left: 0;
z-index: 999;
}
.detail-lucky {
// 抽奖特效容器样式
.slot-container {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
}
.slot-icon {
padding-bottom: 25rpx;
}
// 抽奖特效视图样式
.slot-view {
background-size: 100% 100%;
width: 100%;
padding-top: 80rpx;
padding-bottom: 80rpx;
display: flex;
justify-content: center;
align-items: center;
}
// 根据模式设置不同的背景
.slot-view-1 {
background: url("https://image.zfunbox.cn/static/image/lucky/di_5.png") no-repeat;
background-size: 100% 100%;
}
.slot-view-3 {
background: url("https://image.zfunbox.cn/static/image/lucky/di_3.png") no-repeat;
background-size: 100% 100%;
}
.slot-view-5 {
background: url("https://image.zfunbox.cn/static/image/lucky/di_5.png") no-repeat;
background-size: 100% 100%;
}
// 抽奖项样式
.item-lottry {
height: 152.78rpx;
width: 152.78rpx;
display: flex;
justify-content: center;
align-items: center;
font-size: 30rpx;
border-radius: 16rpx;
color: black;
box-sizing: border-box;
background-color: rgba(255, 255, 255, 1);
}
// 跳过动画按钮样式
.skip-animation {
color: #249073;
font-size: 21rpx;
text-align: center;
padding-top: 20rpx;
padding-bottom: 10rpx;
display: inline-block;
opacity: 0;
transition: opacity 0.5s ease;
user-select: none;
}
.skip-animation:active {
opacity: 0.7;
}
}
</style>