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:
@@ -16,6 +16,7 @@ const storage = multer.diskStorage({
|
||||
const upload = multer({ storage });
|
||||
|
||||
exports.uploadImage = upload.single('image');
|
||||
exports.uploadImages = upload.array('images');
|
||||
|
||||
exports.getAllPages = async (req, res) => {
|
||||
try {
|
||||
@@ -51,6 +52,51 @@ exports.saveImageDetails = async (req, res) => {
|
||||
}
|
||||
};
|
||||
|
||||
exports.saveImageDetailsBulk = async (req, res) => {
|
||||
try {
|
||||
const { baseTitle, description, page, startNumber } = req.body;
|
||||
const files = req.files || [];
|
||||
|
||||
if (!baseTitle || !String(baseTitle).trim()) {
|
||||
return res.status(400).json({ error: 'Bitte einen Basis-Titel angeben.' });
|
||||
}
|
||||
if (files.length === 0) {
|
||||
return res.status(400).json({ error: 'Bitte mindestens ein Bild auswählen.' });
|
||||
}
|
||||
|
||||
const pageItem = page ? await Page.findAll({ where: { link: page } }) : [];
|
||||
const pageId = pageItem && pageItem[0] ? pageItem[0].id : null;
|
||||
const firstNumber = Number.parseInt(startNumber, 10);
|
||||
const startAt = Number.isFinite(firstNumber) ? firstNumber : 1;
|
||||
|
||||
const createdImages = [];
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
const runningNumber = startAt + i;
|
||||
const title = `${String(baseTitle).trim()} ${runningNumber}`;
|
||||
const newImage = await Image.create({
|
||||
id: uuidv4(),
|
||||
filename: file.filename,
|
||||
title,
|
||||
description: description || '',
|
||||
pageId,
|
||||
});
|
||||
createdImages.push(newImage);
|
||||
}
|
||||
|
||||
// Menübild nur dann setzen, wenn genau ein Bild hochgeladen wurde.
|
||||
if (page && createdImages.length === 1) {
|
||||
const imageUrl = `/uploads/${createdImages[0].filename}`;
|
||||
await MenuItem.update({ image: imageUrl }, { where: { link: page } });
|
||||
}
|
||||
|
||||
res.status(201).json(createdImages);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Bulk-Upload der Bilder:', error);
|
||||
res.status(500).json({ error: 'Fehler beim Bulk-Upload der Bilder' });
|
||||
}
|
||||
};
|
||||
|
||||
exports.getImages = async (req, res) => {
|
||||
try {
|
||||
const images = await Image.findAll({ order: [['title', 'ASC']] });
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { getAllPages, uploadImage, saveImageDetails, getImages, getImagesByPage, getImageById, getImageByHash, updateImage } = require('../controllers/imageController');
|
||||
const { getAllPages, uploadImage, uploadImages, saveImageDetails, saveImageDetailsBulk, getImages, getImagesByPage, getImageById, getImageByHash, updateImage } = require('../controllers/imageController');
|
||||
const authMiddleware = require('../middleware/authMiddleware')
|
||||
|
||||
router.post('/', authMiddleware, uploadImage, saveImageDetails);
|
||||
router.post('/bulk', authMiddleware, uploadImages, saveImageDetailsBulk);
|
||||
router.get('/', authMiddleware, getImages);
|
||||
router.get('/page/:pageId', getImagesByPage);
|
||||
router.put('/hash/:id', getImageByHash);
|
||||
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user