// ============================================================ // Publicar BD — exportación real CSV, XLSX y SQL // ============================================================ const Publicacion = () => { const [data, setData] = useState({ status: 'loading', stats: {}, preview: {}, error: '' }); const [formats, setFormats] = useState({ finished_books: 'xlsx', user_participation: 'xlsx' }); const [downloading, setDownloading] = useState(''); const [message, setMessage] = useState(null); const baseUrl = window.APP_CONFIG.API_BASE_URL.replace(/\/$/, ''); const load = async () => { setData(previous => ({ ...previous, status: 'loading', error: '' })); try { const response = await apiRequest('publication/dashboard.php'); setData({ status: 'loaded', stats: response.data?.stats || {}, preview: response.data?.preview || {}, error: '', }); } catch (error) { setData(previous => ({ ...previous, status: 'error', error: error.message || 'No fue posible cargar Publicar BD.' })); } }; useEffect(() => { load(); }, []); const fileNameFromHeader = (header, fallback) => { const utf8 = header.match(/filename\*=UTF-8''([^;]+)/i); if (utf8) return decodeURIComponent(utf8[1]); const simple = header.match(/filename="?([^";]+)"?/i); return simple ? simple[1] : fallback; }; const download = async (report) => { const format = formats[report]; const key = `${report}-${format}`; setDownloading(key); setMessage(null); try { const response = await fetch(`${baseUrl}/publication/export.php?report=${encodeURIComponent(report)}&format=${encodeURIComponent(format)}`, { method: 'GET', credentials: 'include', cache: 'no-store', }); if (!response.ok) { let text = `No fue posible generar el archivo. HTTP ${response.status}`; try { const payload = await response.json(); text = payload.message || text; if (payload.errors?.[0]?.message) text += ` ${payload.errors[0].message}`; } catch (error) {} throw new Error(text); } const blob = await response.blob(); const fallback = `${report}_${new Date().toISOString().slice(0,19).replaceAll(':','-')}.${format}`; const fileName = fileNameFromHeader(response.headers.get('content-disposition') || '', fallback); const url = URL.createObjectURL(blob); const anchor = document.createElement('a'); anchor.href = url; anchor.download = fileName; document.body.appendChild(anchor); anchor.click(); anchor.remove(); setTimeout(() => URL.revokeObjectURL(url), 1500); setMessage({ tone: 'success', text: `Exportación generada: ${fileName}` }); } catch (error) { setMessage({ tone: 'error', text: error.message || 'No fue posible descargar la exportación.' }); } finally { setDownloading(''); } }; const formatSelector = (report) => (
| Inventario | Título | Serie | Ruta final | Digitalizadas | Editadas | Archivos finales |
|---|---|---|---|---|---|---|
| {row.inventory_number} | {row.title} {row.author || '—'} | {row.series_collection || '—'} | {row.final_path || '—'} | {Number(row.digitalization_real_images || 0)} | {Number(row.editing_real_images || 0)} | {Number(row.real_final_total_files || 0)} |
| Libro | Proceso | Usuario | Perfil | Inicio | Conclusión | Estado |
|---|---|---|---|---|---|---|
| #{row.inventory_number} {row.title} | {row.process_stage} | {row.user_name} @{row.username} | {row.user_roles || '—'} | {row.started_at || row.assigned_at || '—'} | {row.completed_at || '—'} | {row.assignment_status} |