feat(新页面): 抽奖活动页
BIN
src/assets/images/Lottery/backGift.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
src/assets/images/Lottery/bg.png
Normal file
|
After Width: | Height: | Size: 5.1 MiB |
BIN
src/assets/images/Lottery/cashBt.png
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
src/assets/images/Lottery/cashBtActive.png
Normal file
|
After Width: | Height: | Size: 150 KiB |
BIN
src/assets/images/Lottery/done.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
src/assets/images/Lottery/gift.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
src/assets/images/Lottery/giftLeft.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
src/assets/images/Lottery/giftRight.png
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
src/assets/images/Lottery/goToTask.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
src/assets/images/Lottery/invite.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
src/assets/images/Lottery/lotteryBt.png
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
src/assets/images/Lottery/lotteryBtActive.png
Normal file
|
After Width: | Height: | Size: 149 KiB |
BIN
src/assets/images/Lottery/nextGift.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
src/assets/images/Lottery/pageTitle.png
Normal file
|
After Width: | Height: | Size: 444 KiB |
BIN
src/assets/images/Lottery/rankingBt.png
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
src/assets/images/Lottery/rankingBtActive.png
Normal file
|
After Width: | Height: | Size: 150 KiB |
BIN
src/assets/images/Lottery/receive.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
src/assets/images/Lottery/rewardBg.png
Normal file
|
After Width: | Height: | Size: 763 KiB |
BIN
src/assets/images/Lottery/rewardConfirm.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
src/assets/images/Lottery/spin1.png
Normal file
|
After Width: | Height: | Size: 177 KiB |
BIN
src/assets/images/Lottery/spin10.png
Normal file
|
After Width: | Height: | Size: 172 KiB |
BIN
src/assets/images/Lottery/talking.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
src/assets/images/Lottery/ticket.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
src/assets/images/Lottery/turnTable.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
@ -245,6 +245,12 @@ const router = createRouter({
|
||||
component: () => import('../views/Invitation/InvitationToRegister.vue'),
|
||||
meta: { requiresAuth: true },
|
||||
},
|
||||
{
|
||||
path: '/lottery',
|
||||
name: 'lottery',
|
||||
component: () => import('../views/Activities/Lottery/Lottery.vue'),
|
||||
meta: { requiresAuth: true },
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
|
||||
@ -119,6 +119,7 @@ export const ROLE_PERMISSIONS = {
|
||||
'/halloween', //万圣节活动页面
|
||||
'/recharge-agency-recruit', //充值代理介绍页面
|
||||
'/invitation-to-register', //邀请新用户注册页面
|
||||
'/lottery', // 抽奖活动页面
|
||||
],
|
||||
|
||||
// 加载页面
|
||||
|
||||
@ -410,6 +410,7 @@ class RouteGuard {
|
||||
'/halloween', //万圣节活动页面
|
||||
'/recharge-agency-recruit', //充值代理介绍页面
|
||||
'/invitation-to-register', //邀请新用户注册页面
|
||||
'/lottery', // 抽奖活动页面
|
||||
]
|
||||
return publicPages.includes(path)
|
||||
}
|
||||
|
||||
946
src/views/Activities/Lottery/Lottery.vue
Normal file
@ -0,0 +1,946 @@
|
||||
<template>
|
||||
<div class="fullPage">
|
||||
<!-- 状态栏占位区域(仅在APP中显示) -->
|
||||
<div v-if="isInAppEnvironment" style="height: 30px"></div>
|
||||
<div style="padding: 10px 10px 10px">
|
||||
<!-- 页面标题 -->
|
||||
<img :src="images.pageTitle" alt="" width="100%" style="display: block" />
|
||||
|
||||
<!-- 弹幕 -->
|
||||
<div></div>
|
||||
|
||||
<!-- 模块切换按钮 -->
|
||||
<div style="display: flex; justify-content: space-around">
|
||||
<div style="width: 30%" @click="handleBt('Rank')">
|
||||
<img :src="rankShow ? images.rankingBtActive : images.rankingBt" alt="" width="100%" />
|
||||
</div>
|
||||
<div style="width: 30%" @click="handleBt('Cash')">
|
||||
<img :src="cashShow ? images.cashBtActive : images.cashBt" alt="" width="100%" />
|
||||
</div>
|
||||
<div style="width: 30%" @click="handleBt('Lottery')">
|
||||
<img :src="lotteryShow ? images.lotteryBtActive : images.lotteryBt" alt="" width="100%" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 排行榜模块 -->
|
||||
<div
|
||||
v-if="rankShow"
|
||||
style="
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
|
||||
backdrop-filter: blur(32px);
|
||||
|
||||
display: flex;
|
||||
padding: 12px;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
margin-bottom: 18vw;
|
||||
"
|
||||
>
|
||||
<div style="font-weight: 590">Ranking</div>
|
||||
<div
|
||||
v-for="value in 10"
|
||||
style="
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
backdrop-filter: blur(32px);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px;
|
||||
"
|
||||
>
|
||||
<div style="display: flex; align-items: center; gap: 4px">
|
||||
<div style="font-weight: 700">999</div>
|
||||
<img
|
||||
:src="''"
|
||||
alt=""
|
||||
width="15%"
|
||||
style="border-radius: 50%; aspect-ratio: 1/1; object-fit: cover"
|
||||
@error="defaultAvatarUrl"
|
||||
/>
|
||||
<div style="width: 70%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis">
|
||||
asdfadsfasfasfda
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 4px">
|
||||
<img src="/src/assets/icon/dollar.png" alt="" width="10vw" />
|
||||
<div style="color: #2df860; font-weight: 500">99999</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 提现模块 -->
|
||||
<div v-if="cashShow" style="width: 100%; display: flex; flex-direction: column; gap: 3vw">
|
||||
<!-- 个人信息 -->
|
||||
<div
|
||||
style="
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
backdrop-filter: blur(32px);
|
||||
|
||||
padding: 12px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
"
|
||||
>
|
||||
<img
|
||||
:src="''"
|
||||
alt=""
|
||||
width="15%"
|
||||
style="border-radius: 50%; aspect-ratio: 1/1; object-fit: cover"
|
||||
@error="defaultAvatarUrl"
|
||||
/>
|
||||
<div
|
||||
style="
|
||||
width: 85%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
gap: 4px;
|
||||
"
|
||||
>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center">
|
||||
<div
|
||||
style="
|
||||
max-width: 40%;
|
||||
font-weight: 500;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
"
|
||||
>
|
||||
Nanfangjianasdfasdfasdfasdf
|
||||
</div>
|
||||
<div style="font-weight: 600">Current amount:$1</div>
|
||||
</div>
|
||||
<div style="text-align: end; font-weight: 400; font-size: 0.8em">
|
||||
Only $9 left to withdraw $10.00
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 标题 -->
|
||||
<div
|
||||
style="
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
backdrop-filter: blur(32px);
|
||||
padding: 12px;
|
||||
font-weight: 600;
|
||||
"
|
||||
>
|
||||
Transfer to others
|
||||
</div>
|
||||
|
||||
<!-- 转账功能 -->
|
||||
<div
|
||||
style="
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
|
||||
backdrop-filter: blur(32px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
padding: 12px;
|
||||
"
|
||||
>
|
||||
<!-- 转账对象 -->
|
||||
<div
|
||||
style="
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
|
||||
backdrop-filter: blur(32px);
|
||||
padding: 12px;
|
||||
"
|
||||
>
|
||||
<!-- 基本信息 -->
|
||||
<div style="display: flex; align-items: center">
|
||||
<!-- 头像 -->
|
||||
<div style="position: relative; width: 50px; margin-right: 12px">
|
||||
<img
|
||||
:src="selectedPayee.avatar || ''"
|
||||
:alt="selectedPayee.name"
|
||||
style="width: 100%; object-fit: cover; border-radius: 50%"
|
||||
@error="defaultAvatarUrl"
|
||||
/>
|
||||
</div>
|
||||
<!-- 个人信息 -->
|
||||
<div style="flex: 1">
|
||||
<div style="margin: 0 0 4px 0; font-weight: 700">
|
||||
{{ selectedPayee.name || '' }}
|
||||
</div>
|
||||
<div style="margin: 0; font-size: 0.9em; font-weight: 500">
|
||||
ID: {{ selectedPayee.account || '' }}
|
||||
</div>
|
||||
</div>
|
||||
<!-- 换人按钮 -->
|
||||
<button
|
||||
style="
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(
|
||||
152deg,
|
||||
rgba(198, 112, 255, 0.6) 7.01%,
|
||||
rgba(119, 38, 255, 0.6) 92.99%
|
||||
);
|
||||
border: none;
|
||||
font-weight: 500;
|
||||
padding: 2px 8px;
|
||||
"
|
||||
@click="searchPayee"
|
||||
>
|
||||
Change
|
||||
</button>
|
||||
</div>
|
||||
<!-- 身份图标 -->
|
||||
<div style="margin-left: 50px; display: flex; gap: 5px">
|
||||
<img v-if="selectedPayee.isHost" src="/src/assets/icon/host.png" alt="" width="30%" />
|
||||
<img
|
||||
v-if="selectedPayee.isAgency"
|
||||
src="/src/assets/icon/agency.png"
|
||||
alt=""
|
||||
width="30%"
|
||||
style="display: block"
|
||||
/>
|
||||
<img
|
||||
v-if="selectedPayee.hasSalary"
|
||||
src="/src/assets/icon/RA.png"
|
||||
alt=""
|
||||
width="30%"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 空状态 - 默认显示 -->
|
||||
<div style="display: flex; justify-content: center; align-items: center">
|
||||
<div
|
||||
style="
|
||||
font-weight: 590;
|
||||
padding: 16px;
|
||||
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
|
||||
backdrop-filter: blur(32px);
|
||||
"
|
||||
@click="searchPayee"
|
||||
>
|
||||
Search
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 转账金额选择 -->
|
||||
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px">
|
||||
<div
|
||||
v-for="coin in coinOptions"
|
||||
:key="coin.id"
|
||||
@click="selectCoin(coin)"
|
||||
:class="['coin-item', { selected: selectedCoin === coin.id }]"
|
||||
>
|
||||
<img src="/src/assets/icon/dollar.png" alt="" style="width: 40%" />
|
||||
<div style="font-weight: 500; color: #131111">${{ coin.price }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 转账按钮 -->
|
||||
<div style="display: flex; justify-content: center; align-items: center">
|
||||
<div
|
||||
style="
|
||||
width: 70%;
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 32px;
|
||||
background: linear-gradient(135deg, #bb92ff 2.82%, #8b45ff 99.15%);
|
||||
font-weight: 590;
|
||||
"
|
||||
@click="transfer"
|
||||
:disabled="!selectedCoin || !selectedPayee.value?.id"
|
||||
>
|
||||
Transfer
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 抽奖模块 -->
|
||||
<div v-if="lotteryShow" style="width: 100%; display: flex; flex-direction: column; gap: 3vw">
|
||||
<!-- 抽奖转盘 -->
|
||||
<div style="position: relative">
|
||||
<img :src="images.turnTable" alt="" width="100%" style="display: block" />
|
||||
<div
|
||||
style="
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
margin: 11% 0 10.5%;
|
||||
padding: 0 8%;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-template-rows: repeat(3, 1fr);
|
||||
gap: 4.5%;
|
||||
"
|
||||
>
|
||||
<div
|
||||
v-for="(prize, index) in prizes"
|
||||
style="
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
border-width: 2px;
|
||||
border-style: solid;
|
||||
"
|
||||
:style="[
|
||||
getGridPosition(index),
|
||||
{ borderColor: activeIndex === index ? '#00ffa3' : 'transparent' },
|
||||
]"
|
||||
:class="{ 'active-prize': activeIndex === index }"
|
||||
>
|
||||
<img src="/src/assets/icon/coinMore.png" alt="" width="50%" style="display: block" />
|
||||
<div>{{ prize.value }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 按钮 -->
|
||||
<div
|
||||
style="grid-area: 2 / 2; display: flex; justify-content: center; align-items: center"
|
||||
:disabled="isRolling"
|
||||
@click="sweepstakes(1)"
|
||||
></div>
|
||||
</div>
|
||||
<!-- 底部饰品 -->
|
||||
<div
|
||||
style="
|
||||
position: absolute;
|
||||
bottom: -2vw;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
"
|
||||
>
|
||||
<img
|
||||
:src="images.giftLeft"
|
||||
alt=""
|
||||
width="20%"
|
||||
style="display: block; margin-left: -10px"
|
||||
/>
|
||||
<img
|
||||
:src="images.giftRight"
|
||||
alt=""
|
||||
width="20%"
|
||||
style="display: block; margin-right: -10px"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 抽奖按钮 -->
|
||||
<div style="display: flex; justify-content: space-around">
|
||||
<img
|
||||
:src="images.spin1"
|
||||
alt=""
|
||||
width="40%"
|
||||
@click="sweepstakes(1)"
|
||||
style="display: block"
|
||||
/>
|
||||
<img
|
||||
:src="images.spin10"
|
||||
alt=""
|
||||
width="40%"
|
||||
@click="sweepstakes(10)"
|
||||
style="display: block"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 抽奖次数 -->
|
||||
<div
|
||||
style="
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
|
||||
backdrop-filter: blur(32px);
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
"
|
||||
>
|
||||
<div style="font-weight: 590">Current raffle tickets:{{ rollTimes }}</div>
|
||||
<div style="font-weight: 590; font-size: 0.9em">History</div>
|
||||
</div>
|
||||
|
||||
<!-- 任务列表 -->
|
||||
<div
|
||||
style="
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
|
||||
backdrop-filter: blur(32px);
|
||||
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
"
|
||||
>
|
||||
<div style="font-weight: 590">Task for Spins</div>
|
||||
<div
|
||||
v-for="task in taskList"
|
||||
style="
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 0 4px 0 rgba(1, 255, 39, 0.25);
|
||||
backdrop-filter: blur(32px);
|
||||
display: flex;
|
||||
padding: 8px;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
"
|
||||
>
|
||||
<!-- 图标 -->
|
||||
<div style="width: 20%">
|
||||
<img
|
||||
v-if="task.type === 'talk'"
|
||||
:src="images.talking"
|
||||
alt=""
|
||||
width="100%"
|
||||
style="display: block"
|
||||
/>
|
||||
<img
|
||||
v-if="task.type === 'gift'"
|
||||
:src="images.gift"
|
||||
alt=""
|
||||
width="100%"
|
||||
style="display: block"
|
||||
/>
|
||||
<img
|
||||
v-if="task.type === 'invite'"
|
||||
:src="images.invite"
|
||||
alt=""
|
||||
width="100%"
|
||||
style="display: block"
|
||||
/>
|
||||
</div>
|
||||
<!-- 内容 -->
|
||||
<div style="width: 60%">
|
||||
<div style="color: rgba(0, 0, 0, 0.8); font-weight: 590">{{ task.title }}</div>
|
||||
<div style="display: flex; align-items: center; gap: 8px">
|
||||
<img :src="images.ticket" alt="" width="15%" style="display: block" />
|
||||
<div style="color: #2f0; font-weight: 590">*1</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 按钮 -->
|
||||
<div style="width: 20%">
|
||||
<img
|
||||
:src="images.goToTask"
|
||||
alt=""
|
||||
width="100%"
|
||||
style="display: block"
|
||||
v-if="task.done === 0"
|
||||
/>
|
||||
<img
|
||||
:src="images.receive"
|
||||
alt=""
|
||||
width="100%"
|
||||
style="display: block"
|
||||
v-else-if="task.received === 0"
|
||||
/>
|
||||
<img :src="images.done" alt="" width="100%" style="display: block" v-else />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 我的排名 -->
|
||||
<div
|
||||
v-if="rankShow"
|
||||
style="
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 999;
|
||||
width: 100vw;
|
||||
padding: 12px;
|
||||
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
border-radius: 12px 12px 0 0;
|
||||
border-top: 1px solid #77ff87;
|
||||
border-right: 1px solid #77ff87;
|
||||
border-left: 1px solid #77ff87;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
backdrop-filter: blur(32px);
|
||||
"
|
||||
>
|
||||
<div style="display: flex; align-items: center; gap: 4px">
|
||||
<div style="font-weight: 700">999</div>
|
||||
<img
|
||||
:src="''"
|
||||
alt=""
|
||||
width="15%"
|
||||
style="border-radius: 50%; aspect-ratio: 1/1; object-fit: cover"
|
||||
@error="defaultAvatarUrl"
|
||||
/>
|
||||
<div style="width: 70%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis">
|
||||
asdfadsfasfasfda
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 4px">
|
||||
<img src="/src/assets/icon/dollar.png" alt="" width="10vw" />
|
||||
<div style="color: #2df860; font-weight: 500">99999</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 弹窗遮罩层 -->
|
||||
<maskLayer :maskLayerShow="maskLayerShow" @click="closedPopup">
|
||||
<div
|
||||
style="
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
"
|
||||
@click.stop
|
||||
>
|
||||
<div style="position: relative; width: 90%">
|
||||
<img :src="images.rewardBg" alt="" width="100%" style="display: block" />
|
||||
<div
|
||||
style="
|
||||
position: absolute;
|
||||
inset: 23% 10% 10%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
"
|
||||
>
|
||||
<div
|
||||
style="width: 100%; display: flex; justify-content: space-around; align-items: center"
|
||||
>
|
||||
<!-- 上一个奖品 -->
|
||||
<div style="width: 8%">
|
||||
<img
|
||||
v-if="result.length > 1 && resultShowIndex > 0"
|
||||
:src="images.backGift"
|
||||
alt=""
|
||||
width="100%"
|
||||
style="display: block; object-fit: cover"
|
||||
@click="resultShowIndex--"
|
||||
/>
|
||||
</div>
|
||||
<!-- 奖品 -->
|
||||
<img src="/src/assets/icon/coinMore.png" alt="" width="50%" style="display: block" />
|
||||
<!-- 下一个奖品 -->
|
||||
<div style="width: 8%">
|
||||
<img
|
||||
v-if="result.length > 1 && resultShowIndex + 1 < result.length"
|
||||
:src="images.nextGift"
|
||||
alt=""
|
||||
width="100%"
|
||||
style="display: block; object-fit: cover"
|
||||
@click="resultShowIndex++"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style="
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 1.2em;
|
||||
font-weight: 590;
|
||||
background: linear-gradient(0deg, #f3b700 0%, #ffeec6 100%);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
position: relative;
|
||||
"
|
||||
>
|
||||
You Get {{ result[resultShowIndex]?.value }}
|
||||
<div
|
||||
v-if="result.length > 1"
|
||||
style="
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
inset: 0;
|
||||
|
||||
padding-right: 10%;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
|
||||
font-weight: 590;
|
||||
background: linear-gradient(0deg, #f3b700 0%, #ffeec6 100%);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
"
|
||||
>
|
||||
{{ resultShowIndex + 1 }} / {{ result.length }}
|
||||
</div>
|
||||
</div>
|
||||
<img
|
||||
:src="images.rewardConfirm"
|
||||
alt=""
|
||||
width="40%"
|
||||
@click="closedPopup"
|
||||
style="display: block"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</maskLayer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
connectApplication,
|
||||
parseAccessOrigin,
|
||||
parseHeader,
|
||||
setHttpHeaders,
|
||||
isInApp,
|
||||
} from '@/utils/appBridge.js'
|
||||
import {
|
||||
appConnectionManager,
|
||||
isAppConnected,
|
||||
getAppHeaderInfo,
|
||||
} from '@/utils/appConnectionManager.js'
|
||||
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
|
||||
import GeneralHeader from '@/components/GeneralHeader.vue'
|
||||
import itemCenter from '@/components/WeeklyStar/itemCenter.vue'
|
||||
import TopUser from '@/components/WeeklyStar/topUser.vue'
|
||||
import maskLayer from '@/components/MaskLayer.vue'
|
||||
import { useDebounce, useThrottle } from '@/utils/useDebounce'
|
||||
import { getMemberProfile } from '@/api/wallet'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
// vite动态导入图片
|
||||
const imageModules = import.meta.glob('@/assets/images/Lottery/*.{jpg,png,svg}', {
|
||||
eager: true,
|
||||
})
|
||||
// 生成文件名映射对象(自动移除路径和扩展名)
|
||||
const images = Object.fromEntries(
|
||||
Object.entries(imageModules).map(([path, module]) => {
|
||||
const fileName = path.split('/').pop().split('.')[0]
|
||||
return [fileName, module.default]
|
||||
})
|
||||
)
|
||||
|
||||
// 奖品数据 (8个位置)
|
||||
const prizes = ref([
|
||||
{ value: '奖品1' },
|
||||
{ value: '奖品2' },
|
||||
{ value: '奖品3' },
|
||||
{ value: '奖品4' },
|
||||
{ value: '奖品5' },
|
||||
{ value: '奖品6' },
|
||||
{ value: '奖品7' },
|
||||
{ value: '奖品8' },
|
||||
])
|
||||
|
||||
const activeIndex = ref(-1) // 当前高亮格子
|
||||
const isRolling = ref(false) // 抽奖状态
|
||||
const rollTimes = ref(11) // 当前可抽奖次数
|
||||
const result = ref([]) // 抽奖结果
|
||||
const resultShowIndex = ref(0)
|
||||
|
||||
const isInAppEnvironment = ref(false) // 检测是否在APP环境中
|
||||
const maskLayerShow = ref(false)
|
||||
const rankShow = ref(true)
|
||||
const cashShow = ref(false)
|
||||
const lotteryShow = ref(false)
|
||||
|
||||
const selectedCoin = ref(null)
|
||||
|
||||
// 点击展示主体内容
|
||||
const handleBt = (type) => {
|
||||
rankShow.value = type == 'Rank' ? true : false
|
||||
cashShow.value = type == 'Cash' ? true : false
|
||||
lotteryShow.value = type == 'Lottery' ? true : false
|
||||
}
|
||||
|
||||
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 },
|
||||
{ type: 'talk', title: 'On the mic(0/2hours)', done: 0, received: 0, num: 1 },
|
||||
{ type: 'gift', title: 'Send a gift', done: 1, received: 1, num: 1 },
|
||||
{ type: 'gift', title: 'Send three gifts', done: 0, received: 0, num: 1 },
|
||||
{ type: 'gift', title: 'Send ten gifts', done: 0, received: 0, num: 1 },
|
||||
{ type: 'gift', title: 'Send fifteen gifts', done: 0, received: 0, num: 1 },
|
||||
{ type: 'invite', title: 'Invite a user', done: 1, received: 1, num: 1 },
|
||||
{ type: 'invite', title: 'Invite three users', done: 0, received: 0, num: 1 },
|
||||
])
|
||||
|
||||
// 选中的收款人
|
||||
const selectedPayee = ref({
|
||||
id: null,
|
||||
account: '3232131',
|
||||
name: 'asdfasdfasdfas',
|
||||
avatar: '',
|
||||
type: '',
|
||||
isHost: true,
|
||||
isAgency: true,
|
||||
hasSalary: true,
|
||||
})
|
||||
|
||||
const searchPayee = () => {
|
||||
router.push('/search-payee')
|
||||
}
|
||||
|
||||
// 转账金币选项
|
||||
const coinOptions = ref([
|
||||
{ id: 1, amount: 10500, price: 1 },
|
||||
{ id: 2, amount: 52500, price: 5 },
|
||||
{ id: 3, amount: 105000, price: 10 },
|
||||
])
|
||||
|
||||
//选择金币
|
||||
const selectCoin = (coin) => {
|
||||
// 单选逻辑:如果已经选中相同的金币,则取消选择;否则选中新的金币
|
||||
if (selectedCoin.value === coin.id) {
|
||||
selectedCoin.value = null
|
||||
} else {
|
||||
selectedCoin.value = coin.id
|
||||
}
|
||||
}
|
||||
|
||||
const transfer = async () => {
|
||||
if (!selectedCoin.value) {
|
||||
showError('Please select an amount first')
|
||||
return
|
||||
}
|
||||
|
||||
if (!selectedPayee.value?.id) {
|
||||
showError('Please select a payee first')
|
||||
return
|
||||
}
|
||||
|
||||
const selectedCoinData = coinOptions.find((coin) => coin.id === selectedCoin.value)
|
||||
|
||||
// 获取支付密码
|
||||
// const password = prompt('Please enter your payment password:')
|
||||
// if (!password) {
|
||||
// showError('Payment password is required')
|
||||
// return
|
||||
// }
|
||||
|
||||
// 构造请求参数
|
||||
const transferData = {
|
||||
amount: selectedCoinData.price,
|
||||
acceptUserId: selectedPayee.value?.id,
|
||||
acceptMethod: 'BANK_TRANSFER',
|
||||
// password: password
|
||||
}
|
||||
|
||||
try {
|
||||
// 调用转账接口
|
||||
const response = await userBankTransfer(transferData)
|
||||
if (response.status) {
|
||||
showSuccess(
|
||||
`Successfully transferred $${selectedCoinData.price} to ${selectedPayee.value?.name}`
|
||||
)
|
||||
} else {
|
||||
showError(`Failed to transfer $${selectedCoinData.price}`)
|
||||
}
|
||||
|
||||
// 重置选择
|
||||
selectedCoin.value = null
|
||||
|
||||
// 刷新银行余额
|
||||
await fetchBankBalance()
|
||||
} catch (error) {
|
||||
// 错误处理
|
||||
console.error('Transfer failed:', error)
|
||||
|
||||
if (error.errorCode === 5000) {
|
||||
showError('Insufficient balance')
|
||||
} else if (error.errorCode === 5010 || error.errorCode === 5009) {
|
||||
showError('Payment password error')
|
||||
} else {
|
||||
showError('Transfer failed, please try again later')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const closedPopup = () => {
|
||||
maskLayerShow.value = false
|
||||
result.value = []
|
||||
resultShowIndex.value = 0
|
||||
}
|
||||
|
||||
const defaultAvatarUrl = (e) => {
|
||||
console.log('头像资源出错')
|
||||
e.target.onerror = null //防止循环
|
||||
e.target.src = new URL('/src/assets/images/WeeklyStar/defaultAvatar.png', import.meta.url).href
|
||||
}
|
||||
|
||||
const getGridPosition = (index) => {
|
||||
//顺时针位置
|
||||
const positions = [
|
||||
{ gridArea: '1/1' }, //上左
|
||||
{ gridArea: '1/2' }, //上中
|
||||
{ gridArea: '1/3' }, //上右
|
||||
{ gridArea: '2/3' }, //中右
|
||||
{ gridArea: '3/3' }, //下右
|
||||
{ gridArea: '3/2' }, //下中
|
||||
{ gridArea: '3/1' }, //下左
|
||||
{ gridArea: '2/1' }, //中左
|
||||
]
|
||||
return positions[index]
|
||||
}
|
||||
|
||||
// 抽奖
|
||||
const startLottery = (resultIndex) => {
|
||||
return new Promise((resolve) => {
|
||||
if (isRolling.value) return // 防止重复点击
|
||||
isRolling.value = true
|
||||
activeIndex.value = -1
|
||||
|
||||
let speed = 200 // 初始速度
|
||||
let currentCycle = 0 // 当前圈数
|
||||
let constantSpeedCycle = 0 // 当前匀速圈数
|
||||
let totalCycles = 1 // 至少旋转2圈数
|
||||
|
||||
const roll = () => {
|
||||
activeIndex.value = (activeIndex.value + 1) % prizes.value.length
|
||||
|
||||
if (activeIndex.value === resultIndex && speed > 200) {
|
||||
isRolling.value = false
|
||||
|
||||
setTimeout(() => {
|
||||
resolve() // 抽奖结束
|
||||
}, 500)
|
||||
} else {
|
||||
if (activeIndex.value === prizes.value.length - 1) {
|
||||
currentCycle++
|
||||
}
|
||||
// 加速旋转
|
||||
if (currentCycle < totalCycles) {
|
||||
speed -= 20
|
||||
} else {
|
||||
// 匀速旋转
|
||||
if (activeIndex.value === prizes.value.length - 1) {
|
||||
constantSpeedCycle++
|
||||
}
|
||||
if (constantSpeedCycle > 2) {
|
||||
// 最后减速效果
|
||||
speed += 20
|
||||
}
|
||||
}
|
||||
setTimeout(roll, speed)
|
||||
}
|
||||
}
|
||||
|
||||
roll()
|
||||
})
|
||||
}
|
||||
|
||||
// 连抽
|
||||
const sweepstakes = async (consecutive) => {
|
||||
// 检查抽奖次数
|
||||
if (rollTimes.value >= consecutive) {
|
||||
// 抽奖次数
|
||||
for (let i = 0; i < consecutive; i++) {
|
||||
const item = { value: `奖品${Math.floor(Math.random() * 8) + 1}` } //接口获取的抽奖结果
|
||||
const index = prizes.value.findIndex((prizes) => prizes.value === item.value) //转盘第几位停下
|
||||
console.log('index:', index)
|
||||
await startLottery(index)
|
||||
result.value.push(item)
|
||||
}
|
||||
rollTimes.value -= consecutive
|
||||
maskLayerShow.value = true
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
isInAppEnvironment.value = isInApp()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
* {
|
||||
color: #fff;
|
||||
font-family: 'SF Pro Text';
|
||||
}
|
||||
|
||||
.fullPage {
|
||||
width: 100vw;
|
||||
min-height: 100vh;
|
||||
background: #1f5631;
|
||||
background-image: url(@/assets/images/Lottery/bg.png);
|
||||
background-size: 100% auto;
|
||||
background-repeat: no-repeat;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.active-prize {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 51px 80px 0 rgba(56, 253, 182, 0.49), 0 21.307px 33.422px 0 rgba(56, 253, 182, 0.35),
|
||||
0 11.392px 17.869px 0 rgba(56, 253, 182, 0.29), 0 6.386px 10.017px 0 rgba(56, 253, 182, 0.25),
|
||||
0 3.392px 5.32px 0 rgba(56, 253, 182, 0.2), 0 1.411px 2.214px 0 rgba(56, 253, 182, 0.14);
|
||||
}
|
||||
|
||||
/* 金币网格 */
|
||||
|
||||
.coin-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border: 2px solid transparent;
|
||||
|
||||
transition: all 0.2s;
|
||||
aspect-ratio: 1/1;
|
||||
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
|
||||
backdrop-filter: blur(32px);
|
||||
}
|
||||
|
||||
.coin-item.selected {
|
||||
border-color: #8b5cf6;
|
||||
}
|
||||
|
||||
.coin-item:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 360px) {
|
||||
* {
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 360px) {
|
||||
* {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
* {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1024px) {
|
||||
* {
|
||||
font-size: 32px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||