se modificaron filtros y campos de expedientes, se agrego paginacion

se modificaron algunos campos de la tabla de pedimentoDetail. de igualforma se modificadron los filtros
se modifico el filtrado de pedimento en Procesos.jsx y se modifico el filtrado
This commit is contained in:
2025-08-16 18:45:16 -06:00
parent 8af75c6ac6
commit fdb19c7e47
3 changed files with 164 additions and 31 deletions

View File

@@ -80,7 +80,7 @@ export default function Documents() {
// Construir objeto de filtros
const filters = {
search: searchFilter || undefined,
pedimento_app: pedimentoFilter || undefined,
pedimento_app: pedimentoFilter || undefined,
existe_expediente: expedienteFilter === 'all' ? undefined : expedienteFilter,
contribuyente: contribuyenteFilter || undefined,
curp_apoderado: curpApoderadoFilter || undefined,
@@ -235,7 +235,7 @@ export default function Documents() {
className="w-full border border-gray-300 rounded-xl px-3 py-2.5 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 bg-white shadow-sm transition-all duration-200 hover:shadow-md"
/>
</div>
{/* Pedimento */}
{/* Pedimento_app */}
<div className="flex flex-col">
<label className="text-xs font-semibold text-gray-700 mb-1.5">Pedimento</label>
<input
@@ -418,9 +418,9 @@ export default function Documents() {
<th className="px-4 py-4 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Fecha de pago</th>
<th className="px-4 py-4 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Contribuyente</th>
<th className="px-4 py-4 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">CURP Apoderado</th>
<th className="px-4 py-4 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Importe total</th>
<th className="px-4 py-4 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Partidas</th>
<th className="px-4 py-4 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Saldo disponible</th>
<th className="px-4 py-4 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Importe pedimento_app</th>
<th className="px-4 py-4 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Importe pedimento</th>
<th className="px-4 py-4 text-left text-xs font-bold text-gray-700 uppercase tracking-wider border-b border-gray-200">Expediente</th>
</tr>
</thead>
@@ -455,13 +455,13 @@ export default function Documents() {
to={`/expedientes/pedimento/${ped.id}`}
className="text-blue-600 hover:text-blue-800 font-semibold transition-colors duration-200 group-hover:underline"
>
{ped.pedimento}
{ped.pedimento_app}
</Link>
</td>
<td className="px-4 py-4 whitespace-nowrap text-sm text-gray-700">{ped.fecha_pago}</td>
<td className="px-4 py-4 whitespace-nowrap text-sm text-gray-700 max-w-xs truncate" title={ped.contribuyente}>{ped.contribuyente}</td>
<td className="px-4 py-4 whitespace-nowrap text-sm text-gray-700">{ped.curp_apoderado}</td>
<td className="px-4 py-4 whitespace-nowrap text-sm text-gray-900 font-semibold">${ped.importe_total}</td>
<td className="px-4 py-4 whitespace-nowrap text-sm text-gray-900 font-semibold">{ped.numero_partidas}</td>
<td className="px-4 py-4 whitespace-nowrap text-sm text-gray-900 font-semibold">${ped.saldo_disponible}</td>
<td className="px-4 py-4 whitespace-nowrap text-sm text-gray-900 font-semibold">${ped.importe_pedimento_app}</td>
<td className="px-4 py-4 whitespace-nowrap">
@@ -540,7 +540,7 @@ export default function Documents() {
to={`/expedientes/pedimento/${ped.id}`}
className="text-lg font-semibold text-blue-600 hover:text-blue-800 transition-colors duration-200"
>
{ped.pedimento}
{ped.pedimento_app}
</Link>
<p className="text-sm text-gray-500">{ped.fechapago}</p>
</div>
@@ -569,15 +569,15 @@ export default function Documents() {
)}
<div className="grid grid-cols-1 gap-2">
<div className="flex items-center justify-between bg-green-50 rounded-lg p-2">
<span className="text-sm font-medium text-green-700">Importe total:</span>
<span className="text-sm font-bold text-green-800">${ped.importe_total}</span>
<span className="text-sm font-medium text-green-700">Partidas</span>
<span className="text-sm font-bold text-green-800">${ped.numero_partidas}</span>
</div>
<div className="flex items-center justify-between bg-blue-50 rounded-lg p-2">
<span className="text-sm font-medium text-blue-700">Saldo disponible:</span>
<span className="text-sm font-bold text-blue-800">${ped.saldo_disponible}</span>
</div>
<div className="flex items-center justify-between bg-gray-50 rounded-lg p-2">
<span className="text-sm font-medium text-gray-700">Importe pedimento_app:</span>
<span className="text-sm font-medium text-gray-700">Importe pedimento:</span>
<span className="text-sm font-bold text-gray-800">${ped.importe_pedimento_app}</span>
</div>
</div>

View File

@@ -326,6 +326,21 @@ const [docsPrev, setDocsPrev] = useState(null);
setPreviewXmlHtml('');
};
// Lógica para botones numerados de paginación
const totalPages = Math.max(1, Math.ceil(docsCount / pageSize));
let pageNumbers = [];
if (totalPages <= 7) {
pageNumbers = Array.from({ length: totalPages }, (_, i) => i + 1);
} else {
if (page <= 4) {
pageNumbers = [1, 2, 3, 4, 5, '...', totalPages];
} else if (page >= totalPages - 3) {
pageNumbers = [1, '...', totalPages - 4, totalPages - 3, totalPages - 2, totalPages - 1, totalPages];
} else {
pageNumbers = [1, '...', page - 1, page, page + 1, '...', totalPages];
}
}
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 via-white to-blue-50 p-4 lg:p-6">
<div className="max-w-7xl mx-auto">
@@ -481,7 +496,7 @@ const [docsPrev, setDocsPrev] = useState(null);
</svg>
Pedimento
</dt>
<dd className="text-xl font-bold text-gray-900">{pedimento.pedimento}</dd>
<dd className="text-xl font-bold text-gray-900">{pedimento.pedimento_app}</dd>
</div>
<div className="bg-gradient-to-br from-green-50 to-green-100/50 p-4 rounded-xl border border-green-200/50 shadow-sm hover:shadow-md transition-all duration-300 hover:scale-105">
@@ -706,10 +721,10 @@ const [docsPrev, setDocsPrev] = useState(null);
{/* Vista Desktop - Tabla */}
<div className="hidden lg:block">
<div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gradient-to-r from-blue-500 to-blue-700">
<table className="min-w-full border border-gray-200 rounded-xl shadow-sm bg-white">
<thead className="sticky top-0 z-10 bg-white border-b border-gray-200">
<tr>
<th className="px-4 py-3 text-left text-xs font-bold text-white uppercase tracking-wider">
<th className="px-4 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider bg-gray-50 border-r border-gray-200 first:rounded-tl-xl last:rounded-tr-xl">
<input
type="checkbox"
checked={allSelected}
@@ -717,42 +732,42 @@ const [docsPrev, setDocsPrev] = useState(null);
className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
/>
</th>
<th className="px-4 py-3 text-left text-xs font-bold text-white uppercase tracking-wider cursor-pointer" onClick={() => {
<th className="px-4 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider bg-gray-50 border-r border-gray-200 cursor-pointer select-none" onClick={() => {
setOrderBy('archivo');
setOrderDir(orderBy === 'archivo' && orderDir === 'asc' ? 'desc' : 'asc');
}}>
Archivo {orderBy === 'archivo' && (<span className="ml-1">{orderDir === 'asc' ? '▲' : '▼'}</span>)}
</th>
<th className="px-4 py-3 text-left text-xs font-bold text-white uppercase tracking-wider cursor-pointer" onClick={() => {
<th className="px-4 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider bg-gray-50 border-r border-gray-200 cursor-pointer select-none" onClick={() => {
setOrderBy('document_type');
setOrderDir(orderBy === 'document_type' && orderDir === 'asc' ? 'desc' : 'asc');
}}>
Tipo {orderBy === 'document_type' && (<span className="ml-1">{orderDir === 'asc' ? '▲' : '▼'}</span>)}
</th>
<th className="px-4 py-3 text-left text-xs font-bold text-white uppercase tracking-wider cursor-pointer" onClick={() => {
<th className="px-4 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider bg-gray-50 border-r border-gray-200 cursor-pointer select-none" onClick={() => {
setOrderBy('extension');
setOrderDir(orderBy === 'extension' && orderDir === 'asc' ? 'desc' : 'asc');
}}>
Extensión {orderBy === 'extension' && (<span className="ml-1">{orderDir === 'asc' ? '▲' : '▼'}</span>)}
</th>
<th className="px-4 py-3 text-left text-xs font-bold text-white uppercase tracking-wider cursor-pointer" onClick={() => {
<th className="px-4 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider bg-gray-50 border-r border-gray-200 cursor-pointer select-none" onClick={() => {
setOrderBy('size');
setOrderDir(orderBy === 'size' && orderDir === 'asc' ? 'desc' : 'asc');
}}>
Tamaño {orderBy === 'size' && (<span className="ml-1">{orderDir === 'asc' ? '▲' : '▼'}</span>)}
</th>
<th className="px-4 py-3 text-left text-xs font-bold text-white uppercase tracking-wider cursor-pointer" onClick={() => {
<th className="px-4 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider bg-gray-50 border-r border-gray-200 cursor-pointer select-none" onClick={() => {
setOrderBy('created_at');
setOrderDir(orderBy === 'created_at' && orderDir === 'asc' ? 'desc' : 'asc');
}}>
Fecha {orderBy === 'created_at' && (<span className="ml-1">{orderDir === 'asc' ? '▲' : '▼'}</span>)}
</th>
<th className="px-4 py-3 text-center text-xs font-bold text-white uppercase tracking-wider">
<th className="px-4 py-3 text-center text-xs font-bold text-gray-700 uppercase tracking-wider bg-gray-50 first:rounded-tr-xl last:rounded-tr-xl">
Acciones
</th>
</tr>
</thead>
<tbody className="bg-white/50 divide-y divide-gray-100">
<tbody className="bg-white divide-y divide-gray-100">
{documents
.filter(doc => {
if (!documentTypeFilter) return true;
@@ -798,8 +813,8 @@ const [docsPrev, setDocsPrev] = useState(null);
return 0;
})
.map((doc, index) => (
<tr key={doc.id} className="hover:bg-blue-50 transition-all duration-200">
<td className="px-4 py-3 whitespace-nowrap">
<tr key={doc.id} className="hover:bg-blue-100/60 transition-all duration-150 border-b border-gray-100 last:border-b-0">
<td className="px-4 py-3 whitespace-nowrap align-middle border-r border-gray-100">
<input
type="checkbox"
checked={selected.includes(doc.id)}
@@ -807,32 +822,32 @@ const [docsPrev, setDocsPrev] = useState(null);
className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
/>
</td>
<td className="px-4 py-3 whitespace-nowrap">
<td className="px-4 py-3 whitespace-nowrap align-middle border-r border-gray-100">
<div className="text-sm font-medium text-gray-900 max-w-xs truncate" title={doc.archivo || 'Sin nombre'}>
{doc.archivo ? doc.archivo.split('/').pop() : 'Sin nombre'}
</div>
</td>
<td className="px-4 py-3 whitespace-nowrap">
<td className="px-4 py-3 whitespace-nowrap align-middle border-r border-gray-100">
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-800">
{getDocumentTypeName(doc.document_type)}
</span>
</td>
<td className="px-4 py-3 whitespace-nowrap">
<td className="px-4 py-3 whitespace-nowrap align-middle border-r border-gray-100">
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
{doc.extension || 'N/A'}
</span>
</td>
<td className="px-4 py-3 whitespace-nowrap text-sm text-gray-700">
<td className="px-4 py-3 whitespace-nowrap text-sm text-gray-700 align-middle border-r border-gray-100">
{doc.size || 'N/A'}
</td>
<td className="px-4 py-3 whitespace-nowrap text-sm text-gray-700">
<td className="px-4 py-3 whitespace-nowrap text-sm text-gray-700 align-middle border-r border-gray-100">
{doc.created_at ? new Date(doc.created_at).toLocaleDateString('es-ES', {
year: 'numeric',
month: 'short',
day: 'numeric'
}) : 'N/A'}
</td>
<td className="px-4 py-3 whitespace-nowrap text-center">
<td className="px-4 py-3 whitespace-nowrap text-center align-middle">
<div className="flex justify-center space-x-2">
<button
onClick={() => handlePreview(doc)}
@@ -859,6 +874,65 @@ const [docsPrev, setDocsPrev] = useState(null);
))}
</tbody>
</table>
{/* Paginación Desktop */}
<div className="flex flex-col sm:flex-row justify-between items-center mt-4 gap-2 w-full">
{/* Izquierda: Selector de registros por página */}
<div className="flex items-center gap-2 w-full sm:w-auto justify-start">
<span className="text-sm text-gray-600 whitespace-nowrap">Registros por página</span>
<select
value={pageSize}
onChange={e => setPageSize(Number(e.target.value))}
className="px-2 py-1 rounded border border-gray-300 text-sm"
>
{[10, 20, 50, 100].map(size => (
<option key={size} value={size}>{size}</option>
))}
</select>
</div>
{/* Centro: Paginación numerada */}
<div className="flex gap-1 items-center flex-wrap justify-center w-full sm:w-auto">
<button
onClick={e => handlePageChange(1, e)}
disabled={page === 1}
className="px-2 py-1 rounded-lg border border-gray-300 bg-white text-gray-700 hover:bg-blue-50 disabled:opacity-50"
title="Primera página"
>«</button>
<button
onClick={e => handlePageChange(page - 1, e)}
disabled={page === 1}
className="px-2 py-1 rounded-lg border border-gray-300 bg-white text-gray-700 hover:bg-blue-50 disabled:opacity-50"
title="Anterior"
>&lt;</button>
{pageNumbers.map((num, idx) =>
num === '...'
? <span key={idx} className="px-2 text-gray-400 select-none"></span>
: <button
key={num}
onClick={e => handlePageChange(num, e)}
className={`px-2 py-1 rounded-lg border border-gray-300 ${num === page ? 'bg-blue-500 text-white font-bold' : 'bg-white text-gray-700 hover:bg-blue-50'} transition-colors`}
disabled={num === page}
>{num}</button>
)}
<button
onClick={e => handlePageChange(page + 1, e)}
disabled={page >= totalPages}
className="px-2 py-1 rounded-lg border border-gray-300 bg-white text-gray-700 hover:bg-blue-50 disabled:opacity-50"
title="Siguiente"
>&gt;</button>
<button
onClick={e => handlePageChange(totalPages, e)}
disabled={page >= totalPages}
className="px-2 py-1 rounded-lg border border-gray-300 bg-white text-gray-700 hover:bg-blue-50 disabled:opacity-50"
title="Última página"
>»</button>
</div>
{/* Derecha: Rango de registros */}
<div className="text-sm text-gray-600 w-full sm:w-auto text-right">
{docsCount > 0
? `Mostrando ${((page - 1) * pageSize) + 1} a ${Math.min(page * pageSize, docsCount)} de ${docsCount} registros`
: 'Mostrando 0 de 0 registros'}
</div>
</div>
</div>
</div>
@@ -958,6 +1032,65 @@ const [docsPrev, setDocsPrev] = useState(null);
</div>
</div>
))}
{/* Controles de paginación móvil */}
<div className="flex flex-col sm:flex-row justify-between items-center mt-4 gap-2 w-full">
{/* Izquierda: Selector de registros por página */}
<div className="flex items-center gap-2 w-full sm:w-auto justify-start">
<span className="text-sm text-gray-600 whitespace-nowrap">Registros por página</span>
<select
value={pageSize}
onChange={e => setPageSize(Number(e.target.value))}
className="px-2 py-1 rounded border border-gray-300 text-sm"
>
{[10, 20, 50, 100].map(size => (
<option key={size} value={size}>{size}</option>
))}
</select>
</div>
{/* Centro: Paginación numerada */}
<div className="flex gap-1 items-center flex-wrap justify-center w-full sm:w-auto">
<button
onClick={e => handlePageChange(1, e)}
disabled={page === 1}
className="px-2 py-1 rounded-lg border border-gray-300 bg-white text-gray-700 hover:bg-blue-50 disabled:opacity-50"
title="Primera página"
>«</button>
<button
onClick={e => handlePageChange(page - 1, e)}
disabled={page === 1}
className="px-2 py-1 rounded-lg border border-gray-300 bg-white text-gray-700 hover:bg-blue-50 disabled:opacity-50"
title="Anterior"
>&lt;</button>
{pageNumbers.map((num, idx) =>
num === '...'
? <span key={idx} className="px-2 text-gray-400 select-none"></span>
: <button
key={num}
onClick={e => handlePageChange(num, e)}
className={`px-2 py-1 rounded-lg border border-gray-300 ${num === page ? 'bg-blue-500 text-white font-bold' : 'bg-white text-gray-700 hover:bg-blue-50'} transition-colors`}
disabled={num === page}
>{num}</button>
)}
<button
onClick={e => handlePageChange(page + 1, e)}
disabled={page >= totalPages}
className="px-2 py-1 rounded-lg border border-gray-300 bg-white text-gray-700 hover:bg-blue-50 disabled:opacity-50"
title="Siguiente"
>&gt;</button>
<button
onClick={e => handlePageChange(totalPages, e)}
disabled={page >= totalPages}
className="px-2 py-1 rounded-lg border border-gray-300 bg-white text-gray-700 hover:bg-blue-50 disabled:opacity-50"
title="Última página"
>»</button>
</div>
{/* Derecha: Rango de registros */}
<div className="text-sm text-gray-600 w-full sm:w-auto text-right">
{docsCount > 0
? `Mostrando ${((page - 1) * pageSize) + 1} a ${Math.min(page * pageSize, docsCount)} de ${docsCount} registros`
: 'Mostrando 0 de 0 registros'}
</div>
</div>
</div>
</>
)}

View File

@@ -695,7 +695,7 @@ export default function Procesos() {
try {
// Construir filtros
const filters = {};
if (pedimentoPedimentoFilter) filters['pedimento__pedimento'] = pedimentoPedimentoFilter;
if (pedimentoPedimentoFilter) filters['pedimento__pedimento_app'] = pedimentoPedimentoFilter;
if (estadoFilter) filters['estado'] = estadoFilter;
if (servicioFilter) filters['servicio'] = servicioFilter;
if (sortField) {
@@ -1158,7 +1158,7 @@ export default function Procesos() {
</td>
<td className="px-4 py-4 whitespace-nowrap align-middle text-sm text-gray-900 font-mono">
{typeof proc.pedimento === 'object' && proc.pedimento !== null
? proc.pedimento.pedimento || JSON.stringify(proc.pedimento)
? proc.pedimento.pedimento_app || proc.pedimento.pedimento || JSON.stringify(proc.pedimento)
: proc.pedimento}
</td>
<td className="px-4 py-4 whitespace-nowrap align-middle text-sm text-gray-700">