3021 lines
92 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="fullPage">
<!-- 预加载状态 -->
<div v-if="isLoading" class="loading-container">
<LoadingContent>{{ $t('loading') }}...</LoadingContent>
</div>
<!-- 主要内容 -->
<div
v-if="!isLoading"
style="width: 100vw; min-height: 100vh; overflow: hidden; position: relative"
>
<!-- 页面背景 -->
<BackgroundLayer
:useCanvas="true"
:backgroundImages="[imageUrl('bg0'), imageUrl('bg1'), imageUrl('bg2'), imageUrl('bg3')]"
/>
<!-- 页面内容 -->
<div class="s4-x1" style="position: relative; z-index: 2">
<!-- 头部动画 -->
<!-- <img v-smart-img :src="webpUrl('pageTop')" alt="" width="100%" style="display: block" /> -->
<!-- 倒计时和帮助按钮 -->
<div class="s4-x2">
<!-- 倒计时 -->
<div class="timeBox">
<div style="width: 20%">
<itemCenter :imgUrl="imageUrl('timeBg')">
<div class="timeText" style="">{{ Days }}D</div>
</itemCenter>
</div>
<div class="timeText timeGap"></div>
<div style="width: 20%">
<itemCenter :imgUrl="imageUrl('timeBg')">
<div class="timeText" style="">{{ Hours }}</div>
</itemCenter>
</div>
<div class="timeText timeGap">:</div>
<div style="width: 20%">
<itemCenter :imgUrl="imageUrl('timeBg')">
<div class="timeText" style="">{{ Minutes }}</div>
</itemCenter>
</div>
<div class="timeText timeGap">:</div>
<div style="width: 20%">
<itemCenter :imgUrl="imageUrl('timeBg')">
<div class="timeText" style="">{{ Seconds }}</div>
</itemCenter>
</div>
</div>
<!-- 规则按钮 -->
<img
v-smart-img
:src="imageUrl(getImgName('rulesBt'))"
alt=""
style="display: block; width: 25vw"
@click="openPopup('rule')"
/>
</div>
<!-- 弹幕 -->
<Barrage class="barrage-container" :barrageList="barrageList"></Barrage>
<!-- 模块切换按钮 -->
<div style="margin: 0 3vw; display: flex; justify-content: space-between">
<!-- 排行榜模块按钮 -->
<div style="width: 45vw" @click="handleBt('reward')">
<img
v-show="RankingShow"
v-smart-img
:src="imageUrl(getImgName('rankBtActive'))"
alt=""
style="width: 100%; display: block"
/>
<img
v-show="!RankingShow"
v-smart-img
:src="imageUrl(getImgName('rankBt'))"
alt=""
style="width: 100%; display: block"
/>
</div>
<!-- 抽奖模块按钮 -->
<div style="width: 45vw" @click="handleBt('lottery')">
<img
v-show="!RankingShow"
v-smart-img
:src="imageUrl(getImgName('lotteryBtActive'))"
alt=""
style="width: 100%; display: block"
/>
<img
v-show="RankingShow"
v-smart-img
:src="imageUrl(getImgName('lotteryBt'))"
alt=""
style="width: 100%; display: block"
/>
</div>
</div>
<!-- 标签页切换按钮 -->
<itemCenter :imgUrl="imageUrl('tagsBg')" style="padding: 0 3vw">
<div
style="
width: 100%;
height: 10vw;
padding: 0 10vw;
position: relative;
z-index: 2;
display: flex;
align-items: center;
justify-content: space-between;
"
>
<!-- 排行榜模块按钮 -->
<div
v-for="tag in tabList"
style="
width: 50%;
min-width: 0;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
"
@click="handleBt(tag.value)"
>
<div
style="width: 60%; min-width: 0; overflow: hidden; position: relative"
v-if="isTextOverflow(tag.name)"
>
<!-- 滚动容器 -->
<div class="scroll-wrapper">
<!-- 第一套内容 -->
<div class="scroll-content">
<div
style="
color: #fff;
font-size: 1.5em;
font-weight: 700;
text-shadow: 0 1px 1px #712eb1;
white-space: nowrap;
line-height: 1.2em;
"
>
{{ tag.name }}
</div>
</div>
<!-- 第二套内容间隔30px -->
<div class="scroll-content">
<div
style="
color: #fff;
font-size: 1.5em;
font-weight: 700;
text-shadow: 0 1px 1px #712eb1;
white-space: nowrap;
line-height: 1.2em;
"
>
{{ tag.name }}
</div>
</div>
</div>
</div>
<!-- 不滚动的文本如果长度不需要滚动 -->
<div
v-else
style="
width: 60%;
min-width: 0;
color: #fff;
font-size: 1.5em;
font-weight: 700;
text-shadow: 0 1px 1px #712eb1;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: 1.2em;
"
>
{{ tag.name }}
</div>
</div>
</div>
<!-- 按钮背景图 -->
<div
style="position: absolute; inset: 0 10vw; display: flex; align-items: center"
:style="underlineStyle"
>
<img v-smart-img :src="imageUrl('tagBtBg')" alt="" style="width: 50%" />
</div>
</itemCenter>
<!-- Rewards模块 -->
<div v-show="reward" style="display: flex; flex-direction: column; align-items: center">
<!-- 我的充值记录 -->
<itemCenter :imgUrl="imageUrl('myInfoBg')" contentStyle="padding: 18vw 10vw 7vw;gap:2vw;">
<!-- 头像 -->
<itemCenter
:imgUrl="imageUrl('myAvatarFrame')"
contentStyle=""
style="width: 20vw; position: relative; z-index: 2"
>
<img
:src="myRechargeRecode?.userAvatar"
alt=""
style="
width: 90%;
display: block;
aspect-ratio: 1/1;
object-fit: cover;
border-radius: 50%;
position: relative;
z-index: -1;
"
/>
</itemCenter>
<!-- 基本信息 -->
<div
style="
flex: 1;
min-width: 0;
align-self: stretch;
display: flex;
flex-direction: column;
justify-content: center;
gap: 1vw;
"
>
<!-- 名称 -->
<div
style="
width: 70%;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
"
>
{{ myRechargeRecode?.userName }}
</div>
<!-- 账号 -->
<div>{{ $t('user_id_prefix') }} {{ myRechargeRecode?.account }}</div>
<!-- 总充值 -->
<div style="display: flex; justify-content: space-between; align-items: center">
<div>
{{ t('Accumulated recharge') }}:${{
formatRechargeAmount(myRechargeRecode?.totalAmount)
}}
</div>
<img
v-show="rechargehidden"
v-smart-img
:src="imageUrl('rechargehidden')"
alt=""
style="width: 5vw; display: block; object-fit: cover"
@click="rechargehidden = !rechargehidden"
/>
<img
v-show="!rechargehidden"
v-smart-img
:src="imageUrl('rechargeShow')"
alt=""
style="width: 5vw; display: block; object-fit: cover"
@click="rechargehidden = !rechargehidden"
/>
</div>
</div>
</itemCenter>
<!-- 奖励列表 -->
<div
v-for="(rewardsTop, top) in rewardsList"
:key="top"
style="position: relative; width: 100%; margin: 10px 0"
>
<itemCenter
:imgUrl="topImg[Number(rewardsTop.sort) - 1]"
:contentStyle="rewardContentLayer(rewardsTop.sort)"
>
<!-- 奖励列表 -->
<div
v-for="(reward, rewardIndex) in rewardsTop.rewardProps"
:key="rewardIndex"
style="
width: 100%;
align-self: stretch;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
"
>
<div
style="
width: 100%;
min-width: 0;
aspect-ratio: 1/1;
display: flex;
justify-content: center;
align-items: center;
"
>
<!-- 奖励图片 -->
<img
:src="reward.cover || ''"
alt=""
style="
display: block;
min-width: 0;
width: 70%;
aspect-ratio: 1/1;
object-fit: contain;
"
@error="(e) => handleRewardImageError(e, reward.type)"
/>
</div>
<!-- 数值 -->
<div
style="
width: 80%;
height: 4.5vw;
display: flex;
justify-content: center;
align-items: center;
"
>
<div style="min-width: 0; font-size: 1em; font-weight: 590; color: #fff">
{{ showDetail(reward.type, reward) }}
</div>
</div>
</div>
<!-- 按钮 -->
<div
style="
position: absolute;
bottom: 10vw;
left: 0;
right: 0;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
"
>
<img
v-if="rewardsTop.claimStatus == -1"
:src="imageUrl(getImgName('rewardReceiveNot'))"
alt=""
style="width: 55vw; display: block; object-fit: cover"
/>
<img
v-if="rewardsTop.claimStatus == 0"
:src="imageUrl(getImgName('rewardReceive'))"
alt=""
style="width: 55vw; display: block; object-fit: cover"
@click="receiveReward(rewardsTop)"
/>
<img
v-if="rewardsTop.claimStatus == 1"
:src="imageUrl(getImgName('rewardReceived'))"
alt=""
style="width: 55vw; display: block; object-fit: cover"
/>
</div>
</itemCenter>
</div>
</div>
<!-- 排行榜模块 -->
<div v-show="rankShow">
<!-- 前三名 -->
<div style="margin: 4vw 0">
<!-- 第一 -->
<div style="display: flex; justify-content: center">
<TopUser
ranking="1"
:BorderImgUrl="imageUrl('top1')"
:avatarUrl="RankingHasTop3[0].userAvatar"
:name="RankingHasTop3[0].userName"
:distributionValue="RankingHasTop3[0].amount"
style="width: 70%"
@click="viewUserInfo(RankingHasTop3[0].userId)"
/>
</div>
<!-- 第二三 -->
<div
style="
position: relative;
z-index: 3;
display: flex;
justify-content: space-between;
margin-top: -34%;
pointer-events: none;
"
>
<div
style="pointer-events: auto; width: 30%"
@click.stop="viewUserInfo(RankingHasTop3[1].userId)"
>
<TopUser
ranking="2"
:BorderImgUrl="imageUrl('top2')"
:avatarUrl="RankingHasTop3[1].userAvatar"
:name="RankingHasTop3[1].userName"
:distributionValue="RankingHasTop3[1].amount"
style="width: 100%"
/>
</div>
<div
style="pointer-events: auto; width: 30%"
@click.stop="viewUserInfo(RankingHasTop3[2].userId)"
>
<TopUser
ranking="3"
:BorderImgUrl="imageUrl('top3')"
:avatarUrl="RankingHasTop3[2].userAvatar"
:name="RankingHasTop3[2].userName"
:distributionValue="RankingHasTop3[2].amount"
style="width: 100%"
/>
</div>
</div>
</div>
<!-- 第四名开始 -->
<div v-if="showRanking.length > 0" style="position: relative; z-index: 2">
<itemCenter
v-for="(listItem, index) in showRanking"
:key="listItem.userId"
:imgUrl="imageUrl('RankingItem')"
:contentStyle="`padding: 0 9%`"
:lazy="true"
:immediate="index < 2"
@click="viewUserInfo(listItem.userId)"
>
<!-- 基本信息 -->
<div
style="
flex: 1;
min-width: 0;
display: flex;
justify-content: space-around;
align-items: center;
gap: 4px;
"
>
<!-- 排名 -->
<div style="color: #ffe601; font-weight: 700">
{{ listItem?.rank }}
</div>
<!-- 头像 -->
<img
:src="listItem?.userAvatar || ''"
alt=""
style="
display: block;
width: 3.5em;
margin: 0 2%;
aspect-ratio: 1/1;
border-radius: 50%;
object-fit: cover;
"
@error="handleAvatarImageError"
/>
<!-- 名称id -->
<div style="flex: 1; min-width: 0; display: flex; flex-direction: column">
<div
style="
color: #fff;
font-weight: 860;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
"
class="s4-x3"
>
{{ listItem?.userName }}
</div>
<div style="color: #fff; font-weight: 590" class="s4-x3">
{{ $t('user_id_prefix') }} {{ listItem?.specialAccount || listItem?.account }}
</div>
</div>
</div>
<!-- 贡献值 -->
<div
style="
width: auto;
min-width: 0;
display: flex;
align-items: center;
"
>
<div style="color: #fff; font-weight: 700" class="s4-x3">
${{ listItem?.amount }}
</div>
</div>
</itemCenter>
</div>
<!-- 触发加载功能 -->
<div ref="RankingLoadmore"></div>
</div>
<!-- 抽奖模块 -->
<div
v-show="lotteryShow"
style="margin-top: -12vw; width: 100vw; display: flex; flex-direction: column; gap: 3vw"
>
<itemCenter
:imgUrl="imageUrl('lottery')"
:contentStyle="`flex-direction: column;justify-content: flex-start;gap: 5vw`"
>
<!-- 中奖历史按钮 -->
<img
v-smart-img
:src="imageUrl(getImgName('historyBt'))"
alt=""
style="width: 15vw; position: absolute; top: 18vw; right: 4vw"
@click="openPopup('history')"
/>
<!-- 抽奖转盘 -->
<div
style="
width: 100%;
height: 61vw;
align-self: stretch;
margin: 42.5vw 0 0;
padding: 0 18vw;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
gap: 1vw;
direction: ltr;
"
>
<div
v-for="(prize, index) in activity.prizeList"
style="
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: relative;
"
:style="[getGridPosition(index)]"
>
<!-- <img
:src="prize.prizeImage || ''"
:alt="prize.prizeName || ''"
width="60%"
style="display: block"
/> -->
<!-- <div style="font-size: 0.8em">{{ prize.prizeName }}</div> -->
<!-- 转到的奖品项 -->
<img
v-show="activeIndex === index"
v-smart-img
:src="imageUrl('prizeActiveFrame')"
alt=""
style="
display: block;
width: 100%;
position: absolute;
inset: 0;
"
/>
</div>
<!-- 按钮 -->
<div
style="
grid-area: 2 / 2;
display: flex;
justify-content: center;
align-items: center;
"
:disabled="isRolling"
@click="sweepstakes(1)"
></div>
</div>
<!-- 抽奖按钮 -->
<div
style="height: 12vw; display: flex; justify-content: space-between; gap: 4vw"
class="s4-x4"
>
<!-- 单抽 -->
<div style="width: 30vw; height: 100%" @click="sweepstakes(1)"></div>
<!-- 10连抽 -->
<div style="width: 30vw; height: 100%" @click="sweepstakes(10)"></div>
</div>
<!-- 抽奖次数 -->
<div style="height: 11vw; display: flex; justify-content: center; align-items: center">
<div style="font-weight: 590">
{{ t('current_tickets', { count: rollTimes }) }}
</div>
</div>
</itemCenter>
<!-- 总抽奖次数 -->
<div
style="
position: relative;
z-index: 2;
margin: -80vw 4vw 0;
display: flex;
flex-direction: column;
gap: 2vw;
padding: 12px;
border-radius: 12px;
background:
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%
),
linear-gradient(0deg, #5d69ec 0%, #5d69ec 100%), #e8e8e8;
background-blend-mode: hard-light, normal, normal;
"
>
<div style="display: flex; justify-content: space-between; align-items: center">
<div style="font-size: 1.2em; font-weight: 700">
{{
t('Total Tickets:({ usedCount }/100)', { usedCount: totalDraw?.usedCount || 0 })
}}
</div>
<!-- 按钮 -->
<div style="width: 20%">
<!-- 未满足条件 -->
<img
v-if="RechargeBadgeInfo.claimStatus == -1"
v-smart-img
:src="imageUrl('taskBtGo')"
width="100%"
style="display: block"
/>
<!-- 未领取 -->
<img
v-if="RechargeBadgeInfo.claimStatus == 0"
:src="imageUrl('taskBtReceive')"
:alt="t('receive')"
width="100%"
style="display: block"
@click="receiveRechargeBadge(RechargeBadgeInfo)"
/>
<!-- 已领取 -->
<img
v-if="RechargeBadgeInfo.claimStatus == 1"
:src="imageUrl('taskBtReceived')"
:alt="t('done')"
width="100%"
style="display: block"
/>
</div>
</div>
<div style="display: flex; align-items: center; gap: 4vw">
<img
v-for="Badge in RechargeBadgeInfo.rewardProps"
:src="Badge.cover || ''"
alt=""
style="display: block; width: 18vw"
/>
<div>{{ t('Lucky Dollars Medal*permanent') }}</div>
</div>
</div>
<!-- 任务列表 -->
<div
style="
position: relative;
z-index: 2;
margin: 0 4vw;
border-radius: 12px;
background:
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%
),
linear-gradient(0deg, #5d69ec 0%, #5d69ec 100%), #e8e8e8;
background-blend-mode: hard-light, normal, normal;
padding: 12px;
display: flex;
flex-direction: column;
gap: 12px;
"
>
<div style="font-weight: 590">{{ t('Task for tickets') }}</div>
<div
v-for="task in taskList"
style="
border-radius: 12px;
border: 2px solid #fff;
background: linear-gradient(
264deg,
rgba(220, 228, 255, 0.4) 10.17%,
rgba(151, 176, 255, 0.4) 60.22%,
rgba(220, 228, 255, 0.4) 103.12%
);
box-shadow:
0 36.858px 13.981px 0 rgba(151, 176, 255, 0.02),
0 20.335px 12.71px 0 rgba(151, 176, 255, 0.08),
0 8.897px 8.897px 0 rgba(151, 176, 255, 0.13),
0 2.542px 5.084px 0 rgba(151, 176, 255, 0.15);
backdrop-filter: blur(4.5px);
display: flex;
padding: 8px;
justify-content: space-between;
align-items: center;
"
>
<!-- 图标 -->
<div style="width: 20%">
<img
v-if="task.taskType == 1"
v-smart-img
:src="imageUrl('taskTalk')"
alt=""
width="100%"
style="display: block"
/>
<img
v-if="task.taskType == 2"
v-smart-img
:src="imageUrl('taskGift')"
alt=""
width="100%"
style="display: block"
/>
<img
v-if="task.taskType == 4"
v-smart-img
:src="imageUrl('taskGame')"
alt=""
width="100%"
style="display: block"
/>
<img
v-if="task.taskType == 5"
v-smart-img
:src="imageUrl('taskRecharge')"
alt=""
width="100%"
style="display: block"
/>
</div>
<!-- 内容 -->
<div style="width: 60%">
<!-- 任务进度 -->
<div style="color: #fff; font-weight: 590; font-size: 0.9em">
{{ showTarget(task) }}
</div>
<!-- 任务奖励 -->
<div style="display: flex; align-items: center; gap: 8px">
<div style="color: #fff; font-weight: 590">{{ t('Rewards:') }}</div>
<img
v-smart-img
:src="imageUrl('ticket')"
:alt="t('ticket')"
width="15%"
style="display: block"
/>
<div style="color: #fff; font-weight: 590">*{{ task.rewardValue }}</div>
</div>
</div>
<!-- 按钮 -->
<div style="width: 20%">
<!-- 前往任务 -->
<img
v-if="task.taskStatus == 0"
v-smart-img
:src="imageUrl('taskBtGo')"
width="100%"
style="display: block"
/>
<!-- 领取抽奖券 -->
<img
v-else-if="task.taskStatus === 1"
v-smart-img
:src="imageUrl('taskBtReceive')"
:alt="t('receive')"
width="100%"
style="display: block"
@click="receiveTaskReward(task.taskCode)"
/>
<!-- 已完成 -->
<img
v-else
v-smart-img
:src="imageUrl('taskBtReceived')"
:alt="t('done')"
width="100%"
style="display: block"
/>
</div>
</div>
</div>
</div>
<!-- 提现模块 -->
<div
v-show="incomeShow"
style="width: 100%; padding: 0 4vw; display: flex; flex-direction: column; gap: 3vw"
>
<!-- 个人信息 -->
<div
style="
border-radius: 12px;
background:
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%
),
linear-gradient(0deg, #5d69ec 0%, #5d69ec 100%), #e8e8e8;
background-blend-mode: hard-light, normal, normal;
padding: 16px 12px;
display: flex;
align-items: center;
gap: 8px;
position: relative;
"
>
<!-- 头像 -->
<img
:src="userInfo.userAvatar || ''"
alt=""
style="
width: 12vw;
min-width: 0;
border-radius: 50%;
aspect-ratio: 1/1;
object-fit: cover;
"
@error="handleAvatarImageError"
/>
<!-- 基本信息 -->
<div
style="
flex: 1;
min-width: 0;
align-self: stretch;
display: flex;
flex-direction: column;
justify-content: space-around;
gap: 4px;
"
>
<!-- 帮助按钮 -->
<img
v-smart-img
src="/src/assets/icon/Azizi/helpWhite.png"
alt=""
class="s4-x5"
@click="openPopup('help')"
/>
<!-- 名称 -->
<div
style="
max-width: 70%;
min-width: 0;
font-weight: 500;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
"
>
{{ userInfo.userNickname || '' }}
</div>
<div style="display: flex; justify-content: space-between; align-items: center">
<div style="min-width: 0">
{{ $t('user_id_prefix') }} {{ userInfo.account || '' }}
</div>
<div style="width: auto; font-weight: 600">
{{ t('current_earnings', { amount: currentAmount.availableAmount }) }}
</div>
</div>
</div>
</div>
<!-- 操作抽屉 -->
<div
style="
border-radius: 12px;
background:
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%
),
linear-gradient(0deg, #5d69ec 0%, #5d69ec 100%), #e8e8e8;
background-blend-mode: hard-light, normal, normal;
padding: 12px;
font-weight: 600;
display: flex;
flex-direction: column;
gap: 8px;
"
>
<!-- 转账功能 -->
<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="s4-x6"
src="/src/assets/icon/Azizi/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: 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="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: 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"
>
{{ 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: 12px;
border: 2px solid #fff;
background: linear-gradient(
264deg,
rgba(220, 228, 255, 0.4) 10.17%,
rgba(151, 176, 255, 0.4) 60.22%,
rgba(220, 228, 255, 0.4) 103.12%
);
box-shadow:
0 36.858px 13.981px 0 rgba(151, 176, 255, 0.02),
0 20.335px 12.71px 0 rgba(151, 176, 255, 0.08),
0 8.897px 8.897px 0 rgba(151, 176, 255, 0.13),
0 2.542px 5.084px 0 rgba(151, 176, 255, 0.15);
backdrop-filter: blur(4.5px);
padding: 12px 0;
"
>
<div
style="
font-weight: 590;
padding: 16px;
border-radius: 12px;
border: 2px solid #fff;
background: linear-gradient(
264deg,
rgba(220, 228, 255, 0.4) 10.17%,
rgba(151, 176, 255, 0.4) 60.22%,
rgba(220, 228, 255, 0.4) 103.12%
);
box-shadow:
0 36.858px 13.981px 0 rgba(151, 176, 255, 0.02),
0 20.335px 12.71px 0 rgba(151, 176, 255, 0.08),
0 8.897px 8.897px 0 rgba(151, 176, 255, 0.13),
0 2.542px 5.084px 0 rgba(151, 176, 255, 0.15);
backdrop-filter: blur(4.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/Azizi/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: 12px;
border: 2px solid #fff;
background: linear-gradient(
264deg,
rgba(220, 228, 255, 0.4) 10.17%,
rgba(151, 176, 255, 0.4) 60.22%,
rgba(220, 228, 255, 0.4) 103.12%
);
box-shadow:
0 36.858px 13.981px 0 rgba(151, 176, 255, 0.02),
0 20.335px 12.71px 0 rgba(151, 176, 255, 0.08),
0 8.897px 8.897px 0 rgba(151, 176, 255, 0.13),
0 2.542px 5.084px 0 rgba(151, 176, 255, 0.15);
backdrop-filter: blur(4.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="s4-x6"
src="/src/assets/icon/Azizi/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/Azizi/coin.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: 12px;
border: 2px solid #fff;
background: linear-gradient(
264deg,
rgba(220, 228, 255, 0.4) 10.17%,
rgba(151, 176, 255, 0.4) 60.22%,
rgba(220, 228, 255, 0.4) 103.12%
);
box-shadow:
0 36.858px 13.981px 0 rgba(151, 176, 255, 0.02),
0 20.335px 12.71px 0 rgba(151, 176, 255, 0.08),
0 8.897px 8.897px 0 rgba(151, 176, 255, 0.13),
0 2.542px 5.084px 0 rgba(151, 176, 255, 0.15);
backdrop-filter: blur(4.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="currentAmount.availableAmount >= 10"
>
<div>{{ t('go_to_withdraw') }}</div>
<img
v-smart-img
class="s4-x6"
src="/src/assets/icon/Azizi/arrowWhite.png"
alt=""
style="width: 1em; display: block"
/>
</div>
</div>
</div>
</div>
<!-- 我的排名占位 -->
<div v-show="rankShow" style="height: 25vw"></div>
<!-- 我的排名 -->
<itemCenter
v-show="rankShow"
style="position: fixed; bottom: 0; z-index: 2"
:imgUrl="imageUrl('myRankingBg')"
:contentStyle="`padding: 2vw 8vw 0`"
>
<!-- 基本信息 -->
<div
style="
flex: 1;
min-width: 0;
display: flex;
justify-content: space-around;
align-items: center;
gap: 8px;
"
>
<!-- 排名 -->
<div style="color: #ffe601; font-weight: 700">
{{ myRanking?.rank || 999 }}
</div>
<!-- 头像 -->
<img
:src="myRanking?.userAvatar || ''"
alt=""
style="
display: block;
width: 4em;
aspect-ratio: 1/1;
border-radius: 50%;
object-fit: cover;
"
@error="handleAvatarImageError"
/>
<!-- 名称 -->
<div style="flex: 1; min-width: 0; display: flex; flex-direction: column">
<div
style="
color: #fff;
font-weight: 860;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
"
class="s4-x3"
>
{{ myRanking?.userName }}
</div>
</div>
</div>
<!-- 贡献值 -->
<div
style="
width: auto;
min-width: 0;
display: flex;
align-items: center;
"
>
<div style="color: #fff; font-weight: 700">${{ myRanking?.amount || 0 }}</div>
</div>
</itemCenter>
<!-- 弹窗遮罩层 -->
<maskLayer :maskLayerShow="maskLayerShow" @click="closedPopup">
<div
style="
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
"
@click="closedPopup"
>
<!-- 抽奖结果 -->
<div v-if="resultShow" style="position: relative; width: 90%" @click.stop>
<itemCenter
:imgUrl="imageUrl('rewardBg')"
:contentStyle="`inset: 31vw 10vw 4vw;
flex-direction: column;
justify-content: space-between;
gap:2vw`"
>
<div
style="
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
"
>
<!-- 上一个奖品 -->
<div
style="
width: 8vw;
align-self: stretch;
display: flex;
justify-content: center;
align-items: center;
"
>
<img
v-smart-img
v-show="result.length > 1 && resultShowIndex > 0"
:src="imageUrl('rewardBack')"
alt=""
style="display: block; width: 100%; object-fit: cover"
@click="resultShowIndex--"
/>
</div>
<!-- 奖品 -->
<img
:src="result[resultShowIndex]?.prize?.prizeImage"
alt=""
width="50%"
style="display: block"
/>
<!-- 下一个奖品 -->
<div
style="
width: 8vw;
align-self: stretch;
display: flex;
justify-content: center;
align-items: center;
"
>
<img
v-smart-img
v-show="result.length > 1 && resultShowIndex + 1 < result.length"
:src="imageUrl('rewardNext')"
alt=""
style="display: block; width: 100%; object-fit: cover"
@click="resultShowIndex++"
/>
</div>
</div>
<div
style="
width: 100%;
height: 5vw;
text-align: center;
font-size: 0.9em;
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]?.prize?.prizeName }}
<div
v-if="result.length > 1"
style="
position: absolute;
z-index: 9999;
inset: 0;
padding-right: 8%;
display: flex;
justify-content: flex-end;
align-items: center;
font-size: 0.8em;
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>
<!-- 关闭弹窗按钮 -->
<div style="width: 30vw; height: 10vw" @click="closedPopup"></div>
</itemCenter>
</div>
<!-- 中奖历史 -->
<div v-if="historyShow" style="position: relative; width: 95%" @click.stop>
<itemCenter :imgUrl="imageUrl('historyBg')" :contentStyle="`padding: 22vw 4vw 4vw;`">
<div
style="
width: 100%;
height: 100%;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 8px;
"
class="scrollbar"
>
<div
v-for="(record, index) in myRecords"
style="
border-radius: 12px;
border: 2px solid #fff;
background: linear-gradient(
264deg,
rgba(220, 228, 255, 0.4) 10.17%,
rgba(151, 176, 255, 0.4) 60.22%,
rgba(220, 228, 255, 0.4) 103.12%
);
box-shadow: 0 2.542px 5.084px 0 rgba(151, 176, 255, 0.15);
backdrop-filter: blur(4.5px);
display: flex;
padding: 12px;
justify-content: space-between;
align-items: center;
"
>
<div style="display: flex; align-items: center; gap: 4px">
<img
:src="record.prize?.prizeImage || ''"
alt=""
style="width: 10vw; object-fit: cover; display: block; aspect-ratio: 1/1"
/>
<div style="font-weight: 590; font-size: 0.9em">
{{ record.prize?.prizeName }}
</div>
</div>
<div style="font-weight: 510; font-size: 0.8em">
{{ formatUTCCustom(record.drawTime) }}
</div>
</div>
</div>
</itemCenter>
</div>
<!-- 帮助弹窗 -->
<div v-if="helpShow" style="position: relative; width: 90%" @click.stop>
<itemCenter :imgUrl="imageUrl(getImgName('helpInfo'))" :contentStyle="``">
<div class="close-btn" @click="closedPopup"></div>
</itemCenter>
</div>
<!-- 规则弹窗 -->
<div v-if="ruleShow" style="position: relative; width: 90%" @click.stop>
<itemCenter :imgUrl="imageUrl(getImgName('ruleInfo'))" :contentStyle="``">
<div class="close-btn" @click="closedPopup"></div>
</itemCenter>
</div>
</div>
</maskLayer>
</div>
</div>
</template>
<script setup>
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
import { viewUserInfo } from '@/utils/appBridge.js'
import { useRoute, useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { setDocumentDirection } from '@/locales/i18n'
import { useLangStore } from '@/stores/lang'
import { getPngUrl, getWebpUrl } from '@/config/imagePaths.js'
import { connectToApp } from '@/utils/appConnector.js'
import { setUserInfo } from '@/utils/userStore.js'
import { formatUTCCustom } from '@/utils/utcFormat.js'
import { showError, showSuccess } from '@/utils/toast.js'
import { getSelectedPayee, clearSelectedPayee } from '@/utils/payeeStore.js'
import { handleAvatarImageError, handleRewardImageError } from '@/utils/image/imageHandler.js'
import { preloadImages, preloadImagesIdle } from '@/utils/image/imagePreloader.js'
import { useThrottle } from '@/utils/useDebounce'
import { getMemberProfile, getUserIdentity } from '@/api/wallet'
import {
ranklist, //获取排行榜
activityDetail, // 获取活动详情
myRecharge, // 获取充值记录
activityRewardConfigs, // 获取活动奖励配置列表
myTickets, // 获取剩余中奖券
myTotalDrawCount, // 获取我的累计抽奖次数
onceDraw, // 执行单次抽奖
multiDraw, // 执行连抽
drawRecords, // 获取中奖记录
ActTaskList, // 获取任务列表
rewardConfigsBadge, // 获取累计抽奖-徽章信息
receiveTickets, // 领取任务奖励
receiveRechargeReward, // 领取充值奖励
receiveRewardBadge, // 领取累计抽奖奖励-徽章
winnerHistory, //获取历史中奖用户
withdrawableAmount, //获取可提现金额
transferActivityDollar, // 转账活动美金
exchangeCoin, //兑换代币
} from '@/api/lottery'
import BackgroundLayer from '@/components/BackgroundLayer.vue'
import TopUser from './components/topUser.vue'
import Barrage from './components/Barrage.vue'
import itemCenter from '@/components/itemCenter.vue'
import maskLayer from '@/components/MaskLayer.vue'
const { t, locale } = useI18n()
const router = useRouter()
const route = useRoute()
const langStore = useLangStore()
// 当前语言类型
const currentLangType = computed(() => {
return langStore.selectedLang?.type || 'en'
})
const isLoading = ref(true) // 预加载状态
// 获取OSS图片URL的函数
const imageUrl = (filename) => getPngUrl('Activities/LuckyDollars/Season4/', filename)
const webpUrl = (filename) => getWebpUrl('Activities/LuckyDollars/Season4/', filename)
// 根据语言获取图片名
const getImgName = (filename) => {
return currentLangType.value === 'ar' ? `${filename}_ar` : filename
}
// 监听语言变化并设置文档方向
locale.value && setDocumentDirection(locale.value)
const reward = ref(false) //奖励标签页
const rankShow = ref(false) //排行榜标签页
const lotteryShow = ref(false) //抽奖标签页
const incomeShow = ref(false) //收益标签页
const RankingShow = computed(() => {
return rankShow.value || reward.value
})
const tabList = computed(() => {
if (RankingShow.value) {
return [
{ name: t('recharge_reward'), value: 'reward' },
{ name: t('ranking'), value: 'ranking' },
]
} else {
return [
{ name: t('lottery'), value: 'lottery' },
{ name: t('withdraw'), value: 'withdraw' },
]
}
})
// 遮罩层
const resultShow = ref(false)
const helpShow = ref(false)
const ruleShow = ref(false)
const historyShow = ref(false)
const maskLayerShow = computed(() => {
return helpShow.value || resultShow.value || historyShow.value || ruleShow.value
})
const barrageList = ref([]) // 弹幕数据
// 活动详情
const activityId = ref('2007771533988216322') //活动ID
const activityCode = ref('16322') //活动码
const activity = ref({}) //活动详情和奖池
const userInfo = ref({}) //用户信息
const userIdentity = ref({}) //用户身份
const myRechargeRecode = ref({}) //我的充值记录
const rechargehidden = ref(true) //金额是否隐藏
const rewardsList = ref([]) // 奖励列表
// 根据隐藏状态处理金额显示的方法
const formatRechargeAmount = (amount) => {
if (rechargehidden.value) {
// 如果隐藏,则将数字替换为*
return String(amount || '0').replace(/\d/g, '*')
} else {
// 如果不隐藏,则正常显示
return amount || '0'
}
}
const RankingLoadmore = ref(null) //触底模块
const rankingPageNo = ref(1) //分页页码
const ranking = ref([]) //原始排行榜
const rankingAdd = ref([]) //加载排行榜项
// 完整排行榜
const rankingTotal = computed(() => {
return [...ranking.value, ...rankingAdd.value]
})
const myRanking = ref({}) //我的排名
const topImg = ref([
imageUrl('RewardRecharge100'),
imageUrl('RewardRecharge500'),
imageUrl('RewardRecharge1000'),
imageUrl('RewardRecharge3000'),
imageUrl('RewardRecharge5000'),
imageUrl('RewardRecharge10000'),
]) // top图片
// 处理排行榜小于3人时的情况
const RankingHasTop3 = computed(() => {
let RankingTop3 = [...rankingTotal.value]
if (rankingTotal.value.length < 3) {
let addNullUser = Array.from({ length: 3 - rankingTotal.value.length }, () => ({
userAvatar: '',
userName: '',
amount: '',
}))
RankingTop3.push(...addNullUser)
}
return RankingTop3
})
// 展示用的榜单
const showRanking = computed(() => {
return rankingTotal.value.filter((_, index) => index >= 3)
// return []
})
const activeIndex = ref(-1) // 当前高亮格子
const isRolling = ref(false) // 抽奖状态
const rollTimes = ref(0) // 拥有抽奖券量
const totalDraw = ref({}) // 我的总抽奖次数
const currentAmount = ref({ availableAmount: 0 }) //可提现金额
const result = ref([]) // 抽奖结果
const resultShowIndex = ref(0)
const myRecords = ref([]) // 抽奖结果
const RechargeBadgeInfo = ref([]) //充值奖励-徽章信息
const transferShow = ref(false)
const exchangeShow = ref(false)
const withdrawShow = ref(false)
const selectedCoin = ref(null)
// 倒计时相关数据
const Days = ref(0)
const Hours = ref(0)
const Minutes = ref(0)
const Seconds = ref(0)
let countdownTimer = 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 handleBt = (type) => {
reward.value = type == 'reward' ? true : false
rankShow.value = type == 'ranking' ? true : false
lotteryShow.value = type == 'lottery' ? true : false
incomeShow.value = type == 'withdraw' ? true : false
drawerShowBt('') // 收起抽屉
selectedCoin.value = null // 清除选择币种
}
// 获取目标时间2026年5月1日上午5点北京时间
const getTargetTime = () => {
const target = new Date(2026, 4, 1, 5, 0, 0) // 月份从0开始10代表11月
return target.getTime()
}
// 计算倒计时
const calculateCountdown = () => {
const now = Date.now()
const targetTime = getTargetTime()
let diff = targetTime - now
// 如果已过期,清零并停止计时器
if (diff <= 0) {
Days.value = 0
Hours.value = '00'
Minutes.value = '00'
Seconds.value = '00'
if (countdownTimer) {
clearInterval(countdownTimer)
countdownTimer = null
}
return
}
// 计算天、小时、分钟、秒
const totalSeconds = Math.floor(diff / 1000)
Days.value = Math.floor(totalSeconds / (24 * 3600))
Hours.value = String(Math.floor((totalSeconds % (24 * 3600)) / 3600)).padStart(2, '0')
Minutes.value = String(Math.floor((totalSeconds % 3600) / 60)).padStart(2, '0')
Seconds.value = String(Math.floor(totalSeconds % 60)).padStart(2, '0')
}
// 启动倒计时
const startCountdown = () => {
calculateCountdown() // 立即执行一次
countdownTimer = setInterval(calculateCountdown, 1000)
}
// 判断文本是否溢出(需要滚动)
const isTextOverflow = (text) => {
// 创建临时元素来测量文本宽度
const tempDiv = document.createElement('div')
tempDiv.style.position = 'absolute'
tempDiv.style.visibility = 'hidden'
tempDiv.style.whiteSpace = 'nowrap'
tempDiv.style.fontSize = '1.5em'
tempDiv.style.fontWeight = '700'
tempDiv.style.textShadow = '0 1px 1px #712eb1'
tempDiv.style.lineHeight = '1.2em'
tempDiv.textContent = text
document.body.appendChild(tempDiv)
// 获取容器实际可用宽度
const containerWidth = window.innerWidth * 0.8 * 0.5 * 0.6 // 所在容器宽度
const textWidth = tempDiv.getBoundingClientRect().width
document.body.removeChild(tempDiv)
// 如果文本宽度超过容器宽度,则需要滚动
return textWidth > containerWidth
}
const taskList = ref([])
// 展示任务目标
const showTarget = (task) => {
if (task.targetType == 'MIC_TIME') {
let timeType = task.targetValue < 60
let currentValue = timeType ? task.currentValue : task.currentValue / 60
let targetValue = timeType ? task.targetValue : task.targetValue / 60
// 直接去除小数部分(向下取整)
currentValue = Math.floor(currentValue * 10) / 10
targetValue = Math.floor(targetValue * 10) / 10
let timeUnit = timeType ? t('minutes_short') : t('hours_short')
return t('on_mic_progress', {
current: currentValue,
total: targetValue,
unit: timeUnit,
})
} else if (task.targetType == 'SEND_GIFT') {
if (task.taskCode == 'SP_SEND_GIFT_5') {
return t('Send 5 Ramadan gifts ({currentValue}/{targetValue})', {
currentValue: task.currentValue,
targetValue: task.targetValue,
})
}
} else if (task.targetType == 'SAVE_COINS') {
if (task.taskCode == 'SP_SAVE_50000') {
return t('Win 50,000 coins in total across any games ({currentValue}/{targetValue})', {
currentValue: task.currentValue,
targetValue: task.targetValue,
})
} else if (task.taskCode == 'SP_SAVE_100000') {
return t('Win 100,000 coins in total across any games ({currentValue}/{targetValue})', {
currentValue: task.currentValue,
targetValue: task.targetValue,
})
} else if (task.taskCode == 'SP_SAVE_500000') {
return t('Win 500,000 coins in total across any games ({currentValue}/{targetValue})', {
currentValue: task.currentValue,
targetValue: task.targetValue,
})
}
} else if (task.targetType == 'RECHARGE_AMOUNT') {
if (task.taskCode == 'SP_RECHARGE_1') {
return t('Daily total recharge amount: $1 ({currentValue}/{targetValue})', {
currentValue: task.currentValue,
targetValue: task.targetValue,
})
} else if (task.taskCode == 'SP_RECHARGE_10') {
return t('Daily total recharge amount: $10 ({currentValue}/{targetValue})', {
currentValue: task.currentValue,
targetValue: task.targetValue,
})
} else if (task.taskCode == 'SP_RECHARGE_50') {
return t('Daily total recharge amount: $50 ({currentValue}/{targetValue})', {
currentValue: task.currentValue,
targetValue: task.targetValue,
})
} else if (task.taskCode == 'SP_RECHARGE_100') {
return t('Daily total recharge amount: $100 ({currentValue}/{targetValue})', {
currentValue: task.currentValue,
targetValue: task.targetValue,
})
}
} else {
return `${task.taskName}(${task.currentValue}/${task.targetValue})`
}
}
// 选中的收款人
const selectedPayee = ref({})
// 初始化收款人信息
const initializePayee = () => {
const savedPayee = getSelectedPayee()
if (savedPayee) {
Object.assign(selectedPayee.value, savedPayee)
handleBt('withdraw')
drawerShowBt('transfer')
}
}
// 清除当前选中的收款人
const clearPayee = () => {
Object.assign(selectedPayee.value, {
id: null,
account: '',
name: '',
avatar: '',
type: '',
isHost: false,
isAgency: false,
hasSalary: false,
})
clearSelectedPayee()
}
// 计算按钮背景图位置
const underlineStyle = computed(() => {
console.log('计算属性')
// 访问 locale.value 使其成为依赖项
const currentLocale = locale.value
console.log('当前语言:', currentLocale)
let star = true
if (reward.value || lotteryShow.value) {
star = true
} else {
star = false
}
return {
justifyContent: star ? 'flex-start' : 'flex-end',
}
})
// 前往搜索代理页
const searchPayee = () => {
router.push({
path: '/search-payee',
query: { from: '/activities/lucky-dollars-season4', activeAction: 'incomeShow' },
})
}
// 前往提现页
const goToWithdraw = () => {
router.push({ path: '/cash-out', query: { activityId: activityId.value } })
}
// 转账金币选项
const coinOptions = ref([
{ id: 1, price: 1 },
{ id: 2, price: 5 },
{ id: 3, 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: activityId.value,
}
try {
// 调用转账接口
const response = await transferActivityDollar(transferData)
if (response.status) {
showSuccess(
t('transfer_success', {
price: selectedCoin.value.price,
name: selectedPayee.value?.name,
}),
)
} else {
showError(t('transfer_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: activityId.value,
}
try {
// 调用转账接口
const response = await exchangeCoin(transferData)
if (response.status) {
showSuccess(t('exchange_success_coins'))
} else {
showError(t('exchange_failed_coins'))
}
// 重置选择
selectedCoin.value = null
getDrawableAmount() //刷新可提现金额
} catch (error) {
showError(error.errorMsg)
}
}
// 打开弹窗
const openPopup = (type) => {
closedPopup(false) //先关闭其他弹窗,不清除抽奖结果
switch (type) {
case 'result':
resultShow.value = true
break
case 'help':
helpShow.value = true
break
case 'history':
historyShow.value = true
break
case 'rule':
ruleShow.value = true
break
}
}
// 关闭弹窗
const closedPopup = (clear = true) => {
resultShow.value = false
helpShow.value = false
historyShow.value = false
ruleShow.value = false
if (clear) {
result.value = []
}
resultShowIndex.value = 0
}
//奖盘布局
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圈数
const roll = () => {
activeIndex.value = (activeIndex.value + 1) % activity.value.prizeList.length
console.log('当前索引:', activeIndex.value)
if (activeIndex.value === resultIndex && speed > 200) {
setTimeout(() => {
resolve() // 抽奖结束
}, 500)
} else {
if (activeIndex.value === activity.value.prizeList.length - 1) {
currentCycle++
}
// 加速旋转
if (currentCycle < totalCycles) {
speed -= 20
} else {
// 匀速旋转
if (activeIndex.value === activity.value.prizeList.length - 1) {
constantSpeedCycle++
}
if (constantSpeedCycle > 2) {
// 最后减速效果
speed += 20
}
}
setTimeout(roll, speed)
}
}
roll()
})
}
// 连抽
const sweepstakes = async (consecutive = 1) => {
if (isRolling.value) return // 防止重复点击
// 检查抽奖次数
if (rollTimes.value >= consecutive) {
isRolling.value = true
let data = {
activityId: activityId.value,
drawCount: consecutive,
}
try {
// 单抽
if (consecutive == 1) {
const resOnceDraw = await onceDraw(data)
if (resOnceDraw.status && resOnceDraw.body) {
getTotalDrawCount() //刷新累计抽奖次数
getConfigsBadgeInfo() //刷新累计抽奖-徽章信息
getTickets() //重新获取拥有的抽奖券
getDrawableAmount() //刷新可提现金额
result.value.push(resOnceDraw.body)
console.log('单抽结果:', resOnceDraw.body)
console.log('当前抽奖结果索引:', resultShowIndex.value)
console.log('单抽赋值结果:', result.value)
console.log('展示结果:', result.value[resultShowIndex.value])
console.log('展示结果:', result.value[0])
const resItem = resOnceDraw.body //接口获取的抽奖结果(单抽为对象)
//取抽奖结果的位置
const index = activity.value.prizeList.findIndex(
(prize) => prize.prizeName == resItem?.prize.prizeName,
) //转盘第几位停下
console.log('index:', index)
await startLottery(index)
}
}
//连抽
else {
const resMultiDraw = await multiDraw(data)
if (resMultiDraw.status && resMultiDraw.body) {
getTotalDrawCount() //刷新累计抽奖次数
getConfigsBadgeInfo() //刷新累计抽奖-徽章信息
getTickets() //重新获取拥有的抽奖券
getDrawableAmount() //刷新可提现金额
result.value = resMultiDraw.body.results
//取第一个抽奖结果的位置
let index = activity.value.prizeList.findIndex(
(prize) => prize.prizeName == result.value[0]?.prize.prizeName,
)
console.log('index:', index)
await startLottery(index)
}
}
getDrawRecords() // 获取中奖记录
openPopup('result') //打开中奖结果弹窗
isRolling.value = false
} catch (error) {
isRolling.value = false
if (error.response.errorCode == 3274) {
showError('Device has been used by another account')
}
}
}
}
//获取用户信息
const getUserInfo = async () => {
if (Object.keys(userInfo.value).length === 0) {
const resUserInfo = await getMemberProfile()
if (resUserInfo.status && resUserInfo.body) {
setUserInfo(resUserInfo.body, null)
userInfo.value = resUserInfo.body
}
}
const resIdentity = await getUserIdentity()
if (resIdentity.status && resIdentity.body) {
userIdentity.value = resIdentity.body
}
}
//获取排行榜
const getRanking = async () => {
let data = {
activityId: activityId.value,
pageNo: rankingPageNo.value,
pageSize: 20,
}
const resRanking = await ranklist(data)
if (resRanking.status && resRanking.body) {
myRanking.value = resRanking.body?.currentUser //我的排名信息
if (resRanking.body.topList.length > 0) {
if (resRanking.body.topList.length == 20) {
rankingAdd.value = []
ranking.value.push(...resRanking.body?.topList)
rankingPageNo.value++
} else {
rankingAdd.value = resRanking.body?.topList
}
}
} else {
ranking.value = []
myRanking.value = {}
}
}
//获取奖池
const getActivityDetail = async () => {
getDrawableAmount() //获取可提现金额
const resDetail = await activityDetail(activityCode.value)
if (resDetail.status && resDetail.body) {
activity.value = resDetail.body
} else {
activity.value = {}
}
}
//获取充值记录
const getMyRecharge = async () => {
const resMyRecharge = await myRecharge(activityId.value)
if (resMyRecharge.status && resMyRecharge.body) {
myRechargeRecode.value = resMyRecharge.body
} else {
myRechargeRecode.value = {}
}
}
//获取充值奖励列表
const getActivityReward = async () => {
let data = {
activityType: 'CONSUMPTION_ACTIVITY',
activityId: activityId.value,
}
const resActivityReward = await activityRewardConfigs(data)
if (resActivityReward.status && resActivityReward.body) {
rewardsList.value = resActivityReward.body.map((rewards) => {
let jsonData = JSON.parse(rewards.jsonData)
let addReward = []
if (rewards.sort == 1) {
addReward = [
// {
// type: 'TICKET',
// cover: imageUrl('ticket'),
// content: 10,
// },
]
} else if (rewards.sort == 2) {
addReward = [
{
type: 'TICKET',
cover: imageUrl('ticket'),
content: 15,
},
]
} else if (rewards.sort == 3) {
addReward = [
{
type: 'TICKET',
cover: imageUrl('ticket'),
content: 20,
},
]
} else if (rewards.sort == 4) {
addReward = [
{
type: 'TICKET',
cover: imageUrl('ticket'),
content: 30,
},
{
type: 'GIFT',
cover: imageUrl('reward_gift'),
content: 1,
},
]
} else if (rewards.sort == 5) {
addReward = [
{
type: 'TICKET',
cover: imageUrl('ticket'),
content: 40,
},
{
type: 'GIFT',
cover: imageUrl('reward_gift'),
content: 1,
},
]
} else if (rewards.sort == 6) {
addReward = [
{
type: 'TICKET',
cover: imageUrl('ticket'),
content: 50,
},
{
type: 'GIFT',
cover: imageUrl('reward_gift'),
content: 1,
},
{
type: 'PROPS',
detailType: 'AVATAR_FRAME',
cover: imageUrl('reward_frame'),
quantity: 365,
},
{
type: 'PROPS',
detailType: 'RIDE',
cover: imageUrl('reward_ride'),
quantity: 60,
},
]
}
rewards.rewardProps.push(...addReward) //补充奖励项
rewards = {
...rewards,
...jsonData,
}
return rewards
})
} else {
rewardsList.value = {}
}
}
//充值奖励的内容样式
const rewardContentLayer = (sort) => {
let gridStyle = ''
if (currentLangType.value == 'ar') {
gridStyle = 'direction: ltr;'
}
if (sort == '1') {
return `display: grid;grid-template-columns: repeat(3, 1fr);gap:5.5vw 6.5vw;padding: 23.5vw 5.5vw 29vw;${gridStyle}`
} else if (sort == '2' || sort == '3') {
return `display: grid;grid-template-columns: repeat(3, 1fr);gap:5.5vw 6.5vw;padding: 23.5vw 5.5vw 29vw;${gridStyle}`
} else if (sort == '4' || sort == '5' || sort == '6') {
return `display: grid;grid-template-columns: repeat(3, 1fr);gap:5.5vw 6.5vw;padding: 23.5vw 5.5vw 29vw;${gridStyle}`
}
}
// 格式化奖励的展示信息
const showDetail = (type, reward) => {
let showamount = ['GOLD', 'DIAMOND', 'GIFT', 'FRAGMENTS', 'TICKET']
if (showamount.includes(type)) {
return `*${reward.content}`
} else if (type === 'DOLLARS') {
return `$${reward.content}`
} else {
return `${reward.quantity}Days`
}
}
//获取拥有的抽奖券
const getTickets = async () => {
const resTickets = await myTickets(activityId.value)
if (resTickets.status && resTickets.body) {
rollTimes.value = resTickets.body
} else {
rollTimes.value = 0
}
}
//获取累计抽奖次数
const getTotalDrawCount = async () => {
const resTotalDrawCount = await myTotalDrawCount(activityId.value)
if (resTotalDrawCount.status && resTotalDrawCount.body) {
totalDraw.value = resTotalDrawCount.body
}
}
//可提现金额
const getDrawableAmount = async () => {
const resDrawableAmount = await withdrawableAmount(activityId.value)
if (resDrawableAmount.status && resDrawableAmount.body) {
currentAmount.value = resDrawableAmount.body
}
}
//获取任务列表
const getTaskList = async () => {
const resTaskList = await ActTaskList(activityId.value)
if (resTaskList.status && resTaskList.body) {
taskList.value = resTaskList.body
}
}
// 获取累计抽奖-徽章信息
const getConfigsBadgeInfo = async () => {
let data = {
activityType: 'USER_RECHARGE_DRAW',
activityId: activityId.value,
}
const resConfigsBadge = await rewardConfigsBadge(data)
if (resConfigsBadge.status && resConfigsBadge.body) {
RechargeBadgeInfo.value = resConfigsBadge.body?.[0]
}
}
//获取中奖记录
const getDrawRecords = async () => {
const resDrawRecords = await drawRecords(activityCode.value)
if (resDrawRecords.status && resDrawRecords.body) {
myRecords.value = resDrawRecords.body?.records || []
}
}
//获取中奖用户列表
const getWinners = async () => {
const resWinners = await winnerHistory(activityId.value)
if (resWinners.status && resWinners.body) {
barrageList.value = resWinners.body
}
}
// 领取任务奖励
const receiveTaskReward = async (code) => {
let data = {
activityId: activityId.value,
taskCode: code,
}
try {
const resReceive = await receiveTickets(data)
if (resReceive.status && resReceive.body) {
getTaskList() //获取任务列表
getTickets() //获取拥有的抽奖券
}
} catch (error) {
showError(error.errorMsg)
}
}
// 领取充值奖励
const receiveReward = async (rewards) => {
let data = {
activityType: rewards.activityType,
activityId: activityId.value,
ruleId: rewards.ruleId,
}
try {
const resReceive = await receiveRechargeReward(data)
if (resReceive.status && resReceive.body) {
getActivityReward() // 刷新充值奖励
}
} catch (error) {
showError(error.errorMsg)
}
}
// 领取累计抽奖奖励-徽章
const receiveRechargeBadge = async (rewards) => {
let data = {
activityType: rewards.activityType,
activityId: activityId.value,
ruleId: rewards.ruleId,
}
try {
const resReceive = await receiveRewardBadge(data)
if (resReceive.status && resReceive.body) {
getConfigsBadgeInfo() // 刷新累计抽奖-徽章信息
}
} catch (error) {
showError(error.errorMsg)
}
}
// 页面初始化数据
const initData = async () => {
await Promise.all([
getUserInfo(), //获取用户信息
initializePayee(), //获取收款人信息
getRanking(), //获取排行榜
getActivityDetail(), //获取奖池
getDrawRecords(), // 获取中奖记录
getMyRecharge(), //获取充值记录
getActivityReward(), //获得奖励列表
getTickets(), //获取拥有的抽奖券
getTotalDrawCount(), //获取我的累计抽奖次数
getTaskList(), //获取任务列表
getWinners(), //获取历史中奖用户
getConfigsBadgeInfo(), // 刷新累计抽奖-徽章信息
])
}
// 预加载关键图片
const preloadCriticalImages = async () => {
const criticalImages = [
// webpUrl('pageTop'),
imageUrl('bg0'),
imageUrl('bg1'),
imageUrl('bg2'),
imageUrl('bg3'),
imageUrl('myAvatarFrame'),
imageUrl('myInfoBg'),
imageUrl(getImgName('rankBt')),
imageUrl(getImgName('rankBtActive')),
imageUrl('rechargehidden'),
imageUrl('rechargeShow'),
imageUrl('rewardBg'),
imageUrl('rewardBack'),
imageUrl('rewardNext'),
imageUrl(getImgName('rewardReceive')),
imageUrl(getImgName('rewardReceived')),
imageUrl(getImgName('rewardReceiveNot')),
imageUrl('RewardRecharge100'),
imageUrl('RewardRecharge500'),
imageUrl('RewardRecharge1000'),
imageUrl('RewardRecharge3000'),
imageUrl('RewardRecharge5000'),
imageUrl('RewardRecharge10000'),
imageUrl('tagBtBg'),
imageUrl('tagsBg'),
imageUrl('timeBg'),
]
await preloadImages(criticalImages)
}
// 完成预加载
const completePreloading = async () => {
try {
// 执行所有初始化操作
await Promise.all([initData(), preloadCriticalImages()])
console.log('预加载完成,初始化数据成功')
} catch (error) {
console.error('预加载过程中发生错误:', error)
} finally {
isLoading.value = false
await registerRankingLoadObserver()
}
}
const registerRankingLoadObserver = async () => {
await nextTick()
observer.disconnect()
if (RankingLoadmore.value) {
console.log('监控加载模块')
observer.observe(RankingLoadmore.value)
}
}
// 预加载其他图片
const preloadOtherImages = async () => {
const criticalImages = [
imageUrl(getImgName('helpInfo')),
imageUrl(getImgName('historyBg')),
imageUrl(getImgName('historyBt')),
imageUrl('lottery'),
imageUrl(getImgName('lotteryBt')),
imageUrl(getImgName('lotteryBtActive')),
imageUrl('myRankingBg'),
imageUrl('RankingItem'),
imageUrl(getImgName('rulesBt')),
imageUrl(getImgName('ruleInfo')),
imageUrl('taskBtGo'),
imageUrl('taskBtReceive'),
imageUrl('taskBtReceived'),
imageUrl('taskGame'),
imageUrl('taskGift'),
imageUrl('taskRecharge'),
imageUrl('taskTalk'),
imageUrl('ticket'),
imageUrl('top1'),
imageUrl('top2'),
imageUrl('top3'),
imageUrl('reward_gift'),
imageUrl('reward_frame'),
imageUrl('reward_ride'),
]
await preloadImagesIdle(criticalImages)
}
// 使用工具函数连接APP
const connectToAppHandler = async () => {
await connectToApp(() => {
// 连接成功回调
completePreloading() // 完成预加载
})
}
// 触发节流获取排行榜
const debouceGetRanking = useThrottle(() => {
getRanking() //加载新的排行榜项
}, 1000)
// IntersectionObserver配置
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.intersectionRatio > 0 && rankingTotal.value.length != 0) {
console.log('触发RankingLoadmore加载')
debouceGetRanking()
}
})
})
// 组件挂载时检测环境
onMounted(() => {
console.log('route.query.activeAction:', route.query.activeAction)
if (route.query.activeAction == 'incomeShow') {
handleBt('withdraw')
} else {
handleBt('reward')
}
connectToAppHandler()
preloadOtherImages() // 预加载其他图片
startCountdown() //开启倒计时
underlineStyle.value // 触发计算属性更新
})
onUnmounted(() => {
observer.disconnect()
if (countdownTimer) {
clearInterval(countdownTimer)
countdownTimer = null
}
clearPayee() //清空收款人信息
})
</script>
<style lang="scss" scoped>
* {
color: #fff;
}
.fullPage {
width: 100vw;
min-height: 100vh;
background: linear-gradient(90deg, #140e64 0%, #4b0bb5 100%);
position: relative;
padding-bottom: 2vw;
}
/* 添加加载动画样式 */
.loading-container {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #666;
}
.scrollbar::-webkit-scrollbar {
display: none;
}
// 滚动效果样式
.scroll-wrapper {
display: flex;
width: fit-content;
}
.scroll-content {
display: flex;
align-items: center;
gap: 4px;
}
@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: 30px;
}
[dir='rtl'] .scroll-content {
margin-left: auto;
margin-right: 30px;
}
[dir='ltr'] .scroll-wrapper {
animation: scroll-left 5s linear infinite;
will-change: transform;
}
[dir='rtl'] .scroll-wrapper {
animation: scroll-right 5s linear infinite;
will-change: transform;
}
/* 金币网格 */
.coin-item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
// transition: all 0.2s;
aspect-ratio: 1/1;
border-radius: 12px;
border: 2px solid #fff;
background: linear-gradient(
264deg,
rgba(220, 228, 255, 0.4) 10.17%,
rgba(151, 176, 255, 0.4) 60.22%,
rgba(220, 228, 255, 0.4) 103.12%
);
box-shadow:
0 36.858px 13.981px 0 rgba(151, 176, 255, 0.02),
0 20.335px 12.71px 0 rgba(151, 176, 255, 0.08),
0 8.897px 8.897px 0 rgba(151, 176, 255, 0.13),
0 2.542px 5.084px 0 rgba(151, 176, 255, 0.15);
backdrop-filter: blur(4.5px);
}
.coin-item.selected {
border-radius: 12px;
border: 2px solid #80d7ff;
box-shadow:
-0.25px -0.25px 1px 0 #16bcff,
0.25px 0.25px 1px 0 #16bcff,
0 0 3px 0 rgba(22, 188, 255, 0.8),
0 0 5px 0 rgba(22, 188, 255, 0.6),
0 0 4px 0 rgba(0, 83, 117, 0.3);
}
.coin-item:active {
transform: scale(0.98);
}
.rotated {
transform: rotate(90deg);
}
.drawer-enter-active,
.drawer-leave-active {
transition: all 0.2s ease-out;
}
.drawer-enter-from,
.drawer-leave-to {
transform: translateY(-5px);
opacity: 0;
}
.help-btn {
display: block;
width: 16px;
position: absolute;
top: 4px;
right: 8px;
}
.close-btn {
position: absolute;
width: 8vw;
aspect-ratio: 1/1;
top: 6.5vw;
right: 8.8vw;
}
.barrage-container {
margin-top: 2vw;
}
.timeBox {
width: 50vw;
display: flex;
justify-content: center;
}
.timeText {
color: #fff;
font-weight: 590;
font-size: 1.2em;
margin-top: 1vw;
}
.timeGap {
width: 6px;
align-self: stretch;
display: flex;
justify-content: center;
align-items: center;
}
.s4-x2 {
margin-top: 90vw;
display: flex;
justify-content: space-between;
align-items: center;
}
.s4-x5 {
width: 5vw;
min-width: 0;
display: block;
position: absolute;
top: 5px;
right: 5px;
}
@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;
}
}
[dir='rtl'] .timeBox {
flex-direction: row-reverse;
}
[dir='rtl'] .s4-x2 {
flex-direction: row-reverse;
}
/* RTL支持 */
[dir='rtl'] .section-title {
text-align: right;
}
[dir='rtl'] .barrage-container {
}
[dir='rtl'] .s4-x6 {
transform: scaleX(-1);
}
[dir='rtl'] .help-btn {
left: 8px;
right: auto;
}
[dir='rtl'] .close-btn {
left: 8.8vw;
right: auto;
}
[dir='rtl'] .s4-x5 {
left: 5px;
right: auto;
}
[dir='rtl'] .s4-x6.rotated {
transform: scaleX(-1) rotate(90deg);
}
[dir='rtl'] .title-icon {
margin-left: 0;
margin-right: 10px;
}
[dir='rtl'] .s4-x4 {
flex-direction: row-reverse;
}
[dir='rtl'] .user-info {
text-align: right;
}
[dir='rtl'] .action-buttons {
grid-template-columns: 1fr 1fr;
}
</style>