feat: 添加抽奖
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
<template>
|
||||
<view
|
||||
class="grid-lottery"
|
||||
:style="{
|
||||
height: gridLotteryHeight,
|
||||
}"
|
||||
>
|
||||
<view class="lottery-list">
|
||||
<view
|
||||
v-for="(item, index) in formateList"
|
||||
:key="item.id"
|
||||
class="lottery-item"
|
||||
:style="{
|
||||
width: `${itemWidth}%`,
|
||||
height: `${itemHeight}${itemHeightUnit}`,
|
||||
transform: `translate(${place(index).x}%, ${place(index).y}${itemHeightUnit})`,
|
||||
}"
|
||||
>
|
||||
<view class="relative">
|
||||
<slot name="lottery-item" :data="item" :index="index" :currIndex="currIndex" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
class="start-button"
|
||||
:style="{
|
||||
left: `${itemWidth}%`,
|
||||
right: `${itemWidth}%`,
|
||||
top: `${itemWidth}%`,
|
||||
bottom: `${itemWidth}%`,
|
||||
}"
|
||||
@tap="onStart"
|
||||
>
|
||||
<slot name="start-button"></slot>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'GridLottery',
|
||||
props: {
|
||||
// 转盘转动间隔
|
||||
interval: {
|
||||
type: Number,
|
||||
default: 50,
|
||||
},
|
||||
// 是否逐渐减速
|
||||
isIntervalIncrease: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 减速开始时间
|
||||
intervalIncreaseStartTime: {
|
||||
type: Number,
|
||||
default: 3000,
|
||||
},
|
||||
// 最小速度
|
||||
maxInterval: {
|
||||
type: Number,
|
||||
default: 500,
|
||||
},
|
||||
// 奖项外框高度
|
||||
itemHeight: {
|
||||
type: Number,
|
||||
default: 100,
|
||||
},
|
||||
// 高度单位
|
||||
itemHeightUnit: {
|
||||
type: String,
|
||||
default: 'rpx',
|
||||
},
|
||||
// 总数必须为>=8 且被4整除
|
||||
list: {
|
||||
type: Array,
|
||||
default() {
|
||||
// return [
|
||||
// {
|
||||
// id: string,
|
||||
// sort: number
|
||||
// }
|
||||
// ];
|
||||
return []
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
transform: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
currIndex: 0,
|
||||
startFlag: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
gridLotteryHeight({ itemHeight, formateList, colunmCount, itemHeightUnit }) {
|
||||
return `${itemHeight * ((formateList.length - colunmCount * 2) / 2 + 2)}${itemHeightUnit}`
|
||||
},
|
||||
itemWidth() {
|
||||
return 100 / this.colunmCount
|
||||
},
|
||||
colunmCount() {
|
||||
const len = this.list.length
|
||||
if (len > 8) {
|
||||
return 3 + Math.floor((len - 8) / 4)
|
||||
}
|
||||
return 3
|
||||
},
|
||||
|
||||
formateList() {
|
||||
const len = this.list.length
|
||||
if (len > 7 && (len - 8) % 4 !== 0) {
|
||||
console.warn(
|
||||
'请检查数组,总数必须为>=8 且大余8部分部分能被4整除,如长度为8、12、16...的数组',
|
||||
)
|
||||
}
|
||||
const _list = this.list || []
|
||||
const formateList = _list.sort((a, b) => a.sort - b.sort)
|
||||
return formateList
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// 通过索引获取定位
|
||||
place(index) {
|
||||
const len = this.list.length
|
||||
// 序号
|
||||
const indexToOrder = index + 1
|
||||
if (indexToOrder > this.colunmCount) {
|
||||
// 去除上下行,总行数
|
||||
const rowCount = (len - this.colunmCount * 2) / 2
|
||||
// 非处于左侧
|
||||
if (index > this.colunmCount + rowCount) {
|
||||
// 处于右侧
|
||||
if (indexToOrder > this.colunmCount * 2 + rowCount) {
|
||||
return {
|
||||
x: 0,
|
||||
y: this.itemHeight * (rowCount * 2 + this.colunmCount * 2 - index),
|
||||
}
|
||||
}
|
||||
// 处于底部
|
||||
return {
|
||||
x: 100 * (this.colunmCount * 2 + rowCount - indexToOrder),
|
||||
y: this.itemHeight * (rowCount + 1),
|
||||
}
|
||||
}
|
||||
// 处于右侧
|
||||
return {
|
||||
x: 100 * (this.colunmCount - 1),
|
||||
y: this.itemHeight * (indexToOrder - this.colunmCount),
|
||||
}
|
||||
}
|
||||
// 处于顶部
|
||||
return {
|
||||
x: 100 * index,
|
||||
y: 0,
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 开始抽奖
|
||||
* @param {string|number} id 获奖id
|
||||
* @param {number} minTime 转盘最小持续时间
|
||||
*/
|
||||
async start(id, minTime) {
|
||||
if (this.startFlag) return
|
||||
const len = this.formateList.length
|
||||
const activeIndex = this.formateList.findIndex((item) => item.id === id)
|
||||
if (activeIndex === -1) {
|
||||
const errorText = `没有找到该中奖id ${id}`
|
||||
console.error(errorText)
|
||||
return this.$emit('onError', errorText)
|
||||
}
|
||||
let time = minTime
|
||||
// 动画速度
|
||||
let interval = this.interval
|
||||
const startRotate = () => {
|
||||
this.startFlag = true
|
||||
clearTimeout(this.timer)
|
||||
this.timer = setTimeout(() => {
|
||||
// 抽奖结束
|
||||
if (time < 1 && this.currIndex === activeIndex) {
|
||||
this.startFlag = false
|
||||
clearTimeout(this.timer)
|
||||
return this.$emit('onEnd', this.formateList[activeIndex])
|
||||
}
|
||||
time -= interval
|
||||
if (time < 3000 && this.isIntervalIncrease) {
|
||||
// 调整动画速度
|
||||
interval = interval >= this.maxInterval ? this.maxInterval : interval + 20
|
||||
}
|
||||
this.currIndex = this.currIndex >= len - 1 ? 0 : this.currIndex + 1
|
||||
this.transform = this.place(this.currIndex)
|
||||
return startRotate()
|
||||
}, interval)
|
||||
}
|
||||
startRotate()
|
||||
},
|
||||
onStart() {
|
||||
this.$emit('onStart')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.grid-lottery {
|
||||
position: relative;
|
||||
.start-button {
|
||||
position: absolute;
|
||||
}
|
||||
.lottery-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.lottery-item {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,19 +1,146 @@
|
||||
<script setup lang="ts">
|
||||
import NavBar from '@/components/NavBar.vue'
|
||||
</script>
|
||||
|
||||
<route lang="json5">
|
||||
{
|
||||
style: {
|
||||
navigationBarTitleText: '幸运大转盘',
|
||||
navigationBarTitleText: '转盘抽奖',
|
||||
navigationBarBackgroundColor: '#fff',
|
||||
navigationStyle: 'custom',
|
||||
},
|
||||
}
|
||||
</route>
|
||||
|
||||
<script setup lang="ts">
|
||||
import NavBar from '@/components/NavBar.vue'
|
||||
import GridLottery from '@/components/GridLottery.vue'
|
||||
|
||||
import lotteryIcon from '@/static/images/home/nav-2.png'
|
||||
|
||||
const list = [
|
||||
{
|
||||
id: 1,
|
||||
sort: 0,
|
||||
title: '\u6BDB\u5DFE',
|
||||
icon: lotteryIcon,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
sort: 1,
|
||||
title: '\u6BDB\u5DFE',
|
||||
icon: lotteryIcon,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
sort: 2,
|
||||
title: '\u6BDB\u5DFE',
|
||||
icon: lotteryIcon,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
sort: 3,
|
||||
title: '\u6BDB\u5DFE',
|
||||
icon: lotteryIcon,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
sort: 4,
|
||||
title: '\u6BDB\u5DFE',
|
||||
icon: lotteryIcon,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
sort: 5,
|
||||
title: '\u6BDB\u5DFE',
|
||||
icon: lotteryIcon,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
sort: 6,
|
||||
title: '\u6BDB\u5DFE',
|
||||
icon: lotteryIcon,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
sort: 7,
|
||||
title: '\u6BDB\u5DFE',
|
||||
icon: lotteryIcon,
|
||||
},
|
||||
]
|
||||
|
||||
const gridLotteryRef = ref(null)
|
||||
const onStart = () => {
|
||||
// 中奖id,抽奖轮转时间毫秒
|
||||
gridLotteryRef.value.start(3, 10000)
|
||||
}
|
||||
const onEnd = () => {
|
||||
console.log('onEnd')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="min-h-screen">
|
||||
<view class="min-h-screen lottery-page">
|
||||
<NavBar />
|
||||
<view class="mt-240 w-315 h-315 flex items-center justify-center mx-auto lottery-container">
|
||||
<grid-lottery
|
||||
:itemHeight="186"
|
||||
ref="gridLotteryRef"
|
||||
class="w-280 ml-8 mt-8"
|
||||
:list="list"
|
||||
@onStart="onStart"
|
||||
@onEnd="onEnd"
|
||||
>
|
||||
<!-- <view slot="lottery-item" slot-scope="slotProps">{{ slotProps }}</view> -->
|
||||
<template #lottery-item="{ data, index, currIndex }">
|
||||
<view
|
||||
class="overflow-hidden relative lottery-item flex flex-col items-center justify-center rounded-10 bg-[linear-gradient(180deg,#fffdf7,#fff1ca)] w-86 h-86"
|
||||
:class="{
|
||||
mask: currIndex !== index,
|
||||
}"
|
||||
>
|
||||
<image :src="data.icon" class="w-30 h-30" />
|
||||
<view class="text-14 text-#333 mt-8">{{ data.title }}</view>
|
||||
</view>
|
||||
</template>
|
||||
<template #start-button>
|
||||
<view
|
||||
class="w-86 flex flex-col items-center justify-center h-86 bg-[linear-gradient(180deg,#FF8282,#D73434)] text-#FBEDC6 text-25 rounded-10"
|
||||
>
|
||||
<view>点击</view>
|
||||
<view>抽奖</view>
|
||||
</view>
|
||||
</template>
|
||||
<template #activity-box>
|
||||
<view class="w-86 h-86 bg-red-500"></view>
|
||||
</template>
|
||||
</grid-lottery>
|
||||
</view>
|
||||
<view class="text-16 mx-auto w-315 mb-15 font-bold text-#fff mt-30">抽奖规则</view>
|
||||
<view class="text-12 mx-auto w-315 mb-15 text-#fff mt-15">
|
||||
1. 每轮抽奖消耗10000认购点,每轮抽奖次数为3次,每轮抽奖结束后,消耗的认购点将恢复为0。
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<style>
|
||||
.lottery-item {
|
||||
&.mask {
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
content: '';
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.lottery-container {
|
||||
background-image: url('@/static/images/lottery-bar.png');
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.lottery-page {
|
||||
background-color: #517aae;
|
||||
background-image: url('@/static/images/lottery-bg.png');
|
||||
background-repeat: no-repeat;
|
||||
background-position: top;
|
||||
background-size: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
+1
-1
@@ -183,7 +183,7 @@
|
||||
"path": "lottery/index",
|
||||
"type": "page",
|
||||
"style": {
|
||||
"navigationBarTitleText": "幸运大转盘",
|
||||
"navigationBarTitleText": "转盘抽奖",
|
||||
"navigationBarBackgroundColor": "#fff",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 412 KiB |
Reference in New Issue
Block a user