From de7676da26a38f11f0345aa9d0e51f1e6cece327 Mon Sep 17 00:00:00 2001 From: Juan Felipe Zapata Moreno Date: Fri, 22 Aug 2025 15:43:37 -0600 Subject: [PATCH] =?UTF-8?q?Se=20agregaron=20las=20gr=C3=A1ficas=20en=20tra?= =?UTF-8?q?mites?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dashboard/AtencionController.php | 181 +++++++++++------- .../Controllers/Dashboard/ObrasController.php | 22 ++- .../Dashboard/TramiteController.php | 37 +++- resources/js/Pages/App/AtencionCiudadana.vue | 47 +++-- resources/js/Pages/App/Obras.vue | 115 ++++++++++- resources/js/Pages/App/Tramites.vue | 131 +++++++------ 6 files changed, 370 insertions(+), 163 deletions(-) diff --git a/app/Http/Controllers/Dashboard/AtencionController.php b/app/Http/Controllers/Dashboard/AtencionController.php index 2274323..4c38771 100644 --- a/app/Http/Controllers/Dashboard/AtencionController.php +++ b/app/Http/Controllers/Dashboard/AtencionController.php @@ -4,6 +4,7 @@ use Illuminate\Http\Request; use Illuminate\Routing\Controller as BaseController; +use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Log; @@ -11,84 +12,40 @@ class AtencionController extends BaseController { public function Atencion(Request $request) { - $query = $request->only(['start', 'end', 'type', 'action']); + $query = $request->only(['start', 'end', 'type', 'action', 'period', 'charts_only']); $input = array_merge(['action' => 'index', 'type' => 'api'], $query); $startDate = $input['start'] ?? date('Y-01-01'); $endDate = $input['end'] ?? date('Y-12-31'); + $period = $input['period'] ?? null; + $chartsOnly = $input['charts_only'] ?? false; - $baseParams = [ - 'start_date' => $startDate, - 'end_date' => $endDate, - 'type' => $input['type'] ?? 'api', - 'action' => $input['action'] ?? 'index', - ]; + // Cache key para diferentes tipos de peticiones + $cacheKey = 'atencion_' . md5(serialize([ + 'start' => $startDate, + 'end' => $endDate, + 'period' => $period, + 'charts_only' => $chartsOnly + ])); - $baseUrl = 'https://apoyos.comalcalco.gob.mx/beneficiaries/stats-by-date-range'; - $countsUrl = 'https://apoyos.comalcalco.gob.mx/beneficiaries/counts-by-date'; - $dashboardUrl = 'https://apoyos.comalcalco.gob.mx/beneficiaries/dashboard/api'; - $dashboardUrl2 = 'https://apoyos.comalcalco.gob.mx/beneficiaries/dashboard/api?type=servicio'; + // Intentar obtener desde cache (2 minutos) + if (Cache::has($cacheKey)) { + return response()->json(Cache::get($cacheKey), 200) + ->header('Content-Type', 'application/json'); + } try { - $response = Http::get($baseUrl, $baseParams); - - if (!$response->successful()) { - return response()->json(['error' => 'Error del servicio'], $response->status()); + // Si solo necesitamos gráficas, hacer menos peticiones + if ($chartsOnly) { + $result = $this->getChartsData($startDate, $endDate); + } else { + $result = $this->getFullData($startDate, $endDate, $period); } - $mainData = $response->json(); - $countsAc = []; - try { - $countsResp = Http::get($countsUrl, [ - 'start_date' => $startDate, - 'end_date' => $endDate, - ]); + // Cachear resultado por 2 minutos + Cache::put($cacheKey, $result, 120); - if ($countsResp->successful()) { - $countsAc = $countsResp->json(); - } else { - Log::error('Error al obtener los conteos de atención', ['status' => $countsResp->status()]); - } - } catch (\Exception $e) { - Log::error('Error al obtener los conteos de atención', ['exception' => $e->getMessage()]); - } - - $dashboardData = []; - try { - $dashboardResp = Http::get($dashboardUrl); - - if ($dashboardResp->successful()) { - $dashboardData = $dashboardResp->json(); - } else { - Log::error('Error al obtener datos del dashboard', ['status' => $dashboardResp->status()]); - } - } catch (\Exception $e) { - Log::error('Error al obtener datos del dashboard', ['exception' => $e->getMessage()]); - } - - $dashboardServicioData = []; - try { - $dashboardResp2 = Http::get($dashboardUrl2); - - if ($dashboardResp2->successful()) { - $dashboardServicioData = $dashboardResp2->json(); - } else { - Log::error('Error al obtener datos del dashboard servicio', ['status' => $dashboardResp2->status()]); - } - } catch (\Exception $e) { - Log::error('Error al obtener datos del dashboard servicio', ['exception' => $e->getMessage()]); - } - - // Combina todos los resultados - $combinedData = array_merge( - is_array($mainData) ? $mainData : [], - [ - 'counts' => $countsAc, - 'dashboard' => $dashboardData, - 'dashboard_servicio' => $dashboardServicioData, - ] - ); - return response()->json($combinedData, 200) + return response()->json($result, 200) ->header('Content-Type', 'application/json'); } catch (\Exception $e) { Log::error('Error en la consulta de atención', ['exception' => $e->getMessage()]); @@ -96,6 +53,96 @@ public function Atencion(Request $request) } } + private function getChartsData($startDate, $endDate) + { + $baseParams = [ + 'start_date' => $startDate, + 'end_date' => $endDate, + 'type' => 'api', + 'action' => 'index', + ]; + + $baseUrl = 'https://apoyos.comalcalco.gob.mx/beneficiaries/stats-by-date-range'; + + // Solo hacer la petición principal para gráficas + $response = Http::timeout(15)->get($baseUrl, $baseParams); + + if (!$response->successful()) { + throw new \Exception('Error del servicio principal'); + } + + return $response->json(); + } + + private function getFullData($startDate, $endDate, $period) + { + $baseParams = [ + 'start_date' => $startDate, + 'end_date' => $endDate, + 'type' => 'api', + 'action' => 'index', + ]; + + $urls = [ + 'main' => 'https://apoyos.comalcalco.gob.mx/beneficiaries/stats-by-date-range', + 'counts' => 'https://apoyos.comalcalco.gob.mx/beneficiaries/counts-by-date', + 'dashboard' => 'https://apoyos.comalcalco.gob.mx/beneficiaries/dashboard/api', + 'dashboard_servicio' => 'https://apoyos.comalcalco.gob.mx/beneficiaries/dashboard/api?type=servicio' + ]; + + // Hacer peticiones en paralelo usando HTTP Pool + $responses = Http::pool(fn($pool) => [ + $pool->timeout(15)->get($urls['main'], $baseParams), + $pool->timeout(15)->get($urls['counts'], [ + 'start_date' => $startDate, + 'end_date' => $endDate, + ]), + $pool->timeout(15)->get($urls['dashboard']), + $pool->timeout(15)->get($urls['dashboard_servicio']) + ]); + + $mainData = []; + $countsAc = []; + $dashboardData = []; + $dashboardServicioData = []; + + // Procesar respuestas + if ($responses[0]->successful()) { + $mainData = $responses[0]->json(); + } else { + Log::error('Error en petición principal', ['status' => $responses[0]->status()]); + } + + if ($responses[1]->successful()) { + $countsAc = $responses[1]->json(); + } else { + Log::error('Error en petición counts', ['status' => $responses[1]->status()]); + } + + if ($responses[2]->successful()) { + $dashboardData = $responses[2]->json(); + } else { + Log::error('Error en petición dashboard', ['status' => $responses[2]->status()]); + } + + if ($responses[3]->successful()) { + $dashboardServicioData = $responses[3]->json(); + } else { + Log::error('Error en petición dashboard servicio', ['status' => $responses[3]->status()]); + } + + // Combinar todos los resultados + return array_merge( + is_array($mainData) ? $mainData : [], + [ + 'counts' => $countsAc, + 'dashboard' => $dashboardData, + 'dashboard_servicio' => $dashboardServicioData, + ] + ); + } + + public function getSupportOptions(Request $request) { try { diff --git a/app/Http/Controllers/Dashboard/ObrasController.php b/app/Http/Controllers/Dashboard/ObrasController.php index c8ee62f..b1b7455 100644 --- a/app/Http/Controllers/Dashboard/ObrasController.php +++ b/app/Http/Controllers/Dashboard/ObrasController.php @@ -4,6 +4,7 @@ use Illuminate\Routing\Controller as BaseController; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Cache; class ObrasController extends BaseController { @@ -12,10 +13,23 @@ public function Obras(Request $request) $query = $request->only(['start', 'end', 'type', 'action']); $query = array_merge($query, ['action' => 'index', 'type' => 'api'], $query); + // Caché por 2 minutos (datos más dinámicos) + $cacheKey = "obras_data_" . md5(serialize($query)); + + if ($cachedData = Cache::get($cacheKey)) { + return response()->json($cachedData, 200) + ->header('Content-Type', 'application/json'); + } + try { $response = Http::timeout(5)->get('https://obras-information.comalcalco.gob.mx/api/controller.php', $query); if (! $response->successful()) { + Log::warning('Obras service error', [ + 'status' => $response->status(), + 'body' => $response->body(), + 'query' => $query + ]); return response()->json(['error' => 'External service error'], $response->status()); } @@ -40,10 +54,16 @@ public function Obras(Request $request) // Combinar ambas respuestas $combinedData = array_merge($mainData, ['counters' => $countersData, 'users' => $usersData]); + // Cachear por 2 minutos + Cache::put($cacheKey, $combinedData, now()->addMinutes(2)); + return response()->json($combinedData, $response->status()) ->header('Content-Type', $response->header('Content-Type', 'application/json')); } catch (\Throwable $e) { - Log::error('Proxy error: '.$e->getMessage()); + Log::error('Proxy error: '.$e->getMessage(), [ + 'query' => $query, + 'trace' => $e->getTraceAsString() + ]); return response()->json(['error' => 'Unable to contact external service'], 502); } } diff --git a/app/Http/Controllers/Dashboard/TramiteController.php b/app/Http/Controllers/Dashboard/TramiteController.php index 12cccf2..214f539 100644 --- a/app/Http/Controllers/Dashboard/TramiteController.php +++ b/app/Http/Controllers/Dashboard/TramiteController.php @@ -1,9 +1,12 @@ -only(['start', 'end', 'type']); $query = array_merge(['type' => 'api'], $query); - try { - $response = Http::timeout(5)->get('https://tramites.comalcalco.gob.mx/reporte-especial', $query); + // Caché por 2 minutos (datos más dinámicos) + $cacheKey = "tramites_data_" . md5(serialize($query)); - if (! $response->successful()) { + if ($cachedData = Cache::get($cacheKey)) { + return response()->json($cachedData, 200) + ->header('Content-Type', 'application/json'); + } + + try { + $response = Http::timeout(20)->get('https://tramites.comalcalco.gob.mx/reporte-especial', $query); + + if (!$response->successful()) { + Log::warning('Tramites service error', [ + 'status' => $response->status(), + 'body' => $response->body(), + 'query' => $query + ]); return response()->json(['error' => 'External service error'], $response->status()); } - return response()->json($response->json(), $response->status()) + $data = $response->json(); + + // Cachear por 2 minutos + Cache::put($cacheKey, $data, now()->addMinutes(2)); + + return response()->json($data, $response->status()) ->header('Content-Type', $response->header('Content-Type', 'application/json')); + } catch (\Throwable $e) { - Log::error('Proxy error: '.$e->getMessage()); + Log::error('Proxy error: ' . $e->getMessage(), [ + 'query' => $query, + 'trace' => $e->getTraceAsString() + ]); return response()->json(['error' => 'Unable to contact external service'], 502); } } diff --git a/resources/js/Pages/App/AtencionCiudadana.vue b/resources/js/Pages/App/AtencionCiudadana.vue index 668b9b8..529f8e4 100644 --- a/resources/js/Pages/App/AtencionCiudadana.vue +++ b/resources/js/Pages/App/AtencionCiudadana.vue @@ -67,11 +67,10 @@ const periodOptions = [ { id: "semana", name: "Esta Semana" }, ]; -// NUEVO: Función para cargar datos de gráficas +//Función para cargar datos de gráficas const loadChartsData = async () => { const cacheKey = getChartsCacheKey(); - // Verificar cache de gráficas if (chartsCache.has(cacheKey)) { const cachedData = chartsCache.get(cacheKey); buildChartsFromData(cachedData); @@ -87,19 +86,16 @@ const loadChartsData = async () => { const res = await axios.get("/api/reporte-atencion", { params, - timeout: 10000, + timeout: 20000, // Aumentar timeout headers: { "X-Requested-With": "XMLHttpRequest" }, }); const payload = res.data || {}; - - // Guardar en cache de gráficas chartsCache.set(cacheKey, payload); - buildChartsFromData(payload); } catch (e) { console.error("Error cargando datos de gráficas:", e); - // En caso de error, mantener gráficas actuales o limpiar + // En caso de error, mantener gráficas actuales } }; @@ -139,17 +135,15 @@ const normalizeResponse = (res) => { const load = async () => { const cacheKey = getCacheKey(); - // Verificar cache primero if (cache.has(cacheKey)) { const cachedData = cache.get(cacheKey); - applyDataToComponents(cachedData); + applyDataToComponents(cachedData, false); // Sin gráficas return; } loading.value = true; error.value = null; - // Cancelar petición anterior if (cancelTokenSource) { cancelTokenSource.cancel("cancel"); } @@ -158,28 +152,22 @@ const load = async () => { try { const params = { period: selectedPeriod.value, - // NO incluir fechas personalizadas aquí }; const res = await axios.get("/api/reporte-atencion", { params, - timeout: 10000, + timeout: 20000, // Aumentar timeout cancelToken: cancelTokenSource.token, headers: { "X-Requested-With": "XMLHttpRequest" }, }); const payload = res.data || {}; - - // Guardar en cache cache.set(cacheKey, payload); - - // Aplicar datos (SIN gráficas) - applyDataToComponents(payload, false); + applyDataToComponents(payload, false); // Sin gráficas para evitar conflicto } catch (e) { if (!axios.isCancel(e)) { console.error("Error en la petición:", e); - error.value = - e.response?.data?.error || e.message || "Error al cargar datos"; + error.value = e.response?.data?.error || e.message || "Error al cargar datos"; clearComponentData(); } } finally { @@ -421,13 +409,32 @@ const closeExportModal = () => { showExportModal.value = false; }; +const toggleGroup = (typeName) => { + if (expandedGroups.value.has(typeName)) { + expandedGroups.value.delete(typeName); + } else { + expandedGroups.value.add(typeName); + } +}; + // Watchers para recargar datos cuando cambien los filtros watch([selectedDepartment, selectedType, selectedPeriod], () => { clearTimeout(debounceId); debounceId = setTimeout(load, 100); }); -onMounted(load); +onMounted(() => { + // Cargar datos iniciales + load(); + // Cargar gráficas iniciales + loadChartsData(); + + // Limpiar caches + setInterval(() => { + cache.clear(); + chartsCache.clear(); + }, 600000); // 10 minutos +});