inital commit
This commit is contained in:
138
src/components/ContactPersonForm.vue
Normal file
138
src/components/ContactPersonForm.vue
Normal file
@@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<div class="contact-person-form">
|
||||
<h2>Kontaktperson Formular</h2>
|
||||
<form @submit.prevent="saveContactPerson">
|
||||
<label for="name">Name:</label>
|
||||
<input type="text" id="name" v-model="localContactPerson.name" required>
|
||||
|
||||
<label for="phone">Telefon:</label>
|
||||
<input type="text" id="phone" v-model="localContactPerson.phone">
|
||||
|
||||
<label for="street">Straße:</label>
|
||||
<input type="text" id="street" v-model="localContactPerson.street">
|
||||
|
||||
<label for="zipcode">PLZ:</label>
|
||||
<input type="text" id="zipcode" v-model="localContactPerson.zipcode">
|
||||
|
||||
<label for="city">Ort:</label>
|
||||
<input type="text" id="city" v-model="localContactPerson.city">
|
||||
|
||||
<label for="email">Email:</label>
|
||||
<input type="email" id="email" v-model="localContactPerson.email">
|
||||
|
||||
<label for="positions">Positionen:</label>
|
||||
<multiselect
|
||||
v-model="selectedPositions"
|
||||
:options="positions"
|
||||
:multiple="true"
|
||||
:close-on-select="false"
|
||||
:clear-on-select="false"
|
||||
:preserve-search="true"
|
||||
placeholder="Wähle einige"
|
||||
label="caption"
|
||||
track-by="id"
|
||||
:preselect-first="false"
|
||||
></multiselect>
|
||||
|
||||
<button type="submit">Speichern</button>
|
||||
<button type="button" @click="resetForm">Neue Kontaktperson</button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Multiselect from 'vue-multiselect';
|
||||
import axios from 'axios';
|
||||
|
||||
export default {
|
||||
name: 'ContactPersonForm',
|
||||
components: { Multiselect },
|
||||
props: {
|
||||
contactPerson: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
name: '',
|
||||
phone: '',
|
||||
street: '',
|
||||
zipcode: '',
|
||||
city: '',
|
||||
email: '',
|
||||
positions: []
|
||||
})
|
||||
},
|
||||
positions: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
localContactPerson: { ...this.contactPerson },
|
||||
selectedPositions: this.contactPerson.positions || []
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
contactPerson: {
|
||||
handler(newVal) {
|
||||
this.localContactPerson = { ...newVal };
|
||||
this.selectedPositions = newVal.positions || [];
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
},
|
||||
selectedPositions(newVal) {
|
||||
this.localContactPerson.positions = newVal;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async saveContactPerson() {
|
||||
try {
|
||||
const positionIds = this.selectedPositions.map(position => position.id);
|
||||
const payload = {
|
||||
...this.localContactPerson,
|
||||
positionIds: positionIds
|
||||
};
|
||||
if (this.localContactPerson.id) {
|
||||
await axios.put(`http://localhost:3000/api/contact-persons/${this.localContactPerson.id}`, payload);
|
||||
} else {
|
||||
await axios.post('http://localhost:3000/api/contact-persons', payload);
|
||||
}
|
||||
|
||||
this.$emit('contactPersonSaved');
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Speichern der Kontaktperson:', error);
|
||||
}
|
||||
},
|
||||
resetForm() {
|
||||
this.localContactPerson = {
|
||||
name: '',
|
||||
phone: '',
|
||||
street: '',
|
||||
zipcode: '',
|
||||
city: '',
|
||||
email: '',
|
||||
positions: []
|
||||
};
|
||||
this.selectedPositions = [];
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@import '~vue-multiselect/dist/vue-multiselect.css';
|
||||
.contact-person-form {
|
||||
max-width: 400px;
|
||||
margin: auto;
|
||||
}
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
label {
|
||||
margin-top: 10px;
|
||||
}
|
||||
button {
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
250
src/components/EventForm.vue
Normal file
250
src/components/EventForm.vue
Normal file
@@ -0,0 +1,250 @@
|
||||
<template>
|
||||
<div class="event-form">
|
||||
<h2>Veranstaltung Formular</h2>
|
||||
<form @submit.prevent="saveEvent">
|
||||
<table>
|
||||
<tr>
|
||||
<td><label for="name">Name:</label></td>
|
||||
<td><input type="text" id="name" v-model="eventData.name" required></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="eventType">Typ:</label></td>
|
||||
<td>
|
||||
<multiselect
|
||||
v-model="selectedEventType"
|
||||
:options="eventTypes"
|
||||
label="caption"
|
||||
track-by="id"
|
||||
placeholder="Typ wählen"
|
||||
></multiselect>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="dateMode">Datum-Modus:</label></td>
|
||||
<td>
|
||||
<select v-model="dateMode">
|
||||
<option value="date">Datum</option>
|
||||
<option value="weekday">Wochentag</option>
|
||||
<option value="interval">Intervall</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="dateMode === 'date' || dateMode === 'interval'">
|
||||
<td><label for="date">Datum:</label></td>
|
||||
<td><input type="date" id="date" v-model="eventData.date"></td>
|
||||
</tr>
|
||||
<tr v-if="dateMode === 'weekday' || dateMode === 'interval'">
|
||||
<td><label for="dayOfWeek">Wochentag:</label></td>
|
||||
<td>
|
||||
<multiselect
|
||||
v-model="eventData.dayOfWeek"
|
||||
:options="weekdays"
|
||||
label="name"
|
||||
track-by="value"
|
||||
placeholder="Wochentag wählen"
|
||||
></multiselect>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="time">Uhrzeit:</label></td>
|
||||
<td><input type="time" id="time" v-model="eventData.time"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="endTime">Ende-Uhrzeit:</label></td>
|
||||
<td><input type="time" id="endTime" v-model="eventData.endTime"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="description">Beschreibung:</label></td>
|
||||
<td><textarea id="description" v-model="eventData.description" class="descriptionedit"></textarea></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="institution">Institution:</label></td>
|
||||
<td>
|
||||
<multiselect
|
||||
v-model="selectedInstitution"
|
||||
:options="localInstitutions"
|
||||
label="name"
|
||||
track-by="id"
|
||||
placeholder="Institution wählen"
|
||||
></multiselect>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="eventPlace">Veranstaltungsort:</label></td>
|
||||
<td>
|
||||
<multiselect
|
||||
v-model="selectedEventPlace"
|
||||
:options="localEventPlaces"
|
||||
label="name"
|
||||
track-by="id"
|
||||
placeholder="Veranstaltungsort wählen"
|
||||
></multiselect>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="contactPersons">Kontaktpersonen:</label></td>
|
||||
<td>
|
||||
<multiselect
|
||||
v-model="selectedContactPersons"
|
||||
:options="localContactPersons"
|
||||
:multiple="true"
|
||||
label="name"
|
||||
track-by="id"
|
||||
placeholder="Kontaktpersonen wählen"
|
||||
></multiselect>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><button type="submit">Speichern</button></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import Multiselect from 'vue-multiselect';
|
||||
|
||||
export default {
|
||||
name: 'EventForm',
|
||||
components: { Multiselect },
|
||||
props: {
|
||||
event: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => ({})
|
||||
},
|
||||
institutions: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => []
|
||||
},
|
||||
eventPlaces: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => []
|
||||
},
|
||||
contactPersons: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
eventData: { ...this.event },
|
||||
selectedEventType: null,
|
||||
selectedInstitution: this.event.institution || null,
|
||||
selectedEventPlace: this.event.eventPlace || null,
|
||||
selectedContactPersons: this.event.contactPersons || [],
|
||||
eventTypes: [],
|
||||
dateMode: 'date',
|
||||
weekdays: [
|
||||
{ name: 'Montag', value: 1 },
|
||||
{ name: 'Dienstag', value: 2 },
|
||||
{ name: 'Mittwoch', value: 3 },
|
||||
{ name: 'Donnerstag', value: 4 },
|
||||
{ name: 'Freitag', value: 5 },
|
||||
{ name: 'Samstag', value: 6 },
|
||||
{ name: 'Sonntag', value: 7 },
|
||||
],
|
||||
localInstitutions: [...this.institutions],
|
||||
localEventPlaces: [...this.eventPlaces],
|
||||
localContactPersons: [...this.contactPersons]
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
event(newVal) {
|
||||
this.eventData = { ...newVal };
|
||||
this.selectedEventType = this.eventTypes.find(type => type.id === newVal.eventTypeId) || null;
|
||||
this.selectedInstitution = newVal.institution || null;
|
||||
this.selectedEventPlace = newVal.eventPlace || null;
|
||||
this.selectedContactPersons = newVal.contactPersons || [];
|
||||
this.determineDateMode();
|
||||
},
|
||||
institutions(newVal) {
|
||||
this.localInstitutions = [...newVal];
|
||||
},
|
||||
eventPlaces(newVal) {
|
||||
this.localEventPlaces = [...newVal];
|
||||
},
|
||||
contactPersons(newVal) {
|
||||
this.localContactPersons = [...newVal];
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
try {
|
||||
const eventTypeResponse = await axios.get('http://localhost:3000/api/event-types');
|
||||
this.eventTypes = eventTypeResponse.data;
|
||||
this.selectedEventType = this.eventTypes.find(type => type.id === this.event.eventTypeId) || null;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch event types:', error);
|
||||
}
|
||||
this.determineDateMode();
|
||||
},
|
||||
methods: {
|
||||
async saveEvent() {
|
||||
try {
|
||||
const payload = {
|
||||
...this.eventData,
|
||||
eventTypeId: this.selectedEventType ? this.selectedEventType.id : null,
|
||||
institution_id: this.selectedInstitution ? this.selectedInstitution.id : null,
|
||||
event_place_id: this.selectedEventPlace ? this.selectedEventPlace.id : null,
|
||||
contactPersonIds: this.selectedContactPersons.map(person => person.id)
|
||||
};
|
||||
payload.dayOfWeek = payload.dayOfWeek.value;
|
||||
let response;
|
||||
if (this.eventData.id) {
|
||||
response = await axios.put(`http://localhost:3000/api/events/${this.eventData.id}`, payload);
|
||||
} else {
|
||||
response = await axios.post('http://localhost:3000/api/events', payload);
|
||||
}
|
||||
this.$emit('saved', response.data);
|
||||
} catch (error) {
|
||||
console.error('Failed to save event:', error);
|
||||
}
|
||||
},
|
||||
determineDateMode() {
|
||||
if (this.eventData.date && this.eventData.dayOfWeek) {
|
||||
this.dateMode = 'interval';
|
||||
} else if (this.eventData.date) {
|
||||
this.dateMode = 'date';
|
||||
} else if (this.eventData.dayOfWeek) {
|
||||
this.dateMode = 'weekday';
|
||||
} else {
|
||||
this.dateMode = 'date';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@import 'vue-multiselect/dist/vue-multiselect.css';
|
||||
|
||||
.event-form {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
td {
|
||||
padding: 8px;
|
||||
vertical-align: top;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
}
|
||||
button {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.descriptionedit {
|
||||
width: 100%;
|
||||
height: 10em;
|
||||
}
|
||||
</style>
|
||||
@@ -1,58 +0,0 @@
|
||||
<template>
|
||||
<div class="hello">
|
||||
<h1>{{ msg }}</h1>
|
||||
<p>
|
||||
For a guide and recipes on how to configure / customize this project,<br>
|
||||
check out the
|
||||
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
|
||||
</p>
|
||||
<h3>Installed CLI Plugins</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
|
||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
|
||||
</ul>
|
||||
<h3>Essential Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
|
||||
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
|
||||
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
|
||||
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
|
||||
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
|
||||
</ul>
|
||||
<h3>Ecosystem</h3>
|
||||
<ul>
|
||||
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
|
||||
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
|
||||
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
|
||||
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
|
||||
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'HelloWorld',
|
||||
props: {
|
||||
msg: String
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
h3 {
|
||||
margin: 40px 0 0;
|
||||
}
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
li {
|
||||
display: inline-block;
|
||||
margin: 0 10px;
|
||||
}
|
||||
a {
|
||||
color: #42b983;
|
||||
}
|
||||
</style>
|
||||
124
src/components/InstitutionForm.vue
Normal file
124
src/components/InstitutionForm.vue
Normal file
@@ -0,0 +1,124 @@
|
||||
<template>
|
||||
<div class="institution-form">
|
||||
<h2>{{ institution && institution.id ? 'Institution bearbeiten' : 'Institution erstellen' }}</h2>
|
||||
<form @submit.prevent="saveInstitution">
|
||||
<label for="name">Name:</label>
|
||||
<input type="text" id="name" v-model="localInstitution.name" required>
|
||||
|
||||
<label for="street">Straße:</label>
|
||||
<input type="text" id="street" v-model="localInstitution.street">
|
||||
|
||||
<label for="zipcode">PLZ:</label>
|
||||
<input type="text" id="zipcode" v-model="localInstitution.zipcode">
|
||||
|
||||
<label for="city">Ort:</label>
|
||||
<input type="text" id="city" v-model="localInstitution.city">
|
||||
|
||||
<label for="phone">Telefon:</label>
|
||||
<input type="text" id="phone" v-model="localInstitution.phone">
|
||||
|
||||
<label for="fax">Fax:</label>
|
||||
<input type="text" id="fax" v-model="localInstitution.fax">
|
||||
|
||||
<label for="email">E-Mail:</label>
|
||||
<input type="email" id="email" v-model="localInstitution.email">
|
||||
|
||||
<label for="contactPersons">Kontaktpersonen:</label>
|
||||
<multiselect
|
||||
v-model="selectedContactPersons"
|
||||
:options="contactPersons"
|
||||
:multiple="true"
|
||||
placeholder="Kontaktpersonen auswählen"
|
||||
label="name"
|
||||
track-by="id"
|
||||
></multiselect>
|
||||
|
||||
<button type="submit">Speichern</button>
|
||||
<button type="button" @click="$emit('cancelled')">Abbrechen</button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Multiselect from 'vue-multiselect';
|
||||
import axios from 'axios';
|
||||
|
||||
export default {
|
||||
name: 'InstitutionForm',
|
||||
components: { Multiselect },
|
||||
props: {
|
||||
institution: {
|
||||
type: Object,
|
||||
default: () => null
|
||||
},
|
||||
contactPersons: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
localInstitution: {
|
||||
name: '',
|
||||
street: '',
|
||||
zipcode: '',
|
||||
city: '',
|
||||
phone: '',
|
||||
fax: '',
|
||||
email: '',
|
||||
contactPersons: []
|
||||
},
|
||||
selectedContactPersons: []
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
institution: {
|
||||
immediate: true,
|
||||
handler(newVal) {
|
||||
if (newVal) {
|
||||
this.localInstitution = { ...newVal };
|
||||
this.selectedContactPersons = newVal.contactPersons || [];
|
||||
}
|
||||
}
|
||||
},
|
||||
selectedContactPersons(newVal) {
|
||||
this.localInstitution.contactPersons = newVal;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async saveInstitution() {
|
||||
try {
|
||||
if (this.localInstitution.id) {
|
||||
await axios.put(`http://localhost:3000/api/institutions/${this.localInstitution.id}`, this.localInstitution);
|
||||
} else {
|
||||
await axios.post('http://localhost:3000/api/institutions', this.localInstitution);
|
||||
}
|
||||
this.$emit('saved');
|
||||
this.$emit('cancelled');
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Speichern der Institution:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@import '~vue-multiselect/dist/vue-multiselect.css';
|
||||
|
||||
.institution-form {
|
||||
max-width: 400px;
|
||||
margin: auto;
|
||||
}
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
label {
|
||||
margin-top: 10px;
|
||||
}
|
||||
button {
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
68
src/components/PositionSelect.vue
Normal file
68
src/components/PositionSelect.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div>
|
||||
<multiselect
|
||||
v-model="selectedPositions"
|
||||
:options="options"
|
||||
:multiple="true"
|
||||
:close-on-select="false"
|
||||
:clear-on-select="false"
|
||||
:preserve-search="true"
|
||||
placeholder="Positionen auswählen"
|
||||
label="caption"
|
||||
track-by="id"
|
||||
></multiselect>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Multiselect from 'vue-multiselect';
|
||||
import axios from 'axios';
|
||||
|
||||
export default {
|
||||
name: 'PositionSelect',
|
||||
components: { Multiselect },
|
||||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedPositions: this.value
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
value(newVal) {
|
||||
this.selectedPositions = newVal;
|
||||
console.log('PositionSelect - value watch - newVal:', newVal);
|
||||
},
|
||||
selectedPositions(newVal) {
|
||||
console.log('PositionSelect - selectedPositions watch - newVal:', newVal);
|
||||
this.$emit('input', newVal);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.fetchPositions();
|
||||
},
|
||||
methods: {
|
||||
async fetchPositions() {
|
||||
try {
|
||||
const response = await axios.get('http://localhost:3000/api/positions');
|
||||
console.log('PositionSelect - fetchPositions - response.data:', response.data);
|
||||
this.$emit('update:options', response.data);
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Abrufen der Positionen:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@import '~vue-multiselect/dist/vue-multiselect.css';
|
||||
</style>
|
||||
Reference in New Issue
Block a user