483 lines
13 KiB
Vue
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>
|