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:
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
><</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"
|
||||
>></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"
|
||||
><</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"
|
||||
>></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>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user