Files
yourpart3/frontend/src/components/form/MultiselectWidget.vue
Torsten Schulz (local) d6bfe50b4e Änderung: Erweiterung der Benutzerkontoeinstellungen und Verbesserung der E-Mail-Verschlüsselung
Änderungen:
- Implementierung von neuen Methoden `getAccountSettings` und `setAccountSettings` im `SettingsService`, um Benutzerkontoeinstellungen zu verwalten.
- Anpassung der E-Mail-Verschlüsselung im `User`-Modell zur Verwendung von Buffer für die Speicherung und zur Verbesserung der Fehlerbehandlung bei der Entschlüsselung.
- Hinzufügung eines neuen `immutable`-Feldes im `UserParamType`-Modell, um unveränderliche Einstellungen zu kennzeichnen.
- Anpassungen in den Frontend-Komponenten zur Berücksichtigung von unveränderlichen Feldern und zur Verbesserung der Benutzeroberfläche.

Diese Anpassungen verbessern die Sicherheit der Benutzerdaten und erweitern die Funktionalität der Kontoeinstellungen.
2025-09-15 11:48:00 +02:00

146 lines
4.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<label>
<span :style="{ width: width + 'em' }">{{ $t(labelTr) }}</span>
<Multiselect
v-model="selectedOptions"
:options="validList"
:multiple="true"
:close-on-select="false"
:clear-on-select="false"
:preserve-search="true"
:placeholder="$t('select_option')"
:track-by="'value'"
:disabled="disabled"
>
<template #option="{ option }">
<span v-if="option && option.value">{{ getTranslation(option) }}</span>
</template>
<template #tag="{ option, remove }">
<span v-if="option && option.captionTr" class="multiselect__tag">
{{ $t(option.captionTr) }}
<span @click="remove(option)">×</span>
</span>
<span v-else>@e</span>
</template>
</Multiselect>
</label>
</template>
<script>
import Multiselect from 'vue-multiselect';
import 'vue-multiselect/dist/vue-multiselect.min.css';
export default {
name: "MultiselectWidget",
components: { Multiselect },
props: {
labelTr: { type: String, required: true },
value: { type: String, required: false, default: '[]' },
tooltipTr: { type: String, required: true },
width: { type: Number, required: false, default: 10 },
list: {
type: Array,
required: true,
default: () => [] // Standardwert hinzufügen, um undefined zu vermeiden
},
disabled: {
type: Boolean,
required: false,
default: false
},
},
data() {
return {
internalValues: this.stringToArray(this.value), // Speichert nur die IDs (Werte)
selectedOptions: this.getOptionsFromIds(this.stringToArray(this.value)) // Hilfsvariable, speichert die vollständigen Objekte
};
},
computed: {
validList() {
return this.validatedList(); // Immer ein Array zurückgeben
}
},
watch: {
value(newValue) {
const ids = this.stringToArray(newValue);
this.internalValues = ids; // Nur die IDs speichern
this.selectedOptions = this.getOptionsFromIds(ids); // Optionen basierend auf IDs setzen
},
selectedOptions(newOptions) {
this.internalValues = newOptions.map(option => option.value); // Nur die IDs extrahieren
this.updateValue();
}
},
methods: {
stringToArray(str) {
try {
const array = JSON.parse(str);
return array.filter(item => item !== null && item !== undefined);
} catch (error) {
console.error('Invalid JSON string in value:', str);
return [];
}
},
updateValue() {
const stringValue = JSON.stringify(this.internalValues); // In JSON-String umwandeln
this.$emit("input", stringValue); // String an das Parent-Element übermitteln
},
getTranslation(option) {
return option.captionTr ? this.$t(option.captionTr) : option.caption;
},
findOption(optionId) {
return this.validatedList().find(opt => opt.value === optionId);
},
getOptionsFromIds(ids) {
return ids.map(id => this.findOption(id)).filter(option => option); // Vollständige Objekte basierend auf IDs abrufen
},
validatedList() {
// Überprüfen, ob die Liste valide ist
if (!this.list || !Array.isArray(this.list)) {
return [];
}
return this.list.filter(option => option && option.value !== null && option.value !== undefined && (option.captionTr || option.caption));
}
}
};
</script>
<style scoped>
label {
display: block;
margin-bottom: 1em;
}
label>span {
display: inline-block;
margin-bottom: 0.5em;
}
.multiselect {
margin-left: 0.5em;
}
.custom-tag {
background-color: #f0f0f0;
border: 1px solid #ccc;
padding: 5px;
border-radius: 4px;
margin-right: 5px;
display: inline-block;
}
.custom-tag span {
margin-left: 8px;
cursor: pointer;
}
.multiselect {
display: inline-block;
width: 7em;
}
.multiselect__tags {
white-space: nowrap;
}
</style>