Files
analiticaNucleo/nuxt4-app/app/components/ingresos/FiltrosActivos.vue
josedario87 2b252d798b
Some checks failed
deploy-analiticaNucleo / deploy (push) Failing after 2s
preparando el deploy
2025-10-05 12:13:32 -06:00

317 lines
10 KiB
Vue

<template>
<UCard class="brand-card border border-transparent">
<template #header>
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<UIcon name="i-lucide-filter" class="size-4 text-[#c08040]" />
<h3 class="text-sm font-semibold text-[var(--brand-text)]">Filtros Activos</h3>
<span class="text-xs text-[var(--brand-text-muted)]">({{ totalFiltros }})</span>
</div>
<div class="flex items-center gap-2">
<UButton
size="xs"
variant="ghost"
color="neutral"
@click="showFiltros"
icon="i-lucide-plus"
>
Agregar filtros
</UButton>
<UButton
v-if="totalFiltros > 0"
size="xs"
variant="ghost"
color="neutral"
@click="resetearAHoy"
icon="i-lucide-rotate-ccw"
>
Resetear a Hoy
</UButton>
</div>
</div>
</template>
<div v-if="totalFiltros === 0" class="text-center py-4 text-sm text-[var(--brand-text-muted)]">
No hay filtros activos
</div>
<div v-else class="flex flex-wrap gap-2">
<!-- Clientes -->
<div
v-for="clienteId in selectedClienteIds"
:key="`cliente-${clienteId}`"
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium bg-blue-500/10 text-blue-400 border border-blue-500/30 transition-all hover:bg-blue-500/20"
>
<UIcon name="i-lucide-user" class="size-3" />
<span>{{ getNombreCliente(clienteId) }}</span>
<button
@click="removeCliente(clienteId)"
class="ml-1 hover:text-blue-300 transition-colors"
>
<UIcon name="i-lucide-x" class="size-3" />
</button>
</div>
<!-- Botón para agregar más clientes -->
<button
v-if="selectedClienteIds.length > 0"
@click="showClienteSelector"
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium bg-blue-500/5 text-blue-400 border border-blue-500/20 border-dashed transition-all hover:bg-blue-500/10 hover:border-blue-500/40"
title="Agregar más clientes"
>
<UIcon name="i-lucide-user-plus" class="size-3" />
<span>Agregar cliente</span>
</button>
<!-- Fechas -->
<div
v-if="fechaDesde || fechaHasta"
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium bg-purple-500/10 text-purple-400 border border-purple-500/30 transition-all hover:bg-purple-500/20"
>
<UIcon name="i-lucide-calendar" class="size-3" />
<span>{{ getPresetLabel() }}</span>
<button
@click="removeFechas"
class="ml-1 hover:text-purple-300 transition-colors"
>
<UIcon name="i-lucide-x" class="size-3" />
</button>
</div>
<!-- Tipos -->
<div
v-for="tipo in selectedTipos"
:key="`tipo-${tipo}`"
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium bg-orange-500/10 text-orange-400 border border-orange-500/30 transition-all hover:bg-orange-500/20"
>
<UIcon name="i-lucide-coffee" class="size-3" />
<span>{{ getLabelTipo(tipo) }}</span>
<button
@click="removeTipo(tipo)"
class="ml-1 hover:text-orange-300 transition-colors"
>
<UIcon name="i-lucide-x" class="size-3" />
</button>
</div>
<!-- Estados -->
<div
v-for="estado in selectedEstados"
:key="`estado-${estado}`"
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium bg-green-500/10 text-green-400 border border-green-500/30 transition-all hover:bg-green-500/20"
>
<UIcon name="i-lucide-check-circle" class="size-3" />
<span>{{ getLabelEstado(estado) }}</span>
<button
@click="removeEstado(estado)"
class="ml-1 hover:text-green-300 transition-colors"
>
<UIcon name="i-lucide-x" class="size-3" />
</button>
</div>
<!-- Ubicaciones -->
<div
v-for="ubicacion in selectedUbicaciones"
:key="`ubicacion-${ubicacion}`"
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium bg-cyan-500/10 text-cyan-400 border border-cyan-500/30 transition-all hover:bg-cyan-500/20"
>
<UIcon name="i-lucide-map-pin" class="size-3" />
<span>{{ ubicacion }}</span>
<button
@click="removeUbicacion(ubicacion)"
class="ml-1 hover:text-cyan-300 transition-colors"
>
<UIcon name="i-lucide-x" class="size-3" />
</button>
</div>
<!-- Calidades -->
<div
v-for="calidad in selectedCalidades"
:key="`calidad-${calidad}`"
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium bg-yellow-500/10 text-yellow-400 border border-yellow-500/30 transition-all hover:bg-yellow-500/20"
>
<UIcon name="i-lucide-star" class="size-3" />
<span>{{ calidad }}</span>
<button
@click="removeCalidad(calidad)"
class="ml-1 hover:text-yellow-300 transition-colors"
>
<UIcon name="i-lucide-x" class="size-3" />
</button>
</div>
<!-- Incluir Anulados -->
<div
v-if="includeAnulados"
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium bg-red-500/10 text-red-400 border border-red-500/30 transition-all hover:bg-red-500/20"
>
<UIcon name="i-lucide-alert-triangle" class="size-3" />
<span>Con anulados</span>
<button
@click="removeAnulados"
class="ml-1 hover:text-red-300 transition-colors"
>
<UIcon name="i-lucide-x" class="size-3" />
</button>
</div>
<!-- Sin Filtros -->
<div
v-if="noFilter"
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium bg-gray-500/10 text-gray-400 border border-gray-500/30 transition-all hover:bg-gray-500/20"
>
<UIcon name="i-lucide-ban" class="size-3" />
<span>Sin filtros</span>
<button
@click="removeNoFilter"
class="ml-1 hover:text-gray-300 transition-colors"
>
<UIcon name="i-lucide-x" class="size-3" />
</button>
</div>
</div>
</UCard>
</template>
<script setup lang="ts">
interface Props {
clientes: any[]
selectedClienteIds: number[]
selectedPreset: string
fechaDesde: string | null
fechaHasta: string | null
selectedTipos: string[]
selectedEstados: string[]
selectedUbicaciones: string[]
selectedCalidades: string[]
includeAnulados: boolean
noFilter: boolean
tiposOptions: any[]
estadosOptions: any[]
}
const props = defineProps<Props>()
const emit = defineEmits<{
'update:selectedClienteIds': [value: number[]]
'update:fechaDesde': [value: string | null]
'update:fechaHasta': [value: string | null]
'update:selectedPreset': [value: string]
'update:selectedTipos': [value: string[]]
'update:selectedEstados': [value: string[]]
'update:selectedUbicaciones': [value: string[]]
'update:selectedCalidades': [value: string[]]
'update:includeAnulados': [value: boolean]
'update:noFilter': [value: boolean]
'showClienteSelector': []
'showFiltros': []
}>()
const totalFiltros = computed(() => {
let count = 0
count += props.selectedClienteIds.length
count += (props.fechaDesde || props.fechaHasta) ? 1 : 0
count += props.selectedTipos.length
count += props.selectedEstados.length
count += props.selectedUbicaciones.length
count += props.selectedCalidades.length
count += props.includeAnulados ? 1 : 0
count += props.noFilter ? 1 : 0
return count
})
function showClienteSelector() {
emit('showClienteSelector')
}
function showFiltros() {
emit('showFiltros')
}
function getNombreCliente(id: number): string {
const cliente = props.clientes.find(c => c.id === id)
return cliente?.name || `Cliente ${id}`
}
function getLabelTipo(value: string): string {
const tipo = props.tiposOptions.find(t => t.value === value)
return tipo?.label || value
}
function getLabelEstado(value: string): string {
const estado = props.estadosOptions.find(e => e.value === value)
return estado?.label || value
}
function getPresetLabel(): string {
// Si es un preset conocido, mostrar su nombre
const presetLabels: Record<string, string> = {
'hoy': 'Hoy',
'semana': 'Esta Semana',
'mes': 'Este Mes',
'ytd': 'YTD',
'cosecha-20-21': 'Cosecha 20-21',
'cosecha-21-22': 'Cosecha 21-22',
'cosecha-22-23': 'Cosecha 22-23',
'cosecha-23-24': 'Cosecha 23-24',
'cosecha-24-25': 'Cosecha 24-25',
'cosecha-25-26': 'Cosecha 25-26'
}
const label = props.selectedPreset && props.selectedPreset !== 'custom' ? presetLabels[props.selectedPreset] : undefined
if (label) {
return label
}
// Si es personalizado, mostrar las fechas
return `${props.fechaDesde || '—'}${props.fechaHasta || '—'}`
}
function removeCliente(id: number) {
emit('update:selectedClienteIds', props.selectedClienteIds.filter(cid => cid !== id))
}
function removeFechas() {
emit('update:fechaDesde', null)
emit('update:fechaHasta', null)
emit('update:selectedPreset', '')
}
function removeTipo(tipo: string) {
emit('update:selectedTipos', props.selectedTipos.filter(t => t !== tipo))
}
function removeEstado(estado: string) {
emit('update:selectedEstados', props.selectedEstados.filter(e => e !== estado))
}
function removeUbicacion(ubicacion: string) {
emit('update:selectedUbicaciones', props.selectedUbicaciones.filter(u => u !== ubicacion))
}
function removeCalidad(calidad: string) {
emit('update:selectedCalidades', props.selectedCalidades.filter(c => c !== calidad))
}
function removeAnulados() {
emit('update:includeAnulados', false)
}
function removeNoFilter() {
emit('update:noFilter', false)
}
function resetearAHoy() {
emit('update:selectedClienteIds', [])
emit('update:selectedPreset', 'hoy')
emit('update:selectedTipos', [])
emit('update:selectedEstados', [])
emit('update:selectedUbicaciones', [])
emit('update:selectedCalidades', [])
emit('update:includeAnulados', false)
emit('update:noFilter', false)
}
</script>