pagina panorama facturador en camino
This commit is contained in:
41
nuxt4-app/app/components/MetricCard.vue
Normal file
41
nuxt4-app/app/components/MetricCard.vue
Normal file
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<div
|
||||
class="p-4 rounded-lg border transition-all"
|
||||
:class="[variantClasses, props.class]"
|
||||
>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-xs uppercase tracking-wide opacity-80 mb-1">{{ label }}</span>
|
||||
<div class="flex items-baseline gap-2">
|
||||
<span class="text-2xl font-bold">{{ value }}</span>
|
||||
<span v-if="unit" class="text-sm opacity-70">{{ unit }}</span>
|
||||
</div>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
label: string
|
||||
value: string | number
|
||||
unit?: string
|
||||
variant?: 'default' | 'primary' | 'success' | 'danger' | 'warning' | 'info'
|
||||
class?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
variant: 'default'
|
||||
})
|
||||
|
||||
const variantClasses = computed(() => {
|
||||
const variants = {
|
||||
default: 'bg-[#1c140c] border-[#3a2a16] text-[var(--brand-text)]',
|
||||
primary: 'bg-[#1c140c] border-[#c08040] text-[var(--brand-primary)]',
|
||||
success: 'bg-[#1c140c] border-green-600/30 text-green-400',
|
||||
danger: 'bg-[#1c140c] border-red-600/30 text-red-400',
|
||||
warning: 'bg-[#1c140c] border-yellow-600/30 text-yellow-400',
|
||||
info: 'bg-[#1c140c] border-cyan-600/30 text-cyan-400'
|
||||
}
|
||||
return variants[props.variant]
|
||||
})
|
||||
</script>
|
||||
42
nuxt4-app/app/components/ingresos/InventariosDeposito.vue
Normal file
42
nuxt4-app/app/components/ingresos/InventariosDeposito.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<UCard class="brand-card border border-transparent">
|
||||
<template #header>
|
||||
<h2 class="text-xl font-bold brand-section-title">Inventarios en Depósito</h2>
|
||||
</template>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<MetricCard
|
||||
label="Total QQ Seco en Depósito"
|
||||
:value="metrics.totalQqSecoDeposito.value.toFixed(2)"
|
||||
unit="QQ"
|
||||
variant="warning"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Total QQ Mojado en Depósito"
|
||||
:value="metrics.totalQqMojadoDeposito.value.toFixed(2)"
|
||||
unit="QQ"
|
||||
variant="info"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Total QQ Oreado en Depósito"
|
||||
:value="metrics.totalQqOreadoDeposito.value.toFixed(2)"
|
||||
unit="QQ"
|
||||
variant="info"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Total Lb Uva en Depósito"
|
||||
:value="metrics.totalLbUvaDeposito.value.toFixed(2)"
|
||||
unit="lb"
|
||||
variant="info"
|
||||
/>
|
||||
</div>
|
||||
</UCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { IngresosMetrics } from '~/composables/useIngresosMetrics'
|
||||
|
||||
defineProps<{
|
||||
metrics: IngresosMetrics
|
||||
}>()
|
||||
</script>
|
||||
46
nuxt4-app/app/components/ingresos/InversionRestante.vue
Normal file
46
nuxt4-app/app/components/ingresos/InversionRestante.vue
Normal file
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<UCard class="brand-card border border-transparent">
|
||||
<template #header>
|
||||
<h2 class="text-xl font-bold brand-section-title">Inversión Restante a Realizar</h2>
|
||||
</template>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<MetricCard
|
||||
label="Inversión Restante Oreado"
|
||||
:value="formatCurrency(metrics.inversionRestanteOreado.value)"
|
||||
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
|
||||
label="Inversión Restante Esperada"
|
||||
:value="formatCurrency(metrics.inversionRestanteEsperada.value)"
|
||||
variant="danger"
|
||||
class="font-bold"
|
||||
/>
|
||||
</div>
|
||||
</UCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { IngresosMetrics } from '~/composables/useIngresosMetrics'
|
||||
|
||||
defineProps<{
|
||||
metrics: IngresosMetrics
|
||||
}>()
|
||||
|
||||
const formatCurrency = (value: number) => {
|
||||
return new Intl.NumberFormat('es-GT', {
|
||||
style: 'currency',
|
||||
currency: 'GTQ'
|
||||
}).format(value)
|
||||
}
|
||||
</script>
|
||||
46
nuxt4-app/app/components/ingresos/InversionTotal.vue
Normal file
46
nuxt4-app/app/components/ingresos/InversionTotal.vue
Normal file
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<UCard class="brand-card border border-transparent">
|
||||
<template #header>
|
||||
<h2 class="text-xl font-bold brand-section-title">Inversión Hasta la Fecha</h2>
|
||||
</template>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<MetricCard
|
||||
label="Inversión en Uva"
|
||||
:value="formatCurrency(metrics.inversionUva.value)"
|
||||
variant="success"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Inversión en Oreado"
|
||||
:value="formatCurrency(metrics.inversionOreado.value)"
|
||||
variant="success"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Inversión en Mojado"
|
||||
:value="formatCurrency(metrics.inversionMojado.value)"
|
||||
variant="success"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Total Invertido"
|
||||
:value="formatCurrency(metrics.totalInvertido.value)"
|
||||
variant="primary"
|
||||
class="font-bold"
|
||||
/>
|
||||
</div>
|
||||
</UCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { IngresosMetrics } from '~/composables/useIngresosMetrics'
|
||||
|
||||
defineProps<{
|
||||
metrics: IngresosMetrics
|
||||
}>()
|
||||
|
||||
const formatCurrency = (value: number) => {
|
||||
return new Intl.NumberFormat('es-GT', {
|
||||
style: 'currency',
|
||||
currency: 'GTQ'
|
||||
}).format(value)
|
||||
}
|
||||
</script>
|
||||
44
nuxt4-app/app/components/ingresos/SecosVendidos.vue
Normal file
44
nuxt4-app/app/components/ingresos/SecosVendidos.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<UCard class="brand-card border border-transparent">
|
||||
<template #header>
|
||||
<h2 class="text-xl font-bold brand-section-title">Secos Vendidos y Pérdidas</h2>
|
||||
</template>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<MetricCard
|
||||
label="Total QQ Secos por Vender"
|
||||
:value="metrics.totalQqSecoPorVender.value.toFixed(2)"
|
||||
unit="QQ"
|
||||
variant="info"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Precio de Venta Promedio por QQ"
|
||||
:value="formatCurrency(metrics.precioVentaPromedioPorQq.value)"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Precio de Compra Promedio por QQ"
|
||||
:value="formatCurrency(metrics.precioCompraPromedioPorQq.value)"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Margen de Ganancia por QQ"
|
||||
:value="formatCurrency(metrics.margenGananciaPorQq.value)"
|
||||
:variant="metrics.margenGananciaPorQq.value > 0 ? 'success' : 'danger'"
|
||||
/>
|
||||
</div>
|
||||
</UCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { IngresosMetrics } from '~/composables/useIngresosMetrics'
|
||||
|
||||
defineProps<{
|
||||
metrics: IngresosMetrics
|
||||
}>()
|
||||
|
||||
const formatCurrency = (value: number) => {
|
||||
return new Intl.NumberFormat('es-GT', {
|
||||
style: 'currency',
|
||||
currency: 'GTQ'
|
||||
}).format(value)
|
||||
}
|
||||
</script>
|
||||
45
nuxt4-app/app/components/ingresos/TotalesIngresoCompra.vue
Normal file
45
nuxt4-app/app/components/ingresos/TotalesIngresoCompra.vue
Normal file
@@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<UCard class="brand-card border border-transparent">
|
||||
<template #header>
|
||||
<h2 class="text-xl font-bold brand-section-title">Totales de Ingreso y Compra</h2>
|
||||
</template>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<MetricCard
|
||||
label="Total QQ Seco Ingresado"
|
||||
:value="metrics.totalQqSecoIngresado.value.toFixed(2)"
|
||||
unit="QQ"
|
||||
variant="primary"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Total QQ Seco Comprado"
|
||||
:value="metrics.totalQqSecoComprado.value.toFixed(2)"
|
||||
unit="QQ"
|
||||
variant="success"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Precio Promedio Ponderado Uva"
|
||||
:value="metrics.precioPromedioUvaPorQqLb.value.toFixed(2)"
|
||||
unit="$/lb"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Precio Promedio Ponderado Oreado"
|
||||
:value="metrics.precioPromedioOreadoPorQq.value.toFixed(2)"
|
||||
unit="$/QQ"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Precio Promedio Ponderado Mojado"
|
||||
:value="metrics.precioPromedioMojadoPorQq.value.toFixed(2)"
|
||||
unit="$/QQ"
|
||||
/>
|
||||
</div>
|
||||
</UCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { IngresosMetrics } from '~/composables/useIngresosMetrics'
|
||||
|
||||
defineProps<{
|
||||
metrics: IngresosMetrics
|
||||
}>()
|
||||
</script>
|
||||
56
nuxt4-app/app/components/ingresos/TotalesVerde.vue
Normal file
56
nuxt4-app/app/components/ingresos/TotalesVerde.vue
Normal file
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<UCard class="brand-card border border-transparent">
|
||||
<template #header>
|
||||
<h2 class="text-xl font-bold brand-section-title">Totales Netos de Verde</h2>
|
||||
</template>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<MetricCard
|
||||
label="Total Lb Neto de Verde"
|
||||
:value="metrics.totalLbNetoVerde.value.toFixed(2)"
|
||||
unit="lb"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Precio Promedio Ponderado Pagado"
|
||||
:value="metrics.precioPromedioVerdePagado.value.toFixed(2)"
|
||||
unit="$/lb"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Total Lb Neto de Verde en Depósito"
|
||||
:value="metrics.totalLbNetoVerdeDeposito.value.toFixed(2)"
|
||||
unit="lb"
|
||||
variant="info"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Inversión en Verde Hasta la Fecha"
|
||||
:value="formatCurrency(metrics.inversionVerdeHastaFecha.value)"
|
||||
variant="success"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Inversión Restante a Realizar en Verde"
|
||||
:value="formatCurrency(metrics.inversionRestanteVerde.value)"
|
||||
variant="warning"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Total Lb Neto Comprado de Verde"
|
||||
:value="metrics.totalLbNetoCompradoVerde.value.toFixed(2)"
|
||||
unit="lb"
|
||||
/>
|
||||
</div>
|
||||
</UCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { IngresosMetrics } from '~/composables/useIngresosMetrics'
|
||||
|
||||
defineProps<{
|
||||
metrics: IngresosMetrics
|
||||
}>()
|
||||
|
||||
const formatCurrency = (value: number) => {
|
||||
return new Intl.NumberFormat('es-GT', {
|
||||
style: 'currency',
|
||||
currency: 'GTQ'
|
||||
}).format(value)
|
||||
}
|
||||
</script>
|
||||
53
nuxt4-app/app/components/rechazos/RechazoCard.vue
Normal file
53
nuxt4-app/app/components/rechazos/RechazoCard.vue
Normal file
@@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<div class="bg-[#1c140c] rounded-lg p-4 border-l-4" :class="borderColor">
|
||||
<h3 class="text-lg font-semibold mb-3 capitalize text-[var(--brand-text)]">{{ title }}</h3>
|
||||
<div class="space-y-2">
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-[var(--brand-text-muted)] text-sm">Total {{ unidad }}:</span>
|
||||
<span class="font-medium text-[var(--brand-text)]">{{ metrics.value.totalCantidad.toFixed(2) }} {{ unidad }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-[var(--brand-text-muted)] text-sm">Precio promedio:</span>
|
||||
<span class="font-medium text-[var(--brand-text)]">{{ formatCurrency(metrics.value.precioPromedio) }}</span>
|
||||
</div>
|
||||
<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="font-bold text-green-400">{{ formatCurrency(metrics.value.totalCobrado) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { RechazoMetrics } from '~/composables/useRechazosMetrics'
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
metrics: ComputedRef<RechazoMetrics>
|
||||
unidad: 'libras' | 'galones'
|
||||
color?: 'blue' | 'green' | 'yellow' | 'red' | 'purple' | 'pink'
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
color: 'blue'
|
||||
})
|
||||
|
||||
const borderColor = computed(() => {
|
||||
const colors = {
|
||||
blue: 'border-blue-500',
|
||||
green: 'border-green-500',
|
||||
yellow: 'border-yellow-500',
|
||||
red: 'border-red-500',
|
||||
purple: 'border-purple-500',
|
||||
pink: 'border-pink-500'
|
||||
}
|
||||
return colors[props.color]
|
||||
})
|
||||
|
||||
const formatCurrency = (value: number) => {
|
||||
return new Intl.NumberFormat('es-GT', {
|
||||
style: 'currency',
|
||||
currency: 'GTQ'
|
||||
}).format(value)
|
||||
}
|
||||
</script>
|
||||
69
nuxt4-app/app/components/rechazos/RechazosSubproductos.vue
Normal file
69
nuxt4-app/app/components/rechazos/RechazosSubproductos.vue
Normal file
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<UCard class="brand-card border border-transparent">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<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="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>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<RechazosRechazoCard
|
||||
title="Chibolita"
|
||||
:metrics="metrics.chibolita"
|
||||
unidad="libras"
|
||||
color="blue"
|
||||
/>
|
||||
<RechazosRechazoCard
|
||||
title="Perico"
|
||||
:metrics="metrics.perico"
|
||||
unidad="libras"
|
||||
color="green"
|
||||
/>
|
||||
<RechazosRechazoCard
|
||||
title="Vano"
|
||||
:metrics="metrics.vano"
|
||||
unidad="galones"
|
||||
color="yellow"
|
||||
/>
|
||||
<RechazosRechazoCard
|
||||
title="Picadillo"
|
||||
:metrics="metrics.picadillo"
|
||||
unidad="galones"
|
||||
color="red"
|
||||
/>
|
||||
<RechazosRechazoCard
|
||||
title="Magalla"
|
||||
:metrics="metrics.magalla"
|
||||
unidad="galones"
|
||||
color="purple"
|
||||
/>
|
||||
<RechazosRechazoCard
|
||||
title="Pinta"
|
||||
:metrics="metrics.pinta"
|
||||
unidad="libras"
|
||||
color="pink"
|
||||
/>
|
||||
</div>
|
||||
</UCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { RechazosMetrics } from '~/composables/useRechazosMetrics'
|
||||
|
||||
const props = defineProps<{
|
||||
metrics: RechazosMetrics
|
||||
}>()
|
||||
|
||||
const totalRechazos = computed(() => props.metrics.totalRechazos)
|
||||
|
||||
const formatCurrency = (value: number) => {
|
||||
return new Intl.NumberFormat('es-GT', {
|
||||
style: 'currency',
|
||||
currency: 'GTQ'
|
||||
}).format(value)
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user