179 lines
5.1 KiB
Vue
179 lines
5.1 KiB
Vue
<template>
|
|
<div class="flex flex-col gap-3">
|
|
<!-- Versión ultra compacta de MetadatosCard -->
|
|
<div v-if="ingresosMetadata" class="flex flex-col gap-3">
|
|
<!-- Header compacto -->
|
|
<div class="flex items-center justify-between pb-2 border-b border-[var(--brand-border)]">
|
|
<h3 class="text-sm font-bold text-[var(--brand-text)]">{{ ingresosMetadata.table }}</h3>
|
|
<span class="text-xs font-semibold text-[var(--brand-primary)]">
|
|
{{ formatNumber(recordCount) }}
|
|
</span>
|
|
</div>
|
|
|
|
<!-- Info grid compacto -->
|
|
<div class="grid grid-cols-2 gap-x-3 gap-y-2 text-xs">
|
|
<div>
|
|
<dt class="text-[var(--brand-text-muted)] uppercase text-[10px]">Tamaño</dt>
|
|
<dd class="font-medium text-[var(--brand-text)]">{{ formatSize(ingresosMetadata.approxSizeBytes) }}</dd>
|
|
</div>
|
|
<div>
|
|
<dt class="text-[var(--brand-text-muted)] uppercase text-[10px]">Desde</dt>
|
|
<dd class="font-medium text-[var(--brand-text)]">{{ formatDate(ingresosMetadata.createdAtRange?.from) }}</dd>
|
|
</div>
|
|
<div class="col-span-2">
|
|
<dt class="text-[var(--brand-text-muted)] uppercase text-[10px]">Columnas ({{ ingresosMetadata.columns?.length || 0 }})</dt>
|
|
<dd class="font-medium text-[var(--brand-text)] truncate text-[10px]">
|
|
{{ (ingresosMetadata.columns || []).slice(0, 5).join(', ') }}{{ (ingresosMetadata.columns?.length || 0) > 5 ? '...' : '' }}
|
|
</dd>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Última actualización -->
|
|
<div class="text-[10px] text-[var(--brand-text-muted)] pt-2 border-t border-[var(--brand-border)]">
|
|
{{ tableStore ? tableStore.formattedLastUpdated : 'Sin datos' }}
|
|
</div>
|
|
|
|
<!-- Botones de acción compactos -->
|
|
<div class="flex gap-2">
|
|
<UButton
|
|
:loading="isLoadingLatest"
|
|
:disabled="isLoadingAll"
|
|
size="xs"
|
|
color="primary"
|
|
variant="soft"
|
|
@click="loadLatestData"
|
|
block
|
|
>
|
|
<template #leading>
|
|
<UIcon name="i-lucide-clock" class="w-3 h-3" />
|
|
</template>
|
|
Últimos
|
|
</UButton>
|
|
|
|
<UButton
|
|
:loading="isLoadingAll"
|
|
:disabled="isLoadingLatest"
|
|
size="xs"
|
|
color="primary"
|
|
variant="outline"
|
|
@click="loadAllData"
|
|
block
|
|
>
|
|
<template #leading>
|
|
<UIcon name="i-lucide-database" class="w-3 h-3" />
|
|
</template>
|
|
Todos
|
|
</UButton>
|
|
</div>
|
|
|
|
<!-- Progress bar compacto -->
|
|
<UProgress
|
|
v-if="isLoadingLatest || isLoadingAll"
|
|
:model-value="loadingProgress"
|
|
:max="100"
|
|
size="xs"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useTableDataStore } from '~/stores/tableDataFactory'
|
|
|
|
interface Props {
|
|
ingresosMetadata: any
|
|
}
|
|
|
|
const props = defineProps<Props>()
|
|
|
|
const { $getTableStore } = useNuxtApp()
|
|
|
|
// Loading states
|
|
const isLoadingLatest = ref(false)
|
|
const isLoadingAll = ref(false)
|
|
const loadingProgress = ref(0)
|
|
|
|
// Get the table store
|
|
const tableStore = computed(() => {
|
|
if (typeof $getTableStore === 'function') {
|
|
return $getTableStore(props.ingresosMetadata.name)
|
|
}
|
|
return useTableDataStore(props.ingresosMetadata.name)
|
|
})
|
|
|
|
// Calculate record count
|
|
const recordCount = computed(() => {
|
|
return tableStore.value?.recordCount || 0
|
|
})
|
|
|
|
async function loadLatestData() {
|
|
isLoadingLatest.value = true
|
|
loadingProgress.value = 0
|
|
|
|
try {
|
|
const store = tableStore.value
|
|
if (!store) return
|
|
|
|
await store.loadLatestDataInBatches((progress) => {
|
|
loadingProgress.value = progress
|
|
})
|
|
|
|
loadingProgress.value = 100
|
|
} catch (error) {
|
|
console.error('Error loading latest data:', error)
|
|
} finally {
|
|
setTimeout(() => {
|
|
isLoadingLatest.value = false
|
|
loadingProgress.value = 0
|
|
}, 500)
|
|
}
|
|
}
|
|
|
|
async function loadAllData() {
|
|
isLoadingAll.value = true
|
|
loadingProgress.value = 0
|
|
|
|
try {
|
|
const store = tableStore.value
|
|
if (!store) return
|
|
|
|
await store.loadAllDataInBatches((progress) => {
|
|
loadingProgress.value = progress
|
|
})
|
|
|
|
loadingProgress.value = 100
|
|
} catch (error) {
|
|
console.error('Error loading all data:', error)
|
|
} finally {
|
|
setTimeout(() => {
|
|
isLoadingAll.value = false
|
|
loadingProgress.value = 0
|
|
}, 500)
|
|
}
|
|
}
|
|
|
|
function formatSize(bytes: number | null | undefined): string {
|
|
if (!bytes) return 'N/A'
|
|
if (bytes < 1024) return `${bytes} B`
|
|
const units = ['KB', 'MB', 'GB']
|
|
let size = bytes / 1024
|
|
let unitIndex = 0
|
|
while (size >= 1024 && unitIndex < units.length - 1) {
|
|
size /= 1024
|
|
unitIndex++
|
|
}
|
|
return `${size.toFixed(1)} ${units[unitIndex]}`
|
|
}
|
|
|
|
function formatDate(value: string | null | undefined): string {
|
|
if (!value) return '—'
|
|
const date = new Date(value)
|
|
if (Number.isNaN(date.getTime())) return value
|
|
return date.toLocaleDateString('es-ES', { year: 'numeric', month: 'short', day: 'numeric' })
|
|
}
|
|
|
|
function formatNumber(value: number): string {
|
|
return new Intl.NumberFormat('es-ES').format(value)
|
|
}
|
|
</script>
|