feat(tournament): enhance tournament group handling for pools and classes

- Updated TournamentService to manage participant class IDs more effectively in pooled groups, ensuring accurate statistics and match handling.
- Refactored TournamentGroupsTab and TournamentPlacementsTab components to utilize a new method for retrieving group rankings based on class ID, improving data organization.
- Adjusted getLivePosition method to accommodate group objects, enhancing flexibility in live match updates.
- Improved group ranking logic to support multiple entries per group and class, ensuring accurate display of tournament standings.
This commit is contained in:
Torsten Schulz (local)
2026-01-30 22:51:04 +01:00
parent 7e1b09fa97
commit 6cdcbfe0db
4 changed files with 53 additions and 20 deletions

View File

@@ -118,14 +118,14 @@
<th>{{ $t('tournaments.sets') }}</th>
<th>{{ $t('tournaments.diff') }}</th>
<th>{{ $t('tournaments.pointsRatio') }}</th>
<th v-for="(opponent, idx) in groupRankings[group.groupId]" :key="`opp-${opponent.id}`">
<th v-for="(opponent, idx) in groupRankingsForGroup(group)" :key="`opp-${opponent.id}`">
G{{ String.fromCharCode(96 + group.groupNumber) }}{{ idx + 1 }}
</th>
<th>{{ $t('tournaments.livePosition') }}</th>
</tr>
</thead>
<tbody>
<tr v-for="(pl, idx) in groupRankings[group.groupId]" :key="pl.id">
<tr v-for="(pl, idx) in groupRankingsForGroup(group)" :key="pl.id">
<td><strong>G{{ String.fromCharCode(96 + group.groupNumber) }}{{ idx + 1 }}</strong></td>
<td>{{ pl.position }}.</td>
<td><span v-if="pl.seeded" class="seeded-star">★</span>{{ pl.name }}<span v-if="pl.gaveUp" class="gave-up-badge" :title="$t('tournaments.gaveUpHint')">{{ $t('tournaments.gaveUp') }}</span></td>
@@ -140,7 +140,7 @@
({{ (Math.abs(pl.pointsWon || 0) - Math.abs(pl.pointsLost || 0)) >= 0 ? '+' : '' }}{{ Math.abs(pl.pointsWon || 0) - Math.abs(pl.pointsLost || 0) }})
</span>
</td>
<td v-for="(opponent, oppIdx) in groupRankings[group.groupId]"
<td v-for="(opponent, oppIdx) in groupRankingsForGroup(group)"
:key="`match-${pl.id}-${opponent.id}`"
:class="['match-cell', { 'clickable': idx !== oppIdx, 'active-group-cell': activeGroupCells.includes(`match-${pl.id}-${opponent.id}`), 'diagonal-cell': idx === oppIdx }]"
@click="idx !== oppIdx ? handleMatchClick(pl.id, opponent.id, group.groupId) : null">
@@ -151,7 +151,7 @@
</span>
<span v-else class="no-match">-</span>
</td>
<td>{{ getLivePosition(pl.id, group.groupId) }}.</td>
<td>{{ getLivePosition(pl.id, group) }}.</td>
</tr>
</tbody>
</table>
@@ -285,6 +285,10 @@ export default {
}
},
methods: {
groupRankingsForGroup(group) {
const key = `${group.groupId}-${group.classId ?? 'null'}`;
return this.groupRankings[key] || [];
},
filterMatchesByClass(matches) {
// Wenn keine Klasse ausgewählt ist (null), zeige alle
if (this.selectedViewClass === null || this.selectedViewClass === undefined) {
@@ -403,8 +407,9 @@ export default {
return classes;
},
getLivePosition(playerId, groupId) {
const groupPlayers = this.groupRankings[groupId] || [];
getLivePosition(playerId, group) {
const groupId = group && typeof group === 'object' ? group.groupId : group;
const groupPlayers = this.groupRankingsForGroup && group && typeof group === 'object' ? this.groupRankingsForGroup(group) : (this.groupRankings[groupId] || []);
const liveStats = groupPlayers.map(player => {
let livePoints = player.points || 0;
let liveSetsWon = player.setsWon || 0;
@@ -455,7 +460,7 @@ export default {
});
const position = liveStats.findIndex(p => p.id === playerId) + 1;
return position || groupPlayers.findIndex(p => p.id === playerId) + 1;
return position || (groupPlayers.findIndex(p => p.id === playerId) + 1) || 0;
},
handleMatchClick(player1Id, player2Id, groupId) {
// Highlight das Match

View File

@@ -409,10 +409,11 @@ export default {
},
groupPlacements() {
const placements = [];
// Primär: aus groups + groupRankings
// Primär: aus groups + groupRankings (Schlüssel groupId-classId bei Pool)
if ((this.groups || []).length > 0) {
this.groups.forEach(group => {
const rankings = this.groupRankings[group.groupId] || [];
const key = `${group.groupId}-${group.classId ?? 'null'}`;
const rankings = this.groupRankings[key] || [];
if (rankings.length > 0) {
placements.push({
groupId: group.groupId,

View File

@@ -479,10 +479,11 @@ export default {
},
groupRankings() {
// Die Teilnehmer kommen bereits sortiert vom Backend mit allen benötigten Statistiken
// Schlüssel: groupId-classId (bei Pool mehrere Einträge pro Gruppe, pro Klasse getrennt)
const rankings = {};
this.groups.forEach(g => {
rankings[g.groupId] = g.participants.map(p => ({
const key = `${g.groupId}-${g.classId ?? 'null'}`;
rankings[key] = g.participants.map(p => ({
id: p.id,
name: p.name,
seeded: p.seeded || false,
@@ -502,6 +503,9 @@ export default {
});
return rankings;
},
groupRankingsKey(groupId, classId) {
return `${groupId}-${classId ?? 'null'}`;
},
// Mapping von groupId zu groupNumber für die Teilnehmer-Auswahl
groupIdToNumberMap() {