Agregar componente RechazosSubproductos para panorama facturador
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 5m28s
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 5m28s
This commit is contained in:
118
nuxt4-app/app/components/RechazosSubproductos.vue
Normal file
118
nuxt4-app/app/components/RechazosSubproductos.vue
Normal file
@@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<UCard class="brand-card border border-transparent">
|
||||
<template #header>
|
||||
<h2 class="text-xl font-bold brand-section-title">Rechazos y Subproductos</h2>
|
||||
<p class="text-sm text-[var(--brand-text-muted)] mt-1">Resumen de rechazos por tipo</p>
|
||||
</template>
|
||||
|
||||
<div v-if="data && data.length > 0" class="overflow-x-auto">
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
<tr class="border-b border-[#3a2a16]">
|
||||
<th class="text-left py-3 px-4 text-xs text-[var(--brand-text-muted)] uppercase tracking-wide">Tipo</th>
|
||||
<th class="text-right py-3 px-4 text-xs text-[var(--brand-text-muted)] uppercase tracking-wide">Registros</th>
|
||||
<th class="text-right py-3 px-4 text-xs text-[var(--brand-text-muted)] uppercase tracking-wide">Cantidad Total</th>
|
||||
<th class="text-right py-3 px-4 text-xs text-[var(--brand-text-muted)] uppercase tracking-wide">Total Cobrado</th>
|
||||
<th class="text-right py-3 px-4 text-xs text-[var(--brand-text-muted)] uppercase tracking-wide">Precio Promedio</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="(rechazo, index) in data"
|
||||
:key="rechazo.tipo"
|
||||
class="border-b border-[#3a2a16] hover:bg-[#2a1f0f] transition-colors"
|
||||
>
|
||||
<td class="py-3 px-4 text-[var(--brand-text)] capitalize font-medium">
|
||||
{{ rechazo.tipo }}
|
||||
</td>
|
||||
<td class="py-3 px-4 text-right text-[var(--brand-text)]">
|
||||
{{ rechazo.num_registros }}
|
||||
</td>
|
||||
<td class="py-3 px-4 text-right text-[var(--brand-text)]">
|
||||
{{ formatNumber(rechazo.total_cantidad) }}
|
||||
</td>
|
||||
<td class="py-3 px-4 text-right text-green-400 font-semibold">
|
||||
{{ formatCurrency(rechazo.total_cobrado) }}
|
||||
</td>
|
||||
<td class="py-3 px-4 text-right text-[var(--brand-text-muted)]">
|
||||
{{ formatCurrency(rechazo.precio_promedio) }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot class="border-t-2 border-[#3a2a16] bg-[#1c140c]">
|
||||
<tr>
|
||||
<td class="py-3 px-4 text-[var(--brand-text)] font-bold uppercase text-sm">Total</td>
|
||||
<td class="py-3 px-4 text-right text-[var(--brand-text)] font-bold">
|
||||
{{ totalRegistros }}
|
||||
</td>
|
||||
<td class="py-3 px-4 text-right text-[var(--brand-text)] font-bold">
|
||||
{{ formatNumber(totalCantidad) }}
|
||||
</td>
|
||||
<td class="py-3 px-4 text-right text-green-400 font-bold">
|
||||
{{ formatCurrency(totalCobrado) }}
|
||||
</td>
|
||||
<td class="py-3 px-4 text-right text-[var(--brand-text-muted)]">
|
||||
{{ formatCurrency(promedioGeneral) }}
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div v-else class="text-center py-8 text-[var(--brand-text-muted)]">
|
||||
No hay rechazos registrados en este período
|
||||
</div>
|
||||
</UCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
interface Rechazo {
|
||||
tipo: string
|
||||
num_registros: number
|
||||
total_cantidad: number
|
||||
total_cobrado: number
|
||||
precio_promedio: number
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
data: Rechazo[]
|
||||
}>()
|
||||
|
||||
const totalRegistros = computed(() => {
|
||||
if (!props.data || props.data.length === 0) return 0
|
||||
return props.data.reduce((sum, r) => sum + r.num_registros, 0)
|
||||
})
|
||||
|
||||
const totalCantidad = computed(() => {
|
||||
if (!props.data || props.data.length === 0) return 0
|
||||
return props.data.reduce((sum, r) => sum + r.total_cantidad, 0)
|
||||
})
|
||||
|
||||
const totalCobrado = computed(() => {
|
||||
if (!props.data || props.data.length === 0) return 0
|
||||
return props.data.reduce((sum, r) => sum + r.total_cobrado, 0)
|
||||
})
|
||||
|
||||
const promedioGeneral = computed(() => {
|
||||
if (!props.data || props.data.length === 0 || totalCantidad.value === 0) return 0
|
||||
return totalCobrado.value / totalCantidad.value
|
||||
})
|
||||
|
||||
const formatNumber = (value: number) => {
|
||||
if (!value) return '0.00'
|
||||
return new Intl.NumberFormat('es-HN', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
}).format(value)
|
||||
}
|
||||
|
||||
const formatCurrency = (value: number) => {
|
||||
if (!value) return 'L 0.00'
|
||||
return new Intl.NumberFormat('es-HN', {
|
||||
style: 'currency',
|
||||
currency: 'HNL',
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
}).format(value).replace('HNL', 'L')
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user