// ============================================================ // 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) => (
{['csv','xlsx','sql'].map(format => ( ))}
); const booksPreview = data.preview.finished_books || []; const usersPreview = data.preview.user_participation || []; return
{message &&
{message.text}
} {data.error &&
{data.error}
}
Libros terminados
Todos los campos, rutas y cantidades reales de archivos
Registros
{Number(data.stats.finished_books || 0)}
Criterio
Estado completed · etapa published
Formato de salida
{formatSelector('finished_books')}
Incluye campos de books, proyecto, rutas de Digitalización, Edición y FINALIZADO, conteos registrados y conteos físicos reales.
Usuarios participantes
Libros y usuarios que intervinieron en cada proceso
Participaciones
{Number(data.stats.participations || 0)}
Procesos
Digitalización · Edición · Calidad · Conversión
Formato de salida
{formatSelector('user_participation')}
Incluye libro, proceso, usuario, perfiles, asignación, inicio, conclusión, estado y observaciones.
Vista previa · libros terminados
Primeros cinco registros encontrados
{booksPreview.map(row => )} {!booksPreview.length && }
InventarioTítuloSerieRuta finalDigitalizadasEditadasArchivos 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)}
Vista previa · participación de usuarios
Primeras ocho participaciones
{usersPreview.map(row => )} {!usersPreview.length && }
LibroProcesoUsuarioPerfilInicioConclusiónEstado
#{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}
; }; Object.assign(window, { Publicacion });