Fix: Corregir implementación de InputMenu según documentación oficial
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 52s
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 52s
Correcciones aplicadas: - Usar ignore-filter para control manual del filtrado - Implementar label-key y value-key correctamente - Usar slot #item-label en lugar de #item para personalización - Usar slot #empty para mensajes cuando no hay resultados - Mapear items a formato InputMenuItem con label y value - Usar clases de Nuxt UI (text-muted) en lugar de variables CSS - Simplificar lógica eliminando control manual del estado open Funcionalidad: - Filtrado solo se activa con mínimo 4 caracteres - Búsqueda por nombre y cédula - Selección múltiple con tags visuales - Formato de cédula mantenido
This commit is contained in:
@@ -4,29 +4,39 @@
|
|||||||
<UInputMenu
|
<UInputMenu
|
||||||
v-model="selectedClientes"
|
v-model="selectedClientes"
|
||||||
v-model:search-term="searchQuery"
|
v-model:search-term="searchQuery"
|
||||||
v-model:open="isMenuOpen"
|
|
||||||
:items="filteredItems"
|
:items="filteredItems"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
multiple
|
multiple
|
||||||
icon="i-lucide-search"
|
label-key="name"
|
||||||
placeholder="Buscar clientes por nombre o cédula (mínimo 4 caracteres)..."
|
|
||||||
value-key="id"
|
value-key="id"
|
||||||
|
icon="i-lucide-search"
|
||||||
|
placeholder="Buscar clientes por nombre o cédula..."
|
||||||
|
ignore-filter
|
||||||
>
|
>
|
||||||
<template #item="{ item }">
|
<template #item-label="{ item }">
|
||||||
<div class="flex-1 min-w-0">
|
<div class="flex flex-col gap-0.5">
|
||||||
<div class="font-medium truncate">
|
<span class="font-medium">{{ item.name }}</span>
|
||||||
{{ item.name }}
|
<span v-if="item.cedula" class="text-xs text-muted">
|
||||||
</div>
|
{{ formatCedula(item.cedula) }}
|
||||||
<div class="text-xs text-[var(--brand-text-muted)]">
|
</span>
|
||||||
<span v-if="item.cedula">{{ formatCedula(item.cedula) }}</span>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
|
|
||||||
|
<template #empty>
|
||||||
|
<div class="text-center py-2">
|
||||||
|
<span v-if="searchQuery.length < 4" class="text-muted text-sm">
|
||||||
|
Escribe al menos 4 caracteres para buscar
|
||||||
|
</span>
|
||||||
|
<span v-else class="text-muted text-sm">
|
||||||
|
No se encontraron clientes
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</UInputMenu>
|
</UInputMenu>
|
||||||
|
|
||||||
<!-- Selected count and clear all -->
|
<!-- Selected count and clear all -->
|
||||||
<div v-if="selectedClientes.length > 0" class="flex items-center justify-between text-sm">
|
<div v-if="selectedClientes.length > 0" class="flex items-center justify-between text-sm">
|
||||||
<span class="text-[var(--brand-text-muted)]">
|
<span class="text-muted">
|
||||||
{{ selectedClientes.length }} cliente{{ selectedClientes.length !== 1 ? 's' : '' }} seleccionado{{ selectedClientes.length !== 1 ? 's' : '' }}
|
{{ selectedClientes.length }} cliente{{ selectedClientes.length !== 1 ? 's' : '' }} seleccionado{{ selectedClientes.length !== 1 ? 's' : '' }}
|
||||||
</span>
|
</span>
|
||||||
<UButton
|
<UButton
|
||||||
@@ -42,6 +52,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import type { InputMenuItem } from '@nuxt/ui'
|
||||||
|
|
||||||
interface Cliente {
|
interface Cliente {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
@@ -61,7 +73,6 @@ const emit = defineEmits<{
|
|||||||
const clientes = ref<Cliente[]>([])
|
const clientes = ref<Cliente[]>([])
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const searchQuery = ref('')
|
const searchQuery = ref('')
|
||||||
const isMenuOpen = ref(false)
|
|
||||||
|
|
||||||
// Computed - Sync with props
|
// Computed - Sync with props
|
||||||
const selectedClientes = computed({
|
const selectedClientes = computed({
|
||||||
@@ -74,7 +85,7 @@ const selectedClientes = computed({
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Computed - Filter items based on search (min 4 characters)
|
// Computed - Filter items based on search (min 4 characters)
|
||||||
const filteredItems = computed(() => {
|
const filteredItems = computed((): InputMenuItem[] => {
|
||||||
const query = searchQuery.value.trim()
|
const query = searchQuery.value.trim()
|
||||||
|
|
||||||
// Only show items if search has at least 4 characters
|
// Only show items if search has at least 4 characters
|
||||||
@@ -84,19 +95,18 @@ const filteredItems = computed(() => {
|
|||||||
|
|
||||||
const lowerQuery = query.toLowerCase()
|
const lowerQuery = query.toLowerCase()
|
||||||
|
|
||||||
return clientes.value.filter(c =>
|
return clientes.value
|
||||||
c.name.toLowerCase().includes(lowerQuery) ||
|
.filter(c =>
|
||||||
c.cedula?.includes(query)
|
c.name.toLowerCase().includes(lowerQuery) ||
|
||||||
)
|
c.cedula?.includes(query)
|
||||||
})
|
)
|
||||||
|
.map(c => ({
|
||||||
// Watch searchQuery to control menu opening
|
id: c.id,
|
||||||
watch(searchQuery, (newValue) => {
|
name: c.name,
|
||||||
if (newValue.trim().length >= 4 && filteredItems.value.length > 0) {
|
cedula: c.cedula,
|
||||||
isMenuOpen.value = true
|
label: c.name,
|
||||||
} else {
|
value: c.id
|
||||||
isMenuOpen.value = false
|
}))
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
|
|||||||
Reference in New Issue
Block a user