1113 lines
31 KiB
Vue
1113 lines
31 KiB
Vue
<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> |