mejoras ui/Ux y refactorizacion del selector rapido de dateRange
This commit is contained in:
87
nuxt4-app/app/components/ClienteSelector.vue
Normal file
87
nuxt4-app/app/components/ClienteSelector.vue
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex flex-col md:flex-row gap-4">
|
||||||
|
<!-- Selector de clientes -->
|
||||||
|
<div class="flex-1">
|
||||||
|
<label class="text-xs text-[var(--brand-text-muted)] block mb-1">Seleccionar clientes</label>
|
||||||
|
<USelectMenu
|
||||||
|
v-model="selectedClientes"
|
||||||
|
:options="clienteOptions"
|
||||||
|
multiple
|
||||||
|
searchable
|
||||||
|
searchable-placeholder="Buscar cliente..."
|
||||||
|
placeholder="Todos los clientes"
|
||||||
|
value-attribute="id"
|
||||||
|
option-attribute="name"
|
||||||
|
:ui="{
|
||||||
|
wrapper: 'w-full',
|
||||||
|
input: 'w-full'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<span v-if="selectedClientes.length === 0">Todos los clientes</span>
|
||||||
|
<span v-else-if="selectedClientes.length === 1">
|
||||||
|
{{ clienteOptions.find(c => c.id === selectedClientes[0])?.name }}
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
|
{{ selectedClientes.length }} clientes seleccionados
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</USelectMenu>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-end">
|
||||||
|
<UButton
|
||||||
|
:ui="{ base: 'bg-[#c08040] text-[#1b1209] border border-[#d99a56] hover:bg-[#d99a56] hover:border-[#f0c07c]' }"
|
||||||
|
@click="clearSelection"
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
|
Limpiar
|
||||||
|
</UButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, watch } from 'vue'
|
||||||
|
|
||||||
|
interface Cliente {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
cedula?: number
|
||||||
|
ubicacion?: string
|
||||||
|
telefono?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
clientes: Cliente[]
|
||||||
|
selectedIds: number[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
'update:selectedIds': [value: number[]]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// Reactive reference para el v-model
|
||||||
|
const selectedClientes = computed({
|
||||||
|
get: () => props.selectedIds,
|
||||||
|
set: (value) => emit('update:selectedIds', value)
|
||||||
|
})
|
||||||
|
|
||||||
|
const clienteOptions = computed(() => {
|
||||||
|
return props.clientes
|
||||||
|
.filter(c => c.name && c.name.trim() !== '')
|
||||||
|
.sort((a, b) => a.name.localeCompare(b.name))
|
||||||
|
})
|
||||||
|
|
||||||
|
function clearSelection() {
|
||||||
|
emit('update:selectedIds', [])
|
||||||
|
console.log('Cliente selection cleared')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch para logging
|
||||||
|
watch(() => props.selectedIds, (newIds) => {
|
||||||
|
console.log('Selected cliente IDs:', newIds)
|
||||||
|
}, { deep: true })
|
||||||
|
</script>
|
||||||
197
nuxt4-app/app/components/DateRangeSelector.vue
Normal file
197
nuxt4-app/app/components/DateRangeSelector.vue
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex flex-col md:flex-row gap-4">
|
||||||
|
<!-- Presets -->
|
||||||
|
<div class="flex-1">
|
||||||
|
<label class="text-xs text-[var(--brand-text-muted)] block mb-1">Rango rápido</label>
|
||||||
|
<UFieldGroup>
|
||||||
|
<UButton
|
||||||
|
color="neutral"
|
||||||
|
variant="subtle"
|
||||||
|
:label="currentPresetLabel"
|
||||||
|
class="flex-1"
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
<UDropdownMenu :items="dropdownItems" :popper="{ placement: 'bottom-end' }">
|
||||||
|
<UButton
|
||||||
|
color="neutral"
|
||||||
|
variant="outline"
|
||||||
|
icon="i-lucide-chevron-down"
|
||||||
|
square
|
||||||
|
/>
|
||||||
|
</UDropdownMenu>
|
||||||
|
</UFieldGroup>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Fechas manuales -->
|
||||||
|
<div class="grid grid-cols-2 gap-4 flex-1">
|
||||||
|
<div>
|
||||||
|
<label class="text-xs text-[var(--brand-text-muted)]">Fecha desde</label>
|
||||||
|
<UInput :model-value="fechaDesde" type="date" @input="onManualDateChange" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-xs text-[var(--brand-text-muted)]">Fecha hasta</label>
|
||||||
|
<UInput :model-value="fechaHasta" type="date" @input="onManualDateChange" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-end">
|
||||||
|
<UButton
|
||||||
|
:ui="{ base: 'bg-[#c08040] text-[#1b1209] border border-[#d99a56] hover:bg-[#d99a56] hover:border-[#f0c07c]' }"
|
||||||
|
@click="clearPreset"
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
|
Limpiar
|
||||||
|
</UButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, watch, onMounted } from 'vue'
|
||||||
|
|
||||||
|
type PresetValue =
|
||||||
|
| '' | 'custom' | 'hoy' | 'semana' | 'mes' | 'ytd'
|
||||||
|
| 'cosecha-20-21' | 'cosecha-21-22' | 'cosecha-22-23'
|
||||||
|
| 'cosecha-23-24' | 'cosecha-24-25' | 'cosecha-25-26'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
selectedPreset: PresetValue
|
||||||
|
fechaDesde: string | null
|
||||||
|
fechaHasta: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
'update:selectedPreset': [value: PresetValue]
|
||||||
|
'update:fechaDesde': [value: string | null]
|
||||||
|
'update:fechaHasta': [value: string | null]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// Definir funciones antes del watch
|
||||||
|
const toLocalDateStr = (d: Date) => {
|
||||||
|
const y = d.getFullYear()
|
||||||
|
const m = String(d.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(d.getDate()).padStart(2, '0')
|
||||||
|
return `${y}-${m}-${day}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectPreset(preset: PresetValue) {
|
||||||
|
console.log('selectPreset called with:', preset)
|
||||||
|
emit('update:selectedPreset', preset)
|
||||||
|
|
||||||
|
if (preset === '' || preset === 'custom') {
|
||||||
|
emit('update:fechaDesde', null)
|
||||||
|
emit('update:fechaHasta', null)
|
||||||
|
console.log('Cleared dates')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = new Date()
|
||||||
|
const set = (sd: string, ed: string) => {
|
||||||
|
emit('update:fechaDesde', sd)
|
||||||
|
emit('update:fechaHasta', ed)
|
||||||
|
console.log('Set dates:', sd, ed)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (preset) {
|
||||||
|
case 'hoy': set(toLocalDateStr(now), toLocalDateStr(now)); break
|
||||||
|
case 'semana': {
|
||||||
|
const d = new Date(now)
|
||||||
|
const day = d.getDay() || 7
|
||||||
|
d.setDate(d.getDate() - (day - 1)) // lunes
|
||||||
|
set(toLocalDateStr(d), toLocalDateStr(now))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'mes': set(toLocalDateStr(new Date(now.getFullYear(), now.getMonth(), 1)), toLocalDateStr(now)); break
|
||||||
|
case 'ytd': set(toLocalDateStr(new Date(now.getFullYear(), 0, 1)), toLocalDateStr(now)); break
|
||||||
|
case 'cosecha-20-21': set('2020-09-25', '2021-09-24'); break
|
||||||
|
case 'cosecha-21-22': set('2021-09-25', '2022-09-24'); break
|
||||||
|
case 'cosecha-22-23': set('2022-09-25', '2023-09-24'); break
|
||||||
|
case 'cosecha-23-24': set('2023-09-25', '2024-09-24'); break
|
||||||
|
case 'cosecha-24-25': set('2024-09-25', '2025-09-09'); break
|
||||||
|
case 'cosecha-25-26': set('2025-09-10', toLocalDateStr(now)); break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onManualDateChange(event: Event) {
|
||||||
|
const target = event.target as HTMLInputElement
|
||||||
|
const value = target.value
|
||||||
|
|
||||||
|
// Si el usuario modifica las fechas manualmente, cambiar a "Personalizado"
|
||||||
|
emit('update:selectedPreset', 'custom')
|
||||||
|
|
||||||
|
// Actualizar la fecha correspondiente según el input
|
||||||
|
if (target.type === 'date') {
|
||||||
|
const label = target.labels?.[0]?.textContent
|
||||||
|
if (label?.includes('desde')) {
|
||||||
|
emit('update:fechaDesde', value)
|
||||||
|
} else if (label?.includes('hasta')) {
|
||||||
|
emit('update:fechaHasta', value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Manual date change, preset set to custom')
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearPreset() {
|
||||||
|
emit('update:selectedPreset', '')
|
||||||
|
emit('update:fechaDesde', null)
|
||||||
|
emit('update:fechaHasta', null)
|
||||||
|
console.log('Preset cleared')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch para aplicar el preset cuando cambia (incluyendo el valor inicial)
|
||||||
|
watch(() => props.selectedPreset, (newPreset) => {
|
||||||
|
if (newPreset && newPreset !== 'custom' && newPreset !== '') {
|
||||||
|
selectPreset(newPreset)
|
||||||
|
}
|
||||||
|
}, { immediate: true })
|
||||||
|
|
||||||
|
const currentPresetLabel = computed(() => {
|
||||||
|
switch (props.selectedPreset) {
|
||||||
|
case '': return 'Sin filtro'
|
||||||
|
case 'custom': return 'Personalizado'
|
||||||
|
case 'hoy': return 'Hoy'
|
||||||
|
case 'semana': return 'Esta Semana'
|
||||||
|
case 'mes': return 'Este Mes'
|
||||||
|
case 'ytd': return 'YTD'
|
||||||
|
case 'cosecha-20-21': return 'Cosecha 20-21'
|
||||||
|
case 'cosecha-21-22': return 'Cosecha 21-22'
|
||||||
|
case 'cosecha-22-23': return 'Cosecha 22-23'
|
||||||
|
case 'cosecha-23-24': return 'Cosecha 23-24'
|
||||||
|
case 'cosecha-24-25': return 'Cosecha 24-25'
|
||||||
|
case 'cosecha-25-26': return 'Cosecha 25-26'
|
||||||
|
default: return 'Seleccionar rango'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const dropdownItems = [
|
||||||
|
{
|
||||||
|
label: 'Sin filtro',
|
||||||
|
onSelect: () => {
|
||||||
|
selectPreset('')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Rápidos',
|
||||||
|
children: [
|
||||||
|
{ label: 'Hoy', onSelect: () => { selectPreset('hoy') } },
|
||||||
|
{ label: 'Esta Semana', onSelect: () => { selectPreset('semana') } },
|
||||||
|
{ label: 'Este Mes', onSelect: () => { selectPreset('mes') } },
|
||||||
|
{ label: 'YTD', onSelect: () => { selectPreset('ytd') } }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Cosechas',
|
||||||
|
children: [
|
||||||
|
{ label: 'Cosecha 20-21 (25 Sep 2020)', onSelect: () => { selectPreset('cosecha-20-21') } },
|
||||||
|
{ label: 'Cosecha 21-22 (25 Sep 2021)', onSelect: () => { selectPreset('cosecha-21-22') } },
|
||||||
|
{ label: 'Cosecha 22-23 (25 Sep 2022)', onSelect: () => { selectPreset('cosecha-22-23') } },
|
||||||
|
{ label: 'Cosecha 23-24 (25 Sep 2023)', onSelect: () => { selectPreset('cosecha-23-24') } },
|
||||||
|
{ label: 'Cosecha 24-25 (25 Sep 2024)', onSelect: () => { selectPreset('cosecha-24-25') } },
|
||||||
|
{ label: 'Cosecha 25-26 (10 Sep 2025 → hoy)', onSelect: () => { selectPreset('cosecha-25-26') } }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
</script>
|
||||||
@@ -5,25 +5,39 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||||
<MetricCard
|
<div class="p-4 rounded-lg border transition-all bg-[#1c140c] border-purple-900/40 text-purple-300">
|
||||||
label="Total qq Secos por Vender"
|
<div class="flex flex-col">
|
||||||
:value="formatNumber(metrics.totalQqSecoPorVender.value)"
|
<span class="text-xs uppercase tracking-wide opacity-80 mb-1">Total qq Secos por Vender</span>
|
||||||
unit="qq"
|
<div class="flex items-baseline gap-2">
|
||||||
variant="info"
|
<span class="text-2xl font-bold">{{ formatNumber(metrics.totalQqSecoPorVender.value) }}</span>
|
||||||
/>
|
<span class="text-sm font-bold opacity-70">qq</span>
|
||||||
<MetricCard
|
</div>
|
||||||
label="Precio de Venta Promedio por qq"
|
</div>
|
||||||
:value="formatCurrency(metrics.precioVentaPromedioPorQq.value)"
|
</div>
|
||||||
/>
|
<div class="p-4 rounded-lg border transition-all bg-[#1c140c] border-purple-800/40 text-purple-400">
|
||||||
<MetricCard
|
<div class="flex flex-col">
|
||||||
label="Precio de Compra Promedio por qq"
|
<span class="text-xs uppercase tracking-wide opacity-80 mb-1">Precio de Venta Promedio por qq</span>
|
||||||
:value="formatCurrency(metrics.precioCompraPromedioPorQq.value)"
|
<div class="flex items-baseline gap-2">
|
||||||
/>
|
<span class="text-2xl font-bold">{{ formatCurrency(metrics.precioVentaPromedioPorQq.value) }}</span>
|
||||||
<MetricCard
|
</div>
|
||||||
label="Margen de Ganancia por qq"
|
</div>
|
||||||
:value="formatCurrency(metrics.margenGananciaPorQq.value)"
|
</div>
|
||||||
:variant="metrics.margenGananciaPorQq.value > 0 ? 'success' : 'danger'"
|
<div class="p-4 rounded-lg border transition-all bg-[#1c140c] border-purple-700/40 text-purple-500">
|
||||||
/>
|
<div class="flex flex-col">
|
||||||
|
<span class="text-xs uppercase tracking-wide opacity-80 mb-1">Precio de Compra Promedio por qq</span>
|
||||||
|
<div class="flex items-baseline gap-2">
|
||||||
|
<span class="text-2xl font-bold">{{ formatCurrency(metrics.precioCompraPromedioPorQq.value) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-4 rounded-lg border transition-all bg-[#1c140c] text-purple-600" :class="metrics.margenGananciaPorQq.value > 0 ? 'border-purple-600/40' : 'border-red-600/40'">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-xs uppercase tracking-wide opacity-80 mb-1">Margen de Ganancia por qq</span>
|
||||||
|
<div class="flex items-baseline gap-2">
|
||||||
|
<span class="text-2xl font-bold">{{ formatCurrency(metrics.margenGananciaPorQq.value) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</UCard>
|
</UCard>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
Totales Generales (Pagado + Pendiente)
|
Totales Generales (Pagado + Pendiente)
|
||||||
</h3>
|
</h3>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||||
<div class="p-4 rounded-lg border transition-all bg-[#1c140c] border-[#c08040] text-[var(--brand-primary)]">
|
<div class="p-4 rounded-lg border transition-all bg-[#1c140c] border-red-600/40 text-red-400">
|
||||||
<div class="flex items-center justify-between mb-1">
|
<div class="flex items-center justify-between mb-1">
|
||||||
<span class="text-xs uppercase tracking-wide opacity-80">Total Uva Ingresada</span>
|
<span class="text-xs uppercase tracking-wide opacity-80">Total Uva Ingresada</span>
|
||||||
<UButton
|
<UButton
|
||||||
@@ -31,13 +31,13 @@
|
|||||||
label="Total qq Seco Mojado"
|
label="Total qq Seco Mojado"
|
||||||
:value="formatNumber(metrics.totalQqSecoMojadoIngresado.value)"
|
:value="formatNumber(metrics.totalQqSecoMojadoIngresado.value)"
|
||||||
unit="qq"
|
unit="qq"
|
||||||
variant="primary"
|
variant="info"
|
||||||
/>
|
/>
|
||||||
<MetricCard
|
<MetricCard
|
||||||
label="Total qq Seco Oreado"
|
label="Total qq Seco Oreado"
|
||||||
:value="formatNumber(metrics.totalQqSecoOreadoIngresado.value)"
|
:value="formatNumber(metrics.totalQqSecoOreadoIngresado.value)"
|
||||||
unit="qq"
|
unit="qq"
|
||||||
variant="primary"
|
variant="warning"
|
||||||
/>
|
/>
|
||||||
<MetricCard
|
<MetricCard
|
||||||
label="Total qq Seco Ingresado"
|
label="Total qq Seco Ingresado"
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
Solo Pagados
|
Solo Pagados
|
||||||
</h3>
|
</h3>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||||
<div class="p-4 rounded-lg border transition-all bg-[#1c140c] border-green-600/30 text-green-400">
|
<div class="p-4 rounded-lg border transition-all bg-[#1c140c] border-red-600/40 text-red-400">
|
||||||
<div class="flex items-center justify-between mb-1">
|
<div class="flex items-center justify-between mb-1">
|
||||||
<span class="text-xs uppercase tracking-wide opacity-80">Total Uva Pagada</span>
|
<span class="text-xs uppercase tracking-wide opacity-80">Total Uva Pagada</span>
|
||||||
<UButton
|
<UButton
|
||||||
@@ -74,19 +74,19 @@
|
|||||||
label="Total qq Seco Mojado Pagado"
|
label="Total qq Seco Mojado Pagado"
|
||||||
:value="formatNumber(metrics.totalQqSecoMojadoPagado.value)"
|
:value="formatNumber(metrics.totalQqSecoMojadoPagado.value)"
|
||||||
unit="qq"
|
unit="qq"
|
||||||
variant="success"
|
variant="info"
|
||||||
/>
|
/>
|
||||||
<MetricCard
|
<MetricCard
|
||||||
label="Total qq Seco Oreado Pagado"
|
label="Total qq Seco Oreado Pagado"
|
||||||
:value="formatNumber(metrics.totalQqSecoOreadoPagado.value)"
|
:value="formatNumber(metrics.totalQqSecoOreadoPagado.value)"
|
||||||
unit="qq"
|
unit="qq"
|
||||||
variant="success"
|
variant="warning"
|
||||||
/>
|
/>
|
||||||
<MetricCard
|
<MetricCard
|
||||||
label="Total qq Seco Comprado"
|
label="Total qq Seco Comprado"
|
||||||
:value="formatNumber(metrics.totalQqSecoComprado.value)"
|
:value="formatNumber(metrics.totalQqSecoComprado.value)"
|
||||||
unit="qq"
|
unit="qq"
|
||||||
variant="success"
|
variant="primary"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
Inventario en Depósito
|
Inventario en Depósito
|
||||||
</h3>
|
</h3>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||||
<div class="p-4 rounded-lg border transition-all bg-[#1c140c] border-yellow-600/30 text-yellow-400">
|
<div class="p-4 rounded-lg border transition-all bg-[#1c140c] border-red-600/40 text-red-400">
|
||||||
<div class="flex items-center justify-between mb-1">
|
<div class="flex items-center justify-between mb-1">
|
||||||
<span class="text-xs uppercase tracking-wide opacity-80">Total Uva en Depósito</span>
|
<span class="text-xs uppercase tracking-wide opacity-80">Total Uva en Depósito</span>
|
||||||
<UButton
|
<UButton
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
label="Total qq Seco Mojado en Depósito"
|
label="Total qq Seco Mojado en Depósito"
|
||||||
:value="formatNumber(metrics.totalQqMojadoDeposito.value)"
|
:value="formatNumber(metrics.totalQqMojadoDeposito.value)"
|
||||||
unit="qq"
|
unit="qq"
|
||||||
variant="warning"
|
variant="info"
|
||||||
/>
|
/>
|
||||||
<MetricCard
|
<MetricCard
|
||||||
label="Total qq Seco Oreado en Depósito"
|
label="Total qq Seco Oreado en Depósito"
|
||||||
@@ -129,7 +129,7 @@
|
|||||||
label="Total qq Seco en Depósito"
|
label="Total qq Seco en Depósito"
|
||||||
:value="formatNumber(metrics.totalQqSecoDeposito.value)"
|
:value="formatNumber(metrics.totalQqSecoDeposito.value)"
|
||||||
unit="qq"
|
unit="qq"
|
||||||
variant="warning"
|
variant="primary"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -147,7 +147,7 @@ defineProps<{
|
|||||||
|
|
||||||
type UnitDisplay = 'lb' | 'qq' | 'both'
|
type UnitDisplay = 'lb' | 'qq' | 'both'
|
||||||
|
|
||||||
const unitDisplay = ref<UnitDisplay>('both')
|
const unitDisplay = ref<UnitDisplay>('lb')
|
||||||
|
|
||||||
const unitDisplayLabel = computed(() => {
|
const unitDisplayLabel = computed(() => {
|
||||||
switch (unitDisplay.value) {
|
switch (unitDisplay.value) {
|
||||||
|
|||||||
@@ -14,17 +14,17 @@
|
|||||||
<MetricCard
|
<MetricCard
|
||||||
label="Inversión en Uva"
|
label="Inversión en Uva"
|
||||||
:value="formatCurrency(metrics.inversionUva.value)"
|
:value="formatCurrency(metrics.inversionUva.value)"
|
||||||
variant="success"
|
variant="danger"
|
||||||
/>
|
|
||||||
<MetricCard
|
|
||||||
label="Inversión en Oreado"
|
|
||||||
:value="formatCurrency(metrics.inversionOreado.value)"
|
|
||||||
variant="success"
|
|
||||||
/>
|
/>
|
||||||
<MetricCard
|
<MetricCard
|
||||||
label="Inversión en Mojado"
|
label="Inversión en Mojado"
|
||||||
:value="formatCurrency(metrics.inversionMojado.value)"
|
:value="formatCurrency(metrics.inversionMojado.value)"
|
||||||
variant="success"
|
variant="info"
|
||||||
|
/>
|
||||||
|
<MetricCard
|
||||||
|
label="Inversión en Oreado"
|
||||||
|
:value="formatCurrency(metrics.inversionOreado.value)"
|
||||||
|
variant="warning"
|
||||||
/>
|
/>
|
||||||
<MetricCard
|
<MetricCard
|
||||||
label="Total Invertido"
|
label="Total Invertido"
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
Precios Promedio Ponderados
|
Precios Promedio Ponderados
|
||||||
</h3>
|
</h3>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||||
<div class="p-4 rounded-lg border transition-all bg-[#1c140c] border-[#3a2a16] text-[var(--brand-text)]">
|
<div class="p-4 rounded-lg border transition-all bg-[#1c140c] border-red-600/40 text-red-400">
|
||||||
<div class="flex items-center justify-between mb-1">
|
<div class="flex items-center justify-between mb-1">
|
||||||
<span class="text-xs uppercase tracking-wide opacity-80">Precio Promedio Ponderado Uva</span>
|
<span class="text-xs uppercase tracking-wide opacity-80">Precio Promedio Ponderado Uva</span>
|
||||||
<UButton
|
<UButton
|
||||||
@@ -56,20 +56,23 @@
|
|||||||
<span class="text-sm font-bold opacity-70 ml-2">{{ formatPrecioUvaUnit() }}</span>
|
<span class="text-sm font-bold opacity-70 ml-2">{{ formatPrecioUvaUnit() }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<MetricCard
|
|
||||||
label="Precio Promedio Ponderado Oreado"
|
|
||||||
:value="formatNumber(metrics.precioPromedioOreadoPorQq.value)"
|
|
||||||
unit="L./qq"
|
|
||||||
/>
|
|
||||||
<MetricCard
|
<MetricCard
|
||||||
label="Precio Promedio Ponderado Mojado"
|
label="Precio Promedio Ponderado Mojado"
|
||||||
:value="formatNumber(metrics.precioPromedioMojadoPorQq.value)"
|
:value="formatNumber(metrics.precioPromedioMojadoPorQq.value)"
|
||||||
unit="L./qq"
|
unit="L./qq"
|
||||||
|
variant="info"
|
||||||
|
/>
|
||||||
|
<MetricCard
|
||||||
|
label="Precio Promedio Ponderado Oreado"
|
||||||
|
:value="formatNumber(metrics.precioPromedioOreadoPorQq.value)"
|
||||||
|
unit="L./qq"
|
||||||
|
variant="warning"
|
||||||
/>
|
/>
|
||||||
<MetricCard
|
<MetricCard
|
||||||
label="Precio Promedio Ponderado qq Seco"
|
label="Precio Promedio Ponderado qq Seco"
|
||||||
:value="formatNumber(metrics.precioPromedioQqSeco.value)"
|
:value="formatNumber(metrics.precioPromedioQqSeco.value)"
|
||||||
unit="L./qq"
|
unit="L./qq"
|
||||||
|
variant="primary"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -80,25 +83,25 @@
|
|||||||
Inversión Restante a Realizar
|
Inversión Restante a Realizar
|
||||||
</h3>
|
</h3>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||||
|
<MetricCard
|
||||||
|
label="Inversión Restante Uva"
|
||||||
|
:value="formatCurrency(metrics.inversionRestanteUva.value)"
|
||||||
|
variant="danger"
|
||||||
|
/>
|
||||||
|
<MetricCard
|
||||||
|
label="Inversión Restante Mojado"
|
||||||
|
:value="formatCurrency(metrics.inversionRestanteMojado.value)"
|
||||||
|
variant="info"
|
||||||
|
/>
|
||||||
<MetricCard
|
<MetricCard
|
||||||
label="Inversión Restante Oreado"
|
label="Inversión Restante Oreado"
|
||||||
:value="formatCurrency(metrics.inversionRestanteOreado.value)"
|
:value="formatCurrency(metrics.inversionRestanteOreado.value)"
|
||||||
variant="warning"
|
variant="warning"
|
||||||
/>
|
/>
|
||||||
<MetricCard
|
|
||||||
label="Inversión Restante Mojado"
|
|
||||||
:value="formatCurrency(metrics.inversionRestanteMojado.value)"
|
|
||||||
variant="warning"
|
|
||||||
/>
|
|
||||||
<MetricCard
|
|
||||||
label="Inversión Restante Uva"
|
|
||||||
:value="formatCurrency(metrics.inversionRestanteUva.value)"
|
|
||||||
variant="warning"
|
|
||||||
/>
|
|
||||||
<MetricCard
|
<MetricCard
|
||||||
label="Inversión Restante Esperada"
|
label="Inversión Restante Esperada"
|
||||||
:value="formatCurrency(metrics.inversionRestanteEsperada.value)"
|
:value="formatCurrency(metrics.inversionRestanteEsperada.value)"
|
||||||
variant="danger"
|
variant="primary"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -116,7 +119,7 @@ const props = defineProps<{
|
|||||||
|
|
||||||
type UnitDisplay = 'lb' | 'qq' | 'both'
|
type UnitDisplay = 'lb' | 'qq' | 'both'
|
||||||
|
|
||||||
const unitDisplay = ref<UnitDisplay>('both')
|
const unitDisplay = ref<UnitDisplay>('lb')
|
||||||
|
|
||||||
const unitDisplayLabel = computed(() => {
|
const unitDisplayLabel = computed(() => {
|
||||||
switch (unitDisplay.value) {
|
switch (unitDisplay.value) {
|
||||||
|
|||||||
@@ -5,37 +5,58 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
<MetricCard
|
<div class="p-4 rounded-lg border transition-all bg-[#1c140c] border-green-700/40 text-green-300">
|
||||||
label="Total Lb Neto de Verde"
|
<div class="flex flex-col">
|
||||||
:value="formatNumber(metrics.totalLbNetoVerde.value)"
|
<span class="text-xs uppercase tracking-wide opacity-80 mb-1">Total Lb Neto de Verde</span>
|
||||||
unit="lb"
|
<div class="flex items-baseline gap-2">
|
||||||
/>
|
<span class="text-2xl font-bold">{{ formatNumber(metrics.totalLbNetoVerde.value) }}</span>
|
||||||
<MetricCard
|
<span class="text-sm font-bold opacity-70">lb</span>
|
||||||
label="Precio Promedio Ponderado Pagado"
|
</div>
|
||||||
:value="formatNumber(metrics.precioPromedioVerdePagado.value)"
|
</div>
|
||||||
unit="L./lb"
|
</div>
|
||||||
/>
|
<div class="p-4 rounded-lg border transition-all bg-[#1c140c] border-green-600/40 text-green-400">
|
||||||
<MetricCard
|
<div class="flex flex-col">
|
||||||
label="Total Lb Neto de Verde en Depósito"
|
<span class="text-xs uppercase tracking-wide opacity-80 mb-1">Precio Promedio Ponderado Pagado</span>
|
||||||
:value="formatNumber(metrics.totalLbNetoVerdeDeposito.value)"
|
<div class="flex items-baseline gap-2">
|
||||||
unit="lb"
|
<span class="text-2xl font-bold">{{ formatNumber(metrics.precioPromedioVerdePagado.value) }}</span>
|
||||||
variant="info"
|
<span class="text-sm font-bold opacity-70">L./lb</span>
|
||||||
/>
|
</div>
|
||||||
<MetricCard
|
</div>
|
||||||
label="Inversión en Verde Hasta la Fecha"
|
</div>
|
||||||
:value="formatCurrency(metrics.inversionVerdeHastaFecha.value)"
|
<div class="p-4 rounded-lg border transition-all bg-[#1c140c] border-green-500/40 text-green-500">
|
||||||
variant="success"
|
<div class="flex flex-col">
|
||||||
/>
|
<span class="text-xs uppercase tracking-wide opacity-80 mb-1">Total Lb Neto de Verde en Depósito</span>
|
||||||
<MetricCard
|
<div class="flex items-baseline gap-2">
|
||||||
label="Inversión Restante a Realizar en Verde"
|
<span class="text-2xl font-bold">{{ formatNumber(metrics.totalLbNetoVerdeDeposito.value) }}</span>
|
||||||
:value="formatCurrency(metrics.inversionRestanteVerde.value)"
|
<span class="text-sm font-bold opacity-70">lb</span>
|
||||||
variant="warning"
|
</div>
|
||||||
/>
|
</div>
|
||||||
<MetricCard
|
</div>
|
||||||
label="Total Lb Neto Comprado de Verde"
|
<div class="p-4 rounded-lg border transition-all bg-[#1c140c] border-emerald-600/40 text-emerald-400">
|
||||||
:value="formatNumber(metrics.totalLbNetoCompradoVerde.value)"
|
<div class="flex flex-col">
|
||||||
unit="lb"
|
<span class="text-xs uppercase tracking-wide opacity-80 mb-1">Inversión en Verde Hasta la Fecha</span>
|
||||||
/>
|
<div class="flex items-baseline gap-2">
|
||||||
|
<span class="text-2xl font-bold">{{ formatCurrency(metrics.inversionVerdeHastaFecha.value) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-4 rounded-lg border transition-all bg-[#1c140c] border-lime-600/40 text-lime-400">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-xs uppercase tracking-wide opacity-80 mb-1">Inversión Restante a Realizar en Verde</span>
|
||||||
|
<div class="flex items-baseline gap-2">
|
||||||
|
<span class="text-2xl font-bold">{{ formatCurrency(metrics.inversionRestanteVerde.value) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-4 rounded-lg border transition-all bg-[#1c140c] border-teal-600/40 text-teal-400">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="text-xs uppercase tracking-wide opacity-80 mb-1">Total Lb Neto Comprado de Verde</span>
|
||||||
|
<div class="flex items-baseline gap-2">
|
||||||
|
<span class="text-2xl font-bold">{{ formatNumber(metrics.totalLbNetoCompradoVerde.value) }}</span>
|
||||||
|
<span class="text-sm font-bold opacity-70">lb</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</UCard>
|
</UCard>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between items-center pt-2 border-t border-[#3a2a16]">
|
<div class="flex justify-between items-center pt-2 border-t border-[#3a2a16]">
|
||||||
<span class="text-[var(--brand-text)] font-semibold">Total cobrado:</span>
|
<span class="text-[var(--brand-text)] font-semibold">Total cobrado:</span>
|
||||||
<span class="font-bold text-green-400">{{ formatCurrency(metrics.value.totalCobrado) }}</span>
|
<span class="font-bold text-white-400">{{ formatCurrency(metrics.value.totalCobrado) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<h2 class="text-xl font-bold brand-section-title">Rechazos y Subproductos</h2>
|
<h2 class="text-xl font-bold brand-section-title">Rechazos y Subproductos</h2>
|
||||||
<div class="rounded-lg border border-[#3a2a16] bg-[#1c140c] px-4 py-2">
|
<div class="rounded-lg border border-[#3a2a16] bg-[#1c140c] px-4 py-2">
|
||||||
<div class="text-xs text-[var(--brand-text-muted)] uppercase tracking-wide mb-1">Total Rechazos</div>
|
<div class="text-xs text-[var(--brand-text-muted)] uppercase tracking-wide mb-1">Total Rechazos</div>
|
||||||
<div class="text-2xl font-bold text-green-400">{{ formatCurrency(totalRechazos.value) }}</div>
|
<div class="text-2xl font-bold text-[var(--brand-text)]">{{ formatCurrency(totalRechazos.value) }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<h2 class="text-xl font-bold brand-section-title">Filtros</h2>
|
<h2 class="text-xl font-bold brand-section-title">Filtros y Configuraciones</h2>
|
||||||
<p class="text-xs text-[var(--brand-text-muted)] mt-1">
|
<p class="text-xs text-[var(--brand-text-muted)] mt-1">
|
||||||
Aplicados a <code>created_at</code> de ingresos y rechazos
|
Aplicados a <code>created_at</code> de ingresos y rechazos
|
||||||
</p>
|
</p>
|
||||||
@@ -62,51 +62,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="flex flex-col md:flex-row gap-4">
|
<DateRangeSelector
|
||||||
<!-- Presets -->
|
:selected-preset="selectedPreset"
|
||||||
<div class="flex-1">
|
:fecha-desde="fechaDesde"
|
||||||
<label class="text-xs text-[var(--brand-text-muted)] block mb-1">Rango rápido</label>
|
:fecha-hasta="fechaHasta"
|
||||||
<UFieldGroup>
|
@update:selected-preset="selectedPreset = $event"
|
||||||
<UButton
|
@update:fecha-desde="fechaDesde = $event"
|
||||||
color="neutral"
|
@update:fecha-hasta="fechaHasta = $event"
|
||||||
variant="subtle"
|
/>
|
||||||
:label="currentPresetLabel"
|
|
||||||
class="flex-1"
|
|
||||||
disabled
|
|
||||||
/>
|
|
||||||
<UDropdownMenu :items="dropdownItems" :popper="{ placement: 'bottom-end' }">
|
|
||||||
<UButton
|
|
||||||
color="neutral"
|
|
||||||
variant="outline"
|
|
||||||
icon="i-lucide-chevron-down"
|
|
||||||
square
|
|
||||||
/>
|
|
||||||
</UDropdownMenu>
|
|
||||||
</UFieldGroup>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Fechas manuales -->
|
|
||||||
<div class="grid grid-cols-2 gap-4 flex-1">
|
|
||||||
<div>
|
|
||||||
<label class="text-xs text-[var(--brand-text-muted)]">Fecha desde</label>
|
|
||||||
<UInput v-model="fechaDesde" type="date" @input="onManualDateChange" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="text-xs text-[var(--brand-text-muted)]">Fecha hasta</label>
|
|
||||||
<UInput v-model="fechaHasta" type="date" @input="onManualDateChange" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-end">
|
|
||||||
<UButton
|
|
||||||
:ui="{ base: 'bg-[#c08040] text-[#1b1209] border border-[#d99a56] hover:bg-[#d99a56] hover:border-[#f0c07c]' }"
|
|
||||||
@click="clearPreset"
|
|
||||||
size="sm"
|
|
||||||
>
|
|
||||||
Limpiar
|
|
||||||
</UButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="text-xs text-[var(--brand-text-muted)]">
|
<div class="text-xs text-[var(--brand-text-muted)]">
|
||||||
@@ -210,108 +173,9 @@ type PresetValue =
|
|||||||
| 'cosecha-23-24' | 'cosecha-24-25' | 'cosecha-25-26';
|
| 'cosecha-23-24' | 'cosecha-24-25' | 'cosecha-25-26';
|
||||||
|
|
||||||
const selectedPreset = ref<PresetValue>('cosecha-25-26')
|
const selectedPreset = ref<PresetValue>('cosecha-25-26')
|
||||||
|
|
||||||
const currentPresetLabel = computed(() => {
|
|
||||||
switch (selectedPreset.value) {
|
|
||||||
case '': return 'Sin filtro'
|
|
||||||
case 'custom': return 'Personalizado'
|
|
||||||
case 'hoy': return 'Hoy'
|
|
||||||
case 'semana': return 'Esta Semana'
|
|
||||||
case 'mes': return 'Este Mes'
|
|
||||||
case 'ytd': return 'YTD'
|
|
||||||
case 'cosecha-20-21': return 'Cosecha 20-21'
|
|
||||||
case 'cosecha-21-22': return 'Cosecha 21-22'
|
|
||||||
case 'cosecha-22-23': return 'Cosecha 22-23'
|
|
||||||
case 'cosecha-23-24': return 'Cosecha 23-24'
|
|
||||||
case 'cosecha-24-25': return 'Cosecha 24-25'
|
|
||||||
case 'cosecha-25-26': return 'Cosecha 25-26'
|
|
||||||
default: return 'Seleccionar rango'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const dropdownItems = [
|
|
||||||
{
|
|
||||||
label: 'Sin filtro',
|
|
||||||
onSelect: () => {
|
|
||||||
selectPreset('')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Rápidos',
|
|
||||||
children: [
|
|
||||||
{ label: 'Hoy', onSelect: () => { selectPreset('hoy') } },
|
|
||||||
{ label: 'Esta Semana', onSelect: () => { selectPreset('semana') } },
|
|
||||||
{ label: 'Este Mes', onSelect: () => { selectPreset('mes') } },
|
|
||||||
{ label: 'YTD', onSelect: () => { selectPreset('ytd') } }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Cosechas',
|
|
||||||
children: [
|
|
||||||
{ label: 'Cosecha 20-21 (25 Sep 2020)', onSelect: () => { selectPreset('cosecha-20-21') } },
|
|
||||||
{ label: 'Cosecha 21-22 (25 Sep 2021)', onSelect: () => { selectPreset('cosecha-21-22') } },
|
|
||||||
{ label: 'Cosecha 22-23 (25 Sep 2022)', onSelect: () => { selectPreset('cosecha-22-23') } },
|
|
||||||
{ label: 'Cosecha 23-24 (25 Sep 2023)', onSelect: () => { selectPreset('cosecha-23-24') } },
|
|
||||||
{ label: 'Cosecha 24-25 (25 Sep 2024)', onSelect: () => { selectPreset('cosecha-24-25') } },
|
|
||||||
{ label: 'Cosecha 25-26 (10 Sep 2025 → hoy)', onSelect: () => { selectPreset('cosecha-25-26') } }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
// Fechas (YYYY-MM-DD) — Honduras (UTC-6)
|
|
||||||
const toLocalDateStr = (d: Date) => {
|
|
||||||
const y = d.getFullYear()
|
|
||||||
const m = String(d.getMonth() + 1).padStart(2,'0')
|
|
||||||
const day = String(d.getDate()).padStart(2,'0')
|
|
||||||
return `${y}-${m}-${day}`
|
|
||||||
}
|
|
||||||
const fechaDesde = ref<string | null>(null)
|
const fechaDesde = ref<string | null>(null)
|
||||||
const fechaHasta = ref<string | null>(null)
|
const fechaHasta = ref<string | null>(null)
|
||||||
|
|
||||||
function selectPreset(preset: PresetValue) {
|
|
||||||
console.log('selectPreset called with:', preset)
|
|
||||||
selectedPreset.value = preset
|
|
||||||
|
|
||||||
if (preset === '' || preset === 'custom') {
|
|
||||||
fechaDesde.value = null
|
|
||||||
fechaHasta.value = null
|
|
||||||
console.log('Cleared dates')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const now = new Date()
|
|
||||||
const set = (sd: string, ed: string) => {
|
|
||||||
fechaDesde.value = sd
|
|
||||||
fechaHasta.value = ed
|
|
||||||
console.log('Set dates:', sd, ed)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (preset) {
|
|
||||||
case 'hoy': set(toLocalDateStr(now), toLocalDateStr(now)); break
|
|
||||||
case 'semana': {
|
|
||||||
const d = new Date(now)
|
|
||||||
const day = d.getDay() || 7
|
|
||||||
d.setDate(d.getDate() - (day - 1)) // lunes
|
|
||||||
set(toLocalDateStr(d), toLocalDateStr(now))
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case 'mes': set(toLocalDateStr(new Date(now.getFullYear(), now.getMonth(), 1)), toLocalDateStr(now)); break
|
|
||||||
case 'ytd': set(toLocalDateStr(new Date(now.getFullYear(), 0, 1)), toLocalDateStr(now)); break
|
|
||||||
case 'cosecha-20-21': set('2020-09-25', '2021-09-24'); break
|
|
||||||
case 'cosecha-21-22': set('2021-09-25', '2022-09-24'); break
|
|
||||||
case 'cosecha-22-23': set('2022-09-25', '2023-09-24'); break
|
|
||||||
case 'cosecha-23-24': set('2023-09-25', '2024-09-24'); break
|
|
||||||
case 'cosecha-24-25': set('2024-09-25', '2025-09-09'); break
|
|
||||||
case 'cosecha-25-26': set('2025-09-10', toLocalDateStr(now)); break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onManualDateChange() {
|
|
||||||
// Si el usuario modifica las fechas manualmente, cambiar a "Personalizado"
|
|
||||||
selectedPreset.value = 'custom'
|
|
||||||
console.log('Manual date change, preset set to custom')
|
|
||||||
}
|
|
||||||
|
|
||||||
async function onToggleAnulados(newValue: boolean | 'indeterminate') {
|
async function onToggleAnulados(newValue: boolean | 'indeterminate') {
|
||||||
if (newValue === true) {
|
if (newValue === true) {
|
||||||
// Pedir confirmación al activar
|
// Pedir confirmación al activar
|
||||||
@@ -335,12 +199,6 @@ async function onToggleAnulados(newValue: boolean | 'indeterminate') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearPreset() {
|
|
||||||
selectedPreset.value = ''
|
|
||||||
fechaDesde.value = null
|
|
||||||
fechaHasta.value = null
|
|
||||||
console.log('Preset cleared')
|
|
||||||
}
|
|
||||||
|
|
||||||
const rangoLegible = computed(() => {
|
const rangoLegible = computed(() => {
|
||||||
if (!fechaDesde.value && !fechaHasta.value) return 'Sin filtro de fecha'
|
if (!fechaDesde.value && !fechaHasta.value) return 'Sin filtro de fecha'
|
||||||
@@ -494,7 +352,7 @@ onMounted(async () => {
|
|||||||
console.error('Error loading data:', err)
|
console.error('Error loading data:', err)
|
||||||
} finally {
|
} finally {
|
||||||
// Default preset: cosecha 25-26
|
// Default preset: cosecha 25-26
|
||||||
selectPreset('cosecha-25-26')
|
selectedPreset.value = 'cosecha-25-26'
|
||||||
includeAnulados.value = false
|
includeAnulados.value = false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user