162 lines
6.5 KiB
Vue
162 lines
6.5 KiB
Vue
<template>
|
|
<div class="flex flex-col">
|
|
<!-- Toolbar con selector de cosechas -->
|
|
<UDashboardToolbar>
|
|
<template #left>
|
|
<div class="flex items-center gap-4">
|
|
<span class="text-sm text-[var(--brand-text-muted)]">Seleccionar cosechas a comparar:</span>
|
|
</div>
|
|
</template>
|
|
|
|
<template #right>
|
|
<div class="flex items-center gap-3">
|
|
<USwitch
|
|
v-model="pageSections.heatmap"
|
|
size="xs"
|
|
label="Heatmap"
|
|
/>
|
|
<USwitch
|
|
v-model="pageSections.totales"
|
|
size="xs"
|
|
label="Totales"
|
|
/>
|
|
<USwitch
|
|
v-model="pageSections.evolucion"
|
|
size="xs"
|
|
label="Evolución"
|
|
/>
|
|
<USwitch
|
|
v-model="pageSections.porTipo"
|
|
size="xs"
|
|
label="Por Tipo"
|
|
/>
|
|
</div>
|
|
</template>
|
|
</UDashboardToolbar>
|
|
|
|
<div class="flex flex-col gap-8 p-6">
|
|
<!-- Loading State -->
|
|
<UCard v-if="loading && !ingresosStore.hasData" class="brand-card border border-transparent">
|
|
<div class="flex flex-col items-center justify-center gap-4 py-10 text-[var(--brand-text-muted)]">
|
|
<div class="flex items-center gap-3">
|
|
<span class="inline-flex h-8 w-8 animate-spin rounded-full border-2 border-[#c08040] border-t-transparent align-middle" aria-hidden="true" />
|
|
<span class="text-sm uppercase tracking-[0.3em]">Cargando datos...</span>
|
|
</div>
|
|
</div>
|
|
</UCard>
|
|
|
|
<!-- Error State -->
|
|
<div v-else-if="error" class="rounded-lg border border-red-500/40 bg-red-500/18 p-4 text-sm text-red-200">
|
|
<p>Error al cargar datos: {{ error }}</p>
|
|
</div>
|
|
|
|
<!-- Main Content -->
|
|
<template v-else>
|
|
<!-- Selector de Cosechas -->
|
|
<UCard class="brand-card border border-transparent">
|
|
<template #header>
|
|
<div class="flex items-center gap-2">
|
|
<UIcon name="i-lucide-calendar-range" class="size-5 text-[#c08040]" />
|
|
<h3 class="text-base font-semibold text-[var(--brand-text)]">Cosechas a Comparar</h3>
|
|
</div>
|
|
</template>
|
|
|
|
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-3">
|
|
<label
|
|
v-for="cosecha in cosechasDisponibles"
|
|
:key="cosecha.id"
|
|
class="flex items-center gap-2 p-3 rounded-lg border cursor-pointer transition-all"
|
|
:class="cosechasSeleccionadas.includes(cosecha.id)
|
|
? 'border-[#c08040] bg-[#c08040]/10'
|
|
: 'border-[var(--brand-border)] hover:border-[#c08040]/50'"
|
|
>
|
|
<input
|
|
type="checkbox"
|
|
:value="cosecha.id"
|
|
v-model="cosechasSeleccionadas"
|
|
class="rounded border-[var(--brand-border)] text-[#c08040] focus:ring-[#c08040]"
|
|
/>
|
|
<div class="flex flex-col">
|
|
<span class="text-sm font-medium text-[var(--brand-text)]">{{ cosecha.label }}</span>
|
|
<span class="text-xs text-[var(--brand-text-muted)]">{{ cosecha.periodo }}</span>
|
|
</div>
|
|
</label>
|
|
</div>
|
|
</UCard>
|
|
|
|
<!-- Vista Heatmap -->
|
|
<div v-if="cosechasSeleccionadas.length > 0 && pageSections.heatmap">
|
|
<ComparativaCosechasHeatmap :ingresos="ingresos" :cosechas-seleccionadas="cosechasSeleccionadas" />
|
|
</div>
|
|
|
|
<!-- Resumen General por Cosecha -->
|
|
<div v-if="cosechasSeleccionadas.length > 0 && pageSections.totales">
|
|
<ComparativaCosechasTotales :ingresos="ingresos" :cosechas-seleccionadas="cosechasSeleccionadas" />
|
|
</div>
|
|
|
|
<!-- Comparativa por Tipo de Café -->
|
|
<div v-if="cosechasSeleccionadas.length > 0 && pageSections.porTipo">
|
|
<ComparativaCosechasPorTipo :ingresos="ingresos" :cosechas-seleccionadas="cosechasSeleccionadas" />
|
|
</div>
|
|
|
|
<!-- Evolución Temporal Comparada -->
|
|
<div v-if="cosechasSeleccionadas.length > 0 && pageSections.evolucion">
|
|
<ComparativaCosechasEvolucion :ingresos="ingresos" :cosechas-seleccionadas="cosechasSeleccionadas" />
|
|
</div>
|
|
|
|
<!-- Empty State -->
|
|
<UCard v-if="cosechasSeleccionadas.length === 0" class="brand-card border border-transparent">
|
|
<div class="flex flex-col items-center justify-center gap-4 py-16 text-[var(--brand-text-muted)]">
|
|
<UIcon name="i-lucide-bar-chart-2" class="size-16 opacity-50" />
|
|
<p class="text-sm">Selecciona al menos una cosecha para ver las comparativas</p>
|
|
</div>
|
|
</UCard>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useTableDataStore } from '~/stores/tableDataFactory'
|
|
import type { IngresoRecord } from '~/composables/useIngresosMetrics'
|
|
|
|
definePageMeta({
|
|
layout: 'informe',
|
|
title: 'Comparativa Cosechas'
|
|
})
|
|
|
|
// Definir secciones específicas de esta página
|
|
const pageSections = ref({
|
|
heatmap: true,
|
|
totales: false,
|
|
evolucion: false,
|
|
porTipo: false
|
|
})
|
|
|
|
// Definición de cosechas disponibles
|
|
const cosechasDisponibles = [
|
|
{ id: 'cosecha-20-21', label: 'Cosecha 20-21', periodo: 'Sep 2020 - Sep 2021', fechaInicio: '2020-09-25', fechaFin: '2021-09-24' },
|
|
{ id: 'cosecha-21-22', label: 'Cosecha 21-22', periodo: 'Sep 2021 - Sep 2022', fechaInicio: '2021-09-25', fechaFin: '2022-09-24' },
|
|
{ id: 'cosecha-22-23', label: 'Cosecha 22-23', periodo: 'Sep 2022 - Sep 2023', fechaInicio: '2022-09-25', fechaFin: '2023-09-24' },
|
|
{ id: 'cosecha-23-24', label: 'Cosecha 23-24', periodo: 'Sep 2023 - Sep 2024', fechaInicio: '2023-09-25', fechaFin: '2024-09-24' },
|
|
{ id: 'cosecha-24-25', label: 'Cosecha 24-25', periodo: 'Sep 2024 - Sep 2025', fechaInicio: '2024-09-25', fechaFin: '2025-09-09' },
|
|
{ id: 'cosecha-25-26', label: 'Cosecha 25-26', periodo: 'Sep 2025 - Hoy', fechaInicio: '2025-09-10', fechaFin: new Date().toISOString().split('T')[0] }
|
|
]
|
|
|
|
// Cosechas seleccionadas (por defecto las 3 más recientes)
|
|
const cosechasSeleccionadas = ref<string[]>(['cosecha-23-24', 'cosecha-24-25'])
|
|
|
|
// Store de ingresos
|
|
const ingresosStore = useTableDataStore<IngresoRecord>('ingresos')
|
|
|
|
// Datos de ingresos desde el store
|
|
const ingresos = computed(() => ingresosStore.allRecords as IngresoRecord[])
|
|
|
|
// Loading and error states
|
|
const loading = computed(() => ingresosStore.isLoading)
|
|
const error = computed(() => ingresosStore.error)
|
|
|
|
// Exportar cosechas para los componentes
|
|
provide('cosechasDisponibles', cosechasDisponibles)
|
|
</script>
|