feat(clientes-maestro): importar y exportar clientes del archivo maestro

- Tabla ClienteMaestro (27 campos, unique numCliente)
- Importador Excel: 1535 clientes del Reporte maestro
- API: listar/filtros/exportar/detalle/importar
- Frontend: tabla paginada, filtros, exportar Excel
- Dark mode completo, 52 tests verdes
This commit is contained in:
2026-09-07 09:11:09 +00:00
parent c2a8f4e929
commit 9021733455
18 changed files with 1428 additions and 10 deletions

View File

@@ -0,0 +1,85 @@
import { API_URL, conAuth, manejar401 } from './auth'
// ─── Tipos ──────────────────────────────────────────────────────────
export interface ClienteMaestro {
id: string
numCliente: string
nombre: string
apellidoPaterno: string
apellidoMaterno: string | null
sexo: string | null
telefono: string | null
email: string | null
estadoCivil: string | null
rangoEdad: string | null
ocupacion: string | null
rangoIngresos: string | null
credito: string | null
institucion: string | null
medioContacto: string | null
canal: string | null
desarrollo: string | null
manzana: string | null
lote: string | null
interior: string | null
tipoCasa: string | null
etapa: string | null
valorTotal: number | null
estatus: string | null
fechaLiberacion: string | null
vendedor: string | null
vendedorId: string | null
importadoEn: string
}
export interface FiltrosClientesMaestro {
busqueda?: string
desarrollo?: string
estatus?: string
pagina?: number
limite?: number
}
export interface ResultadoListado {
datos: ClienteMaestro[]
total: number
pagina: number
limite: number
}
// ─── API calls ──────────────────────────────────────────────────────
/** GET /api/clientes-maestro — listar con filtros y paginación */
export async function listarClientesMaestro(filtros: FiltrosClientesMaestro = {}): Promise<ResultadoListado> {
const params = new URLSearchParams()
if (filtros.busqueda) params.set('busqueda', filtros.busqueda)
if (filtros.desarrollo) params.set('desarrollo', filtros.desarrollo)
if (filtros.estatus) params.set('estatus', filtros.estatus)
if (filtros.pagina) params.set('pagina', String(filtros.pagina))
if (filtros.limite) params.set('limite', String(filtros.limite))
const resp = await fetch(`${API_URL}/clientes-maestro?${params}`, conAuth())
manejar401(resp)
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
return (await resp.json()) as ResultadoListado
}
/** GET /api/clientes-maestro/exportar — array de objetos para xlsx */
export async function exportarClientesMaestro(filtros: Omit<FiltrosClientesMaestro, 'pagina' | 'limite'> = {}): Promise<ClienteMaestro[]> {
const params = new URLSearchParams()
if (filtros.busqueda) params.set('busqueda', filtros.busqueda)
if (filtros.desarrollo) params.set('desarrollo', filtros.desarrollo)
if (filtros.estatus) params.set('estatus', filtros.estatus)
const resp = await fetch(`${API_URL}/clientes-maestro/exportar?${params}`, conAuth())
manejar401(resp)
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
return (await resp.json()) as ClienteMaestro[]
}
/** GET /api/clientes-maestro/:numCliente — detalle */
export async function obtenerClienteMaestro(numCliente: string): Promise<ClienteMaestro> {
const resp = await fetch(`${API_URL}/clientes-maestro/${encodeURIComponent(numCliente)}`, conAuth())
manejar401(resp)
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
return (await resp.json()) as ClienteMaestro
}