feat: 添加抽奖

This commit is contained in:
anonymous
2024-12-31 21:46:39 +08:00
parent 5095c16564
commit 0889d068a8
5 changed files with 356 additions and 7 deletions
+222
View File
@@ -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>
+133 -6
View File
@@ -1,19 +1,146 @@
<script setup lang="ts">
import NavBar from '@/components/NavBar.vue'
</script>
<route lang="json5"> <route lang="json5">
{ {
style: { style: {
navigationBarTitleText: '幸运大转盘', navigationBarTitleText: '转盘抽奖',
navigationBarBackgroundColor: '#fff', navigationBarBackgroundColor: '#fff',
navigationStyle: 'custom', navigationStyle: 'custom',
}, },
} }
</route> </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> <template>
<view class="min-h-screen"> <view class="min-h-screen lottery-page">
<NavBar /> <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> </view>
</template> </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
View File
@@ -183,7 +183,7 @@
"path": "lottery/index", "path": "lottery/index",
"type": "page", "type": "page",
"style": { "style": {
"navigationBarTitleText": "幸运大转盘", "navigationBarTitleText": "转盘抽奖",
"navigationBarBackgroundColor": "#fff", "navigationBarBackgroundColor": "#fff",
"navigationStyle": "custom" "navigationStyle": "custom"
} }
Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 KiB