Remove all database dependencies and simplify application
BREAKING CHANGE: Remove all data analysis features This commit removes all database-dependent functionality and simplifies the application to focus on authentication and user management only. Changes: - Remove all /api/data and /api/metadata server endpoints - Remove Supabase configuration from nuxt.config.ts and .env.example - Remove @supabase/supabase-js dependency from package.json - Delete data analysis pages: explorer, metadatos, rawExplorer, panorama, comparativa-cosechas, informe-ingresos - Simplify sidebar navigation to show only "Inicio" - Update home page to focus on authentication and profile management - Remove "Supabase" and "Solo lectura" badges from navbar - Keep only auth-related API endpoints: /api/auth/status and /api/auth/check-group The application now serves as an authentication-protected portal with: - Authentik SSO integration - User profile management - Settings and notifications pages (coming soon) - No database or data analysis features
This commit is contained in:
@@ -1,530 +0,0 @@
|
||||
<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">
|
||||
<UButton
|
||||
@click="mostrarConfiguracion = !mostrarConfiguracion"
|
||||
size="xs"
|
||||
color="neutral"
|
||||
variant="ghost"
|
||||
icon="i-lucide-palette"
|
||||
:class="{ 'bg-[#c08040]/20 text-[#c08040]': mostrarConfiguracion }"
|
||||
>
|
||||
Configurar estilos
|
||||
</UButton>
|
||||
<div class="w-px h-4 bg-[var(--brand-border)]" />
|
||||
<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"
|
||||
/>
|
||||
</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>
|
||||
<!-- Metadatos de Resumen de Ingresos -->
|
||||
<UCard class="brand-card border border-transparent">
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2">
|
||||
<UIcon name="i-lucide-database" class="size-5 text-[#c08040]" />
|
||||
<h3 class="text-base font-semibold text-[var(--brand-text)]">Fuente de Datos: Resumen Diario de Ingresos</h3>
|
||||
</div>
|
||||
</template>
|
||||
<MetadatosCard v-if="resumenIngresosMetadata" :metadata="resumenIngresosMetadata" :compact="true" />
|
||||
</UCard>
|
||||
|
||||
<!-- 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 transition-all"
|
||||
:class="[
|
||||
cosecha.disabled
|
||||
? 'border-gray-600/20 bg-gray-800/20 cursor-not-allowed opacity-50'
|
||||
: cosechasSeleccionadas.includes(cosecha.id)
|
||||
? 'border-[#c08040] bg-[#c08040]/10 cursor-pointer'
|
||||
: 'border-[var(--brand-border)] hover:border-[#c08040]/50 cursor-pointer'
|
||||
]"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
:value="cosecha.id"
|
||||
v-model="cosechasSeleccionadas"
|
||||
:disabled="cosecha.disabled"
|
||||
class="rounded border-[var(--brand-border)] text-[#c08040] focus:ring-[#c08040] disabled:cursor-not-allowed"
|
||||
/>
|
||||
<div class="flex flex-col flex-1">
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<span class="text-sm font-medium text-[var(--brand-text)]">{{ cosecha.label }}</span>
|
||||
<span
|
||||
v-if="!cosecha.disabled"
|
||||
class="text-[10px] px-1.5 py-0.5 rounded-full bg-[#c08040]/20 text-[#c08040] font-semibold"
|
||||
>
|
||||
{{ cosecha.registros }}
|
||||
</span>
|
||||
</div>
|
||||
<span class="text-xs text-[var(--brand-text-muted)]">
|
||||
{{ cosecha.disabled ? 'Sin datos' : cosecha.periodo }}
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</UCard>
|
||||
|
||||
<!-- Vista Heatmap -->
|
||||
<div v-if="cosechasSeleccionadas.length > 0 && pageSections.heatmap">
|
||||
<ComparativaCosechasHeatmap :ingresos="resumenIngresos" :cosechas-seleccionadas="cosechasSeleccionadas" />
|
||||
</div>
|
||||
|
||||
<!-- Resumen General por Cosecha -->
|
||||
<div v-if="cosechasSeleccionadas.length > 0 && pageSections.totales">
|
||||
<ComparativaCosechasTotales :ingresos="resumenIngresos" :cosechas-seleccionadas="cosechasSeleccionadas" />
|
||||
</div>
|
||||
|
||||
<!-- Evolución Temporal Comparada -->
|
||||
<div v-if="cosechasSeleccionadas.length > 0 && pageSections.evolucion">
|
||||
<ComparativaCosechasEvolucion :ingresos="resumenIngresos" :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>
|
||||
|
||||
<!-- Modal de Configuración de Estilos -->
|
||||
<UCard class="brand-card" v-if="mostrarConfiguracion">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2">
|
||||
<UIcon name="i-lucide-palette" class="size-5 text-[#c08040]" />
|
||||
<h3 id="modal-title" class="text-base font-semibold text-[var(--brand-text)]">Configuración de Estilos</h3>
|
||||
</div>
|
||||
<UButton
|
||||
@click="resetearConfiguracion"
|
||||
size="xs"
|
||||
color="neutral"
|
||||
variant="ghost"
|
||||
icon="i-lucide-rotate-ccw"
|
||||
>
|
||||
Resetear
|
||||
</UButton>
|
||||
</div>
|
||||
<p id="modal-description" class="sr-only">
|
||||
Personaliza los colores, dimensiones y opacidad de las gráficas
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<div class="flex flex-col gap-6">
|
||||
<!-- Sección: Colores de Cosechas -->
|
||||
<div>
|
||||
<h4 class="text-sm font-semibold text-[var(--brand-text)] mb-3 flex items-center gap-2">
|
||||
<UIcon name="i-lucide-droplets" class="size-4" />
|
||||
Colores de Cosechas (por año)
|
||||
</h4>
|
||||
<p class="text-xs text-[var(--brand-text-muted)] mb-3">
|
||||
Los colores son fijos para cada cosecha, sin importar el orden en que se seleccionen
|
||||
</p>
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div
|
||||
v-for="(cosecha, index) in cosechasDefiniciones"
|
||||
:key="`color-${cosecha.id}`"
|
||||
class="flex items-center gap-3 p-3 rounded-lg border border-[var(--brand-border)] bg-[var(--brand-bg-secondary)]"
|
||||
>
|
||||
<label class="text-xs text-[var(--brand-text-muted)] flex-1">
|
||||
{{ cosecha.label }}
|
||||
</label>
|
||||
<input
|
||||
type="color"
|
||||
v-model="estilosGraficas.coloresCosechas[index]"
|
||||
class="w-10 h-8 rounded cursor-pointer border border-[var(--brand-border)]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sección: Dimensiones -->
|
||||
<div>
|
||||
<h4 class="text-sm font-semibold text-[var(--brand-text)] mb-3 flex items-center gap-2">
|
||||
<UIcon name="i-lucide-ruler" class="size-4" />
|
||||
Dimensiones
|
||||
</h4>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<!-- Ancho de celda (Heatmap) -->
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="text-xs text-[var(--brand-text-muted)]">
|
||||
Ancho de celda (Heatmap)
|
||||
</label>
|
||||
<div class="flex items-center gap-2">
|
||||
<input
|
||||
type="range"
|
||||
v-model.number="estilosGraficas.anchoCelda"
|
||||
min="40"
|
||||
max="150"
|
||||
step="10"
|
||||
class="flex-1"
|
||||
/>
|
||||
<span class="text-xs text-[var(--brand-text)] w-12 text-right">
|
||||
{{ estilosGraficas.anchoCelda }}px
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alto de celda (Heatmap) -->
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="text-xs text-[var(--brand-text-muted)]">
|
||||
Alto de celda (Heatmap)
|
||||
</label>
|
||||
<div class="flex items-center gap-2">
|
||||
<input
|
||||
type="range"
|
||||
v-model.number="estilosGraficas.altoCelda"
|
||||
min="4"
|
||||
max="20"
|
||||
step="1"
|
||||
class="flex-1"
|
||||
/>
|
||||
<span class="text-xs text-[var(--brand-text)] w-12 text-right">
|
||||
{{ estilosGraficas.altoCelda }}px
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ancho máximo de barra -->
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="text-xs text-[var(--brand-text-muted)]">
|
||||
Ancho máximo de barra
|
||||
</label>
|
||||
<div class="flex items-center gap-2">
|
||||
<input
|
||||
type="range"
|
||||
v-model.number="estilosGraficas.anchoMaxBarra"
|
||||
min="150"
|
||||
max="500"
|
||||
step="25"
|
||||
class="flex-1"
|
||||
/>
|
||||
<span class="text-xs text-[var(--brand-text)] w-12 text-right">
|
||||
{{ estilosGraficas.anchoMaxBarra }}px
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alto de barra -->
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="text-xs text-[var(--brand-text-muted)]">
|
||||
Alto de barra
|
||||
</label>
|
||||
<div class="flex items-center gap-2">
|
||||
<input
|
||||
type="range"
|
||||
v-model.number="estilosGraficas.altoBarra"
|
||||
min="6"
|
||||
max="24"
|
||||
step="2"
|
||||
class="flex-1"
|
||||
/>
|
||||
<span class="text-xs text-[var(--brand-text)] w-12 text-right">
|
||||
{{ estilosGraficas.altoBarra }}px
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sección: Opacidad -->
|
||||
<div>
|
||||
<h4 class="text-sm font-semibold text-[var(--brand-text)] mb-3 flex items-center gap-2">
|
||||
<UIcon name="i-lucide-sun-dim" class="size-4" />
|
||||
Opacidad
|
||||
</h4>
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="text-xs text-[var(--brand-text-muted)]">
|
||||
Opacidad de celdas vacías (Heatmap)
|
||||
</label>
|
||||
<div class="flex items-center gap-2">
|
||||
<input
|
||||
type="range"
|
||||
v-model.number="estilosGraficas.opacidadVacias"
|
||||
min="0"
|
||||
max="0.3"
|
||||
step="0.05"
|
||||
class="flex-1"
|
||||
/>
|
||||
<span class="text-xs text-[var(--brand-text)] w-12 text-right">
|
||||
{{ (estilosGraficas.opacidadVacias * 100).toFixed(0) }}%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="flex justify-end gap-2">
|
||||
<UButton
|
||||
@click="mostrarConfiguracion = false"
|
||||
color="neutral"
|
||||
variant="ghost"
|
||||
>
|
||||
Cerrar
|
||||
</UButton>
|
||||
</div>
|
||||
</template>
|
||||
</UCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useTableDataStore } from '~/stores/tableDataFactory'
|
||||
import { useMetadataStore } from '~/stores/metadata'
|
||||
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
|
||||
})
|
||||
|
||||
// Estado del modal de configuración
|
||||
const mostrarConfiguracion = ref(false)
|
||||
|
||||
// Configuración de estilos por defecto
|
||||
const estilosGraficasDefault = {
|
||||
coloresCosechas: [
|
||||
'#c08040', // Cosecha 20-21
|
||||
'#d99a56', // Cosecha 21-22
|
||||
'#8b6f47', // Cosecha 22-23
|
||||
'#a0826e', // Cosecha 23-24
|
||||
'#b89968', // Cosecha 24-25
|
||||
'#f0c07c' // Cosecha 25-26
|
||||
],
|
||||
anchoCelda: 80,
|
||||
altoCelda: 6,
|
||||
anchoMaxBarra: 300,
|
||||
altoBarra: 8,
|
||||
opacidadVacias: 0.05
|
||||
}
|
||||
|
||||
// Cargar configuración desde cookies
|
||||
function cargarConfiguracionDesdeCookies() {
|
||||
const cookie = useCookie<typeof estilosGraficasDefault>('estilos-graficas', {
|
||||
maxAge: 60 * 60 * 24 * 365, // 1 año
|
||||
sameSite: 'lax'
|
||||
})
|
||||
|
||||
if (cookie.value) {
|
||||
try {
|
||||
return { ...estilosGraficasDefault, ...cookie.value }
|
||||
} catch (e) {
|
||||
console.error('Error al cargar configuración desde cookies:', e)
|
||||
return { ...estilosGraficasDefault }
|
||||
}
|
||||
}
|
||||
|
||||
return { ...estilosGraficasDefault }
|
||||
}
|
||||
|
||||
// Configuración reactiva de estilos
|
||||
const estilosGraficas = ref(cargarConfiguracionDesdeCookies())
|
||||
|
||||
// Guardar en cookies cuando cambie la configuración
|
||||
watch(estilosGraficas, (newValue) => {
|
||||
const cookie = useCookie<typeof estilosGraficasDefault>('estilos-graficas', {
|
||||
maxAge: 60 * 60 * 24 * 365, // 1 año
|
||||
sameSite: 'lax'
|
||||
})
|
||||
cookie.value = newValue
|
||||
}, { deep: true })
|
||||
|
||||
// Función para resetear la configuración
|
||||
function resetearConfiguracion() {
|
||||
estilosGraficas.value = { ...estilosGraficasDefault }
|
||||
}
|
||||
|
||||
// Store de resumen de ingresos (registros por día con métricas agregadas)
|
||||
const resumenIngresosStore = useTableDataStore<any>('vista_resumen_ingresos')
|
||||
|
||||
// Datos de resumen desde el store
|
||||
const resumenIngresos = computed(() => resumenIngresosStore.allRecords)
|
||||
|
||||
// Definición de cosechas disponibles (8 sep - 7 sep)
|
||||
const cosechasDefiniciones = [
|
||||
{ id: 'cosecha-20-21', label: 'Cosecha 20-21', periodo: '8 Sep 2020 - 7 Sep 2021', fechaInicio: '2020-09-08', fechaFin: '2021-09-07' },
|
||||
{ id: 'cosecha-21-22', label: 'Cosecha 21-22', periodo: '8 Sep 2021 - 7 Sep 2022', fechaInicio: '2021-09-08', fechaFin: '2022-09-07' },
|
||||
{ id: 'cosecha-22-23', label: 'Cosecha 22-23', periodo: '8 Sep 2022 - 7 Sep 2023', fechaInicio: '2022-09-08', fechaFin: '2023-09-07' },
|
||||
{ id: 'cosecha-23-24', label: 'Cosecha 23-24', periodo: '8 Sep 2023 - 7 Sep 2024', fechaInicio: '2023-09-08', fechaFin: '2024-09-07' },
|
||||
{ id: 'cosecha-24-25', label: 'Cosecha 24-25', periodo: '8 Sep 2024 - 7 Sep 2025', fechaInicio: '2024-09-08', fechaFin: '2025-09-07' },
|
||||
{ id: 'cosecha-25-26', label: 'Cosecha 25-26', periodo: '8 Sep 2025 - Hoy', fechaInicio: '2025-09-08', fechaFin: new Date().toISOString().split('T')[0] }
|
||||
] as const satisfies readonly { id: string; label: string; periodo: string; fechaInicio: string; fechaFin: string }[]
|
||||
|
||||
// Calcular cuántos registros tiene cada cosecha
|
||||
const registrosPorCosecha = computed(() => {
|
||||
const counts: Record<string, number> = {}
|
||||
|
||||
cosechasDefiniciones.forEach(cosecha => {
|
||||
const registros = resumenIngresos.value.filter((record: any) => {
|
||||
const fecha = new Date(record.fecha || record.created_at)
|
||||
const inicio = new Date(cosecha.fechaInicio)
|
||||
const fin = new Date(cosecha.fechaFin)
|
||||
return fecha >= inicio && fecha <= fin
|
||||
})
|
||||
counts[cosecha.id] = registros.length
|
||||
})
|
||||
|
||||
return counts
|
||||
})
|
||||
|
||||
// Cosechas disponibles con información de registros
|
||||
const cosechasDisponibles = computed(() => {
|
||||
return cosechasDefiniciones.map(cosecha => ({
|
||||
...cosecha,
|
||||
registros: registrosPorCosecha.value[cosecha.id] || 0,
|
||||
disabled: (registrosPorCosecha.value[cosecha.id] || 0) === 0
|
||||
}))
|
||||
})
|
||||
|
||||
// Cosechas seleccionadas (persistir en cookies)
|
||||
const cosechasSeleccionadas = useCookie<string[]>('comparativa-cosechas-seleccionadas', {
|
||||
default: () => [],
|
||||
maxAge: 60 * 60 * 24 * 365, // 1 año
|
||||
sameSite: 'lax'
|
||||
})
|
||||
|
||||
// Watch para filtrar cosechas deshabilitadas y seleccionar las más recientes con datos
|
||||
watch(cosechasDisponibles, (disponibles) => {
|
||||
// Remover cosechas deshabilitadas de la selección
|
||||
cosechasSeleccionadas.value = cosechasSeleccionadas.value.filter(id => {
|
||||
const cosecha = disponibles.find(c => c.id === id)
|
||||
return cosecha && !cosecha.disabled
|
||||
})
|
||||
|
||||
// Si no hay ninguna seleccionada, seleccionar las 2 más recientes con datos
|
||||
if (cosechasSeleccionadas.value.length === 0) {
|
||||
const conDatos = disponibles.filter(c => !c.disabled)
|
||||
cosechasSeleccionadas.value = conDatos.slice(-2).map(c => c.id)
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
// Loading and error states
|
||||
const loading = computed(() => resumenIngresosStore.isLoading)
|
||||
const error = computed(() => resumenIngresosStore.error)
|
||||
|
||||
// Metadatos desde el store de metadata
|
||||
const metadataStore = useMetadataStore()
|
||||
|
||||
const resumenIngresosMetadata = computed(() => {
|
||||
const meta = metadataStore.metadata.find((t: any) => t.table === 'vista_resumen_ingresos')
|
||||
return meta ? { ...meta, name: 'vista_resumen_ingresos' } : null
|
||||
})
|
||||
|
||||
// Definir las métricas disponibles para los componentes
|
||||
const metricasDisponibles = {
|
||||
pesoSeco: {
|
||||
key: 'total_peso_seco',
|
||||
label: 'Peso Seco Total',
|
||||
unidad: 'qq',
|
||||
descripcion: 'Peso seco total del día'
|
||||
},
|
||||
pesoNetoUva: {
|
||||
key: 'peso_neto_uva',
|
||||
label: 'Peso Neto Uva',
|
||||
unidad: 'qq',
|
||||
descripcion: 'Peso neto de café uva'
|
||||
},
|
||||
pesoNetoVerde: {
|
||||
key: 'peso_neto_verde',
|
||||
label: 'Peso Neto Verde',
|
||||
unidad: 'qq',
|
||||
descripcion: 'Peso neto de café verde'
|
||||
},
|
||||
sacos: {
|
||||
key: 'sacos_total_dia',
|
||||
label: 'Sacos Totales',
|
||||
unidad: 'sacos',
|
||||
descripcion: 'Total de sacos del día'
|
||||
},
|
||||
lempirasUva: {
|
||||
key: 'total_lempiras_uva',
|
||||
label: 'Lempiras Uva',
|
||||
unidad: 'L',
|
||||
descripcion: 'Total en lempiras de café uva'
|
||||
},
|
||||
lempirasVerde: {
|
||||
key: 'total_lempiras_verde',
|
||||
label: 'Lempiras Verde',
|
||||
unidad: 'L',
|
||||
descripcion: 'Total en lempiras de café verde'
|
||||
},
|
||||
lempirasMojadoOreado: {
|
||||
key: 'total_lempiras_mojado_oreado',
|
||||
label: 'Lempiras Mojado+Oreado',
|
||||
unidad: 'L',
|
||||
descripcion: 'Total en lempiras de café mojado y oreado (combinados)',
|
||||
// Esta métrica se calcula combinando total_lempiras_mojado + total_lempiras_oreado
|
||||
computed: true,
|
||||
keys: ['total_lempiras_mojado', 'total_lempiras_oreado']
|
||||
}
|
||||
}
|
||||
|
||||
// Exportar definiciones de cosechas, métricas y configuración para los componentes
|
||||
// Usamos cosechasDefiniciones (array estático) en lugar de cosechasDisponibles (computed)
|
||||
// porque los componentes hijos no necesitan la info de disabled/registros
|
||||
provide('cosechasDisponibles', cosechasDefiniciones)
|
||||
provide('metricasDisponibles', metricasDisponibles)
|
||||
provide('estilosGraficas', estilosGraficas)
|
||||
</script>
|
||||
Reference in New Issue
Block a user