Enhance diary note and tag management in backend controllers
Updated the diaryNoteController to require diaryDateId in note creation and improved error handling for missing fields. Enhanced the createTag function in diaryTagController to validate tag names and return appropriate responses. Additionally, refined the deleteTag function to ensure proper error handling when a tag is not found. These changes improve the robustness and usability of the diary management features.
This commit is contained in:
10
frontend/src/utils/debounce.js
Normal file
10
frontend/src/utils/debounce.js
Normal file
@@ -0,0 +1,10 @@
|
||||
export function debounce(fn, wait = 300) {
|
||||
let timeoutId;
|
||||
return function (...args) {
|
||||
const context = this;
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = setTimeout(() => {
|
||||
fn.apply(context, args);
|
||||
}, wait);
|
||||
};
|
||||
}
|
||||
@@ -519,11 +519,6 @@
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import apiClient from '../apiClient.js';
|
||||
import apiClientAdmin from '../apiClientAdmin.js';
|
||||
import apiClientMembers from '../apiClientMembers.js';
|
||||
import apiClientDiary from '../apiClientDiary.js';
|
||||
import apiClientTournaments from '../apiClientTournaments.js';
|
||||
import { getSafeErrorMessage } from '../utils/errorMessages.js';
|
||||
import Multiselect from 'vue-multiselect';
|
||||
import Sortable from 'sortablejs';
|
||||
import PDFGenerator from '../components/PDFGenerator.js';
|
||||
|
||||
@@ -699,7 +699,7 @@ address={{address}}`;
|
||||
});
|
||||
},
|
||||
|
||||
parseAndImportTemplate() {
|
||||
async parseAndImportTemplate() {
|
||||
if (!this.importTemplate.trim()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
<li class="special-link" @click="loadAllMatches">Gesamtspielplan</li>
|
||||
<li class="special-link" @click="loadAdultMatches">Spielplan Erwachsene</li>
|
||||
<li class="divider"></li>
|
||||
<li v-for="league in leagues" :key="league.id" @click="loadMatchesForLeague(league.id, league.name)">{{
|
||||
league.name }}</li>
|
||||
<li v-if="leagues.length === 0" class="no-leagues">Keine Ligen für diese Saison gefunden</li>
|
||||
<li v-for="team in teams" :key="team.id" @click="loadMatchesForTeam(team)"
|
||||
:class="{ active: selectedTeam && selectedTeam.id === team.id }">
|
||||
{{ team.name }}<span class="team-league" v-if="team.league && team.league.name"> ({{ team.league.name }})</span>
|
||||
</li>
|
||||
<li v-if="teams.length === 0" class="no-leagues">Keine Teams für diese Saison gefunden</li>
|
||||
</ul>
|
||||
|
||||
<div class="flex-item" ref="scheduleContainer">
|
||||
@@ -286,9 +288,10 @@ export default {
|
||||
},
|
||||
showImportModal: false,
|
||||
selectedFile: null,
|
||||
leagues: [],
|
||||
teams: [],
|
||||
matches: [],
|
||||
selectedLeague: '',
|
||||
selectedTeam: null,
|
||||
hoveredMatch: null,
|
||||
selectedSeasonId: null,
|
||||
currentSeason: null,
|
||||
@@ -483,13 +486,16 @@ export default {
|
||||
});
|
||||
this.showInfo('Erfolg', 'Spielplan erfolgreich importiert!', '', 'success');
|
||||
this.closeImportModal();
|
||||
this.loadLeagues();
|
||||
this.loadTeams();
|
||||
} catch (error) {
|
||||
this.showInfo('Fehler', 'Fehler beim Importieren der CSV-Datei', '', 'error');
|
||||
}
|
||||
},
|
||||
// Sortierfunktion für Ligen
|
||||
sortLeagues(leagues) {
|
||||
if (!Array.isArray(leagues)) {
|
||||
return [];
|
||||
}
|
||||
// Ligen-Priorität
|
||||
const leagueOrder = [
|
||||
'1. Bundesliga',
|
||||
@@ -547,32 +553,55 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
async loadLeagues() {
|
||||
async loadTeams() {
|
||||
try {
|
||||
const clubId = this.currentClub;
|
||||
const seasonParam = this.selectedSeasonId ? `?seasonid=${this.selectedSeasonId}` : '';
|
||||
const response = await apiClient.get(`/matches/leagues/current/${clubId}${seasonParam}`);
|
||||
this.leagues = this.sortLeagues(response.data);
|
||||
const response = await apiClient.get(`/club-teams/club/${clubId}${seasonParam}`);
|
||||
const teams = response.data.filter(team => !!team.league);
|
||||
|
||||
const uniqueLeaguesMap = new Map();
|
||||
teams.forEach(team => {
|
||||
if (team.league && !uniqueLeaguesMap.has(team.league.id)) {
|
||||
uniqueLeaguesMap.set(team.league.id, team.league);
|
||||
}
|
||||
});
|
||||
const sortedLeagues = this.sortLeagues(Array.from(uniqueLeaguesMap.values()));
|
||||
const leagueOrder = sortedLeagues.map(l => l.id);
|
||||
|
||||
this.teams = teams.sort((a, b) => {
|
||||
const idxA = leagueOrder.indexOf(a.league.id);
|
||||
const idxB = leagueOrder.indexOf(b.league.id);
|
||||
if (idxA !== idxB) return idxA - idxB;
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('ScheduleView: Error loading leagues:', error);
|
||||
this.showInfo('Fehler', 'Fehler beim Laden der Ligen', '', 'error');
|
||||
console.error('ScheduleView: Error loading teams:', error);
|
||||
this.showInfo('Fehler', 'Fehler beim Laden der Teams', '', 'error');
|
||||
}
|
||||
},
|
||||
onSeasonChange(season) {
|
||||
this.currentSeason = season;
|
||||
this.loadLeagues();
|
||||
this.loadTeams();
|
||||
// Leere die aktuellen Matches, da sie für eine andere Saison sind
|
||||
this.matches = [];
|
||||
this.selectedLeague = '';
|
||||
this.selectedTeam = null;
|
||||
},
|
||||
async loadMatchesForLeague(leagueId, leagueName) {
|
||||
this.selectedLeague = leagueName;
|
||||
async loadMatchesForTeam(team) {
|
||||
if (!team || !team.league) {
|
||||
this.showInfo('Hinweis', 'Für dieses Team ist keine Liga hinterlegt. Bitte zuerst eine Liga zuordnen.', '', 'warning');
|
||||
return;
|
||||
}
|
||||
this.selectedTeam = team;
|
||||
this.selectedLeague = `${team.name}${team.league?.name ? ` (${team.league.name})` : ''}`;
|
||||
this.activeTab = 'schedule';
|
||||
try {
|
||||
const response = await apiClient.get(`/matches/leagues/${this.currentClub}/matches/${leagueId}`);
|
||||
const response = await apiClient.get(`/matches/leagues/${this.currentClub}/matches/${team.league.id}`);
|
||||
this.matches = response.data;
|
||||
|
||||
// Lade auch die Tabellendaten für diese Liga
|
||||
await this.loadLeagueTable(leagueId);
|
||||
await this.loadLeagueTable(team.league.id);
|
||||
} catch (error) {
|
||||
this.showInfo('Fehler', 'Fehler beim Laden der Matches', '', 'error');
|
||||
this.matches = [];
|
||||
@@ -580,6 +609,7 @@ export default {
|
||||
},
|
||||
async loadAllMatches() {
|
||||
this.selectedLeague = 'Gesamtspielplan';
|
||||
this.selectedTeam = null;
|
||||
try {
|
||||
const seasonParam = this.selectedSeasonId ? `?seasonid=${this.selectedSeasonId}` : '';
|
||||
const response = await apiClient.get(`/matches/leagues/${this.currentClub}/matches${seasonParam}`);
|
||||
@@ -591,6 +621,7 @@ export default {
|
||||
},
|
||||
async loadAdultMatches() {
|
||||
this.selectedLeague = 'Spielplan Erwachsene';
|
||||
this.selectedTeam = null;
|
||||
try {
|
||||
const seasonParam = this.selectedSeasonId ? `?seasonid=${this.selectedSeasonId}` : '';
|
||||
const response = await apiClient.get(`/matches/leagues/${this.currentClub}/matches${seasonParam}`);
|
||||
@@ -778,21 +809,15 @@ export default {
|
||||
},
|
||||
|
||||
async fetchTableFromMyTischtennis() {
|
||||
if (!this.selectedLeague || this.selectedLeague === 'Gesamtspielplan' || this.selectedLeague === 'Spielplan Erwachsene') {
|
||||
if (!this.selectedTeam || !this.selectedTeam.league || this.selectedLeague === 'Gesamtspielplan' || this.selectedLeague === 'Spielplan Erwachsene') {
|
||||
this.showInfo('Info', 'Bitte wählen Sie eine spezifische Liga aus, um die Tabelle zu laden.', '', 'info');
|
||||
return;
|
||||
}
|
||||
|
||||
this.fetchingTable = true;
|
||||
try {
|
||||
// Find the league ID for the current selected league
|
||||
const league = this.leagues.find(l => l.name === this.selectedLeague);
|
||||
if (!league) {
|
||||
this.showInfo('Fehler', 'Liga nicht gefunden', '', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await apiClient.post(`/matches/leagues/${this.currentClub}/table/${league.id}/fetch`);
|
||||
const leagueId = this.selectedTeam.league.id;
|
||||
const response = await apiClient.post(`/matches/leagues/${this.currentClub}/table/${leagueId}/fetch`);
|
||||
this.leagueTable = response.data.data;
|
||||
this.showInfo('Erfolg', 'Tabellendaten erfolgreich von MyTischtennis geladen!', '', 'success');
|
||||
} catch (error) {
|
||||
@@ -804,9 +829,10 @@ export default {
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
// Ligen werden geladen, sobald eine Saison ausgewählt ist
|
||||
// Die SeasonSelector-Komponente wird automatisch die aktuelle Saison auswählen
|
||||
// und dann onSeasonChange aufrufen, was loadLeagues() triggert
|
||||
// Teams werden geladen, sobald eine Saison ausgewählt ist
|
||||
// Die SeasonSelector-Komponente wählt automatisch die aktuelle Saison aus
|
||||
// und ruft anschließend onSeasonChange auf, was loadTeams() ausführt
|
||||
this.loadTeams();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1292,4 +1318,13 @@ li {
|
||||
.btn-cancel:hover {
|
||||
background-color: #5a6268;
|
||||
}
|
||||
|
||||
.output ul li.active {
|
||||
font-weight: 600;
|
||||
color: var(--primary-color, #2b7cff);
|
||||
}
|
||||
|
||||
.team-league {
|
||||
color: var(--text-muted, #6c757d);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -670,20 +670,9 @@
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import apiClient from '../apiClient';
|
||||
import apiClient from '../apiClient.js';
|
||||
import InfoDialog from '../components/InfoDialog.vue';
|
||||
import ConfirmDialog from '../components/ConfirmDialog.vue';
|
||||
import CsvImportDialog from '../components/CsvImportDialog.vue';
|
||||
import MemberSelectionDialog from '../components/MemberSelectionDialog.vue';
|
||||
import TournamentGroupEditor from '../components/TournamentGroupEditor.vue';
|
||||
import TournamentKoEditor from '../components/TournamentKoEditor.vue';
|
||||
import TournamentSeedingDialog from '../components/TournamentSeedingDialog.vue';
|
||||
import TournamentParticipantMatrix from '../components/TournamentParticipantMatrix.vue';
|
||||
import TournamentMatchMatrix from '../components/TournamentMatchMatrix.vue';
|
||||
import TournamentKoBracket from '../components/TournamentKoBracket.vue';
|
||||
import TournamentExportDialog from '../components/TournamentExportDialog.vue';
|
||||
import TournamentParticipantStats from '../components/TournamentParticipantStats.vue';
|
||||
import TournamentImportHistory from '../components/TournamentImportHistory.vue';
|
||||
import { buildInfoConfig, buildConfirmConfig, safeErrorMessage } from '../utils/dialogUtils.js';
|
||||
export default {
|
||||
name: 'TournamentsView',
|
||||
|
||||
Reference in New Issue
Block a user