Files
seguidorDeLotes/nuxt4/app/components/lotes/LoteForm.vue
josedario87 ee3dffa38e
Some checks failed
build-and-deploy / build-and-deploy (push) Failing after 1m47s
Implementar sistema completo de trazabilidad de lotes
- 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
2025-11-21 18:39:04 -06:00

148 lines
3.6 KiB
Vue

<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>