diff --git a/backend/controllers/predefinedActivityController.js b/backend/controllers/predefinedActivityController.js
index 102a2f1..1320a7a 100644
--- a/backend/controllers/predefinedActivityController.js
+++ b/backend/controllers/predefinedActivityController.js
@@ -5,8 +5,8 @@ import fs from 'fs';
export const createPredefinedActivity = async (req, res) => {
try {
- const { name, code, description, durationText, duration, imageLink } = req.body;
- const predefinedActivity = await predefinedActivityService.createPredefinedActivity({ name, code, description, durationText, duration, imageLink });
+ const { name, code, description, durationText, duration, imageLink, drawingData } = req.body;
+ const predefinedActivity = await predefinedActivityService.createPredefinedActivity({ name, code, description, durationText, duration, imageLink, drawingData });
res.status(201).json(predefinedActivity);
} catch (error) {
console.error('[createPredefinedActivity] - Error:', error);
@@ -42,8 +42,8 @@ export const getPredefinedActivityById = async (req, res) => {
export const updatePredefinedActivity = async (req, res) => {
try {
const { id } = req.params;
- const { name, code, description, durationText, duration, imageLink } = req.body;
- const updatedActivity = await predefinedActivityService.updatePredefinedActivity(id, { name, code, description, durationText, duration, imageLink });
+ const { name, code, description, durationText, duration, imageLink, drawingData } = req.body;
+ const updatedActivity = await predefinedActivityService.updatePredefinedActivity(id, { name, code, description, durationText, duration, imageLink, drawingData });
res.status(200).json(updatedActivity);
} catch (error) {
console.error('[updatePredefinedActivity] - Error:', error);
diff --git a/backend/models/PredefinedActivity.js b/backend/models/PredefinedActivity.js
index 749c6a5..63c7d8d 100644
--- a/backend/models/PredefinedActivity.js
+++ b/backend/models/PredefinedActivity.js
@@ -19,6 +19,11 @@ const PredefinedActivity = sequelize.define('PredefinedActivity', {
type: DataTypes.TEXT,
allowNull: true,
},
+ drawingData: {
+ type: DataTypes.TEXT,
+ allowNull: true,
+ comment: 'JSON string with metadata for Court Drawing Tool'
+ },
durationText: {
type: DataTypes.STRING,
allowNull: true,
diff --git a/backend/services/predefinedActivityService.js b/backend/services/predefinedActivityService.js
index 8152d3a..2dd9cdd 100644
--- a/backend/services/predefinedActivityService.js
+++ b/backend/services/predefinedActivityService.js
@@ -15,6 +15,7 @@ class PredefinedActivityService {
durationText: data.durationText,
duration: data.duration,
imageLink: data.imageLink,
+ drawingData: data.drawingData ? JSON.stringify(data.drawingData) : null,
});
}
@@ -32,6 +33,7 @@ class PredefinedActivityService {
durationText: data.durationText,
duration: data.duration,
imageLink: data.imageLink,
+ drawingData: data.drawingData ? JSON.stringify(data.drawingData) : null,
});
}
diff --git a/frontend/src/components/CourtDrawingTool.vue b/frontend/src/components/CourtDrawingTool.vue
index 065ecc9..0ec848f 100644
--- a/frontend/src/components/CourtDrawingTool.vue
+++ b/frontend/src/components/CourtDrawingTool.vue
@@ -176,7 +176,6 @@
-
@@ -196,6 +195,10 @@ export default {
drawingData: { // Added for loading saved drawing data
type: Object,
default: null
+ },
+ allowImageUpload: { // Neu: steuert, ob das Tool ein Bild erzeugt/hochlädt
+ type: Boolean,
+ default: true
}
},
data() {
@@ -1092,7 +1095,7 @@ export default {
}
},
- async saveDrawing() {
+ async saveDrawing() {
console.log('CourtDrawingTool: saveDrawing called');
try {
@@ -1116,7 +1119,10 @@ export default {
};
console.log('CourtDrawingTool: drawingData created:', drawingData);
-
+ // Immer Metadaten nach oben geben
+ this.$emit('update-drawing-data', drawingData);
+
+ if (this.allowImageUpload) {
// Konvertiere DataURL zu Blob für Upload
const response = await fetch(dataURL);
const blob = await response.blob();
@@ -1132,9 +1138,15 @@ export default {
console.log('CourtDrawingTool: emitting upload-image event');
this.$emit('upload-image', file, drawingData);
console.log('CourtDrawingTool: upload-image event emitted');
-
- // Emittiere das File für Upload (Parent-Komponente macht den Upload)
- console.log('CourtDrawingTool: File ready for upload');
+ } else {
+ // Kein Bild-Upload mehr: gebe lediglich die Zeichnungsdaten an den Parent weiter,
+ // damit Felder (Kürzel/Name/Beschreibung) gefüllt werden können
+ this.$emit('update-fields', {
+ code: this.getFullCode ? this.getFullCode() : '',
+ name: this.getFullTitle ? this.getFullTitle() : '',
+ description: ''
+ });
+ }
} catch (error) {
console.error('CourtDrawingTool: Error in saveDrawing:', error);
}
diff --git a/frontend/src/views/PredefinedActivities.vue b/frontend/src/views/PredefinedActivities.vue
index 4ca2b5b..ae71ad1 100644
--- a/frontend/src/views/PredefinedActivities.vue
+++ b/frontend/src/views/PredefinedActivities.vue
@@ -81,8 +81,10 @@
v-model="editModel.drawingData"
:activity-id="editModel.id"
:drawing-data="editModel.drawingData"
+ :allow-image-upload="false"
@save="onDrawingSave"
@update-fields="onUpdateFields"
+ @update-drawing-data="onUpdateDrawingData"
@upload-image="onDrawingImageUpload"
@image-uploaded="onImageUploaded"
/>
@@ -150,6 +152,15 @@ export default {
}
},
methods: {
+ parseDrawingData(value) {
+ if (!value) return null;
+ if (typeof value === 'object') return value;
+ try { return JSON.parse(value); } catch (e) { return null; }
+ },
+ normalizeActivity(activity, images) {
+ const drawingData = this.parseDrawingData(activity && activity.drawingData);
+ return { ...(activity || {}), drawingData };
+ },
async reload() {
const r = await apiClient.get('/predefined-activities');
this.activities = r.data || [];
@@ -159,23 +170,12 @@ export default {
const r = await apiClient.get(`/predefined-activities/${a.id}`);
const { images, ...activity } = r.data;
this.images = images || [];
-
- // Lade Zeichnungsdaten aus dem ersten Bild, falls vorhanden
- let drawingData = null;
- if (images && images.length > 0 && images[0].drawingData) {
- try {
- drawingData = JSON.parse(images[0].drawingData);
- console.log('PredefinedActivities: Loaded drawingData:', drawingData);
- } catch (error) {
- console.error('PredefinedActivities: Error parsing drawingData:', error);
- }
- } else {
- // Keine Bilder vorhanden - setze drawingData explizit auf null
- console.log('PredefinedActivities: No images found, setting drawingData to null');
- drawingData = null;
+ // Server-Daten normalisieren und ggf. image-drawingData fallbacken
+ let model = this.normalizeActivity(activity, images);
+ if (!model.drawingData && images && images.length > 0 && images[0].drawingData) {
+ model.drawingData = this.parseDrawingData(images[0].drawingData);
}
-
- this.editModel = { ...activity, drawingData };
+ this.editModel = model;
},
async reloadImages() {
if (this.editModel && this.editModel.id) {
@@ -226,11 +226,14 @@ export default {
if (this.editModel.id) {
const { id, ...payload } = this.editModel;
+ if (payload.drawingData && typeof payload.drawingData === 'object') {
+ payload.drawingData = payload.drawingData;
+ }
const r = await apiClient.put(`/predefined-activities/${id}`, payload);
- this.editModel = r.data;
+ this.editModel = this.normalizeActivity(r.data);
} else {
const r = await apiClient.post('/predefined-activities', this.editModel);
- this.editModel = r.data;
+ this.editModel = this.normalizeActivity(r.data);
}
// Nach dem Speichern (sowohl CREATE als auch UPDATE): Bild hochladen falls vorhanden
@@ -328,6 +331,11 @@ export default {
this.editModel.description = fields.description;
}
},
+ onUpdateDrawingData(data) {
+ if (this.editModel) {
+ this.editModel.drawingData = data;
+ }
+ },
async onDrawingImageUpload(file, drawingData) {
console.log('onDrawingImageUpload called with file:', file);