211 lines
5.8 KiB
Vue
211 lines
5.8 KiB
Vue
|
<template>
|
||
|
<q-form @submit="save" @reset="reset">
|
||
|
<q-card-section class="fit row justify-start content-center items-center">
|
||
|
<q-input
|
||
|
v-model="userModel.firstname"
|
||
|
class="col-xs-12 col-sm-6 q-pa-sm"
|
||
|
label="Vorname"
|
||
|
:rules="[notEmpty]"
|
||
|
autocomplete="given-name"
|
||
|
filled
|
||
|
/>
|
||
|
<q-input
|
||
|
v-model="userModel.lastname"
|
||
|
class="col-xs-12 col-sm-6 q-pa-sm"
|
||
|
label="Nachname"
|
||
|
:rules="[notEmpty]"
|
||
|
autocomplete="family-name"
|
||
|
filled
|
||
|
/>
|
||
|
<q-input
|
||
|
v-model="userModel.display_name"
|
||
|
class="col-xs-12 col-sm-6 q-pa-sm"
|
||
|
label="Angezeigter Name"
|
||
|
:rules="[notEmpty]"
|
||
|
autocomplete="nickname"
|
||
|
filled
|
||
|
/>
|
||
|
<q-input
|
||
|
v-model="userModel.mail"
|
||
|
class="col-xs-12 col-sm-6 q-pa-sm"
|
||
|
label="E-Mail"
|
||
|
:rules="[isEmail, notEmpty]"
|
||
|
autocomplete="email"
|
||
|
filled
|
||
|
/>
|
||
|
<q-input
|
||
|
v-model="userModel.userid"
|
||
|
class="col-xs-12 col-sm-6 q-pa-sm"
|
||
|
label="Benutzername"
|
||
|
:readonly="!newUser"
|
||
|
:rules="newUser ? [isFreeUID, notEmpty] : []"
|
||
|
autocomplete="username"
|
||
|
filled
|
||
|
/>
|
||
|
<q-select
|
||
|
v-model="userModel.roles"
|
||
|
class="col-xs-12 col-sm-6 q-pa-sm"
|
||
|
label="Rollen"
|
||
|
filled
|
||
|
multiple
|
||
|
use-chips
|
||
|
:readonly="!canSetRoles"
|
||
|
:options="allRoles"
|
||
|
option-label="name"
|
||
|
option-value="name"
|
||
|
/>
|
||
|
<IsoDateInput
|
||
|
v-model="userModel.birthday"
|
||
|
class="col-xs-12 col-sm-6 q-pa-sm"
|
||
|
label="Geburtstag"
|
||
|
autocomplete="bday"
|
||
|
/>
|
||
|
<q-file
|
||
|
v-model="avatar"
|
||
|
class="col-xs-12 col-sm-6 q-pa-sm"
|
||
|
filled
|
||
|
label="Avatar"
|
||
|
accept=".jpg, image/*"
|
||
|
max-file-size="204800"
|
||
|
hint="Bilddateien, max. 200 KiB"
|
||
|
@rejected="onAvatarRejected"
|
||
|
>
|
||
|
<template #append>
|
||
|
<q-icon name="mdi-file-image" @click.stop />
|
||
|
</template>
|
||
|
</q-file>
|
||
|
</q-card-section>
|
||
|
<q-separator v-if="!newUser" />
|
||
|
<q-card-section v-if="!newUser" class="fit row justify-start content-center items-center">
|
||
|
<PasswordInput
|
||
|
v-if="isCurrentUser"
|
||
|
v-model="password"
|
||
|
:rules="[notEmpty]"
|
||
|
filled
|
||
|
label="Passwort"
|
||
|
autocomplete="current-password"
|
||
|
class="col-xs-12 col-sm-6 q-pa-sm"
|
||
|
hint="Passwort muss immer eingetragen werden"
|
||
|
/>
|
||
|
<PasswordInput
|
||
|
v-model="newPassword"
|
||
|
filled
|
||
|
label="Neues Password"
|
||
|
autocomplete="new-password"
|
||
|
class="col-xs-12 col-sm-6 q-pa-sm"
|
||
|
/>
|
||
|
</q-card-section>
|
||
|
<q-card-actions align="right">
|
||
|
<q-btn label="Reset" type="reset" />
|
||
|
<q-btn color="primary" type="submit" label="Speichern" />
|
||
|
</q-card-actions>
|
||
|
</q-form>
|
||
|
</template>
|
||
|
|
||
|
<script lang="ts">
|
||
|
import { Notify } from 'quasar';
|
||
|
import { IsoDateInput, PasswordInput } from '@flaschengeist/api/components';
|
||
|
import { defineComponent, computed, ref, onBeforeMount, PropType, watchEffect } from 'vue';
|
||
|
import { hasPermission, notEmpty, isEmail, useMainStore, useUserStore } from '@flaschengeist/api';
|
||
|
|
||
|
export default defineComponent({
|
||
|
name: 'MainUserSettings',
|
||
|
components: { IsoDateInput, PasswordInput },
|
||
|
props: {
|
||
|
user: {
|
||
|
required: true,
|
||
|
type: Object as PropType<FG.User>,
|
||
|
},
|
||
|
newUser: { type: Boolean, default: false },
|
||
|
},
|
||
|
emits: {
|
||
|
'update:user': (payload: FG.User) => !!payload,
|
||
|
},
|
||
|
setup(props, { emit }) {
|
||
|
const userStore = useUserStore();
|
||
|
const mainStore = useMainStore();
|
||
|
|
||
|
onBeforeMount(() => {
|
||
|
void userStore.getRoles(false);
|
||
|
});
|
||
|
|
||
|
const password = ref('');
|
||
|
const newPassword = ref('');
|
||
|
const avatar = ref<File | FileList | string[]>();
|
||
|
const userModel = ref(Object.assign({}, props.user));
|
||
|
|
||
|
const canSetRoles = computed(() => hasPermission('users_set_roles'));
|
||
|
const allRoles = computed(() => userStore.roles.map((role) => role.name));
|
||
|
const isCurrentUser = computed(() => userModel.value.userid === mainStore.currentUser.userid);
|
||
|
|
||
|
/* Reset model if props changed */
|
||
|
watchEffect(() => {if(props.user.userid && props.user.userid !== userModel.value.userid) reset()})
|
||
|
|
||
|
function onAvatarRejected() {
|
||
|
Notify.create({
|
||
|
group: false,
|
||
|
type: 'negative',
|
||
|
message: 'Datei zu groß oder keine gültige Bilddatei.',
|
||
|
timeout: 10000,
|
||
|
progress: true,
|
||
|
actions: [{ icon: 'mdi-close', color: 'white' }],
|
||
|
});
|
||
|
avatar.value = undefined;
|
||
|
}
|
||
|
|
||
|
function save() {
|
||
|
let changed = userModel.value;
|
||
|
if (typeof changed.birthday === 'string') changed.birthday = new Date(changed.birthday);
|
||
|
changed = Object.assign(changed, {
|
||
|
password: password.value,
|
||
|
});
|
||
|
if (newPassword.value != '') {
|
||
|
changed = Object.assign(changed, {
|
||
|
new_password: newPassword.value,
|
||
|
});
|
||
|
}
|
||
|
|
||
|
emit('update:user', changed);
|
||
|
|
||
|
if (avatar.value)
|
||
|
userStore
|
||
|
.uploadAvatar(changed, avatar.value instanceof File ? avatar.value : avatar.value[0])
|
||
|
.catch((response: Response) => {
|
||
|
if (response && response.status == 400) {
|
||
|
onAvatarRejected();
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function reset() {
|
||
|
userModel.value = Object.assign({}, props.user);
|
||
|
password.value = '';
|
||
|
newPassword.value = '';
|
||
|
}
|
||
|
|
||
|
function isFreeUID(val: string) {
|
||
|
return (
|
||
|
userStore.users.findIndex((user) => user.userid === val) === -1 ||
|
||
|
'Benutzername ist schon vergeben'
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
allRoles,
|
||
|
avatar,
|
||
|
canSetRoles,
|
||
|
isCurrentUser,
|
||
|
isEmail,
|
||
|
isFreeUID,
|
||
|
newPassword,
|
||
|
notEmpty,
|
||
|
onAvatarRejected,
|
||
|
password,
|
||
|
reset,
|
||
|
save,
|
||
|
userModel,
|
||
|
};
|
||
|
},
|
||
|
});
|
||
|
</script>
|