Bilder hinzugefügt
This commit is contained in:
@@ -123,20 +123,28 @@
|
||||
<div class="modal-content">
|
||||
<span class="close" @click="closeNotesModal">×</span>
|
||||
<h3>Notizen für {{ selectedMember.firstName }} {{ selectedMember.lastName }}</h3>
|
||||
<multiselect v-model="selectedMemberTags" :options="availableTags" placeholder="Tags auswählen"
|
||||
label="name" track-by="id" multiple :close-on-select="true" @tag="addNewTagForMember"
|
||||
@remove="removeMemberTag" @input="updateMemberTags" :allow-empty="false"
|
||||
@keydown.enter.prevent="addNewTagForMemberFromInput" />
|
||||
<div>
|
||||
<textarea v-model="newNoteContent" placeholder="Neue Notiz" rows="4" cols="30"></textarea>
|
||||
<button @click="addMemberNote">Hinzufügen</button>
|
||||
<div class="modal-body">
|
||||
<div class="modal-left">
|
||||
<img v-if="selectedMember.imageUrl" :src="selectedMember.imageUrl" alt="Mitgliedsbild"
|
||||
style="width: 250px; height: 250px; object-fit: cover;" />
|
||||
</div>
|
||||
<div class="modal-right">
|
||||
<multiselect v-model="selectedMemberTags" :options="availableTags" placeholder="Tags auswählen"
|
||||
label="name" track-by="id" multiple :close-on-select="true" @tag="addNewTagForMember"
|
||||
@remove="removeMemberTag" @input="updateMemberTags" :allow-empty="false"
|
||||
@keydown.enter.prevent="addNewTagForMemberFromInput" />
|
||||
<div>
|
||||
<textarea v-model="newNoteContent" placeholder="Neue Notiz" rows="4" cols="30"></textarea>
|
||||
<button @click="addMemberNote">Hinzufügen</button>
|
||||
</div>
|
||||
<ul>
|
||||
<li v-for="note in notes" :key="note.id">
|
||||
<button @click="deleteNote(note.id)">Löschen</button>
|
||||
{{ note.content }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<ul>
|
||||
<li v-for="note in notes" :key="note.id">
|
||||
<button @click="deleteNote(note.id)">Löschen</button>
|
||||
{{ note.content }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -339,8 +347,9 @@ export default {
|
||||
this.selectedActivityTags = [];
|
||||
}
|
||||
},
|
||||
openNotesModal(member) {
|
||||
async openNotesModal(member) {
|
||||
this.selectedMember = member;
|
||||
await this.loadMemberImage(member);
|
||||
this.loadMemberNotesAndTags(this.date.id, member.id);
|
||||
this.showNotesModal = true;
|
||||
},
|
||||
@@ -608,6 +617,18 @@ export default {
|
||||
alert('Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.');
|
||||
}
|
||||
},
|
||||
async loadMemberImage(member) {
|
||||
try {
|
||||
const response = await apiClient.get(`/clubmembers/${this.currentClub}/image/${member.id}`, {
|
||||
responseType: 'blob',
|
||||
});
|
||||
const imageUrl = URL.createObjectURL(response.data);
|
||||
member.imageUrl = imageUrl;
|
||||
} catch (error) {
|
||||
console.error("Failed to load member image:", error);
|
||||
member.imageUrl = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
|
||||
@@ -789,4 +810,21 @@ input[type="number"] {
|
||||
.drag-handle {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.modal-left {
|
||||
flex: 0 0 250px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.modal-right {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
<div>
|
||||
<h2>Mitglieder</h2>
|
||||
<div class="newmember">
|
||||
<div class="toggle-new-member"><span @click="toggleNewMember"><span class="add">{{ memberFormIsOpen ? '-' :
|
||||
'+' }}</span>{{ memberToEdit === null ? "Neues Mitglied" : "Mitglied bearbeiten" }}</span>
|
||||
<div class="toggle-new-member">
|
||||
<span @click="toggleNewMember">
|
||||
<span class="add">{{ memberFormIsOpen ? '-' : '+' }}</span>
|
||||
{{ memberToEdit === null ? "Neues Mitglied" : "Mitglied bearbeiten" }}
|
||||
</span>
|
||||
<button v-if="memberToEdit !== null" @click="resetToNewMember">Neues Mitglied anlegen</button>
|
||||
</div>
|
||||
<div v-if="memberFormIsOpen" class="new-member-form">
|
||||
@@ -15,8 +18,13 @@
|
||||
<label><span>Telefon-Nr.:</span> <input type="text" v-model="newPhone"></label>
|
||||
<label><span>Email-Adresse:</span> <input type="email" v-model="newEmail"></label>
|
||||
<label><span>Aktiv:</span> <input type="checkbox" v-model="newActive"></label>
|
||||
<label><span>Bild:</span> <input type="file" @change="onFileSelected"></label>
|
||||
<div v-if="memberImagePreview">
|
||||
<img :src="memberImagePreview" alt="Vorschau des Mitgliedsbildes"
|
||||
style="max-width: 200px; max-height: 200px;">
|
||||
</div>
|
||||
<div>
|
||||
<button @click="addNewMember">Anlegen</button>
|
||||
<button @click="addNewMember">{{ memberToEdit ? 'Ändern' : 'Anlegen' }}</button>
|
||||
<button @click="resetNewMember" v-if="memberToEdit === null">Felder leeren</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -25,6 +33,7 @@
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Bild</th>
|
||||
<th>Name, Vorname</th>
|
||||
<th>Adresse</th>
|
||||
<th>Geburtsdatum</th>
|
||||
@@ -34,17 +43,31 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="member in members" :key="member.id" @click="editMember(member)">
|
||||
<td>
|
||||
<img v-if="member.imageUrl" :src="member.imageUrl" alt="Mitgliedsbild"
|
||||
style="max-width: 50px; max-height: 50px;"
|
||||
@click.stop="openImageModal(member.imageUrl)">
|
||||
</td>
|
||||
<td>{{ member.lastName }}, {{ member.firstName }}</td>
|
||||
<td>{{ member.street }}, {{ member.city }}</td>
|
||||
<td>{{ member.birthDate }}</td>
|
||||
<td>{{ member.phone }}</td>
|
||||
<td>{{ member.email }}</td>
|
||||
<td><button @click.stop="openNotesModal(member)">Notizen</button></td>
|
||||
<td>
|
||||
<button @click.stop="openNotesModal(member)">Notizen</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div v-if="showImageModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<span class="close" @click="closeImageModal">×</span>
|
||||
<img :src="selectedImageUrl" alt="Großes Mitgliedsbild" style="max-width: 100%; max-height: 100%;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="showNotesModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<span class="close" @click="closeNotesModal">×</span>
|
||||
@@ -65,7 +88,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { mapGetters } from 'vuex';
|
||||
import apiClient from '../apiClient.js';
|
||||
|
||||
export default {
|
||||
@@ -86,9 +109,13 @@ export default {
|
||||
newEmail: '',
|
||||
newActive: true,
|
||||
memberToEdit: null,
|
||||
memberImage: null,
|
||||
memberImagePreview: null,
|
||||
notes: [],
|
||||
newNoteContent: '',
|
||||
showNotesModal: false,
|
||||
showImageModal: false,
|
||||
selectedImageUrl: null,
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
@@ -98,6 +125,9 @@ export default {
|
||||
async init() {
|
||||
const response = await apiClient.get(`/clubmembers/${this.currentClub}`);
|
||||
this.members = response.data;
|
||||
this.members.forEach(member => {
|
||||
this.loadMemberImage(member);
|
||||
});
|
||||
},
|
||||
toggleNewMember() {
|
||||
this.memberFormIsOpen = !this.memberFormIsOpen;
|
||||
@@ -111,9 +141,24 @@ export default {
|
||||
this.newPhone = '';
|
||||
this.newEmail = '';
|
||||
this.newActive = true;
|
||||
this.memberImage = null;
|
||||
this.memberImagePreview = null;
|
||||
},
|
||||
onFileSelected(event) {
|
||||
const file = event.target.files[0];
|
||||
this.memberImage = file;
|
||||
|
||||
// Bildvorschau erstellen
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
this.memberImagePreview = e.target.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
},
|
||||
async addNewMember() {
|
||||
const response = await apiClient.post(`/clubmembers/${this.currentClub}`, {
|
||||
const memberData = {
|
||||
firstname: this.newFirstname,
|
||||
lastname: this.newLastname,
|
||||
street: this.newStreet,
|
||||
@@ -123,8 +168,32 @@ export default {
|
||||
email: this.newEmail,
|
||||
active: this.newActive,
|
||||
id: this.memberToEdit ? this.memberToEdit.id : null,
|
||||
});
|
||||
this.members = response.data;
|
||||
};
|
||||
|
||||
let response;
|
||||
try {
|
||||
response = await apiClient.post(`/clubmembers/${this.currentClub}`, memberData);
|
||||
this.members = response.data;
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Speichern des Mitglieds:", error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.memberImage) {
|
||||
const formData = new FormData();
|
||||
formData.append('image', this.memberImage);
|
||||
formData.append('clubId', this.currentClub);
|
||||
try {
|
||||
await apiClient.post(`/clubmembers/${this.currentClub}/image/${this.memberToEdit.id}`, formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Hochladen des Bildes:", error);
|
||||
}
|
||||
}
|
||||
|
||||
this.resetNewMember();
|
||||
this.memberFormIsOpen = false;
|
||||
},
|
||||
@@ -138,19 +207,21 @@ export default {
|
||||
this.newPhone = member.phone;
|
||||
this.newEmail = member.email;
|
||||
this.newActive = member.active;
|
||||
this.loadNotes(member);
|
||||
try {
|
||||
const response = await apiClient.get(`/clubmembers/${member.id}/image`, {
|
||||
params: { clubId: this.currentClub },
|
||||
responseType: 'blob'
|
||||
});
|
||||
this.memberImagePreview = URL.createObjectURL(response.data);
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Laden des Bildes:", error);
|
||||
this.memberImagePreview = null;
|
||||
}
|
||||
|
||||
},
|
||||
resetToNewMember() {
|
||||
this.memberToEdit = null;
|
||||
this.newFirstname = '';
|
||||
this.newLastname = '';
|
||||
this.newStreet = '';
|
||||
this.newCity = '';
|
||||
this.newBirthdate = '01.01.2010';
|
||||
this.newPhone = '';
|
||||
this.newEmail = '';
|
||||
this.newActive = true;
|
||||
this.memberNotes = [];
|
||||
this.resetNewMember();
|
||||
},
|
||||
async loadNotes(member) {
|
||||
this.selectedMember = member;
|
||||
@@ -176,12 +247,32 @@ export default {
|
||||
this.notes = response.data;
|
||||
},
|
||||
openNotesModal(member) {
|
||||
this.editMember(member);
|
||||
this.memberToEdit = member;
|
||||
this.showNotesModal = true;
|
||||
},
|
||||
closeNotesModal() {
|
||||
this.showNotesModal = false;
|
||||
}
|
||||
},
|
||||
openImageModal(imageUrl) {
|
||||
this.selectedImageUrl = imageUrl;
|
||||
this.showImageModal = true;
|
||||
},
|
||||
closeImageModal() {
|
||||
this.showImageModal = false;
|
||||
this.selectedImageUrl = null;
|
||||
},
|
||||
async loadMemberImage(member) {
|
||||
try {
|
||||
const response = await apiClient.get(`/clubmembers/${this.currentClub}/image/${member.id}`, {
|
||||
responseType: 'blob',
|
||||
});
|
||||
const imageUrl = URL.createObjectURL(response.data);
|
||||
member.imageUrl = imageUrl;
|
||||
} catch (error) {
|
||||
console.error("Failed to load member image:", error);
|
||||
member.imageUrl = null; // Fallback, falls das Bild nicht geladen werden kann
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -247,17 +338,18 @@ table td {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: rgba(200, 200, 200, 0.5);
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: #fefefe;
|
||||
padding: 20px;
|
||||
border: 1px solid #555;
|
||||
width: 50%;
|
||||
max-width: 500px;
|
||||
position: relative;
|
||||
border: 1px solid #888;
|
||||
width: 80%;
|
||||
max-width: 800px;
|
||||
max-height: 80%;
|
||||
box-shadow: 4px 3px 2px #999;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.close {
|
||||
@@ -271,19 +363,8 @@ table td {
|
||||
|
||||
.close:hover,
|
||||
.close:focus {
|
||||
color: black;
|
||||
color: #000;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
padding: 0;
|
||||
/* Kein Padding für Listenelemente */
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user