From 9bd96e6d69ed25a1d256ab9555c61cb6e7fe29eb Mon Sep 17 00:00:00 2001 From: josedario87 Date: Wed, 1 Oct 2025 03:51:18 -0600 Subject: [PATCH] ui?ux mejorada, comparativa cosecha-cosecha --- nuxt4-app/app/components/app/AppSidebar.vue | 6 + .../comparativa/CosechasEvolucion.vue | 319 ++++++++++++++++++ .../comparativa/CosechasPorTipo.vue | 296 ++++++++++++++++ .../comparativa/CosechasTotales.vue | 263 +++++++++++++++ nuxt4-app/app/composables/useInformeLayout.ts | 26 +- nuxt4-app/app/layouts/informe.vue | 218 +++++++++--- nuxt4-app/app/pages/comparativa-cosechas.vue | 176 ++++++++++ nuxt4-app/app/pages/informe-ingresos.vue | 109 +++++- 8 files changed, 1353 insertions(+), 60 deletions(-) create mode 100644 nuxt4-app/app/components/comparativa/CosechasEvolucion.vue create mode 100644 nuxt4-app/app/components/comparativa/CosechasPorTipo.vue create mode 100644 nuxt4-app/app/components/comparativa/CosechasTotales.vue create mode 100644 nuxt4-app/app/pages/comparativa-cosechas.vue diff --git a/nuxt4-app/app/components/app/AppSidebar.vue b/nuxt4-app/app/components/app/AppSidebar.vue index 3e9e58f..7409786 100644 --- a/nuxt4-app/app/components/app/AppSidebar.vue +++ b/nuxt4-app/app/components/app/AppSidebar.vue @@ -101,6 +101,12 @@ const navigationPrimary = computed(() => [ to: '/informe-ingresos', active: route.path === '/informe-ingresos' }, + { + label: 'Comparativa Cosechas', + icon: 'i-lucide-calendar-range', + to: '/comparativa-cosechas', + active: route.path === '/comparativa-cosechas' + }, { label: 'Explorador de datos', icon: 'i-lucide-table', diff --git a/nuxt4-app/app/components/comparativa/CosechasEvolucion.vue b/nuxt4-app/app/components/comparativa/CosechasEvolucion.vue new file mode 100644 index 0000000..8521981 --- /dev/null +++ b/nuxt4-app/app/components/comparativa/CosechasEvolucion.vue @@ -0,0 +1,319 @@ + + + diff --git a/nuxt4-app/app/components/comparativa/CosechasPorTipo.vue b/nuxt4-app/app/components/comparativa/CosechasPorTipo.vue new file mode 100644 index 0000000..d6c8540 --- /dev/null +++ b/nuxt4-app/app/components/comparativa/CosechasPorTipo.vue @@ -0,0 +1,296 @@ + + + diff --git a/nuxt4-app/app/components/comparativa/CosechasTotales.vue b/nuxt4-app/app/components/comparativa/CosechasTotales.vue new file mode 100644 index 0000000..73c12b1 --- /dev/null +++ b/nuxt4-app/app/components/comparativa/CosechasTotales.vue @@ -0,0 +1,263 @@ + + + diff --git a/nuxt4-app/app/composables/useInformeLayout.ts b/nuxt4-app/app/composables/useInformeLayout.ts index 5d2aecb..2d537e8 100644 --- a/nuxt4-app/app/composables/useInformeLayout.ts +++ b/nuxt4-app/app/composables/useInformeLayout.ts @@ -17,13 +17,23 @@ export interface ActiveFilter { onRemove: () => void } +export interface PageSections { + totalesCafe: boolean + totalesVerde: boolean + tablaIngresos: boolean + top10Clientes: boolean + graficas: boolean +} + export function useInformeLayout() { const setFiltrosResumenFn = inject<(resumen: FiltrosResumen | null) => void>('setFiltrosResumen') const setDatasourceCountsFn = inject<(counts: DatasourceCounts) => void>('setDatasourceCounts') const setFilteredResultsFn = inject<(results: DatasourceCounts) => void>('setFilteredResults') const setActiveFiltersFn = inject<(filters: ActiveFilter[]) => void>('setActiveFilters') + const setMetadatosNeedUpdateFn = inject<(needsUpdate: boolean) => void>('setMetadatosNeedUpdate') const filtrosCollapsedRef = inject>('filtrosCollapsed') const metadatosCollapsedRef = inject>('metadatosCollapsed') + const pageSectionsRef = inject>('pageSections') function setFiltrosResumen(count: number, summary: string, results: number) { if (setFiltrosResumenFn) { @@ -55,13 +65,27 @@ export function useInformeLayout() { } } + function setMetadatosNeedUpdate(needsUpdate: boolean) { + if (setMetadatosNeedUpdateFn) { + setMetadatosNeedUpdateFn(needsUpdate) + } + } + return { setFiltrosResumen, clearFiltrosResumen, setDatasourceCounts, setFilteredResults, setActiveFilters, + setMetadatosNeedUpdate, filtrosCollapsed: filtrosCollapsedRef || ref(false), - metadatosCollapsed: metadatosCollapsedRef || ref(false) + metadatosCollapsed: metadatosCollapsedRef || ref(false), + pageSections: pageSectionsRef || ref({ + totalesCafe: true, + totalesVerde: true, + tablaIngresos: true, + top10Clientes: true, + graficas: true + }) } } diff --git a/nuxt4-app/app/layouts/informe.vue b/nuxt4-app/app/layouts/informe.vue index 5a15b6d..4c0d998 100644 --- a/nuxt4-app/app/layouts/informe.vue +++ b/nuxt4-app/app/layouts/informe.vue @@ -5,7 +5,7 @@ @@ -328,8 +382,19 @@ definePageMeta({ title: 'Informe Ingresos' }) -// Obtener estado colapsado desde el layout -const { filtrosCollapsed, metadatosCollapsed, setFiltrosResumen, setDatasourceCounts, setFilteredResults, setActiveFilters } = useInformeLayout() +// Obtener estado colapsado y visibilidad de secciones desde el layout +const { filtrosCollapsed, metadatosCollapsed, pageSections, setFiltrosResumen, setDatasourceCounts, setFilteredResults, setActiveFilters, setMetadatosNeedUpdate } = useInformeLayout() + +// Computed properties invertidos para switches (ON = visible, OFF = oculto) +const showFiltros = computed({ + get: () => !filtrosCollapsed.value, + set: (value) => { filtrosCollapsed.value = !value } +}) + +const showMetadatos = computed({ + get: () => !metadatosCollapsed.value, + set: (value) => { metadatosCollapsed.value = !value } +}) // View modes with explicit hierarchy type ViewMode = 'ingresos-only' | 'clientes-only' | 'ingresos-clientes' | 'clientes-ingresos' @@ -750,6 +815,30 @@ const clientesMetadata = computed(() => { return meta ? { ...meta, name: 'clientes' } : null }) +// Detectar si los metadatos necesitan actualización +const metadatosNeedUpdate = computed(() => { + // Comparar count de ingresos + if (ingresosMetadata.value && ingresosMetadata.value.count) { + if (ingresos.value.length !== ingresosMetadata.value.count) { + return true + } + } + + // Comparar count de clientes + if (clientesMetadata.value && clientesMetadata.value.count) { + if (clientes.value.length !== clientesMetadata.value.count) { + return true + } + } + + return false +}) + +// Actualizar el estado de warning en el layout +watch(metadatosNeedUpdate, (needsUpdate) => { + setMetadatosNeedUpdate(needsUpdate) +}, { immediate: true }) + // Load data on mount onMounted(async () => { try {