需求:后台返回对应的奖品数据,小程序以九宫格形式展示奖品信息,点击抽奖后转动转盘,通过接口获取奖品对应的位置,并把奖品位置高亮显示。
实现的效果:
①未抽奖
2、抽奖中
③抽奖完成
实现代码
<template>
<div class="model_lottery" ref="model_lottery">
<div class=lottery_block v-if="lotteryBlock && lotteryBlock.length > 1">
<div class="lottery_o"
v-for="(item, index) in lotteryBlock"
@click="startLottery(item)"
:class="{
lottery_btn: index === 4,
_active: item.positionIdx === startPosition,
disabled: lotteryState !== 0 && index === 4,
is_selected: item.positionIdx === startPosition && lotteryState === 2
}"
:key="index"><span>{{ index === 4 ? '立即抽奖' : item.prizeName }}</span>
</div>
</div>
<van-empty v-else description="暂无抽奖活动" />
<div class="mes_model" v-if="sussessMesVisible">
<div>
<p>{{ this.receiveState ? lotteyName : '领取失败,请重新领取' }}</p>
<van-button
@click="submitLottery"
type="info" size="small">{{ this.receiveState ? '确认' : '重新领取' }}</van-button>
</div>
</div>
<div class="bg_wrap" :style="{ backgroundImage: `url(${bgUrl})`}"></div>
</div>
</template>
<script>
import axios from 'axios'
import { findLuckyDrawPrize, drawLuckyDrawPrize, getHitPrizeV2 } from '@/api/allServeMethods'
export default {
data () {
return {
positionMap: { 0: 0, 1: 1, 2: 2, 3: 7, 5: 3, 6: 6, 7: 5, 8: 4 }, // 奖品位置-顺时针旋转
lotteryBlock: [], // 奖品数据
startPosition: -1, // 旋转的位置
lotterySpeed: 160, // 抽奖转动速度
rotateTimes: 1, // 当前抽奖旋转周数
lotteryTimer: null,
lotteryState: 0, // 抽奖状态 0 未开始 1 进行中 2 抽奖结束
lotteryItem: '', // 抽奖活动数据
searchParams: {},
selectedLottery: '', // 抽中的奖品
sussessMesVisible: false,
receiveState: true,
lotteyName: '',
hitPosition: 0, // 抽中奖品位置
bgUrl: '',
getPrizeStatus: true // 获取奖品状态
}
},
created () {
document.title = '抽奖'
this.findLuckyDrawPrize()
},
methods: {
// 查询抽奖活动奖品
findLuckyDrawPrize () {
const searchParams = {}
let serverName = location.search.substring(1)
serverName = serverName.split('&')
serverName.forEach(item => {
if (item.split('=')[0] !== 'contextPath') {
searchParams[item.split('=')[0]] = item.split('=')[1]
}
})
this.searchParams = searchParams
findLuckyDrawPrize(searchParams).then(res => {
this.lotteryItem = res.data
this.bgUrl = res.data.backgroundImageUrl || []
let lotteryBlock = res.data.prizeList || []
if (lotteryBlock.length) {
lotteryBlock.splice(4, 0, {})
this.lotteryBlock = lotteryBlock.map((item, index) => {
return {
...item,
prizePosition: item.prizePosition - 1, // 接口返回奖品位置从1开始
index,
positionIdx: this.positionMap[index]
}
})
}
console.log(this.lotteryBlock)
if (this.lotteryItem.enableDraw === '0') {
this.lotteryState = 1
this.$toast(res.msg)
}
})
},
// 开始抽奖
startLottery (lotteryItem) {
// lotteryItem.positionIdx || lotteryItem.positionIdx === 0 -- 点击立即抽奖之外无效
if (lotteryItem.positionIdx || lotteryItem.positionIdx === 0 || this.lotteryState !== 0) return
this.setTimeoutLottery()
this.getHitPrize()
},
// 抽奖转盘动画
setTimeoutLottery () {
this.lotteryState = 1
this.startPosition++
if (this.startPosition === 8) { // 转了一周
this.startPosition = 0
this.rotateTimes++
}
if (this.rotateTimes === 1) {
this.lotterySpeed -= 15
}
if (this.rotateTimes >= 7) {
this.lotterySpeed += (20 * this.lotteryBlock.find(item => item.positionIdx === this.startPosition).index / 2)
}
if (this.lotteryTimer) {
clearTimeout(this.lotteryTimer)
}
let selectLottery = this.lotteryBlock.find(o => o.prizePosition === this.hitPosition)
if (!this.getPrizeStatus) {
clearTimeout(this.lotteryTimer)
} else if (!(this.rotateTimes === 8 && selectLottery && this.startPosition === selectLottery.positionIdx)) {
this.lotteryTimer = setTimeout(() => {
this.setTimeoutLottery()
}, this.lotterySpeed)
} else {
this.lotteryState = 2
this.drawLuckyDrawPrize()
}
},
// 获取抽奖奖品
getHitPrize () {
const searchParams = {
...this.searchParams,
activityId: this.lotteryItem.activityId,
batchKey: this.lotteryItem.batchKey,
randomKey: this.lotteryItem.randomKey
}
getHitPrizeV2(searchParams).then(res => {
this.hitPosition = res.data - 1 // 接口返回奖品位置从1开始
this.getPrizeStatus = true
}).catch(() => {
this.getPrizeStatus = false
})
},
// 领取抽奖奖品
drawLuckyDrawPrize () {
this.selectedLottery = this.lotteryBlock.find(item => item.prizePosition === this.hitPosition)
const searchParams = {
...this.searchParams,
activityId: this.lotteryItem.activityId,
batchKey: this.lotteryItem.batchKey,
prizeId: this.selectedLottery.prizeId,
randomKey: this.lotteryItem.randomKey
}
drawLuckyDrawPrize(searchParams).then(res => {
this.sussessMesVisible = true
this.receiveState = true
this.lotteyName = res.msg
this.sendTextMessage()
}).catch(() => {
this.sussessMesVisible = true
this.receiveState = false
})
},
// 领取奖品成功发送通知
sendTextMessage () {
if (this.selectedLottery.prizeType === '9' || !this.searchParams.notifyUrl) return
const searchParams = {
touser: this.searchParams.weiCode,
content: `恭喜您,抽中了奖品【${this.selectedLottery.prizeName}】`
}
axios.post(this.searchParams.notifyUrl, searchParams)
.then(res => {
console.log(res)
})
},
// 确认或重新领取
submitLottery () {
if (!this.receiveState) {
this.drawLuckyDrawPrize()
}
this.sussessMesVisible = false
},
iframePostMessage (data) {
window.addEventListener('message', function (event) {
console.log(event)
top.postMessage(data, '*')
}, false)
}
}
}
</script>
<style scoped lang="less">
.model_lottery {
height: 100%;
font-size: 14px;
overflow: hidden;
color: #4c4c4c;
position: relative;
.bg_wrap {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
background-size: 100% 100%;
background-repeat: no-repeat no-repeat;
z-index: -1;
opacity: 0.3;
}
.lottery_block {
width: 320px;
height: 320px;
margin: 50% calc(50% - 160px);
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.lottery_o {
width: ~"calc(320px / 3 - 10px)";
margin: 5px;
height: ~"calc(320px / 3 - 10px)";
background: #f1f1f1;
border-radius: 2px;
position: relative;
span {
display: block;
word-break:break-all;
word-wrap:break-word;
position: absolute;
top: 50%;
left: 5px;
transform: translateY(-50%);
width: ~"calc(100% - 10px)";
text-align: center;
}
&._active {
background: orange;
span {
color: #fff;
}
}
&.lottery_btn {
width: ~"calc(320px / 3 - 30px)";
height: ~"calc(320px / 3 - 30px)";
border-radius: 50%;
background: orangered;
margin-top: 15px;
cursor: pointer;
transition: .1s;
span {
color: #fff;
letter-spacing: 2px;
font-size: 14px;
padding: 0;
}
}
&.disabled {
opacity: .2;
}
&.is_selected {
animation: selectLottery 1.8s linear;
animation-delay: 1s;
}
}
}
@keyframes selectLottery {
0% {
opacity: .1;
}
20% {
opacity: 1;
}
40% {
opacity: .1;
}
60% {
opacity: 1;
}
80% {
opacity: .1;
}
100% {
opacity: 1;
}
}
.mes_model {
width: 60%;
height: 120px;
background: #fff;
position: absolute;
top: 50%;
margin-top: -60px;
left: 20%;
border-radius: 4px;
z-index: 999;
box-shadow: 0 0 4px rgba(0,0,0,.3);
text-align: center;
& > div {
position: absolute;
top: 50%;
transform: translateY(-50%);
left: 0;
right: 0;
text-align: center;
padding: 0 10px;
& > p {
font-size: 14px;
text-align: center;
padding-bottom: 10px;
}
}
/deep/.van-button__text {
letter-spacing: 2px;
}
}
}
</style>
findLuckyDrawPrize查询奖品数据,对应的数据结构如下:
getHitPrize获取奖品对应的位置,返回数据结构如下: