feat(抽奖活动页): 对接接口

This commit is contained in:
hzj 2025-10-22 19:39:28 +08:00
parent edf03650bd
commit caef58fa15
2 changed files with 332 additions and 71 deletions

106
src/api/lottery.js Normal file
View File

@ -0,0 +1,106 @@
import { get, post } from '../utils/http.js'
// 获取排行榜
export const ranklist = async (applicationId) => {
try {
const response = await get(`/activity/lottery/rank-list`)
return response
} catch (error) {
console.error('Failed to fetch get rank list:', error)
console.error('error:' + error.response.errorMsg)
throw error
}
}
// 获取有效活动
export const validActivity = async () => {
try {
const response = await get(`/activity/lottery/valid-activity`)
return response
} catch (error) {
console.error('Failed to fetch get valid activity:', error)
console.error('error:' + error.response.errorMsg)
throw error
}
}
// 获取活动详情
export const activityDetail = async (activityCode) => {
try {
const response = await get(`/activity/lottery/detail/${activityCode}`)
return response
} catch (error) {
console.error('Failed to fetch get activity detail:', error)
console.error('error:' + error.response.errorMsg)
throw error
}
}
// 获取剩余中奖券
export const myTickets = async () => {
try {
const response = await get(`/activity/lottery/my-ticket-count`)
return response
} catch (error) {
console.error('Failed to fetch get my tickets:', error)
console.error('error:' + error.response.errorMsg)
throw error
}
}
// 执行单次抽奖
export const onceDraw = async (data) => {
try {
const response = await post('/activity/lottery/draw', data)
return response
} catch (error) {
console.error('Failed to fetch once draw:', error)
throw error
}
}
// 执行连抽
export const multiDraw = async (data) => {
try {
const response = await post('/activity/lottery/multi-draw', data)
return response
} catch (error) {
console.error('Failed to fetch multiply draw:', error)
throw error
}
}
// 获取中奖记录
export const drawRecords = async () => {
try {
const response = await get(`/activity/lottery/my-records`)
return response
} catch (error) {
console.error('Failed to fetch get draw records:', error)
console.error('error:' + error.response.errorMsg)
throw error
}
}
// 获取任务列表
export const ActTaskList = async () => {
try {
const response = await get(`/spins/task/list`)
return response
} catch (error) {
console.error('Failed to fetch get tickets:', error)
console.error('error:' + error.response.errorMsg)
throw error
}
}
// 领取任务奖励
export const receiveTickets = async (data) => {
try {
const response = await post('/spins/task/receive/reward', data)
return response
} catch (error) {
console.error('Failed to fetch receive reward:', error)
throw error
}
}

View File

@ -43,7 +43,7 @@
> >
<div style="font-weight: 590">Ranking</div> <div style="font-weight: 590">Ranking</div>
<div <div
v-for="value in 10" v-for="user in ranking"
style=" style="
border-radius: 12px; border-radius: 12px;
background: rgba(255, 255, 255, 0.2); background: rgba(255, 255, 255, 0.2);
@ -55,22 +55,26 @@
" "
> >
<div style="display: flex; align-items: center; gap: 4px"> <div style="display: flex; align-items: center; gap: 4px">
<div style="font-weight: 700">999</div> <div style="font-weight: 700">{{ user.rank }}</div>
<img <img
:src="''" :src="user.avatar || ''"
alt="" alt=""
width="15%" width="15%"
style="border-radius: 50%; aspect-ratio: 1/1; object-fit: cover" style="border-radius: 50%; aspect-ratio: 1/1; object-fit: cover"
@error="defaultAvatarUrl" @error="defaultAvatarUrl"
/> />
<div style="width: 70%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis"> <div style="width: 70%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis">
asdfadsfasfasfda {{ user.nickname || '' }}
</div> </div>
</div> </div>
<div style="display: flex; gap: 4px"> <div style="display: flex; gap: 4px">
<img src="/src/assets/icon/dollar.png" alt="" width="10vw" /> <img
<div style="color: #2df860; font-weight: 500">99999</div> src="/src/assets/icon/dollar.png"
alt=""
style="display: block; object-fit: cover; width: 5vw"
/>
<div style="color: #2df860; font-weight: 500">{{ user.totalAmount }}</div>
</div> </div>
</div> </div>
</div> </div>
@ -100,7 +104,7 @@
@click="helpShow = true" @click="helpShow = true"
/> />
<img <img
:src="''" :src="userInfo.userAvatar || ''"
alt="" alt=""
width="15%" width="15%"
style="border-radius: 50%; aspect-ratio: 1/1; object-fit: cover" style="border-radius: 50%; aspect-ratio: 1/1; object-fit: cover"
@ -125,7 +129,7 @@
text-overflow: ellipsis; text-overflow: ellipsis;
" "
> >
Nanfangjianasdfasdfasdfasdf {{ userInfo.userNickname || '' }}
</div> </div>
<div style="font-weight: 600">Current amount:$1</div> <div style="font-weight: 600">Current amount:$1</div>
</div> </div>
@ -152,6 +156,7 @@
<div <div
style="display: flex; justify-content: space-between; align-items: center" style="display: flex; justify-content: space-between; align-items: center"
@click="drawerShowBt('transfer')" @click="drawerShowBt('transfer')"
v-if="userIdentity.anchor"
> >
<div>Transfer To Recharge Agent</div> <div>Transfer To Recharge Agent</div>
<img <img
@ -397,7 +402,7 @@
" "
> >
<div <div
v-for="(prize, index) in prizes" v-for="(prize, index) in activity.prizeList"
style=" style="
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -413,8 +418,8 @@
]" ]"
:class="{ 'active-prize': activeIndex === index }" :class="{ 'active-prize': activeIndex === index }"
> >
<img src="/src/assets/icon/coinMore.png" alt="" width="50%" style="display: block" /> <img :src="prize.prizeImage || ''" alt="" width="50%" style="display: block" />
<div>{{ prize.value }}</div> <div style="font-size: 0.8em">{{ prize.prizeName }}</div>
</div> </div>
<!-- 按钮 --> <!-- 按钮 -->
@ -515,21 +520,21 @@
<!-- 图标 --> <!-- 图标 -->
<div style="width: 20%"> <div style="width: 20%">
<img <img
v-if="task.type === 'talk'" v-if="task.taskType == 1"
:src="images.talking" :src="images.talking"
alt="" alt=""
width="100%" width="100%"
style="display: block" style="display: block"
/> />
<img <img
v-if="task.type === 'gift'" v-if="task.taskType == 2"
:src="images.gift" :src="images.gift"
alt="" alt=""
width="100%" width="100%"
style="display: block" style="display: block"
/> />
<img <img
v-if="task.type === 'invite'" v-if="task.taskType == 3"
:src="images.invite" :src="images.invite"
alt="" alt=""
width="100%" width="100%"
@ -538,28 +543,39 @@
</div> </div>
<!-- 内容 --> <!-- 内容 -->
<div style="width: 60%"> <div style="width: 60%">
<div style="color: rgba(0, 0, 0, 0.8); font-weight: 590">{{ task.title }}</div> <div>
<div v-if="task.taskType == 1" style="color: rgba(0, 0, 0, 0.8); font-weight: 590">
{{ showTarget(task) }}
</div>
<div v-else style="color: rgba(0, 0, 0, 0.8); font-weight: 590">
{{ task.taskName }}
</div>
</div>
<div style="display: flex; align-items: center; gap: 8px"> <div style="display: flex; align-items: center; gap: 8px">
<img :src="images.ticket" alt="" width="15%" style="display: block" /> <img :src="images.ticket" alt="" width="15%" style="display: block" />
<div style="color: #2f0; font-weight: 590">*1</div> <div style="color: #2f0; font-weight: 590">*{{ task.rewardValue }}</div>
</div> </div>
</div> </div>
<!-- 按钮 --> <!-- 按钮 -->
<div style="width: 20%"> <div style="width: 20%">
<!-- 前往任务 -->
<img <img
v-if="task.taskStatus == 0"
:src="images.goToTask" :src="images.goToTask"
alt="" alt=""
width="100%" width="100%"
style="display: block" style="display: block"
v-if="task.done === 0"
/> />
<!-- 领取抽奖券 -->
<img <img
v-else-if="task.taskStatus === 1"
:src="images.receive" :src="images.receive"
alt="" alt=""
width="100%" width="100%"
style="display: block" style="display: block"
v-else-if="task.received === 0" @click="receiveTaskReward(task.taskCode)"
/> />
<!-- 已完成 -->
<img :src="images.done" alt="" width="100%" style="display: block" v-else /> <img :src="images.done" alt="" width="100%" style="display: block" v-else />
</div> </div>
</div> </div>
@ -591,22 +607,26 @@
" "
> >
<div style="display: flex; align-items: center; gap: 4px"> <div style="display: flex; align-items: center; gap: 4px">
<div style="font-weight: 700">999</div> <div style="font-weight: 700">{{ userInfo.rank || 999 }}</div>
<img <img
:src="''" :src="userInfo.userAvatar || ''"
alt="" alt=""
width="15%" width="15%"
style="border-radius: 50%; aspect-ratio: 1/1; object-fit: cover" style="border-radius: 50%; aspect-ratio: 1/1; object-fit: cover"
@error="defaultAvatarUrl" @error="defaultAvatarUrl"
/> />
<div style="width: 70%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis"> <div style="width: 70%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis">
asdfadsfasfasfda {{ userInfo.userNickname || '' }}
</div> </div>
</div> </div>
<div style="display: flex; gap: 4px"> <div style="display: flex; gap: 4px">
<img src="/src/assets/icon/dollar.png" alt="" width="10vw" /> <img
<div style="color: #2df860; font-weight: 500">99999</div> src="/src/assets/icon/dollar.png"
alt=""
style="display: block; object-fit: cover; width: 5vw"
/>
<div style="color: #2df860; font-weight: 500">{{ userInfo.totalAmount || 0 }}</div>
</div> </div>
</div> </div>
@ -650,7 +670,12 @@
/> />
</div> </div>
<!-- 奖品 --> <!-- 奖品 -->
<img src="/src/assets/icon/coinMore.png" alt="" width="50%" style="display: block" /> <img
:src="result[resultShowIndex]?.prize?.prizeImage"
alt=""
width="50%"
style="display: block"
/>
<!-- 下一个奖品 --> <!-- 下一个奖品 -->
<div style="width: 8%"> <div style="width: 8%">
<img <img
@ -677,7 +702,7 @@
position: relative; position: relative;
" "
> >
You Get {{ result[resultShowIndex]?.value }} You Get {{ result[resultShowIndex]?.prize?.prizeName }}
<div <div
v-if="result.length > 1" v-if="result.length > 1"
style=" style="
@ -744,7 +769,7 @@
class="scrollbar" class="scrollbar"
> >
<div <div
v-for="value in 10" v-for="(record, index) in myRecords"
style=" style="
border-radius: 12px; border-radius: 12px;
background: rgba(255, 255, 255, 0.2); background: rgba(255, 255, 255, 0.2);
@ -759,14 +784,17 @@
> >
<div style="display: flex; align-items: center; gap: 4px"> <div style="display: flex; align-items: center; gap: 4px">
<img <img
src="/src/assets/icon/coin.png" :src="record.prize.prizeImage || ''"
alt="" alt=""
style="width: 10vw; object-fit: cover; display: block; aspect-ratio: 1/1" style="width: 10vw; object-fit: cover; display: block; aspect-ratio: 1/1"
/> />
<div style="font-weight: 590; font-size: 0.9em">100000 coins</div> <div style="font-weight: 590; font-size: 0.9em">
<div style="font-weight: 590; font-size: 0.9em">x1</div> {{ record.prize.prizeName }} x1
</div>
</div>
<div style="font-weight: 510; font-size: 0.8em">
{{ formatUTCCustom(record.drawTime) }}
</div> </div>
<div style="font-weight: 510; font-size: 0.8em">2025.08.01 10:59:59</div>
</div> </div>
</div> </div>
</div> </div>
@ -801,8 +829,20 @@ import {
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue' import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
import maskLayer from '@/components/MaskLayer.vue' import maskLayer from '@/components/MaskLayer.vue'
import { useDebounce, useThrottle } from '@/utils/useDebounce' import { useDebounce, useThrottle } from '@/utils/useDebounce'
import { getMemberProfile } from '@/api/wallet' import { formatUTCCustom } from '@/utils/utcFormat.js'
import { getMemberProfile, getUserIdentity } from '@/api/wallet'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import {
ranklist, //
validActivity, //
activityDetail, //
myTickets, //
onceDraw, //
multiDraw, //
drawRecords, //
ActTaskList, //
receiveTickets, //
} from '@/api/lottery'
import Barrage from '@/components/Lottery/Barrage.vue' import Barrage from '@/components/Lottery/Barrage.vue'
const router = useRouter() const router = useRouter()
@ -825,23 +865,23 @@ const barrageList = ref([
{ text: 'Junge withdrew $10', type: 'doller' }, { text: 'Junge withdrew $10', type: 'doller' },
]) ])
//
const activity = ref({})
// (8) // (8)
const prizes = ref([ const prizes = ref([])
{ value: '奖品1' },
{ value: '奖品2' }, const userInfo = ref({}) //
{ value: '奖品3' }, const userIdentity = ref({}) //
{ value: '奖品4' },
{ value: '奖品5' }, const ranking = ref([]) //
{ value: '奖品6' },
{ value: '奖品7' },
{ value: '奖品8' },
])
const activeIndex = ref(-1) // const activeIndex = ref(-1) //
const isRolling = ref(false) // const isRolling = ref(false) //
const rollTimes = ref(11) // const rollTimes = ref(0) //
const result = ref([]) // const result = ref([]) //
const resultShowIndex = ref(0) const resultShowIndex = ref(0)
const myRecords = ref([]) //
const isInAppEnvironment = ref(false) // APP const isInAppEnvironment = ref(false) // APP
@ -882,18 +922,17 @@ const handleBt = (type) => {
selectedCoin.value = null // selectedCoin.value = null //
} }
const taskList = ref([ const taskList = ref([])
{ type: 'talk', title: 'On the mic(0/15mins)', done: 1, received: 1, num: 1 },
{ type: 'talk', title: 'On the mic(0/30mins)', done: 1, received: 0, num: 1 }, //
{ type: 'talk', title: 'On the mic(0/1hours)', done: 0, received: 0, num: 1 }, const showTarget = (task) => {
{ type: 'talk', title: 'On the mic(0/2hours)', done: 0, received: 0, num: 1 }, let timeType = task.targetValue < 60
{ type: 'gift', title: 'Send a gift', done: 1, received: 1, num: 1 }, let currentValue = timeType ? task.currentValue : task.currentValue / 60
{ type: 'gift', title: 'Send three gifts', done: 0, received: 0, num: 1 }, let targetValue = timeType ? task.targetValue : task.targetValue / 60
{ type: 'gift', title: 'Send ten gifts', done: 0, received: 0, num: 1 }, let timeUnit = timeType ? 'mins' : 'hours'
{ type: 'gift', title: 'Send fifteen gifts', done: 0, received: 0, num: 1 },
{ type: 'invite', title: 'Invite a user', done: 1, received: 1, num: 1 }, return `On the mic(${currentValue}/${targetValue}${timeUnit})`
{ type: 'invite', title: 'Invite three users', done: 0, received: 0, num: 1 }, }
])
// //
const selectedPayee = ref({ const selectedPayee = ref({
@ -928,6 +967,7 @@ const selectCoin = (coin) => {
} }
} }
//
const transfer = async () => { const transfer = async () => {
if (!selectedCoin.value) { if (!selectedCoin.value) {
showError('Please select an amount first') showError('Please select an amount first')
@ -986,6 +1026,7 @@ const transfer = async () => {
} }
} }
//
const closedPopup = () => { const closedPopup = () => {
resultShow.value = false resultShow.value = false
helpShow.value = false helpShow.value = false
@ -994,12 +1035,14 @@ const closedPopup = () => {
resultShowIndex.value = 0 resultShowIndex.value = 0
} }
//
const defaultAvatarUrl = (e) => { const defaultAvatarUrl = (e) => {
console.log('头像资源出错') console.log('头像资源出错')
e.target.onerror = null // e.target.onerror = null //
e.target.src = new URL('/src/assets/images/WeeklyStar/defaultAvatar.png', import.meta.url).href e.target.src = new URL('/src/assets/images/WeeklyStar/defaultAvatar.png', import.meta.url).href
} }
//
const getGridPosition = (index) => { const getGridPosition = (index) => {
// //
const positions = [ const positions = [
@ -1015,11 +1058,9 @@ const getGridPosition = (index) => {
return positions[index] return positions[index]
} }
// //
const startLottery = (resultIndex) => { const startLottery = (resultIndex) => {
return new Promise((resolve) => { return new Promise((resolve) => {
if (isRolling.value) return //
isRolling.value = true
activeIndex.value = -1 activeIndex.value = -1
let speed = 200 // let speed = 200 //
@ -1031,8 +1072,6 @@ const startLottery = (resultIndex) => {
activeIndex.value = (activeIndex.value + 1) % prizes.value.length activeIndex.value = (activeIndex.value + 1) % prizes.value.length
if (activeIndex.value === resultIndex && speed > 200) { if (activeIndex.value === resultIndex && speed > 200) {
isRolling.value = false
setTimeout(() => { setTimeout(() => {
resolve() // resolve() //
}, 500) }, 500)
@ -1063,18 +1102,61 @@ const startLottery = (resultIndex) => {
// //
const sweepstakes = async (consecutive) => { const sweepstakes = async (consecutive) => {
if (isRolling.value) return //
// //
if (rollTimes.value >= consecutive) { if (rollTimes.value >= consecutive) {
// isRolling.value = true
for (let i = 0; i < consecutive; i++) { let data = {
const item = { value: `奖品${Math.floor(Math.random() * 8) + 1}` } // activityId: activity.value.activity.id,
const index = prizes.value.findIndex((prizes) => prizes.value === item.value) // drawCount: consecutive,
console.log('index:', index)
await startLottery(index)
result.value.push(item)
} }
rollTimes.value -= consecutive //
if (consecutive == 1) {
const resOnceDraw = await onceDraw(data)
if (resOnceDraw.status && resOnceDraw.body) {
const resItem = resOnceDraw.body //
const index = activity.value.prizeList.findIndex(
(prize) => prize.prizeName == resItem?.prize.prizeName
) //
console.log('index:', index)
await startLottery(index)
result.value.push(resItem)
}
}
//
else {
const resMultiDraw = await multiDraw(data)
if (resMultiDraw.status && resMultiDraw.body) {
const resDrawList = resMultiDraw.body //
for (let i = 0; i < resDrawList.results.length; i++) {
const resItem = resDrawList.results[i]
const index = activity.value.prizeList.findIndex(
(prize) => prize.prizeName == resItem?.prize.prizeName
) //
console.log('index:', index)
await startLottery(index)
result.value.push(resItem)
}
}
}
getTickets() //
resultShow.value = true resultShow.value = true
isRolling.value = false
}
}
//
const getUserInfo = async () => {
if (Object.keys(userInfo.value).length === 0) {
const resUserInfo = await getMemberProfile()
if (resUserInfo.status && resUserInfo.body) {
userInfo.value =
userInfo.value == {} ? resUserInfo.body : Object.assign(userInfo.value, resUserInfo.body)
}
}
const resIdentity = await getUserIdentity()
if (resIdentity.status && resIdentity.body) {
userIdentity.value = resIdentity.body
} }
} }
@ -1093,7 +1175,7 @@ const connectToApp = async () => {
console.groupEnd() console.groupEnd()
// //
// getUserInfo() getUserInfo()
return { success: true, environment: 'browser' } return { success: true, environment: 'browser' }
} }
@ -1113,7 +1195,7 @@ const connectToApp = async () => {
console.groupEnd() console.groupEnd()
// //
// getUserInfo() getUserInfo()
return { success: true, environment: 'app', fromCache: true } return { success: true, environment: 'app', fromCache: true }
} }
@ -1127,7 +1209,7 @@ const connectToApp = async () => {
console.groupEnd() console.groupEnd()
// //
// getUserInfo() getUserInfo()
return { success: true, environment: 'app', fromCache: true } return { success: true, environment: 'app', fromCache: true }
} }
@ -1178,7 +1260,7 @@ const connectToApp = async () => {
console.groupEnd() console.groupEnd()
// //
// getUserInfo() getUserInfo()
return connectionResult return connectionResult
} catch (error) { } catch (error) {
@ -1200,9 +1282,82 @@ const connectToApp = async () => {
} }
} }
//
const getRanking = async () => {
const resRanking = await ranklist()
if (resRanking.status && resRanking.body) {
ranking.value = resRanking.body
//
const myInfo = ranking.value.find((item) => item.account === userInfo.value.account)
if (myInfo) {
userInfo.value = userInfo.value == {} ? myInfo : Object.assign(userInfo.value, myInfo)
}
} else {
ranking.value = {}
}
}
//
const getActivityDetail = async () => {
const resvalidActivity = await validActivity() //
console.log('id:', resvalidActivity.body?.id)
console.log('id2:', JSON.stringify(resvalidActivity.body))
if (resvalidActivity.body?.activityCode) {
const resDetail = await activityDetail(resvalidActivity.body?.activityCode)
if (resDetail.status && resDetail.body) {
activity.value = resDetail.body
} else {
activity.value = {}
}
}
}
//
const getTickets = async () => {
const resTickets = await myTickets()
if (resTickets.status && resTickets.body) {
rollTimes.value = resTickets.body
} else {
rollTimes.value = 0
}
}
//
const getTaskList = async () => {
const resTaskList = await ActTaskList()
if (resTaskList.status && resTaskList.body) {
taskList.value = resTaskList.body
}
}
//
const getDrawRecords = async () => {
const resDrawRecords = await drawRecords()
if (resDrawRecords.status && resDrawRecords.body) {
myRecords.value = resDrawRecords.body?.records || []
}
}
//
const receiveTaskReward = async (code) => {
let data = {
taskCode: code,
}
const resReceive = await receiveTickets(data)
if (resReceive.status && resReceive.body) {
getTaskList() //
}
}
onMounted(() => { onMounted(() => {
connectToApp() connectToApp()
isInAppEnvironment.value = isInApp() isInAppEnvironment.value = isInApp()
getRanking() //
getActivityDetail() //
getDrawRecords() //
getTickets() //
getTaskList() //
}) })
</script> </script>