// ============================================================ // Auditoría de Digitalización // Optimizada: Finalizados paginados + hojas PDF cargadas por libro // ============================================================ const AuditoriaDigitalizacion = ({ onSessionExpired }) => { const [activeTab, setActiveTab] = useState('digitalized'); const [digitalized, setDigitalized] = useState({ items: [], summary: { total_books: 0, mismatch_books: 0, database_images: 0, filesystem_images: 0, difference: 0, }, loading: true, error: '', }); const [finalized, setFinalized] = useState({ items: [], summary: { total_books: 0, database_images: 0, jpg_count: 0, tiff_count: 0, pdf_color_files: 0, pdf_bw_files: 0, pdf_optimized_files: 0, }, pagination: { page: 1, per_page: 20, total: 0, total_pages: 1, }, loading: false, error: '', }); const [searchInput, setSearchInput] = useState(''); const [search, setSearch] = useState(''); const [onlyMismatch, setOnlyMismatch] = useState(false); const formatNumber = (value) => new Intl.NumberFormat('es-MX').format(Number(value || 0)); const formatDate = (value) => { if (!value) return '—'; const date = new Date(String(value).replace(' ', 'T')); if (Number.isNaN(date.getTime())) { return value; } return date.toLocaleString('es-MX', { dateStyle: 'short', timeStyle: 'short', }); }; const loadDigitalized = async () => { setDigitalized((previous) => ({ ...previous, loading: true, error: '', })); try { const params = new URLSearchParams(); params.set('view', 'digitalized'); if (search) params.set('search', search); if (onlyMismatch) params.set('only_mismatch', '1'); const response = await window.apiRequest( `digitalization/image-audit.php?${params.toString()}` ); const data = response?.data || {}; setDigitalized({ items: Array.isArray(data.items) ? data.items : [], summary: data.summary || {}, loading: false, error: '', }); } catch (err) { if (err?.status === 401) { onSessionExpired(); return; } setDigitalized((previous) => ({ ...previous, loading: false, error: err?.message || 'No fue posible cargar la auditoría.', })); } }; const loadPdfPagesProgressively = async (items) => { for (const item of items) { try { const response = await window.apiRequest( `digitalization/image-audit.php?view=finalized_pdf&book_id=${encodeURIComponent(item.book_id)}` ); const detail = response?.data || {}; setFinalized((previous) => ({ ...previous, items: previous.items.map((row) => Number(row.book_id) === Number(item.book_id) ? { ...row, pdf_color_pages: detail.pdf_color_pages, pdf_bw_pages: detail.pdf_bw_pages, pdf_optimized_pages: detail.pdf_optimized_pages, pdf_pages_status: 'loaded', } : row ), })); } catch (err) { if (err?.status === 401) { onSessionExpired(); return; } setFinalized((previous) => ({ ...previous, items: previous.items.map((row) => Number(row.book_id) === Number(item.book_id) ? { ...row, pdf_pages_status: 'error', } : row ), })); } } }; const loadFinalized = async (page = finalized.pagination.page) => { setFinalized((previous) => ({ ...previous, loading: true, error: '', })); try { const params = new URLSearchParams(); params.set('view', 'finalized'); params.set('page', String(page)); params.set('per_page', '20'); if (search) params.set('search', search); const response = await window.apiRequest( `digitalization/image-audit.php?${params.toString()}` ); const data = response?.data || {}; const items = Array.isArray(data.items) ? data.items : []; setFinalized({ items, summary: data.summary || {}, pagination: data.pagination || { page: 1, per_page: 20, total: items.length, total_pages: 1, }, loading: false, error: '', }); window.setTimeout(() => { loadPdfPagesProgressively(items); }, 50); } catch (err) { if (err?.status === 401) { onSessionExpired(); return; } setFinalized((previous) => ({ ...previous, loading: false, error: err?.message || 'No fue posible cargar los libros finalizados.', })); } }; useEffect(() => { if (activeTab === 'finalized') { loadFinalized(1); } else { loadDigitalized(); } }, [activeTab, search, onlyMismatch]); const submitSearch = (event) => { event.preventDefault(); setSearch(searchInput.trim()); }; const clearSearch = () => { setSearchInput(''); setSearch(''); }; const changeTab = (tab) => { setActiveTab(tab); setSearchInput(''); setSearch(''); setOnlyMismatch(false); }; const escapeHtml = (value) => String(value ?? '') .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"'); const excelText = (value) => `
| ${escapeHtml(h)} | `).join('')}
|---|
| {label} | ))}|||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| {item.inventory_number || item.barcode || '—'} |
{item.title || 'Sin título'}
{item.series_collection || 'Sin serie'}
|
{item.converted_by || '—'} | {formatDate(item.completed_at)} | {formatNumber(item.database_image_count)} | {formatNumber(item.jpg_count)} | {formatNumber(item.tiff_count)} | {formatNumber(item.pdf_color_count)} |
|
{formatNumber(item.pdf_bw_count)} |
|
{formatNumber(item.pdf_optimized_count)} |
|
{item.folder_exists ? item.relative_path : 'Carpeta no encontrada'} |
| {label} | ))}|||||||
|---|---|---|---|---|---|---|---|
| {item.inventory_number || item.barcode || '—'} | {item.title || 'Sin título'} | {item.digitalized_by || '—'} | {formatDate(item.completed_at)} | {formatNumber(item.database_image_count)} | {formatNumber(item.filesystem_image_count)} | {item.difference > 0 ? '+' : ''} {formatNumber(item.difference)} | {mismatch ? 'Diferencia' : 'Correcto'} |