Add bulk image upload functionality: Implement new routes and methods for handling bulk image uploads in the imageController. Update ImageUpload component to support switching between single and bulk upload modes, including form handling for multiple images, base title, start number, and optional page association. Enhance user experience with improved form validation and reset functionality.

This commit is contained in:
Torsten Schulz (local)
2026-04-29 13:36:35 +02:00
parent b47e832e45
commit e44950d857
3 changed files with 138 additions and 2 deletions

View File

@@ -1,7 +1,16 @@
<template>
<div>
<h1>Bild hochladen</h1>
<form @submit.prevent="uploadImage">
<div class="upload-mode-switch">
<button type="button" :class="{ active: uploadMode === 'single' }" @click="uploadMode = 'single'">
Einzel-Upload
</button>
<button type="button" :class="{ active: uploadMode === 'bulk' }" @click="uploadMode = 'bulk'">
Bulk-Upload
</button>
</div>
<form v-if="uploadMode === 'single'" @submit.prevent="uploadImage">
<div>
<label for="title">Titel</label>
<input type="text" id="title" v-model="title" />
@@ -24,6 +33,38 @@
<button type="submit">Hochladen</button>
</form>
<form v-else @submit.prevent="uploadImagesBulk">
<h2>Bulk-Upload</h2>
<div>
<label for="bulkBaseTitle">Basis-Titel</label>
<input type="text" id="bulkBaseTitle" v-model="bulkBaseTitle" placeholder="z. B. Gemeindebrief Bild" required />
</div>
<div>
<label for="bulkStartNumber">Startnummer</label>
<input type="number" id="bulkStartNumber" v-model.number="bulkStartNumber" min="1" />
</div>
<div>
<label for="bulkDescription">Beschreibung</label>
<textarea id="bulkDescription" v-model="bulkDescription"></textarea>
</div>
<div>
<label for="bulkImages">Bilder</label>
<input type="file" id="bulkImages" ref="bulkImagesInput" @change="onBulkFilesChange" accept="image/*" multiple />
</div>
<div>
<label for="bulkPage">Seite</label>
<select id="bulkPage" v-model="bulkSelectedPage">
<option value="">Keine Seite</option>
<option v-for="page in pages" :key="`bulk-${page.value}`" :value="page.value">{{ page.caption }}</option>
</select>
</div>
<p v-if="bulkFiles.length > 0">
{{ bulkFiles.length }} Datei(en) ausgewählt.
Erste Titel-Vorschau: <strong>{{ bulkBaseTitle || 'Titel' }} {{ bulkStartNumber }}</strong>
</p>
<button type="submit" :disabled="bulkFiles.length === 0">Bulk hochladen</button>
</form>
<div v-if="images.length">
<h2>Hochgeladene Bilder</h2>
<div v-for="image in images" :key="image.id" class="uploaded-image">
@@ -47,7 +88,13 @@ export default {
title: '',
description: '',
image: null,
bulkBaseTitle: '',
bulkStartNumber: 1,
bulkDescription: '',
bulkFiles: [],
bulkSelectedPage: '',
selectedPage: '',
uploadMode: 'single',
pages: [],
images: []
};
@@ -58,6 +105,9 @@ export default {
onFileChange(e) {
this.image = e.target.files[0];
},
onBulkFilesChange(e) {
this.bulkFiles = Array.from(e.target.files || []);
},
async uploadImage() {
const formData = new FormData();
formData.append('title', this.title);
@@ -81,6 +131,25 @@ export default {
console.error('Fehler beim Abrufen der Bilder:', error);
}
},
async uploadImagesBulk() {
if (!this.bulkBaseTitle || this.bulkFiles.length === 0) {
return;
}
const formData = new FormData();
formData.append('baseTitle', this.bulkBaseTitle);
formData.append('startNumber', this.bulkStartNumber);
formData.append('description', this.bulkDescription);
formData.append('page', this.bulkSelectedPage);
this.bulkFiles.forEach((file) => formData.append('images', file));
try {
await axios.post('/image/bulk', formData);
this.fetchImages();
this.resetBulkForm();
} catch (error) {
console.error('Fehler beim Bulk-Upload der Bilder:', error);
}
},
async fetchPages() {
try {
const response = await axios.get('/menu-data');
@@ -116,6 +185,16 @@ export default {
this.image = null;
this.selectedPage = '';
document.getElementById('image').value = null;
},
resetBulkForm() {
this.bulkBaseTitle = '';
this.bulkStartNumber = 1;
this.bulkDescription = '';
this.bulkFiles = [];
this.bulkSelectedPage = '';
if (this.$refs.bulkImagesInput) {
this.$refs.bulkImagesInput.value = null;
}
}
},
mounted() {
@@ -142,4 +221,14 @@ form div {
width: 100%;
margin: 5px 0;
}
.upload-mode-switch {
display: flex;
gap: 8px;
margin-bottom: 12px;
}
.upload-mode-switch button.active {
font-weight: bold;
}
</style>