Implementar sistema completo de trazabilidad de lotes
Some checks failed
build-and-deploy / build-and-deploy (push) Failing after 1m47s
Some checks failed
build-and-deploy / build-and-deploy (push) Failing after 1m47s
- Agregar PostgreSQL 16 con esquema completo - Crear API endpoints para lotes y operaciones - Implementar UI con Nuxt UI (tablas, formularios, trazabilidad) - Agregar datos de ejemplo del flujo completo - Documentar sistema en PLAN_TRAZABILIDAD.md
This commit is contained in:
147
nuxt4/app/components/lotes/LoteForm.vue
Normal file
147
nuxt4/app/components/lotes/LoteForm.vue
Normal file
@@ -0,0 +1,147 @@
|
||||
<template>
|
||||
<UCard>
|
||||
<template #header>
|
||||
<h3 class="text-lg font-semibold">
|
||||
{{ lote ? 'Editar Lote' : 'Nuevo Lote' }}
|
||||
</h3>
|
||||
</template>
|
||||
|
||||
<UForm :state="formState" @submit="handleSubmit" class="space-y-4">
|
||||
<UFormGroup label="Código" name="codigo" help="Opcional - Si no se especifica, se generará automáticamente">
|
||||
<UInput
|
||||
v-model="formState.codigo"
|
||||
placeholder="Ej: UVA-001, SEC-042"
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Tipo" name="tipo" required>
|
||||
<USelect
|
||||
v-model="formState.tipo"
|
||||
:options="TIPOS_LOTE"
|
||||
placeholder="Selecciona un tipo"
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Cantidad (kg)" name="cantidad_kg">
|
||||
<UInput
|
||||
v-model.number="formState.cantidad_kg"
|
||||
type="number"
|
||||
step="0.01"
|
||||
placeholder="0.00"
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Lugar ID" name="lugar_id" help="Opcional - ID del lugar donde se encuentra">
|
||||
<UInput
|
||||
v-model.number="formState.lugar_id"
|
||||
type="number"
|
||||
placeholder="1"
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Información Adicional (JSON)" name="meta" help="Opcional - Datos adicionales en formato JSON">
|
||||
<UTextarea
|
||||
v-model="metaText"
|
||||
placeholder='{"humedad": 12.5, "notas": "café especial"}'
|
||||
rows="3"
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
<div class="flex gap-2 justify-end">
|
||||
<UButton
|
||||
type="button"
|
||||
variant="outline"
|
||||
label="Cancelar"
|
||||
@click="$emit('cancel')"
|
||||
/>
|
||||
<UButton
|
||||
type="submit"
|
||||
:loading="loading"
|
||||
:label="lote ? 'Actualizar' : 'Crear'"
|
||||
/>
|
||||
</div>
|
||||
</UForm>
|
||||
</UCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Lote } from '~/composables/useLotes'
|
||||
|
||||
const props = defineProps<{
|
||||
lote?: Lote | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
cancel: []
|
||||
success: [lote: Lote]
|
||||
}>()
|
||||
|
||||
const { createLote, updateLote, TIPOS_LOTE } = useLotes()
|
||||
|
||||
const loading = ref(false)
|
||||
const metaText = ref('')
|
||||
|
||||
const formState = ref({
|
||||
codigo: '',
|
||||
tipo: '',
|
||||
cantidad_kg: undefined as number | undefined,
|
||||
lugar_id: undefined as number | undefined,
|
||||
})
|
||||
|
||||
// Si hay un lote para editar, cargar sus datos
|
||||
watchEffect(() => {
|
||||
if (props.lote) {
|
||||
formState.value = {
|
||||
codigo: props.lote.codigo || '',
|
||||
tipo: props.lote.tipo,
|
||||
cantidad_kg: props.lote.cantidad_kg || undefined,
|
||||
lugar_id: props.lote.lugar_id || undefined,
|
||||
}
|
||||
metaText.value = props.lote.meta ? JSON.stringify(props.lote.meta, null, 2) : ''
|
||||
}
|
||||
})
|
||||
|
||||
const handleSubmit = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
// Parsear meta si existe
|
||||
let meta = null
|
||||
if (metaText.value.trim()) {
|
||||
try {
|
||||
meta = JSON.parse(metaText.value)
|
||||
} catch (err) {
|
||||
useToast().add({
|
||||
title: 'Error',
|
||||
description: 'El formato JSON de información adicional no es válido',
|
||||
color: 'red',
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const data = {
|
||||
codigo: formState.value.codigo || undefined,
|
||||
tipo: formState.value.tipo,
|
||||
cantidad_kg: formState.value.cantidad_kg,
|
||||
lugar_id: formState.value.lugar_id,
|
||||
meta,
|
||||
}
|
||||
|
||||
let result: Lote | null = null
|
||||
|
||||
if (props.lote) {
|
||||
// Actualizar lote existente
|
||||
result = await updateLote(props.lote.id, data)
|
||||
} else {
|
||||
// Crear nuevo lote
|
||||
result = await createLote(data)
|
||||
}
|
||||
|
||||
if (result) {
|
||||
emit('success', result)
|
||||
}
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user