2026-01-20 11:06:28 +08:00

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>