chore: 支持战区冠军添加图片,增加英雄榜字体及特效

This commit is contained in:
2025-11-24 14:32:58 +08:00
parent 593dad093e
commit 885f0a51dd
2 changed files with 179 additions and 33 deletions

View File

@@ -475,30 +475,53 @@
<h2 class="game-subtitle">🏆 冠军Logo配置</h2> <h2 class="game-subtitle">🏆 冠军Logo配置</h2>
<div class="config-section"> <div class="config-section">
<h3 class="text-gold">🎯 战区冠军Logo</h3> <h3 class="text-gold">🎯 战区冠军配置</h3>
<div class="logo-upload-section"> <div class="logo-upload-section">
<div class="config-item">
<label class="checkbox-label">
<span>显示类型</span>
<select v-model="championLogos.teamChampionType" class="select-input">
<option value="avatar">头像</option>
<option value="photo">照片</option>
</select>
</label>
</div>
<div class="logo-preview"> <div class="logo-preview">
<div v-if="championLogos.teamChampion" class="logo-image-container"> <div v-if="championLogos.teamChampion" class="logo-image-container">
<img :src="championLogos.teamChampion" alt="战区冠军Logo" class="logo-preview-image"> <img :src="championLogos.teamChampion" alt="战区冠军" class="logo-preview-image" :style="championLogos.teamChampionType === 'photo' ? { width: championLogos.teamChampionPhotoWidth + 'px', height: championLogos.teamChampionPhotoHeight + 'px', objectFit: 'cover' } : {}">
</div> </div>
<div v-else class="logo-placeholder"> <div v-else class="logo-placeholder">
<span>未上传Logo</span> <span>未上传图片</span>
</div> </div>
</div> </div>
<div class="upload-controls"> <div class="upload-controls">
<input type="file" accept="image/*" @change="(e) => handleChampionLogoUpload(e, 'teamChampion')" <input type="file" accept="image/*" @change="(e) => handleChampionLogoUpload(e, 'teamChampion')"
class="logo-input"> class="logo-input">
<button v-if="championLogos.teamChampion" @click="clearChampionLogo('teamChampion')" class="btn-clear"> <button v-if="championLogos.teamChampion" @click="clearChampionLogo('teamChampion')" class="btn-clear">
清除Logo 清除图片
</button> </button>
</div> </div>
<div class="size-control"> <div v-if="championLogos.teamChampionType === 'avatar'" class="size-control">
<label class="text-gold">显示大小</label> <label class="text-gold">头像大小</label>
<input type="number" v-model.number="championLogos.teamChampionSize" min="30" max="200" <input type="number" v-model.number="championLogos.teamChampionSize" min="30" max="200"
class="width-input" placeholder="输入大小(像素)"> class="width-input" placeholder="输入大小(像素)">
<span class="size-unit">px</span> <span class="size-unit">px</span>
</div> </div>
<p class="upload-hint">支持JPGPNGGIF格式建议尺寸200x200像素文件大小不超过5MB</p> <div v-if="championLogos.teamChampionType === 'photo'" class="size-controls">
<div class="size-control">
<label class="text-gold">照片宽度</label>
<input type="number" v-model.number="championLogos.teamChampionPhotoWidth" min="50" max="400"
class="width-input" placeholder="输入宽度(像素)">
<span class="size-unit">px</span>
</div>
<div class="size-control">
<label class="text-gold">照片高度</label>
<input type="number" v-model.number="championLogos.teamChampionPhotoHeight" min="30" max="300"
class="width-input" placeholder="输入高度(像素)">
<span class="size-unit">px</span>
</div>
</div>
<p class="upload-hint">支持JPGPNGGIF格式建议尺寸200x200像素头像或400x300像素照片文件大小不超过5MB</p>
</div> </div>
</div> </div>

View File

@@ -61,10 +61,21 @@
<div class="team-rankings"> <div class="team-rankings">
<!-- 战区冠军 --> <!-- 战区冠军 -->
<div class="team-champion"> <div class="team-champion">
<div class="team-logo"> <div class="team-logo" :class="{ 'photo-container': localDisplayConfig.championLogos?.teamChampionType === 'photo' }">
<img v-if="localDisplayConfig.championLogos?.teamChampion" <img v-if="localDisplayConfig.championLogos?.teamChampion"
:src="localDisplayConfig.championLogos.teamChampion" alt="战区冠军" class="champion-logo" :src="localDisplayConfig.championLogos.teamChampion" alt="战区冠军"
:style="{ width: localDisplayConfig.championLogos?.teamChampionSize + 'px', height: localDisplayConfig.championLogos?.teamChampionSize + 'px' }"> class="champion-logo"
:style="localDisplayConfig.championLogos?.teamChampionType === 'photo'
? {
width: localDisplayConfig.championLogos?.teamChampionPhotoWidth + 'px',
height: localDisplayConfig.championLogos?.teamChampionPhotoHeight + 'px',
objectFit: 'cover'
}
: {
width: localDisplayConfig.championLogos?.teamChampionSize + 'px',
height: localDisplayConfig.championLogos?.teamChampionSize + 'px'
}
">
<img v-else src="/crown.png" alt="战区冠军" class="champion-logo" /> <img v-else src="/crown.png" alt="战区冠军" class="champion-logo" />
</div> </div>
<div class="champion-name"> <div class="champion-name">
@@ -102,30 +113,32 @@
<div class="individual-rankings"> <div class="individual-rankings">
<!-- 英雄冠军 --> <!-- 英雄冠军 -->
<div class="individual-champion"> <div class="individual-champion">
<div class="individual-avatar champion-container"> <div class="hero-ranking-text left-hero-ranking-text">英雄榜</div>
<div class="crown-animation" :class="{'crown-animation-run': localDisplayConfig.crown?.animationEnabled}" v-if="filteredIndividualRankings.length > 0" :style="{ <div class="champion-content">
fontSize: (localDisplayConfig.crown?.size || localDisplayConfig.championLogos?.individualChampionSize * 0.8) + 'px' <div class="individual-avatar champion-container">
// transform: 'translateX(-50%)' <div class="crown-animation" :class="{'crown-animation-run': localDisplayConfig.crown?.animationEnabled}" v-if="filteredIndividualRankings.length > 0" :style="{
}"> fontSize: (localDisplayConfig.crown?.size || localDisplayConfig.championLogos?.individualChampionSize * 0.8) + 'px'
👑 }">
👑
</div>
<img v-if="filteredIndividualRankings[0]?.avatar && filteredIndividualRankings[0].avatar.startsWith('/')"
:src="filteredIndividualRankings[0].avatar" alt="冠军头像" class="avatar-image avatar-image-champion"
:style="{ width: localDisplayConfig.championLogos?.individualChampionSize + 'px', height: localDisplayConfig.championLogos?.individualChampionSize + 'px' }">
<img v-else-if="localDisplayConfig.championLogos?.individualChampion"
:src="localDisplayConfig.championLogos.individualChampion" alt="英雄冠军" class="champion-logo"
:style="{ width: localDisplayConfig.championLogos?.individualChampionSize + 'px', height: localDisplayConfig.championLogos?.individualChampionSize + 'px' }">
<div v-else class="champion-log">
<span
:style="{ fontSize: localDisplayConfig.championLogos?.individualChampionSize ? (localDisplayConfig.championLogos.individualChampionSize * 0.8) + 'px' : '2rem' }">
{{ filteredIndividualRankings[0]?.avatar || '👤' }}
</span>
</div>
</div> </div>
<img v-if="filteredIndividualRankings[0]?.avatar && filteredIndividualRankings[0].avatar.startsWith('/')" <div class="champion-name">
:src="filteredIndividualRankings[0].avatar" alt="冠军头像" class="avatar-image avatar-image-champion" {{ filteredIndividualRankings[0]?.name || '暂无冠军' }}
:style="{ width: localDisplayConfig.championLogos?.individualChampionSize + 'px', height: localDisplayConfig.championLogos?.individualChampionSize + 'px' }">
<img v-else-if="localDisplayConfig.championLogos?.individualChampion"
:src="localDisplayConfig.championLogos.individualChampion" alt="英雄冠军" class="champion-logo"
:style="{ width: localDisplayConfig.championLogos?.individualChampionSize + 'px', height: localDisplayConfig.championLogos?.individualChampionSize + 'px' }">
<div v-else class="champion-log">
<span
:style="{ fontSize: localDisplayConfig.championLogos?.individualChampionSize ? (localDisplayConfig.championLogos.individualChampionSize * 0.8) + 'px' : '2rem' }">
{{ filteredIndividualRankings[0]?.avatar || '👤' }}
</span>
</div> </div>
</div>
<div class="champion-name">
{{ filteredIndividualRankings[0]?.name || '暂无冠军' }}
</div> </div>
<div class="hero-ranking-text right-hero-ranking-text">英雄榜</div>
</div> </div>
<!-- 英雄排名 --> <!-- 英雄排名 -->
<div class="individual-rankings-container"> <div class="individual-rankings-container">
@@ -207,6 +220,9 @@ function createDefaultDisplayConfig() {
championLogos: { championLogos: {
teamChampion: '', teamChampion: '',
teamChampionSize: 60, teamChampionSize: 60,
teamChampionType: 'avatar', // 'avatar' 或 'photo'
teamChampionPhotoWidth: 120,
teamChampionPhotoHeight: 80,
individualChampion: '', individualChampion: '',
individualChampionSize: 60 individualChampionSize: 60
}, },
@@ -1097,6 +1113,12 @@ onUnmounted(() => {
border-radius: 50%; border-radius: 50%;
} }
.photo-container .champion-logo {
max-width: unset !important;
border-radius: 0 !important;
}
.avatar-image { .avatar-image {
width: 30px; width: 30px;
height: 30px; height: 30px;
@@ -1802,6 +1824,108 @@ onUnmounted(() => {
text-shadow: 0 0 10px rgba(255, 215, 0, 0.5); text-shadow: 0 0 10px rgba(255, 215, 0, 0.5);
} }
/* 照片容器样式 */
.team-logo.photo-container {
overflow: hidden;
}
.individual-champion {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
margin-bottom: 20px;
gap: 30px;
}
.hero-ranking-text {
font-size: 2.8rem;
font-weight: 300;
color: #ffd700;
writing-mode: vertical-rl;
text-orientation: mixed;
letter-spacing: 10px;
position: relative;
text-shadow:
0 0 5px rgba(255, 215, 0, 0.8),
0 0 10px rgba(255, 215, 0, 0.6),
0 0 15px rgba(255, 215, 0, 0.4),
2px 2px 2px rgba(0, 0, 0, 0.8);
/* 3D立体效果 */
text-stroke: 1px rgba(255, 255, 255, 0.2);
-webkit-text-stroke: 1px rgba(255, 255, 255, 0.2);
/* 金色渐变背景 */
background: linear-gradient(135deg, #ffd700, #ffc107, #ffd700);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
/* 发光效果动画 */
animation: glow-hero 2s infinite alternate ease-in-out;
}
/* 发光效果动画 */
@keyframes glow-hero {
0% {
text-shadow:
0 0 5px rgba(255, 215, 0, 0.8),
0 0 10px rgba(255, 215, 0, 0.6),
0 0 15px rgba(255, 215, 0, 0.4),
2px 2px 2px rgba(0, 0, 0, 0.8);
}
100% {
text-shadow:
0 0 10px rgba(255, 215, 0, 1),
0 0 20px rgba(255, 215, 0, 0.8),
0 0 30px rgba(255, 215, 0, 0.6),
3px 3px 3px rgba(0, 0, 0, 0.8);
}
}
/* 为容器添加旋转光环效果 */
.hero-ranking-decoration::before {
content: '';
position: absolute;
width: 180%;
height: 180%;
top: -40%;
left: -40%;
background: radial-gradient(circle, transparent 50%, rgba(255, 215, 0, 0.4) 70%, transparent 90%);
border-radius: 50%;
animation: rotate-hero-ranking-decoration 8s linear infinite;
z-index: -1;
filter: blur(3px);
}
/* 添加第二层光环效果 */
.hero-ranking-decoration::after {
content: '';
position: absolute;
width: 140%;
height: 140%;
top: -20%;
left: -20%;
background: radial-gradient(circle, transparent 60%, rgba(255, 140, 0, 0.3) 80%, transparent 100%);
border-radius: 50%;
animation: rotate-hero-ranking-decoration 12s linear infinite reverse;
z-index: -2;
filter: blur(2px);
}
@keyframes rotate-hero-ranking-decoration {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.champion-content {
display: flex;
flex-direction: column;
align-items: center;
}
@media (max-width: 768px) { @media (max-width: 768px) {
/* 战区排名容器设置 - 根据配置决定显示行数和滚动行为 */ /* 战区排名容器设置 - 根据配置决定显示行数和滚动行为 */
@@ -2106,7 +2230,6 @@ onUnmounted(() => {
/* 冠军部分调整 */ /* 冠军部分调整 */
.team-champion, .team-champion,
.individual-champion { .individual-champion {
transform: scale(0.9);
margin: 5px 0; margin: 5px 0;
} }