This commit is contained in:
@@ -26,11 +26,11 @@
|
||||
<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="(e) => onManualDateChange('desde', e)" />
|
||||
<UInput :model-value="fechaDesde" type="date" @input="(e: Event) => onManualDateChange('desde', e)" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-xs text-[var(--brand-text-muted)]">Fecha hasta</label>
|
||||
<UInput :model-value="fechaHasta" type="date" @input="(e) => onManualDateChange('hasta', e)" />
|
||||
<UInput :model-value="fechaHasta" type="date" @input="(e: Event) => onManualDateChange('hasta', e)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -138,7 +138,7 @@ function setToday() {
|
||||
|
||||
// Watch para aplicar el preset cuando cambia (incluyendo el valor inicial)
|
||||
watch(() => props.selectedPreset, (newPreset) => {
|
||||
if (newPreset && newPreset !== 'custom' && newPreset !== '') {
|
||||
if (newPreset !== '' && newPreset !== 'custom') {
|
||||
selectPreset(newPreset)
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
compact && tableStore?.isStale ? 'bg-yellow-500/10 border-l-4 !border-l-yellow-500' : ''
|
||||
]"
|
||||
@click="toggleCompact"
|
||||
:ui="compact ? { body: { padding: '0' }, header: { padding: 'px-3 py-2' }, footer: { padding: '0' } } : {}"
|
||||
:ui="compact ? { body: 'p-0', header: 'px-3 py-2', footer: 'p-0' } : {}"
|
||||
>
|
||||
<template v-if="compact" #header>
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
@@ -38,7 +38,7 @@
|
||||
:loading="isLoadingLatest"
|
||||
:disabled="isLoadingAll"
|
||||
:ui="{ base: tableStore?.isStale ? 'bg-yellow-500 text-black border-0 hover:bg-yellow-400 font-bold' : 'bg-[#c08040] text-[#1b1209] border-0 hover:bg-[#d99a56]' }"
|
||||
size="2xs"
|
||||
size="xs"
|
||||
icon="i-lucide-clock"
|
||||
@click.stop="loadLatestData"
|
||||
:class="{ 'animate-spin': isLoadingLatest, 'animate-bounce': tableStore?.isStale && !isLoadingLatest }"
|
||||
@@ -48,7 +48,7 @@
|
||||
:loading="isLoadingAll"
|
||||
:disabled="isLoadingLatest"
|
||||
:ui="{ base: tableStore?.isStale ? 'bg-yellow-500 text-black border-0 hover:bg-yellow-400 font-bold' : 'bg-[#c08040] text-[#1b1209] border-0 hover:bg-[#d99a56]' }"
|
||||
size="2xs"
|
||||
size="xs"
|
||||
icon="i-lucide-database"
|
||||
@click.stop="loadAllData"
|
||||
:class="{ 'animate-spin': isLoadingAll }"
|
||||
@@ -58,7 +58,7 @@
|
||||
icon="i-lucide-chevron-down"
|
||||
color="neutral"
|
||||
variant="ghost"
|
||||
size="2xs"
|
||||
size="xs"
|
||||
@click.stop="toggleCompact"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -105,10 +105,10 @@ defineEmits<{
|
||||
// Compute initials from name
|
||||
const clienteInitials = computed(() => {
|
||||
const names = props.cliente.name.trim().split(' ')
|
||||
if (names.length >= 2) {
|
||||
if (names.length >= 2 && names[0] && names[1]) {
|
||||
return (names[0][0] + names[1][0]).toUpperCase()
|
||||
}
|
||||
return names[0].substring(0, 2).toUpperCase()
|
||||
return names[0]?.substring(0, 2).toUpperCase() || 'XX'
|
||||
})
|
||||
|
||||
// Format date helper
|
||||
|
||||
@@ -228,7 +228,7 @@
|
||||
class="text-[10px] text-blue-400 font-medium"
|
||||
title="Acumulado hasta la fecha actual"
|
||||
>
|
||||
↗ {{ formatTotal(cosecha.totalALaFecha) }}
|
||||
↗ {{ formatTotal(cosecha.totalALaFecha || 0) }}
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
@@ -344,14 +344,14 @@
|
||||
class="text-[10px] text-blue-400 font-medium"
|
||||
title="Acumulado hasta la fecha actual"
|
||||
>
|
||||
↗ {{ formatTotal(cosecha.totalALaFecha) }}
|
||||
↗ {{ formatTotal(cosecha.totalALaFecha || 0) }}
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="text-[10px] text-gray-500 italic"
|
||||
title="Sin datos hasta la fecha actual"
|
||||
>
|
||||
{{ formatTotal(cosecha.totalALaFecha) }}
|
||||
{{ formatTotal(cosecha.totalALaFecha || 0) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -853,7 +853,7 @@ function getDiaDelAnio(mes: number, dia: number, esBisiesto: boolean): number {
|
||||
|
||||
let diaDelAnio = 0
|
||||
for (let i = 0; i < mes - 1; i++) {
|
||||
diaDelAnio += diasPorMes[i]
|
||||
diaDelAnio += diasPorMes[i] || 0
|
||||
}
|
||||
diaDelAnio += dia - 1 // -1 porque empezamos en día 0
|
||||
|
||||
@@ -1093,7 +1093,7 @@ async function toggleFullscreen() {
|
||||
try {
|
||||
if (!document.fullscreenElement) {
|
||||
// Entrar a pantalla completa
|
||||
await cardContainer.value.$el.requestFullscreen()
|
||||
await cardContainer.value.requestFullscreen()
|
||||
isFullscreen.value = true
|
||||
} else {
|
||||
// Salir de pantalla completa
|
||||
@@ -1130,7 +1130,7 @@ onMounted(() => {
|
||||
document.addEventListener('fullscreenchange', handleFullscreenChange)
|
||||
|
||||
// Agregar listener para zoom con rueda del mouse
|
||||
const container = cardContainer.value?.$el
|
||||
const container = cardContainer.value
|
||||
if (container) {
|
||||
container.addEventListener('wheel', handleWheel, { passive: false })
|
||||
}
|
||||
@@ -1140,7 +1140,7 @@ onUnmounted(() => {
|
||||
document.removeEventListener('fullscreenchange', handleFullscreenChange)
|
||||
|
||||
// Remover listener de zoom
|
||||
const container = cardContainer.value?.$el
|
||||
const container = cardContainer.value
|
||||
if (container) {
|
||||
container.removeEventListener('wheel', handleWheel)
|
||||
}
|
||||
|
||||
@@ -243,8 +243,9 @@ const maxPesoPorTipo = computed(() => {
|
||||
let max = 0
|
||||
datosCosechas.value.forEach(cosecha => {
|
||||
tipos.forEach(tipo => {
|
||||
if (cosecha.pesosPorTipo[tipo] > max) {
|
||||
max = cosecha.pesosPorTipo[tipo]
|
||||
const valor = cosecha.pesosPorTipo[tipo]
|
||||
if (valor !== undefined && valor > max) {
|
||||
max = valor
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -255,8 +256,9 @@ const maxCantidadPorTipo = computed(() => {
|
||||
let max = 0
|
||||
datosCosechas.value.forEach(cosecha => {
|
||||
tipos.forEach(tipo => {
|
||||
if (cosecha.cantidadPorTipo[tipo] > max) {
|
||||
max = cosecha.cantidadPorTipo[tipo]
|
||||
const valor = cosecha.cantidadPorTipo[tipo]
|
||||
if (valor !== undefined && valor > max) {
|
||||
max = valor
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -312,8 +314,8 @@ function getCosechaColor(cosechaIdOrIndex: string | number): string {
|
||||
return colores[index % colores.length]
|
||||
}
|
||||
|
||||
// Si es un número, buscar el ID de la cosecha en datosPorTipo
|
||||
const cosecha = datosPorTipo.value[cosechaIdOrIndex]
|
||||
// Si es un número, buscar el ID de la cosecha en datosCosechas
|
||||
const cosecha = datosCosechas.value[cosechaIdOrIndex]
|
||||
if (cosecha?.id) {
|
||||
const index = cosechaColorMap[cosecha.id] ?? cosechaIdOrIndex
|
||||
return colores[index % colores.length]
|
||||
|
||||
@@ -183,12 +183,23 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Cliente } from '~/composables/useClienteSelector'
|
||||
interface Cliente {
|
||||
id: number
|
||||
name: string
|
||||
cedula?: number
|
||||
ubicacion?: string
|
||||
telefono?: string
|
||||
}
|
||||
|
||||
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 {
|
||||
clientes: Cliente[]
|
||||
selectedClienteIds: number[]
|
||||
selectedPreset: string
|
||||
selectedPreset: PresetValue
|
||||
fechaDesde: string | null
|
||||
fechaHasta: string | null
|
||||
selectedTipos: string[]
|
||||
@@ -207,7 +218,7 @@ const props = defineProps<Props>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:selectedClienteIds': [value: number[]]
|
||||
'update:selectedPreset': [value: string]
|
||||
'update:selectedPreset': [value: PresetValue]
|
||||
'update:fechaDesde': [value: string | null]
|
||||
'update:fechaHasta': [value: string | null]
|
||||
'update:selectedTipos': [value: string[]]
|
||||
|
||||
@@ -260,8 +260,9 @@ function getPresetLabel(): string {
|
||||
'cosecha-25-26': 'Cosecha 25-26'
|
||||
}
|
||||
|
||||
if (props.selectedPreset && props.selectedPreset !== 'custom' && presetLabels[props.selectedPreset]) {
|
||||
return presetLabels[props.selectedPreset]
|
||||
const label = props.selectedPreset && props.selectedPreset !== 'custom' ? presetLabels[props.selectedPreset] : undefined
|
||||
if (label) {
|
||||
return label
|
||||
}
|
||||
|
||||
// Si es personalizado, mostrar las fechas
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
v-for="tipo in tipos"
|
||||
:key="tipo.value"
|
||||
:model-value="tiposSeleccionados.includes(tipo.value)"
|
||||
@update:model-value="(checked) => toggleTipo(tipo.value, checked)"
|
||||
@update:model-value="(checked: boolean) => toggleTipo(tipo.value, checked)"
|
||||
:label="getTipoLabel(tipo)"
|
||||
:disabled="isTipoDisabled(tipo.value)"
|
||||
size="xs"
|
||||
|
||||
@@ -159,10 +159,10 @@ export function createTableDataStore<T = Record<string, unknown>>(
|
||||
})
|
||||
|
||||
if (response && typeof response === 'object' && 'records' in response) {
|
||||
const dataset = response as { records?: T[] }
|
||||
const dataset = response as { records?: any[] }
|
||||
this.data = Array.isArray(dataset.records) ? dataset.records : []
|
||||
} else if (Array.isArray(response)) {
|
||||
this.data = response as T[]
|
||||
this.data = response
|
||||
} else {
|
||||
this.data = []
|
||||
}
|
||||
@@ -322,7 +322,7 @@ export function createTableDataStore<T = Record<string, unknown>>(
|
||||
|
||||
if (response.records && response.records.length > 0) {
|
||||
console.log(`[${tableName}] loadAllDataInBatches: Got ${response.records.length} records`)
|
||||
this.data.push(...(response.records as T[]))
|
||||
this.data.push(...response.records)
|
||||
totalFetched += response.records.length
|
||||
console.log(`[${tableName}] loadAllDataInBatches: Total fetched so far: ${totalFetched}, data.length: ${this.data.length}`)
|
||||
|
||||
@@ -442,7 +442,7 @@ export function createTableDataStore<T = Record<string, unknown>>(
|
||||
console.log(`[${tableName}] loadLatestDataInBatches: ${newRecords.length} new records after filtering`)
|
||||
|
||||
if (newRecords.length > 0) {
|
||||
this.data.unshift(...(newRecords as T[]))
|
||||
this.data.unshift(...newRecords)
|
||||
newRecordsCount += newRecords.length
|
||||
console.log(`[${tableName}] loadLatestDataInBatches: Total new records: ${newRecordsCount}, data.length: ${this.data.length}`)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user