feat(tactics): add functionality for managing tactic plans in official tournaments
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 55s
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 55s
- Implemented routes for listing, saving, updating, and deleting tactic plans in officialTournamentRoutes.js. - Created OfficialTournamentTacticPlan model to handle tactic plan data. - Developed OfficialTournamentService methods for tactic plan operations including validation and error handling. - Enhanced OfficialTournaments.vue to include a new tactics tab with UI for managing tactic plans. - Added TacticBoard component for visualizing and editing tactic paths. - Updated server.js to synchronize the new tactic plan model.
This commit is contained in:
@@ -6,10 +6,53 @@ import { Op } from 'sequelize';
|
||||
import OfficialTournament from '../models/OfficialTournament.js';
|
||||
import OfficialCompetition from '../models/OfficialCompetition.js';
|
||||
import OfficialCompetitionMember from '../models/OfficialCompetitionMember.js';
|
||||
import OfficialTournamentTacticPlan from '../models/OfficialTournamentTacticPlan.js';
|
||||
import Member from '../models/Member.js';
|
||||
import OfficialTournamentParserService from './officialTournamentParserService.js';
|
||||
|
||||
class OfficialTournamentService {
|
||||
async listTacticPlans(clubId, tournamentId) {
|
||||
const tournament = await OfficialTournament.findOne({ where: { id: tournamentId, clubId } });
|
||||
if (!tournament) return null;
|
||||
return OfficialTournamentTacticPlan.findAll({
|
||||
where: { tournamentId },
|
||||
include: [
|
||||
{ model: OfficialCompetition, as: 'competition', attributes: ['id', 'ageClassCompetition'] },
|
||||
{ model: Member, as: 'member', attributes: ['id', 'firstName', 'lastName'] },
|
||||
],
|
||||
order: [['updatedAt', 'DESC']],
|
||||
});
|
||||
}
|
||||
|
||||
async saveTacticPlan(clubId, tournamentId, planId, payload) {
|
||||
const { competitionId, memberId } = payload;
|
||||
if (!competitionId || !memberId) {
|
||||
const error = new Error('Bitte Spieler/in und Konkurrenz auswählen.'); error.status = 400; throw error;
|
||||
}
|
||||
const tournament = await OfficialTournament.findOne({ where: { id: tournamentId, clubId } });
|
||||
if (!tournament) { const error = new Error('Turnier nicht gefunden.'); error.status = 404; throw error; }
|
||||
const competition = await OfficialCompetition.findOne({ where: { id: competitionId, tournamentId } });
|
||||
if (!competition) { const error = new Error('Die Konkurrenz gehört nicht zu diesem Turnier.'); error.status = 400; throw error; }
|
||||
const entry = await OfficialCompetitionMember.findOne({ where: { tournamentId, competitionId, memberId } });
|
||||
if (!entry || (!entry.registered && !entry.participated)) {
|
||||
const error = new Error('Taktikpläne sind nur für angemeldete oder teilnehmende Spieler/innen möglich.'); error.status = 400; throw error;
|
||||
}
|
||||
const fields = ['competitionId', 'memberId', 'round', 'opponentName', 'ownStrengths', 'ownWeaknesses', 'opponentStrengths', 'opponentWeaknesses', 'drawingData'];
|
||||
const values = Object.fromEntries(fields.map((key) => [key, payload[key] ?? null]));
|
||||
if (planId) {
|
||||
const plan = await OfficialTournamentTacticPlan.findOne({ where: { id: planId, tournamentId } });
|
||||
if (!plan) { const error = new Error('Matchplan nicht gefunden.'); error.status = 404; throw error; }
|
||||
await plan.update(values);
|
||||
return plan;
|
||||
}
|
||||
return OfficialTournamentTacticPlan.create({ tournamentId, ...values });
|
||||
}
|
||||
|
||||
async deleteTacticPlan(clubId, tournamentId, planId) {
|
||||
const tournament = await OfficialTournament.findOne({ where: { id: tournamentId, clubId } });
|
||||
if (!tournament) return null;
|
||||
return OfficialTournamentTacticPlan.destroy({ where: { id: planId, tournamentId } });
|
||||
}
|
||||
async uploadTournamentPdf(clubId, pdfBuffer) {
|
||||
const data = await pdfParse(pdfBuffer);
|
||||
const parsed = OfficialTournamentParserService.parseTournamentText(data.text);
|
||||
@@ -306,6 +349,7 @@ class OfficialTournamentService {
|
||||
async deleteOfficialTournament(clubId, id) {
|
||||
const t = await OfficialTournament.findOne({ where: { id, clubId } });
|
||||
if (!t) return false;
|
||||
await OfficialTournamentTacticPlan.destroy({ where: { tournamentId: id } });
|
||||
await OfficialCompetition.destroy({ where: { tournamentId: id } });
|
||||
await OfficialTournament.destroy({ where: { id } });
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user