1551 lines
48 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.

<!-- src/views/Activities/Game/index.vue -->
<template>
<div class="fullPage">
<!-- 预加载状态 -->
<div v-if="isLoading" class="loading-container">
<!-- 页面背景 -->
<BackgroundLayer :backgroundImages="[imageUrl('bg')]" />
<img
v-smart-img
:src="imageUrl('bg2')"
alt=""
style="display: block; width: 100%; position: absolute; inset: 80vw 0 0; z-index: -1"
/>
<!-- 加载动画 -->
<div class="loading-spinner"></div>
<p>{{ $t('loading') }}...</p>
</div>
<!-- 主要内容 -->
<div v-else>
<!-- 新增的背景图层 -->
<img
v-smart-img
:src="imageUrl('bg2')"
alt=""
style="display: block; width: 100%; position: absolute; inset: 80vw 0 0; z-index: 0"
/>
<div class="bg">
<itemCenter
:imgUrl="imageUrl('bg')"
style="min-height: 100vw; position: absolute; z-index: 0"
>
<img
v-smart-img
:src="webpUrl('bg')"
alt=""
style="min-height: 100vw; display: block; width: 100%; object-fit: cover"
/>
</itemCenter>
<!-- 状态栏占位区域仅在APP中显示 -->
<div style="height: 30px"></div>
<!-- 第一名 -->
<div style="display: flex; justify-content: center; margin-top: 11vw">
<TopUser
ranking="1"
:BorderImgUrl="imageUrl('top1')"
:avatarUrl="RankingHasTop10[0].avatar"
:name="RankingHasTop10[0].nickname"
:distributionValue="RankingHasTop10[0].quantity || ''"
style="width: 55%"
@click="viewUserInfo(RankingHasTop10[0].userId)"
/>
</div>
<!-- 按钮 -->
<div style="margin-top: 6vw; display: flex; justify-content: flex-end; align-items: center">
<!-- 帮助按钮 -->
<img
v-smart-img
:src="imageUrl('helpBt')"
alt=""
style="display: block; position: relative; width: 8vw; margin-right: 4vw"
@click="openPopup('help')"
/>
</div>
<!-- 倒计时 -->
<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="">{{ Second }}</div>
</itemCenter>
</div>
</div>
<!-- 切换按钮 -->
<div>
<div style="display: flex; justify-content: space-around; margin-top: 2vw">
<!-- 历史模块按钮 -->
<div style="width: 30%; position: relative" @click="changeModule('history')">
<img
v-smart-img
:src="imageUrl(getImgName('historyBtActive'))"
alt=""
:class="{
'grayscale-container': !historyShow,
}"
style="display: block; width: 100%"
/>
</div>
<!-- 排行榜模块按钮 -->
<div style="width: 30%; position: relative" @click="changeModule('ranking')">
<img
v-smart-img
:src="imageUrl(getImgName('rankingBtActive'))"
alt=""
:class="{
'grayscale-container': !rankingShow,
}"
style="display: block; width: 100%"
/>
</div>
<!-- 奖励模块按钮 -->
<div style="width: 30%; position: relative" @click="changeModule('rewards')">
<img
v-smart-img
:src="imageUrl(getImgName('rewardBtActive'))"
alt=""
:class="{
'grayscale-container': !rewardsShow,
}"
style="display: block; width: 100%"
/>
</div>
</div>
</div>
<!-- 模块 -->
<div>
<!-- history -->
<div
v-show="historyShow"
style="display: flex; flex-direction: column; align-items: center"
>
<!-- 历史榜首 -->
<itemCenter
style="min-height: 110.3vw"
:imgUrl="imageUrl(getImgName('historyTopBg'))"
:contentStyle="`inset: 25vw 5vw 4vw;
flex-direction: column;
justify-content: center;
gap:2vw`"
>
<!-- 主要内容 -->
<div
style="
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
gap: 2vw;
"
>
<!-- 上一周榜首按钮 -->
<div
style="
width: 8vw;
align-self: stretch;
display: flex;
justify-content: center;
align-items: center;
"
>
<img
v-smart-img
v-show="historyTopList.length > 1 && historyTopIndex > 0"
:src="imageUrl('topBackBt')"
alt=""
class="flipImg"
style="display: block; width: 100%; object-fit: cover"
@click="historyTopIndex--"
/>
</div>
<!-- 榜首 -->
<TopUser
:BorderImgUrl="imageUrl('historyTopFrame')"
:avatarUrl="historyTopList[historyTopIndex].topUser.avatar"
:name="historyTopList[historyTopIndex].topUser.nickname"
:distributionValue="historyTopList[historyTopIndex].topUser.quantity || ''"
style="flex: 1; min-width: 0"
@click="viewUserInfo(historyTopList[historyTopIndex].topUser.userId)"
/>
<!-- 下一周榜首按钮 -->
<div
style="
width: 8vw;
align-self: stretch;
display: flex;
justify-content: center;
align-items: center;
"
>
<img
v-smart-img
v-show="
historyTopList.length > 1 && historyTopIndex + 1 < historyTopList.length
"
:src="imageUrl('topNextBt')"
alt=""
class="flipImg"
style="display: block; width: 100%; object-fit: cover"
@click="historyTopIndex++"
/>
</div>
</div>
<!-- 结算时间 -->
<div
style="
font-size: 1.3em;
font-weight: 590;
background-image: -webkit-linear-gradient(
top,
rgb(243, 183, 0),
rgb(255, 238, 198)
);
background-clip: text;
-webkit-text-fill-color: transparent;
"
>
{{ historyTopList[historyTopIndex].cycleDisplay }}
</div>
</itemCenter>
<!-- 特殊奖励 -->
<img
v-smart-img
:src="imageUrl(getImgName('specialRewardsNew'))"
alt=""
style="display: block; width: 100%; object-fit: cover"
/>
</div>
<!-- Ranking -->
<div v-show="rankingShow">
<!-- 切换按钮 -->
<div style="display: flex; justify-content: space-around; margin-top: 2vw">
<!-- 周榜模块按钮 -->
<div style="width: 40%; position: relative" @click="changeRanking('week')">
<itemCenter
style="min-height: 8vw"
:imgUrl="imageUrl('BtBg')"
:contentStyle="`padding-top: 1vw;`"
:class="{
'grayscale-container': !weekShow,
}"
>
<div style="font-weight: 700; font-size: 1.3em">{{ t('weekly_rank') }}</div>
</itemCenter>
</div>
<!-- 日榜模块按钮 -->
<div style="width: 40%; position: relative" @click="changeRanking('daily')">
<itemCenter
style="min-height: 8vw"
:imgUrl="imageUrl('BtBg')"
:contentStyle="`padding-top: 1vw;`"
:class="{
'grayscale-container': !dailyShow,
}"
>
<div style="font-weight: 700; font-size: 1.3em">{{ t('daily_rank') }}</div>
</itemCenter>
</div>
</div>
<!-- 周榜 -->
<div v-show="weekShow" style="position: relative; width: 100%; margin: 4px 0 10px">
<div style="position: relative; z-index: 1">
<!-- 第2-4名 -->
<itemCenter
style="min-height: 132.2vw"
:imgUrl="imageUrl(getImgName('RankingMain'))"
:contentStyle="`padding: 25% 4% 0;flex-direction: column;`"
>
<div>
<!-- 第2名 -->
<div style="display: flex; justify-content: center">
<TopUser
ranking="2"
:BorderImgUrl="imageUrl('top2')"
:avatarUrl="RankingHasTop10[1].avatar"
:name="RankingHasTop10[1].nickname"
:distributionValue="RankingHasTop10[1].quantity || ''"
style="width: 40%"
@click="viewUserInfo(RankingHasTop10[1].userId)"
/>
</div>
<!-- 第3-4名 -->
<div style="display: flex; justify-content: space-between; margin-top: -5vw">
<TopUser
ranking="3"
:BorderImgUrl="imageUrl('top3')"
:avatarUrl="RankingHasTop10[2].avatar"
:name="RankingHasTop10[2].nickname"
:distributionValue="RankingHasTop10[2].quantity || ''"
style="width: 38%"
@click="viewUserInfo(RankingHasTop10[2].userId)"
/>
<TopUser
ranking="4"
:BorderImgUrl="imageUrl('top4')"
:avatarUrl="RankingHasTop10[3].avatar"
:name="RankingHasTop10[3].nickname"
:distributionValue="RankingHasTop10[3].quantity || ''"
style="width: 38%"
@click="viewUserInfo(RankingHasTop10[3].userId)"
/>
</div>
</div>
</itemCenter>
<!-- 第5-10名 -->
<itemCenter
style="min-height: 90.13vw"
:imgUrl="imageUrl('RankingCenterBg')"
:contentStyle="`padding: 0 5%;flex-direction: column;justify-content: space-around;`"
>
<!-- 5-7 -->
<div style="width: 100%; display: flex; justify-content: space-between">
<TopUser
v-for="topUser in RankingHasTop10.slice(4, 7)"
:key="topUser.userId"
ranking="5-7"
:BorderImgUrl="imageUrl('top5_7')"
:avatarUrl="topUser.avatar"
:name="topUser.nickname"
:distributionValue="topUser.quantity || ''"
style="width: 30%"
@click="viewUserInfo(topUser.userId)"
/>
</div>
<!-- 8-10 -->
<div style="width: 100%; display: flex; justify-content: space-between">
<TopUser
v-for="topUser in RankingHasTop10.slice(7, 10)"
:key="topUser.userId"
ranking="8-10"
:BorderImgUrl="imageUrl('top8_10')"
:avatarUrl="topUser.avatar"
:name="topUser.nickname"
:distributionValue="topUser.quantity || ''"
style="width: 30%"
@click="viewUserInfo(topUser.userId)"
/>
</div>
</itemCenter>
<!-- 第11名开始 -->
<div v-if="showRanking.length > 0" style="position: relative; z-index: 2">
<itemCenter
style="min-height: 26.4vw"
v-for="(listItem, index) in showRanking"
:key="listItem.userId"
:imgUrl="imageUrl('RankingItem')"
:contentStyle="`padding: 0 10%`"
: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: 8px;
"
>
<!-- 排名 -->
<div style="color: #ffe601; font-weight: 700">
{{ listItem?.rank }}
</div>
<!-- 头像 -->
<img
:src="listItem?.avatar || ''"
alt=""
style="
display: block;
width: 13vw;
aspect-ratio: 1/1;
border-radius: 50%;
object-fit: cover;
"
@error="handleAvatarImageError"
/>
<!-- 名称、id -->
<div
style="
flex: 1;
min-width: 0;
align-self: stretch;
display: flex;
flex-direction: column;
justify-content: space-around;
"
>
<div
style="
color: #fff;
font-weight: 860;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
"
class="UserNickname"
>
{{ listItem?.nickname }}
</div>
<div style="color: #fff; font-weight: 590" class="UserNickname">
{{ $t('user_id_prefix') }} {{ listItem?.account }}
</div>
</div>
</div>
<!-- 贡献值 -->
<div
style="
width: auto;
min-width: 0;
display: flex;
align-items: center;
"
>
<img
v-smart-img
src="/src/assets/icon/coin.png"
alt=""
style="display: block; width: 1.5em; aspect-ratio: 1/1; object-fit: cover"
/>
<div style="color: #ffe601; font-weight: 700" class="UserNickname">
{{ listItem?.quantity }}
</div>
</div>
</itemCenter>
</div>
<!-- 底框 -->
<img
v-smart-img
:src="imageUrl('RankingBottomBorder')"
alt=""
width="100%"
style="display: block; margin-top: -6vw; position: relative; z-index: 2"
/>
</div>
</div>
<!-- 日榜 -->
<div v-show="dailyShow" style="position: relative; width: 100%; margin: 4px 0 10px">
<div style="position: relative; z-index: 1">
<!-- 头部 -->
<itemCenter
style="min-height: 132.2vw"
:imgUrl="imageUrl(getImgName('RankingMain'))"
:contentStyle="`padding: 25% 0 0;flex-direction: column;`"
>
<!-- 前3名 -->
<itemCenter
style="z-index: 0"
:imgUrl="imageUrl('top1-3FrameDaily')"
:contentStyle="`flex-direction: column;padding: 17vw 9.5vw 7vw 10.2vw;justify-content: space-between;`"
>
<!-- 第1名 -->
<div style="display: flex; justify-content: center">
<TopUserDaily
ranking="1"
:avatarUrl="RankingDailyHasTop3[0].avatar"
:name="RankingDailyHasTop3[0].nickname"
:distributionValue="RankingDailyHasTop3[0].quantity || ''"
style="width: 40%"
@click="viewUserInfo(RankingDailyHasTop3[0].userId)"
/>
</div>
<!-- 第2-3名 -->
<div style="margin-top: -5vw" class="top2-3">
<TopUserDaily
ranking="2"
:avatarUrl="RankingDailyHasTop3[1].avatar"
:name="RankingDailyHasTop3[1].nickname"
:distributionValue="RankingDailyHasTop3[1].quantity || ''"
style="width: 38%"
@click="viewUserInfo(RankingDailyHasTop3[1].userId)"
/>
<TopUserDaily
ranking="3"
:avatarUrl="RankingDailyHasTop3[2].avatar"
:name="RankingDailyHasTop3[2].nickname"
:distributionValue="RankingDailyHasTop3[2].quantity || ''"
style="width: 38%"
@click="viewUserInfo(RankingDailyHasTop3[2].userId)"
/>
</div>
</itemCenter>
</itemCenter>
<!-- 第4名开始 -->
<div
v-if="showRankingDaily.length > 0"
style="margin-top: -2vw; position: relative; z-index: -1"
>
<itemCenter
style="min-height: 26.4vw"
v-for="(listItem, index) in showRankingDaily"
:key="listItem.userId"
:imgUrl="imageUrl('RankingItem')"
:contentStyle="`padding: 0 10%`"
: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: 8px;
"
>
<!-- 排名 -->
<div style="color: #ffe601; font-weight: 700">
{{ listItem?.rank }}
</div>
<!-- 头像 -->
<img
:src="listItem?.avatar || ''"
alt=""
style="
display: block;
width: 13vw;
aspect-ratio: 1/1;
border-radius: 50%;
object-fit: cover;
"
@error="handleAvatarImageError"
/>
<!-- 名称、id -->
<div
style="
flex: 1;
min-width: 0;
align-self: stretch;
display: flex;
flex-direction: column;
justify-content: space-around;
"
>
<div
style="
color: #fff;
font-weight: 860;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
"
class="UserNickname"
>
{{ listItem?.nickname }}
</div>
<div style="color: #fff; font-weight: 590" class="UserNickname">
{{ $t('user_id_prefix') }} {{ listItem?.account }}
</div>
</div>
</div>
<!-- 贡献值 -->
<div
style="
width: auto;
min-width: 0;
display: flex;
align-items: center;
"
>
<img
v-smart-img
src="/src/assets/icon/coin.png"
alt=""
style="display: block; width: 1.5em; aspect-ratio: 1/1; object-fit: cover"
/>
<div style="color: #ffe601; font-weight: 700" class="UserNickname">
{{ listItem?.quantity }}
</div>
</div>
</itemCenter>
</div>
<!-- 底框 -->
<img
v-smart-img
:src="imageUrl('RankingBottomBorder')"
alt=""
width="100%"
style="display: block; margin-top: -6vw; position: relative; z-index: 2"
/>
</div>
</div>
</div>
<!-- Rewards -->
<div
v-show="rewardsShow"
style="display: flex; flex-direction: column; align-items: center"
>
<!-- 切换按钮 -->
<div style="display: flex; justify-content: space-around; margin-top: 2vw">
<!-- 周榜奖励模块按钮 -->
<div style="width: 40%; position: relative" @click="changeRanking('week')">
<itemCenter
style="min-height: 8vw"
:imgUrl="imageUrl('BtBg')"
:contentStyle="`padding-top: 1vw;`"
:class="{
'grayscale-container': !weekShow,
}"
>
<div style="font-weight: 700; font-size: 1.3em">{{ t('weekly_rewards') }}</div>
</itemCenter>
</div>
<!-- 日榜奖励模块按钮 -->
<div style="width: 40%; position: relative" @click="changeRanking('daily')">
<itemCenter
style="min-height: 8vw"
:imgUrl="imageUrl('BtBg')"
:contentStyle="`padding-top: 1vw;`"
:class="{
'grayscale-container': !dailyShow,
}"
>
<div style="font-weight: 700; font-size: 1.3em">{{ t('daily_rewards') }}</div>
</itemCenter>
</div>
</div>
<!-- 周榜奖励模块 -->
<div
v-show="weekShow"
v-for="(rewardsTop, top) in rewardsList"
:key="top"
style="position: relative; width: 100%; margin: 4px 0 10px"
>
<!-- 第一名奖励 -->
<itemCenter
style="min-height: 110.3vw"
v-if="top == 0"
:imgUrl="topImg[0]"
:contentStyle="`display: grid;grid-template-columns: repeat(2, 1fr);gap: 2vw;padding: 28vw 4vw 8vw 37vw;`"
>
<div
v-for="(reward, rewardIndex) in rewardsTop.rewards"
:key="rewardIndex"
style="
width: 100%;
min-width: 0;
align-self: stretch;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
"
>
<div
style="
width: 100%;
aspect-ratio: 1/1;
display: flex;
justify-content: center;
align-items: center;
"
>
<!-- 奖励图片 -->
<img
:src="reward.cover || ''"
alt=""
style="display: block; width: 70%; object-fit: cover"
@error="(e) => handleRewardImageError(e, reward.type)"
/>
</div>
<!-- 数值 -->
<div
style="
width: 100%;
display: flex;
justify-content: center;
align-items: center;
"
>
<div
style="
min-width: 0;
color: #f9e447;
text-align: center;
font-size: 1.2em;
font-weight: 900;
"
>
{{ showDetail(reward.type, reward) }}
</div>
</div>
</div>
<!-- 启动时间 -->
<div
style="
position: absolute;
left: 3.5vw;
bottom: 10vw;
width: 28vw;
display: flex;
justify-content: center;
align-items: center;
"
>
<div
style="color: #f9e447; text-align: center; font-size: 1.2em; font-weight: 900"
>
7Days
</div>
</div>
</itemCenter>
<!-- 第2-4、5-7、8-10名奖励 -->
<itemCenter
v-else
style="min-height: 110.3vw"
:imgUrl="topImg[Number(rewardsTop.rankRange) - 1]"
:contentStyle="`display: grid;grid-template-columns: repeat(3, 1fr);gap: 4vw;padding: 28vw 3vw 10vw;`"
>
<div
v-for="(reward, rewardIndex) in rewardsTop.rewards"
:key="rewardIndex"
style="width: 100%"
:style="rewardIndex == 3 ? `grid-row: 2;grid-column: 2;` : ''"
>
<div
style="
width: 100%;
aspect-ratio: 1/1;
display: flex;
justify-content: center;
align-items: center;
"
>
<!-- 奖励图片 -->
<img
:src="reward.cover || ''"
alt=""
style="display: block; width: 70%; object-fit: cover"
@error="(e) => handleRewardImageError(e, reward.type)"
/>
</div>
<!-- 数值 -->
<div
style="
width: 100%;
display: flex;
justify-content: center;
align-items: center;
"
>
<div
style="
min-width: 0;
color: #f9e447;
text-align: center;
font-size: 1.2em;
font-weight: 900;
"
>
{{ showDetail(reward.type, reward) }}
</div>
</div>
</div>
</itemCenter>
</div>
<!-- 日榜奖励模块 -->
<img
v-show="dailyShow"
v-for="(value, index) in 3"
:src="imageUrl(`top${index + 1}RewardDaily`)"
alt=""
style="width: 100%; margin: 4px 0 10px"
/>
</div>
</div>
<!-- 我的排名占位 -->
<div v-if="rankingShow" style="height: 22vw"></div>
<!-- 我的排名 -->
<itemCenter
v-if="rankingShow"
style="min-height: 24.33vw; position: fixed; bottom: 0; z-index: 3"
:imgUrl="imageUrl('myRankingBg')"
:contentStyle="`padding: 0 8%`"
>
<!-- 基本信息 -->
<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.avatar || ''"
alt=""
style="
display: block;
width: 15vw;
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="UserNickname"
>
{{ myRanking.nickname }}
</div>
</div>
</div>
<!-- 贡献值 -->
<div
style="
width: auto;
min-width: 0;
display: flex;
align-items: center;
"
>
<img
v-smart-img
src="/src/assets/icon/coin.png"
alt=""
style="display: block; width: 1.5em; aspect-ratio: 1/1; object-fit: cover"
/>
<div style="color: #ffe601; font-weight: 700">
{{ myRanking.quantity || 0 }}
</div>
</div>
</itemCenter>
<!-- 弹窗遮罩层 -->
<maskLayer :maskLayerShow="maskLayerShow" @click="closedPopup">
<!-- 居中弹窗 -->
<div
style="
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
"
@click="closedPopup"
>
<!-- help弹窗 -->
<div v-show="helpShow" @click.stop>
<itemCenter
style="min-height: 156.33vw"
:imgUrl="imageUrl(getImgName('helpBg'))"
:contentStyle="`inset: 15% 8% 3%;overflow-y: auto;display:block;`"
>
<img
v-smart-img
:src="imageUrl(getImgName('helpInfo'))"
alt=""
style="display: block; width: 100%; object-fit: cover; margin-bottom: 6vw"
/>
</itemCenter>
</div>
<!-- 每日弹窗 -->
<div v-show="dailyPopUpShow" @click.stop>
<itemCenter
style="min-height: 147.2vw"
:imgUrl="imageUrl(getImgName('dailyPopUpNew'))"
:contentStyle="`z-index: 0;`"
>
<!-- 关闭按钮 -->
<div
style="
display: block;
position: absolute;
z-index: 9;
width: 8vw;
top: 3vw;
right: 2vw;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
user-select: none;
touch-action: manipulation;
"
@click="closedPopup"
@touchend="closedPopup"
>
<img
v-smart-img
:src="imageUrl('closeBt')"
alt=""
style="display: block; width: 100%; pointer-events: none"
/>
</div>
</itemCenter>
</div>
</div>
</maskLayer>
</div>
</div>
</div>
</template>
<script setup>
import { computed, onMounted, onUnmounted, ref } from 'vue'
import { viewUserInfo } from '@/utils/appBridge.js'
import { connectToApp } from '@/utils/appConnector.js'
import { useLangStore } from '@/stores/lang'
import { getPngUrl, getWebpUrl } from '@/config/imagePaths.js'
import { preloadImages } from '@/utils/image/imagePreloader.js'
import { handleAvatarImageError, handleRewardImageError } from '@/utils/image/imageHandler.js'
import { useGamesKingStore } from '@/stores/gamesKing'
import { storeToRefs } from 'pinia'
import { useI18n } from 'vue-i18n'
import {
getThisWeekRewardsAndGifts, // 获取本周奖励和礼物
getRankingListAndMyRanking, // 获取排行榜和我的排名
getHistoryTopOne, // 获取历史榜首
activityResource, // 活动特定资源
} from '@/api/activity.js'
import BackgroundLayer from '@/components/BackgroundLayer.vue'
import itemCenter from '@/components/itemCenter.vue'
import TopUser from './components/topUser.vue'
import TopUserDaily from './components/topUserDaily.vue'
import maskLayer from '@/components/MaskLayer.vue'
const gamesKingStore = useGamesKingStore()
// 预加载状态
const isLoading = ref(true)
const { t, locale } = useI18n()
const langStore = useLangStore()
// 当前语言类型
const currentLangType = computed(() => {
return langStore.selectedLang?.type || 'en'
})
// 获取OSS图片URL的函数
const imageUrl = (filename) => getPngUrl('Ranking/GamesKing/', filename)
const webpUrl = (filename) => getWebpUrl('Ranking/GamesKing/', filename)
// 根据语言获取图片名
const getImgName = (filename) => {
return currentLangType.value === 'ar' ? `${filename}_ar` : filename
}
const {
checkDate, // 对应周几
checkStatus, // 是否已看过
} = storeToRefs(gamesKingStore)
const helpShow = ref(false) //帮助模块
const dailyPopUpShow = ref(false)
const maskLayerShow = computed(() => {
return helpShow.value || dailyPopUpShow.value
})
// 打开弹窗
const openPopup = (type) => {
closedPopup() //先关闭其他弹窗
switch (type) {
case 'help':
helpShow.value = true
break
case 'dailyPopUp':
dailyPopUpShow.value = true
break
default:
break
}
}
// 关闭弹窗
const closedPopup = () => {
console.log('点击关闭弹窗')
// 关闭所有弹窗
helpShow.value = false
dailyPopUpShow.value = false
// 此时打开的是每日弹窗,设置为已看过
if (dailyPopUpShow.value) {
checkStatus.value = true
}
}
// 检查今日是否已看过
const checkShow = () => {
const now = new Date()
const dailyDate = now.getMonth() + '-' + now.getDate()
if (dailyDate != checkDate.value) {
checkDate.value = dailyDate // 更新周几
checkStatus.value = false // 更新今日状态
openPopup('dailyPopUp')
} else if (!checkStatus.value) {
openPopup('dailyPopUp')
}
}
// 倒计时
const Days = ref(0)
const Hours = ref(0)
const Minutes = ref(0)
const Second = ref(0)
let timer = null
// 模块切换展示
const historyShow = ref(false) //历史榜首
const rankingShow = ref(true) //排行榜
const rewardsShow = ref(false) //奖励模块
const changeModule = (module) => {
switch (module) {
case 'history':
historyShow.value = true
rankingShow.value = false
rewardsShow.value = false
break
case 'ranking':
historyShow.value = false
rankingShow.value = true
rewardsShow.value = false
break
case 'rewards':
historyShow.value = false
rankingShow.value = false
rewardsShow.value = true
}
}
const historyTopList = ref([]) // 历史榜首
const historyTopIndex = ref(0)
const weekShow = ref(true) // 周榜展示
const dailyShow = ref(false) // 日榜展示
const RankingWeek = ref([]) // 周榜
const RankingDaily = ref([]) // 日榜
const myWeekRanking = ref({}) // 我的周排名
const myDailyRanking = ref({}) // 我的日排名
const rewardsList = ref([]) // 奖励列表
const myRanking = computed(() => {
if (weekShow.value) {
return myWeekRanking.value
}
return myDailyRanking.value
}) // 我的排名
// 榜单切换
const changeRanking = (type) => {
switch (type) {
case 'week':
weekShow.value = true
dailyShow.value = false
break
case 'daily':
weekShow.value = false
dailyShow.value = true
break
}
}
const topImg = ref([
imageUrl('top1RewardBg'),
imageUrl('top2_4RewardBg'),
imageUrl('top5_7RewardBg'),
imageUrl('top8_10RewardBg'),
]) // top奖励背景
// 处理周榜小于10人时的情况
const RankingHasTop10 = computed(() => {
let RankingShow = [...RankingWeek.value]
if (RankingWeek.value.length < 10) {
let addNullUser = Array.from({ length: 10 - RankingWeek.value.length }, () => ({
avatar: '',
nickname: '',
quantity: '',
}))
RankingShow.push(...addNullUser)
}
return RankingShow
})
// 展示用的周榜
const showRanking = computed(() => {
return RankingWeek.value.filter((_, index) => index >= 10)
// return []
})
// 处理日榜小于3人时的情况
const RankingDailyHasTop3 = computed(() => {
let RankingShow = [...RankingDaily.value]
if (RankingDaily.value.length < 3) {
let addNullUser = Array.from({ length: 3 - RankingDaily.value.length }, () => ({
avatar: '',
nickname: '',
quantity: '',
}))
RankingShow.push(...addNullUser)
}
return RankingShow
})
// 展示用的日榜
const showRankingDaily = computed(() => {
return RankingDaily.value.filter((_, index) => index >= 3)
// return []
})
// 获取对应的时间戳
const getNextMondayInBeijing = () => {
const now = new Date()
const targetDate = new Date(now.getTime()) // 创建一个基于当前时间的新日期对象
// 转换为北京时间来判断星期几
const utcTime = now.getTime() + now.getTimezoneOffset() * 60000
const beijingTime = new Date(utcTime + 8 * 3600000) // UTC+8
const beijingDay = beijingTime.getDay() // 0=周日, 1=周一, ..., 6=周六
const beijingHour = beijingTime.getHours()
// 转换为 0=周一, 1=周二, ..., 6=周日
const normalizedDay = beijingDay === 0 ? 6 : beijingDay - 1
let daysToAdd
if (normalizedDay === 0) {
// 今天是周一
if (beijingHour >= 5) {
daysToAdd = 7 // 超过5点计算到下周一的所需时间
} else {
daysToAdd = 0 // 今天
}
} else {
daysToAdd = 7 - normalizedDay // 到下周一的天数
}
// 正确地添加天数
targetDate.setDate(targetDate.getDate() + daysToAdd) // 添加天数到下周一的当前时间
targetDate.setHours(5, 0, 0, 0) // 将时间重新设置为早上5点作为目标时间戳
return targetDate.getTime()
}
const targetTime = ref(getNextMondayInBeijing()) // 闭包保存目标时间 (核心修正)
// 格式化时间
const formatTime = (value) => {
return value < 10 ? `0${value}` : value
}
// 倒计时
const getCountdown = () => {
const now = Date.now()
let diff = targetTime.value - now
if (diff <= 0) {
// 初始化数据
initData()
targetTime.value += 7 * 86400000 // +7天 (更新闭包变量)
diff = targetTime.value - now
}
const totalSeconds = Math.floor(diff / 1000)
Days.value = Math.floor(totalSeconds / (24 * 3600))
Hours.value = formatTime(Math.floor((totalSeconds % (24 * 3600)) / 3600))
Minutes.value = formatTime(Math.floor((totalSeconds % 3600) / 60))
Second.value = formatTime(Math.floor(totalSeconds % 60))
}
// 格式化奖励的展示信息
const showDetail = (type, reward) => {
let showamount = ['GOLD', 'DIAMOND', 'GIFT', 'FRAGMENTS']
if (showamount.includes(type)) {
return reward.content
} else if (type === 'DOLLARS') {
return `$${reward.content}`
} else {
return `${reward.quantity}Days`
}
}
// 获取历史榜首
const getAllTopOne = async () => {
const resHistoryTopOne = await getHistoryTopOne('10')
if (resHistoryTopOne.status && resHistoryTopOne.body) {
historyTopList.value = resHistoryTopOne.body?.historicalList
}
}
// 获取周排行榜和我的排名
const getWeekListAndMy = async () => {
let data = {
activityType: 10,
}
const resMyWeekStarRanking = await getRankingListAndMyRanking(data)
console.log('resMyWeekStarRanking:', resMyWeekStarRanking)
if (resMyWeekStarRanking.status && resMyWeekStarRanking.body) {
myWeekRanking.value = resMyWeekStarRanking.body.currentUserRank
RankingWeek.value = resMyWeekStarRanking.body.rankingList
}
}
// 获取日排行榜和我的排名
const getDailyListAndMy = async () => {
let data = {
activityType: 15,
cycleType: 1,
}
const resDailyListAndMy = await getRankingListAndMyRanking(data)
console.log('resDailyListAndMy:', resDailyListAndMy)
if (resDailyListAndMy.status && resDailyListAndMy.body) {
myDailyRanking.value = resDailyListAndMy.body.currentUserRank
RankingDaily.value = resDailyListAndMy.body.rankingList
}
}
// 获取每周奖励列表
const getRewardsAndGifts = async () => {
const resRewardsAndGifts = await getThisWeekRewardsAndGifts('2001207026499137537')
if (resRewardsAndGifts.status && resRewardsAndGifts.body) {
rewardsList.value = resRewardsAndGifts.body.butOneRewards
}
}
// 刷新页面数据
const initData = async () => {
await Promise.all([
getAllTopOne(), // 获取历史榜首
getWeekListAndMy(), // 获取周榜和我的排名
getDailyListAndMy(), // 获取日榜和我的排名
getRewardsAndGifts(), // 获取本周的礼物和奖励列表
])
}
// 预加载关键图片
const preloadCriticalImages = async () => {
const criticalImages = [
imageUrl('bg'),
imageUrl('bg2'),
imageUrl('closeBt'),
imageUrl(getImgName('dailyPopUpNew')),
imageUrl('helpBt'),
imageUrl(getImgName('helpInfo')),
imageUrl(getImgName('historyBtActive')),
imageUrl('myRankingBg'),
imageUrl(getImgName('rankingBtActive')),
imageUrl(getImgName('rewardBtActive')),
imageUrl('RankingBottomBorder'),
imageUrl('RankingCenterBg'),
imageUrl('RankingItem'),
imageUrl(getImgName('RankingMain')),
imageUrl('BtBg'),
imageUrl('top1RewardDaily'),
imageUrl('top2RewardDaily'),
imageUrl('top3RewardDaily'),
imageUrl('timeBg'),
imageUrl('topBackBt'),
imageUrl('topNextBt'),
imageUrl('top1'),
imageUrl('top2'),
imageUrl('top3'),
imageUrl('top4'),
imageUrl('top5_7'),
imageUrl('top8_10'),
imageUrl('top1-3FrameDaily'),
]
await preloadImages(criticalImages)
}
// 完成预加载
const completePreloading = async () => {
try {
// 执行所有初始化操作
await Promise.all([initData(), preloadCriticalImages()])
} catch (error) {
console.error('预加载过程中发生错误:', error)
} finally {
// 无论成功或失败都结束加载状态
isLoading.value = false
}
}
// 预加载其他图片
const preloadOtherImages = async () => {
const criticalImages = [
imageUrl(getImgName('historyTopBg')),
imageUrl('historyTopFrame'),
imageUrl(getImgName('specialRewardsNew')),
imageUrl('top1RewardBg'),
imageUrl('top2_4RewardBg'),
imageUrl('top5_7RewardBg'),
imageUrl('top8_10RewardBg'),
]
await preloadImages(criticalImages)
}
// 使用工具函数连接APP
const connectToAppHandler = async () => {
await connectToApp(() => {
// 连接成功回调
completePreloading() // 完成预加载
})
}
// 组件挂载时检测环境
onMounted(() => {
connectToAppHandler()
preloadOtherImages() // 预加载其他图片
checkShow() // 检查是否展示每日弹窗
getCountdown()
timer = setInterval(getCountdown, 1000) //倒计时每秒更新
})
onUnmounted(() => {
clearInterval(timer) //摧毁计时器
})
</script>
<style lang="scss" scoped>
* {
color: #fff;
}
.fullPage {
position: relative;
background: #5d0c00;
}
.bg {
width: 100vw;
min-height: 100vh;
position: relative;
z-index: 1;
}
.timeText {
color: #fff;
font-weight: 590;
font-size: 1.5em;
}
.timeGap {
width: 6px;
align-self: stretch;
display: flex;
justify-content: center;
align-items: center;
}
.grayscale-container {
filter: grayscale(100%) brightness(100%);
}
.top2-3 {
display: flex;
justify-content: space-between;
}
[dir='rtl'] .top2-3 {
flex-direction: row-reverse;
}
.btTitle {
color: #fff;
font-weight: 700;
}
.topTitle {
font-size: 1.5em;
}
.history-name {
font-size: 0.8em;
}
.history-time {
font-size: 0.8em;
}
.UserNickname {
font-size: 0.8em;
}
.timeBox {
min-height: 20.27vw;
display: flex;
justify-content: center;
margin-top: 10vw;
}
/* 添加加载动画样式 */
.loading-container {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #666;
overflow: hidden;
position: relative;
z-index: 0;
}
.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);
}
}
@media screen and (max-width: 360px) {
* {
font-size: 10px;
}
}
@media screen and (min-width: 360px) {
* {
font-size: 14px;
}
}
@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'] .flipImg {
transform: scaleX(-1);
}
</style>