Showing
43 changed files
with
111 additions
and
312 deletions
| ... | @@ -4,7 +4,7 @@ | ... | @@ -4,7 +4,7 @@ |
| 4 | "version": "0.0.1", | 4 | "version": "0.0.1", |
| 5 | "type": "module", | 5 | "type": "module", |
| 6 | "scripts": { | 6 | "scripts": { |
| 7 | - "dev": "vite dev", | 7 | + "dev": "NODE_TLS_REJECT_UNAUTHORIZED=0 vite dev", |
| 8 | "build": "vite build", | 8 | "build": "vite build", |
| 9 | "preview": "vite preview", | 9 | "preview": "vite preview", |
| 10 | "prepare": "svelte-kit sync || echo ''" | 10 | "prepare": "svelte-kit sync || echo ''" | ... | ... |
src/lib/api.js
0 → 100644
| 1 | +// ═══════════════════════════════════════════════════════════════ | ||
| 2 | +// CONFIGURACIÓN CENTRAL DE API | ||
| 3 | +// Cambiar la IP aquí actualiza todas las llamadas del proyecto | ||
| 4 | +// ═══════════════════════════════════════════════════════════════ | ||
| 5 | + | ||
| 6 | +export const API_HOST = 'https://abierto.economiayfinanzas.gob.bo/presupuesto'; | ||
| 7 | +export const DOWNLOAD_BASE = 'https://abierto.economiayfinanzas.gob.bo/presupuesto/descargas/'; |
This diff is collapsed. Click to expand it.
| 1 | import { error } from '@sveltejs/kit'; | 1 | import { error } from '@sveltejs/kit'; |
| 2 | 2 | ||
| 3 | -const API_BASE = 'http://136.112.29.74/api/acteco'; | 3 | +import { API_HOST } from '$lib/api.js'; |
| 4 | +const API_BASE = API_HOST + '/api/acteco'; | ||
| 4 | 5 | ||
| 5 | // Jerarquía acteco: códigos con punto "1" → "1.1" → "1.1.1" | 6 | // Jerarquía acteco: códigos con punto "1" → "1.1" → "1.1.1" |
| 6 | // Todos tienen nivel "actividad" en la API, derivamos la profundidad del código | 7 | // Todos tienen nivel "actividad" en la API, derivamos la profundidad del código | ... | ... |
| 1 | -const API_BASE = 'http://136.112.29.74/api/acteco'; | 1 | +import { API_HOST } from '$lib/api.js'; |
| 2 | +const API_BASE = API_HOST + '/api/acteco'; | ||
| 2 | 3 | ||
| 3 | export async function GET({ url }) { | 4 | export async function GET({ url }) { |
| 4 | const codigo = url.searchParams.get('codigo') || ''; | 5 | const codigo = url.searchParams.get('codigo') || ''; | ... | ... |
| 1 | -const API_BASE = 'http://136.112.29.74/api/acteco'; | 1 | +import { API_HOST } from '$lib/api.js'; |
| 2 | +const API_BASE = API_HOST + '/api/acteco'; | ||
| 2 | 3 | ||
| 3 | export async function GET({ url }) { | 4 | export async function GET({ url }) { |
| 4 | const codigo = url.searchParams.get('codigo') || ''; | 5 | const codigo = url.searchParams.get('codigo') || ''; | ... | ... |
| 1 | -const API_BASE = 'http://136.112.29.74/api/diario'; | 1 | +import { API_HOST } from '$lib/api.js'; |
| 2 | +const API_BASE = API_HOST + '/api/diario'; | ||
| 2 | 3 | ||
| 3 | export async function GET({ url }) { | 4 | export async function GET({ url }) { |
| 4 | const tipo = url.searchParams.get('tipo') || 'status'; | 5 | const tipo = url.searchParams.get('tipo') || 'status'; | ... | ... |
| 1 | -const API_BASE = 'http://136.112.29.74/api/entidad'; | 1 | +import { API_HOST } from '$lib/api.js'; |
| 2 | +const API_BASE = API_HOST + '/api/entidad'; | ||
| 2 | 3 | ||
| 3 | export async function GET({ url }) { | 4 | export async function GET({ url }) { |
| 4 | const codigo = url.searchParams.get('codigo') || ''; | 5 | const codigo = url.searchParams.get('codigo') || ''; | ... | ... |
| 1 | -const API_BASE = 'http://136.112.29.74/api/finfun/clasificador'; | 1 | +import { API_HOST } from '$lib/api.js'; |
| 2 | +const API_BASE = API_HOST + '/api/finfun/clasificador'; | ||
| 2 | 3 | ||
| 3 | export async function GET() { | 4 | export async function GET() { |
| 4 | try { | 5 | try { |
| 5 | const response = await fetch(API_BASE); | 6 | const response = await fetch(API_BASE); |
| 6 | - if (!response.ok) { | 7 | + if (!response.ok) throw new Error(); |
| 7 | - return new Response(JSON.stringify({ error: `API error: ${response.status}` }), { | ||
| 8 | - status: response.status, headers: { 'Content-Type': 'application/json' } | ||
| 9 | - }); | ||
| 10 | - } | ||
| 11 | const data = await response.json(); | 8 | const data = await response.json(); |
| 12 | return new Response(JSON.stringify(data), { | 9 | return new Response(JSON.stringify(data), { |
| 13 | headers: { 'Content-Type': 'application/json' } | 10 | headers: { 'Content-Type': 'application/json' } | ... | ... |
| 1 | -const API_BASE = 'http://136.112.29.74/api/finfun'; | 1 | +import { API_HOST } from '$lib/api.js'; |
| 2 | +const API_BASE = API_HOST + '/api/finfun'; | ||
| 2 | 3 | ||
| 3 | export async function GET({ url }) { | 4 | export async function GET({ url }) { |
| 4 | const codigo = url.searchParams.get('codigo') || ''; | 5 | const codigo = url.searchParams.get('codigo') || ''; | ... | ... |
| 1 | -const API_BASE = 'http://136.112.29.74/api/finfun'; | 1 | +import { API_HOST } from '$lib/api.js'; |
| 2 | +const API_BASE = API_HOST + '/api/finfun'; | ||
| 2 | 3 | ||
| 4 | +// Cache en memoria | ||
| 3 | let cachedClasificador = null; | 5 | let cachedClasificador = null; |
| 4 | let cachedEstados = null; | 6 | let cachedEstados = null; |
| 5 | let cachedTimestamp = 0; | 7 | let cachedTimestamp = 0; |
| 6 | const CACHE_TTL = 5 * 60 * 1000; | 8 | const CACHE_TTL = 5 * 60 * 1000; |
| 7 | 9 | ||
| 8 | -function getParent(finfun) { | 10 | +function getParent(finfun, nivel) { |
| 9 | - const idx = finfun.lastIndexOf('.'); | 11 | + const code = String(finfun); |
| 10 | - if (idx === -1) return null; | 12 | + if (nivel === 'finalidad') return null; |
| 11 | - return finfun.substring(0, idx); | 13 | + if (nivel === 'grp_funcion') { |
| 14 | + return code.startsWith('10') ? '10' : code.charAt(0); | ||
| 15 | + } | ||
| 16 | + if (nivel === 'funcion') { | ||
| 17 | + if (code.startsWith('10')) return code.substring(0, 3); | ||
| 18 | + return code.substring(0, 2); | ||
| 19 | + } | ||
| 20 | + return null; | ||
| 12 | } | 21 | } |
| 13 | 22 | ||
| 14 | async function loadAndCacheAll() { | 23 | async function loadAndCacheAll() { |
| ... | @@ -58,7 +67,7 @@ export async function GET({ url }) { | ... | @@ -58,7 +67,7 @@ export async function GET({ url }) { |
| 58 | nivel: item.nivel, | 67 | nivel: item.nivel, |
| 59 | finfun: item.finfun, | 68 | finfun: item.finfun, |
| 60 | desc_finfun: item.desc_finfun, | 69 | desc_finfun: item.desc_finfun, |
| 61 | - parent: getParent(item.finfun), | 70 | + parent: getParent(item.finfun, item.nivel), |
| 62 | devengado: yearData.total | 71 | devengado: yearData.total |
| 63 | }); | 72 | }); |
| 64 | } | 73 | } |
| ... | @@ -89,7 +98,7 @@ export async function GET({ url }) { | ... | @@ -89,7 +98,7 @@ export async function GET({ url }) { |
| 89 | nivel: item.nivel, | 98 | nivel: item.nivel, |
| 90 | finfun: item.finfun, | 99 | finfun: item.finfun, |
| 91 | desc_finfun: item.desc_finfun, | 100 | desc_finfun: item.desc_finfun, |
| 92 | - parent: getParent(item.finfun), | 101 | + parent: getParent(item.finfun, item.nivel), |
| 93 | devengado: yearData.monto | 102 | devengado: yearData.monto |
| 94 | }; | 103 | }; |
| 95 | } catch { return null; } | 104 | } catch { return null; } | ... | ... |
| 1 | -const API_BASE = 'http://136.112.29.74/api/finfun'; | 1 | +import { API_HOST } from '$lib/api.js'; |
| 2 | +const API_BASE = API_HOST + '/api/finfun'; | ||
| 2 | 3 | ||
| 3 | export async function GET({ url }) { | 4 | export async function GET({ url }) { |
| 4 | const codigo = url.searchParams.get('codigo') || ''; | 5 | const codigo = url.searchParams.get('codigo') || ''; | ... | ... |
| 1 | -const API_BASE = 'http://136.112.29.74/api/objeto'; | 1 | +import { API_HOST } from '$lib/api.js'; |
| 2 | +const API_BASE = API_HOST + '/api/objeto'; | ||
| 2 | 3 | ||
| 3 | export async function GET({ url }) { | 4 | export async function GET({ url }) { |
| 4 | const codigo = url.searchParams.get('codigo') || ''; | 5 | const codigo = url.searchParams.get('codigo') || ''; | ... | ... |
| 1 | -const API_BASE = 'http://136.112.29.74/api/objeto'; | 1 | +import { API_HOST } from '$lib/api.js'; |
| 2 | +const API_BASE = API_HOST + '/api/objeto'; | ||
| 2 | 3 | ||
| 3 | export async function GET({ url }) { | 4 | export async function GET({ url }) { |
| 4 | const codigo = url.searchParams.get('codigo') || ''; | 5 | const codigo = url.searchParams.get('codigo') || ''; | ... | ... |
| 1 | -const API_BASE = 'http://136.112.29.74/api/organismo'; | 1 | +import { API_HOST } from '$lib/api.js'; |
| 2 | +const API_BASE = API_HOST + '/api/organismo'; | ||
| 2 | 3 | ||
| 3 | export async function GET({ url }) { | 4 | export async function GET({ url }) { |
| 4 | const codigo = url.searchParams.get('codigo') || ''; | 5 | const codigo = url.searchParams.get('codigo') || ''; | ... | ... |
| 1 | -const API_BASE = 'http://136.112.29.74/api/programa_proyecto'; | 1 | +import { API_HOST } from '$lib/api.js'; |
| 2 | +const API_BASE = API_HOST + '/api/programa_proyecto'; | ||
| 2 | 3 | ||
| 3 | export async function GET({ url }) { | 4 | export async function GET({ url }) { |
| 4 | const codigo = url.searchParams.get('codigo') || ''; | 5 | const codigo = url.searchParams.get('codigo') || ''; | ... | ... |
| 1 | -const API_BASE = 'http://136.112.29.74/api/rubro'; | 1 | +import { API_HOST } from '$lib/api.js'; |
| 2 | +const API_BASE = API_HOST + '/api/rubro'; | ||
| 2 | 3 | ||
| 3 | export async function GET({ url }) { | 4 | export async function GET({ url }) { |
| 4 | const codigo = url.searchParams.get('codigo') || ''; | 5 | const codigo = url.searchParams.get('codigo') || ''; | ... | ... |
| 1 | -const API_BASE = 'http://136.112.29.74/api/rubro'; | 1 | +import { API_HOST } from '$lib/api.js'; |
| 2 | +const API_BASE = API_HOST + '/api/rubro'; | ||
| 2 | 3 | ||
| 3 | export async function GET({ url }) { | 4 | export async function GET({ url }) { |
| 4 | const codigo = url.searchParams.get('codigo') || ''; | 5 | const codigo = url.searchParams.get('codigo') || ''; | ... | ... |
| 1 | // Proxy para evitar CORS | 1 | // Proxy para evitar CORS |
| 2 | -const API_BASE = 'http://136.112.29.74/api/search'; | 2 | +import { API_HOST } from '$lib/api.js'; |
| 3 | +const API_BASE = API_HOST + '/api/search'; | ||
| 3 | 4 | ||
| 4 | export async function GET({ url }) { | 5 | export async function GET({ url }) { |
| 5 | const q = url.searchParams.get('q') || ''; | 6 | const q = url.searchParams.get('q') || ''; |
| ... | @@ -37,8 +38,8 @@ export async function GET({ url }) { | ... | @@ -37,8 +38,8 @@ export async function GET({ url }) { |
| 37 | headers: { 'Content-Type': 'application/json' } | 38 | headers: { 'Content-Type': 'application/json' } |
| 38 | }); | 39 | }); |
| 39 | } catch (err) { | 40 | } catch (err) { |
| 40 | - console.error('Proxy error:', err); | 41 | + console.error('Proxy error:', err.message, 'URL:', apiUrl.toString()); |
| 41 | - return new Response(JSON.stringify({ error: 'Failed to fetch from API' }), { | 42 | + return new Response(JSON.stringify({ error: 'Failed to fetch from API', detail: err.message, url: apiUrl.toString() }), { |
| 42 | status: 500, | 43 | status: 500, |
| 43 | headers: { 'Content-Type': 'application/json' } | 44 | headers: { 'Content-Type': 'application/json' } |
| 44 | }); | 45 | }); | ... | ... |
| 1 | -const API_BASE = 'http://136.112.29.74/api/ubigeo'; | 1 | +import { API_HOST } from '$lib/api.js'; |
| 2 | +const API_BASE = API_HOST + '/api/ubigeo'; | ||
| 2 | 3 | ||
| 3 | export async function GET({ url }) { | 4 | export async function GET({ url }) { |
| 4 | const codigo = url.searchParams.get('codigo') || ''; | 5 | const codigo = url.searchParams.get('codigo') || ''; | ... | ... |
This diff is collapsed. Click to expand it.
| 1 | <script> | 1 | <script> |
| 2 | - import { supabase } from '$lib/supabase'; | ||
| 3 | import { onMount, untrack } from 'svelte'; | 2 | import { onMount, untrack } from 'svelte'; |
| 4 | import { page } from '$app/stores'; | 3 | import { page } from '$app/stores'; |
| 5 | import { goto } from '$app/navigation'; | 4 | import { goto } from '$app/navigation'; |
| ... | @@ -154,16 +153,11 @@ | ... | @@ -154,16 +153,11 @@ |
| 154 | treemapNodes = []; | 153 | treemapNodes = []; |
| 155 | try { | 154 | try { |
| 156 | const entidadFiltro = selectedEntity?.entidad ?? 0; | 155 | const entidadFiltro = selectedEntity?.entidad ?? 0; |
| 157 | - const { data, error: dbError } = await supabase | 156 | + const res = await fetch(`/api/finfun-treemap?gestion=${selectedYear}&entidad=${entidadFiltro}`); |
| 158 | - .schema('ppto') | 157 | + const data = await res.json(); |
| 159 | - .from('treemap_finfun') | 158 | + |
| 160 | - .select('gestion, nivel, finfun, desc_funcion, parent, devengado') | 159 | + if (data.error) { |
| 161 | - .eq('gestion', selectedYear) | 160 | + console.error('Error fetching treemap data:', data.error); |
| 162 | - .eq('entidad', entidadFiltro) | ||
| 163 | - .gt('devengado', 0); | ||
| 164 | - | ||
| 165 | - if (dbError) { | ||
| 166 | - console.error('Error fetching treemap data:', dbError.message); | ||
| 167 | return; | 161 | return; |
| 168 | } | 162 | } |
| 169 | 163 | ||
| ... | @@ -171,7 +165,7 @@ | ... | @@ -171,7 +165,7 @@ |
| 171 | gestion: d.gestion, | 165 | gestion: d.gestion, |
| 172 | nivel: d.nivel, | 166 | nivel: d.nivel, |
| 173 | finfun: d.finfun, | 167 | finfun: d.finfun, |
| 174 | - desc_finfun: d.desc_funcion, | 168 | + desc_finfun: d.desc_finfun, |
| 175 | parent: d.parent, | 169 | parent: d.parent, |
| 176 | devengado: d.devengado || 0 | 170 | devengado: d.devengado || 0 |
| 177 | })); | 171 | })); |
| ... | @@ -186,15 +180,11 @@ | ... | @@ -186,15 +180,11 @@ |
| 186 | async function loadEntitiesForYear(year) { | 180 | async function loadEntitiesForYear(year) { |
| 187 | if (!year) return; | 181 | if (!year) return; |
| 188 | try { | 182 | try { |
| 189 | - const { data, error: dbError } = await supabase | 183 | + const res = await fetch('/api/objeto-treemap-entidades'); |
| 190 | - .schema('ppto') | 184 | + const data = await res.json(); |
| 191 | - .from('entidades_treemap') | 185 | + |
| 192 | - .select('entidad, desc_entidad, sigla_entidad') | 186 | + if (data.error) { |
| 193 | - .eq('gestion', year) | 187 | + console.error('Error loading entities:', data.error); |
| 194 | - .order('desc_entidad'); | ||
| 195 | - | ||
| 196 | - if (dbError) { | ||
| 197 | - console.error('Error loading entities:', dbError.message); | ||
| 198 | return; | 188 | return; |
| 199 | } | 189 | } |
| 200 | entities = data || []; | 190 | entities = data || []; |
| ... | @@ -580,13 +570,10 @@ | ... | @@ -580,13 +570,10 @@ |
| 580 | document.body.offsetHeight; // Force reflow | 570 | document.body.offsetHeight; // Force reflow |
| 581 | }); | 571 | }); |
| 582 | 572 | ||
| 583 | - const { data, error } = await supabase | 573 | + const clasRes = await fetch('/api/finfun-clasificador'); |
| 584 | - .schema('ppto') | 574 | + const data = await clasRes.json(); |
| 585 | - .from('clas_finfun') | ||
| 586 | - .select('*') | ||
| 587 | - .order('finfun'); | ||
| 588 | 575 | ||
| 589 | - if (!error && data) { | 576 | + if (Array.isArray(data)) { |
| 590 | allItems = data; | 577 | allItems = data; |
| 591 | 578 | ||
| 592 | // Extraer finalidades únicas (nivel más agregado) | 579 | // Extraer finalidades únicas (nivel más agregado) |
| ... | @@ -842,55 +829,6 @@ | ... | @@ -842,55 +829,6 @@ |
| 842 | Jerarquía: Finalidad → Grupo Función → Función | 829 | Jerarquía: Finalidad → Grupo Función → Función |
| 843 | </p> | 830 | </p> |
| 844 | 831 | ||
| 845 | - <!-- Toggle de modos: Lista, Mapa, Comparar + Botón filtros móvil --> | ||
| 846 | - <div class="flex items-center gap-3"> | ||
| 847 | - <div class="header-modes"> | ||
| 848 | - <button | ||
| 849 | - class="header-mode-btn" | ||
| 850 | - class:active={viewMode === 'lista'} | ||
| 851 | - onclick={() => setMode('lista')} | ||
| 852 | - > | ||
| 853 | - <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | ||
| 854 | - <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h16M4 18h16" /> | ||
| 855 | - </svg> | ||
| 856 | - Lista | ||
| 857 | - </button> | ||
| 858 | - <button | ||
| 859 | - class="header-mode-btn" | ||
| 860 | - class:active={viewMode === 'mapa'} | ||
| 861 | - onclick={() => setMode('mapa')} | ||
| 862 | - > | ||
| 863 | - <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | ||
| 864 | - <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 5a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM14 5a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1h-4a1 1 0 01-1-1V5zM4 15a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1H5a1 1 0 01-1-1v-4zM14 15a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1h-4a1 1 0 01-1-1v-4z" /> | ||
| 865 | - </svg> | ||
| 866 | - Mapa | ||
| 867 | - </button> | ||
| 868 | - <button | ||
| 869 | - class="header-mode-btn" | ||
| 870 | - class:active={viewMode === 'comparar'} | ||
| 871 | - onclick={() => setMode('comparar')} | ||
| 872 | - > | ||
| 873 | - <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | ||
| 874 | - <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" /> | ||
| 875 | - </svg> | ||
| 876 | - Comparar | ||
| 877 | - </button> | ||
| 878 | - </div> | ||
| 879 | - | ||
| 880 | - <!-- Botón filtros para móvil en modo mapa --> | ||
| 881 | - {#if viewMode === 'mapa'} | ||
| 882 | - <button | ||
| 883 | - class="lg:hidden flex items-center gap-2 px-3 py-1.5 rounded-lg text-sm" | ||
| 884 | - style="background-color: var(--theme-fill); color: var(--theme-titulo);" | ||
| 885 | - onclick={() => mapaSidebarOpen = !mapaSidebarOpen} | ||
| 886 | - > | ||
| 887 | - <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | ||
| 888 | - <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4" /> | ||
| 889 | - </svg> | ||
| 890 | - Filtros | ||
| 891 | - </button> | ||
| 892 | - {/if} | ||
| 893 | - </div> | ||
| 894 | </div> | 832 | </div> |
| 895 | </div> | 833 | </div> |
| 896 | </header> | 834 | </header> | ... | ... |
| ... | @@ -1441,52 +1441,6 @@ | ... | @@ -1441,52 +1441,6 @@ |
| 1441 | <div class="mt-2"> | 1441 | <div class="mt-2"> |
| 1442 | <div class="flex flex-col md:flex-row gap-4 md:items-center md:justify-between"> | 1442 | <div class="flex flex-col md:flex-row gap-4 md:items-center md:justify-between"> |
| 1443 | <div class="flex flex-col sm:flex-row sm:items-center gap-3 sm:gap-4"> | 1443 | <div class="flex flex-col sm:flex-row sm:items-center gap-3 sm:gap-4"> |
| 1444 | - {#if viewMode === 'lista'} | ||
| 1445 | - <div class="header-modes"> | ||
| 1446 | - <button | ||
| 1447 | - class="header-mode-btn active" | ||
| 1448 | - onclick={() => setMode('lista')} | ||
| 1449 | - > | ||
| 1450 | - <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | ||
| 1451 | - <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h16M4 18h16" /> | ||
| 1452 | - </svg> | ||
| 1453 | - Lista | ||
| 1454 | - </button> | ||
| 1455 | - <button | ||
| 1456 | - class="header-mode-btn" | ||
| 1457 | - onclick={() => setMode('mapa')} | ||
| 1458 | - > | ||
| 1459 | - <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | ||
| 1460 | - <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z" /> | ||
| 1461 | - </svg> | ||
| 1462 | - Mapa | ||
| 1463 | - </button> | ||
| 1464 | - <button | ||
| 1465 | - class="header-mode-btn" | ||
| 1466 | - onclick={() => { setMode('comparar'); initCompareMode(); }} | ||
| 1467 | - > | ||
| 1468 | - <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | ||
| 1469 | - <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" /> | ||
| 1470 | - </svg> | ||
| 1471 | - Comparar | ||
| 1472 | - </button> | ||
| 1473 | - </div> | ||
| 1474 | - | ||
| 1475 | - <!-- Guía inline (solo para lista) --> | ||
| 1476 | - <div class="hidden sm:block text-sm border-l pl-4" style="color: var(--theme-texto); border-color: var(--theme-borde);"> | ||
| 1477 | - <span class="flex items-center gap-1.5"> | ||
| 1478 | - Clic en | ||
| 1479 | - <span class="inline-flex items-center justify-center w-5 h-5 rounded" style="background-color: color-mix(in srgb, var(--theme-accent) 20%, transparent); color: var(--theme-accent);"> | ||
| 1480 | - <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | ||
| 1481 | - <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" /> | ||
| 1482 | - </svg> | ||
| 1483 | - </span> | ||
| 1484 | - para ver el presupuesto histórico · | ||
| 1485 | - <span class="underline decoration-dotted font-medium" style="color: var(--theme-accent);">N var.</span> | ||
| 1486 | - = número de cambios en la descripción oficial | ||
| 1487 | - </span> | ||
| 1488 | - </div> | ||
| 1489 | - {/if} | ||
| 1490 | </div> | 1444 | </div> |
| 1491 | 1445 | ||
| 1492 | <div class="flex flex-wrap items-center gap-3 flex-shrink-0"> | 1446 | <div class="flex flex-wrap items-center gap-3 flex-shrink-0"> | ... | ... |
| 1 | <script> | 1 | <script> |
| 2 | - import { supabase } from '$lib/supabase'; | ||
| 3 | import { onMount } from 'svelte'; | 2 | import { onMount } from 'svelte'; |
| 4 | import { page } from '$app/stores'; | 3 | import { page } from '$app/stores'; |
| 5 | import { goto } from '$app/navigation'; | 4 | import { goto } from '$app/navigation'; |
| ... | @@ -33,15 +32,12 @@ | ... | @@ -33,15 +32,12 @@ |
| 33 | document.body.offsetHeight; // Force reflow | 32 | document.body.offsetHeight; // Force reflow |
| 34 | }); | 33 | }); |
| 35 | 34 | ||
| 36 | - const { data, error } = await supabase | 35 | + try { |
| 37 | - .schema('ppto') | 36 | + const res = await fetch('/api/entidad-clasificador'); |
| 38 | - .from('clas_institucional') | 37 | + const data = await res.json(); |
| 39 | - .select('*') | ||
| 40 | - .order('desc_area') | ||
| 41 | - .order('desc_entidad'); | ||
| 42 | 38 | ||
| 43 | - if (!error && data) { | 39 | + if (Array.isArray(data)) { |
| 44 | - allEntidades = data; | 40 | + allEntidades = data.sort((a, b) => (a.desc_area || '').localeCompare(b.desc_area || '') || (a.desc_entidad || '').localeCompare(b.desc_entidad || '')); |
| 45 | 41 | ||
| 46 | // Agrupar por área (segundo nivel) | 42 | // Agrupar por área (segundo nivel) |
| 47 | const areasMap = {}; | 43 | const areasMap = {}; |
| ... | @@ -74,6 +70,9 @@ | ... | @@ -74,6 +70,9 @@ |
| 74 | selectedArea = areas[0]; | 70 | selectedArea = areas[0]; |
| 75 | } | 71 | } |
| 76 | } | 72 | } |
| 73 | + } catch (err) { | ||
| 74 | + console.error('Error loading clasificador:', err); | ||
| 75 | + } | ||
| 77 | 76 | ||
| 78 | loading = false; | 77 | loading = false; |
| 79 | }); | 78 | }); |
| ... | @@ -238,49 +237,6 @@ | ... | @@ -238,49 +237,6 @@ |
| 238 | 237 | ||
| 239 | <!-- Controles de visualización --> | 238 | <!-- Controles de visualización --> |
| 240 | <div class="mt-8"> | 239 | <div class="mt-8"> |
| 241 | - <div class="flex flex-col sm:flex-row sm:items-center gap-3 sm:gap-4"> | ||
| 242 | - <!-- Toggle Vista --> | ||
| 243 | - <div class="flex items-center gap-3"> | ||
| 244 | - <span class="text-sm font-medium" style="color: var(--theme-titulo);">Explorar como</span> | ||
| 245 | - <nav class="inline-flex rounded-xl border-2 p-1 shadow-sm" style="border-color: var(--theme-titulo); background-color: var(--theme-surface);"> | ||
| 246 | - <a | ||
| 247 | - href="?modo=lista" | ||
| 248 | - class="px-4 py-2 text-sm font-semibold rounded-lg transition-all" | ||
| 249 | - style="{viewMode === 'lista' ? `background-color: var(--theme-titulo); color: var(--theme-body);` : `color: var(--theme-texto);`}" | ||
| 250 | - onclick={(e) => { e.preventDefault(); setMode('lista'); }} | ||
| 251 | - > | ||
| 252 | - Lista | ||
| 253 | - </a> | ||
| 254 | - <a | ||
| 255 | - href="?modo=mapa" | ||
| 256 | - class="px-4 py-2 text-sm font-semibold rounded-lg transition-all" | ||
| 257 | - style="{viewMode === 'mapa' ? `background-color: var(--theme-titulo); color: var(--theme-body);` : `color: var(--theme-texto);`}" | ||
| 258 | - onclick={(e) => { e.preventDefault(); setMode('mapa'); }} | ||
| 259 | - > | ||
| 260 | - Mapa | ||
| 261 | - </a> | ||
| 262 | - <a | ||
| 263 | - href="?modo=comparar" | ||
| 264 | - class="px-4 py-2 text-sm font-semibold rounded-lg transition-all" | ||
| 265 | - style="{viewMode === 'comparar' ? `background-color: var(--theme-titulo); color: var(--theme-body);` : `color: var(--theme-texto);`}" | ||
| 266 | - onclick={(e) => { e.preventDefault(); setMode('comparar'); }} | ||
| 267 | - > | ||
| 268 | - Comparar | ||
| 269 | - </a> | ||
| 270 | - </nav> | ||
| 271 | - </div> | ||
| 272 | - | ||
| 273 | - <!-- Guía inline --> | ||
| 274 | - <div class="hidden sm:block text-sm border-l pl-4" style="color: var(--theme-texto); border-color: var(--theme-borde);"> | ||
| 275 | - {#if viewMode === 'lista'} | ||
| 276 | - <span>Navega por áreas y subáreas</span> | ||
| 277 | - {:else if viewMode === 'mapa'} | ||
| 278 | - <span>Visualización geográfica del presupuesto</span> | ||
| 279 | - {:else} | ||
| 280 | - <span>Compara dos entidades o periodos</span> | ||
| 281 | - {/if} | ||
| 282 | - </div> | ||
| 283 | - </div> | ||
| 284 | </div> | 240 | </div> |
| 285 | </div> | 241 | </div> |
| 286 | </header> | 242 | </header> | ... | ... |
| ... | @@ -1604,52 +1604,6 @@ | ... | @@ -1604,52 +1604,6 @@ |
| 1604 | <!-- Selector de modo + Guía inline (visible en sm+) --> | 1604 | <!-- Selector de modo + Guía inline (visible en sm+) --> |
| 1605 | <div class="flex flex-col sm:flex-row sm:items-center gap-3 sm:gap-4"> | 1605 | <div class="flex flex-col sm:flex-row sm:items-center gap-3 sm:gap-4"> |
| 1606 | <!-- Selector de modo (solo para lista, en mapa y comparar está en el sidebar) --> | 1606 | <!-- Selector de modo (solo para lista, en mapa y comparar está en el sidebar) --> |
| 1607 | - {#if viewMode === 'lista'} | ||
| 1608 | - <div class="header-modes"> | ||
| 1609 | - <button | ||
| 1610 | - class="header-mode-btn active" | ||
| 1611 | - onclick={() => setMode('lista')} | ||
| 1612 | - > | ||
| 1613 | - <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | ||
| 1614 | - <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h16M4 18h16" /> | ||
| 1615 | - </svg> | ||
| 1616 | - Lista | ||
| 1617 | - </button> | ||
| 1618 | - <button | ||
| 1619 | - class="header-mode-btn" | ||
| 1620 | - onclick={() => setMode('mapa')} | ||
| 1621 | - > | ||
| 1622 | - <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | ||
| 1623 | - <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z" /> | ||
| 1624 | - </svg> | ||
| 1625 | - Mapa | ||
| 1626 | - </button> | ||
| 1627 | - <button | ||
| 1628 | - class="header-mode-btn" | ||
| 1629 | - onclick={() => { setMode('comparar'); initCompareMode(); }} | ||
| 1630 | - > | ||
| 1631 | - <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | ||
| 1632 | - <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" /> | ||
| 1633 | - </svg> | ||
| 1634 | - Comparar | ||
| 1635 | - </button> | ||
| 1636 | - </div> | ||
| 1637 | - | ||
| 1638 | - <!-- Guía inline (solo para lista) --> | ||
| 1639 | - <div class="hidden sm:block text-sm border-l pl-4" style="color: var(--theme-texto); border-color: var(--theme-borde);"> | ||
| 1640 | - <span class="flex items-center gap-1.5"> | ||
| 1641 | - Clic en | ||
| 1642 | - <span class="inline-flex items-center justify-center w-5 h-5 rounded" style="background-color: color-mix(in srgb, var(--theme-accent) 20%, transparent); color: var(--theme-accent);"> | ||
| 1643 | - <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | ||
| 1644 | - <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" /> | ||
| 1645 | - </svg> | ||
| 1646 | - </span> | ||
| 1647 | - para ver el presupuesto histórico · | ||
| 1648 | - <span class="underline decoration-dotted font-medium" style="color: var(--theme-accent);">N var.</span> | ||
| 1649 | - = número de cambios en la descripción oficial | ||
| 1650 | - </span> | ||
| 1651 | - </div> | ||
| 1652 | - {/if} | ||
| 1653 | </div> | 1607 | </div> |
| 1654 | 1608 | ||
| 1655 | <!-- Filtros (botón móvil para abrir sidebar en mapa y comparar) --> | 1609 | <!-- Filtros (botón móvil para abrir sidebar en mapa y comparar) --> | ... | ... |
| ... | @@ -1453,52 +1453,6 @@ | ... | @@ -1453,52 +1453,6 @@ |
| 1453 | <div class="mt-2"> | 1453 | <div class="mt-2"> |
| 1454 | <div class="flex flex-col md:flex-row gap-4 md:items-center md:justify-between"> | 1454 | <div class="flex flex-col md:flex-row gap-4 md:items-center md:justify-between"> |
| 1455 | <div class="flex flex-col sm:flex-row sm:items-center gap-3 sm:gap-4"> | 1455 | <div class="flex flex-col sm:flex-row sm:items-center gap-3 sm:gap-4"> |
| 1456 | - {#if viewMode === 'lista'} | ||
| 1457 | - <div class="header-modes"> | ||
| 1458 | - <button | ||
| 1459 | - class="header-mode-btn active" | ||
| 1460 | - onclick={() => setMode('lista')} | ||
| 1461 | - > | ||
| 1462 | - <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | ||
| 1463 | - <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h16M4 18h16" /> | ||
| 1464 | - </svg> | ||
| 1465 | - Lista | ||
| 1466 | - </button> | ||
| 1467 | - <button | ||
| 1468 | - class="header-mode-btn" | ||
| 1469 | - onclick={() => setMode('mapa')} | ||
| 1470 | - > | ||
| 1471 | - <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | ||
| 1472 | - <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z" /> | ||
| 1473 | - </svg> | ||
| 1474 | - Mapa | ||
| 1475 | - </button> | ||
| 1476 | - <button | ||
| 1477 | - class="header-mode-btn" | ||
| 1478 | - onclick={() => { setMode('comparar'); initCompareMode(); }} | ||
| 1479 | - > | ||
| 1480 | - <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | ||
| 1481 | - <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" /> | ||
| 1482 | - </svg> | ||
| 1483 | - Comparar | ||
| 1484 | - </button> | ||
| 1485 | - </div> | ||
| 1486 | - | ||
| 1487 | - <!-- Guía inline (solo para lista) --> | ||
| 1488 | - <div class="hidden sm:block text-sm border-l pl-4" style="color: var(--theme-texto); border-color: var(--theme-borde);"> | ||
| 1489 | - <span class="flex items-center gap-1.5"> | ||
| 1490 | - Clic en | ||
| 1491 | - <span class="inline-flex items-center justify-center w-5 h-5 rounded" style="background-color: color-mix(in srgb, var(--theme-accent) 20%, transparent); color: var(--theme-accent);"> | ||
| 1492 | - <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | ||
| 1493 | - <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" /> | ||
| 1494 | - </svg> | ||
| 1495 | - </span> | ||
| 1496 | - para ver el presupuesto histórico · | ||
| 1497 | - <span class="underline decoration-dotted font-medium" style="color: var(--theme-accent);">N var.</span> | ||
| 1498 | - = número de cambios en la descripción oficial | ||
| 1499 | - </span> | ||
| 1500 | - </div> | ||
| 1501 | - {/if} | ||
| 1502 | </div> | 1456 | </div> |
| 1503 | 1457 | ||
| 1504 | <!-- Filtros (botón móvil para abrir sidebar en mapa y comparar) --> | 1458 | <!-- Filtros (botón móvil para abrir sidebar en mapa y comparar) --> | ... | ... |
src/routes/descargas/+page.svelte
0 → 100644
This diff is collapsed. Click to expand it.
| 1 | import { error } from '@sveltejs/kit'; | 1 | import { error } from '@sveltejs/kit'; |
| 2 | 2 | ||
| 3 | -const API_BASE = 'http://136.112.29.74/api/finfun'; | 3 | +import { API_HOST } from '$lib/api.js'; |
| 4 | +const API_BASE = API_HOST + '/api/finfun'; | ||
| 4 | 5 | ||
| 5 | // Jerarquía finfun: Finalidad → Grupo Función → Función | 6 | // Jerarquía finfun: Finalidad → Grupo Función → Función |
| 6 | // Códigos con punto: "1" (finalidad), "1.1" (grpfuncion), "1.1.1" (función) | 7 | // Códigos con punto: "1" (finalidad), "1.1" (grpfuncion), "1.1.1" (función) | ... | ... |
| 1 | import { error } from '@sveltejs/kit'; | 1 | import { error } from '@sveltejs/kit'; |
| 2 | 2 | ||
| 3 | -const API_BASE = 'http://136.112.29.74/api/objeto'; | 3 | +import { API_HOST } from '$lib/api.js'; |
| 4 | +const API_BASE = API_HOST + '/api/objeto'; | ||
| 4 | 5 | ||
| 5 | export async function load({ params }) { | 6 | export async function load({ params }) { |
| 6 | const { codigo } = params; | 7 | const { codigo } = params; | ... | ... |
| 1 | import { error } from '@sveltejs/kit'; | 1 | import { error } from '@sveltejs/kit'; |
| 2 | 2 | ||
| 3 | -const API_BASE = 'http://136.112.29.74/api/organismo'; | 3 | +import { API_HOST } from '$lib/api.js'; |
| 4 | +const API_BASE = API_HOST + '/api/organismo'; | ||
| 4 | 5 | ||
| 5 | export async function load({ params }) { | 6 | export async function load({ params }) { |
| 6 | const { codigo } = params; | 7 | const { codigo } = params; | ... | ... |
| 1 | import { error } from '@sveltejs/kit'; | 1 | import { error } from '@sveltejs/kit'; |
| 2 | 2 | ||
| 3 | -const API_BASE = 'http://136.112.29.74/api/rubro'; | 3 | +import { API_HOST } from '$lib/api.js'; |
| 4 | +const API_BASE = API_HOST + '/api/rubro'; | ||
| 4 | 5 | ||
| 5 | export async function load({ params }) { | 6 | export async function load({ params }) { |
| 6 | const { codigo } = params; | 7 | const { codigo } = params; | ... | ... |
static/descargas.html
0 → 100644
This diff is collapsed. Click to expand it.
-
Please register or login to post a comment