Add member gallery generation feature in backend and frontend
This commit introduces a new API endpoint for generating a member gallery, allowing users to retrieve a composite image of active members' latest images. The backend has been updated with a new method in MemberService to handle gallery creation, while the frontend has been enhanced with a dialog for displaying the generated gallery. This feature improves the user experience by providing a visual representation of club members.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="diary">
|
||||
<h2>Trainingstagebuch</h2>
|
||||
<div>
|
||||
<div class="diary-header-row">
|
||||
<label>Datum:
|
||||
<select v-model="date" @change="handleDateChange">
|
||||
<option value="new">Neu anlegen</option>
|
||||
@@ -11,6 +11,13 @@
|
||||
<button v-if="date && date !== 'new' && canDeleteCurrentDate" class="btn-secondary"
|
||||
@click="deleteCurrentDate">Datum löschen</button>
|
||||
</label>
|
||||
<button
|
||||
class="btn-secondary gallery-trigger"
|
||||
:disabled="!currentClub || galleryLoading"
|
||||
@click="openGalleryDialog"
|
||||
>
|
||||
{{ galleryLoading ? 'Galerie wird erstellt…' : 'Mitglieder-Galerie' }}
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="showForm && date === 'new'">
|
||||
<h3>Neues Datum anlegen</h3>
|
||||
@@ -493,6 +500,25 @@
|
||||
:initial-drawing-data="null"
|
||||
@ok="handleDrawingDialogOkForDiary"
|
||||
/>
|
||||
|
||||
<!-- Mitglieder-Galerie Dialog -->
|
||||
<BaseDialog
|
||||
v-model="showGalleryDialog"
|
||||
title="Mitglieder-Galerie"
|
||||
size="large"
|
||||
:close-on-overlay="true"
|
||||
@close="closeGalleryDialog"
|
||||
>
|
||||
<div class="gallery-dialog-content">
|
||||
<div v-if="galleryLoading" class="gallery-loading">Galerie wird erstellt…</div>
|
||||
<div v-else-if="galleryImageUrl" class="gallery-image-wrapper">
|
||||
<img :src="galleryImageUrl" alt="Mitglieder-Galerie" class="gallery-dialog-image">
|
||||
</div>
|
||||
<div v-else class="gallery-error">
|
||||
{{ galleryError || 'Keine Galerie verfügbar.' }}
|
||||
</div>
|
||||
</div>
|
||||
</BaseDialog>
|
||||
</div>
|
||||
|
||||
<!-- Info Dialog -->
|
||||
@@ -637,6 +663,10 @@ export default {
|
||||
accidents: [],
|
||||
editingActivityId: null, // ID der Aktivität, die gerade bearbeitet wird
|
||||
// Suche für Inline-Edit
|
||||
showGalleryDialog: false,
|
||||
galleryLoading: false,
|
||||
galleryImageUrl: null,
|
||||
galleryError: '',
|
||||
editShowDropdown: false,
|
||||
editSearchResults: [],
|
||||
editSearchForId: null,
|
||||
@@ -749,6 +779,35 @@ export default {
|
||||
}
|
||||
this.confirmDialog.isOpen = false;
|
||||
},
|
||||
revokeGalleryImage() {
|
||||
if (this.galleryImageUrl) {
|
||||
URL.revokeObjectURL(this.galleryImageUrl);
|
||||
this.galleryImageUrl = null;
|
||||
}
|
||||
},
|
||||
async openGalleryDialog() {
|
||||
if (!this.currentClub || this.galleryLoading) {
|
||||
return;
|
||||
}
|
||||
this.galleryLoading = true;
|
||||
this.galleryError = '';
|
||||
try {
|
||||
const response = await apiClient.get(`/clubmembers/gallery/${this.currentClub}`, { responseType: 'blob' });
|
||||
this.revokeGalleryImage();
|
||||
this.galleryImageUrl = URL.createObjectURL(response.data);
|
||||
this.showGalleryDialog = true;
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Erstellen der Mitglieder-Galerie:', error);
|
||||
this.galleryError = error?.response?.data?.error || 'Galerie konnte nicht erstellt werden.';
|
||||
this.showInfo('Fehler', 'Galerie konnte nicht erstellt werden.', this.galleryError, 'error');
|
||||
} finally {
|
||||
this.galleryLoading = false;
|
||||
}
|
||||
},
|
||||
closeGalleryDialog() {
|
||||
this.showGalleryDialog = false;
|
||||
this.revokeGalleryImage();
|
||||
},
|
||||
|
||||
hasActivityVisual(pa) {
|
||||
if (!pa) return false;
|
||||
@@ -2355,6 +2414,7 @@ export default {
|
||||
if (this.timeChecker) {
|
||||
clearInterval(this.timeChecker);
|
||||
}
|
||||
this.revokeGalleryImage();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -2400,6 +2460,44 @@ h3 {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.diary-header-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.gallery-trigger {
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
.gallery-dialog-content {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 60vh;
|
||||
max-height: 70vh;
|
||||
}
|
||||
|
||||
.gallery-image-wrapper {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.gallery-dialog-image {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 18px rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
.gallery-loading,
|
||||
.gallery-error {
|
||||
font-size: 1rem;
|
||||
color: var(--text-color, #333);
|
||||
}
|
||||
|
||||
.column:first-child {
|
||||
flex: 1;
|
||||
overflow: visible;
|
||||
|
||||
Reference in New Issue
Block a user