Refactor TournamentPlacementsTab to use groupedRankingList and improve final placements display

- Updated the final placements logic to utilize groupedRankingList for better performance and accuracy.
- Enhanced the display of class placements, including handling cases for entries without a class.
- Improved the no placements message condition to reflect the new data structure.
- Added a new computed method to retrieve player names from entry objects, enhancing clarity in the UI.
This commit is contained in:
Torsten Schulz (local)
2025-11-29 00:28:47 +01:00
parent 6acdcfa5c3
commit bf0d5b0935
2 changed files with 26 additions and 89 deletions

View File

@@ -9,13 +9,16 @@
/>
<!-- Endplatzierungen (K.O.-Runde) -->
<section v-if="finalPlacements.length > 0" class="final-placements">
<section v-if="Object.keys(finalPlacementsByClass).length > 0" class="final-placements">
<h3>{{ $t('tournaments.finalPlacements') }}</h3>
<template v-for="(classPlacements, classId) in finalPlacementsByClass" :key="`final-${classId}`">
<div v-if="shouldShowClass(classId === 'null' ? null : parseInt(classId))" class="class-section">
<h4 v-if="classId !== 'null' && classId !== 'undefined'" class="class-header">
{{ getClassName(classId) }}
</h4>
<h4 v-else class="class-header">
{{ $t('tournaments.withoutClass') }}
</h4>
<table>
<thead>
<tr>
@@ -24,9 +27,9 @@
</tr>
</thead>
<tbody>
<tr v-for="placement in classPlacements" :key="placement.id">
<td><strong>{{ placement.position }}.</strong></td>
<td>{{ placement.name }}</td>
<tr v-for="(entry, entryIdx) in classPlacements" :key="`${entry.member?.id || entryIdx}-${entryIdx}`">
<td><strong>{{ entry.position }}.</strong></td>
<td>{{ getEntryPlayerName(entry) }}</td>
</tr>
</tbody>
</table>
@@ -69,7 +72,7 @@
</template>
</section>
<div v-if="finalPlacements.length === 0 && groupPlacements.length === 0" class="no-placements">
<div v-if="Object.keys(finalPlacementsByClass).length === 0 && groupPlacements.length === 0" class="no-placements">
<p>{{ $t('tournaments.noPlacementsYet') }}</p>
</div>
</div>
@@ -108,6 +111,10 @@ export default {
type: Object,
required: true
},
groupedRankingList: {
type: Object,
required: true
},
participants: {
type: Array,
required: true
@@ -125,91 +132,10 @@ export default {
'update:selectedViewClass'
],
computed: {
finalPlacements() {
// Extrahiere Endplatzierungen aus den K.O.-Matches
const placements = [];
const finishedMatches = this.knockoutMatches.filter(m => m.isFinished);
// Finde die Finale-Matches (letzte Runde)
const rounds = [...new Set(finishedMatches.map(m => m.round))];
if (rounds.length === 0) return [];
// Sortiere Runden nach Reihenfolge (Finale ist die letzte)
const roundOrder = ['Finale', 'Halbfinale', 'Viertelfinale', 'Achtelfinale'];
rounds.sort((a, b) => {
const aIdx = roundOrder.indexOf(a);
const bIdx = roundOrder.indexOf(b);
if (aIdx === -1 && bIdx === -1) return a.localeCompare(b);
if (aIdx === -1) return 1;
if (bIdx === -1) return -1;
return aIdx - bIdx;
});
const finalRound = rounds[rounds.length - 1];
const finalMatches = finishedMatches.filter(m => m.round === finalRound);
// Für jedes Finale-Match: Gewinner = Platz 1, Verlierer = Platz 2
finalMatches.forEach(match => {
const winner = this.getMatchWinner(match);
const loser = this.getMatchLoser(match);
if (winner) {
placements.push({
id: `final-${match.id}-winner`,
classId: match.classId,
position: 1,
name: winner,
matchId: match.id
});
}
if (loser) {
placements.push({
id: `final-${match.id}-loser`,
classId: match.classId,
position: 2,
name: loser,
matchId: match.id
});
}
});
// Wenn es Halbfinale gibt, finde die Verlierer (Platz 3)
const semiFinalRound = rounds.find(r => r.includes('Halbfinale'));
if (semiFinalRound) {
const semiFinalMatches = finishedMatches.filter(m => m.round === semiFinalRound);
semiFinalMatches.forEach(match => {
const loser = this.getMatchLoser(match);
if (loser) {
placements.push({
id: `semi-${match.id}-loser`,
classId: match.classId,
position: 3,
name: loser,
matchId: match.id
});
}
});
}
return placements.sort((a, b) => {
if (a.classId !== b.classId) {
const aNum = a.classId || 999999;
const bNum = b.classId || 999999;
return aNum - bNum;
}
return a.position - b.position;
});
},
finalPlacementsByClass() {
const grouped = {};
this.finalPlacements.forEach(p => {
const key = p.classId || 'null';
if (!grouped[key]) {
grouped[key] = [];
}
grouped[key].push(p);
});
return grouped;
// Verwende die bereits berechnete groupedRankingList aus TournamentTab
// Diese enthält die korrekten Platzierungen basierend auf extendedRankingList oder rankingList
return this.groupedRankingList;
},
groupPlacements() {
// Extrahiere Gruppenplatzierungen
@@ -393,6 +319,16 @@ export default {
name1: this.getPlayerName(match.player1, match),
name2: this.getPlayerName(match.player2, match)
};
},
getEntryPlayerName(entry) {
// Die entry hat die Struktur: { position, member, classId }
// member ist ein Member-Objekt mit firstName/lastName direkt
if (entry.member) {
if (entry.member.firstName && entry.member.lastName) {
return `${entry.member.firstName} ${entry.member.lastName}`;
}
}
return this.$t('tournaments.unknown');
}
}
};

View File

@@ -218,6 +218,7 @@
:knockout-matches="knockoutMatches"
:groups="groups"
:group-rankings="groupRankings"
:grouped-ranking-list="groupedRankingList"
:participants="participants"
:external-participants="externalParticipants"
:pairings="pairings"