Se agrego el titulo de busqueda en partes
This commit is contained in:
@@ -22,13 +22,9 @@
|
||||
type A76ClassCreate,
|
||||
type A76ClassUpdate
|
||||
} from '$lib/api/dashboard/a76/classes';
|
||||
|
||||
// APIs para recuperar nombres al editar
|
||||
import { materialTypesApi } from "$lib/api/dashboard/a76/material-types";
|
||||
import { clientsProvidersApi } from '$lib/api/dashboard/a76/clients-providers';
|
||||
// Nota: Asumo que tienes una API para obtener una unidad por código o lista,
|
||||
// si no, usaremos la descripción del modal.
|
||||
|
||||
|
||||
// --- MODALES IMPORTADOS ---
|
||||
import MaterialTypeSelectorDialog from '$lib/components/dashboard/goods/modales/material-type-selector-dialog.svelte';
|
||||
import UnitMeasureSelectorDialog from '$lib/components/dashboard/goods/modales/unit-measure-dialog.svelte';
|
||||
@@ -43,12 +39,10 @@
|
||||
let loading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
|
||||
// Estados de Modales
|
||||
let showClientModal = $state(false);
|
||||
let showMaterialModal = $state(false);
|
||||
let showUnitModal = $state(false);
|
||||
|
||||
// Descripciones Visuales (Para que el usuario sepa qué seleccionó)
|
||||
let selectedClientName = $state("");
|
||||
let selectedMaterialDesc = $state("");
|
||||
let selectedUnitDesc = $state("");
|
||||
@@ -62,7 +56,7 @@
|
||||
description_es: '',
|
||||
description_en: '',
|
||||
material_key: '',
|
||||
unit_of_measure: '', // Ahora vacío para obligar selección
|
||||
unit_of_measure: '',
|
||||
fraction: '',
|
||||
us_fraction: '',
|
||||
sub_key: '',
|
||||
@@ -83,7 +77,7 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Carga del Registro a Editar y sus descripciones visuales
|
||||
|
||||
async function loadClassData(classId: number, companyId: number) {
|
||||
loading = true;
|
||||
try {
|
||||
@@ -111,10 +105,9 @@
|
||||
iva_exempt_fraction: data.iva_exempt_fraction
|
||||
};
|
||||
|
||||
// Recuperar descripciones visuales para que no se vean solo códigos
|
||||
if (data.client_id) await fetchClientName(data.client_id, companyId);
|
||||
if (data.material_key) await fetchMaterialName(data.material_key);
|
||||
if (data.unit_of_measure) selectedUnitDesc = data.unit_of_measure; // O buscar descripción si tienes API
|
||||
if (data.unit_of_measure) selectedUnitDesc = data.unit_of_measure;
|
||||
}
|
||||
} catch (e) {
|
||||
error = "No se pudo cargar la información de la Clase";
|
||||
@@ -135,8 +128,6 @@
|
||||
|
||||
async function fetchMaterialName(key: string) {
|
||||
try {
|
||||
// Asumiendo que list devuelve items y podemos buscar ahí,
|
||||
// o si tienes un get(key) mejor.
|
||||
const res = await materialTypesApi.list(1, 100);
|
||||
const list = (res as any).data?.items || [];
|
||||
const found = list.find((m: any) => m.key === key);
|
||||
@@ -158,7 +149,6 @@
|
||||
}
|
||||
|
||||
function handleUnitSelect(item: any) {
|
||||
// Asumiendo que el modal devuelve { code: 'KG', description: 'Kilogramos' }
|
||||
formData.unit_of_measure = item.code;
|
||||
selectedUnitDesc = item.description || item.code;
|
||||
}
|
||||
|
||||
@@ -6,26 +6,29 @@
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Label } from '$lib/components/ui/label';
|
||||
import { companyStore } from '$lib/stores/company.svelte';
|
||||
import { Plus, Search, Trash2, RefreshCw } from 'lucide-svelte';
|
||||
import { Plus, Search, RefreshCw, Loader2, Trash2 } from 'lucide-svelte';
|
||||
|
||||
// 1. ESTADOS
|
||||
let partsList = $state<Part[]>([]);
|
||||
let listLoading = $state(false);
|
||||
let listError = $state<string | null>(null);
|
||||
|
||||
// Estado Búsqueda
|
||||
let searchCode = $state('');
|
||||
let searchedPart = $state<Part | null>(null);
|
||||
let searchResults = $state<Part[]>([]); // Array para guardar los resultados
|
||||
let searchLoading = $state(false);
|
||||
let isSearching = $state(false); // Para saber si estamos viendo resultados de búsqueda
|
||||
|
||||
// 2. CARGA DE DATOS
|
||||
// 2. CARGA DE DATOS (Lista Completa)
|
||||
async function loadParts() {
|
||||
const companyId = companyStore.activeCompany?.id;
|
||||
if (!companyId) return;
|
||||
|
||||
listLoading = true;
|
||||
listError = null;
|
||||
isSearching = false; // Reseteamos modo búsqueda
|
||||
searchResults = [];
|
||||
|
||||
try {
|
||||
const response = await partsApi.list({
|
||||
@@ -35,10 +38,7 @@
|
||||
});
|
||||
|
||||
if (response.data) {
|
||||
|
||||
partsList = response.data.items || response.data.parts || [];
|
||||
|
||||
console.log("Datos recibidos:", response.data);
|
||||
} else if (response.error) {
|
||||
listError = response.error;
|
||||
}
|
||||
@@ -56,10 +56,14 @@
|
||||
}
|
||||
});
|
||||
|
||||
// 4. BÚSQUEDA MANUAL
|
||||
async function handleSearch() {
|
||||
if (!searchCode.trim()) return;
|
||||
|
||||
searchLoading = true;
|
||||
listError = null; // Limpiamos errores previos
|
||||
const companyId = companyStore.activeCompany?.id;
|
||||
|
||||
if (!companyId) return;
|
||||
|
||||
try {
|
||||
@@ -71,9 +75,12 @@
|
||||
const results = response.data.items || response.data.parts || [];
|
||||
|
||||
if (results.length > 0) {
|
||||
searchedPart = results[0];
|
||||
searchResults = results; // Guardamos TODOS los resultados
|
||||
isSearching = true; // Activamos modo búsqueda
|
||||
} else {
|
||||
listError = "No se encontró la parte";
|
||||
listError = "No se encontraron partes con ese criterio";
|
||||
searchResults = [];
|
||||
isSearching = true; // Aún en modo búsqueda, pero vacía
|
||||
}
|
||||
} catch (e) {
|
||||
listError = "Error en la búsqueda";
|
||||
@@ -84,12 +91,16 @@
|
||||
|
||||
function clearSearch() {
|
||||
searchCode = '';
|
||||
searchedPart = null;
|
||||
loadParts();
|
||||
searchResults = [];
|
||||
isSearching = false;
|
||||
listError = null;
|
||||
loadParts(); // Recargamos la lista completa
|
||||
}
|
||||
|
||||
const columns = createColumns(loadParts);
|
||||
const tableData = $derived(searchedPart ? [searchedPart] : partsList);
|
||||
|
||||
// Si estamos buscando, mostramos searchResults, si no, la lista completa
|
||||
const tableData = $derived(isSearching ? searchResults : partsList);
|
||||
</script>
|
||||
|
||||
<div class="space-y-6 p-4">
|
||||
@@ -111,17 +122,32 @@
|
||||
</div>
|
||||
|
||||
<Card.Root>
|
||||
<Card.Content class="pt-6">
|
||||
<Card.Header>
|
||||
<Card.Title>Búsqueda Rápida</Card.Title>
|
||||
<Card.Description>Ingresa el número de parte o descripción para filtrar.</Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<div class="flex gap-4">
|
||||
<div class="flex-1">
|
||||
<Input bind:value={searchCode} placeholder="Buscar por número de parte o descripción..." />
|
||||
<div class="flex-1 max-w-xl">
|
||||
<Input
|
||||
bind:value={searchCode}
|
||||
placeholder="Buscar por número de parte o descripción..."
|
||||
onkeydown={(e) => e.key === 'Enter' && handleSearch()}
|
||||
/>
|
||||
</div>
|
||||
<Button onclick={handleSearch} disabled={searchLoading}>
|
||||
<Search class="mr-2 h-4 w-4" />
|
||||
Buscar
|
||||
{#if searchLoading}
|
||||
<Loader2 class="mr-2 h-4 w-4 animate-spin" />
|
||||
Buscando...
|
||||
{:else}
|
||||
<Search class="mr-2 h-4 w-4" />
|
||||
Buscar
|
||||
{/if}
|
||||
</Button>
|
||||
{#if searchedPart || searchCode}
|
||||
|
||||
{#if isSearching || searchCode}
|
||||
<Button variant="ghost" onclick={clearSearch}>
|
||||
<Trash2 class="mr-2 h-4 w-4" />
|
||||
Limpiar
|
||||
</Button>
|
||||
{/if}
|
||||
@@ -131,16 +157,22 @@
|
||||
|
||||
<Card.Root>
|
||||
<Card.Header>
|
||||
<Card.Title>{searchedPart ? 'Resultado' : 'Listado General'}</Card.Title>
|
||||
<Card.Title>
|
||||
{#if isSearching}
|
||||
Resultados de la búsqueda ({searchResults.length})
|
||||
{:else}
|
||||
Listado General ({partsList.length} registros)
|
||||
{/if}
|
||||
</Card.Title>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
{#if listError}
|
||||
<div class="bg-destructive/10 text-destructive p-4 rounded-lg border border-destructive/20">
|
||||
<div class="bg-destructive/10 text-destructive p-4 rounded-lg border border-destructive/20 mb-4">
|
||||
{listError}
|
||||
</div>
|
||||
{:else}
|
||||
<DataTable data={tableData} {columns} />
|
||||
{/if}
|
||||
|
||||
<DataTable data={tableData} {columns} />
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
</div>
|
||||
@@ -545,7 +545,7 @@
|
||||
placeholder="Seleccione un cliente..."
|
||||
readonly
|
||||
onclick={() => showClientModal = true}
|
||||
/>
|
||||
/>
|
||||
</div>
|
||||
<Button variant="outline" class="shrink-0" type="button" onclick={() => showClientModal = true}>
|
||||
<Search class="h-4 w-4 mr-2" /> Buscar
|
||||
|
||||
Reference in New Issue
Block a user