Files
portal-epromos/admin/dashboard_landing_widget_data.php
T

172 lines
5.4 KiB
PHP

<?php
// ruleta/admin/dashboard_landing_widget_data.php
header('Content-Type: application/json; charset=utf-8');
// No HTML en errores:
ini_set('display_errors', '0');
ini_set('log_errors', '1');
// Captura warnings/notices para adjuntarlos al JSON:
$php_warnings = [];
set_error_handler(function($errno, $errstr, $errfile, $errline) use (&$php_warnings) {
if (error_reporting() === 0) return true;
$php_warnings[] = "$errstr in $errfile:$errline";
return true;
});
// Limpia cualquier output previo
while (ob_get_level() > 0) { ob_end_clean(); }
ob_start();
session_start();
require_once __DIR__ . '/db.php';
if (empty($_SESSION['admin_id'])) {
http_response_code(401);
echo json_encode(['ok'=>false, 'error'=>'auth']);
exit;
}
// Helper seguro para prepares
function must_prepare(mysqli $conn, string $sql): mysqli_stmt {
$st = $conn->prepare($sql);
if (!$st) {
throw new RuntimeException('prepare_failed: '. $conn->error .' | SQL='. preg_replace('/\s+/', ' ', $sql));
}
return $st;
}
function qcount(mysqli $conn, string $sql): int {
$rs = $conn->query($sql);
if (!$rs) throw new RuntimeException('query_failed: '. $conn->error .' | SQL='. preg_replace('/\s+/', ' ', $sql));
$row = $rs->fetch_assoc();
return (int)($row['c'] ?? 0);
}
try {
$from = trim($_GET['from'] ?? '');
$to = trim($_GET['to'] ?? '');
$landing_id = (int)($_GET['landing_id'] ?? 0);
$want_meta = (int)($_GET['meta'] ?? 0);
if ($from === '' || $to === '') {
$to = date('Y-m-d');
$from = date('Y-m-d', strtotime($to.' -30 day'));
}
$from_dt = $from.' 00:00:00';
$to_dt = $to.' 23:59:59';
// --- KPIs
$kpis = [
'landings' => qcount($conn, "SELECT COUNT(*) c FROM landing_pages"),
'variants' => qcount($conn, "SELECT COUNT(*) c FROM landing_variants"),
'blocks' => qcount($conn, "SELECT COUNT(*) c FROM landing_blocks"),
'leads_window' => 0,
'range_label' => date('d M', strtotime($from)).' - '.date('d M', strtotime($to)),
'filtered' => $landing_id > 0
];
if ($landing_id > 0) {
$st = must_prepare($conn, "SELECT COUNT(*) c FROM landing_forms WHERE landing_id=? AND created_at BETWEEN ? AND ?");
$st->bind_param('iss', $landing_id, $from_dt, $to_dt);
} else {
$st = must_prepare($conn, "SELECT COUNT(*) c FROM landing_forms WHERE created_at BETWEEN ? AND ?");
$st->bind_param('ss', $from_dt, $to_dt);
}
$st->execute();
$r = $st->get_result()->fetch_assoc();
$kpis['leads_window'] = (int)($r['c'] ?? 0);
// --- Top + series
$top = [];
if ($landing_id > 0) {
$st = must_prepare($conn, "
SELECT lp.id AS landing_id, lp.titulo,
SUM(lvs.event_type='impression') AS imps,
SUM(lvs.event_type='conversion') AS conv,
ROUND(SUM(lvs.event_type='conversion')/NULLIF(SUM(lvs.event_type='impression'),0)*100,2) AS cr
FROM landing_pages lp
LEFT JOIN landing_variant_stats lvs
ON lvs.landing_id=lp.id
AND lvs.created_at BETWEEN ? AND ?
WHERE lp.id=?
GROUP BY lp.id, lp.titulo
");
$st->bind_param('ssi', $from_dt, $to_dt, $landing_id);
} else {
// --- Top global (landing_id = 0): usar subquery para poder ordenar por 'cr'
$st = must_prepare($conn, "
SELECT landing_id, titulo, imps, conv, cr
FROM (
SELECT
lp.id AS landing_id,
lp.titulo,
SUM(lvs.event_type='impression') AS imps,
SUM(lvs.event_type='conversion') AS conv,
ROUND(
SUM(lvs.event_type='conversion') / NULLIF(SUM(lvs.event_type='impression'), 0) * 100, 2
) AS cr
FROM landing_pages lp
LEFT JOIN landing_variant_stats lvs
ON lvs.landing_id = lp.id
AND lvs.created_at BETWEEN ? AND ?
GROUP BY lp.id, lp.titulo
) t
ORDER BY (cr IS NULL), cr DESC, imps DESC
LIMIT 10
");
$st->bind_param('ss', $from_dt, $to_dt);
}
$st->execute();
$rs = $st->get_result();
while($row = $rs->fetch_assoc()){
$row['imps'] = (int)($row['imps'] ?? 0);
$row['conv'] = (int)($row['conv'] ?? 0);
$row['cr'] = $row['imps'] ? (float)$row['cr'] : null;
// Serie diaria
$st2 = must_prepare($conn, "
SELECT DATE(created_at) d,
SUM(event_type='impression') imp,
SUM(event_type='conversion') conv
FROM landing_variant_stats
WHERE landing_id=? AND created_at BETWEEN ? AND ?
GROUP BY DATE(created_at)
ORDER BY d ASC
");
$lid = (int)$row['landing_id'];
$st2->bind_param('iss', $lid, $from_dt, $to_dt);
$st2->execute();
$ser = $st2->get_result()->fetch_all(MYSQLI_ASSOC);
$row['series'] = array_map(function($p){
return ['d'=>$p['d'], 'imp'=>(int)$p['imp'], 'conv'=>(int)$p['conv']];
}, $ser);
$top[] = $row;
}
// Lista para el select (si meta=1)
$landings_list = [];
if ($want_meta === 1) {
$q = $conn->query("SELECT id, titulo FROM landing_pages ORDER BY titulo ASC");
if (!$q) throw new RuntimeException('query_failed: '. $conn->error .' | SQL=SELECT id,titulo FROM landing_pages ORDER BY titulo ASC');
while($L = $q->fetch_assoc()){
$landings_list[] = ['id'=>(int)$L['id'], 'titulo'=>$L['titulo']];
}
}
$warnings = $php_warnings;
ob_end_clean();
echo json_encode([
'ok'=>true,
'kpis'=>$kpis,
'top'=>$top,
'landings_list'=>$landings_list,
'warnings'=>$warnings
], JSON_UNESCAPED_UNICODE);
} catch (Throwable $e) {
ob_end_clean();
http_response_code(500);
echo json_encode(['ok'=>false, 'error'=>$e->getMessage()], JSON_UNESCAPED_UNICODE);
}