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:
@@ -1656,12 +1656,30 @@ class TournamentService {
|
||||
}
|
||||
|
||||
classGroups.forEach((g, idx) => {
|
||||
// Berechne Rankings für diese Gruppe
|
||||
// Bei zusammengeführten Klassen (Pool): Teilnehmer-classId pro ID
|
||||
const participantIdToClassId = {};
|
||||
for (const tm of g.tournamentGroupMembers || []) {
|
||||
participantIdToClassId[tm.id] = tm.classId ?? g.classId;
|
||||
}
|
||||
for (const ext of g.externalGroupMembers || []) {
|
||||
participantIdToClassId[ext.id] = ext.classId ?? g.classId;
|
||||
}
|
||||
const classIdsInGroup = [...new Set(Object.values(participantIdToClassId).filter(c => c != null))];
|
||||
const isPool = !!g.poolId || classIdsInGroup.length > 1;
|
||||
const participantClassIds = isPool && classIdsInGroup.length > 0 ? classIdsInGroup : [g.classId];
|
||||
|
||||
participantClassIds.forEach((participantClassId) => {
|
||||
const stats = {};
|
||||
|
||||
const effectiveClassId = isPool ? participantClassId : g.classId;
|
||||
|
||||
if (isDoubles && pairingsByGroup[g.id]) {
|
||||
// Bei Doppel: Verwende Paarungen
|
||||
// Bei Doppel: Verwende Paarungen (bei Pool nur Paarungen dieser Klasse)
|
||||
for (const pairing of pairingsByGroup[g.id]) {
|
||||
if (isPool) {
|
||||
const c1 = pairing.member1?.classId ?? pairing.external1?.classId ?? g.classId;
|
||||
const c2 = pairing.member2?.classId ?? pairing.external2?.classId ?? g.classId;
|
||||
if (c1 !== effectiveClassId || c2 !== effectiveClassId) continue;
|
||||
}
|
||||
const player1Name = pairing.member1?.member
|
||||
? `${pairing.member1.member.firstName} ${pairing.member1.member.lastName}`
|
||||
: pairing.external1
|
||||
@@ -1695,9 +1713,9 @@ class TournamentService {
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// Bei Einzel: Verwende einzelne Spieler
|
||||
// Interne Teilnehmer
|
||||
// Bei Einzel: Verwende einzelne Spieler (bei Pool nur Teilnehmer dieser Klasse)
|
||||
for (const tm of g.tournamentGroupMembers || []) {
|
||||
if (isPool && (tm.classId ?? g.classId) !== effectiveClassId) continue;
|
||||
stats[tm.id] = {
|
||||
id: tm.id,
|
||||
name: `${tm.member.firstName} ${tm.member.lastName}`,
|
||||
@@ -1714,9 +1732,8 @@ class TournamentService {
|
||||
matchesLost: 0
|
||||
};
|
||||
}
|
||||
|
||||
// Externe Teilnehmer
|
||||
for (const ext of g.externalGroupMembers || []) {
|
||||
if (isPool && (ext.classId ?? g.classId) !== effectiveClassId) continue;
|
||||
stats[ext.id] = {
|
||||
id: ext.id,
|
||||
name: `${ext.firstName} ${ext.lastName}`,
|
||||
@@ -1735,8 +1752,13 @@ class TournamentService {
|
||||
}
|
||||
}
|
||||
|
||||
// Berechne Statistiken aus Matches
|
||||
// Berechne Statistiken aus Matches (bei Pool nur Spiele innerhalb derselben Klasse)
|
||||
for (const m of groupMatches.filter(m => m.groupId === g.id)) {
|
||||
if (isPool) {
|
||||
const c1 = participantIdToClassId[m.player1Id];
|
||||
const c2 = participantIdToClassId[m.player2Id];
|
||||
if (c1 !== effectiveClassId || c2 !== effectiveClassId) continue;
|
||||
}
|
||||
if (isDoubles) {
|
||||
// Bei Doppel: Finde die Paarungen für player1Id und player2Id
|
||||
const pairing1Key = Object.keys(stats).find(key =>
|
||||
@@ -2020,10 +2042,11 @@ class TournamentService {
|
||||
|
||||
result.push({
|
||||
groupId: g.id,
|
||||
classId: g.classId,
|
||||
classId: effectiveClassId,
|
||||
groupNumber: idx + 1, // Nummer innerhalb der Klasse
|
||||
participants: participantsWithPosition
|
||||
});
|
||||
}); // participantClassIds.forEach
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user