Files
vs100/src/views/BattleRanking.vue

2639 lines
80 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div>
<!-- 第一部分百日大战主题 - 使用banner0.png图片 -->
<section class="theme-section card-game">
<div class="theme-container">
<img src="/banner0.png" alt="百日大战主题" class="banner-image bai-day-battle">
</div>
</section>
<!-- 第二部分战鼓动画浮动并支持拖放 -->
<section v-if="localDisplayConfig.showDrum" class="drums-section card-game" @mousedown="startDrag"
@click="handleDrumClick" :style="{ left: drumsPosition.x + 'px', top: drumsPosition.y + 'px' }">
<div class="drums-container">
<!-- 战鼓动画在上面 -->
<div class="drums-animation">
<div class="drum glow-border" :class="{ beating: isBeating }">🥁</div>
<div class="drum" :class="{ beating: isBeating }">🥁</div>
<div class="trophy" style="font-size: 2.5rem; filter: drop-shadow(0 0 10px var(--gold-primary));">🏆</div>
<div class="drum" :class="{ beating: isBeating }">🥁</div>
<div class="drum" :class="{ beating: isBeating }">🥁</div>
</div>
</div>
</section>
<!-- 任务设置模块 -->
<section class="task-settings-section card-game">
<div class="task-title-container">
<h1 class="game-title" v-if="taskSettings?.mainTitle">任务: <span class="game-title-highlight">{{
taskSettings.mainTitle }} </span> </h1>
<p class="game-subtitle" v-if="taskSettings?.subtitle">{{ taskSettings.subtitle }}</p>
</div>
</section>
<!-- 第三部分奖金设置图片形式 -->
<section v-if="localDisplayConfig.showBonusModule" class="bonus-section card-game"
@mousedown="startBonusDrag"
@touchstart="startBonusTouch"
@click.stop>
<div class="bonus-awards-container">
<div><img src="/award1.png" alt="一等奖" class="award-image"></div>
<div><img src="/award2.png" alt="二等奖" class="award-image"></div>
<div><img src="/award3.png" alt="三等奖" class="award-image"></div>
</div>
</section>
<!-- 第四部分总战绩 -->
<section class="total-score-section card-game">
<div class="total-score-container">
<div class="game-subtitle total-score-total-title">
<img src="/completed_performance.png"
alt="总战绩"
style="width: 880px; display: block; margin: 0 auto; height: auto;"
class="total-score-total-image">
</div>
<div class="total-score-content">
<div class="total-score-item">
<span class="score-value total-score-total-value">{{ localDisplayConfig.team?.totalScoreColumn?.displayStyle === 'amount' ? '¥' : '' }}{{ totalTeamScore }}</span>
</div>
</div>
</div>
</section>
<!-- 第五部分排名明细 -->
<section class="rankings-section card-game">
<div class="rankings-container">
<!-- 战区排名 -->
<div class="team-rankings">
<!-- 战区排名宣传语 -->
<div class="team-rankings-propagation">
<img src="/team-propagation.png" alt="虎狼之师" class="team-rankings-propagation-image"
style="width: 500px; height: auto">
</div>
<!-- 战区冠军 -->
<div class="team-champion">
<div class="team-logo" :class="{ 'photo-container': localDisplayConfig.championLogos?.teamChampionType === 'photo' }">
<img v-if="localDisplayConfig.championLogos?.teamChampion"
:src="localDisplayConfig.championLogos.teamChampion" alt="战区冠军"
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" />
</div>
<div class="champion-name">
{{ teamRankings[0]?.name || '暂无冠军' }}
</div>
</div>
<div class="team-rankings-container">
<h2 class="game-subtitle">战区排名</h2>
<div class="rank-table">
<div class="table-header" :style="{ 'grid-template-columns': teamGridTemplate }">
<span class="rank-col" :style="{ textAlign: localDisplayConfig.team?.columnAlignments?.rank || 'left' }">排名</span>
<span class="name-col" :style="{ textAlign: localDisplayConfig.team?.columnAlignments?.name || 'left' }">战区名称</span>
<span class="score-col" :style="{ textAlign: localDisplayConfig.team?.columnAlignments?.score || 'left' }">{{ localDisplayConfig.team?.totalScoreColumn?.displayName || '业绩' }}</span>
<span v-if="localDisplayConfig.team?.showMemberCount" class="member-col" :style="{ textAlign: localDisplayConfig.team?.columnAlignments?.memberCount || 'left' }">人数</span>
<span v-if="localDisplayConfig.team?.showLeader" class="leader-col" :style="{ textAlign: localDisplayConfig.team?.columnAlignments?.leader || 'left' }">将军</span>
<span v-if="localDisplayConfig.team?.showBonus" class="bonus-col" :style="{ textAlign: localDisplayConfig.team?.columnAlignments?.bonus || 'left' }">奖金</span>
</div>
<div v-for="(item, index) in filteredTeamRankings" :key="item.id" class="table-row"
:style="{ 'grid-template-columns': teamGridTemplate }" :class="{
'top-three': index < 3,
'highlight': index === 0
}">
<span class="rank-col" :style="{ textAlign: localDisplayConfig.team?.columnAlignments?.rank || 'left' }">{{ index + 1 }}</span>
<span class="name-col" :style="{ textAlign: localDisplayConfig.team?.columnAlignments?.name || 'left' }">{{ item.name }}</span>
<span class="score-col" :style="{ textAlign: localDisplayConfig.team?.columnAlignments?.score || 'left' }">{{ localDisplayConfig.team?.totalScoreColumn?.displayStyle === 'amount' ? '¥' : '' }}{{ formatNumber(item.totalScore) }}</span>
<span v-if="localDisplayConfig.team?.showMemberCount" class="member-col" :style="{ textAlign: localDisplayConfig.team?.columnAlignments?.memberCount || 'left' }">{{ item.memberCount }}</span>
<span v-if="localDisplayConfig.team?.showLeader" class="leader-col" :style="{ textAlign: localDisplayConfig.team?.columnAlignments?.leader || 'left' }">{{ item.leader }}</span>
<span v-if="localDisplayConfig.team?.showBonus" class="bonus-col" :style="{ textAlign: localDisplayConfig.team?.columnAlignments?.bonus || 'left' }">¥{{ item.bonus }}</span>
</div>
</div>
</div>
</div>
<div class="individual-rankings">
<!-- 英雄排名宣传语 -->
<div class="individual-rankings-propagation">
<img src="/individual-propagation.png" alt="虎狼之师" class="individual-rankings-propagation-image"
style="width: 500px; height: auto">
</div>
<!-- 英雄冠军 -->
<div class="individual-champion">
<div class="champion-content">
<div class="individual-avatar champion-container">
<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 class="champion-name">
{{ filteredIndividualRankings[0]?.name || '暂无冠军' }}
</div>
</div>
</div>
<!-- 英雄排名 -->
<div class="individual-rankings-container">
<h2 class="game-subtitle">英雄排名</h2>
<div class="rank-table">
<div class="table-header" :style="{ 'grid-template-columns': individualGridTemplate }">
<span class="rank-col" :style="{ textAlign: localDisplayConfig.individual?.columnAlignments?.rank || 'left' }">排名</span>
<span v-if="localDisplayConfig.individual?.showAvatar" class="avatar-col">头像</span>
<span class="name-col" :style="{ textAlign: localDisplayConfig.individual?.columnAlignments?.name || 'left' }">姓名</span>
<span v-if="localDisplayConfig.individual?.showTeam" class="team-col" :style="{ textAlign: localDisplayConfig.individual?.columnAlignments?.team || 'left' }">{{
localDisplayConfig.individual?.teamColumn?.displayName || '战区' }}</span>
<span class="score-col" :style="{ textAlign: localDisplayConfig.individual?.columnAlignments?.score || 'left' }">{{ localDisplayConfig.individual?.scoreColumn?.displayName || '业绩' }}</span>
<span v-if="localDisplayConfig.individual?.showLevel" class="level-col" :style="{ textAlign: localDisplayConfig.individual?.columnAlignments?.level || 'left' }">等级</span>
<span v-if="localDisplayConfig.individual?.showDepartment" class="dept-col" :style="{ textAlign: localDisplayConfig.individual?.columnAlignments?.department || 'left' }">部门</span>
<span v-if="localDisplayConfig.individual?.showBonus" class="bonus-col" :style="{ textAlign: localDisplayConfig.individual?.columnAlignments?.bonus || 'left' }">奖金</span>
</div>
<div v-for="(item, index) in filteredIndividualRankings" :key="item.id" class="table-row"
:style="{ 'grid-template-columns': individualGridTemplate }" :class="{
'top-three': index < 3,
'highlight': index === 0
}">
<span class="rank-col" :style="{ textAlign: localDisplayConfig.individual?.columnAlignments?.rank || 'left' }">{{ index + 1 }}</span>
<span v-if="localDisplayConfig.individual?.showAvatar" class="avatar-col">
<img v-if="item.avatar && item.avatar.startsWith('/')" :src="item.avatar" alt="头像"
class="avatar-image">
<span v-else>{{ item.avatar || '👤' }}</span>
</span>
<span class="name-col" :style="{ textAlign: localDisplayConfig.individual?.columnAlignments?.name || 'left' }">{{ item.name || '-' }}</span>
<span v-if="localDisplayConfig.individual?.showTeam" class="team-col" :style="{ textAlign: localDisplayConfig.individual?.columnAlignments?.team || 'left' }">{{ item.team || '-' }}</span>
<span class="score-col" :style="{ textAlign: localDisplayConfig.individual?.columnAlignments?.score || 'left' }">{{ localDisplayConfig.individual?.scoreColumn?.displayStyle === 'amount' ? '¥' : '' }}{{ formatNumber(item.score) }}</span>
<span v-if="localDisplayConfig.individual?.showLevel" class="level-col" :style="{ textAlign: localDisplayConfig.individual?.columnAlignments?.level || 'left' }"
:class="`level-${item.level}`">{{ item.level }}</span>
<span v-if="localDisplayConfig.individual?.showDepartment" class="dept-col" :style="{ textAlign: localDisplayConfig.individual?.columnAlignments?.department || 'left' }">{{ item.department }}</span>
<span v-if="localDisplayConfig.individual?.showBonus" class="bonus-col" :style="{ textAlign: localDisplayConfig.individual?.columnAlignments?.bonus || 'left' }">¥{{ item.bonus }}</span>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- 浮动倒计时组件 -->
<div class="timer-float glow-border" :style="{ right: '20px', top: '10px' }">
<span class="label">距离结束还有</span>
<div class="countdown" style="display: flex; gap: 15px;">
<span class="time-item timer-number">{{ days }}</span>
<span class="time-item timer-number">{{ hours }}</span>
<span class="time-item timer-number">{{ minutes }}</span>
<span class="time-item timer-number">{{ seconds }}</span>
</div>
</div>
<!-- 浮动管理员入口 -->
<div class="admin-entry-float">
<button @click="goToAdmin" class="btn-game-secondary">
🔐 管理员入口
</button>
</div>
</div>
</template>
<script setup>
import { ref, onBeforeMount, onMounted, onUnmounted, watch, computed, reactive, proxyRefs } from 'vue';
import { useRouter } from 'vue-router';
import {
individualRankings as importedIndividualRankings,
teamRankings as importedTeamRankings,
bonusRules,
displayConfig,
battleEndTime,
drumConfig,
initializeData
} from '../data/mockData.js';
import { readConfig } from '../services/configService.js';
// 创建默认显示配置的函数
function createDefaultDisplayConfig() {
return {
championLogos: {
teamChampion: '',
teamChampionSize: 60,
teamChampionType: 'avatar', // 'avatar' 或 'photo'
teamChampionPhotoWidth: 120,
teamChampionPhotoHeight: 80,
individualChampion: '',
individualChampionSize: 60
},
crownPosition: {
top: -100, // 皇冠位置的top值默认-100px
left: null, // 皇冠位置的left值默认null使用居中
right: null, // 皇冠位置的right值默认null
bottom: null // 皇冠位置的bottom值默认null
},
subtitleImage: {
src: '/completed_performance.png',
width: 200,
height: 60,
alt: '总战绩'
},
individual: {
scoreColumn: {
displayName: '业绩',
displayStyle: 'number'
},
teamColumn: {
displayName: '战区'
},
showLevel: true,
showDepartment: true,
showBonus: false,
showTeam: true, // 默认显示战区列
showAvatar: false, // 默认不显示头像列
defaultDisplayRows: 0, // 默认显示所有行
filterZeroScore: false, // 默认不过滤业绩为0的记录
columnWidths: {
team: 120 // 默认战区列宽
},
columnAlignments: {
rank: 'left',
name: 'left',
score: 'left',
level: 'left',
department: 'left',
team: 'left',
bonus: 'left'
}
},
team: {
totalScoreColumn: {
displayName: '战绩',
displayStyle: 'number'
},
showMemberCount: true,
showLeader: true,
showBonus: false,
defaultDisplayRows: 0, // 默认显示所有行
filterZeroScore: false, // 默认不过滤业绩为0的记录
columnWidths: {},
columnAlignments: {
rank: 'left',
name: 'left',
score: 'left',
memberCount: 'left',
leader: 'left',
bonus: 'left'
}
}
};
}
// 创建默认奖金规则的函数
function createDefaultBonusRules() {
return [
{ rank: '1-3', description: '前三名', individualBonus: '¥10000, ¥8000, ¥5000', teamBonus: '¥50000, ¥30000, ¥20000' },
{ rank: '4-10', description: '四至十名', individualBonus: '¥3000/人', teamBonus: '¥10000/队' },
{ rank: '11-20', description: '十一至二十名', individualBonus: '¥1000/人', teamBonus: '¥5000/队' }
];
}
// 初始化默认显示配置
const defaultDisplayConfig = createDefaultDisplayConfig();
// 深度合并配置,确保所有必要属性都存在
function mergeConfig(config1, config2) {
if (!config2) return config1;
const merged = { ...config1 };
for (const key in config2) {
if (config2.hasOwnProperty(key)) {
if (typeof config2[key] === 'object' && config2[key] !== null) {
merged[key] = mergeConfig(merged[key] || {}, config2[key]);
} else {
// 确保所有非对象类型的属性也被正确复制
merged[key] = config2[key];
}
}
}
return merged;
}
// 响应式数据 - 使用ref包装导入的数据确保响应式更新
const individualRankings = ref(importedIndividualRankings || []);
const teamRankings = ref(importedTeamRankings || []);
// 计算属性 - 过滤后的个人排名数据
const filteredIndividualRankings = computed(() => {
let filtered = individualRankings.value;
// 如果配置了过滤业绩为0的记录
if (localDisplayConfig.value?.individual?.filterZeroScore) {
filtered = filtered.filter(item => item.score > 0);
}
return filtered;
});
// 计算属性 - 过滤后的战区排名数据
const filteredTeamRankings = computed(() => {
let filtered = teamRankings.value;
// 如果配置了过滤业绩为0的记录
if (localDisplayConfig.value?.team?.filterZeroScore) {
filtered = filtered.filter(item => item.totalScore > 0);
}
return filtered;
});
// 格式化数字为中国人习惯的金额表达方式(使用万分位分隔符)
function formatNumber(num) {
if (num === null || num === undefined || isNaN(num)) return '0';
const numStr = num.toString();
// 先处理小数部分
const parts = numStr.split('.');
let integerPart = parts[0];
const decimalPart = parts.length > 1 ? '.' + parts[1] : '';
// 对于整数部分,从右往左每四位添加一个逗号(万分位分隔)
const formattedInteger = integerPart.replace(/\B(?=(\d{4})+(?!\d))/g, ',');
return formattedInteger + decimalPart;
}
// 计算属性 - 所有战区业绩总和
const totalTeamScore = computed(() => {
const total = teamRankings.value.reduce((total, team) => {
return total + (team.totalScore || 0);
}, 0);
return formatNumber(total);
});
// 确保即使displayConfig存在也要和默认配置合并保证结构完整性
const localDisplayConfig = ref(() => {
if (displayConfig) {
const configCopy = JSON.parse(JSON.stringify(displayConfig));
const merged = mergeConfig(defaultDisplayConfig, configCopy);
// 确保所有必要属性都存在
if (!merged.individual) merged.individual = { ...defaultDisplayConfig.individual };
if (!merged.team) merged.team = { ...defaultDisplayConfig.team };
// 确保columnAlignments属性存在
if (!merged.individual.columnAlignments) {
merged.individual.columnAlignments = { ...defaultDisplayConfig.individual.columnAlignments };
}
if (!merged.team.columnAlignments) {
merged.team.columnAlignments = { ...defaultDisplayConfig.team.columnAlignments };
}
// 确保defaultDisplayRows属性存在
if (merged.individual.defaultDisplayRows === undefined) {
merged.individual.defaultDisplayRows = defaultDisplayConfig.individual.defaultDisplayRows;
}
if (merged.team.defaultDisplayRows === undefined) {
merged.team.defaultDisplayRows = defaultDisplayConfig.team.defaultDisplayRows;
}
return merged;
}
return defaultDisplayConfig;
});
const taskSettings = ref({
mainTitle: '3000万',
subtitle: '时间: 2025-11-12 - 2026-02-08'
});
// 加载任务设置和初始化所有数据
onBeforeMount(async () => {
try {
// 首先初始化所有数据,确保从服务器获取最新配置
await initializeData();
// 然后重新获取最新的数据
const config = await readConfig();
if (config) {
// 更新任务设置
if (config.taskSettings) {
taskSettings.value = config.taskSettings;
}
// 直接从config中更新排名数据确保使用最新的服务器数据
if (config.individualRankings && config.individualRankings.length > 0) {
individualRankings.value = config.individualRankings;
}
if (config.teamRankings && config.teamRankings.length > 0) {
teamRankings.value = config.teamRankings;
}
// 更新显示配置
if (config.displayConfig) {
const configCopy = JSON.parse(JSON.stringify(config.displayConfig));
localDisplayConfig.value = mergeConfig(defaultDisplayConfig, configCopy);
}
}
} catch (error) {
console.error('加载数据失败:', error);
}
});
// 定义英雄排名表中每行默认高度
const tableIndividualTopThreeHeight = 3 * 47.5; // 前三名高度px
const tableIndividualRowHeight = 34.5; // 其他行高度px
const tableIndividualReserveHeight = 10; // 保留空间高度px
// 更新CSS变量将默认显示行数传递给样式
watch(
() => localDisplayConfig.value?.individual?.defaultDisplayRows,
(newValue) => {
if (newValue && newValue > 0) {
const otherRowsHeight = (newValue - 3) * tableIndividualRowHeight;
const actualHeight = tableIndividualTopThreeHeight + otherRowsHeight + tableIndividualReserveHeight;
document.documentElement.style.setProperty('--individual-default-height', `${actualHeight}px`);
document.documentElement.style.setProperty('--individual-overflow-y', 'auto');
document.documentElement.style.setProperty('--individual-overflow-x', 'auto');
document.documentElement.style.setProperty('--individual-scroll-lock', '');
} else {
// 根据实际数据条数计算高度
const otherRowsHeight = (filteredIndividualRankings.value.length - 3) * tableIndividualRowHeight;
const actualHeight = tableIndividualTopThreeHeight + otherRowsHeight + tableIndividualReserveHeight;
document.documentElement.style.setProperty('--individual-default-height', `${actualHeight}px`);
document.documentElement.style.setProperty('--individual-overflow-y', 'hidden');
document.documentElement.style.setProperty('--individual-overflow-x', 'hidden');
document.documentElement.style.setProperty('--individual-scroll-lock', 'lock');
}
},
{ immediate: true }
);
// 当英雄排名数据变化时,重新计算高度(如果当前是显示所有行模式)
watch(
() => filteredIndividualRankings.value.length,
() => {
console.log('filteredIndividualRankings.value.length', filteredIndividualRankings.value.length);
const displayRows = localDisplayConfig.value?.individual?.defaultDisplayRows;
if (!displayRows || displayRows === 0) {
// 根据实际数据条数计算高度
const otherRowsHeight = (filteredIndividualRankings.value.length - 3) * tableIndividualRowHeight;
const actualHeight = tableIndividualTopThreeHeight + otherRowsHeight + tableIndividualReserveHeight;
document.documentElement.style.setProperty('--individual-default-height', `${actualHeight}px`);
document.documentElement.style.setProperty('--individual-overflow-y', 'hidden');
document.documentElement.style.setProperty('--individual-overflow-x', 'hidden');
document.documentElement.style.setProperty('--individual-scroll-lock', 'lock');
}
}
);
// 定义战区排名表中每行默认高度
const tableTeamTopThreeHeight = 3 * 48; // 前三名高度px
const tableTeamRowHeight = 48; // 其他行高度px
const tableTeamReserveHeight = 20; // 保留空间高度px
// 添加监听以同步战区排名默认显示行数配置到CSS变量
watch(
() => localDisplayConfig.value?.team?.defaultDisplayRows,
(newValue) => {
if (newValue && newValue > 0) {
const otherRowsHeight = (newValue - 3) * tableTeamRowHeight;
const actualHeight = tableTeamTopThreeHeight + otherRowsHeight + tableTeamReserveHeight;
document.documentElement.style.setProperty('--team-default-height', `${actualHeight}px`);
document.documentElement.style.setProperty('--team-overflow-y', 'auto');
document.documentElement.style.setProperty('--team-overflow-x', 'auto');
document.documentElement.style.setProperty('--team-scroll-lock', '');
} else {
// 根据实际数据条数计算高度
const otherRowsHeight = (teamRankings.value.length - 3) * tableTeamRowHeight;
const actualHeight = tableTeamTopThreeHeight + otherRowsHeight + tableTeamReserveHeight;
document.documentElement.style.setProperty('--team-default-height', `${actualHeight}px`);
document.documentElement.style.setProperty('--team-overflow-y', 'hidden');
document.documentElement.style.setProperty('--team-overflow-x', 'hidden');
document.documentElement.style.setProperty('--team-scroll-lock', 'lock');
}
},
{ immediate: true }
);
// 当战区数据变化时,重新计算高度(如果当前是显示所有行模式)
watch(
() => teamRankings.value.length,
() => {
const displayRows = localDisplayConfig.value?.team?.defaultDisplayRows;
if (!displayRows || displayRows === 0) {
// 根据实际数据条数计算高度
const otherRowsHeight = (teamRankings.value.length - 3) * tableTeamRowHeight;
const actualHeight = tableTeamTopThreeHeight + otherRowsHeight + tableTeamReserveHeight;
document.documentElement.style.setProperty('--team-default-height', `${actualHeight}px`);
document.documentElement.style.setProperty('--team-overflow-y', 'hidden');
document.documentElement.style.setProperty('--team-overflow-x', 'hidden');
document.documentElement.style.setProperty('--team-scroll-lock', 'lock');
}
}
);
// 监听冠军字体大小配置变化更新CSS变量
watch(
() => localDisplayConfig.value?.championLogos,
(newConfig) => {
if (newConfig) {
// 设置战区冠军字体大小
if (newConfig.teamChampionFontSize) {
document.documentElement.style.setProperty('--team-champion-font-size', newConfig.teamChampionFontSize + 'rem');
}
// 设置英雄冠军字体大小
if (newConfig.individualChampionFontSize) {
document.documentElement.style.setProperty('--individual-champion-font-size', newConfig.individualChampionFontSize + 'rem');
}
}
},
{ immediate: true, deep: true }
);
// 监听皇冠位置配置变化,更新皇冠位置
watch(
() => localDisplayConfig.value?.crownPosition,
(newConfig) => {
if (newConfig) {
// 更新top值
if (newConfig.top !== null && newConfig.top !== undefined) {
document.documentElement.style.setProperty('--crown-top', newConfig.top + 'px');
} else {
document.documentElement.style.removeProperty('--crown-top');
}
// 更新left值
if (newConfig.left !== null && newConfig.left !== undefined) {
document.documentElement.style.setProperty('--crown-left', newConfig.left + 'px');
} else {
document.documentElement.style.removeProperty('--crown-left');
}
// 更新right值
if (newConfig.right !== null && newConfig.right !== undefined) {
document.documentElement.style.setProperty('--crown-right', newConfig.right + 'px');
} else {
document.documentElement.style.removeProperty('--crown-right');
}
// 更新bottom值
if (newConfig.bottom !== null && newConfig.bottom !== undefined) {
document.documentElement.style.setProperty('--crown-bottom', newConfig.bottom + 'px');
} else {
document.documentElement.style.removeProperty('--crown-bottom');
}
}
},
{ deep: true, immediate: true }
);
// 确保奖金规则有默认值
const displayBonusRules = computed(() => {
return Array.isArray(bonusRules) && bonusRules.length > 0
? bonusRules
: createDefaultBonusRules();
});
const router = useRouter();
// 计算英雄排名表格的列布局
const individualGridTemplate = computed(() => {
try {
const config = localDisplayConfig.value?.individual;
if (!config) return '60px 1fr 120px 80px 80px';
// 确保showTeam默认为true
if (config.showTeam === undefined) {
config.showTeam = true;
}
const widths = config.columnWidths || {};
const cols = [];
cols.push((widths.rank || 60) + 'px'); // 排名
// 头像列 - 根据配置决定是否显示
if (config.showAvatar) {
cols.push((widths.avatar || 60) + 'px'); // 头像
}
cols.push((widths.name === 1 || widths.name === '1') ? '1fr' : (widths.name || 120) + 'px'); // 姓名
// 战区列(在姓名列后面)
if (config.showTeam) {
cols.push((widths.team === 1 || widths.team === '1') ? '1fr' : (widths.team || 120) + 'px'); // 战区
}
cols.push((widths.score || 80) + 'px'); // 分数
if (config.showLevel) {
cols.push((widths.level || 80) + 'px'); // 等级
}
if (config.showDepartment) {
cols.push((widths.department === 1 || widths.department === '1') ? '1fr' : (widths.department || 100) + 'px'); // 部门
}
if (config.showBonus) {
cols.push((widths.bonus || 80) + 'px'); // 奖金
}
return cols.join(' ');
} catch (error) {
console.error('计算英雄排名表格布局出错:', error);
return '60px 1fr 120px 80px 80px'; // 兜底布局(不包含头像列)
}
});
// 计算战区排名表格的列布局
const teamGridTemplate = computed(() => {
try {
const config = localDisplayConfig.value?.team;
if (!config) return '60px 1fr 80px 80px';
const widths = config.columnWidths || {};
const cols = [];
cols.push((widths.rank || 60) + 'px'); // 排名
cols.push((widths.name === 1 || widths.name === '1') ? '1fr' : (widths.name || 150) + 'px'); // 战区名
cols.push((widths.score || 80) + 'px'); // 分数
if (config.showMemberCount) {
cols.push((widths.memberCount || 60) + 'px'); // 人数
}
if (config.showLeader) {
cols.push((widths.leader === 1 || widths.leader === '1') ? '1fr' : (widths.leader || 120) + 'px'); // 队长
}
if (config.showBonus) {
cols.push((widths.bonus || 80) + 'px'); // 奖金
}
return cols.join(' ');
} catch (error) {
console.error('计算战区排名表格布局出错:', error);
return '60px 1fr 80px 80px'; // 兜底布局
}
});
// 倒计时状态
const days = ref(0);
const hours = ref(0);
const minutes = ref(0);
const seconds = ref(0);
// 战鼓动画状态
const isBeating = ref(false);
let beatInterval = null;
let countdownInterval = null;
// 音频上下文和战鼓音效
let audioContext = null;
const isPlayingSound = ref(false);
// 战鼓位置状态
const drumsPosition = ref({ x: 20, y: 20 });
// 倒计时位置状态已移除,直接在模板中使用固定位置
// 奖金设置模块位置状态 - 使用reactive存储实际定位值
const bonusPosition = reactive({ x: 'auto', y: 'auto' });
let isDragging = false;
let isBonusDragging = false;
let dragOffset = { x: 0, y: 0 };
let bonusDragOffset = { x: 0, y: 0 };
// 节流函数
function throttle(func, limit) {
let inThrottle;
return function () {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
// 开始拖动战鼓
const startDrag = (e) => {
isDragging = true;
dragOffset.x = e.clientX - drumsPosition.value.x;
dragOffset.y = e.clientY - drumsPosition.value.y;
e.preventDefault();
};
// 开始拖动奖金模块(鼠标事件)
const startBonusDrag = (e) => {
e.stopPropagation(); // 阻止事件冒泡
isBonusDragging = true;
// 计算鼠标相对于元素左上角的偏移量
const rect = e.currentTarget.getBoundingClientRect();
bonusDragOffset.x = e.clientX - rect.left;
bonusDragOffset.y = e.clientY - rect.top;
// 提高拖动时的性能,临时禁用动画效果
e.currentTarget.style.transition = 'none';
e.preventDefault();
};
// 开始拖动奖金模块(触摸事件)
const startBonusTouch = (e) => {
e.stopPropagation(); // 阻止事件冒泡
e.preventDefault(); // 阻止默认行为,如滚动
const touch = e.touches[0];
isBonusDragging = true;
// 计算触摸点相对于元素左上角的偏移量
const rect = e.currentTarget.getBoundingClientRect();
bonusDragOffset.x = touch.clientX - rect.left;
bonusDragOffset.y = touch.clientY - rect.top;
// 提高拖动时的性能,临时禁用动画效果
e.currentTarget.style.transition = 'none';
};
// 结束拖动(鼠标和触摸事件)
const endDrag = (e) => {
isDragging = false;
if (isBonusDragging) {
// 恢复动画效果
const bonusElement = document.querySelector('.bonus-section');
if (bonusElement) {
bonusElement.style.transition = '';
}
}
isBonusDragging = false;
};
// 结束触摸拖动
const endTouch = (e) => {
if (isBonusDragging) {
// 恢复动画效果
const bonusElement = document.querySelector('.bonus-section');
if (bonusElement) {
bonusElement.style.transition = '';
}
}
isBonusDragging = false;
};
// 优化的拖动函数 - 使用节流减少更新频率(鼠标事件)
const drag = throttle((e) => {
if (isDragging) {
drumsPosition.value.x = e.clientX - dragOffset.x;
drumsPosition.value.y = e.clientY - dragOffset.y;
}
if (isBonusDragging) {
// 计算新的位置
const newX = e.clientX - bonusDragOffset.x;
const newY = e.clientY - bonusDragOffset.y;
// 确保元素不会被拖出视口
const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
const element = document.querySelector('.bonus-section');
if (element) {
const elementWidth = element.offsetWidth;
const elementHeight = element.offsetHeight;
// 限制在视口内,添加一些边距
const limitedX = Math.max(10, Math.min(newX, windowWidth - elementWidth - 10));
const limitedY = Math.max(10, Math.min(newY, windowHeight - elementHeight - 10));
// 使用优化的更新函数更新奖金模块位置
requestAnimationFrame(() => {
bonusPosition.x = limitedX;
bonusPosition.y = limitedY;
// 直接设置元素样式确保实时更新
element.style.left = `${limitedX}px`;
element.style.top = `${limitedY}px`;
element.style.right = 'auto';
element.style.bottom = 'auto';
});
}
}
}, 10); // 10ms节流约100FPS
// 优化的触摸拖动函数 - 使用节流减少更新频率
const touchMove = throttle((e) => {
if (isBonusDragging) {
e.preventDefault(); // 阻止页面滚动
const touch = e.touches[0];
// 计算新的位置
const newX = touch.clientX - bonusDragOffset.x;
const newY = touch.clientY - bonusDragOffset.y;
// 确保元素不会被拖出视口
const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
const element = document.querySelector('.bonus-section');
if (element) {
const elementWidth = element.offsetWidth;
const elementHeight = element.offsetHeight;
// 限制在视口内,添加一些边距
const limitedX = Math.max(10, Math.min(newX, windowWidth - elementWidth - 10));
const limitedY = Math.max(10, Math.min(newY, windowHeight - elementHeight - 10));
// 使用优化的更新函数更新奖金模块位置
requestAnimationFrame(() => {
bonusPosition.x = limitedX;
bonusPosition.y = limitedY;
// 直接设置元素样式确保实时更新
element.style.left = `${limitedX}px`;
element.style.top = `${limitedY}px`;
element.style.right = 'auto';
element.style.bottom = 'auto';
});
}
}
}, 10); // 10ms节流约100FPS
// 计算倒计时
const calculateCountdown = () => {
// 使用配置的结束时间
const endDateStr = `${battleEndTime.date}T${battleEndTime.time}`;
const endDate = new Date(endDateStr).getTime();
const now = new Date().getTime();
const distance = endDate - now;
if (distance > 0) {
days.value = Math.floor(distance / (1000 * 60 * 60 * 24));
hours.value = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
minutes.value = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
seconds.value = Math.floor((distance % (1000 * 60)) / 1000);
}
};
// 初始化音频上下文
const initAudioContext = () => {
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
}
};
// 音频缓存用于存储加载的MP3文件
const audioBufferCache = ref({});
// 加载MP3文件到音频缓冲区
const loadAudioFile = async (filePath) => {
try {
// 检查是否已缓存
if (audioBufferCache.value[filePath]) {
return audioBufferCache.value[filePath];
}
// 加载音频文件
const response = await fetch(filePath);
const arrayBuffer = await response.arrayBuffer();
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
// 缓存音频缓冲区
audioBufferCache.value[filePath] = audioBuffer;
return audioBuffer;
} catch (error) {
console.error('加载音频文件失败:', error);
return null;
}
};
// 播放战鼓音效
const playDrumSound = async (isStrongBeat = false) => {
// 检查是否启用声音播放
if (!audioContext || isPlayingSound.value || drumConfig?.sound?.enabled === false) return;
isPlayingSound.value = true;
try {
// 使用配置的音效参数
const soundConfig = drumConfig?.sound || {};
const patternConfig = drumConfig?.pattern || {};
// 检查是否配置了MP3文件路径
if (soundConfig.soundSrc && soundConfig.soundSrc.trim() !== '') {
// 使用MP3文件播放
const audioBuffer = await loadAudioFile(soundConfig.soundSrc);
if (audioBuffer) {
// 创建音频源节点
const source = audioContext.createBufferSource();
const gainNode = audioContext.createGain();
// 连接节点
source.buffer = audioBuffer;
source.connect(gainNode);
gainNode.connect(audioContext.destination);
// 设置音量,支持强拍音量增强
const baseVolume = soundConfig.volume || 1.0;
const accentMultiplier = patternConfig.accentMultiplier || 1.2;
const volume = isStrongBeat ? baseVolume * accentMultiplier : baseVolume;
gainNode.gain.value = volume;
// 播放声音
source.start(0);
// 设置完成后重置播放状态
setTimeout(() => {
isPlayingSound.value = false;
}, audioBuffer.duration * 1000 + 100);
return;
}
}
// 如果没有配置MP3文件或加载失败回退到合成音效
// 创建振荡器节点
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
// 连接节点
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
// 设置战鼓音效参数,支持强拍
const baseVolume = soundConfig.volume || 1.0;
// 使用pattern配置中的强拍音量倍数
const accentMultiplier = patternConfig.accentMultiplier || 1.2;
const volume = isStrongBeat ? baseVolume * accentMultiplier : baseVolume;
// 使用soundConfig中的type1
oscillator.type = soundConfig.type1 || 'sine';
// 基础频率,支持强拍频率偏移
const baseFrequency = soundConfig.frequency1 || 150;
const frequencyOffset = isStrongBeat ? (patternConfig.accentFrequencyOffset || 0) / 100 : 0;
const actualFrequency = baseFrequency * (1 + frequencyOffset);
oscillator.frequency.setValueAtTime(actualFrequency, audioContext.currentTime);
// 频率渐变
oscillator.frequency.exponentialRampToValueAtTime(actualFrequency * 0.5, audioContext.currentTime + 0.1);
// 设置音量包络
gainNode.gain.setValueAtTime(0, audioContext.currentTime);
gainNode.gain.linearRampToValueAtTime(volume, audioContext.currentTime + (soundConfig.attackTime || 0.01));
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + (soundConfig.decayTime || 0.3));
// 播放声音
oscillator.start();
oscillator.stop(audioContext.currentTime + (soundConfig.decayTime || 0.3));
// 双音调效果 - 始终使用
const oscillator2 = audioContext.createOscillator();
const gainNode2 = audioContext.createGain();
oscillator2.connect(gainNode2);
gainNode2.connect(audioContext.destination);
oscillator2.type = soundConfig.type2 || 'triangle';
oscillator2.frequency.setValueAtTime(soundConfig.frequency2 || 100, audioContext.currentTime);
gainNode2.gain.setValueAtTime(0, audioContext.currentTime);
gainNode2.gain.linearRampToValueAtTime(volume * 0.8, audioContext.currentTime + (soundConfig.attackTime || 0.01));
gainNode2.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + (soundConfig.decayTime || 0.3) + 0.2);
oscillator2.start();
oscillator2.stop(audioContext.currentTime + (soundConfig.decayTime || 0.3) + 0.2);
// 设置完成后重置播放状态
setTimeout(() => {
isPlayingSound.value = false;
}, (soundConfig.decayTime || 0.3) * 1000 + 150);
} catch (error) {
console.error('播放战鼓音效出错:', error);
isPlayingSound.value = false;
}
};
// 修改相关函数以支持异步
const handleDrumClick = async () => {
// 如果音频上下文未初始化,初始化它
if (!audioContext) {
initAudioContext();
}
// 如果音频上下文被暂停,恢复它
if (audioContext.state === 'suspended') {
audioContext.resume();
}
// 触发战鼓动画和音效,使用配置的点击效果
const animationConfig = drumConfig?.animation || {};
isBeating.value = true;
await playDrumSound(true); // 点击总是强拍
setTimeout(() => {
isBeating.value = false;
}, animationConfig.clickBeatDuration || 250);
};
// 战鼓动画效果
const startDrumAnimation = () => {
// 检查是否显示战鼓
if (drumConfig?.showDrum === false) return;
// 使用配置的动画和节拍参数
const animationConfig = drumConfig?.animation || {};
const patternConfig = drumConfig?.pattern || {};
// 检查是否启用动画
if (animationConfig.enabled === false) return;
let beatCount = 0;
// 使用配置的节拍间隔
const interval = animationConfig.beatInterval || 200;
beatInterval = setInterval(() => {
beatCount++;
// 使用配置的节拍模式和总拍数
const totalBeats = patternConfig.totalBeats || 4;
const currentBeat = ((beatCount - 1) % totalBeats) + 1;
// 根据节拍模式确定是否是强拍
const strongBeats = patternConfig.strongBeats || [1, 4];
const isStrongBeat = strongBeats.includes(currentBeat);
// 执行动画和音效
isBeating.value = true;
// 根据是否是强拍播放音效
playDrumSound(isStrongBeat);
// 设置CSS变量支持强拍动画增强
const drums = document.querySelectorAll('.drum');
drums.forEach(drum => {
// 使用配置的动画参数
drum.style.setProperty('--drum-scale', isStrongBeat ?
(animationConfig.beatScale || 1.3) * (1 + (patternConfig.accentAnimation || 0) / 100) :
(animationConfig.beatScale || 1.3));
drum.style.setProperty('--drum-translate-y', isStrongBeat ?
`${(animationConfig.beatTranslateY || -15) * (1 + (patternConfig.accentAnimation || 0) / 100)}px` :
`${animationConfig.beatTranslateY || -15}px`);
drum.style.setProperty('--drum-rotate', `${animationConfig.beatRotate || 5}deg`);
drum.style.setProperty('--drum-brightness', isStrongBeat ? '1.4' : '1.3');
drum.style.setProperty('--drum-saturation', isStrongBeat ? '1.3' : '1.2');
});
// 根据节拍类型设置持续时间
const beatDuration = isStrongBeat
? (animationConfig.beatDuration || 150)
: (animationConfig.beatDuration || 100);
setTimeout(() => {
isBeating.value = false;
}, beatDuration);
}, interval);
};
// 已移至文件中异步版本的handleDrumClick函数
// 跳转到管理员页面
const goToAdmin = () => {
router.push('/admin');
};
// 监听窗口点击事件,用于用户交互后初始化音频上下文
document.addEventListener('click', initAudioContext, { once: true });
document.addEventListener('touchstart', initAudioContext, { once: true });
const handleResize = () => {
// 计算并设置排名明细区域的最小高度,使其底部与视口对齐
const rankingsSection = document.querySelector('.rankings-section');
if (rankingsSection) {
const windowHeight = window.innerHeight;
const rankingsTop = rankingsSection.offsetTop;
const rankingsMinHeight = windowHeight - rankingsTop - 20; // 减去一些边距
if (rankingsMinHeight > 0) {
rankingsSection.style.minHeight = rankingsMinHeight + 'px';
}
}
};
onMounted(async () => {
try {
// 异步初始化数据
await initializeData();
// 更新本地显示配置确保columnAlignments属性存在
if (displayConfig) {
const configCopy = JSON.parse(JSON.stringify(displayConfig));
const defaultConfig = createDefaultDisplayConfig();
const merged = mergeConfig(defaultConfig, configCopy);
// 确保columnAlignments属性存在
if (!merged.individual.columnAlignments) {
merged.individual.columnAlignments = { ...defaultConfig.individual.columnAlignments };
}
if (!merged.team.columnAlignments) {
merged.team.columnAlignments = { ...defaultConfig.team.columnAlignments };
}
localDisplayConfig.value = merged;
} else {
localDisplayConfig.value = createDefaultDisplayConfig();
}
} catch (error) {
console.error('初始化数据失败:', error);
// 使用默认配置
localDisplayConfig.value = createDefaultDisplayConfig();
}
calculateCountdown();
countdownInterval = setInterval(calculateCountdown, 10); // 改为10ms更新一次以显示毫秒
startDrumAnimation();
// 监听窗口大小变化,确保排名明细与底部对齐
window.addEventListener('resize', handleResize);
handleResize(); // 初始调整
// 添加拖放相关的事件监听
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', endDrag);
// 添加触摸事件监听
document.addEventListener('touchmove', touchMove, { passive: false });
document.addEventListener('touchend', endTouch);
document.addEventListener('touchcancel', endTouch);
});
// 监听结束时间变化在真实环境中可能需要通过props或store来监听
const handleBattleEndTimeChange = () => {
calculateCountdown();
};
// 监听显示配置变化在真实环境中可能需要通过props或store来监听
const handleDisplayConfigChange = () => {
// 更新本地配置
localDisplayConfig.value = { ...displayConfig };
};
// 这里模拟监听配置变化
// 在实际项目中可能需要通过WebSocket或轮询来更新配置
onUnmounted(() => {
if (countdownInterval) clearInterval(countdownInterval);
if (beatInterval) clearInterval(beatInterval);
window.removeEventListener('resize', handleResize);
// 移除拖放相关的事件监听
document.removeEventListener('mousemove', drag);
document.removeEventListener('mouseup', endDrag);
// 移除触摸事件监听
document.removeEventListener('touchmove', touchMove);
document.removeEventListener('touchend', endTouch);
document.removeEventListener('touchcancel', endTouch);
// 清理音频资源
if (audioContext) {
audioContext.close();
audioContext = null;
}
});
</script>
<style lang="scss" scoped>
@keyframes crownFloat {
0% {
transform: translateY(0px) rotate(0deg);
}
50% {
transform: translateY(-5px) rotate(2deg);
}
100% {
transform: translateY(0px) rotate(0deg);
}
}
.avatar-image-champion {
object-fit: cover;
border-radius: 50%;
}
/* 冠军模块样式 */
.champion-section {
display: flex;
justify-content: space-between;
padding: 20px;
gap: 20px;
}
.team-champion,
.individual-champion {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding: 15px;
margin-bottom: 0;
}
.team-logo {
font-size: 0;
margin-bottom: 0;
display: inline-block;
color: gold;
}
.individual-avatar {
font-size: 2rem;
margin-bottom: 5px;
display: inline-block;
}
/* 冠军头像容器 */
.champion-container {
position: relative;
display: inline-block;
}
/* 皇冠动画效果 */
.crown-animation {
position: absolute;
left: var(--crown-left, 50%);
right: var(--crown-right, auto);
top: var(--crown-top, -100px);
bottom: var(--crown-bottom, auto);
transform: var(--crown-left, translateX(-50%));
z-index: 10;
text-shadow: 0 0 10px var(--gold-primary), 0 0 20px var(--gold-secondary);
}
.crown-animation-run {
animation: crownFloat 2s ease-in-out infinite, crownGlow 3s ease-in-out infinite;
}
/* 皇冠浮动动画 */
@keyframes crownFloat {
0% {
transform: translateX(-50%) translateY(0) rotate(-10deg);
}
50% {
transform: translateX(-50%) translateY(-5px) rotate(10deg);
}
100% {
transform: translateX(-50%) translateY(0) rotate(-10deg);
}
}
/* 皇冠发光效果动画 */
@keyframes crownGlow {
0%, 100% {
text-shadow: 0 0 10px var(--gold-primary), 0 0 20px var(--gold-secondary);
}
50% {
text-shadow: 0 0 15px var(--gold-primary), 0 0 30px var(--gold-secondary), 0 0 40px var(--gold-tertiary);
}
}
@keyframes crownGlow {
0%, 100% {
text-shadow: 0 0 10px var(--gold-primary), 0 0 20px var(--gold-secondary);
}
50% {
text-shadow: 0 0 15px var(--gold-primary), 0 0 30px var(--gold-secondary), 0 0 40px rgba(255, 215, 0, 0.5);
}
}
.champion-logo {
object-fit: cover;
max-width: 120px;
border-radius: 50%;
}
.photo-container .champion-logo {
max-width: unset !important;
border-radius: 0 !important;
}
.avatar-image {
width: 30px;
height: 30px;
object-fit: cover;
vertical-align: middle;
border-radius: 50%;
}
.champion-title {
font-size: 0.9rem;
color: #999;
margin-bottom: 3px;
}
.champion-name {
font-size: var(--individual-champion-font-size, 1.8rem);
font-weight: bold;
color: gold;
}
/* 战区冠军名称特殊样式 */
.team-champion .champion-name {
font-size: var(--team-champion-font-size, 1.8rem);
}
/* 基础样式 */
:root {
--gold-primary: #ffd700;
--gold-secondary: #ffed4a;
--purple-primary: #6c5ce7;
--purple-secondary: #a29bfe;
}
/* 主题容器样式 - 添加居中对齐 */
.theme-container {
text-align: center;
}
.bai-day-battle {
width: 1200px;
}
/* Banner图片样式 - 居中显示 */
.banner-image {
max-width: 90%;
height: auto;
display: inline-block;
border-radius: 8px;
}
.bonus-section {
position: fixed;
cursor: move;
transition: transform 0.2s ease;
z-index: 9999; /* 设置最高层级,确保在最上层显示 */
}
/* 奖金图片容器样式 - Flex布局居中且保持一行 */
.bonus-awards-container {
display: flex;
justify-content: center;
align-items: center;
gap: 5px;
flex-wrap: nowrap;
}
/* 奖金图片样式 */
.award-image {
width: auto;
height: 120px;
/* border-radius: 8px; */
/* box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); */
/* transition: transform 0.2s ease, box-shadow 0.2s ease; */
}
.award-image:hover {
transform: translateY(-5px);
/* box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15); */
}
/* 响应式设计 */
@media (max-width: 768px) {
.total-score-total-image {
width: 340px !important; /* 调整总战绩图片大小,覆盖内联样式 */
}
/* 移动端总战绩金额字体调小 */
.total-score-total-value {
font-size: 5rem !important; /* 调小总战绩金额字体 */
margin-top: -40px !important; /* 调整与图片的间距 */
}
.team-rankings-propagation-image {
width: 200px !important; /* 覆盖内联样式 */
}
.individual-rankings-propagation-image {
width: 200px !important; /* 覆盖内联样式 */
}
/* 战区排名宣传语容器调整 */
.team-rankings-propagation {
position: relative;
z-index: 5; /* 提高z-index避免被其他元素遮挡 */
margin-bottom: 70px; /* 进一步增大战区冠军的间距 */
}
/* 英雄排名宣传语容器调整 */
.individual-rankings-propagation {
position: relative;
z-index: 5; /* 提高z-index避免被其他元素遮挡 */
margin-bottom: 10px; /* 减小英雄榜虎狼之师图片与个人英雄图片的距离 */
}
/* 移动端战区冠军布局调整,与个人英雄冠军保持一致 */
.team-champion {
margin-bottom: 30px; /* 增加与下方战区排名标题的间距 */
padding: 10px; /* 调整内边距 */
min-height: 120px; /* 确保与英雄冠军有相同的视觉权重 */
display: flex;
align-items: center;
justify-content: center;
}
/* 移动端英雄冠军布局调整 */
.individual-champion {
margin-bottom: -10px; /* 恢复为修改之前的间距 */
padding: 10px; /* 与战区冠军保持一致的内边距 */
min-height: 120px; /* 确保与战区冠军有相同的视觉权重 */
display: flex;
align-items: center;
justify-content: center;
}
/* 确保两个排名区域在移动端有相同的起始位置 */
.team-rankings,
.individual-rankings {
position: relative;
z-index: 2; /* 统一的层级 */
padding-top: 10px; /* 统一的顶部内边距 */
}
/* 战区和英雄排名容器在移动端的统一样式 */
.team-rankings-container,
.individual-rankings-container {
margin-top: 20px; /* 与上方冠军图片的统一间距 */
}
/* 隐藏倒计时模块 */
.timer-float {
display: none !important;
}
/* 隐藏管理员入口 */
.admin-entry-float {
display: none !important;
}
/* 奖金模块垂直居中显示两侧20px间距 */
.bonus-section {
/* 背景全部取消设置 **/
background: none !important;
position: static !important;
margin: 20px auto;
width: calc(100% - 40px);
max-width: none;
left: 0 !important;
right: 0 !important;
top: 0 !important;
bottom: 0 !important;
}
/* 保留响应式中的padding设置但移除其他可能冲突的位置样式 */
.bonus-section {
padding: 8px; /* 减小padding */
}
.bonus-awards-container {
gap: 10px;
scale: 0.8;
}
/* 确保图片容器有足够的显示空间 */
.team-rankings, .individual-rankings {
position: relative;
z-index: 2; /* 确保排名区域在奖金模块之上 */
}
.timer-float {
font-size: 0.9rem;
}
.timer-float .countdown {
gap: 8px;
}
}
@media (max-width: 480px) {
.banner-image {
margin-bottom: 15px;
}
.award-image {
max-width: 100%;
}
.timer-float {
font-size: 0.8rem;
}
}
/* 浮动倒计时样式 - 科技感 */
.timer-float {
position: absolute;
background: linear-gradient(135deg, rgba(23, 25, 35, 0.95), rgba(23, 25, 35, 0.85));
padding: 15px 20px;
border-radius: 12px;
z-index: 950;
cursor: move;
backdrop-filter: blur(10px);
border: 1px solid #3a3f51;
box-shadow:
0 0 15px rgba(0, 255, 255, 0.3),
inset 0 0 10px rgba(0, 255, 255, 0.1);
animation: borderPulse 3s infinite alternate;
transition: all 0.3s ease;
}
.timer-float:hover {
transform: scale(1.05);
box-shadow:
0 0 25px rgba(0, 255, 255, 0.5),
inset 0 0 15px rgba(0, 255, 255, 0.2);
}
@keyframes borderPulse {
0% {
box-shadow:
0 0 10px rgba(0, 255, 255, 0.2),
inset 0 0 5px rgba(0, 255, 255, 0.1);
}
100% {
box-shadow:
0 0 20px rgba(0, 255, 255, 0.5),
inset 0 0 15px rgba(0, 255, 255, 0.3);
}
}
.card-game {
/* 半透明背景,增强层次感 */
background: transparent;
/* padding: 20px;
margin-bottom: 30px; */
/* 强化阴影效果 */
border: 0;
}
/* 主题部分 */
.theme-section {
background: transparent;
text-align: center;
}
.main-title {
font-size: 2.5rem;
color: var(--gold-primary);
margin-bottom: 8px;
text-shadow: 0 4px 8px rgba(0, 0, 0, 0.5);
font-weight: bold;
letter-spacing: 2px;
}
.subtitle {
font-size: 1.2rem;
color: #fff;
margin-bottom: 20px;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
}
.countdown {
font-size: 1.2rem;
margin-top: 20px;
}
.timer {
display: inline-block;
background: linear-gradient(45deg, #6c5ce7, #a29bfe);
color: white;
padding: 12px 25px;
border-radius: 50px;
font-weight: bold;
margin-bottom: 14px;
/* 下移4px */
}
/* 科技感倒计时标签 */
.timer-float .label {
color: #00e5ff;
font-family: 'Courier New', monospace;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 1px;
text-shadow: 0 0 5px rgba(0, 229, 255, 0.7);
display: block;
margin-bottom: 10px;
}
/* 科技感时间项 */
.time-item {
background: linear-gradient(135deg, #1a1d2e, #2d3748);
padding: 8px 12px;
border-radius: 8px;
margin: 0 5px;
font-size: 1.3rem;
font-family: 'Courier New', monospace;
font-weight: bold;
color: #00e5ff;
text-shadow: 0 0 10px rgba(0, 229, 255, 0.8);
border: 1px solid #00e5ff;
box-shadow:
0 0 10px rgba(0, 229, 255, 0.3),
inset 0 0 5px rgba(0, 229, 255, 0.2);
transition: all 0.2s ease;
min-width: 60px;
text-align: center;
position: relative;
overflow: hidden;
}
.time-item::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(0, 229, 255, 0.2), transparent);
animation: shine 2s infinite;
}
.time-item:hover {
transform: translateY(-2px);
box-shadow:
0 0 15px rgba(0, 229, 255, 0.5),
inset 0 0 10px rgba(0, 229, 255, 0.3);
}
.time-item.milliseconds {
font-size: 1rem;
color: #ff3d00;
border-color: #ff3d00;
text-shadow: 0 0 10px rgba(255, 61, 0, 0.8);
animation: pulse 1s infinite alternate;
}
.time-item.milliseconds::before {
background: linear-gradient(90deg, transparent, rgba(255, 61, 0, 0.2), transparent);
}
@keyframes shine {
100% {
left: 100%;
}
}
@keyframes pulse {
0% {
box-shadow:
0 0 10px rgba(255, 61, 0, 0.3),
inset 0 0 5px rgba(255, 61, 0, 0.2);
}
100% {
box-shadow:
0 0 15px rgba(255, 61, 0, 0.6),
inset 0 0 10px rgba(255, 61, 0, 0.4);
}
}
/* 毫秒闪烁动画增强紧张感 */
@keyframes blink {
0%,
50% {
opacity: 1;
transform: scale(1);
}
51%,
100% {
opacity: 0.7;
transform: scale(0.95);
}
}
/* 战鼓部分 - 浮动并支持拖放 */
.drums-section {
position: fixed;
left: 20px;
top: 20px;
padding: 20px;
background: rgba(255, 255, 255, 0.95);
border-radius: 20px;
cursor: move;
z-index: 1000;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
transition: box-shadow 0.3s ease;
}
.drums-section:hover {
box-shadow: 0 6px 30px rgba(0, 0, 0, 0.25);
}
.drums-section:active {
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}
.drums-container {
display: flex;
justify-content: center;
}
.drums-animation {
display: flex;
align-items: center;
gap: 20px;
font-size: 3rem;
}
.drum {
transition: transform 0.1s ease, filter 0.1s ease;
animation: idlePulse 2s infinite alternate;
}
.drum.beating {
/* 使用CSS变量方便动态调整 */
--drum-scale: 1.3;
--drum-translate-y: -15px;
--drum-rotate: 5deg;
--drum-brightness: 1.3;
--drum-saturation: 1.2;
transform: scale(var(--drum-scale)) translateY(var(--drum-translate-y)) rotate(var(--drum-rotate));
filter: brightness(var(--drum-brightness)) saturate(var(--drum-saturation));
animation: drumBeat 0.1s ease-in-out;
}
/* 战鼓闲置时的轻微脉动动画 */
@keyframes idlePulse {
0% {
transform: scale(1);
}
100% {
transform: scale(1.05);
}
}
/* 增强跳动效果的关键帧动画 */
@keyframes drumBeat {
0% {
transform: scale(1);
}
50% {
transform: scale(var(--drum-scale, 1.3)) translateY(var(--drum-translate-y, -15px)) rotate(var(--drum-rotate, 5deg));
}
100% {
transform: scale(1);
}
}
.trophy {
animation: bounce 1s infinite alternate;
}
@keyframes bounce {
from {
transform: translateY(0);
}
to {
transform: translateY(-10px);
}
}
/* 按钮样式 */
.btn-game-secondary {
background: linear-gradient(45deg, #6c5ce7, #a29bfe);
color: white;
border: none;
padding: 12px 20px;
border-radius: 30px;
font-size: 1rem;
cursor: pointer;
box-shadow: 0 4px 20px rgba(108, 92, 231, 0.4);
transition: all 0.3s ease;
border: 2px solid rgba(255, 255, 255, 0.3);
display: inline-flex;
align-items: center;
gap: 8px;
}
.btn-game-secondary:hover {
transform: scale(1.1) translateY(-2px);
box-shadow: 0 6px 30px rgba(108, 92, 231, 0.6);
background: linear-gradient(45deg, #7f7fd5, #86a8e7);
}
/* 排名部分 */
.rankings-section {
margin: 0 20px 30px 20px;
}
.rankings-container {
display: flex;
gap: 15px;
flex-wrap: wrap;
justify-content: center;
background: none;
border: none;
}
.individual-rankings,
.team-rankings {
flex: 1;
min-width: 350px;
max-width: 550px;
}
/* 为指定的容器添加背景和边框 */
.team-rankings-container,
.individual-rankings-container {
background: rgba(255, 255, 255, 0.95);
border-radius: 15px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
border: 2px solid rgba(255, 215, 0, 0.5);
padding: 15px;
}
.section-title {
color: #d63031;
text-align: center;
margin-bottom: 15px;
font-size: 1.6rem;
}
.task-settings-section {
margin-top: -220px;
}
.task-title-container {
padding: 30px 40px;
text-align: center;
}
.task-title-container .game-title {
color: #ffffff;
font-size: 2.5rem;
font-weight: bold;
margin: 0 0 15px 0;
animation: glow-pulse 2s infinite alternate;
}
.task-title-container .game-title .game-title-highlight {
font-size: 3.5rem;
}
.task-title-container .game-subtitle {
color: #ffffff;
font-size: 1.5rem;
margin: 0;
}
@keyframes glow-pulse {
0% {
text-shadow: 3px 3px 0 rgba(0, 0, 0, 0.2);
}
100% {
text-shadow: 3px 3px 0 rgba(0, 0, 0, 0.2), 0 0 20px rgba(255, 255, 255, 0.8);
}
}
.rank-table {
border-radius: 10px;
overflow: hidden;
overflow-y: auto;
position: relative;
margin-top: 0.8rem;
max-height: 420px;
// 只对左侧战区的.rank-table生效通过父容器限定
.team-rankings-container & {
-ms-overflow-style: none; /* IE/Edge 隐藏 */
scrollbar-width: none; /* Firefox 隐藏 */
}
// Chrome/Safari 隐藏左侧滚动条(伪元素必须单独写)
.team-rankings-container &::-webkit-scrollbar {
display: none !important;
width: 0 !important;
}
// ========== 新增:右侧英雄排名滚动条保留原样 ==========
.individual-rankings-container & {
-ms-overflow-style: auto; /* 恢复IE/Edge默认 */
scrollbar-width: auto; /* 恢复Firefox默认 */
}
// Chrome/Safari 恢复右侧滚动条
.individual-rankings-container &::-webkit-scrollbar {
display: block !important;
width: 6px !important; // 恢复默认滚动条宽度
}
}
.table-header {
background: linear-gradient(45deg, #6c5ce7, #a29bfe);
color: white;
display: grid;
padding: 12px 10px;
font-weight: bold;
position: sticky;
top: 0;
z-index: 10;
/* 增强标题可读性 */
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.team-rankings .table-header {
position: sticky;
top: 0;
z-index: 10;
}
.table-row {
display: grid;
padding: 12px 10px;
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
transition: all 0.3s ease;
/* 浅色背景增强可读性 */
background: rgba(255, 255, 255, 0.9);
color: #333;
}
.team-rankings .table-row {
padding: 12px 10px;
}
.table-row:hover {
background-color: rgba(255, 255, 255, 0.95);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}
.table-row.top-three {
background-color: rgba(255, 243, 205, 0.95);
font-size: 1.1rem;
font-weight: bold;
color: #000;
transform: scale(1.02);
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.2);
transition: all 0.3s ease;
z-index: 2;
position: relative;
}
.table-row.top-three:hover {
transform: scale(1.03);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.15);
}
/* 前三名特殊背景色,增强亮度和对比度 - 确保英雄排名和战区排名样式一致 */
.team-rankings-container .table-row:nth-child(1),
.individual-rankings-container .table-row:nth-child(1) {
background: linear-gradient(135deg, #ffd700, #403f3c);
color: #333;
box-shadow: 0 6px 20px rgba(255, 215, 0, 0.4);
}
.team-rankings-container .table-row:nth-child(2),
.individual-rankings-container .table-row:nth-child(2) {
background: linear-gradient(135deg, #c0c0c0, #e0e0e0);
color: #333;
box-shadow: 0 6px 20px rgba(192, 192, 192, 0.4);
}
.team-rankings-container .table-row:nth-child(3),
.individual-rankings-container .table-row:nth-child(3) {
background: linear-gradient(135deg, #cd7f32, #d7ccc8);
color: #333;
box-shadow: 0 6px 20px rgba(205, 127, 50, 0.4);
}
.table-row.highlight {
background: linear-gradient(135deg, #ffd32a, #ff7979);
}
.level-SSS {
color: #ffd700;
font-weight: bold;
}
.level-SS {
color: #c0c0c0;
font-weight: bold;
}
.level-S {
color: #cd7f32;
font-weight: bold;
}
.level-A {
color: #4caf50;
font-weight: bold;
}
.level-B {
color: #2196f3;
font-weight: bold;
}
/* 浮动管理员入口 */
.admin-entry-float {
position: fixed;
bottom: 20px;
left: 20px;
z-index: 1000;
}
/* 管理员按钮使用通用按钮样式 */
.admin-entry-float .btn-game-secondary {
font-size: 0.8rem;
padding: 8px 16px;
min-width: 80px;
border-radius: 6px;
}
/* 针对高度大于1080分辨率的精确优化 */
/* 移动端背景图片设置 - 全局样式 */
/* 总战绩部分样式 */
.total-score-section {
margin: 20px auto;
max-width: 1200px;
padding: 20px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
animation: fadeIn 0.5s ease-in-out;
}
.total-score-container {
display: flex;
flex-direction: column;
gap: 15px;
}
.total-score-item {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
padding: 10px;
min-height: 60px; /* 确保有足够的高度来展示垂直居中效果 */
}
.score-value {
font-size: calc(var(--individual-champion-font-size, 6rem) * 2);
font-weight: bold;
color: #fff2c4;
text-shadow: 0 0 10px rgba(0, 0, 0, .8), 0 0 20px rgb(16 16 16 / 30%), 1px 1px 2px rgba(0, 0, 0, .8);
}
.total-score-total-value {
margin-top: -40px;
}
/* 战区冠军分数特殊样式 */
.team-champion .score-value {
font-size: calc(var(--team-champion-font-size, 1.8rem) * 4);
text-shadow:
0 0 15px rgba(255, 215, 0, 0.7),
0 0 30px rgba(255, 215, 0, 0.4),
2px 2px 3px rgba(0, 0, 0, 0.9);
}
/* 照片容器样式 */
.team-logo.photo-container {
overflow: hidden;
margin-top: -97px;
}
.individual-champion {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
margin-bottom: 20px;
gap: 30px;
}
.team-rankings-propagation {
align-items: center;
display: flex;
justify-content: center;
}
.individual-rankings-propagation {
align-items: center;
display: flex;
justify-content: center;
}
@media (max-width: 768px) {
.total-score-total-title {
align-items: center;
display: flex;
justify-content: center;
}
/* 战区排名容器设置 - 根据配置决定显示行数和滚动行为 */
.team-rankings-container .rank-table {
position: relative;
min-height: auto;
/* 移动端强制显示所有行覆盖JS动态设置的CSS变量 */
height: auto !important;
max-height: none !important;
overflow-y: visible !important;
overflow-x: auto !important;
/* 强制覆盖CSS变量 */
--team-default-height: auto !important;
--team-overflow-y: visible !important;
--team-overflow-x: auto !important;
}
/* 移动端战区排名显示所有内容,不受滚动锁定影响 */
:root[style*="--team-scroll-lock: lock"] .team-rankings-container .rank-table {
overflow-y: visible !important;
overflow-x: auto !important;
height: auto !important;
min-width: auto !important;
width: 100% !important;
}
/* 确保表格内容在移动端正确显示 */
:root[style*="--team-scroll-lock: lock"] .team-rankings-container .rank-table .table-header,
:root[style*="--team-scroll-lock: lock"] .team-rankings-container .rank-table .table-row {
min-width: auto !important;
width: 100% !important;
overflow-x: visible !important;
white-space: nowrap !important;
}
.individual-rankings-propagation {
margin-top: -40px;
padding-bottom: 10px;
margin-bottom: 20px; /* 恢复为修改之前的间距 */
}
.individual-rankings {
margin-top: 60px; /* 增加排名列表的顶部间距 */
}
/* 移动端战区排名容器位置调整 */
.team-rankings {
margin-top: 0; /* 确保与英雄排名区域在统一水平线 */
}
/* 英雄排名容器设置 - 根据配置决定显示行数和滚动行为 */
.individual-rankings-container .rank-table {
position: relative;
min-height: auto;
/* 移动端强制显示所有行覆盖JS动态设置的CSS变量 */
height: auto !important;
max-height: none !important;
overflow-y: visible !important;
overflow-x: auto !important;
/* 隐藏滚动条 */
-ms-overflow-style: none;
scrollbar-width: none;
/* 强制覆盖CSS变量 */
--individual-default-height: auto !important;
--individual-overflow-y: visible !important;
--individual-overflow-x: auto !important;
}
/* 移动端英雄排名显示所有内容,不受滚动锁定影响 */
:root[style*="--individual-scroll-lock: lock"] .individual-rankings-container .rank-table {
overflow-y: visible !important;
overflow-x: auto !important;
height: auto !important;
min-width: auto !important;
width: 100% !important;
}
/* 确保表格内容在移动端正确显示 */
:root[style*="--individual-scroll-lock: lock"] .individual-rankings-container .rank-table .table-header,
:root[style*="--individual-scroll-lock: lock"] .individual-rankings-container .rank-table .table-row {
min-width: auto !important;
width: 100% !important;
overflow-x: visible !important;
white-space: nowrap !important;
}
/* 移动端非前三名字体放大 */
.team-rankings-container .table-row:not(:nth-child(1)):not(:nth-child(2)):not(:nth-child(3)),
.individual-rankings-container .table-row:not(:nth-child(1)):not(:nth-child(2)):not(:nth-child(3)) {
font-size: 1.1rem;
}
/* 移动端名次列水平垂直居中 */
.team-rankings-container .table-header > :first-child,
.individual-rankings-container .table-header > :first-child,
.team-rankings-container .table-row > :first-child,
.individual-rankings-container .table-row > :first-child {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
/* 确保前三名特殊样式在移动端正确显示 */
.team-rankings-container .table-row.top-three,
.individual-rankings-container .table-row.top-three {
transform: scale(1);
box-shadow: none;
position: static;
}
.team-rankings-container .table-row:nth-child(1),
.team-rankings-container .table-row:nth-child(2),
.team-rankings-container .table-row:nth-child(3),
.individual-rankings-container .table-row:nth-child(1),
.individual-rankings-container .table-row:nth-child(2),
.individual-rankings-container .table-row:nth-child(3) {
box-shadow: none;
z-index: 1;
}
/* 当设置为禁止滚动时,确保战区排名容器不允许滚动 */
:root[style*="--team-scroll-lock: lock"] .team-rankings-container {
overflow: visible !important;
height: auto !important;
}
:root[style*="--team-scroll-lock: lock"] .team-rankings-container .rank-table {
overflow: hidden !important;
display: block;
min-width: auto !important;
width: 100% !important;
}
/* 确保表格头部和行在禁止滚动模式下能够完整显示内容 */
:root[style*="--team-scroll-lock: lock"] .team-rankings-container .table-header,
:root[style*="--team-scroll-lock: lock"] .team-rankings-container .table-row {
min-width: auto !important;
width: 100% !important;
overflow-x: visible !important;
white-space: normal !important;
}
/* 英雄排名列表隐藏水平滚动条 */
.individual-rankings-container .rank-table::-webkit-scrollbar {
width: 6px; /* 保留垂直滚动条 */
height: 0; /* 隐藏水平滚动条 */
}
/* 移除原有卡片背景,让内容在背景图上显示 */
.card-game {
background: transparent;
box-shadow: none;
}
/* 主题部分调整 */
.theme-section {
width: 100%;
margin: 0;
padding: 0;
}
.banner-image {
width: 100%;
height: auto;
}
/* 战鼓部分调整 */
.drums-section {
transform: scale(0.8);
/* 缩小战鼓元素 */
}
/* 2. 倒计时模块调整 - 移至冠军战区上方,缩小时间显示为一行 */
.timer-float {
position: relative;
right: auto;
top: auto;
margin: 10px auto;
width: 95%;
padding: 8px;
border-radius: 8px;
background: rgba(0, 0, 0, 0.8);
color: white;
text-align: center;
}
.timer-float .label {
font-size: 0.9rem;
display: block;
margin-bottom: 5px;
}
.countdown {
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
flex-wrap: nowrap;
}
.time-item {
font-size: 0.85rem;
padding: 4px 6px;
background: rgba(255, 215, 0, 0.2);
border-radius: 4px;
border: 1px solid rgba(255, 215, 0, 0.5);
}
/* 任务设置调整 */
.task-settings-section {
margin-top: -100px;
/* 调整负边距 */
}
.task-title-container {
padding: 15px;
}
.task-title-container .game-title {
font-size: 1.6rem;
}
.task-title-container .game-title-highlight {
font-size: 2rem;
}
.task-title-container .game-subtitle {
font-size: 1rem;
}
/* 排名部分调整 */
.rankings-section {
margin: 0 10px 20px 10px;
}
.rankings-container {
flex-direction: column;
gap: 10px;
}
.individual-rankings,
.team-rankings {
min-width: auto;
width: 100%;
/* 调整顺序,确保倒计时在冠军上方 */
display: flex;
flex-direction: column;
}
/* 将倒计时移动到冠军上方的位置 */
.team-rankings {
order: -1;
}
.team-rankings-container,
.individual-rankings-container {
padding: 10px;
border-radius: 10px;
background: rgba(255, 255, 255, 0.95);
}
/* 当设置为禁止滚动时,确保战区排名容器不允许滚动 */
:root[style*="--team-scroll-lock: lock"] .team-rankings-container {
overflow: visible !important;
height: auto !important;
}
:root[style*="--team-scroll-lock: lock"] .team-rankings-container .rank-table {
overflow: hidden !important;
white-space: nowrap;
display: block;
}
/* 表格调整 */
.rank-table {
min-height: 250px;
/* 移除最大高度限制,允许显示所有行 */
overflow-x: hidden;
/* 禁止横向滚动 */
overflow-y: auto;
/* 允许纵向滚动 */
/* 隐藏移动端滚动条 */
-ms-overflow-style: none;
scrollbar-width: none;
display: flex;
flex-direction: column;
}
/* 隐藏WebKit浏览器移动端滚动条 */
.rank-table::-webkit-scrollbar {
display: none;
}
/* 英雄排名列表设置 - 根据配置决定显示行数和滚动行为 */
.individual-rankings-container .rank-table {
overflow-x: hidden !important;
/* 禁止横向滚动 */
height: var(--individual-default-height, auto) !important;
overflow-y: var(--individual-overflow-y, auto) !important;
/* 确保英雄排名列表隐藏滚动条 */
-ms-overflow-style: none;
scrollbar-width: none;
display: flex;
flex-direction: column;
}
/* 当设置了滚动锁定时,禁止所有滚动 */
:root[style*="--individual-scroll-lock: lock"] .individual-rankings-container {
overflow: visible !important;
height: auto !important;
}
:root[style*="--individual-scroll-lock: lock"] .individual-rankings-container .rank-table {
overflow: hidden !important;
white-space: nowrap;
display: block;
}
.individual-rankings-container .rank-table::-webkit-scrollbar {
display: none;
}
.table-header {
font-size: 1rem;
padding: 8px 6px;
min-width: 500px;
/* 固定表头,防止滚动时移动 */
position: sticky;
top: 0;
z-index: 10;
background-color: rgba(255, 255, 255, 0.95);
}
.table-row {
font-size: 0.9rem;
padding: 8px 6px;
min-width: 500px;
/* 确保行内容不会被截断 */
overflow: visible;
}
/* 冠军部分调整 */
.team-champion,
.individual-champion {
margin: 5px 0;
}
/* 管理员入口调整 */
.admin-entry-float {
position: relative;
top: auto;
right: auto;
margin: 10px;
text-align: center;
}
.btn-game-secondary {
padding: 10px 15px;
font-size: 0.9rem;
}
/* 3. 奖金模块调整 - 移至底部显示 */
.bonus-section {
position: fixed;
bottom: 0;
left: 0;
right: 0;
width: 100%;
margin: 0;
padding: 10px;
z-index: 1000;
transform: translateY(0);
transition: transform 0.3s ease;
box-shadow: none;
}
.bonus-awards-container {
display: flex;
justify-content: space-around;
align-items: center;
}
.award-image {
height: 120px;
width: auto;
}
/* 确保重要内容优先显示 */
.rank-col,
.name-col,
.score-col {
font-weight: bold;
}
/* 为底部奖金模块留出空间 */
.admin-entry-float {
margin-bottom: 100px;
}
/* 针对极小屏幕的特殊处理 */
@media (max-width: 480px) {
.table-header {
font-size: 0.9rem;
padding: 8px 6px;
min-width: 450px;
}
.table-row {
min-width: 450px;
font-size: 0.75rem;
padding: 6px 4px;
}
.game-title {
font-size: 1.4rem;
}
.game-title-highlight {
font-size: 1.7rem;
}
.award-image {
height: 120px;
}
.countdown {
gap: 6px;
}
.time-item {
font-size: 0.8rem;
padding: 3px 5px;
}
}
}
/* 触摸设备优化 */
@media (hover: none) and (pointer: coarse) {
/* 增大点击区域 */
.btn-game-secondary {
padding: 12px 24px;
font-size: 1rem;
}
/* 移除hover效果添加触摸反馈 */
.table-row:active {
background-color: rgba(255, 255, 255, 0.95);
transform: scale(1.01);
}
.btn-game-secondary:active {
transform: scale(0.98);
}
}
/* 响应式设计1200px以上显示 */
@media (min-width: 1920px) {
.bonus-section {
top: 360px;
left: 320px;
}
}
@media (min-width: 2000px) {
.bonus-section {
position: fixed;
top: 360px;
left: 720px;
z-index: 9999; /* 设置最高层级,确保在最上层显示 */
cursor: move;
transition: transform 0.2s ease;
}
}
.team-rankings-container .rank-table {
-ms-overflow-style: none !important;
scrollbar-width: none !important;
}
.team-rankings-container .rank-table::-webkit-scrollbar {
display: none !important;
width: 0 !important;
}
</style>