465 lines
12 KiB
Vue
465 lines
12 KiB
Vue
<template>
|
|
<div style="width: 100%">
|
|
<itemCenter :imgUrl="BorderImgUrl" :flip="true" :contentStyle="`display:block;`">
|
|
<!-- 第一名 -->
|
|
<div v-if="isTopOne" style="width: 98vw; height: 80%; position: relative">
|
|
<!-- 查看个人信息按钮 -->
|
|
<div style="position: absolute; z-index: 2; inset: 0; display: flex">
|
|
<!-- 情侣1 -->
|
|
<div
|
|
style="flex: 1; min-width: 0; align-self: stretch"
|
|
@click="viewUserInfo(rankingItem.userId)"
|
|
></div>
|
|
<!-- 情侣1 -->
|
|
<div
|
|
style="flex: 1; min-width: 0; align-self: stretch"
|
|
@click="viewUserInfo(rankingItem.cpUserId)"
|
|
></div>
|
|
</div>
|
|
|
|
<!-- 头像 -->
|
|
<div
|
|
style="
|
|
position: absolute;
|
|
z-index: -1;
|
|
top: 17vw;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 25vw;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
gap: 14vw;
|
|
"
|
|
>
|
|
<!-- 情侣1头像 -->
|
|
<img
|
|
:src="rankingItem.userAvatar"
|
|
alt=""
|
|
style="
|
|
display: block;
|
|
width: 25vw;
|
|
object-fit: cover;
|
|
aspect-ratio: 1/1;
|
|
border-radius: 50%;
|
|
"
|
|
@error="handleAvatarImageError"
|
|
@click="viewUserInfo(rankingItem.userId)"
|
|
/>
|
|
<!-- 情侣2头像 -->
|
|
<img
|
|
:src="rankingItem.cpUserAvatar"
|
|
alt=""
|
|
style="
|
|
display: block;
|
|
width: 25vw;
|
|
object-fit: cover;
|
|
aspect-ratio: 1/1;
|
|
border-radius: 50%;
|
|
"
|
|
@error="handleAvatarImageError"
|
|
@click="viewUserInfo(rankingItem.cpUserId)"
|
|
/>
|
|
</div>
|
|
|
|
<!-- 顶部距离 -->
|
|
<div style="height: 27vw"></div>
|
|
<!-- 贡献值 -->
|
|
<div style="height: 17vw; display: flex; justify-content: center; align-items: center">
|
|
<div style="color: #fff; font-weight: 700">
|
|
{{ rankingItem.total }}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 名称 -->
|
|
<div
|
|
style="
|
|
margin-top: -1vw;
|
|
height: 5vw;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
"
|
|
>
|
|
<div style="width: 76vw; display: flex; align-items: center; gap: 2vw">
|
|
<!-- 情侣1名称 -->
|
|
<div
|
|
style="
|
|
flex: 1;
|
|
min-width: 0;
|
|
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
"
|
|
>
|
|
<div
|
|
style="
|
|
padding: 0 20%;
|
|
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
|
|
font-size: 0.9em;
|
|
font-weight: 600;
|
|
"
|
|
>
|
|
{{ rankingItem.userNickname || '' }}
|
|
</div>
|
|
</div>
|
|
<!-- 情侣2名称 -->
|
|
<div
|
|
style="
|
|
flex: 1;
|
|
min-width: 0;
|
|
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
"
|
|
>
|
|
<div
|
|
style="
|
|
padding: 0 20%;
|
|
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
|
|
font-size: 0.9em;
|
|
font-weight: 600;
|
|
"
|
|
>
|
|
{{ rankingItem.cpUserNickname || '' }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 第二三名 -->
|
|
<div v-else style="height: 65%; padding: 0 7%; display: flex; align-items: center">
|
|
<!-- 排名 -->
|
|
<img :src="imageUrl(`top${ranking}Ranking`)" alt="" style="width: 8vw" />
|
|
|
|
<!-- 头像 -->
|
|
<div style="width: 36vw; position: relative">
|
|
<!-- 查看个人信息按钮 -->
|
|
<div style="position: absolute; z-index: 2; inset: 0; display: flex">
|
|
<!-- 情侣1 -->
|
|
<div
|
|
style="flex: 1; min-width: 0; align-self: stretch"
|
|
@click="viewUserInfo(rankingItem.userId)"
|
|
></div>
|
|
<!-- 情侣1 -->
|
|
<div
|
|
style="flex: 1; min-width: 0; align-self: stretch"
|
|
@click="viewUserInfo(rankingItem.cpUserId)"
|
|
></div>
|
|
</div>
|
|
|
|
<!-- 内容 -->
|
|
<itemCenter
|
|
style="width: 100%; z-index: 1"
|
|
:imgUrl="imageUrl(`top${ranking}Frame`)"
|
|
:contentStyle="`z-index: -1;`"
|
|
>
|
|
<div
|
|
style="
|
|
width: 100%;
|
|
padding: 3vw 5vw;
|
|
height: 80%;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
"
|
|
>
|
|
<!-- 情侣1头像 -->
|
|
<img
|
|
:src="rankingItem.userAvatar"
|
|
alt=""
|
|
style="
|
|
display: block;
|
|
min-width: 0;
|
|
width: 10.5vw;
|
|
object-fit: cover;
|
|
aspect-ratio: 1/1;
|
|
border-radius: 50%;
|
|
"
|
|
@error="handleAvatarImageError"
|
|
/>
|
|
<!-- 情侣2头像 -->
|
|
<img
|
|
:src="rankingItem.cpUserAvatar"
|
|
alt=""
|
|
style="
|
|
display: block;
|
|
min-width: 0;
|
|
width: 10.5vw;
|
|
object-fit: cover;
|
|
aspect-ratio: 1/1;
|
|
border-radius: 50%;
|
|
"
|
|
@error="handleAvatarImageError"
|
|
/>
|
|
</div>
|
|
</itemCenter>
|
|
</div>
|
|
|
|
<!-- 名称 -->
|
|
<div
|
|
style="
|
|
flex: 1;
|
|
min-width: 0;
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
gap: 1vw;
|
|
"
|
|
>
|
|
<div style="width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap">
|
|
{{ rankingItem.userNickname || '' }}
|
|
</div>
|
|
<div style="width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap">
|
|
{{ rankingItem.cpUserNickname || '' }}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 贡献 -->
|
|
<div style="width: auto; min-width: 0; display: flex; align-items: center">
|
|
<img
|
|
:src="imageUrl('distribution')"
|
|
alt=""
|
|
style="width: 10vw; display: block; object-fit: cover"
|
|
/>
|
|
<div style="font-weight: 700">{{ rankingItem.total || '0' }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 奖励 -->
|
|
<div class="reward-wrapper">
|
|
<div style="height: 100%; display: flex; align-items: center; overflow: hidden">
|
|
<!-- 滚动容器 -->
|
|
<div class="scroll-wrapper">
|
|
<!-- 第一套内容 -->
|
|
<div class="scroll-content" v-for="value in 2">
|
|
<div
|
|
v-for="(item, index) in rewards.activityRewardProps"
|
|
:key="index"
|
|
style="display: flex; align-items: center; gap: 1vw"
|
|
@click="clickReward(item)"
|
|
>
|
|
<!-- 预览图 -->
|
|
<img
|
|
v-if="item.cover != ''"
|
|
:src="item.cover"
|
|
alt=""
|
|
style="min-width: 0; display: block; width: 10vw; object-fit: cover"
|
|
/>
|
|
<div style="min-width: 0; color: #fff; white-space: nowrap">
|
|
{{ formatRewardDisplay(item.type, item) }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</itemCenter>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
|
import { useRoute, useRouter } from 'vue-router'
|
|
import { useLangStore } from '@/stores/lang'
|
|
import { useI18n } from 'vue-i18n'
|
|
import { getPngUrl } from '@/config/imagePaths.js'
|
|
import { setUserInfo } from '@/utils/userStore.js'
|
|
import { viewUserInfo } from '@/utils/appBridge.js'
|
|
import { connectToApp } from '@/utils/appConnector.js'
|
|
import { preloadImages } from '@/utils/imagePreloader.js'
|
|
import { formatUTCCustom } from '@/utils/utcFormat.js'
|
|
import { showError, showSuccess } from '@/utils/toast.js'
|
|
import { handleAvatarImageError, handleRewardImageError } from '@/utils/imageHandler.js'
|
|
import { useThrottle } from '@/utils/useDebounce.js'
|
|
import { useCoupleStore } from '@/stores/couple'
|
|
import { storeToRefs } from 'pinia'
|
|
import { formatRewardDisplay } from '@/utils/rewardFormatter.js'
|
|
|
|
import itemCenter from '@/components/itemCenter.vue'
|
|
|
|
const { t } = useI18n()
|
|
const router = useRouter()
|
|
const route = useRoute()
|
|
const coupleStore = useCoupleStore()
|
|
|
|
const langStore = useLangStore()
|
|
// 当前语言类型
|
|
const currentLangType = computed(() => {
|
|
return langStore.selectedLang?.type || 'en'
|
|
})
|
|
|
|
// 获取OSS图片URL的函数
|
|
const imageUrl = (filename) => getPngUrl('Ranking/Couple/', filename)
|
|
|
|
// 根据语言获取图片名
|
|
const getImgName = (filename) => {
|
|
return currentLangType.value === 'ar' ? `${filename}_ar` : filename
|
|
}
|
|
|
|
const {
|
|
topRewardShow, // 前三名奖励展示
|
|
topReward, // 前三名奖励项
|
|
} = storeToRefs(coupleStore)
|
|
|
|
const props = defineProps({
|
|
ranking: {
|
|
type: String,
|
|
default: '0',
|
|
},
|
|
|
|
rankingItem: {
|
|
type: Object,
|
|
default: () => ({}),
|
|
},
|
|
|
|
rewards: {
|
|
type: Object,
|
|
default: () => ({}),
|
|
},
|
|
})
|
|
|
|
const BorderImgUrl = computed(() => {
|
|
switch (props.ranking) {
|
|
case '1':
|
|
return imageUrl('top1')
|
|
case '2':
|
|
return imageUrl('top2-3')
|
|
case '3':
|
|
return imageUrl('top2-3')
|
|
default:
|
|
return imageUrl('top2-3')
|
|
}
|
|
})
|
|
|
|
// 是否为第一名
|
|
const isTopOne = computed(() => {
|
|
return props.ranking === '1'
|
|
})
|
|
|
|
// 点击奖品
|
|
const clickReward = (item) => {
|
|
topReward.value = item // 展示奖品赋值
|
|
topRewardShow.value = true // 显示奖品
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
* {
|
|
color: #fff;
|
|
}
|
|
|
|
.showText {
|
|
color: #fff;
|
|
text-align: center;
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.top1Text {
|
|
font-size: 0.75em;
|
|
}
|
|
|
|
.text {
|
|
font-size: 0.6em;
|
|
}
|
|
|
|
.reward-wrapper {
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 15vw;
|
|
right: 4vw;
|
|
height: 13.5vw;
|
|
}
|
|
|
|
[dir='rtl'] .reward-wrapper {
|
|
left: 4vw;
|
|
right: 15vw;
|
|
}
|
|
|
|
.scroll-wrapper {
|
|
display: flex;
|
|
width: fit-content;
|
|
}
|
|
|
|
.scroll-content {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 2vw;
|
|
}
|
|
|
|
@keyframes scroll-left {
|
|
0% {
|
|
transform: translateX(0);
|
|
}
|
|
100% {
|
|
transform: translateX(-50%);
|
|
}
|
|
}
|
|
|
|
@keyframes scroll-right {
|
|
0% {
|
|
transform: translateX(0);
|
|
}
|
|
100% {
|
|
transform: translateX(50%);
|
|
}
|
|
}
|
|
|
|
[dir='ltr'] .scroll-content {
|
|
margin-left: 4vw;
|
|
}
|
|
|
|
[dir='rtl'] .scroll-content {
|
|
margin-left: auto;
|
|
margin-right: 4vw;
|
|
}
|
|
|
|
[dir='ltr'] .scroll-wrapper {
|
|
animation: scroll-left 8s linear infinite;
|
|
will-change: transform;
|
|
}
|
|
|
|
[dir='rtl'] .scroll-wrapper {
|
|
animation: scroll-right 8s linear infinite;
|
|
will-change: transform;
|
|
}
|
|
|
|
@media screen and (max-width: 360px) {
|
|
* {
|
|
font-size: 10px;
|
|
}
|
|
}
|
|
|
|
@media screen and (min-width: 360px) {
|
|
* {
|
|
font-size: 16px;
|
|
}
|
|
}
|
|
|
|
@media screen and (min-width: 768px) {
|
|
* {
|
|
font-size: 24px;
|
|
}
|
|
}
|
|
|
|
@media screen and (min-width: 1024px) {
|
|
* {
|
|
font-size: 32px;
|
|
}
|
|
}
|
|
</style>
|