Se mejoro el formulario de partes
This commit is contained in:
@@ -10,8 +10,9 @@
|
||||
import { Textarea } from '$lib/components/ui/textarea';
|
||||
import * as Tabs from '$lib/components/ui/tabs';
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import * as Select from "$lib/components/ui/select";
|
||||
import { Switch } from "$lib/components/ui/switch";
|
||||
import { ArrowLeft, LoaderCircle, Save, CheckCircle2, XCircle, Package, DollarSign } from 'lucide-svelte';
|
||||
import { ArrowLeft, LoaderCircle, Save, Package, DollarSign, FileText, Settings, Image as ImageIcon } from 'lucide-svelte';
|
||||
|
||||
import { companyStore } from '$lib/stores/company.svelte';
|
||||
import { partsApi, type PartCreate } from '$lib/api/dashboard/a76/parts';
|
||||
@@ -35,27 +36,30 @@
|
||||
part_class: '',
|
||||
country_of_origin: 'MEX',
|
||||
unit_of_measure: 'PZ',
|
||||
// Opcionales 1
|
||||
fraction: '',
|
||||
us_fraction: '',
|
||||
// Costos y Pesos
|
||||
unit_weight: 0,
|
||||
weight_type: 'KG',
|
||||
// Opcionales 2
|
||||
unit_cost: 0,
|
||||
currency_key: 'USD',
|
||||
added_value: 0,
|
||||
us_fraction: '',
|
||||
|
||||
// Opciones
|
||||
supplier: '',
|
||||
fda_key: '',
|
||||
fcc_key: '',
|
||||
part_photo: '',
|
||||
|
||||
// Opcionales 2
|
||||
fda_key: '',
|
||||
|
||||
// Otros
|
||||
commercial_part_number: '',
|
||||
fraction: '', // Fraccion MX
|
||||
eccn: '',
|
||||
license_code: '',
|
||||
export_code: '',
|
||||
exclusion_symbol: '',
|
||||
// Costos
|
||||
unit_cost: 0,
|
||||
currency_key: 'USD',
|
||||
added_value: 0,
|
||||
commercial_part_number: '',
|
||||
// Otros
|
||||
alternate_unit_measure: '',
|
||||
part_photo: '',
|
||||
is_active: true
|
||||
});
|
||||
|
||||
@@ -121,18 +125,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function handleSubmit() {
|
||||
error = null;
|
||||
const activeCompanyId = companyStore.activeCompany?.id;
|
||||
if (!activeCompanyId) { error = 'No hay una compañía activa seleccionada'; return; }
|
||||
if (!formData.client_id) { error = 'ID Cliente requerido'; return; }
|
||||
if (!formData.client_id) { error = 'ID Cliente requerido (Pestaña Otros)'; return; }
|
||||
if (!formData.part_number.trim()) { error = 'Número de Parte requerido'; return; }
|
||||
if (!formData.fraction.trim()) { error = 'Fracción MX requerida'; return; }
|
||||
|
||||
|
||||
loading = true;
|
||||
try {
|
||||
|
||||
const commonData = {
|
||||
description_spanish: formData.description_spanish || null,
|
||||
description_english: formData.description_english || null,
|
||||
@@ -165,60 +166,44 @@
|
||||
|
||||
if (isEdit && id) {
|
||||
const response = await partsApi.update(id, commonData, activeCompanyId);
|
||||
|
||||
if (response.error) throw new Error(response.error);
|
||||
console.log("Registro actualizado con éxito");
|
||||
|
||||
} else {
|
||||
|
||||
const createData: PartCreate = {
|
||||
...commonData,
|
||||
company_id: activeCompanyId,
|
||||
client_id: Number(formData.client_id),
|
||||
part_number: formData.part_number
|
||||
};
|
||||
|
||||
const response = await partsApi.create(createData, activeCompanyId);
|
||||
|
||||
if (response.error) throw new Error(response.error);
|
||||
console.log("Registro creado con éxito");
|
||||
}
|
||||
|
||||
|
||||
goto('/dashboard/goods/parts');
|
||||
|
||||
} catch (e: any) {
|
||||
console.error("Error en el guardado:", e);
|
||||
if (e.message?.includes('already exists')) {
|
||||
error = `El número de parte ${formData.part_number} ya existe para este cliente.`;
|
||||
} else if (e.message?.includes('foreign key constraint')) {
|
||||
error = `Error: Uno de los datos (País, Moneda o Unidad) no existe en el sistema.`;
|
||||
} else if (e.message?.includes('foreign key')) {
|
||||
error = `Error: Uno de los catálogos (País, Moneda, UM) no es válido.`;
|
||||
} else {
|
||||
error = e.message || 'Ocurrió un error inesperado al guardar';
|
||||
error = e.message || 'Error inesperado al guardar';
|
||||
}
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="w-full mx-auto max-w-6xl py-6 px-4 space-y-6 pb-48">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-4">
|
||||
<Button variant="outline" size="icon" href="/dashboard/goods/parts">
|
||||
<ArrowLeft class="h-4 w-4" />
|
||||
</Button>
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold tracking-tight">{title}</h1>
|
||||
<p class="text-xs text-muted-foreground">{isEdit ? 'Modificando registro existente' : 'Creando nuevo registro'}</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<Button variant="outline" size="icon" href="/dashboard/goods/parts">
|
||||
<ArrowLeft class="h-4 w-4" />
|
||||
</Button>
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold tracking-tight">{title}</h1>
|
||||
<p class="text-muted-foreground">Gestión detallada de números de parte.</p>
|
||||
</div>
|
||||
{#if isEdit}
|
||||
<div class="flex items-center gap-2 px-3 py-1 rounded-full border text-xs font-medium {formData.is_active ? 'bg-green-100 text-green-700 border-green-200' : 'bg-red-100 text-red-700 border-red-200'}">
|
||||
{#if formData.is_active} <CheckCircle2 class="w-3 h-3 mr-1"/> Activo {:else} <XCircle class="w-3 h-3 mr-1"/> Inactivo {/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if error}
|
||||
@@ -227,210 +212,253 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#key id}
|
||||
<form onsubmit={(e) => { e.preventDefault(); handleSubmit(); }} class="space-y-6">
|
||||
<Card.Root>
|
||||
<Card.Content class="p-6">
|
||||
<Tabs.Root value="general" class="w-full">
|
||||
|
||||
<div class="min-h-[450px]">
|
||||
<div class="min-h-[500px]">
|
||||
|
||||
<Tabs.Content value="general" class="space-y-4 pt-4 animate-in fade-in slide-in-from-bottom-2 duration-300">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="space-y-4">
|
||||
<div class="grid gap-2">
|
||||
<Label for="client_id" class="required">ID Cliente</Label>
|
||||
<Input type="number" id="client_id" bind:value={formData.client_id} placeholder="Ej. 11" />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="part_number" class="required">Número de Parte</Label>
|
||||
<Input id="part_number" bind:value={formData.part_number} disabled={isEdit} maxlength={50} class="font-mono" />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="part_class">Clase / Familia</Label>
|
||||
<Input id="part_class" bind:value={formData.part_class} maxlength={8} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-4">
|
||||
<div class="grid gap-2">
|
||||
<Label for="country">País de Origen</Label>
|
||||
<Input id="country" bind:value={formData.country_of_origin} maxlength={3} placeholder="MEX" />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="uom" class="required">Unidad Medida (UM)</Label>
|
||||
<select id="uom" bind:value={formData.unit_of_measure} class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm">
|
||||
<option value="PZ">Pieza (PZ)</option>
|
||||
<option value="KG">Kilogramo (KG)</option>
|
||||
<option value="EA">Elemento (EA)</option>
|
||||
<option value="L">Litro (L)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Tabs.Content value="general" class="space-y-6 pt-4 animate-in fade-in duration-300">
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label for="desc_es">Descripción (Español)</Label>
|
||||
<Textarea id="desc_es" bind:value={formData.description_spanish} maxlength={500} />
|
||||
<Label for="part_number" class="text-base font-semibold required">Número de Parte</Label>
|
||||
<Input id="part_number" bind:value={formData.part_number} disabled={isEdit} maxlength={50} class="text-lg font-mono" placeholder="Ej: 123-ABC-456"/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="desc_en">Descripción (Inglés)</Label>
|
||||
<Textarea id="desc_en" bind:value={formData.description_english} maxlength={500} />
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="opt1" class="space-y-4 pt-4 animate-in fade-in slide-in-from-bottom-2 duration-300">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="p-4 border rounded-lg bg-slate-50 dark:bg-slate-900/50 space-y-4">
|
||||
<h3 class="font-semibold text-sm">Clasificación Arancelaria</h3>
|
||||
<div class="space-y-3 p-4 border rounded-lg bg-slate-50 dark:bg-slate-900/30">
|
||||
<h3 class="font-medium text-sm text-muted-foreground flex items-center gap-2">
|
||||
<FileText class="h-4 w-4"/> Descripción
|
||||
</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="grid gap-2">
|
||||
<Label for="frac_mx" class="required">Fracción MX</Label>
|
||||
<Input id="frac_mx" bind:value={formData.fraction} maxlength={10} placeholder="Ej: 85011001" />
|
||||
<Label for="desc_es">Español</Label>
|
||||
<Textarea id="desc_es" bind:value={formData.description_spanish} maxlength={500} rows={3}/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="frac_us">Fracción US (HTS)</Label>
|
||||
<Input id="frac_us" bind:value={formData.us_fraction} maxlength={16} placeholder="Ej: 8501.10.00" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 border rounded-lg bg-slate-50 dark:bg-slate-900/50 space-y-4">
|
||||
<h3 class="font-semibold text-sm flex items-center gap-2">
|
||||
<Package class="h-4 w-4"/> Dimensiones Físicas
|
||||
</h3>
|
||||
<div class="grid gap-2">
|
||||
<Label for="weight">Peso Unitario</Label>
|
||||
<Input type="number" step="0.0001" id="weight" bind:value={formData.unit_weight} />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="weight_type">Tipo Peso</Label>
|
||||
<select id="weight_type" bind:value={formData.weight_type} class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm">
|
||||
<option value="KG">Kilogramos (KG)</option>
|
||||
<option value="LB">Libras (LB)</option>
|
||||
</select>
|
||||
<Label for="desc_en">Inglés</Label>
|
||||
<Textarea id="desc_en" bind:value={formData.description_english} maxlength={500} rows={3}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="opt2" class="space-y-4 pt-4 animate-in fade-in slide-in-from-bottom-2 duration-300">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="grid gap-2">
|
||||
<Label for="supplier">Proveedor</Label>
|
||||
<Input id="supplier" bind:value={formData.supplier} maxlength={14} />
|
||||
<Label for="part_class">Clase</Label>
|
||||
<Input id="part_class" bind:value={formData.part_class} maxlength={8} placeholder="Código de clase"/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="eccn">ECCN (Export Control)</Label>
|
||||
<Input id="eccn" bind:value={formData.eccn} maxlength={20} />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="fda">FDA Key</Label>
|
||||
<Input id="fda" bind:value={formData.fda_key} maxlength={20} />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="fcc">FCC Key</Label>
|
||||
<Input id="fcc" bind:value={formData.fcc_key} maxlength={30} />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="lic_code">License Code</Label>
|
||||
<Input id="lic_code" bind:value={formData.license_code} maxlength={3} />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="exp_code">Export Code</Label>
|
||||
<Input id="exp_code" bind:value={formData.export_code} maxlength={2} />
|
||||
</div>
|
||||
<div class="grid gap-2 md:col-span-2">
|
||||
<Label for="exc_sym">Exclusion Symbol</Label>
|
||||
<Input id="exc_sym" bind:value={formData.exclusion_symbol} maxlength={19} />
|
||||
<Label for="country">País Origen (ISO)</Label>
|
||||
<Input id="country" bind:value={formData.country_of_origin} maxlength={3} placeholder="MEX"/>
|
||||
</div>
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="costs" class="space-y-4 pt-4 animate-in fade-in slide-in-from-bottom-2 duration-300">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="p-4 border rounded-lg bg-green-50/50 dark:bg-green-900/10 space-y-4">
|
||||
<h3 class="font-semibold text-sm text-green-800 dark:text-green-300 flex items-center gap-2">
|
||||
<DollarSign class="h-4 w-4"/> Costos y Moneda
|
||||
</h3>
|
||||
<div class="p-4 border rounded-lg bg-slate-50 dark:bg-slate-900/30 space-y-4">
|
||||
<h3 class="font-medium text-sm text-muted-foreground flex items-center gap-2">
|
||||
<Package class="h-4 w-4"/> Unidades de Medida
|
||||
</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="grid gap-2">
|
||||
<Label for="unit_cost">Costo Unitario</Label>
|
||||
<div class="relative">
|
||||
<span class="absolute left-3 top-2.5 text-muted-foreground">$</span>
|
||||
<Input type="number" step="0.0001" id="unit_cost" bind:value={formData.unit_cost} class="pl-7" />
|
||||
</div>
|
||||
<Label for="uom">UM Comercial</Label>
|
||||
<Select.Root type="single" bind:value={formData.unit_of_measure}>
|
||||
<Select.Trigger id="uom">
|
||||
{formData.unit_of_measure || "Seleccione"}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Item value="PZ">Pieza (PZ)</Select.Item>
|
||||
<Select.Item value="KG">Kilogramo (KG)</Select.Item>
|
||||
<Select.Item value="EA">Elemento (EA)</Select.Item>
|
||||
<Select.Item value="L">Litro (L)</Select.Item>
|
||||
<Select.Item value="M">Metro (M)</Select.Item>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 border rounded-lg bg-green-50/50 dark:bg-green-900/10 space-y-4">
|
||||
<h3 class="font-medium text-sm text-green-800 dark:text-green-300 flex items-center gap-2">
|
||||
<DollarSign class="h-4 w-4"/> Costos y Pesos
|
||||
</h3>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div class="grid gap-2">
|
||||
<Label for="currency">Moneda</Label>
|
||||
<select id="currency" bind:value={formData.currency_key} class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm">
|
||||
<option value="USD">USD - Dólar Americano</option>
|
||||
<option value="MXP">MXP - Peso Mexicano</option>
|
||||
<option value="EUR">EUR - Euro</option>
|
||||
</select>
|
||||
<Select.Root type="single" bind:value={formData.currency_key}>
|
||||
<Select.Trigger id="currency">{formData.currency_key}</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Item value="USD">Dólar (USD)</Select.Item>
|
||||
<Select.Item value="MXP">Peso (MXP)</Select.Item>
|
||||
<Select.Item value="EUR">Euro (EUR)</Select.Item>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="added_value">Valor Agregado</Label>
|
||||
<Input type="number" step="0.0001" id="added_value" bind:value={formData.added_value} />
|
||||
<Label for="unit_cost">Costo Unitario</Label>
|
||||
<Input type="number" step="0.0001" id="unit_cost" bind:value={formData.unit_cost} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 pt-2 border-t border-green-200 dark:border-green-800/30">
|
||||
<div class="grid gap-2">
|
||||
<Label for="comm_pn">No. Parte Comercial</Label>
|
||||
<Input id="comm_pn" bind:value={formData.commercial_part_number} maxlength={70} placeholder="Código usado en factura..." />
|
||||
<p class="text-xs text-muted-foreground">Si difiere del número de parte interno.</p>
|
||||
<Label for="unit_weight">Peso Unitario</Label>
|
||||
<div class="flex gap-2">
|
||||
<Input type="number" step="0.0001" id="unit_weight" bind:value={formData.unit_weight} />
|
||||
<Select.Root type="single" bind:value={formData.weight_type}>
|
||||
<Select.Trigger class="w-[100px]">{formData.weight_type}</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Item value="KG">KG</Select.Item>
|
||||
<Select.Item value="LB">LB</Select.Item>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label for="added_value">Valor Agregado (Monto)</Label>
|
||||
<Input type="number" step="0.0001" id="added_value" bind:value={formData.added_value} />
|
||||
<p class="text-xs text-muted-foreground">Ingrese el monto numérico del valor agregado.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2 pt-4 border-t">
|
||||
<Label for="frac_us">Fracción Americana (HTS)</Label>
|
||||
<Input id="frac_us" bind:value={formData.us_fraction} maxlength={16} placeholder="Ej: 8501.10.00" />
|
||||
</div>
|
||||
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="others" class="space-y-4 pt-4 animate-in fade-in slide-in-from-bottom-2 duration-300">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<Tabs.Content value="opciones" class="space-y-6 pt-4 animate-in fade-in duration-300">
|
||||
|
||||
<div class="space-y-4 p-4 border rounded-lg bg-card">
|
||||
<h3 class="font-medium text-sm text-muted-foreground">Configuración General</h3>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="grid gap-2">
|
||||
<Label for="fcc">Clave FCC</Label>
|
||||
<Input id="fcc" bind:value={formData.fcc_key} maxlength={30} />
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label for="supplier">Proveedor (Textil)</Label>
|
||||
<Input id="supplier" bind:value={formData.supplier} maxlength={14} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label for="alt_um">UM Alterna</Label>
|
||||
<Label for="photo" class="flex items-center gap-2"><ImageIcon class="h-4 w-4"/> URL Imagen de la parte</Label>
|
||||
<Input id="photo" bind:value={formData.part_photo} maxlength={255} placeholder="https://..." />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="opcionales2" class="space-y-6 pt-4 animate-in fade-in duration-300">
|
||||
|
||||
<div class="p-4 border rounded-lg space-y-4">
|
||||
<h3 class="font-medium text-sm text-muted-foreground">FDA (Food and Drug Administration)</h3>
|
||||
<div class="grid gap-2">
|
||||
<Label for="fda">Clave FDA</Label>
|
||||
<Input id="fda" bind:value={formData.fda_key} maxlength={20} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="otros" class="space-y-6 pt-4 animate-in fade-in duration-300">
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label for="client_id" class="required">Catálogo de Clientes (ID)</Label>
|
||||
<Input type="number" id="client_id" bind:value={formData.client_id} placeholder="ID del Cliente" />
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label for="comm_pn">Número de Parte Comercial</Label>
|
||||
<Input id="comm_pn" bind:value={formData.commercial_part_number} maxlength={70} />
|
||||
</div>
|
||||
|
||||
<div class="p-4 border rounded-lg space-y-4">
|
||||
<h3 class="font-medium text-sm text-muted-foreground">Factor Conversión</h3>
|
||||
<div class="grid gap-2">
|
||||
<Label for="alt_um">UM Conversión (Alterna)</Label>
|
||||
<Input id="alt_um" bind:value={formData.alternate_unit_measure} maxlength={14} />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="photo">URL Foto</Label>
|
||||
<Input id="photo" bind:value={formData.part_photo} maxlength={255} />
|
||||
</div>
|
||||
|
||||
<div class="flex items-center space-x-2 pt-4">
|
||||
<Switch id="active-mode" bind:checked={formData.is_active} />
|
||||
<Label for="active-mode">Parte Activa en Sistema</Label>
|
||||
</div>
|
||||
|
||||
<div class="p-4 border rounded-lg space-y-4 bg-slate-50 dark:bg-slate-900/30">
|
||||
<h3 class="font-medium text-sm text-muted-foreground">Datos Regulatorios Adicionales</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="grid gap-2">
|
||||
<Label for="fraction_mx" class="required">Fracción Arancelaria (MX)</Label>
|
||||
<Input id="fraction_mx" bind:value={formData.fraction} maxlength={10} />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="eccn">ECCN</Label>
|
||||
<Input id="eccn" bind:value={formData.eccn} maxlength={20} />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="lic_code">License Code</Label>
|
||||
<Input id="lic_code" bind:value={formData.license_code} maxlength={3} />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="exp_code">Export Code</Label>
|
||||
<Input id="exp_code" bind:value={formData.export_code} maxlength={2} />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="exc_sym">Símbolo de Exclusión</Label>
|
||||
<Input id="exc_sym" bind:value={formData.exclusion_symbol} maxlength={19} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-3 p-4 border rounded-lg bg-card">
|
||||
<Switch id="is_active" bind:checked={formData.is_active} disabled={loading} />
|
||||
<div class="grid gap-0.5">
|
||||
<Label for="is_active">Parte Activa en Sistema</Label>
|
||||
<p class="text-xs text-muted-foreground">Habilitar o deshabilitar</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Tabs.Content>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="fixed bottom-20 left-0 right-0 z-40 flex justify-center pointer-events-none">
|
||||
<Tabs.List class="pointer-events-auto grid grid-cols-5 w-[95%] max-w-4xl shadow-2xl bg-background border p-1 rounded-xl">
|
||||
<Tabs.Trigger value="general" class="text-xs md:text-sm">General</Tabs.Trigger>
|
||||
<Tabs.Trigger value="opt1" class="text-xs md:text-sm">Op. 1</Tabs.Trigger>
|
||||
<Tabs.Trigger value="opt2" class="text-xs md:text-sm">Op. 2</Tabs.Trigger>
|
||||
<Tabs.Trigger value="costs" class="text-xs md:text-sm">Costos</Tabs.Trigger>
|
||||
<Tabs.Trigger value="others" class="text-xs md:text-sm">Otros</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
</div>
|
||||
<Tabs.List class="grid grid-cols-4 fixed bottom-24 left-1/2 -translate-x-1/2 w-[95%] max-w-2xl z-40 shadow-2xl bg-background border p-1 rounded-xl">
|
||||
<Tabs.Trigger value="general" class="flex gap-2 items-center justify-center">
|
||||
<Package class="h-4 w-4 hidden sm:block" /> General
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="opciones" class="flex gap-2 items-center justify-center">
|
||||
<Settings class="h-4 w-4 hidden sm:block" /> Opciones
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="opcionales2" class="flex gap-2 items-center justify-center">
|
||||
<FileText class="h-4 w-4 hidden sm:block" /> Opcionales 2
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value="otros" class="flex gap-2 items-center justify-center">
|
||||
<Settings class="h-4 w-4 hidden sm:block" /> Otros
|
||||
</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
|
||||
</Tabs.Root>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
|
||||
<div class="fixed bottom-0 right-0 left-0 md:left-64 p-4 border-t bg-background/95 backdrop-blur z-50 flex justify-end gap-4 shadow-inner">
|
||||
<div class="max-w-6xl mx-auto flex justify-end gap-4 px-4 w-full">
|
||||
<Button type="button" variant="ghost" href="/dashboard/goods/parts" disabled={loading}>
|
||||
<div class="fixed bottom-0 right-0 left-0 md:left-64 p-4 border-t bg-background/95 backdrop-blur z-50">
|
||||
<div class="max-w-6xl mx-auto flex justify-end gap-4">
|
||||
<Button variant="ghost" href="/dashboard/goods/parts" disabled={loading}>
|
||||
Cancelar
|
||||
</Button>
|
||||
<Button type="submit" disabled={loading} class="min-w-[140px]">
|
||||
{#if loading}
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
Guardando...
|
||||
{:else}
|
||||
<Save class="mr-2 h-4 w-4" />
|
||||
{isEdit ? 'Actualizar' : 'Guardar'}
|
||||
{/if}
|
||||
{isEdit ? 'Actualizar' : 'Guardar'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{/key}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
Reference in New Issue
Block a user