317 lines
6.5 KiB
Vue
317 lines
6.5 KiB
Vue
<template>
|
||
<div style="width: 100%">
|
||
<div style="position: relative">
|
||
<img
|
||
v-smart-img
|
||
:src="BorderImgUrl"
|
||
alt=""
|
||
width="100%"
|
||
style="display: block; position: relative; z-index: 2"
|
||
/>
|
||
<!-- 头像 -->
|
||
<div
|
||
style="
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 1;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
"
|
||
:style="{ height: avatarContainerHeight }"
|
||
>
|
||
<div :style="{ width: avatarWidth }">
|
||
<img
|
||
v-smart-img
|
||
:src="avatarUrl || ''"
|
||
alt=""
|
||
width="100%"
|
||
style="display: block; border-radius: 50%; aspect-ratio: 1/1; object-fit: cover"
|
||
@error="handleAvatarImageError"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 用户名和贡献值 -->
|
||
<div
|
||
style="
|
||
position: absolute;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 3;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 2px;
|
||
"
|
||
:style="{ height: bottomSectionHeight }"
|
||
>
|
||
<div
|
||
style="display: flex; align-items: center; overflow: hidden; width: 100%"
|
||
:style="usernameAreaStyle"
|
||
>
|
||
<!-- 滚动容器 -->
|
||
<div class="scroll-wrapper">
|
||
<!-- 第一套内容 -->
|
||
<div class="scroll-content">
|
||
<div
|
||
style="color: #fff; font-weight: 700; white-space: nowrap"
|
||
:class="textSizeClass"
|
||
>
|
||
{{ name }}
|
||
</div>
|
||
<img
|
||
v-smart-img
|
||
src="/src/assets/icon/coin.png"
|
||
alt=""
|
||
style="display: block; width: 1.1em"
|
||
/>
|
||
<div
|
||
style="
|
||
font-weight: 700;
|
||
background: linear-gradient(180deg, #ffe656 0%, #fff 100%);
|
||
background-clip: text;
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
"
|
||
class="showText"
|
||
:class="isTopOne ? 'top1Text' : 'text'"
|
||
>
|
||
{{ distributionValue }}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 第二套内容,间隔30px -->
|
||
<div class="scroll-content" style="margin-left: 30px">
|
||
<div
|
||
style="color: #fff; font-weight: 700; white-space: nowrap"
|
||
:class="textSizeClass"
|
||
>
|
||
{{ name }}
|
||
</div>
|
||
<img
|
||
v-smart-img
|
||
src="/src/assets/icon/coin.png"
|
||
alt=""
|
||
style="display: block; width: 1.1em"
|
||
/>
|
||
<div
|
||
style="
|
||
font-weight: 700;
|
||
background: linear-gradient(180deg, #ffe656 0%, #fff 100%);
|
||
background-clip: text;
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
"
|
||
class="showText"
|
||
:class="isTopOne ? 'top1Text' : 'text'"
|
||
>
|
||
{{ distributionValue }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { computed } from 'vue'
|
||
import { handleAvatarImageError } from '@/utils/imageHandler.js'
|
||
|
||
const props = defineProps({
|
||
// 排名
|
||
ranking: {
|
||
type: String,
|
||
default: '1',
|
||
},
|
||
|
||
// 头像
|
||
avatarUrl: {
|
||
type: String,
|
||
default: '',
|
||
},
|
||
|
||
// 头像框
|
||
BorderImgUrl: {
|
||
type: String,
|
||
required: true,
|
||
},
|
||
|
||
// 名字
|
||
name: {
|
||
type: String,
|
||
default: '',
|
||
},
|
||
|
||
// 贡献值
|
||
distributionValue: {
|
||
type: String,
|
||
default: '',
|
||
},
|
||
})
|
||
|
||
// 头像容器高度
|
||
const avatarContainerHeight = computed(() => {
|
||
switch (props.ranking) {
|
||
case '1':
|
||
return '93%'
|
||
case '2':
|
||
return '93%'
|
||
case '3':
|
||
return '90%'
|
||
case '4':
|
||
return '90%'
|
||
case '5-7':
|
||
return '85%'
|
||
case '8-10':
|
||
return '85%'
|
||
default:
|
||
return '90%'
|
||
}
|
||
})
|
||
|
||
// 头像宽度
|
||
const avatarWidth = computed(() => {
|
||
switch (props.ranking) {
|
||
case '1':
|
||
return '36%'
|
||
case '2':
|
||
return '50%'
|
||
case '3':
|
||
return '41%'
|
||
case '4':
|
||
return '41%'
|
||
case '5-7':
|
||
return '45%'
|
||
case '8-10':
|
||
return '45%'
|
||
default:
|
||
return '48%'
|
||
}
|
||
})
|
||
|
||
// 底部信息区域高度
|
||
const bottomSectionHeight = computed(() => {
|
||
switch (props.ranking) {
|
||
case '1':
|
||
return '23%'
|
||
case '2':
|
||
return '37%'
|
||
case '3':
|
||
return '39%'
|
||
case '4':
|
||
return '39%'
|
||
case '5-7':
|
||
return '43%'
|
||
case '8-10':
|
||
return '41%'
|
||
default:
|
||
return '30%'
|
||
}
|
||
})
|
||
|
||
// 用户名区域样式
|
||
const usernameAreaStyle = computed(() => {
|
||
switch (props.ranking) {
|
||
case '1':
|
||
return 'height: 50%; width: 36%;'
|
||
case '2':
|
||
return 'height: 39%; width: 90%;'
|
||
case '3':
|
||
return 'height: 26%; width: 70%;'
|
||
case '4':
|
||
return 'height: 26%; width: 75%;'
|
||
case '5-7':
|
||
return 'height: 23%; width: 78%;'
|
||
case '8-10':
|
||
return 'height: 27%; width: 78%;'
|
||
default:
|
||
return 'height: 30%; width: 40%;'
|
||
}
|
||
})
|
||
|
||
// 文字大小类
|
||
const textSizeClass = computed(() => {
|
||
return props.ranking === '1' ? 'top1Text' : 'text'
|
||
})
|
||
|
||
// 是否为第一名
|
||
const isTopOne = computed(() => {
|
||
return props.ranking === '1'
|
||
})
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
* {
|
||
font-family: 'SF Pro';
|
||
color: black;
|
||
}
|
||
|
||
.top1Text {
|
||
font-size: 0.75em;
|
||
}
|
||
|
||
.text {
|
||
font-size: 0.6em;
|
||
}
|
||
|
||
.showText {
|
||
color: #fff;
|
||
text-align: center;
|
||
overflow: hidden;
|
||
white-space: nowrap;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.scroll-wrapper {
|
||
display: flex;
|
||
width: fit-content;
|
||
animation: scroll-left 5s linear infinite;
|
||
will-change: transform;
|
||
}
|
||
|
||
.scroll-content {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
}
|
||
|
||
@keyframes scroll-left {
|
||
0% {
|
||
transform: translateX(0);
|
||
}
|
||
100% {
|
||
transform: translateX(calc(-50% - 15px));
|
||
}
|
||
}
|
||
|
||
@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>
|