483 lines
13 KiB
Vue

<template>
<div>
<!-- 前三名 -->
<div style="">
<!-- 第一 -->
<div style="display: flex; justify-content: center">
<TopUser
ranking="1"
:BorderImgUrl="imageUrl('top1Bg')"
:avatarUrl="RankingHasTop3[0].userAvatar"
:name="RankingHasTop3[0].userName"
:rankingType="rankingType"
: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-around;
pointer-events: none;
"
>
<div
style="pointer-events: auto; width: 42%"
@click.stop="viewUserInfo(RankingHasTop3[1].userId)"
>
<TopUser
ranking="2"
:BorderImgUrl="imageUrl('top2Bg')"
:avatarUrl="RankingHasTop3[1].userAvatar"
:name="RankingHasTop3[1].userName"
:rankingType="rankingType"
:distributionValue="RankingHasTop3[1].amount"
style="width: 100%"
/>
</div>
<div
style="pointer-events: auto; width: 42%"
@click.stop="viewUserInfo(RankingHasTop3[2].userId)"
>
<TopUser
ranking="3"
:BorderImgUrl="imageUrl('top3Bg')"
:avatarUrl="RankingHasTop3[2].userAvatar"
:name="RankingHasTop3[2].userName"
:rankingType="rankingType"
:distributionValue="RankingHasTop3[2].amount"
style="width: 100%"
/>
</div>
</div>
</div>
<!-- 第四名开始 -->
<div
v-if="showRanking.length > 0"
style="position: relative; z-index: 2; display: flex; flex-direction: column; gap: 2vw"
>
<div
v-for="(listItem, index) in showRanking"
:key="listItem.userId"
style="padding: 0 2vw; display: flex; align-items: center; gap: 2vw"
>
<!-- 排名 -->
<itemCenter
style="min-height: 9.11vw; width: 10vw"
:imgUrl="imageUrl('rankingNumBg')"
:contentStyle="`bottom: 0.5vw;`"
@click="viewUserInfo(listItem.userId)"
>
<div style="color: #ffe601; font-weight: 700">{{ listItem?.rank }}</div>
</itemCenter>
<itemCenter
style="min-height: 36vw"
:imgUrl="imageUrl('rankingItemBg')"
:contentStyle="`padding: 9.5vw 4vw 7vw 5vw;gap: 1vw`"
:flip="true"
: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: 10vw;
"
>
<!-- 头像 -->
<img
:src="listItem?.userAvatar || ''"
alt=""
style="
display: block;
width: 19vw;
aspect-ratio: 1/1;
border-radius: 50%;
object-fit: cover;
z-index: -1;
"
@error="handleAvatarImageError"
/>
<!-- 名称id -->
<div style="flex: 1; min-width: 0; display: flex; flex-direction: column">
<!-- 名称 -->
<div style="display: flex; min-width: 0">
<div
style="
color: #fff;
font-weight: 860;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
direction: ltr;
"
class="UserNickname"
>
{{ listItem?.userName }}
</div>
</div>
<!-- id -->
<div style="color: #fff; font-weight: 590" class="UserNickname">
{{ $t('user_id_prefix') }} {{ listItem?.specialAccount || listItem?.account }}
</div>
</div>
</div>
<!-- 贡献值 -->
<div
style="
width: auto;
min-width: 0;
display: flex;
align-items: center;
"
>
<div
v-if="rankingType == 'lottery'"
style="display: flex; justify-content: center; align-items: center"
>
<img
v-smart-img
src="/src/assets/icon/Azizi/coin.png"
alt=""
style="display: block; width: 1.5em; aspect-ratio: 1/1; object-fit: cover"
/>
<div style="color: #ffe601; font-weight: 700" class="Textlittle">
{{ listItem?.amount || 0 }}
</div>
</div>
<div
v-if="rankingType == 'recharge'"
style="color: #fff; font-weight: 700"
class="UserNickname"
>
${{ listItem?.amount }}
</div>
</div>
</itemCenter>
</div>
</div>
<!-- 触发加载功能 -->
<div ref="RankingLoadmore"></div>
</div>
</template>
<script setup>
import { computed, onMounted, onUnmounted, ref } from 'vue'
import { connectToApp } from '@/utils/appConnector.js'
import { useRoute, useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { setDocumentDirection } from '@/locales/i18n'
import { viewUserInfo } from '@/utils/appBridge.js'
import { useLangStore } from '@/stores/lang'
import { getPngUrl } from '@/config/imagePaths.js'
import { preloadImages } from '@/utils/image/imagePreloader.js'
import { showError, showSuccess } from '@/utils/toast.js'
import { handleAvatarImageError, handleRewardImageError } from '@/utils/image/imageHandler.js'
import { formatRewardDisplay } from '@/utils/rewardFormatter.js'
import { useSpringFestival } from '@/stores/springFestival'
import { storeToRefs } from 'pinia'
import { useThrottle } from '@/utils/useDebounce'
import {
ranklist, //获取排行榜
} from '@/api/lottery'
import BackgroundLayer from '@/components/BackgroundLayer.vue'
import itemCenter from '@/components/itemCenter.vue'
import maskLayer from '@/components/MaskLayer.vue'
import TopUser from './components/topUser.vue'
// 预加载状态
const isLoading = ref(true)
const { t, locale } = useI18n()
const router = useRouter()
const route = useRoute()
const springFestivalStore = useSpringFestival()
const {
// 抽奖模块
lotteryRewards, // 抽奖奖池
tickets, // 抽奖券数量
userInfo, // 用户信息
userIdentity, // 用户身份
currentEarnings, // 当前收益
taskList, // 任务列表
// 抽奖排名模块
lotteryPageNo, // 抽奖排名页码
lotteryRanking, // 抽奖排名
addLotteryRanking, // 补充的抽奖排名
myLotteryRanking, // 我的抽奖排名
// 排行榜奖励模块
rankingRewards, // 排名奖池
// 充值排名模块
rechargePageNo, // 充值排名页码
rechargeRanking, // 充值排名
addRechargeRanking, // 补充的充值排名
myRechargeRanking, // 我的充值排名
// 充值奖池模块
myRechargeRecode, // 我的充值记录
RechargeRewards, // 充值奖池
resultShow,
result, // 抽奖结果
drawRecordShow,
myRecords, // 我的抽奖记录
receiveRecordShow,
receiveRecord, // 领取抽奖券记录
earningsHelpShow, // 收益help展示
rechargeHelpShow, // 充值help展示
} = storeToRefs(springFestivalStore)
const langStore = useLangStore()
// 当前语言类型
const currentLangType = computed(() => {
return langStore.selectedLang?.type || 'en'
})
// 获取OSS图片URL的函数
const imageUrl = (filename) => getPngUrl('Activities/SpringFestival/', filename)
// 根据语言获取图片名
const getImgName = (filename) => {
return currentLangType.value === 'ar' ? `${filename}_ar` : filename
}
const props = defineProps({
rankingType: {
type: String,
default: '',
},
})
// 完整排行榜
const rankingTotal = computed(() => {
if (props.rankingType == 'lottery') {
return [...lotteryRanking.value, ...addLotteryRanking.value]
}
return [...rechargeRanking.value, ...addRechargeRanking.value]
})
// 处理排行榜小于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 RankingLoadmore = ref(null) //触底模块
const rankingPageNo = ref(1) //分页页码
//获取排行榜
const getRanking = async () => {
if (lotteryPageNo.value == 0) {
lotteryPageNo.value = 1
}
if (rechargePageNo.value == 0) {
rechargePageNo.value = 1
}
let data = {
activityId: props.rankingType == 'lottery' ? '2007771533988204877' : '2007771533988204888',
pageNo: props.rankingType == 'lottery' ? lotteryPageNo.value : rechargePageNo.value,
pageSize: 20,
}
const resRanking = await ranklist(data)
if (resRanking.status && resRanking.body) {
if (props.rankingType == 'lottery') {
myLotteryRanking.value = resRanking.body?.currentUser // 我的抽奖排名
} else if (props.rankingType == 'recharge') {
myRechargeRanking.value = resRanking.body?.currentUser // 我的充值排名
}
if (resRanking.body.topList.length > 0) {
if (resRanking.body.topList.length == 20) {
if (props.rankingType == 'lottery') {
addLotteryRanking.value = []
lotteryRanking.value.push(...resRanking.body?.topList)
lotteryPageNo.value++
} else if (props.rankingType == 'recharge') {
addRechargeRanking.value = []
rechargeRanking.value.push(...resRanking.body?.topList)
rechargePageNo.value++
}
} else {
if (props.rankingType == 'lottery') {
addLotteryRanking.value = resRanking.body?.topList
} else if (props.rankingType == 'recharge') {
addRechargeRanking.value = resRanking.body?.topList
}
}
}
} else {
if (props.rankingType == 'lottery') {
myLotteryRanking.value = {}
lotteryRanking.value = []
addLotteryRanking.value = []
lotteryPageNo.value = 1
} else if (props.rankingType == 'recharge') {
myRechargeRanking.value = {}
rechargeRanking.value = []
addRechargeRanking.value = []
rechargePageNo.value = 1
}
}
}
// 触发节流获取排行榜
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(() => {
// 监听加载模块
if (RankingLoadmore.value) {
console.log('监控加载模块')
observer.observe(RankingLoadmore.value)
}
})
onUnmounted(() => {})
</script>
<style lang="scss" scoped>
* {
color: #fff;
}
.fullPage {
position: relative;
background: #142c24;
}
.bg {
width: 100vw;
min-height: 100vh;
position: relative;
z-index: 1;
}
.background-overlay {
position: absolute;
inset: 236vw 0 0;
background-image: var(--bg2-url);
background-repeat: repeat-y;
background-position: top center;
background-size: 100% auto;
z-index: 0; /* 确保在.bg之下 */
}
/* 添加加载动画样式 */
.loading-container {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #666;
}
.loading-spinner {
width: 32px;
height: 32px;
border: 3px solid #f3f3f3;
border-top: 3px solid #f59e0b;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 12px;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.scrollY::-webkit-scrollbar {
display: none;
}
[dir='rtl'] .flipImg {
transform: scaleX(-1);
}
@media screen and (max-width: 360px) {
* {
font-size: 10px;
}
}
@media screen and (min-width: 360px) {
* {
font-size: 12px;
}
}
@media screen and (min-width: 768px) {
* {
font-size: 24px;
}
}
@media screen and (min-width: 1024px) {
* {
font-size: 32px;
}
}
</style>