diff --git a/backend/controllers/participantController.js b/backend/controllers/participantController.js index fe5b83d..4787477 100644 --- a/backend/controllers/participantController.js +++ b/backend/controllers/participantController.js @@ -4,7 +4,10 @@ import { devLog } from '../utils/logger.js'; export const getParticipants = async (req, res) => { try { const { dateId } = req.params; - const participants = await Participant.findAll({ where: { diaryDateId: dateId } }); + const participants = await Participant.findAll({ + where: { diaryDateId: dateId }, + attributes: ['id', 'diaryDateId', 'memberId', 'groupId', 'notes', 'createdAt', 'updatedAt'] + }); res.status(200).json(participants); } catch (error) { devLog(error); @@ -12,6 +15,32 @@ export const getParticipants = async (req, res) => { } }; +export const updateParticipantGroup = async (req, res) => { + try { + const { dateId, memberId } = req.params; + const { groupId } = req.body; + + const participant = await Participant.findOne({ + where: { + diaryDateId: dateId, + memberId: memberId + } + }); + + if (!participant) { + return res.status(404).json({ error: 'Teilnehmer nicht gefunden' }); + } + + participant.groupId = groupId || null; + await participant.save(); + + res.status(200).json(participant); + } catch (error) { + devLog(error); + res.status(500).json({ error: 'Fehler beim Aktualisieren der Teilnehmer-Gruppenzuordnung' }); + } +}; + export const addParticipant = async (req, res) => { try { const { diaryDateId, memberId } = req.body; diff --git a/backend/migrations/add_group_id_to_participants.sql b/backend/migrations/add_group_id_to_participants.sql new file mode 100644 index 0000000..2e6fa4c --- /dev/null +++ b/backend/migrations/add_group_id_to_participants.sql @@ -0,0 +1,9 @@ +-- Migration: Add group_id to participants table +-- This allows assigning participants to groups for training organization + +ALTER TABLE participants +ADD COLUMN group_id INTEGER NULL REFERENCES "group"(id) ON DELETE SET NULL ON UPDATE CASCADE; + +-- Add index for better query performance +CREATE INDEX IF NOT EXISTS idx_participants_group_id ON participants(group_id); + diff --git a/backend/models/Participant.js b/backend/models/Participant.js index 5bbcb85..b5438b5 100644 --- a/backend/models/Participant.js +++ b/backend/models/Participant.js @@ -2,6 +2,7 @@ import { DataTypes } from 'sequelize'; import sequelize from '../database.js'; import Member from './Member.js'; import DiaryDate from './DiaryDates.js'; +import Group from './Group.js'; import { encryptData, decryptData } from '../utils/encrypt.js'; const Participant = sequelize.define('Participant', { @@ -27,6 +28,16 @@ const Participant = sequelize.define('Participant', { key: 'id' } }, + groupId: { + type: DataTypes.INTEGER, + allowNull: true, + references: { + model: Group, + key: 'id' + }, + onDelete: 'SET NULL', + onUpdate: 'CASCADE' + }, notes: { type: DataTypes.STRING(4096), allowNull: true, diff --git a/backend/routes/participantRoutes.js b/backend/routes/participantRoutes.js index 96979b7..023a67f 100644 --- a/backend/routes/participantRoutes.js +++ b/backend/routes/participantRoutes.js @@ -1,5 +1,5 @@ import express from 'express'; -import { getParticipants, addParticipant, removeParticipant } from '../controllers/participantController.js'; +import { getParticipants, addParticipant, removeParticipant, updateParticipantGroup } from '../controllers/participantController.js'; import { authenticate } from '../middleware/authMiddleware.js'; const router = express.Router(); @@ -7,5 +7,6 @@ const router = express.Router(); router.get('/:dateId', authenticate, getParticipants); router.post('/add', authenticate, addParticipant); router.post('/remove', authenticate, removeParticipant); +router.put('/:dateId/:memberId/group', authenticate, updateParticipantGroup); export default router; diff --git a/backend/server.js b/backend/server.js index 1aadafe..03134a6 100644 --- a/backend/server.js +++ b/backend/server.js @@ -43,7 +43,7 @@ import permissionRoutes from './routes/permissionRoutes.js'; import schedulerService from './services/schedulerService.js'; const app = express(); -const port = process.env.PORT || 3000; +const port = process.env.PORT || 3005; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); diff --git a/frontend/src/apiClient.js b/frontend/src/apiClient.js index e284cf1..75d5f4e 100644 --- a/frontend/src/apiClient.js +++ b/frontend/src/apiClient.js @@ -2,7 +2,7 @@ import axios from 'axios'; import store from './store'; const apiClient = axios.create({ - baseURL: `${import.meta.env.VITE_BACKEND}/api`, + baseURL: `${import.meta.env.VITE_BACKEND || 'http://localhost:3005'}/api`, }); apiClient.interceptors.request.use(config => { diff --git a/frontend/src/views/DiaryView.vue b/frontend/src/views/DiaryView.vue index 7159064..ef0368d 100644 --- a/frontend/src/views/DiaryView.vue +++ b/frontend/src/views/DiaryView.vue @@ -848,6 +848,17 @@ export default { this.participants = response.data.map(participant => participant.memberId); // Map für memberId -> participantId speichern this.participantMapByMemberId = response.data.reduce((map, p) => { map[p.memberId] = p.id; return map; }, {}); + // Map für memberId -> groupId speichern und mit Reaktivität initialisieren + this.memberGroupsMap = {}; + response.data.forEach(p => { + if (p.groupId) { + if (this.$set) { + this.$set(this.memberGroupsMap, p.memberId, p.groupId); + } else { + this.memberGroupsMap[p.memberId] = p.groupId; + } + } + }); }, async loadActivities(dateId) { @@ -1391,12 +1402,19 @@ export default { }, async createGroups() { try { - // Erstelle die gewünschte Anzahl Gruppen mit Namen 1 bis X - for (let i = 1; i <= this.newGroupCount; i++) { + // Bestimme Startnummer basierend auf vorhandenen Gruppen + const existingNumbers = (this.groups || []) + .map(g => parseInt((g.name || '').trim(), 10)) + .filter(n => Number.isFinite(n)); + const startNumber = existingNumbers.length > 0 ? Math.max(...existingNumbers) + 1 : 1; + + // Erstelle die gewünschte Anzahl Gruppen mit fortlaufender Nummerierung + for (let i = 0; i < this.newGroupCount; i++) { + const groupNumber = startNumber + i; const form = { clubid: this.currentClub, dateid: this.date.id, - name: i.toString(), + name: groupNumber.toString(), lead: '', // Leiter wird leer gelassen } await apiClient.post('/group', form); @@ -1933,14 +1951,25 @@ export default { async updateMemberGroup(memberId, groupId) { try { - // Hier würde normalerweise ein API-Call gemacht werden - // Für jetzt speichern wir es nur lokal - this.memberGroupsMap[memberId] = groupId || ''; + const selectedGroupId = groupId || ''; - // TODO: API-Call zum Speichern der Teilnehmer-Gruppenzuordnung - // await apiClient.put(`/participants/${this.date.id}/${memberId}/group`, { groupId }); + // Verwende Vue.set für Reaktivität (Vue 2) + if (this.$set) { + this.$set(this.memberGroupsMap, memberId, selectedGroupId); + } else { + // Vue 3 oder Fallback + this.memberGroupsMap = { + ...this.memberGroupsMap, + [memberId]: selectedGroupId + }; + } - console.log(`Teilnehmer ${memberId} wurde Gruppe ${groupId} zugewiesen`); + // API-Call zum Speichern der Teilnehmer-Gruppenzuordnung + await apiClient.put(`/participants/${this.date.id}/${memberId}/group`, { + groupId: selectedGroupId || null + }); + + console.log(`Teilnehmer ${memberId} wurde Gruppe ${selectedGroupId} zugewiesen`); } catch (error) { console.error('Fehler beim Aktualisieren der Teilnehmer-Gruppenzuordnung:', error); this.showInfo('Fehler', 'Fehler beim Aktualisieren der Teilnehmer-Gruppenzuordnung', '', 'error'); diff --git a/frontend/src/views/Login.vue b/frontend/src/views/Login.vue index 5b380a4..641e053 100644 --- a/frontend/src/views/Login.vue +++ b/frontend/src/views/Login.vue @@ -98,7 +98,7 @@ export default { ...mapActions(['login']), async executeLogin() { try { - const response = await axios.post(`${import.meta.env.VITE_BACKEND}/api/auth/login`, { email: this.email, password: this.password }, { + const response = await axios.post(`${import.meta.env.VITE_BACKEND || 'http://localhost:3005'}/api/auth/login`, { email: this.email, password: this.password }, { timeout: 5000, }); await this.login({ token: response.data.token, username: this.email }); diff --git a/frontend/src/views/MembersView.vue b/frontend/src/views/MembersView.vue index 9366b82..b4e66c1 100644 --- a/frontend/src/views/MembersView.vue +++ b/frontend/src/views/MembersView.vue @@ -68,11 +68,41 @@ -
|
|