|
|
@@ -0,0 +1,142 @@
|
|
|
+<template>
|
|
|
+ <main>
|
|
|
+ <UiInputAutocomplete
|
|
|
+ :model-value="modelValue"
|
|
|
+ :field="field"
|
|
|
+ :label="label"
|
|
|
+ :items="items"
|
|
|
+ :isLoading="pending"
|
|
|
+ item-title="title"
|
|
|
+ item-value="id"
|
|
|
+ :multiple="multiple"
|
|
|
+ :chips="chips"
|
|
|
+ prependIcon="fas fa-magnifying-glass"
|
|
|
+ :return-object="false"
|
|
|
+ @update:model-value="onUpdateModelvalue"
|
|
|
+ @update:search="onUpdateSearch"
|
|
|
+ />
|
|
|
+ </main>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import {PropType} from "@vue/runtime-core";
|
|
|
+import {computed, ComputedRef, Ref} from "@vue/reactivity";
|
|
|
+import {AnyJson, AssociativeArray} from "~/types/data";
|
|
|
+import {useEntityFetch} from "~/composables/data/useEntityFetch";
|
|
|
+import Access from "~/models/Access/Access";
|
|
|
+
|
|
|
+const props = defineProps({
|
|
|
+ /**
|
|
|
+ * v-model
|
|
|
+ */
|
|
|
+ modelValue: {
|
|
|
+ type: [String, Number, Object, Array],
|
|
|
+ required: false,
|
|
|
+ default: null
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * Filtres à transmettre à la source de données
|
|
|
+ */
|
|
|
+ filters: {
|
|
|
+ type: Object as PropType<Ref<AssociativeArray>>,
|
|
|
+ required: false,
|
|
|
+ default: ref(null)
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * Nom de la propriété d'une entité lorsque l'input concerne cette propriété
|
|
|
+ * - Utilisé par la validation
|
|
|
+ * - Laisser null si le champ ne s'applique pas à une entité
|
|
|
+ */
|
|
|
+ field: {
|
|
|
+ type: String,
|
|
|
+ required: false,
|
|
|
+ default: null
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * Label du champ
|
|
|
+ * Si non défini, c'est le nom de propriété qui est utilisé
|
|
|
+ */
|
|
|
+ label: {
|
|
|
+ type: String,
|
|
|
+ required: false,
|
|
|
+ default: null
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * Définit si le champ est en lecture seule
|
|
|
+ * @see https://vuetifyjs.com/en/api/v-autocomplete/#props-readonly
|
|
|
+ */
|
|
|
+ readonly: {
|
|
|
+ type: Boolean,
|
|
|
+ required: false
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * Autorise la sélection multiple
|
|
|
+ * @see https://vuetifyjs.com/en/api/v-autocomplete/#props-multiple
|
|
|
+ */
|
|
|
+ multiple: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * Rends les résultats sous forme de puces
|
|
|
+ * @see https://vuetifyjs.com/en/api/v-autocomplete/#props-chips
|
|
|
+ */
|
|
|
+ chips: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+const { fetchCollection } = useEntityFetch()
|
|
|
+
|
|
|
+const i18n = useI18n()
|
|
|
+
|
|
|
+const nameFilter = ref(null)
|
|
|
+
|
|
|
+const query: ComputedRef<AnyJson> = computed(() => {
|
|
|
+
|
|
|
+ let q = props.filters.value ?? {}
|
|
|
+ if (nameFilter.value !== null) {
|
|
|
+ q['fullname'] = nameFilter.value
|
|
|
+ }
|
|
|
+
|
|
|
+ return { ...q, ...{ 'groups[]': 'access_people_ref' } }
|
|
|
+})
|
|
|
+
|
|
|
+const { data: collection, pending, refresh } = await fetchCollection(Access, null, query)
|
|
|
+
|
|
|
+const accessToItem = (access: Access): { id: number | string, title: string } => {
|
|
|
+ return {
|
|
|
+ id: access.id,
|
|
|
+ title: access.person ? `${access.person.givenName} ${access.person.name}` : i18n.t('unknown')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const items: ComputedRef<Array<{ id: number | string, title: string }>> = computed(() => {
|
|
|
+ if (!pending.value && collection.value && collection.value.items) {
|
|
|
+ // @ts-ignore
|
|
|
+ return collection.value.items.map(accessToItem)
|
|
|
+ }
|
|
|
+ return []
|
|
|
+})
|
|
|
+
|
|
|
+const emit = defineEmits(['update:model-value'])
|
|
|
+
|
|
|
+const onUpdateModelvalue = (event: Array<number>) => {
|
|
|
+ console.log(event)
|
|
|
+ emit('update:model-value', event)
|
|
|
+}
|
|
|
+
|
|
|
+const onUpdateSearch = (event: string) => {
|
|
|
+ if (event.length <= 2) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ refresh()
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+
|
|
|
+</style>
|