1338 lines
37 KiB
Vue
1338 lines
37 KiB
Vue
<template>
|
||
<div style="display: flex; flex-direction: column; align-items: center">
|
||
<!-- 抽奖游戏 -->
|
||
<itemCenter
|
||
style="min-height: 149.06vw"
|
||
:imgUrl="imageUrl('lotteryBg')"
|
||
:contentStyle="`inset:30vw 6.5vw 13vw 6.5vw;flex-direction: column;justify-content: space-between;`"
|
||
>
|
||
<!-- 中奖历史按钮 -->
|
||
<img
|
||
v-smart-img
|
||
:src="imageUrl('historyBt')"
|
||
alt=""
|
||
style="width: 8vw; position: absolute; top: -28vw; right: -2vw"
|
||
@click="getDrawRecords"
|
||
/>
|
||
|
||
<!-- 中奖历史轮播 -->
|
||
<div
|
||
style="
|
||
position: absolute;
|
||
z-index: 2;
|
||
top: -22vw;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 11vw;
|
||
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
|
||
padding-right: 1vw;
|
||
"
|
||
>
|
||
<div style="width: 33%; min-width: 0; overflow: hidden; position: relative">
|
||
<!-- 滚动容器 -->
|
||
<div
|
||
class="scroll-wrapper"
|
||
ref="scrollWrapper"
|
||
:style="{ animationDuration: `${duration}s` }"
|
||
>
|
||
<!-- 2套内容 -->
|
||
<div class="scroll-content" v-for="value in 2">
|
||
<div
|
||
v-for="(item, index) in luckyUsers"
|
||
:key="index"
|
||
style="align-self: stretch; display: flex; align-items: center; gap: 2vw"
|
||
>
|
||
<div style="font-size: 1.2em; font-weight: 700; color: #fff; white-space: nowrap">
|
||
{{ barrageText(item) }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 抽奖转盘 -->
|
||
<div
|
||
style="
|
||
width: 100%;
|
||
height: 85vw;
|
||
align-self: stretch;
|
||
|
||
padding: 0 5.5vw 0 5.5vw;
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
grid-template-rows: repeat(3, 1fr);
|
||
gap: 0.5vw 1.5vw;
|
||
|
||
direction: ltr;
|
||
"
|
||
>
|
||
<!-- 奖池 -->
|
||
<div
|
||
v-for="(prize, index) in activity.prizeList"
|
||
style="
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
|
||
position: relative;
|
||
"
|
||
:style="[getGridPosition(index)]"
|
||
>
|
||
<div
|
||
style="
|
||
width: 100%;
|
||
flex: 1;
|
||
min-width: 0;
|
||
min-height: 0;
|
||
|
||
padding-top: 6vw;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
"
|
||
>
|
||
<img
|
||
:src="prize.prizeImage || ''"
|
||
:alt="prize.prizeName || ''"
|
||
width="50%"
|
||
style="display: block"
|
||
/>
|
||
</div>
|
||
|
||
<div
|
||
style="
|
||
width: 100%;
|
||
height: 27%;
|
||
min-width: 0;
|
||
min-height: 0;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
"
|
||
>
|
||
<div style="font-size: 0.8em; font-weight: 700; color: #fff">
|
||
{{ prize.prizeName }}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 转到的奖品项 -->
|
||
<img
|
||
v-show="activeIndex === index"
|
||
v-smart-img
|
||
:src="imageUrl('prizeActiveFrame')"
|
||
alt=""
|
||
style="
|
||
display: block;
|
||
width: 112%;
|
||
|
||
position: absolute;
|
||
transform: translate(-50%, -50%);
|
||
top: 50%;
|
||
left: 50%;
|
||
"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 抽奖信息 -->
|
||
<div style="width: 100%; height: 5vw; display: flex; justify-content: space-between">
|
||
<!-- 拥有抽奖券 -->
|
||
<div style="font-weight: 700">{{ $t('remaining_lottery_tickets') }}: {{ tickets }}</div>
|
||
|
||
<!-- 获取抽奖券 -->
|
||
<div style="font-weight: 700" @click="showTaskList">{{ $t('how_to_get_ticket') }}</div>
|
||
</div>
|
||
|
||
<!-- 抽奖按钮 -->
|
||
<div
|
||
style="
|
||
width: 80%;
|
||
height: 11vw;
|
||
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 10vw;
|
||
direction: ltr;
|
||
"
|
||
>
|
||
<!-- 单抽 -->
|
||
<div
|
||
style="
|
||
flex: 1;
|
||
min-width: 0;
|
||
align-self: stretch;
|
||
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
gap: 4vw;
|
||
padding-left: 2vw;
|
||
"
|
||
@click="sweepstakes(1)"
|
||
>
|
||
<div style="color: #fff; font-size: 2em; font-weight: 600; text-shadow: 0 1px 0 #8b00d1">
|
||
1
|
||
</div>
|
||
<img
|
||
v-smart-img
|
||
:src="imageUrl('ticket')"
|
||
alt=""
|
||
style="display: block; width: 3em; object-fit: cover"
|
||
/>
|
||
</div>
|
||
|
||
<!-- 十连抽 -->
|
||
<div
|
||
style="
|
||
flex: 1;
|
||
min-width: 0;
|
||
align-self: stretch;
|
||
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
gap: 2vw;
|
||
"
|
||
@click="sweepstakes(10)"
|
||
>
|
||
<div style="color: #fff; font-size: 2em; font-weight: 600; text-shadow: 0 1px 0 #8b00d1">
|
||
10
|
||
</div>
|
||
<img
|
||
v-smart-img
|
||
:src="imageUrl('ticket')"
|
||
alt=""
|
||
style="display: block; width: 3em; object-fit: cover"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</itemCenter>
|
||
|
||
<!-- 收益操作 -->
|
||
<div style="width: 100%; padding: 0 4vw; display: flex; flex-direction: column; gap: 2vw">
|
||
<!-- 个人信息 -->
|
||
<itemCenter
|
||
style="min-height: 41.67vw; z-index: 0"
|
||
:imgUrl="imageUrl('earningInfoBg')"
|
||
:flip="true"
|
||
:contentStyle="`inset:11vw 10vw 9vw 9vw;justify-content: space-between;gap: 10vw;`"
|
||
>
|
||
<!-- 头像 -->
|
||
<img
|
||
:src="userInfo.userAvatar || ''"
|
||
alt=""
|
||
style="
|
||
position: relative;
|
||
z-index: -1;
|
||
width: 23vw;
|
||
min-width: 0;
|
||
|
||
border-radius: 50%;
|
||
aspect-ratio: 1/1;
|
||
object-fit: cover;
|
||
"
|
||
@error="handleAvatarImageError"
|
||
/>
|
||
|
||
<!-- 基本信息 -->
|
||
<div
|
||
style="
|
||
position: relative;
|
||
flex: 1;
|
||
min-width: 0;
|
||
height: 80%;
|
||
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
gap: 1vw;
|
||
"
|
||
>
|
||
<!-- 帮助按钮 -->
|
||
<img
|
||
v-smart-img
|
||
src="/src/assets/icon/helpWhite.png"
|
||
alt=""
|
||
class="ruleBt"
|
||
@click="openPopup('earningsHelp')"
|
||
/>
|
||
|
||
<!-- 名称 -->
|
||
<div
|
||
style="
|
||
max-width: 70%;
|
||
min-width: 0;
|
||
font-weight: 500;
|
||
overflow: hidden;
|
||
white-space: nowrap;
|
||
text-overflow: ellipsis;
|
||
"
|
||
>
|
||
{{ userInfo.userNickname || '' }}
|
||
</div>
|
||
|
||
<!-- 收益 -->
|
||
<div style="width: 100%; font-weight: 600">
|
||
{{ t('current_earnings', { amount: currentEarnings }) }}
|
||
</div>
|
||
</div>
|
||
</itemCenter>
|
||
|
||
<!-- 操作抽屉 -->
|
||
<div style="position: relative; z-index: 0">
|
||
<!-- 背景图 -->
|
||
<div
|
||
style="
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: -1;
|
||
|
||
border-radius: 12px;
|
||
"
|
||
:style="{
|
||
backgroundImage: `url(${imageUrl('earningsBg')})`,
|
||
backgroundSize: 'cover',
|
||
}"
|
||
></div>
|
||
|
||
<!-- 内容 -->
|
||
<div
|
||
style="
|
||
border-radius: 12px;
|
||
background:
|
||
linear-gradient(0deg, rgba(255, 255, 255, 0.02) 0%, rgba(255, 255, 255, 0.02) 100%),
|
||
linear-gradient(
|
||
99deg,
|
||
rgba(211, 212, 213, 0.15) 12.86%,
|
||
rgba(139, 145, 147, 0.15) 15.34%,
|
||
rgba(87, 95, 99, 0.15) 17.82%,
|
||
rgba(55, 65, 69, 0.15) 18.64%,
|
||
rgba(43, 54, 58, 0.15) 19.47%,
|
||
rgba(52, 62, 66, 0.15) 22.77%,
|
||
rgba(77, 85, 89, 0.15) 26.9%,
|
||
rgba(117, 123, 126, 0.15) 32.68%,
|
||
rgba(173, 176, 177, 0.15) 38.46%,
|
||
rgba(205, 205, 206, 0.15) 41.76%,
|
||
rgba(198, 199, 200, 0.15) 43.41%,
|
||
rgba(180, 182, 184, 0.15) 45.06%,
|
||
rgba(151, 156, 158, 0.15) 46.71%,
|
||
rgba(111, 118, 122, 0.15) 49.19%,
|
||
rgba(72, 83, 87, 0.15) 50.84%,
|
||
rgba(76, 86, 90, 0.15) 52.49%,
|
||
rgba(89, 98, 102, 0.15) 54.97%,
|
||
rgba(112, 117, 120, 0.15) 57.45%,
|
||
rgba(143, 144, 146, 0.15) 59.1%,
|
||
rgba(152, 152, 154, 0.15) 59.92%,
|
||
rgba(165, 165, 166, 0.15) 63.23%,
|
||
rgba(199, 199, 200, 0.15) 70.66%,
|
||
rgba(255, 255, 255, 0.15) 78.91%,
|
||
rgba(209, 209, 210, 0.15) 81.39%,
|
||
rgba(79, 79, 83, 0.15) 87.17%,
|
||
rgba(27, 27, 32, 0.15) 90.47%,
|
||
rgba(49, 49, 54, 0.15) 91.3%,
|
||
rgba(77, 77, 81, 0.15) 92.12%,
|
||
rgba(116, 116, 118, 0.15) 92.95%,
|
||
rgba(165, 165, 167, 0.15) 94.6%,
|
||
rgba(233, 233, 233, 0.15) 95.43%
|
||
);
|
||
background-blend-mode: normal, hard-light;
|
||
backdrop-filter: blur(5px);
|
||
|
||
padding: 12px;
|
||
font-weight: 600;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
position: relative;
|
||
z-index: 0;
|
||
"
|
||
>
|
||
<!-- 转账功能 -->
|
||
<div
|
||
style="display: flex; justify-content: space-between; align-items: center"
|
||
@click="drawerShowBt('transfer')"
|
||
v-if="userIdentity.anchor"
|
||
>
|
||
<div>{{ t('transfer_to_recharge_agent') }}</div>
|
||
<img
|
||
v-smart-img
|
||
class="flipImg"
|
||
src="/src/assets/icon/arrowWhite.png"
|
||
alt=""
|
||
style="width: 1em; display: block; transition: all 0.2s ease"
|
||
:class="{ rotated: transferShow }"
|
||
/>
|
||
</div>
|
||
|
||
<!-- 转账抽屉 -->
|
||
<transition name="drawer">
|
||
<div
|
||
v-if="transferShow"
|
||
style="
|
||
background-color: transparent;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
"
|
||
>
|
||
<!-- 转账对象 -->
|
||
<div
|
||
v-if="selectedPayee.id"
|
||
style="
|
||
border-radius: 8px;
|
||
border: 1px solid #cfcfcf;
|
||
background: rgba(240, 240, 240, 0.3);
|
||
box-shadow:
|
||
-42px 103px 31px 0 rgba(145, 145, 145, 0),
|
||
-27px 66px 29px 0 rgba(145, 145, 145, 0.01),
|
||
-15px 37px 24px 0 rgba(145, 145, 145, 0.03),
|
||
-7px 17px 18px 0 rgba(145, 145, 145, 0.04),
|
||
-2px 4px 10px 0 rgba(145, 145, 145, 0.05);
|
||
backdrop-filter: blur(7.5px);
|
||
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="handleAvatarImageError"
|
||
/>
|
||
</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">
|
||
{{ $t('user_id_prefix') }} {{ selectedPayee.account || '' }}
|
||
</div>
|
||
</div>
|
||
<!-- 换人按钮 -->
|
||
<button
|
||
style="
|
||
border-radius: 20px;
|
||
border: 1px solid #cfcfcf;
|
||
background: rgba(240, 240, 240, 0.3);
|
||
box-shadow:
|
||
0 -5px 4px 0 rgba(255, 255, 255, 0.25) inset,
|
||
0 4px 4px 0 rgba(255, 255, 255, 0.25) inset,
|
||
-42px 103px 31px 0 rgba(145, 145, 145, 0),
|
||
-27px 66px 29px 0 rgba(145, 145, 145, 0.01),
|
||
-15px 37px 24px 0 rgba(145, 145, 145, 0.03),
|
||
-7px 17px 18px 0 rgba(145, 145, 145, 0.04),
|
||
-2px 4px 10px 0 rgba(145, 145, 145, 0.05);
|
||
backdrop-filter: blur(10px);
|
||
|
||
font-weight: 500;
|
||
padding: 2px 8px;
|
||
"
|
||
@click="searchPayee"
|
||
>
|
||
{{ t('change') }}
|
||
</button>
|
||
</div>
|
||
<!-- 身份图标 -->
|
||
<div style="margin-left: 50px; display: flex; gap: 5px">
|
||
<img
|
||
v-if="selectedPayee.isHost"
|
||
v-smart-img
|
||
src="/src/assets/icon/identity/host.png"
|
||
alt=""
|
||
width="30%"
|
||
/>
|
||
<img
|
||
v-if="selectedPayee.isAgency"
|
||
v-smart-img
|
||
src="/src/assets/icon/identity/agency.png"
|
||
alt=""
|
||
width="30%"
|
||
style="display: block"
|
||
/>
|
||
<img
|
||
v-if="selectedPayee.hasSalary"
|
||
v-smart-img
|
||
src="/src/assets/icon/identity/coinSeller.png"
|
||
alt=""
|
||
width="30%"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 空状态 - 默认显示 -->
|
||
<div
|
||
v-else
|
||
style="
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
|
||
border-radius: 8px;
|
||
border: 1px solid #cfcfcf;
|
||
background: rgba(240, 240, 240, 0.3);
|
||
box-shadow:
|
||
-42px 103px 31px 0 rgba(145, 145, 145, 0),
|
||
-27px 66px 29px 0 rgba(145, 145, 145, 0.01),
|
||
-15px 37px 24px 0 rgba(145, 145, 145, 0.03),
|
||
-7px 17px 18px 0 rgba(145, 145, 145, 0.04),
|
||
-2px 4px 10px 0 rgba(145, 145, 145, 0.05);
|
||
backdrop-filter: blur(7.5px);
|
||
|
||
padding: 12px 0;
|
||
"
|
||
>
|
||
<div
|
||
style="
|
||
font-weight: 590;
|
||
padding: 16px 24px;
|
||
|
||
border-radius: 8px;
|
||
border: 0.5px solid #cfcfcf;
|
||
background: rgba(240, 240, 240, 0.3);
|
||
box-shadow:
|
||
-42px 103px 31px 0 rgba(145, 145, 145, 0),
|
||
-27px 66px 29px 0 rgba(145, 145, 145, 0.01),
|
||
-15px 37px 24px 0 rgba(145, 145, 145, 0.03),
|
||
-7px 17px 18px 0 rgba(145, 145, 145, 0.04),
|
||
-2px 4px 10px 0 rgba(145, 145, 145, 0.05);
|
||
backdrop-filter: blur(7.5px);
|
||
"
|
||
@click="searchPayee"
|
||
>
|
||
{{ t('select') }}
|
||
</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?.id === coin.id }]"
|
||
>
|
||
<img v-smart-img src="/src/assets/icon/dollar.png" alt="" style="width: 40%" />
|
||
<div style="font-weight: 500; color: #fff">${{ 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: 8px;
|
||
border: 0.5px solid #cfcfcf;
|
||
background: rgba(240, 240, 240, 0.3);
|
||
box-shadow:
|
||
-42px 103px 31px 0 rgba(145, 145, 145, 0),
|
||
-27px 66px 29px 0 rgba(145, 145, 145, 0.01),
|
||
-15px 37px 24px 0 rgba(145, 145, 145, 0.03),
|
||
-7px 17px 18px 0 rgba(145, 145, 145, 0.04),
|
||
-2px 4px 10px 0 rgba(145, 145, 145, 0.05);
|
||
backdrop-filter: blur(7.5px);
|
||
|
||
font-weight: 590;
|
||
"
|
||
@click="transfer"
|
||
:disabled="!selectedCoin || !selectedPayee.value?.id"
|
||
>
|
||
{{ t('transfer') }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</transition>
|
||
|
||
<!-- 兑换金币 -->
|
||
<div
|
||
style="display: flex; justify-content: space-between; align-items: center"
|
||
@click="drawerShowBt('exchange')"
|
||
>
|
||
<div>{{ t('exchange_gold_coins') }}</div>
|
||
<img
|
||
v-smart-img
|
||
class="flipImg"
|
||
src="/src/assets/icon/arrowWhite.png"
|
||
alt=""
|
||
style="width: 1em; display: block; transition: all 0.2s ease"
|
||
:class="{ rotated: exchangeShow }"
|
||
/>
|
||
</div>
|
||
|
||
<!-- 兑换金币抽屉 -->
|
||
<transition name="drawer">
|
||
<div
|
||
v-if="exchangeShow"
|
||
style="
|
||
background-color: transparent;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
"
|
||
>
|
||
<!-- 转账金额选择 -->
|
||
<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?.id == coin.id }]"
|
||
>
|
||
<img v-smart-img src="/src/assets/icon/coin.png" alt="" style="width: 40%" />
|
||
<div style="direction: ltr; font-size: 0.7em">{{ coin.amount }} coins x1</div>
|
||
<div style="font-weight: 500; color: #fff">${{ 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: 8px;
|
||
border: 0.5px solid #cfcfcf;
|
||
background: rgba(240, 240, 240, 0.3);
|
||
box-shadow:
|
||
-42px 103px 31px 0 rgba(145, 145, 145, 0),
|
||
-27px 66px 29px 0 rgba(145, 145, 145, 0.01),
|
||
-15px 37px 24px 0 rgba(145, 145, 145, 0.03),
|
||
-7px 17px 18px 0 rgba(145, 145, 145, 0.04),
|
||
-2px 4px 10px 0 rgba(145, 145, 145, 0.05);
|
||
backdrop-filter: blur(7.5px);
|
||
|
||
font-weight: 590;
|
||
"
|
||
:disabled="!selectedCoin || !selectedPayee.value?.id"
|
||
@click="exchangeCoinBt"
|
||
>
|
||
{{ t('exchange') }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</transition>
|
||
|
||
<!-- 提取现金 -->
|
||
<div
|
||
style="display: flex; justify-content: space-between; align-items: center"
|
||
@click="goToWithdraw"
|
||
v-if="currentEarnings >= 10"
|
||
>
|
||
<div>{{ t('go_to_withdraw') }}</div>
|
||
<img
|
||
v-smart-img
|
||
class="flipImg"
|
||
src="/src/assets/icon/arrowWhite.png"
|
||
alt=""
|
||
style="width: 1em; display: block"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
||
import { connectToApp } from '@/utils/appConnector.js'
|
||
import { useRoute, useRouter } from 'vue-router'
|
||
import { useI18n } from 'vue-i18n'
|
||
import { setDocumentDirection } from '@/locales/i18n'
|
||
import { viewUserInfo } from '@/utils/appBridge.js'
|
||
import { useLangStore } from '@/stores/lang'
|
||
import { getPngUrl } from '@/config/imagePaths.js'
|
||
import { preloadImages } from '@/utils/image/imagePreloader.js'
|
||
import { showError, showSuccess } from '@/utils/toast.js'
|
||
import { handleAvatarImageError, handleRewardImageError } from '@/utils/image/imageHandler.js'
|
||
import { formatRewardDisplay } from '@/utils/rewardFormatter.js'
|
||
import { getSelectedPayee, clearSelectedPayee } from '@/utils/payeeStore.js'
|
||
import { useSpringFestival } from '@/stores/springFestival'
|
||
import { storeToRefs } from 'pinia'
|
||
|
||
import {
|
||
onceDraw, // 执行单次抽奖
|
||
multiDraw, // 执行连抽
|
||
drawRecords, // 获取抽奖记录
|
||
myTickets, // 获取剩余中奖券
|
||
withdrawableAmount, //获取可提现金额
|
||
transferActivityDollar, // 转账活动美金
|
||
exchangeCoin, //兑换代币
|
||
} from '@/api/lottery'
|
||
|
||
import BackgroundLayer from '@/components/BackgroundLayer.vue'
|
||
import itemCenter from '@/components/itemCenter.vue'
|
||
import maskLayer from '@/components/MaskLayer.vue'
|
||
|
||
// 预加载状态
|
||
const isLoading = ref(true)
|
||
|
||
const { t, locale } = useI18n()
|
||
const router = useRouter()
|
||
const route = useRoute()
|
||
const springFestivalStore = useSpringFestival()
|
||
|
||
const {
|
||
// 抽奖模块
|
||
lotteryRewards, // 抽奖奖池
|
||
tickets, // 抽奖券数量
|
||
luckyUsers, // 中奖用户列表
|
||
userInfo, // 用户信息
|
||
userIdentity, // 用户身份
|
||
currentEarnings, // 当前收益
|
||
selectedPayee, // 选择的收款人
|
||
taskList, // 任务列表
|
||
|
||
// 抽奖排名模块
|
||
lotteryRanking, // 抽奖排名
|
||
addLotteryRanking, // 补充的抽奖排名
|
||
myLotteryRanking, // 我的抽奖排名
|
||
|
||
// 排行榜奖励模块
|
||
rankingRewards, // 排名奖池
|
||
|
||
// 充值排名模块
|
||
rechargeRanking, // 充值排名
|
||
addRechargeRanking, // 补充的充值排名
|
||
myRechargeRanking, // 我的充值排名
|
||
|
||
// 充值奖池模块
|
||
myRechargeRecode, // 我的充值记录
|
||
RechargeRewards, // 充值奖池
|
||
|
||
resultShow,
|
||
result, // 抽奖结果
|
||
|
||
drawRecordShow,
|
||
myRecords, // 我的抽奖记录
|
||
|
||
receiveRecordShow,
|
||
receiveRecord, // 领取抽奖券记录
|
||
|
||
taskListShow, // 任务列表展示
|
||
|
||
earningsHelpShow, // 收益help展示
|
||
rechargeHelpShow, // 充值help展示
|
||
} = storeToRefs(springFestivalStore)
|
||
|
||
const langStore = useLangStore()
|
||
// 当前语言类型
|
||
const currentLangType = computed(() => {
|
||
return langStore.selectedLang?.type || 'en'
|
||
})
|
||
|
||
// 获取OSS图片URL的函数
|
||
const imageUrl = (filename) => getPngUrl('Activities/SpringFestival/', filename)
|
||
|
||
// 根据语言获取图片名
|
||
const getImgName = (filename) => {
|
||
return currentLangType.value === 'ar' ? `${filename}_ar` : filename
|
||
}
|
||
|
||
const props = defineProps({
|
||
// 抽奖结果
|
||
activity: {
|
||
type: Object,
|
||
default: () => ({}),
|
||
},
|
||
})
|
||
|
||
const duration = ref(0) // 弹幕滚动时长
|
||
|
||
// 显示的文本
|
||
const barrageText = (item) => {
|
||
const params = { nickname: item.nickname, prizeName: item.prizeName }
|
||
return item.prizeType == 'GOLD' || item.prizeType == 'MONEY'
|
||
? t('barrage_won_prize', params)
|
||
: t('barrage_won_the_prize', params)
|
||
}
|
||
|
||
const scrollWrapper = ref(null) //滚动模块
|
||
|
||
watch(luckyUsers, async () => {
|
||
if (luckyUsers.value == [] || !scrollWrapper.value) return
|
||
await nextTick()
|
||
|
||
let retryCount = 0 // 当前重试次数
|
||
const maxRetries = 50 // 最大重试次数
|
||
let timerId = null // 用于存储当前的 setTimeout ID
|
||
|
||
const calculateWidth = () => {
|
||
const wrapper = scrollWrapper.value
|
||
if (!wrapper) return
|
||
|
||
const contentWidth = wrapper.scrollWidth
|
||
// console.log('luckyUsers 更新后的宽度:', contentWidth)
|
||
|
||
if (contentWidth === 0) {
|
||
retryCount++
|
||
if (retryCount <= maxRetries) {
|
||
// console.warn(`宽度为 0,第 ${retryCount} 次重试...`)
|
||
// 清除旧的定时器,避免多个实例同时运行
|
||
if (timerId) clearTimeout(timerId)
|
||
timerId = setTimeout(calculateWidth, 500) // 延时重试
|
||
} else {
|
||
// console.error('重试次数已达上限,未能获取有效宽度')
|
||
}
|
||
} else {
|
||
// 正常处理逻辑
|
||
const speed = 80
|
||
duration.value = contentWidth / speed
|
||
console.log('计算总时长(秒):', duration.value)
|
||
// 清除定时器,防止后续不必要的执行
|
||
if (timerId) clearTimeout(timerId)
|
||
}
|
||
}
|
||
|
||
calculateWidth()
|
||
})
|
||
|
||
const isRolling = ref(false) // 是否正在抽奖
|
||
const activeIndex = ref(0)
|
||
|
||
// 抽屉展示
|
||
const transferShow = ref(false) //转账
|
||
const exchangeShow = ref(false) //兑换
|
||
const withdrawShow = ref(false) //提现
|
||
|
||
const selectedCoin = ref(null) // 选择的币种
|
||
|
||
// 抽屉展示
|
||
const drawerShowBt = (type) => {
|
||
transferShow.value = type == 'transfer' ? !transferShow.value : false
|
||
exchangeShow.value = type == 'exchange' ? !exchangeShow.value : false
|
||
withdrawShow.value = type == 'withdraw' ? !withdrawShow.value : false
|
||
selectedCoin.value = null
|
||
}
|
||
|
||
// 打开遮罩层
|
||
const openPopup = (type) => {
|
||
switch (type) {
|
||
case 'result':
|
||
closedPopup() // 关闭弹窗
|
||
resultShow.value = true
|
||
break
|
||
case 'drawRecord':
|
||
closedPopup() // 关闭弹窗
|
||
drawRecordShow.value = true
|
||
break
|
||
case 'receiveRecord':
|
||
closedPopup() // 关闭弹窗
|
||
receiveRecordShow.value = true
|
||
break
|
||
case 'earningsHelp':
|
||
closedPopup() // 关闭弹窗
|
||
earningsHelpShow.value = true
|
||
break
|
||
case 'rechargeHelp':
|
||
closedPopup() // 关闭弹窗
|
||
rechargeHelpShow.value = true
|
||
break
|
||
case 'taskList':
|
||
closedPopup() // 关闭弹窗
|
||
taskListShow.value = true
|
||
break
|
||
|
||
default:
|
||
closedPopup() // 关闭弹窗
|
||
break
|
||
}
|
||
}
|
||
|
||
// 关闭弹窗
|
||
const closedPopup = () => {
|
||
if (taskListShow.value) {
|
||
checkStatus.value = true
|
||
}
|
||
|
||
resultShow.value = false
|
||
drawRecordShow.value = false
|
||
receiveRecordShow.value = false
|
||
earningsHelpShow.value = false
|
||
rechargeHelpShow.value = false
|
||
taskListShow.value = false
|
||
}
|
||
|
||
//奖盘布局
|
||
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) => {
|
||
console.log('开始抽奖动画')
|
||
|
||
return new Promise((resolve) => {
|
||
activeIndex.value = -1
|
||
|
||
let speed = 200 // 初始速度
|
||
let currentCycle = 0 // 当前圈数
|
||
let constantSpeedCycle = 0 // 当前匀速圈数
|
||
let totalCycles = 1 // 至少旋转2圈数
|
||
let activity = props.activity
|
||
|
||
const roll = () => {
|
||
activeIndex.value = (activeIndex.value + 1) % activity.prizeList.length
|
||
console.log('当前索引:', activeIndex.value)
|
||
|
||
if (activeIndex.value === resultIndex && speed > 200) {
|
||
setTimeout(() => {
|
||
resolve() // 抽奖结束
|
||
}, 500)
|
||
} else {
|
||
if (activeIndex.value === activity.prizeList.length - 1) {
|
||
currentCycle++
|
||
}
|
||
// 加速旋转
|
||
if (currentCycle < totalCycles) {
|
||
speed -= 20
|
||
} else {
|
||
// 匀速旋转
|
||
if (activeIndex.value === activity.prizeList.length - 1) {
|
||
constantSpeedCycle++
|
||
}
|
||
if (constantSpeedCycle > 2) {
|
||
// 最后减速效果
|
||
speed += 20
|
||
}
|
||
}
|
||
setTimeout(roll, speed)
|
||
}
|
||
}
|
||
|
||
roll()
|
||
})
|
||
}
|
||
|
||
// 连抽
|
||
const sweepstakes = async (consecutive = 1) => {
|
||
if (isRolling.value) return // 防止重复点击
|
||
|
||
isRolling.value = true
|
||
|
||
let activity = props.activity
|
||
|
||
let data = {
|
||
activityId: '2007771533988204877',
|
||
drawCount: consecutive,
|
||
needCoins: consecutive > tickets.value,
|
||
}
|
||
try {
|
||
// 单抽
|
||
if (consecutive == 1) {
|
||
const resOnceDraw = await onceDraw(data)
|
||
if (resOnceDraw.status && resOnceDraw.body) {
|
||
result.value = [resOnceDraw.body] // 中奖结果赋值
|
||
|
||
const resItem = resOnceDraw.body //接口获取的抽奖结果(单抽为对象)
|
||
//取抽奖结果的位置
|
||
const index = activity.prizeList.findIndex(
|
||
(prize) => prize.prizeName == resItem?.prize.prizeName,
|
||
) //转盘第几位停下
|
||
console.log('index:', index)
|
||
getMyLotteryTicketCount() // 更新抽奖券数量
|
||
getDrawableAmount() //刷新可提现金额
|
||
await startLottery(index)
|
||
}
|
||
}
|
||
//连抽
|
||
else {
|
||
const resMultiDraw = await multiDraw(data)
|
||
if (resMultiDraw.status && resMultiDraw.body) {
|
||
result.value = resMultiDraw.body.results // 中奖结果赋值
|
||
|
||
//取第一个抽奖结果的位置
|
||
let index = activity.prizeList.findIndex(
|
||
(prize) => prize.prizeName == result.value[0]?.prize.prizeName,
|
||
)
|
||
console.log('index:', index)
|
||
|
||
getMyLotteryTicketCount() // 更新抽奖券数量
|
||
getDrawableAmount() //刷新可提现金额
|
||
await startLottery(index)
|
||
}
|
||
}
|
||
openPopup('result') //打开中奖结果弹窗
|
||
isRolling.value = false
|
||
} catch (error) {
|
||
showError(error.response.errorMsg)
|
||
isRolling.value = false
|
||
}
|
||
}
|
||
|
||
// 获取中奖记录,并打开弹窗
|
||
const getDrawRecords = async () => {
|
||
const resDrawRecords = await drawRecords('04877')
|
||
if (resDrawRecords.status && resDrawRecords.body) {
|
||
myRecords.value = resDrawRecords.body?.records || []
|
||
openPopup('drawRecord') // 打开中奖历史弹窗
|
||
}
|
||
}
|
||
|
||
// 打开任务列表
|
||
const showTaskList = () => {
|
||
taskListShow.value = true
|
||
}
|
||
|
||
// 前往搜索代理页
|
||
const searchPayee = () => {
|
||
router.push({
|
||
path: '/search-payee',
|
||
query: { from: '/activities/spring-festival', activeAction: 'TaskShow' },
|
||
})
|
||
}
|
||
|
||
// 前往提现页
|
||
const goToWithdraw = () => {
|
||
router.push({ path: '/cash-out', query: { activityId: '2007771533988204877' } })
|
||
}
|
||
|
||
// 转账金币选项
|
||
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?.id == coin.id) {
|
||
selectedCoin.value = null
|
||
} else {
|
||
selectedCoin.value = coin
|
||
}
|
||
}
|
||
|
||
// 转账
|
||
const transfer = async () => {
|
||
if (!selectedCoin.value) {
|
||
showError(t('please_select_amount'))
|
||
return
|
||
}
|
||
|
||
if (!selectedPayee.value?.id) {
|
||
showError(t('please_select_payee'))
|
||
return
|
||
}
|
||
|
||
// 构造请求参数
|
||
const transferData = {
|
||
amount: selectedCoin.value.price,
|
||
acceptUserId: selectedPayee.value?.id,
|
||
activityId: '2007771533988204877',
|
||
}
|
||
|
||
try {
|
||
// 调用转账接口
|
||
const response = await transferActivityDollar(transferData)
|
||
if (response.status) {
|
||
showSuccess(
|
||
t('transfer_dollar_success', {
|
||
price: selectedCoin.value.price,
|
||
name: selectedPayee.value?.name,
|
||
}),
|
||
)
|
||
} else {
|
||
showError(t('transfer_dollar_failed', { price: selectedCoin.value.price }))
|
||
}
|
||
|
||
selectedCoin.value = null // 重置选择
|
||
|
||
getDrawableAmount() //刷新可提现金额
|
||
} catch (error) {
|
||
showError(error.errorMsg)
|
||
}
|
||
}
|
||
|
||
//兑换代币
|
||
const exchangeCoinBt = async () => {
|
||
if (!selectedCoin.value) {
|
||
showError(t('please_select_amount'))
|
||
return
|
||
}
|
||
|
||
// 构造请求参数
|
||
const transferData = {
|
||
amount: selectedCoin.value.price,
|
||
activityId: '2007771533988204877',
|
||
}
|
||
|
||
try {
|
||
// 调用转账接口
|
||
const response = await exchangeCoin(transferData)
|
||
if (response.status) {
|
||
showSuccess(t('exchange_success_coins', { amount: selectedCoin.value.amount }))
|
||
} else {
|
||
showError(t('exchange_failed_coins', { amount: selectedCoin.value.amount }))
|
||
}
|
||
|
||
// 重置选择
|
||
selectedCoin.value = null
|
||
|
||
getDrawableAmount() //刷新可提现金额
|
||
} catch (error) {
|
||
showError(error.errorMsg)
|
||
}
|
||
}
|
||
|
||
//可提现金额
|
||
const getDrawableAmount = async () => {
|
||
const resDrawableAmount = await withdrawableAmount('2007771533988204877')
|
||
if (resDrawableAmount.status && resDrawableAmount.body) {
|
||
currentEarnings.value = resDrawableAmount.body?.availableAmount || 0
|
||
}
|
||
}
|
||
|
||
// 获取抽奖券
|
||
const getMyLotteryTicketCount = async () => {
|
||
try {
|
||
const response = await myTickets('2007771533988204877')
|
||
if (response.status) {
|
||
tickets.value = response.body || 0
|
||
}
|
||
} catch (error) {
|
||
showError(error.response.errorMsg)
|
||
}
|
||
}
|
||
|
||
onMounted(async () => {
|
||
console.log('route.query.activeAction:', route.query.activeAction)
|
||
if (route.query.activeAction == 'TaskShow') {
|
||
drawerShowBt('transfer')
|
||
}
|
||
})
|
||
|
||
onUnmounted(() => {})
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
* {
|
||
color: #fff;
|
||
}
|
||
|
||
.fullPage {
|
||
position: relative;
|
||
background: #142c24;
|
||
}
|
||
|
||
.bg {
|
||
width: 100vw;
|
||
min-height: 100vh;
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.background-overlay {
|
||
position: absolute;
|
||
inset: 236vw 0 0;
|
||
background-image: var(--bg2-url);
|
||
background-repeat: repeat-y;
|
||
background-position: top center;
|
||
background-size: 100% auto;
|
||
z-index: 0; /* 确保在.bg之下 */
|
||
}
|
||
|
||
/* 添加加载动画样式 */
|
||
.loading-container {
|
||
width: 100vw;
|
||
height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
color: #666;
|
||
}
|
||
|
||
.loading-spinner {
|
||
width: 32px;
|
||
height: 32px;
|
||
border: 3px solid #f3f3f3;
|
||
border-top: 3px solid #f59e0b;
|
||
border-radius: 50%;
|
||
animation: spin 1s linear infinite;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
@keyframes spin {
|
||
0% {
|
||
transform: rotate(0deg);
|
||
}
|
||
100% {
|
||
transform: rotate(360deg);
|
||
}
|
||
}
|
||
|
||
.ruleBt {
|
||
width: 4vw;
|
||
min-width: 0;
|
||
display: block;
|
||
aspect-ratio: 1/1;
|
||
object-fit: cover;
|
||
|
||
position: absolute;
|
||
top: 0;
|
||
right: 0;
|
||
}
|
||
|
||
[dir='rtl'] .ruleBt {
|
||
left: 0;
|
||
right: auto;
|
||
}
|
||
|
||
.scrollY::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
|
||
/* 金币网格 */
|
||
.coin-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
|
||
// transition: all 0.2s;
|
||
aspect-ratio: 1/1;
|
||
|
||
border-radius: 8px;
|
||
border: 1px solid #cfcfcf;
|
||
background: rgba(240, 240, 240, 0.3);
|
||
box-shadow:
|
||
-42px 103px 31px 0 rgba(145, 145, 145, 0),
|
||
-27px 66px 29px 0 rgba(145, 145, 145, 0.01),
|
||
-15px 37px 24px 0 rgba(145, 145, 145, 0.03),
|
||
-7px 17px 18px 0 rgba(145, 145, 145, 0.04),
|
||
-2px 4px 10px 0 rgba(145, 145, 145, 0.05);
|
||
backdrop-filter: blur(7.5px);
|
||
}
|
||
|
||
.coin-item.selected {
|
||
border-radius: 12px;
|
||
border: 2px solid #ffdcdc;
|
||
box-shadow:
|
||
-0.25px -0.25px 1px 0 #ff482d,
|
||
0.25px 0.25px 1px 0 #ff482d,
|
||
0 0 3px 0 rgba(255, 72, 45, 0.8),
|
||
0 0 5px 0 rgba(255, 72, 45, 0.6),
|
||
0 0 4px 0 rgba(175, 23, 0, 0.3);
|
||
}
|
||
|
||
.coin-item:active {
|
||
transform: scale(0.98);
|
||
}
|
||
|
||
.scroll-wrapper {
|
||
display: flex;
|
||
width: fit-content;
|
||
}
|
||
|
||
.scroll-content {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
@keyframes scroll-left {
|
||
0% {
|
||
transform: translateX(0);
|
||
}
|
||
100% {
|
||
transform: translateX(-50%);
|
||
}
|
||
}
|
||
|
||
@keyframes scroll-right {
|
||
0% {
|
||
transform: translateX(0);
|
||
}
|
||
100% {
|
||
transform: translateX(50%);
|
||
}
|
||
}
|
||
|
||
[dir='ltr'] .scroll-content {
|
||
margin-left: 4vw;
|
||
}
|
||
|
||
[dir='rtl'] .scroll-content {
|
||
margin-left: auto;
|
||
margin-right: 4vw;
|
||
}
|
||
|
||
[dir='ltr'] .scroll-wrapper {
|
||
animation-name: scroll-left;
|
||
animation-timing-function: linear;
|
||
animation-iteration-count: infinite;
|
||
will-change: transform;
|
||
}
|
||
|
||
[dir='rtl'] .scroll-wrapper {
|
||
animation-name: scroll-right;
|
||
animation-timing-function: linear;
|
||
animation-iteration-count: infinite;
|
||
will-change: transform;
|
||
}
|
||
|
||
.scrollY::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
|
||
[dir='rtl'] .flipImg {
|
||
transform: scaleX(-1);
|
||
}
|
||
|
||
@media screen and (max-width: 360px) {
|
||
* {
|
||
font-size: 10px;
|
||
}
|
||
}
|
||
|
||
@media screen and (min-width: 360px) {
|
||
* {
|
||
font-size: 12px;
|
||
}
|
||
}
|
||
|
||
@media screen and (min-width: 768px) {
|
||
* {
|
||
font-size: 24px;
|
||
}
|
||
}
|
||
|
||
@media screen and (min-width: 1024px) {
|
||
* {
|
||
font-size: 32px;
|
||
}
|
||
}
|
||
</style>
|