fix: stabilize constructeur selector ui
This commit is contained in:
@@ -81,7 +81,9 @@
|
||||
<label class="label"><span class="label-text font-medium">Constructeur</span></label>
|
||||
<ConstructeurSelect
|
||||
v-if="isEditMode"
|
||||
v-model="component.constructeurId"
|
||||
class="w-full"
|
||||
:model-value="component.constructeurId || component.constructeur?.id || null"
|
||||
@update:modelValue="handleConstructeurChange"
|
||||
/>
|
||||
<div v-else class="input input-bordered input-sm bg-base-200">
|
||||
<div class="flex flex-col">
|
||||
@@ -288,6 +290,11 @@ const documentsLoaded = ref(!!(props.component.documents && props.component.docu
|
||||
const componentDocuments = computed(() => props.component.documents || [])
|
||||
const documentIcon = (doc) => getFileIcon({ name: doc.filename || doc.name, mime: doc.mimeType })
|
||||
|
||||
const handleConstructeurChange = async (value) => {
|
||||
props.component.constructeurId = value
|
||||
await updateComponent()
|
||||
}
|
||||
|
||||
const { uploadDocuments, deleteDocument, loadDocumentsByComponent } = useDocuments()
|
||||
|
||||
watch(
|
||||
@@ -301,16 +308,6 @@ watch(
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.component.constructeurId,
|
||||
(newVal, oldVal) => {
|
||||
if (!props.isEditMode) return
|
||||
if (oldVal === undefined) return
|
||||
if (newVal !== oldVal) {
|
||||
updateComponent()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.component.documents,
|
||||
|
||||
@@ -20,17 +20,21 @@
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16l4-4 4 4m0-8l-4 4-4-4" />
|
||||
</svg>
|
||||
</button>
|
||||
<ul
|
||||
<div
|
||||
v-if="openDropdown"
|
||||
class="menu bg-base-100 border border-base-200 rounded-box shadow-lg mt-1 w-full max-h-48 overflow-y-auto absolute z-20"
|
||||
class="absolute z-20 mt-1 w-full max-h-48 overflow-y-auto bg-base-100 border border-base-200 rounded-box shadow-lg flex flex-col"
|
||||
>
|
||||
<li v-if="options.length === 0" class="px-3 py-2 text-xs text-gray-500">
|
||||
<div
|
||||
v-if="options.length === 0"
|
||||
class="px-3 py-2 text-xs text-gray-500"
|
||||
>
|
||||
Aucun constructeur trouvé
|
||||
</li>
|
||||
<li
|
||||
</div>
|
||||
<button
|
||||
v-for="option in options"
|
||||
:key="option.id"
|
||||
class="px-3 py-2"
|
||||
type="button"
|
||||
class="w-full text-left px-3 py-2 hover:bg-base-200 focus:bg-base-200 focus:outline-none"
|
||||
@click="selectOption(option)"
|
||||
>
|
||||
<div class="flex flex-col">
|
||||
@@ -39,8 +43,8 @@
|
||||
{{ [option.email, option.phone].filter(Boolean).join(' • ') || '—' }}
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-outline btn-sm" @click="openCreateModal = true">
|
||||
Nouveau
|
||||
@@ -111,6 +115,23 @@ const openCreateModal = ref(false)
|
||||
const creating = ref(false)
|
||||
const options = ref([])
|
||||
let searchTimeout = null
|
||||
let lastSearchTerm = ''
|
||||
|
||||
const applyOptions = (items = []) => {
|
||||
const selectedId = props.modelValue
|
||||
const cloned = [...items]
|
||||
const limited = cloned.slice(0, 10)
|
||||
|
||||
if (selectedId && !limited.some(item => item.id === selectedId)) {
|
||||
const selected = cloned.find(item => item.id === selectedId)
|
||||
if (selected) {
|
||||
if (limited.length >= 10) limited.pop()
|
||||
limited.unshift(selected)
|
||||
}
|
||||
}
|
||||
|
||||
options.value = limited
|
||||
}
|
||||
|
||||
const createForm = ref({
|
||||
name: '',
|
||||
@@ -140,10 +161,16 @@ watch(
|
||||
)
|
||||
|
||||
const ensureOptionsLoaded = async (force = false) => {
|
||||
if (!force && !searchTerm.value && constructeurs.value.length) {
|
||||
applyOptions(constructeurs.value)
|
||||
return
|
||||
}
|
||||
if (!force && searchTerm.value === lastSearchTerm && options.value.length) return
|
||||
if (options.value.length && !force) return
|
||||
const result = await searchConstructeurs(searchTerm.value)
|
||||
if (result.success) {
|
||||
options.value = result.data
|
||||
applyOptions(result.data || [])
|
||||
lastSearchTerm = searchTerm.value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,9 +178,16 @@ const onSearch = () => {
|
||||
openDropdown.value = true
|
||||
clearTimeout(searchTimeout)
|
||||
searchTimeout = setTimeout(async () => {
|
||||
if (!searchTerm.value && constructeurs.value.length) {
|
||||
applyOptions(constructeurs.value)
|
||||
lastSearchTerm = ''
|
||||
return
|
||||
}
|
||||
if (searchTerm.value === lastSearchTerm) return
|
||||
const result = await searchConstructeurs(searchTerm.value)
|
||||
if (result.success) {
|
||||
options.value = result.data
|
||||
applyOptions(result.data || [])
|
||||
lastSearchTerm = searchTerm.value
|
||||
}
|
||||
}, 250)
|
||||
}
|
||||
@@ -184,6 +218,17 @@ const handleCreate = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
constructeurs,
|
||||
(list) => {
|
||||
applyOptions(list || [])
|
||||
if (!searchTerm.value) {
|
||||
lastSearchTerm = ''
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
const clickHandler = (event) => {
|
||||
const element = event.target
|
||||
if (element && element.closest) {
|
||||
@@ -209,10 +254,3 @@ onBeforeUnmount(() => {
|
||||
clearTimeout(searchTimeout)
|
||||
})
|
||||
</script>
|
||||
watch(
|
||||
constructeurs,
|
||||
(list) => {
|
||||
options.value = [...list]
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
@@ -42,7 +42,9 @@
|
||||
</span>
|
||||
<ConstructeurSelect
|
||||
v-else
|
||||
v-model="piece.constructeurId"
|
||||
class="w-full"
|
||||
:model-value="piece.constructeurId || piece.constructeur?.id || null"
|
||||
@update:modelValue="handleConstructeurChange"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
@@ -260,6 +262,11 @@ const documentsLoaded = ref(!!(props.piece.documents && props.piece.documents.le
|
||||
const pieceDocuments = computed(() => props.piece.documents || [])
|
||||
const documentIcon = (doc) => getFileIcon({ name: doc.filename || doc.name, mime: doc.mimeType })
|
||||
|
||||
const handleConstructeurChange = (value) => {
|
||||
props.piece.constructeurId = value
|
||||
updatePiece()
|
||||
}
|
||||
|
||||
const { uploadDocuments, deleteDocument, loadDocumentsByPiece } = useDocuments()
|
||||
|
||||
const refreshDocuments = async () => {
|
||||
@@ -337,16 +344,6 @@ watch(
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.piece.constructeurId,
|
||||
(newVal, oldVal) => {
|
||||
if (!props.isEditMode) return
|
||||
if (oldVal === undefined) return
|
||||
if (newVal !== oldVal) {
|
||||
updatePiece()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// Méthodes pour gérer les champs personnalisés
|
||||
const setCustomFieldValue = (fieldValueId, value) => {
|
||||
|
||||
Reference in New Issue
Block a user