Erweitert die Funktionalität in PredefinedActivityImageController.js, um Zeichnungsdaten aus dem Request zu extrahieren und in der Datenbank zu speichern. Aktualisiert das Datenmodell in PredefinedActivityImage.js, um ein neues Feld für Zeichnungsdaten hinzuzufügen. Passt die Routen in predefinedActivityRoutes.js an, um die neue PUT-Methode für das Hochladen von Bildern zu unterstützen. Integriert die Zeichnungsdaten in die Aktivitätenlogik in diaryDateActivityService.js und aktualisiert die Benutzeroberfläche in CourtDrawingTool.vue zur Unterstützung von Zeichnungsdaten. Verbessert die Handhabung von Bild-Uploads in PredefinedActivities.vue und implementiert die Logik zum Laden von Zeichnungsdaten beim Bearbeiten von Aktivitäten.
This commit is contained in:
@@ -33,10 +33,15 @@ export const uploadPredefinedActivityImage = async (req, res) => {
|
||||
.jpeg({ quality: 85 })
|
||||
.toFile(filePath);
|
||||
|
||||
// Extrahiere Zeichnungsdaten aus dem Request
|
||||
const drawingData = req.body.drawingData ? JSON.parse(req.body.drawingData) : null;
|
||||
console.log('[uploadPredefinedActivityImage] - drawingData:', drawingData);
|
||||
|
||||
const imageRecord = await PredefinedActivityImage.create({
|
||||
predefinedActivityId: id,
|
||||
imagePath: filePath,
|
||||
mimeType: 'image/jpeg',
|
||||
drawingData: drawingData ? JSON.stringify(drawingData) : null,
|
||||
});
|
||||
|
||||
// Optional: als imageLink am Activity-Datensatz setzen
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
-- Migration: Add drawing_data column to predefined_activity_images table
|
||||
-- Date: 2025-09-22
|
||||
-- Description: Adds drawing_data column to store Court Drawing Tool metadata
|
||||
|
||||
ALTER TABLE `predefined_activity_images`
|
||||
ADD COLUMN `drawing_data` TEXT NULL
|
||||
COMMENT 'JSON string containing drawing metadata for Court Drawing Tool'
|
||||
AFTER `mime_type`;
|
||||
|
||||
-- Verify the column was added
|
||||
DESCRIBE `predefined_activity_images`;
|
||||
@@ -19,6 +19,11 @@ const PredefinedActivityImage = sequelize.define('PredefinedActivityImage', {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true,
|
||||
},
|
||||
drawingData: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
comment: 'JSON string containing drawing metadata for Court Drawing Tool'
|
||||
},
|
||||
}, {
|
||||
tableName: 'predefined_activity_images',
|
||||
timestamps: true,
|
||||
|
||||
@@ -23,6 +23,7 @@ router.get('/', authenticate, getAllPredefinedActivities);
|
||||
router.get('/:id', authenticate, getPredefinedActivityById);
|
||||
router.put('/:id', authenticate, updatePredefinedActivity);
|
||||
router.post('/:id/image', authenticate, upload.single('image'), uploadPredefinedActivityImage);
|
||||
router.put('/:id/image', authenticate, upload.single('image'), uploadPredefinedActivityImage);
|
||||
router.delete('/:id/image/:imageId', authenticate, deletePredefinedActivityImage);
|
||||
router.get('/search/query', authenticate, searchPredefinedActivities);
|
||||
router.post('/merge', authenticate, mergePredefinedActivities);
|
||||
|
||||
@@ -2,6 +2,7 @@ import DiaryDateActivity from '../models/DiaryDateActivity.js';
|
||||
import GroupActivity from '../models/GroupActivity.js';
|
||||
import Group from '../models/Group.js';
|
||||
import PredefinedActivity from '../models/PredefinedActivity.js';
|
||||
import PredefinedActivityImage from '../models/PredefinedActivityImage.js';
|
||||
import { checkAccess } from '../utils/userUtils.js';
|
||||
import { Op } from 'sequelize';
|
||||
|
||||
@@ -16,11 +17,19 @@ class DiaryDateActivityService {
|
||||
if (!predefinedActivity) {
|
||||
predefinedActivity = await PredefinedActivity.create({
|
||||
name: data.activity,
|
||||
description: '',
|
||||
duration: data.duration
|
||||
description: data.description || '',
|
||||
duration: data.duration && data.duration !== '' ? parseInt(data.duration) : null
|
||||
});
|
||||
}
|
||||
restData.predefinedActivityId = predefinedActivity.id;
|
||||
|
||||
// Bereinige duration-Feld für DiaryDateActivity
|
||||
if (restData.duration === '' || restData.duration === undefined) {
|
||||
restData.duration = null;
|
||||
} else if (typeof restData.duration === 'string') {
|
||||
restData.duration = parseInt(restData.duration);
|
||||
}
|
||||
|
||||
const maxOrderId = await DiaryDateActivity.max('orderId', {
|
||||
where: { diaryDateId: data.diaryDateId }
|
||||
});
|
||||
@@ -54,8 +63,8 @@ class DiaryDateActivityService {
|
||||
console.log('[DiaryDateActivityService::updateActivity] - creating new PredefinedActivity');
|
||||
predefinedActivity = await PredefinedActivity.create({
|
||||
name: data.customActivityName,
|
||||
description: '',
|
||||
duration: data.duration || activity.duration
|
||||
description: data.description || '',
|
||||
duration: data.duration && data.duration !== '' ? parseInt(data.duration) : (activity.duration || null)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -131,7 +140,7 @@ class DiaryDateActivityService {
|
||||
}
|
||||
|
||||
async getActivities(userToken, clubId, diaryDateId) {
|
||||
console.log('[DiaryDateActivityService::getActivities] - check user access');
|
||||
console.log('[DiaryDateActivityService::getActivities] - check user access - SERVER RESTARTED');
|
||||
await checkAccess(userToken, clubId);
|
||||
console.log(`[DiaryDateActivityService::getActivities] - fetch activities for diaryDateId: ${diaryDateId}`);
|
||||
const activities = await DiaryDateActivity.findAll({
|
||||
@@ -141,6 +150,12 @@ class DiaryDateActivityService {
|
||||
{
|
||||
model: PredefinedActivity,
|
||||
as: 'predefinedActivity',
|
||||
include: [
|
||||
{
|
||||
model: PredefinedActivityImage,
|
||||
as: 'images'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
model: GroupActivity,
|
||||
@@ -159,7 +174,70 @@ class DiaryDateActivityService {
|
||||
]
|
||||
});
|
||||
console.log(`[DiaryDateActivityService::getActivities] - found ${activities.length} activities`);
|
||||
return activities;
|
||||
|
||||
// Füge imageUrl zu jeder PredefinedActivity hinzu
|
||||
console.log('[DiaryDateActivityService::getActivities] - Adding imageUrl to activities');
|
||||
const activitiesWithImages = await Promise.all(activities.map(async activity => {
|
||||
// Konvertiere zu JSON und zurück, um alle Eigenschaften zu serialisieren
|
||||
const activityData = activity.toJSON();
|
||||
|
||||
if (activityData.predefinedActivity) {
|
||||
console.log(JSON.parse(JSON.stringify(activityData)));
|
||||
// Hole die erste verfügbare Image-ID direkt aus der Datenbank
|
||||
const allImages = await PredefinedActivityImage.findAll({
|
||||
where: { predefinedActivityId: activityData.predefinedActivity.id },
|
||||
order: [['createdAt', 'ASC']]
|
||||
});
|
||||
|
||||
console.log(`Activity ${activityData.predefinedActivity.id}: allImages =`, allImages.map(img => ({ id: img.id, activityId: img.predefinedActivityId, hasDrawingData: !!img.drawingData })));
|
||||
|
||||
const firstImage = allImages.length > 0 ? allImages[0] : null;
|
||||
console.log(`Activity ${activityData.predefinedActivity.id}: firstImage =`, firstImage?.id);
|
||||
|
||||
// Füge Zeichnungsdaten hinzu, falls vorhanden
|
||||
if (firstImage && firstImage.drawingData) {
|
||||
try {
|
||||
activityData.predefinedActivity.drawingData = JSON.parse(firstImage.drawingData);
|
||||
console.log(`Activity ${activityData.predefinedActivity.id}: drawingData loaded:`, activityData.predefinedActivity.drawingData);
|
||||
} catch (error) {
|
||||
console.error(`Activity ${activityData.predefinedActivity.id}: Error parsing drawingData:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
if (firstImage) {
|
||||
// Füge sowohl imageUrl als auch imageLink mit Image-ID hinzu
|
||||
activityData.predefinedActivity.imageUrl = `/api/predefined-activities/${activityData.predefinedActivity.id}/image/${firstImage.id}`;
|
||||
activityData.predefinedActivity.imageLink = `/api/predefined-activities/${activityData.predefinedActivity.id}/image/${firstImage.id}`;
|
||||
} else {
|
||||
// Fallback: Verwende den Basis-Pfad ohne Image-ID
|
||||
activityData.predefinedActivity.imageUrl = `/api/predefined-activities/${activityData.predefinedActivity.id}/image`;
|
||||
activityData.predefinedActivity.imageLink = `/api/predefined-activities/${activityData.predefinedActivity.id}/image`;
|
||||
}
|
||||
}
|
||||
|
||||
// Auch für GroupActivities
|
||||
if (activityData.groupActivities && activityData.groupActivities.length > 0) {
|
||||
for (const groupActivity of activityData.groupActivities) {
|
||||
if (groupActivity.groupPredefinedActivity) {
|
||||
// Hole die erste verfügbare Image-ID direkt aus der Datenbank
|
||||
const firstImage = await PredefinedActivityImage.findOne({
|
||||
where: { predefinedActivityId: groupActivity.groupPredefinedActivity.id },
|
||||
order: [['createdAt', 'ASC']]
|
||||
});
|
||||
|
||||
if (firstImage) {
|
||||
groupActivity.groupPredefinedActivity.imageUrl = `/api/predefined-activities/${groupActivity.groupPredefinedActivity.id}/image/${firstImage.id}`;
|
||||
groupActivity.groupPredefinedActivity.imageLink = `/api/predefined-activities/${groupActivity.groupPredefinedActivity.id}/image/${firstImage.id}`;
|
||||
} else {
|
||||
groupActivity.groupPredefinedActivity.imageUrl = `/api/predefined-activities/${groupActivity.groupPredefinedActivity.id}/image`;
|
||||
groupActivity.groupPredefinedActivity.imageLink = `/api/predefined-activities/${groupActivity.groupPredefinedActivity.id}/image`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return activityData;
|
||||
}));
|
||||
return activitiesWithImages;
|
||||
}
|
||||
|
||||
async addGroupActivity(userToken, clubId, diaryDateId, groupId, activity) {
|
||||
|
||||
Reference in New Issue
Block a user