started tournament implementation

This commit is contained in:
Torsten Schulz
2025-02-24 16:21:43 +01:00
parent 9442e3683b
commit df41720b50
14 changed files with 906 additions and 15 deletions

View File

@@ -22,6 +22,7 @@
<a href="/diary">Tagebuch</a>
<a href="/pending-approvals">Freigaben</a>
<a href="/schedule">Spielpläne</a>
<a href="/tournaments">Turniere</a>
</div>
<div class="logout-btn">

View File

@@ -9,6 +9,7 @@ import MembersView from './views/MembersView.vue';
import DiaryView from './views/DiaryView.vue';
import PendingApprovalsView from './views/PendingApprovalsView.vue';
import ScheduleView from './views/ScheduleView.vue';
import TournamentsView from './views/TournamentsView.vue';
const routes = [
{ path: '/register', component: Register },
@@ -21,6 +22,7 @@ const routes = [
{ path: '/diary', component: DiaryView },
{ path: '/pending-approvals', component: PendingApprovalsView},
{ path: '/schedule', component: ScheduleView},
{ path: '/tournaments', component: TournamentsView },
];
const router = createRouter({

View File

@@ -1004,23 +1004,11 @@ export default {
},
playBellSound() {
this.bellSound.play()
.then(() => {
console.log("Bell sound played successfully");
})
.catch(error => {
console.error("Error playing bell sound:", error);
});
this.bellSound.play();
},
playThumbSound() {
this.thumbSound.play()
.then(() => {
console.log("Thumb sound played successfully");
})
.catch(error => {
console.error("Error playing thumb sound:", error);
});
this.thumbSound.play();
},
calculateIntermediateTimes() {

View File

@@ -0,0 +1,289 @@
<template>
<div>
<h2>Turnier</h2>
<div>
<div>
<h3>Datum</h3>
<div>
<select v-model="selectedDate">
<option value="new">Neues Turnier</option>
<option v-for="date in dates" :key="date.id" :value="date.id">
{{ new Date(date.date).toLocaleDateString('de-DE', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
}) }}
</option>
</select>
</div>
<template v-if="selectedDate === 'new'">
<div>
<input type="date" v-model="newDate" />
<button @click="createTournament">Erstellen</button>
</div>
</template>
<template v-else>
<div>
<h3>Turnier</h3>
<div>
<div>
<label>
<input type="checkbox" v-model="isGroupTournament">
Spielen in Gruppen
</label>
</div>
<div>
<h4>Teilnehmer</h4>
<ul>
<li v-for="participant in participants" :key="participant.id">
{{ participant.member.firstName }} {{ participant.member.lastName }}
</li>
</ul>
<select v-model="selectedMember">
<option v-for="member in clubMembers" :key="member.id" :value="member.id">
{{ member.firstName }} {{ member.lastName }}
</option>
</select>
<button type="button" @click="addParticipant">Hinzufügen</button>
</div>
<div v-if="isGroupTournament && participants.length > 1">
<label>
Anzahl Gruppen:
<input type="number" v-model="numberOfGroups">
</label>
<button @click="createGroups">Gruppen erstellen</button>
<button @click="randomizeGroups">Zufällig verteilen</button>
</div>
<div v-if="groups && groups.length > 0">
<h4>Gruppen</h4>
<ul class="groupoverview">
<li v-for="group in groups" :key="group.groupId">
<h4>Gruppe {{ group.groupId }}</h4>
<table>
<thead>
<tr>
<th>Spielername</th>
<th>Bilanz</th>
</tr>
</thead>
<tbody>
<tr v-for="participant in group.participants" :key="participant.id">
<td>{{ participant.name }}</td>
<td></td>
</tr>
</tbody>
</table>
</li>
</ul>
<div>
<table>
<thead>
<tr>
<th>&nbsp;</th>
<th>Begegnung</th>
<th>Sätze</th>
<th>Ergebnis</th>
</tr>
</thead>
<tbody>
<tr v-for="match in matches" :key="match.id">
<td>{{ match.groupId ? "Gr " + match.groupId : match.round }}</td>
<td>{{ getPlayerName(match.player1) }} - {{ getPlayerName(match.player2) }}</td>
<td><input size="5" type="text" v-model="match.result" @keyup.enter="saveMatchResult(match, match.result)" /></td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</template>
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import apiClient from '../apiClient';
export default {
name: 'TournamentsView',
computed: {
...mapGetters(['isAuthenticated', 'currentClub', 'clubs']),
},
data() {
return {
selectedDate: 'new',
newDate: '',
dates: [],
participants: [],
selectedMember: null,
clubMembers: [],
numberOfGroups: 1,
isGroupTournament: false,
groups: [],
matches: [],
};
},
watch: {
selectedDate: async function (newVal) {
if (newVal !== 'new') {
try {
const groupResponse = await apiClient.get(`/tournament/${this.currentClub}/${newVal}`);
this.isGroupTournament = groupResponse.data.type === 'groups';
const participantsResponse = await apiClient.post('/tournament/participants', {
clubId: this.currentClub,
tournamentId: newVal,
});
this.participants = participantsResponse.data;
} catch (error) {
console.error(error);
}
await this.fetchGroups();
}
},
isGroupTournament: async function (newVal) {
if (newVal) {
this.numberOfGroups = 2;
} else {
this.numberOfGroups = 1;
}
await apiClient.post('/tournament/modus', {
clubId: this.currentClub,
tournamentId: this.selectedDate,
type: newVal ? 'groups' : 'bestOf',
numberOfGroups: this.numberOfGroups,
});
},
numberOfGroups: async function (newVal) {
await apiClient.post('/tournament/modus', {
clubId: this.currentClub,
tournamentId: this.selectedDate,
type: this.isGroupTournament ? 'groups' : 'bestOf',
numberOfGroups: newVal,
});
}
},
async created() {
if (!this.isAuthenticated) {
this.$router.push('/login');
return;
}
try {
const responseDates = await apiClient.get(`/tournament/${this.currentClub}`);
this.dates = responseDates.data;
} catch (error) {
console.error('Error fetching tournaments:', error);
}
try {
const responseMembers = await apiClient.get(`/clubmembers/get/${this.currentClub}/false`);
this.clubMembers = responseMembers.data;
} catch (error) {
console.error('Error fetching club members:', error);
}
},
methods: {
async createTournament() {
try {
const response = await apiClient.post('/tournament', {
clubId: this.currentClub,
name: this.newDate,
date: this.newDate,
});
this.dates = response.data;
this.newDate = '';
} catch (error) {
console.error('Error creating tournament:', error);
}
},
async addParticipant() {
try {
const response = await apiClient.post('/tournament/participant', {
clubId: this.currentClub,
tournamentId: this.selectedDate,
participant: this.selectedMember,
});
this.participants = response.data;
} catch (error) {
console.error('Error adding participant:', error);
}
},
async createGroups() {
await apiClient.put('/tournament/groups', {
clubId: this.currentClub,
tournamentId: this.selectedDate,
});
await this.fetchGroups();
},
async randomizeGroups() {
try {
const response = await apiClient.post('/tournament/groups', {
clubId: this.currentClub,
tournamentId: this.selectedDate,
});
} catch (error) {
console.error('Error randomizing groups:', error);
}
await this.fetchGroups();
},
async fetchGroups() {
try {
const response = await apiClient.get('/tournament/groups', {
params: {
clubId: this.currentClub,
tournamentId: this.selectedDate
}
});
this.groups = response.data;
const matchesResponse = await apiClient.get(`/tournament/matches/${this.currentClub}/${this.selectedDate}`);
this.matches = matchesResponse.data;
console.log(this.matches);
} catch (error) {
console.error('Error fetching groups:', error);
}
},
getPlayerName(player) {
return player.member.firstName + ' ' + player.member.lastName;
},
async saveMatchResult(match, result) {
try {
await apiClient.post('/tournament/match/result', {
clubId: this.currentClub,
tournamentId: this.selectedDate,
matchId: match.matchId,
result: result,
});
match.result = result; // Aktualisiere das Match in der UI
} catch (error) {
console.error('Error saving match result:', error);
}
}
},
};
</script>
<style scoped>
.tournaments {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
}
.groupoverview {
display: flex;
flex-direction: row;
align-items: baseline;
justify-content: left;
padding: 0;
}
.groupoverview li {
list-style-type: none;
margin: 0;
padding: 0;
}
</style>