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
148 lines
3.6 KiB
Vue
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>
|