DCFronted/src/components/RankContestant.vue
2025-08-01 01:29:18 +08:00

274 lines
6.9 KiB
Vue

<template>
<div class="rank-contestant">
<div class="rank-contestant-header">
<h2>选手排名</h2>
</div>
<div class="rank-content">
<div class="top-three">
<div v-for="(item, idx) in rankData.slice(0, 3)" :key="idx" class="rank-card">
<div class="rank-number">
{{ item.rank }}
</div>
<div class="player-info">
<div class="player-name">{{ item.username }}</div>
<div class="player-faction">{{ item.faction }}</div>
<div class="player-score" :title="`积分: ${item.points}`">{{ item.score }}</div>
</div>
</div>
</div>
<div class="rank-list">
<div v-for="(item, idx) in rankData.slice(3)" :key="idx + 3" class="rank-item">
<div class="rank">{{ item.rank }}</div>
<div class="player-info">
<div class="player-name">{{ item.username }}</div>
<div class="player-faction">{{ item.faction }}</div>
<div class="player-score">{{ item.score }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, watch } from 'vue'
import { getSignUpResultList } from '@/api/tournament'
const props = defineProps({
tournamentId: {
type: Number,
required: true
}
})
const rankData = ref([])
const fetchRankData = async () => {
try {
const response = await getSignUpResultList()
console.log('RankContestant 原始数据:', response)
// 筛选当前赛事的玩家
const filteredPlayers = response.filter(player => player.tournament_id === props.tournamentId)
console.log('RankContestant 筛选后数据:', filteredPlayers)
// 按玩家名称分组,计算总胜利数和总失败数
const playerStats = {}
filteredPlayers.forEach((player, index) => {
const playerName = player.sign_name
const win = parseInt(player.win || 0)
const lose = parseInt(player.lose || 0)
const round = player.round || '0'
console.log(`RankContestant 处理第${index + 1}条数据:`, {
id: player.id,
sign_name: playerName,
round: round,
win: win,
lose: lose,
status: player.status
})
if (!playerStats[playerName]) {
playerStats[playerName] = {
username: playerName,
faction: player.faction || player.team_name || '',
totalWin: 0,
totalLose: 0,
totalPoints: 0,
rounds: []
}
}
playerStats[playerName].totalWin += win
playerStats[playerName].totalLose += lose
playerStats[playerName].rounds.push(round)
// 计算积分(胜场数)
playerStats[playerName].totalPoints = playerStats[playerName].totalWin
})
console.log('RankContestant 分组后统计:', playerStats)
// 转换为数组并按总胜利数排序
const sortedPlayers = Object.values(playerStats)
.sort((a, b) => {
// 首先按总胜利数排序
if (b.totalWin !== a.totalWin) {
return b.totalWin - a.totalWin
}
// 如果胜利数相同,按失败数排序(失败数少的排名靠前)
return a.totalLose - b.totalLose
})
.map((player, index) => ({
id: index + 1, // 使用索引作为ID
rank: (index + 1).toString(),
username: player.username,
faction: player.faction,
win: player.totalWin,
lose: player.totalLose,
points: player.totalPoints,
status: '',
bracket_type: 'winners',
score: `${player.totalWin}${player.totalLose}负 (${player.totalPoints.toFixed(1)}分)`,
rounds: player.rounds.join(',')
}))
console.log('RankContestant 最终排名结果:', sortedPlayers)
rankData.value = sortedPlayers
} catch (error) {
console.error('获取排名数据失败:', error)
}
}
onMounted(() => {
fetchRankData()
})
// 当比赛ID变化时重新获取数据
watch(() => props.tournamentId, () => {
if (props.tournamentId) {
fetchRankData()
}
})
</script>
<style scoped>
.rank-contestant {
background: white;
border-radius: 8px;
padding: 24px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.rank-contestant-header {
margin-bottom: 24px;
}
.rank-contestant-header h2 {
font-size: 20px;
color: #303133;
margin: 0;
}
.rank-content {
display: flex;
flex-direction: column;
gap: 24px;
}
.top-three {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.rank-card {
background: white;
border-radius: 8px;
padding: 20px;
display: flex;
align-items: center;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
border: 1px solid #EBEEF5;
}
.rank-card:nth-child(1) {
background: #FFF9EB;
border: 1px solid #FFE4B5;
}
.rank-card:nth-child(2) {
background: #F8F9FA;
border: 1px solid #E4E7ED;
}
.rank-card:nth-child(3) {
background: #FDF6EC;
border: 1px solid #F3D19E;
}
.rank-number {
font-size: 24px;
font-weight: bold;
margin-right: 16px;
min-width: 50px;
text-align: center;
}
.rank-card:nth-child(1) .rank-number {
color: #E6A23C;
}
.rank-card:nth-child(2) .rank-number {
color: #909399;
}
.rank-card:nth-child(3) .rank-number {
color: #F56C6C;
}
.player-info {
flex: 1;
}
.player-name {
font-size: 16px;
font-weight: 500;
color: #303133;
margin-bottom: 4px;
}
.player-qq {
font-size: 14px;
color: #909399;
margin-bottom: 4px;
}
.player-faction {
font-size: 14px;
color: #409EFF;
margin-bottom: 4px;
}
.player-score {
font-size: 14px;
color: #67C23A;
font-weight: 500;
}
.rank-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.rank-item {
display: flex;
align-items: center;
padding: 16px;
background: white;
border-radius: 4px;
border: 1px solid #EBEEF5;
}
.rank {
width: 40px;
font-size: 16px;
font-weight: 600;
color: #909399;
text-align: center;
margin-right: 16px;
}
@media (max-width: 768px) {
.top-three {
grid-template-columns: 1fr;
}
.rank-contestant {
padding: 16px;
}
}
</style>