594 lines
14 KiB
Vue
594 lines
14 KiB
Vue
<template>
|
||
<page-container title="每日免费送" :showBack="true">
|
||
<view class="prize-draw">
|
||
<view style="height: 512rpx;"></view>
|
||
<view class="choujiang">
|
||
<view style="height:52rpx;"></view>
|
||
<view class="neiquan">
|
||
<view class="grid-container">
|
||
<view class="jiangping" v-for="(item, index) in prizes"
|
||
:class="{ 'xuanzhong': currentIndex === index && !isFinalWin, 'win-flash': currentIndex === index && isFinalWin }"
|
||
:key="index">
|
||
<!-- 奖品图片将在这里显示 -->
|
||
<image :src="item.image"
|
||
style="width:95%;height:95%;margin-left: 1rpx;border-radius: 25rpx;">
|
||
</image>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="draw-btn-container">
|
||
<view class="draw-btn" @click="startDraw"></view>
|
||
</view>
|
||
|
||
</view>
|
||
<view class="bottom-buttons">
|
||
<view class="button-item gzsm" @click="showRules">
|
||
<image src="https://image.zfunbox.cn/huodong/gzsm.png" style="width: 136.11rpx;height: 53.47rpx;">
|
||
</image>
|
||
</view>
|
||
<view class="button-item zjjl" @click="showRecords">
|
||
<image src="https://image.zfunbox.cn/huodong/zbtn.png" style="width: 136.11rpx;height: 53.47rpx;">
|
||
</image>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<rule-pop ref="rulePop"></rule-pop>
|
||
|
||
<!-- 中奖记录弹窗 -->
|
||
<uni-popup ref="recordsPop" type="center" mask-background-color="rgba(0,0,0,0.8)">
|
||
<view class="records-pop">
|
||
<view class="records-pop-title">中奖记录</view>
|
||
<scroll-view scroll-y class="records-pop-content">
|
||
<view v-if="prizeRecords.length > 0" class="records-list">
|
||
<view v-for="(item, index) in prizeRecords" :key="index" class="record-card">
|
||
<view class="flex row align-center"
|
||
style="width: 100%; height: 100%; justify-content: space-between;">
|
||
<view class="flex column" style="margin-left: 24rpx;">
|
||
<text style="font-size: 20rpx; color: #999999;">{{ item.title }}</text>
|
||
<text style="font-size: 20rpx; color: #999999; margin-top: 8rpx;">{{ item.time
|
||
}}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view v-else class="empty-tip">暂无中奖记录</view>
|
||
</scroll-view>
|
||
<view class="close-btn" @click="$refs.recordsPop.close()">
|
||
<image :src="$img1('common/close.png')" style="width: 48rpx;height: 48rpx;"></image>
|
||
</view>
|
||
</view>
|
||
</uni-popup>
|
||
</page-container>
|
||
|
||
</template>
|
||
|
||
<script>
|
||
import PageContainer from '@/components/page-container/page-container.vue'
|
||
|
||
|
||
export default {
|
||
components: {
|
||
PageContainer
|
||
},
|
||
data() {
|
||
return {
|
||
goods_id: 0,
|
||
isDrawing: false,
|
||
prizes: [
|
||
// 这里可以放置奖品数据
|
||
],
|
||
currentIndex: -1, // 当前选中的索引
|
||
timer: null, // 定时器
|
||
speed: 100, // 初始速度,数值越小速度越快
|
||
times: 0, // 动画运行次数计数
|
||
targetIndex: 0, // 最终中奖索引
|
||
isFinalWin: false, // 是否到达最终中奖状态
|
||
animationType: 1, // 动画类型:1=顺序遍历,2=8字形
|
||
path8Index: 0, // 8字形路径当前位置
|
||
animationTypes: {
|
||
SEQUENTIAL: 1, // 顺序遍历
|
||
FIGURE_EIGHT: 2 // 8字形走法
|
||
},
|
||
pathFigureEight: [0, 1, 2, 5, 4, 3, 6, 7, 8, 5, 4, 3], // 8字形路径
|
||
goods: null,
|
||
useMoney: true,
|
||
useIntegral: true,
|
||
useMoney2: true,
|
||
selectPrizes: null,
|
||
prizeRecords: [] // 中奖记录列表
|
||
};
|
||
},
|
||
onLoad() {
|
||
this.load();
|
||
},
|
||
methods: {
|
||
async load() {
|
||
let goods_id = this.$config.getAppSetting('daily_free_draw_id');
|
||
this.goods_id = goods_id;
|
||
//infinite_goodsdetail
|
||
const { status, data, msg } = await this.$request.post('infinite_goodsdetail', { goods_id: goods_id });
|
||
console.log(status, data, msg);
|
||
let { goods, goods_list } = data;
|
||
this.goods = goods;
|
||
let p = [];
|
||
goods_list.data.map(item => {
|
||
console.log(item);
|
||
p.push({
|
||
image: item.imgurl,
|
||
title: item.title,
|
||
id: item.id
|
||
});
|
||
});
|
||
this.prizes = p;
|
||
console.log(goods_list);
|
||
},
|
||
|
||
async startDraw() {
|
||
if (this.isDrawing) return;
|
||
this.isDrawing = true;
|
||
this.isFinalWin = false; // 重置中奖闪烁状态
|
||
|
||
// 清除可能存在的定时器
|
||
if (this.timer) {
|
||
clearInterval(this.timer);
|
||
this.timer = null;
|
||
}
|
||
if (this.goods == null && this.goods.price == '') {
|
||
this.isDrawing = false;
|
||
this.$c.msg('抽奖失败')
|
||
return false;
|
||
}
|
||
console.log('免费');
|
||
try {
|
||
const goods_list_Id = await this.confirmSubmit([1, 1]);
|
||
let targetIndex = 0;
|
||
// console.log(goods_list_Id, targetIndex, this.prizes);
|
||
let selectPrizes = null;
|
||
this.prizes.forEach((item, index, array) => {
|
||
// console.log(item); // 当前元素
|
||
// console.log(index); // 当前索引
|
||
// console.log(array); // 数组本身
|
||
if (item.id == goods_list_Id) {
|
||
targetIndex = index;
|
||
selectPrizes = item;
|
||
}
|
||
});
|
||
|
||
this.selectPrizes = selectPrizes;
|
||
console.log(this.selectPrizes);
|
||
this.targetIndex = targetIndex;
|
||
} catch (error) {
|
||
this.$c.msg(error)
|
||
this.isDrawing = false;
|
||
return;
|
||
}
|
||
// 重置计数和速度
|
||
this.times = 0;
|
||
this.speed = 100;
|
||
this.path8Index = 0;
|
||
|
||
// 随机选择动画类型:1-2之间
|
||
this.animationType = Math.floor(Math.random() * 2) + 1;
|
||
let animationName = "顺序遍历";
|
||
if (this.animationType === this.animationTypes.FIGURE_EIGHT) {
|
||
animationName = "8字形";
|
||
}
|
||
console.log('抽奖动画类型:', animationName);
|
||
|
||
// 随机生成中奖索引(0-8之间)
|
||
// this.targetIndex = Math.floor(Math.random() * 9);
|
||
|
||
// 开始动画
|
||
this.runAnimation();
|
||
},
|
||
|
||
runAnimation() {
|
||
this.timer = setInterval(() => {
|
||
this.times++;
|
||
|
||
// 根据不同的动画类型选择下一个格子
|
||
if (this.animationType === this.animationTypes.SEQUENTIAL) {
|
||
// 顺序遍历方式
|
||
this.currentIndex = (this.currentIndex + 1) % 9;
|
||
} else {
|
||
// 8字形路径
|
||
this.path8Index = (this.path8Index + 1) % this.pathFigureEight.length;
|
||
this.currentIndex = this.pathFigureEight[this.path8Index];
|
||
}
|
||
|
||
// 动画速度控制
|
||
if (this.times > 20) { // 前20次保持高速
|
||
if (this.times > 30) { // 30次后开始减速
|
||
this.speed += 10; // 速度递减
|
||
}
|
||
|
||
// 如果速度减到一定程度,并且当前索引接近中奖索引,则停止
|
||
if (this.speed > 300 && this.currentIndex === this.targetIndex) {
|
||
clearInterval(this.timer);
|
||
this.timer = null;
|
||
this.startWinAnimation();
|
||
return; // 重要:确保不再继续执行
|
||
}
|
||
|
||
// 只有在需要改变速度时才重新设置定时器
|
||
clearInterval(this.timer);
|
||
this.timer = null;
|
||
this.runAnimation();
|
||
}
|
||
}, this.speed);
|
||
},
|
||
|
||
startWinAnimation() {
|
||
// 开始中奖闪烁动画
|
||
this.isFinalWin = true;
|
||
|
||
// 播放闪烁效果后显示结果
|
||
setTimeout(() => {
|
||
this.showResult();
|
||
}, 1500); // 闪烁1.5秒后显示结果
|
||
},
|
||
|
||
showResult() {
|
||
// 动画结束后的操作
|
||
setTimeout(() => {
|
||
this.isDrawing = false;
|
||
if (this.selectPrizes == null) {
|
||
uni.showToast({
|
||
title: '获取奖品失败',
|
||
icon: 'none',
|
||
duration: 2000
|
||
});
|
||
return;
|
||
}
|
||
uni.showToast({
|
||
title: '恭喜获得' + this.selectPrizes.title + '奖品!',
|
||
icon: 'none',
|
||
duration: 2000
|
||
});
|
||
|
||
// 这里可以添加中奖弹窗或其他效果
|
||
}, 500);
|
||
},
|
||
|
||
// 显示规则说明
|
||
showRules() {
|
||
if (this.isDrawing) {
|
||
uni.showToast({
|
||
title: '请等待抽奖完成',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
this.$refs.rulePop.getRule(22, '规则说明')
|
||
},
|
||
|
||
// 显示中奖记录
|
||
showRecords() {
|
||
if (this.isDrawing) {
|
||
uni.showToast({
|
||
title: '请等待抽奖完成',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
// 加载中奖记录
|
||
this.loadPrizeRecords();
|
||
// 打开弹窗
|
||
this.$refs.recordsPop.open();
|
||
},
|
||
|
||
// 加载中奖记录
|
||
async loadPrizeRecords() {
|
||
try {
|
||
const { status, data, msg } = await this.$request.post('infinite_prizerecords', {
|
||
goods_id: this.goods_id
|
||
});
|
||
|
||
if (status !== 1) {
|
||
this.$c.msg(msg || '获取中奖记录失败');
|
||
return;
|
||
}
|
||
|
||
if (data && data.data && data.data.length > 0) {
|
||
// 格式化中奖记录数据
|
||
this.prizeRecords = data.data.map(item => ({
|
||
title: item.goodslist_title || '未知奖品',
|
||
time: item.addtime || ''
|
||
}));
|
||
} else {
|
||
this.prizeRecords = [];
|
||
}
|
||
} catch (error) {
|
||
console.error('加载中奖记录失败', error);
|
||
this.$c.msg('获取中奖记录失败');
|
||
}
|
||
},
|
||
|
||
async confirmSubmit([type, num, flag]) {
|
||
|
||
let url = 'infinite_ordermoney'
|
||
if (type == 1) {
|
||
url = 'infinite_orderbuy'
|
||
}
|
||
let psotData = {
|
||
goods_id: this.goods_id,
|
||
prize_num: num,
|
||
use_money_is: 1,
|
||
use_integral_is: 2,
|
||
use_money2_is: 2,
|
||
coupon_id: '',
|
||
};
|
||
let res = await this.$request.post(url, psotData);
|
||
const { status, data, msg } = res;
|
||
if (status !== 1) {
|
||
// this.$c.msg(msg);
|
||
throw msg;
|
||
}
|
||
console.log(data.order_num);
|
||
if (data.order_num != null) {
|
||
const prize = await this.getPrize(data.order_num);
|
||
console.log(prize);//goodslist_id
|
||
if (prize.goodslist_id != null) {
|
||
return prize.goodslist_id;
|
||
}
|
||
}
|
||
throw '出现异常';
|
||
},
|
||
async getPrize(order_num) {
|
||
if (!order_num) {
|
||
return
|
||
}
|
||
const res = await this.$request.post('infinite_prizeorderlog', {
|
||
order_num
|
||
});
|
||
let { status, data, msg } = res;
|
||
if (status !== 1) {
|
||
throw msg;
|
||
}
|
||
return data.data[0];
|
||
|
||
},
|
||
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
.prize-draw {
|
||
background: url($baseurl+'huodong/bg.png') no-repeat center center;
|
||
background-size: 100% 100%;
|
||
height: 1495.14rpx;
|
||
width: 100vw;
|
||
|
||
.choujiang {
|
||
background: url($baseurl+'huodong/ke.png') no-repeat center center;
|
||
background-size: 100% 100%;
|
||
margin: 0px auto;
|
||
height: 829.86rpx;
|
||
width: 90%;
|
||
position: relative;
|
||
|
||
.neiquan {
|
||
width: 430rpx;
|
||
height: 465rpx;
|
||
margin: 0px auto;
|
||
padding: 15rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.grid-container {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
grid-template-rows: repeat(3, 1fr);
|
||
gap: 10rpx;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.jiangping {
|
||
// background: url($baseurl+'huodong/kuang.png') no-repeat center center;
|
||
// background-size: 100% 100%;
|
||
// border: 1px dashed #75C5FF;
|
||
|
||
border-radius: 12rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background-color: rgba(255, 255, 255, 0.7);
|
||
transition: all 0.05s; // 加快过渡效果,让动画更流畅
|
||
|
||
&:active {
|
||
transform: scale(0.95);
|
||
}
|
||
}
|
||
|
||
.draw-btn-container {
|
||
position: absolute;
|
||
bottom: 95rpx;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 100%;
|
||
display: flex;
|
||
justify-content: center;
|
||
|
||
}
|
||
|
||
.draw-btn {
|
||
width: 298.61rpx;
|
||
height: 118.75rpx;
|
||
background: url($baseurl+'huodong/anniu.png') no-repeat;
|
||
background-size: 100% 100%;
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
//border-radius: 40rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
//box-shadow: 0 4rpx 8rpx rgba(255, 87, 34, 0.3);
|
||
transition: all 0.3s;
|
||
|
||
&:active {
|
||
transform: scale(0.95);
|
||
//box-shadow: 0 2rpx 4rpx rgba(255, 87, 34, 0.3);
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
|
||
.xuanzhong {
|
||
background: url($baseurl+'huodong/xuanzhong.png') no-repeat !important;
|
||
background-size: 100% 100% !important;
|
||
width: 100% !important;
|
||
height: 100% !important;
|
||
}
|
||
|
||
.win-flash {
|
||
background: url($baseurl+'huodong/xuanzhong.png') no-repeat !important;
|
||
background-size: 100% 100% !important;
|
||
width: 100% !important;
|
||
height: 100% !important;
|
||
animation: win-blink 0.3s 5 alternate;
|
||
}
|
||
|
||
.bottom-buttons {
|
||
position: relative;
|
||
top: -20rpx;
|
||
width: 100%;
|
||
display: flex;
|
||
justify-content: space-evenly;
|
||
padding: 10rpx;
|
||
box-sizing: border-box;
|
||
|
||
.button-item {
|
||
width: 136.11rpx;
|
||
height: 53.47rpx;
|
||
font-size: 28rpx;
|
||
border-radius: 35rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: all 0.3s;
|
||
// box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
|
||
|
||
&:active {
|
||
transform: scale(0.95);
|
||
// background-color: rgba(255, 255, 255, 0.9);
|
||
}
|
||
}
|
||
}
|
||
|
||
.gzsm {
|
||
|
||
animation: pulse 0.3s 5 alternate;
|
||
width: 136.11rpx;
|
||
height: 53.47rpx;
|
||
}
|
||
|
||
.zjjl {
|
||
|
||
animation: pulse 0.3s 5 alternate;
|
||
width: 136.11rpx;
|
||
height: 53.47rpx;
|
||
}
|
||
|
||
@keyframes win-blink {
|
||
0% {
|
||
opacity: 1;
|
||
transform: scale(1);
|
||
}
|
||
|
||
100% {
|
||
opacity: 0.5;
|
||
transform: scale(1.05);
|
||
}
|
||
}
|
||
|
||
@keyframes pulse {
|
||
from {
|
||
opacity: 1;
|
||
}
|
||
|
||
to {
|
||
opacity: 0.8;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 中奖记录弹窗样式
|
||
.records-pop {
|
||
width: 600rpx;
|
||
height: 750rpx;
|
||
background-color: #fff;
|
||
border-radius: 20rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
position: relative;
|
||
|
||
.records-pop-title {
|
||
text-align: center;
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
padding: 30rpx 0;
|
||
border-bottom: 1px solid #eee;
|
||
}
|
||
|
||
.records-pop-content {
|
||
flex: 1;
|
||
padding: 20rpx;
|
||
|
||
.records-list {
|
||
width: 94%;
|
||
.record-item {
|
||
padding: 20rpx 0;
|
||
border-bottom: 1px solid #f5f5f5;
|
||
|
||
.prize-info {
|
||
display: flex;
|
||
flex-direction: column;
|
||
|
||
.prize-title {
|
||
font-size: 30rpx;
|
||
color: #333;
|
||
margin-bottom: 10rpx;
|
||
}
|
||
|
||
.prize-time {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.empty-tip {
|
||
text-align: center;
|
||
color: #999;
|
||
font-size: 28rpx;
|
||
margin-top: 200rpx;
|
||
}
|
||
}
|
||
|
||
.close-btn {
|
||
position: absolute;
|
||
left: 50%;
|
||
bottom: -80rpx;
|
||
transform: translateX(-50%);
|
||
width: 48rpx;
|
||
height: 48rpx;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.record-card {
|
||
width: 100%;
|
||
height: 88rpx;
|
||
background-color: #F8F8F8;
|
||
margin: 0 auto 0rpx;
|
||
border-radius: 25rpx;
|
||
}
|
||
}
|
||
</style>
|