Added rendering of Event Images

This commit is contained in:
Torsten Schulz
2025-05-07 11:55:27 +02:00
parent b9ba08f91f
commit bb4f490bb1
6 changed files with 67 additions and 11 deletions

1
.gitignore vendored
View File

@@ -26,3 +26,4 @@ node_modules
server.key server.key
server.cert server.cert
public/images/uploads/1ba24ea7-f52c-4179-896f-1909269cab58.jpg

View File

@@ -61,7 +61,7 @@ const filterEvents = async (req, res) => {
{ model: Institution, as: 'institution' }, { model: Institution, as: 'institution' },
{ model: EventPlace, as: 'eventPlace' }, { model: EventPlace, as: 'eventPlace' },
{ model: EventType, as: 'eventType' }, { model: EventType, as: 'eventType' },
{ model: ContactPerson, as: 'contactPersons', through: { attributes: [] } } { model: ContactPerson, as: 'contactPersons', through: { attributes: [] } },
], ],
order: ['name', 'date', 'time'] order: ['name', 'date', 'time']
}); });

View File

@@ -41,6 +41,10 @@ module.exports = (sequelize) => {
alsoOnHomepage: { alsoOnHomepage: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
allowNull: false allowNull: false
},
relatedImage: {
type: DataTypes.STRING,
allowNull: true
} }
}, { }, {
tableName: 'events', tableName: 'events',
@@ -66,6 +70,10 @@ module.exports = (sequelize) => {
otherKey: 'contact_person_id', otherKey: 'contact_person_id',
as: 'contactPersons' as: 'contactPersons'
}); });
Event.belongsTo(models.Image, {
foreignKey: 'relatedImage',
as: 'relatedImageAssociation'
})
}; };
return Event; return Event;

View File

@@ -94,6 +94,13 @@
></multiselect> ></multiselect>
</td> </td>
</tr> </tr>
<tr>
<td colspan="2"><label><input type="checkbox" v-model="onHomepage">Auf der Startseite anzeigen</label></td>
</tr>
<tr>
<td>Zugewiesenes Bild:</td>
<td><img v-if="assignedImage != null" :src="getImagePath" /><button @click="removeImage">Bild entfernen</button></td>
</tr>
<tr> <tr>
<td colspan="2"><button type="submit">Speichern</button></td> <td colspan="2"><button type="submit">Speichern</button></td>
</tr> </tr>

View File

@@ -3,24 +3,33 @@
<table v-if="events.length > 1" class="event-table"> <table v-if="events.length > 1" class="event-table">
<tr v-for="event in events" :key="event.id"> <tr v-for="event in events" :key="event.id">
<td> <td>
<div v-if="hasImage(event)" class="event-image"><img v-if="imageMap[event.relatedImage]"
:src="imageMap[event.relatedImage]" /></div>
<div v-if="shouldDisplay('name')" class="event-name">{{ event.name }}</div> <div v-if="shouldDisplay('name')" class="event-name">{{ event.name }}</div>
<div>{{ formatDateOrDay(event.date, event.dayOfWeek) }}</div> <div>{{ formatDateOrDay(event.date, event.dayOfWeek) }}</div>
<div v-if="shouldDisplay('time')">{{ formatTime(event.time) }} <span v-if="event.endTime"> - {{ formatTime(event.endTime) }}</span> Uhr</div> <div v-if="shouldDisplay('time')">{{ formatTime(event.time) }} <span v-if="event.endTime"> - {{
formatTime(event.endTime) }}</span> Uhr</div>
<div v-if="shouldDisplay('place')">{{ event.eventPlace?.name }}</div> <div v-if="shouldDisplay('place')">{{ event.eventPlace?.name }}</div>
<div v-if="shouldDisplay('description')" class="description">{{ event.description }}</div> <div v-if="shouldDisplay('description')" class="description">{{ event.description }}</div>
<div v-if="shouldDisplay('contactPerson')">{{ event.contactPersons.map(cp => cp.name).join(', ') }}</div> <div v-if="shouldDisplay('contactPerson')">{{event.contactPersons.map(cp => cp.name).join(', ')}}
</div>
<div v-if="shouldDisplay('institution')">{{ event.institution?.name }}</div> <div v-if="shouldDisplay('institution')">{{ event.institution?.name }}</div>
<div v-if="shouldDisplay('type')">{{ event.eventType?.caption }}</div> <div v-if="shouldDisplay('type')">{{ event.eventType?.caption }}</div>
</td> </td>
</tr> </tr>
</table> </table>
<div v-else-if="events.length === 1" :class="events[0].alsoOnHomepage && config.id === 'home' ? 'homepage' : ''"> <div v-else-if="events.length === 1"
:class="events[0].alsoOnHomepage && config.id === 'home' ? 'homepage' : ''">
<div v-if="hasImage(events[0])" class="event-image"><img v-if="imageMap[events[0].relatedImage]"
:src="imageMap[events[0].relatedImage]" /></div>
<div v-if="shouldDisplay('name')" class="event-name">{{ events[0].name }}</div> <div v-if="shouldDisplay('name')" class="event-name">{{ events[0].name }}</div>
<div>{{ formatDateOrDay(events[0].date, events[0].dayOfWeek) }}</div> <div>{{ formatDateOrDay(events[0].date, events[0].dayOfWeek) }}</div>
<div v-if="shouldDisplay('time')">{{ formatTime(events[0].time) }} <span v-if="events[0].endTime"> - {{ formatTime(events[0].endTime) }}</span> Uhr</div> <div v-if="shouldDisplay('time')">{{ formatTime(events[0].time) }} <span v-if="events[0].endTime"> - {{
formatTime(events[0].endTime) }}</span> Uhr</div>
<div v-if="shouldDisplay('place')">{{ events[0].eventPlace?.name }}</div> <div v-if="shouldDisplay('place')">{{ events[0].eventPlace?.name }}</div>
<div v-if="shouldDisplay('description')" class="description">{{ events[0].description }}</div> <div v-if="shouldDisplay('description')" class="description">{{ events[0].description }}</div>
<div v-if="shouldDisplay('contactPerson')">{{ events[0].contactPersons.map(cp => cp.name).join(', ') }}</div> <div v-if="shouldDisplay('contactPerson')">{{events[0].contactPersons.map(cp => cp.name).join(', ')}}
</div>
<div v-if="shouldDisplay('institution')">{{ events[0].institution?.name }}</div> <div v-if="shouldDisplay('institution')">{{ events[0].institution?.name }}</div>
<div v-if="shouldDisplay('type')">{{ events[0].eventType?.caption }}</div> <div v-if="shouldDisplay('type')">{{ events[0].eventType?.caption }}</div>
</div> </div>
@@ -43,6 +52,7 @@ export default {
data() { data() {
return { return {
events: [], events: [],
imageMap: {},
}; };
}, },
async created() { async created() {
@@ -56,6 +66,18 @@ export default {
this.config this.config
); );
this.events = response.data.events; this.events = response.data.events;
await Promise.all(
this.events
.filter(event => this.hasImage(event))
.map(async event => {
try {
const response = await axios.get('/image/' + event.relatedImage);
this.imageMap[event.relatedImage] = '/images/uploads/' + response.data.filename;
} catch (err) {
console.error(`Bild konnte nicht geladen werden (ID ${event.relatedImage}):`, err);
}
})
);
} catch (error) { } catch (error) {
console.error('Fehler beim Abrufen der Events', error); console.error('Fehler beim Abrufen der Events', error);
} }
@@ -71,6 +93,15 @@ export default {
return daysOfWeek[dayOfWeek]; return daysOfWeek[dayOfWeek];
} }
return ''; return '';
},
hasImage(event) {
return event.relatedImage && event.relatedImage != '';
},
async imagePath(eventImage) {
const response = await axios.get('/image/' + eventImage);
const path = '/images/uploads/' + response.data.filename;
console.log(path);
return path;
} }
} }
}; };
@@ -80,18 +111,27 @@ export default {
.event-name { .event-name {
font-weight: bold; font-weight: bold;
} }
.event-table { .event-table {
border-collapse: collapse; border-collapse: collapse;
} }
.event-table td { .event-table td {
border: 1px solid black; border: 1px solid black;
} }
.homepage { .homepage {
border: 1px solid #9400ff; border: 1px solid #9400ff;
padding: 0.5em; padding: 0.5em;
text-align: center; text-align: center;
} }
.description { .description {
padding: 0.5em 0; padding: 0.5em 0;
} }
.event-image > img {
max-width: 8em;
max-height: 8em;
}
</style> </style>

View File

@@ -19,8 +19,8 @@ module.exports = defineConfig({
}, },
plugins: [ plugins: [
new webpack.DefinePlugin({ new webpack.DefinePlugin({
'process.env': JSON.stringify(process.env) 'process.env.CUSTOM_VAR': JSON.stringify(process.env.CUSTOM_VAR)
}), })
], ],
}, },
}); });