Feat: agregar indicador visual de cambios pendientes en filtros
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 45s
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 45s
Implementación de sistema de tracking para detectar cuando los filtros han cambiado pero no se han aplicado a los datos mostrados. Indicadores visuales implementados: - Alerta amarilla prominente con animación pulse y ping - Borde y sombra amarilla en el card de filtros - Botón 'Actualizar' cambia a amarillo con emoji de advertencia - Botón rápido 'Actualizar ahora' dentro de la alerta - Animaciones llamativas para captar la atención El sistema compara los filtros actuales con los últimos aplicados y muestra indicadores visuales evidentes cuando hay diferencias.
This commit is contained in:
@@ -99,7 +99,14 @@
|
||||
<!-- Main Content -->
|
||||
<template v-else-if="data">
|
||||
<!-- Card de Filtros -->
|
||||
<UCard class="brand-card border border-transparent">
|
||||
<UCard
|
||||
:class="[
|
||||
'brand-card border transition-all duration-300',
|
||||
hasPendingChanges
|
||||
? 'border-yellow-500 shadow-lg shadow-yellow-500/50 ring-2 ring-yellow-400/50'
|
||||
: 'border-transparent'
|
||||
]"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
@@ -114,6 +121,40 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alerta de cambios pendientes -->
|
||||
<UAlert
|
||||
v-if="hasPendingChanges"
|
||||
color="warning"
|
||||
variant="solid"
|
||||
icon="i-lucide-alert-circle"
|
||||
class="animate-pulse"
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-bold">¡Cambios pendientes!</span>
|
||||
<span class="inline-flex h-2 w-2 rounded-full bg-yellow-400 animate-ping"></span>
|
||||
</div>
|
||||
</template>
|
||||
<template #description>
|
||||
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3">
|
||||
<span>Los filtros han cambiado pero no se han aplicado a los datos mostrados. Haz clic en "Actualizar" para aplicar los cambios.</span>
|
||||
<UButton
|
||||
:loading="loading"
|
||||
:disabled="loading"
|
||||
color="yellow"
|
||||
variant="solid"
|
||||
size="xs"
|
||||
@click="loadData"
|
||||
>
|
||||
<template #leading>
|
||||
<UIcon name="i-lucide-refresh-cw" :class="{ 'animate-spin': loading }" />
|
||||
</template>
|
||||
Actualizar ahora
|
||||
</UButton>
|
||||
</div>
|
||||
</template>
|
||||
</UAlert>
|
||||
|
||||
<!-- Alerta roja cuando incluye anulados -->
|
||||
<UAlert
|
||||
v-if="includeAnulados"
|
||||
@@ -143,14 +184,18 @@
|
||||
<UButton
|
||||
:loading="loading"
|
||||
:disabled="loading"
|
||||
:ui="{ base: 'bg-[#c08040] text-[#1b1209] border border-[#d99a56] hover:bg-[#d99a56] hover:border-[#f0c07c] disabled:opacity-50 disabled:cursor-not-allowed' }"
|
||||
:ui="{
|
||||
base: hasPendingChanges
|
||||
? 'bg-yellow-500 text-black border border-yellow-600 hover:bg-yellow-400 hover:border-yellow-500 disabled:opacity-50 disabled:cursor-not-allowed animate-pulse'
|
||||
: 'bg-[#c08040] text-[#1b1209] border border-[#d99a56] hover:bg-[#d99a56] hover:border-[#f0c07c] disabled:opacity-50 disabled:cursor-not-allowed'
|
||||
}"
|
||||
size="sm"
|
||||
@click="loadData"
|
||||
>
|
||||
<template #leading>
|
||||
<UIcon name="i-lucide-refresh-cw" :class="{ 'animate-spin': loading }" />
|
||||
</template>
|
||||
Actualizar
|
||||
{{ hasPendingChanges ? 'Actualizar ⚠️' : 'Actualizar' }}
|
||||
</UButton>
|
||||
</div>
|
||||
</template>
|
||||
@@ -230,6 +275,13 @@ const selectedPreset = ref<PresetValue>('cosecha-25-26')
|
||||
const fechaDesde = ref<string | null>(null)
|
||||
const fechaHasta = ref<string | null>(null)
|
||||
|
||||
// Filtros aplicados (los que se usaron en la última carga de datos)
|
||||
const appliedFilters = ref<{
|
||||
fechaDesde: string | null
|
||||
fechaHasta: string | null
|
||||
includeAnulados: boolean
|
||||
} | null>(null)
|
||||
|
||||
// Computed
|
||||
const rangoLegible = computed(() => {
|
||||
if (!fechaDesde.value && !fechaHasta.value) return 'Sin filtro de fecha'
|
||||
@@ -238,6 +290,19 @@ const rangoLegible = computed(() => {
|
||||
return `${f} → ${t}`
|
||||
})
|
||||
|
||||
// Detectar si hay cambios pendientes sin aplicar
|
||||
const hasPendingChanges = computed(() => {
|
||||
// Si no hay datos cargados, no hay cambios pendientes
|
||||
if (!appliedFilters.value) return false
|
||||
|
||||
// Comparar filtros actuales con los aplicados
|
||||
return (
|
||||
fechaDesde.value !== appliedFilters.value.fechaDesde ||
|
||||
fechaHasta.value !== appliedFilters.value.fechaHasta ||
|
||||
includeAnulados.value !== appliedFilters.value.includeAnulados
|
||||
)
|
||||
})
|
||||
|
||||
// Format currency helper
|
||||
const formatCurrency = (value: number) => {
|
||||
if (!value) return 'L 0.00'
|
||||
@@ -278,6 +343,13 @@ async function loadData() {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
})
|
||||
|
||||
// Guardar los filtros aplicados
|
||||
appliedFilters.value = {
|
||||
fechaDesde: fechaDesde.value,
|
||||
fechaHasta: fechaHasta.value,
|
||||
includeAnulados: includeAnulados.value
|
||||
}
|
||||
} catch (err: any) {
|
||||
error.value = err.message || 'Error al cargar datos'
|
||||
console.error('Error loading panorama data:', err)
|
||||
|
||||
Reference in New Issue
Block a user