Feat: agregar creación de lotes de input en formulario de operación
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m6s

Ahora el formulario de crear operación permite crear nuevos lotes de
entrada directamente desde el paso 2, sin necesidad de salir del modal.

Cambios:
- Agregar botón "Nuevo lote de entrada" en el paso 2
- Mostrar formulario inline para crear lote con código, tipo y cantidad
- Al crear el lote, se agrega automáticamente a la lista de disponibles
- Se selecciona automáticamente como input de la operación
- Importar createLote del composable useLotes
- Agregar estado showCreateInputForm y creatingInput
- Implementar funciones cancelCreateInput y handleCreateInput

Beneficios:
- Flujo más ágil sin interrupciones
- Consistencia con la creación de lotes de output
- Mejor experiencia de usuario
This commit is contained in:
2025-11-22 03:33:19 -06:00
parent cb0261dad3
commit 599a7999c9

View File

@@ -63,6 +63,7 @@
</div> </div>
<div v-else class="space-y-2"> <div v-else class="space-y-2">
<!-- Lotes existentes -->
<div <div
v-for="lote in lotesDisponibles" v-for="lote in lotesDisponibles"
:key="lote.id" :key="lote.id"
@@ -90,8 +91,68 @@
/> />
</div> </div>
</div> </div>
<!-- Formulario para crear nuevo lote de entrada -->
<div v-if="showCreateInputForm" class="p-4 border-2 border-dashed border-primary/50 rounded-lg space-y-3 bg-primary/5">
<div class="flex justify-between items-center">
<h5 class="font-medium text-primary">Nuevo lote de entrada</h5>
<UButton
icon="i-heroicons-x-mark"
size="xs"
variant="ghost"
@click="cancelCreateInput"
/>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-3">
<UFormGroup label="Código (opcional)">
<UInput v-model="newInputLote.codigo" placeholder="Ej: UVA-001" icon="i-heroicons-hashtag" />
</UFormGroup>
<UFormGroup label="Tipo" required>
<USelect
v-model="newInputLote.tipo"
:items="TIPOS_LOTE"
label-key="label"
value-key="value"
placeholder="Selecciona tipo"
searchable
/>
</UFormGroup>
<UFormGroup label="Cantidad (kg)">
<UInput v-model.number="newInputLote.cantidad_kg" type="number" step="0.01" placeholder="0.00" icon="i-heroicons-scale" />
</UFormGroup>
</div>
<div class="flex gap-2 justify-end">
<UButton
label="Cancelar"
variant="outline"
size="sm"
@click="cancelCreateInput"
/>
<UButton
label="Crear y Seleccionar"
color="primary"
size="sm"
:loading="creatingInput"
:disabled="!newInputLote.tipo"
@click="handleCreateInput"
/>
</div>
</div>
</div> </div>
<UButton
v-if="!showCreateInputForm"
icon="i-heroicons-plus"
label="Nuevo lote de entrada"
variant="outline"
block
@click="showCreateInputForm = true"
/>
<div class="flex gap-2 justify-end pt-4"> <div class="flex gap-2 justify-end pt-4">
<UButton <UButton
label="Anterior" label="Anterior"
@@ -191,12 +252,19 @@ const emit = defineEmits<{
success: [] success: []
}>() }>()
const { fetchLotes, createOperacion, TIPOS_OPERACION, TIPOS_LOTE } = useLotes() const { fetchLotes, createLote, createOperacion, TIPOS_OPERACION, TIPOS_LOTE } = useLotes()
const step = ref(1) const step = ref(1)
const loading = ref(false) const loading = ref(false)
const loadingLotes = ref(false) const loadingLotes = ref(false)
const lotesDisponibles = ref<Lote[]>([]) const lotesDisponibles = ref<Lote[]>([])
const showCreateInputForm = ref(false)
const creatingInput = ref(false)
const newInputLote = ref({
codigo: '',
tipo: '',
cantidad_kg: undefined as number | undefined,
})
const formState = ref({ const formState = ref({
tipo: '', tipo: '',
@@ -247,6 +315,43 @@ const removeOutput = (index: number) => {
formState.value.outputs.splice(index, 1) formState.value.outputs.splice(index, 1)
} }
const cancelCreateInput = () => {
showCreateInputForm.value = false
newInputLote.value = {
codigo: '',
tipo: '',
cantidad_kg: undefined,
}
}
const handleCreateInput = async () => {
creatingInput.value = true
try {
const createdLote = await createLote({
codigo: newInputLote.value.codigo || undefined,
tipo: newInputLote.value.tipo,
cantidad_kg: newInputLote.value.cantidad_kg,
})
if (createdLote) {
// Agregar a la lista de lotes disponibles
lotesDisponibles.value.unshift(createdLote)
// Seleccionarlo automáticamente como input
formState.value.inputs.push({
lote_id: createdLote.id,
cantidad_kg: createdLote.cantidad_kg || undefined,
_lote: createdLote,
})
// Cerrar el formulario
cancelCreateInput()
}
} finally {
creatingInput.value = false
}
}
const getTipoLabel = (tipo: string) => { const getTipoLabel = (tipo: string) => {
const foundOp = TIPOS_OPERACION.find((t) => t.value === tipo) const foundOp = TIPOS_OPERACION.find((t) => t.value === tipo)
if (foundOp) return foundOp.label if (foundOp) return foundOp.label