Commit c75dbfb2d4c3404a6fd0f34d17413e16ae71bd43
1 parent
f16256b4
Fix MapLibre proxy routing and enforce Regla 30
Showing
9 changed files
with
390 additions
and
190 deletions
FdwService.java
| ... | ... | @@ -25,7 +25,8 @@ public class FdwService { |
| 25 | 25 | String sqlEntidad = "SELECT sigem_site, sigem_dbname, boundno, boundse, latlong, zoom, maxzoom, minzoom FROM public.entidades WHERE entidad = ?"; |
| 26 | 26 | List<Map<String, Object>> entidades = masterJdbcTemplate.queryForList(sqlEntidad, Integer.parseInt(entidadId)); |
| 27 | 27 | |
| 28 | - if (entidades.isEmpty()) throw new RuntimeException("Entidad " + entidadId + " no encontrada."); | |
| 28 | + if (entidades.isEmpty()) | |
| 29 | + throw new RuntimeException("Entidad " + entidadId + " no encontrada."); | |
| 29 | 30 | |
| 30 | 31 | Map<String, Object> data = entidades.get(0); |
| 31 | 32 | String sigemSite = (String) data.get("sigem_site"); |
| ... | ... | @@ -44,17 +45,25 @@ public class FdwService { |
| 44 | 45 | try { |
| 45 | 46 | gisJdbcTemplate.execute("CREATE EXTENSION IF NOT EXISTS postgres_fdw"); |
| 46 | 47 | gisJdbcTemplate.execute("DROP SERVER IF EXISTS " + serverName + " CASCADE"); |
| 47 | - gisJdbcTemplate.execute(String.format("CREATE SERVER %s FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host '%s', port '%s', dbname '%s')", serverName, host, port, sigemDbname)); | |
| 48 | - gisJdbcTemplate.execute(String.format("CREATE USER MAPPING FOR sigem_user SERVER %s OPTIONS (user '%s', password '%s')", serverName, user, pass)); | |
| 48 | + gisJdbcTemplate.execute(String.format( | |
| 49 | + "CREATE SERVER %s FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host '%s', port '%s', dbname '%s')", | |
| 50 | + serverName, host, port, sigemDbname)); | |
| 51 | + gisJdbcTemplate.execute( | |
| 52 | + String.format("CREATE USER MAPPING FOR sigem_user SERVER %s OPTIONS (user '%s', password '%s')", | |
| 53 | + serverName, user, pass)); | |
| 49 | 54 | gisJdbcTemplate.execute("CREATE SCHEMA IF NOT EXISTS " + schemaName); |
| 50 | - gisJdbcTemplate.execute(String.format("IMPORT FOREIGN SCHEMA public LIMIT TO (v_liq_entidad_totalxobjeto, v_liq_entidad_percentiles, usuarios, ventanas_usuario) FROM SERVER %s INTO %s", serverName, schemaName)); | |
| 55 | + gisJdbcTemplate.execute(String.format( | |
| 56 | + "IMPORT FOREIGN SCHEMA public LIMIT TO (v_liq_entidad_totalxobjeto, v_liq_entidad_percentiles, usuarios, ventanas_usuario) FROM SERVER %s INTO %s", | |
| 57 | + serverName, schemaName)); | |
| 51 | 58 | |
| 52 | 59 | // REGLA 23 ACTUALIZADA: Join OBLIGATORIO por CCC = INM_CTACATASTRAL |
| 53 | 60 | String tableLotes = "public.e" + entidadId + "_lotes_conccc"; |
| 54 | 61 | String viewName = "vw_lotes_morosidad_" + entidadId; |
| 55 | 62 | String viewWms = "vw_lotes_wms_" + entidadId; |
| 56 | - String sqlJoin = String.format("CREATE OR REPLACE VIEW public.%s AS SELECT l.*, m.inm_ficha, m.inm_ctacatastral, m.trb_total_deuda, m.trb_total_pago, m.ultimo_pago FROM %s l LEFT JOIN %s.v_liq_entidad_totalxobjeto m ON l.ccc = m.inm_ctacatastral", viewName, tableLotes, schemaName); | |
| 57 | - | |
| 63 | + String sqlJoin = String.format( | |
| 64 | + "CREATE OR REPLACE VIEW public.%s AS SELECT l.*, m.inm_ficha, m.inm_ctacatastral, m.trb_total_deuda, m.trb_total_pago, m.ultimo_pago FROM %s l LEFT JOIN %s.v_liq_entidad_totalxobjeto m ON l.ccc = m.inm_ctacatastral", | |
| 65 | + viewName, tableLotes, schemaName); | |
| 66 | + | |
| 58 | 67 | gisJdbcTemplate.execute(sqlJoin); |
| 59 | 68 | gisJdbcTemplate.execute(sqlJoin.replace(viewName, viewWms)); |
| 60 | 69 | |
| ... | ... | @@ -64,15 +73,20 @@ public class FdwService { |
| 64 | 73 | geoServerService.truncateCache(viewName); |
| 65 | 74 | geoServerService.publishLayer(viewWms, viewWms, "morosidad_style_wms", boundNo, boundSe); |
| 66 | 75 | geoServerService.truncateCache(viewWms); |
| 67 | - } catch (Exception e) { System.err.println("Advertencia GS: " + e.getMessage()); } | |
| 76 | + } catch (Exception e) { | |
| 77 | + System.err.println("Advertencia GS: " + e.getMessage()); | |
| 78 | + } | |
| 68 | 79 | |
| 69 | - } catch (Exception e) { throw new RuntimeException("Error FDW: " + e.getMessage(), e); } | |
| 80 | + } catch (Exception e) { | |
| 81 | + throw new RuntimeException("Error FDW: " + e.getMessage(), e); | |
| 82 | + } | |
| 70 | 83 | } |
| 71 | 84 | |
| 72 | 85 | private String extractParam(String siteParam, String key, String defaultValue) { |
| 73 | 86 | if (siteParam != null && siteParam.contains(key + "=")) { |
| 74 | 87 | String[] parts = siteParam.split(key + "="); |
| 75 | - if (parts.length > 1) return parts[1].split(" ")[0].trim(); | |
| 88 | + if (parts.length > 1) | |
| 89 | + return parts[1].split(" ")[0].trim(); | |
| 76 | 90 | } |
| 77 | 91 | return defaultValue; |
| 78 | 92 | } |
| ... | ... | @@ -91,8 +105,12 @@ public class FdwService { |
| 91 | 105 | conn.setRequestProperty("Content-Type", "text/xml"); |
| 92 | 106 | conn.setDoOutput(true); |
| 93 | 107 | conn.setConnectTimeout(2000); |
| 94 | - try (java.io.OutputStream os = conn.getOutputStream()) { os.write(xmlBody.getBytes()); } | |
| 108 | + try (java.io.OutputStream os = conn.getOutputStream()) { | |
| 109 | + os.write(xmlBody.getBytes()); | |
| 110 | + } | |
| 95 | 111 | conn.getResponseCode(); |
| 96 | - } catch (Exception e) { System.err.println("Error MVT: " + e.getMessage()); } | |
| 112 | + } catch (Exception e) { | |
| 113 | + System.err.println("Error MVT: " + e.getMessage()); | |
| 114 | + } | |
| 97 | 115 | } |
| 98 | 116 | } | ... | ... |
GIS-GEOSERVER-REGLAS.md
| ... | ... | @@ -4,12 +4,20 @@ Regla 0. Eres un senior fullstack developer con experiencia reconocida en Base d |
| 4 | 4 | El ecosistema principal es Java 21 con Spring Boot y deberá usarse de forma preferencial todas las veces que se pueda. |
| 5 | 5 | El frontend usa el framework corporativo AdminLTE/Bootstrap. |
| 6 | 6 | |
| 7 | +Este proyecto GIS-GEOSERVER debe utilizar un patrón arquitectónico llamado Monolito Spring Boot con Recursos Embebidos (Server-Side Monolith). | |
| 8 | + | |
| 9 | +El Backend (El Cerebro): Está escrito en Java 21 con Spring Boot (ubicado en la carpeta src/main/java/). Se encarga de la lógica pesada: seguridad, conexión a la base de datos PostgreSQL/PostGIS, consultas FDW, y expone los servicios REST (ej. /api/gis/entidad/505). | |
| 10 | + | |
| 11 | +El Frontend (La Cara): Utiliza tecnologías de navegador clásicas: HTML, Vanilla JavaScript, jQuery y AdminLTE/Bootstrap. Pero en lugar de vivir en un servidor web aparte (como un Nginx puro o un Node.js), todos estos archivos viven dentro de la carpeta del propio proyecto Java: en src/main/resources/static/ y src/main/resources/templates/. | |
| 12 | + | |
| 13 | +No hay dos servidores distintos. Cuando Spring Boot arranca su servidor interno (Tomcat), hace el trabajo doble: Si el navegador le pide datos, el código Java responde con JSON (API REST). Si el navegador le pide /gis-geoserver/mapas, el mismo servidor Java va a su propia carpeta interna (static o templates), lee el archivo HTML, y se lo envía al navegador del usuario. Cuando se ejecute el comando de Maven (mvnw clean package) se empaquetará tanto el código Java como los archivos HTML dentro de un único archivo .jar. Todo se levanta en un solo contenedor Docker y el proxy de Apache enruta todo bajo el mismo prefijo (/gis-geoserver/). | |
| 14 | + | |
| 7 | 15 | Regla 1. El ambiente de desarrollo y compilación se encuentra en el 192.168.1.123. |
| 8 | 16 | El JENKINS a usar está en este servidor. Los comandos del jenkins se ejecutan en el servidor 192.168.1.123. |
| 9 | 17 | El MAVEN a usar está en este servidor. Los comandos maven se ejecutan en el servidor 192.168.1.123. |
| 10 | 18 | El DOCKER a usar está en el servidor 192.168.1.123. Los comandos docker se ejecutan en el servidor192.168.1.123. |
| 11 | 19 | Todas las compilaciones se ejecutarán en el servidor 192.168.1.123. |
| 12 | -La base de datos georreferenciada SIGEM del Postgis está en este servidor y el superuser es el usuario registrado en el motor de base de datos como: | |
| 20 | +La base de datos georreferenciada física es SIGEM del Postgis está en este servidor y el superuser es el usuario registrado en el motor de base de datos como: | |
| 13 | 21 | Usuario: sigem_user |
| 14 | 22 | Contraseña: sigem_pass |
| 15 | 23 | |
| ... | ... | @@ -18,6 +26,7 @@ Regla 2. Las bases de datos alfanuméricas de los municipios a usar vinculadas a |
| 18 | 26 | Regla 3. El proxypass principal de redireccionamiento reside en el servidor 192.168.1.10 |
| 19 | 27 | El proxypass maestro de redireccionamiento reside en el servidor 192.168.1.20 |
| 20 | 28 | Estos proxypass no deben ser modificados por ningún motivo. |
| 29 | +El proxy de Nginx de la Regla 3 tiene GeoServer mapeado a la ruta /geoserver/. Las peticiones se deberán mantener en el mismo dominio para evitar bloqueos CORS y para que sean enrutadas correctamente al contenedor de GeoServer. | |
| 21 | 30 | |
| 22 | 31 | Regla 4. Para el LOGIN, para el campo desplegable de las ENTIDADES (Municipios) los datos deben ser obtenidos de la tabla ENTIDADES del SIGEMWEB del servidor 192.168.1.254. |
| 23 | 32 | Para el LOGIN, el usuario debe utilizar su usuario y contraseña del SIGEM del municipio. |
| ... | ... | @@ -54,11 +63,18 @@ Regla 11. Jenkins (.123): admin / x25yvaga2024. |
| 54 | 63 | |
| 55 | 64 | Regla 12. Jenkins SSH Credential ID: sigem-server-123 (root). |
| 56 | 65 | |
| 57 | -Regla 13. Tomcat Manager: manager / x25yvaga2023. GeoServer Web UI: admin / geoserver. | |
| 66 | +Regla 13. | |
| 67 | +Tomcat Manager: manager / x25yvaga2023. | |
| 68 | +GeoServer Web UI: admin / geoserver. | |
| 69 | + | |
| 70 | +Regla 14. | |
| 71 | +Endpoints Geoserver (.123:8080): /geoserver/wms, /geoserver/wfs, /geoserver/rest. | |
| 58 | 72 | |
| 59 | -Regla 14. Endpoints Geoserver (.123:8080): /geoserver/wms, /geoserver/wfs, /geoserver/rest. | |
| 73 | +User: admin | |
| 74 | +Password: x25yvaga2023 | |
| 60 | 75 | |
| 61 | -Regla 15. La aplicación se desplegará en el servidor 192.168.1.123 | |
| 76 | +Regla 15. | |
| 77 | +La aplicación se desplegará en el servidor 192.168.1.123 | |
| 62 | 78 | La carpeta de trabajo es: /yvyape/proyectos/sigem-gis |
| 63 | 79 | |
| 64 | 80 | Regla 16. Conexión FDW y Sincronización de Vistas. |
| ... | ... | @@ -66,7 +82,10 @@ Debe verificarse la existencia del FDW del municipio en cada LOGIN. |
| 66 | 82 | Si no existe, crearlo. |
| 67 | 83 | Refrescar obligatoriamente las vistas `vw_lotes_morosidad_X`. |
| 68 | 84 | |
| 69 | -Regla 17. Git (.100): cbareiro@yvaga.com.py / carlos57. Repo: git@git.yvaga.com.py:geo/gis-geoserver.git. | |
| 85 | +Regla 17. GIT | |
| 86 | +El repositorio de Git se encuentra en git.yvaga.com.py en el servidor 192.168.1.100 | |
| 87 | +Credenciales de Git (.100): cbareiro@yvaga.com.py / carlos57. Repo: git@git.yvaga.com.py:geo/gis-geoserver.git. | |
| 88 | +Si la carpeta a usar ya tiene archivos, el comando puede fallar, y debe limpiarse antes de clonar. | |
| 70 | 89 | |
| 71 | 90 | Regla 18. SSH Local: Usar Bitvise con usuario cbareiro. |
| 72 | 91 | |
| ... | ... | @@ -78,10 +97,17 @@ Regla 20. Prefijo FrontEnd: /gis-geoserver/. |
| 78 | 97 | Regla 21. ContextPath Backend: /gis-geoserver. |
| 79 | 98 | |
| 80 | 99 | Regla 22: Integridad de Comandos Remotos: |
| 81 | -Se utilizarán comandos disponibles en Bitvise. | |
| 82 | -Los accesos a otros servidores se realizarán mediante SSH y sftp. | |
| 100 | +Desde el ambiente de desarrollo (Windows 11) se utilizará SSH de Bitvise para los accesos a otros servidores, usando la Regla 9. | |
| 101 | +Debe usarse -cmdQuoted para ejecutar comandos complejos. | |
| 102 | + | |
| 83 | 103 | Queda prohibido el uso de comandos printf, echo o concatenaciones multilínea complejas para crear archivos. Usar sftpc para subir archivos íntegros. |
| 84 | -Para los comandos SQL complejos debido a la interpretación del shell de Windowsy para asegurar la integridad total (Regla 22), se deben subir los archivos de estructura y población por SFTP ejecutándolos desde el respectivo servidor. El paso intermedio para no generar errores es preparar los archivos de comandos en el servidor local y luego copiar el archivo de comandos al interior del contenedor antes de su ejecución. | |
| 104 | +Para los comandos SQL complejos debido a la interpretación del shell de Windows y para asegurar la integridad total (Regla 22), se deben subir los archivos de estructura y población por SFTPC ejecutándolos desde el respectivo servidor. El paso intermedio para no generar errores es preparar los archivos de comandos en el servidor local y luego copiar el archivo de comandos al interior del contenedor antes de su ejecución, usando sftpc para subir archivos íntegros. | |
| 105 | + | |
| 106 | +Por ejemplo: | |
| 107 | +…\GIS-GEOSERVER > sexec cbareiro@192.168.1.123 -pw=x25yvaga2023 -cmd="cd /yvyape/proyectos/sigem-gis" | |
| 108 | +…\GIS-GEOSERVER > sexec cbareiro@192.168.1.123 -pw=x25yvaga2023 -cmd="./mvnw clean package -DskipTests" | |
| 109 | +…\GIS-GEOSERVER > sftpc cbareiro@192.168.1.123 -pw=x25yvaga2023 -cmd="put -o docker-compose.yml.remote.tmp /yvyape/proyectos/sigem-gis/docker-compose.yml" | |
| 110 | +…\GIS-GEOSERVER > sexec cbareiro@192.168.1.123 -pw=x25yvaga2023 -cmdQuoted -cmd="curl -s -u admin:geoserver -X PUT -H 'Content-Type: application/xml' -d @/yvyape/proyectos/sigem-gis/geoserver_config.xml http://proyecto-geoserver-1:8080/geoserver/rest/workspaces/sigem/datastores/sigem/featuretypes/vw_lotes_morosidad_505.xml" | |
| 85 | 111 | |
| 86 | 112 | Regla 23. Columnas de Unión (Joins). Standard SNC. |
| 87 | 113 | Para toda vista de unión con el FDW, se debe utilizar la columna `snc_cuenta` (limpia) contra `REPLACE(liq.inm_ctacatastral, '-', '')`. |
| ... | ... | @@ -144,13 +170,13 @@ La inserción en la base de datos se realizará mediante el uso directo de ST_Ge |
| 144 | 170 | Implementar un TRUNCATE automático al inicio del proceso de importación. Si al importar los números son UTM, se deben transformar a 4326 antes de guardarlos. |
| 145 | 171 | Las columnas de las tablas eXXX_lotes_activos deberá tener todas las columnas del SNC. |
| 146 | 172 | |
| 147 | - | |
| 148 | 173 | Regla 29. |
| 149 | -Para la construcción en la compilación, se usa JAVA21 del 192.168.1.123, en sincronía con la Regla 1. | |
| 174 | +Para la construcción en la compilación, se usa JAVA21 del 192.168.1.123, en sincronía con la Regla 1. | |
| 175 | +El uso de rutas relativas en Docker ya ha estado causando problemas desde antes. Debes usar rutas absolutas | |
| 150 | 176 | |
| 151 | 177 | Regla 30. Arquitectura de Visualización en Dos Niveles. |
| 152 | 178 | El visor GIS utiliza una estrategia de superposición para optimizar el rendimiento y la claridad visual. Utiliza dos tipos de capas para mostrar los lotes: Una Capa Base (Lotes Grises) y múltiples Capas Temáticas (Lotes Coloreados). |
| 153 | 179 | 1. Capa Base (Esqueleto): Utiliza la tabla física soberana `eXXX_lotes_activos`. Se publica en GeoServer con un estilo neutro (gris/transparente). Representa la totalidad del territorio y siempre es local y persistente. |
| 154 | 180 | 2. Capa Temática (Inteligencia): Utiliza la vista lógica `vw_lotes_morosidad_XXX`. Es la capa dinámica que aplica el JOIN con el FDW municipal. |
| 155 | 181 | El Efecto Visual: La capa temática se superpone a la base. Aquellos lotes con coincidencia tributaria se "pintan" con el estilo de morosidad (semáforo), mientras que los lotes sin vínculo o sin deuda permanecen en gris (dejando ver la capa base), garantizando que la ciudad nunca se vea "incompleta". |
| 156 | - | |
| 182 | +El contenedor de GeoServer (sigem-gis-geoserver-1) y el de PostgreSQL (proyecto-postgres-1) tienen sus propias redes internas de Docker y no tienen acceso directo a otras redes Docker por seguridad y estabilidad. Por lo tanto, debe configurarse y ejecutarse dentro de la red privada interna de Docker. | |
| 157 | 183 | \ No newline at end of file | ... | ... |
apply_config.sh
0 → 100644
apply_config_v2.sh
0 → 100644
apply_config_v3.sh
0 → 100644
apply_config_v4.sh
0 → 100644
geoserver_config.xml
0 → 100644
mapas.html
| 1 | 1 | <!DOCTYPE html> |
| 2 | 2 | <html lang="es"> |
| 3 | + | |
| 3 | 4 | <head> |
| 4 | 5 | <meta charset="UTF-8"> |
| 5 | 6 | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| ... | ... | @@ -9,57 +10,209 @@ |
| 9 | 10 | <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"> |
| 10 | 11 | <link rel="stylesheet" href="https://unpkg.com/maplibre-gl@3.6.2/dist/maplibre-gl.css"> |
| 11 | 12 | <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;700&display=swap" rel="stylesheet"> |
| 12 | - | |
| 13 | + | |
| 13 | 14 | <style> |
| 14 | - body { font-family: 'Roboto', sans-serif; height: 100vh; background: #0b0e14; overflow: hidden; } | |
| 15 | - #map { position: absolute; top: 0; bottom: 0; left: 0; right: 0; } | |
| 16 | - | |
| 15 | + body { | |
| 16 | + font-family: 'Roboto', sans-serif; | |
| 17 | + height: 100vh; | |
| 18 | + background: #0b0e14; | |
| 19 | + overflow: hidden; | |
| 20 | + } | |
| 21 | + | |
| 22 | + #map { | |
| 23 | + position: absolute; | |
| 24 | + top: 0; | |
| 25 | + bottom: 0; | |
| 26 | + left: 0; | |
| 27 | + right: 0; | |
| 28 | + } | |
| 29 | + | |
| 17 | 30 | /* Tema Oscuro Personalizado */ |
| 18 | - .main-sidebar { background-color: #0f172a !important; width: 280px !important; } | |
| 19 | - .content-wrapper { background: transparent !important; } | |
| 20 | - .main-header { background-color: #0f172a !important; border-bottom: 1px solid #1e293b !important; } | |
| 21 | - | |
| 22 | - .nav-link p { color: #94a3b8; font-weight: 500; } | |
| 23 | - .nav-link.active { background-color: #3b82f6 !important; color: white !important; } | |
| 24 | - .nav-link.active p { color: white !important; } | |
| 25 | - | |
| 26 | - .info-box { background: #1e293b; color: white; border-radius: 8px; margin-bottom: 15px; border: 1px solid #334155; } | |
| 27 | - .info-box-text { color: #94a3b8; text-transform: uppercase; font-size: 0.7rem; font-weight: 700; } | |
| 28 | - .info-box-number { font-size: 1.2rem; color: #fff; } | |
| 29 | - | |
| 30 | - .map-section-title { color: #475569; font-size: 0.65rem; font-weight: 700; text-transform: uppercase; padding: 10px 15px; letter-spacing: 1px; } | |
| 31 | - | |
| 31 | + .main-sidebar { | |
| 32 | + background-color: #0f172a !important; | |
| 33 | + width: 280px !important; | |
| 34 | + } | |
| 35 | + | |
| 36 | + .content-wrapper { | |
| 37 | + background: transparent !important; | |
| 38 | + } | |
| 39 | + | |
| 40 | + .main-header { | |
| 41 | + background-color: #0f172a !important; | |
| 42 | + border-bottom: 1px solid #1e293b !important; | |
| 43 | + } | |
| 44 | + | |
| 45 | + .nav-link p { | |
| 46 | + color: #94a3b8; | |
| 47 | + font-weight: 500; | |
| 48 | + } | |
| 49 | + | |
| 50 | + .nav-link.active { | |
| 51 | + background-color: #3b82f6 !important; | |
| 52 | + color: white !important; | |
| 53 | + } | |
| 54 | + | |
| 55 | + .nav-link.active p { | |
| 56 | + color: white !important; | |
| 57 | + } | |
| 58 | + | |
| 59 | + .info-box { | |
| 60 | + background: #1e293b; | |
| 61 | + color: white; | |
| 62 | + border-radius: 8px; | |
| 63 | + margin-bottom: 15px; | |
| 64 | + border: 1px solid #334155; | |
| 65 | + } | |
| 66 | + | |
| 67 | + .info-box-text { | |
| 68 | + color: #94a3b8; | |
| 69 | + text-transform: uppercase; | |
| 70 | + font-size: 0.7rem; | |
| 71 | + font-weight: 700; | |
| 72 | + } | |
| 73 | + | |
| 74 | + .info-box-number { | |
| 75 | + font-size: 1.2rem; | |
| 76 | + color: #fff; | |
| 77 | + } | |
| 78 | + | |
| 79 | + .map-section-title { | |
| 80 | + color: #475569; | |
| 81 | + font-size: 0.65rem; | |
| 82 | + font-weight: 700; | |
| 83 | + text-transform: uppercase; | |
| 84 | + padding: 10px 15px; | |
| 85 | + letter-spacing: 1px; | |
| 86 | + } | |
| 87 | + | |
| 32 | 88 | /* Widget Superior */ |
| 33 | - .top-widget { position: absolute; top: 15px; left: 50%; transform: translateX(-50%); background: rgba(15, 23, 42, 0.9); padding: 8px 25px; border-radius: 50px; border: 1px solid #334155; color: white; font-weight: 700; font-size: 0.85rem; z-index: 10; box-shadow: 0 4px 20px rgba(0,0,0,0.5); backdrop-filter: blur(5px); } | |
| 89 | + .top-widget { | |
| 90 | + position: absolute; | |
| 91 | + top: 15px; | |
| 92 | + left: 50%; | |
| 93 | + transform: translateX(-50%); | |
| 94 | + background: rgba(15, 23, 42, 0.9); | |
| 95 | + padding: 8px 25px; | |
| 96 | + border-radius: 50px; | |
| 97 | + border: 1px solid #334155; | |
| 98 | + color: white; | |
| 99 | + font-weight: 700; | |
| 100 | + font-size: 0.85rem; | |
| 101 | + z-index: 10; | |
| 102 | + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5); | |
| 103 | + backdrop-filter: blur(5px); | |
| 104 | + } | |
| 34 | 105 | |
| 35 | 106 | /* Leyenda Inferior Derecha */ |
| 36 | - .legend-card { position: absolute; bottom: 30px; right: 20px; width: 220px; background: rgba(15, 23, 42, 0.9); border-radius: 12px; border: 1px solid #334155; padding: 15px; color: white; z-index: 10; box-shadow: 0 4px 20px rgba(0,0,0,0.5); display: none; } | |
| 37 | - .legend-title { font-size: 0.7rem; font-weight: 800; color: #3b82f6; text-transform: uppercase; margin-bottom: 10px; border-bottom: 1px solid #334155; padding-bottom: 5px; } | |
| 38 | - .legend-item { display: flex; align-items: center; margin-bottom: 4px; font-size: 0.75rem; color: #cbd5e1; } | |
| 39 | - .legend-color { width: 15px; height: 10px; border-radius: 2px; margin-right: 12px; } | |
| 107 | + .legend-card { | |
| 108 | + position: absolute; | |
| 109 | + bottom: 30px; | |
| 110 | + right: 20px; | |
| 111 | + width: 220px; | |
| 112 | + background: rgba(15, 23, 42, 0.9); | |
| 113 | + border-radius: 12px; | |
| 114 | + border: 1px solid #334155; | |
| 115 | + padding: 15px; | |
| 116 | + color: white; | |
| 117 | + z-index: 10; | |
| 118 | + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5); | |
| 119 | + display: none; | |
| 120 | + } | |
| 121 | + | |
| 122 | + .legend-title { | |
| 123 | + font-size: 0.7rem; | |
| 124 | + font-weight: 800; | |
| 125 | + color: #3b82f6; | |
| 126 | + text-transform: uppercase; | |
| 127 | + margin-bottom: 10px; | |
| 128 | + border-bottom: 1px solid #334155; | |
| 129 | + padding-bottom: 5px; | |
| 130 | + } | |
| 131 | + | |
| 132 | + .legend-item { | |
| 133 | + display: flex; | |
| 134 | + align-items: center; | |
| 135 | + margin-bottom: 4px; | |
| 136 | + font-size: 0.75rem; | |
| 137 | + color: #cbd5e1; | |
| 138 | + } | |
| 139 | + | |
| 140 | + .legend-color { | |
| 141 | + width: 15px; | |
| 142 | + height: 10px; | |
| 143 | + border-radius: 2px; | |
| 144 | + margin-right: 12px; | |
| 145 | + } | |
| 40 | 146 | |
| 41 | 147 | /* Estilo Botones Menú MVT/PNG */ |
| 42 | - .btn-map-mode { background: #1e293b; border: 1px solid #334155; border-radius: 6px; margin: 5px 15px; padding: 10px; cursor: pointer; transition: 0.3s; display: flex; align-items: center; color: #cbd5e1; font-size: 0.85rem; } | |
| 43 | - .btn-map-mode:hover { background: #334155; } | |
| 44 | - .btn-map-mode.active { background: #3b82f6; color: white; border-color: #60a5fa; box-shadow: 0 0 15px rgba(59, 130, 246, 0.4); } | |
| 45 | - .btn-map-mode i { margin-right: 12px; font-size: 1rem; } | |
| 148 | + .btn-map-mode { | |
| 149 | + background: #1e293b; | |
| 150 | + border: 1px solid #334155; | |
| 151 | + border-radius: 6px; | |
| 152 | + margin: 5px 15px; | |
| 153 | + padding: 10px; | |
| 154 | + cursor: pointer; | |
| 155 | + transition: 0.3s; | |
| 156 | + display: flex; | |
| 157 | + align-items: center; | |
| 158 | + color: #cbd5e1; | |
| 159 | + font-size: 0.85rem; | |
| 160 | + } | |
| 161 | + | |
| 162 | + .btn-map-mode:hover { | |
| 163 | + background: #334155; | |
| 164 | + } | |
| 165 | + | |
| 166 | + .btn-map-mode.active { | |
| 167 | + background: #3b82f6; | |
| 168 | + color: white; | |
| 169 | + border-color: #60a5fa; | |
| 170 | + box-shadow: 0 0 15px rgba(59, 130, 246, 0.4); | |
| 171 | + } | |
| 172 | + | |
| 173 | + .btn-map-mode i { | |
| 174 | + margin-right: 12px; | |
| 175 | + font-size: 1rem; | |
| 176 | + } | |
| 177 | + | |
| 178 | + .btn-sync { | |
| 179 | + background: rgba(34, 197, 94, 0.1); | |
| 180 | + border: 1px dashed #22c55e; | |
| 181 | + color: #22c55e; | |
| 182 | + padding: 8px; | |
| 183 | + margin: 15px; | |
| 184 | + border-radius: 6px; | |
| 185 | + cursor: pointer; | |
| 186 | + font-size: 0.8rem; | |
| 187 | + font-weight: 700; | |
| 188 | + display: flex; | |
| 189 | + justify-items: center; | |
| 190 | + align-items: center; | |
| 191 | + justify-content: center; | |
| 192 | + } | |
| 46 | 193 | |
| 47 | - .btn-sync { background: rgba(34, 197, 94, 0.1); border: 1px dashed #22c55e; color: #22c55e; padding: 8px; margin: 15px; border-radius: 6px; cursor: pointer; font-size: 0.8rem; font-weight: 700; display: flex; justify-items: center; align-items: center; justify-content: center; } | |
| 48 | - .btn-sync:hover { background: #22c55e; color: white; } | |
| 194 | + .btn-sync:hover { | |
| 195 | + background: #22c55e; | |
| 196 | + color: white; | |
| 197 | + } | |
| 49 | 198 | </style> |
| 50 | 199 | </head> |
| 200 | + | |
| 51 | 201 | <body class="hold-transition sidebar-mini layout-fixed"> |
| 52 | 202 | <div class="wrapper"> |
| 53 | 203 | <!-- Header --> |
| 54 | 204 | <nav class="main-header navbar navbar-expand navbar-dark"> |
| 55 | 205 | <ul class="navbar-nav"> |
| 56 | - <li class="nav-item"><a class="nav-link" data-widget="pushmenu" href="#" role="button"><i class="fas fa-bars"></i></a></li> | |
| 206 | + <li class="nav-item"><a class="nav-link" data-widget="pushmenu" href="#" role="button"><i | |
| 207 | + class="fas fa-bars"></i></a></li> | |
| 57 | 208 | <li class="nav-item d-none d-sm-inline-block"> |
| 58 | - <span class="nav-link text-white font-weight-bold">SIGEM GIS | <small class="text-gray">Bienvenido, OPERADOR SISTEMA</small></span> | |
| 209 | + <span class="nav-link text-white font-weight-bold">SIGEM GIS | <small class="text-gray">Bienvenido, | |
| 210 | + OPERADOR SISTEMA</small></span> | |
| 59 | 211 | </li> |
| 60 | 212 | </ul> |
| 61 | 213 | <ul class="navbar-nav ml-auto"> |
| 62 | - <li class="nav-item"><a href="login.html" class="btn btn-sm btn-outline-danger mr-3 font-weight-bold">Cerrar Sesión</a></li> | |
| 214 | + <li class="nav-item"><a href="login.html" | |
| 215 | + class="btn btn-sm btn-outline-danger mr-3 font-weight-bold">Cerrar Sesión</a></li> | |
| 63 | 216 | </ul> |
| 64 | 217 | </nav> |
| 65 | 218 | |
| ... | ... | @@ -99,7 +252,8 @@ |
| 99 | 252 | <i class="fas fa-chart-pie"></i> Por Total (Percentiles) |
| 100 | 253 | </div> |
| 101 | 254 | <div class="btn-map-mode" id="btn-png" onclick="setMapMode('png')"> |
| 102 | - <i class="fas fa-image text-warning"></i> Vista PNG (Full) <small class="ml-1 text-muted">[M]</small> | |
| 255 | + <i class="fas fa-image text-warning"></i> Vista PNG (Full) <small | |
| 256 | + class="ml-1 text-muted">[M]</small> | |
| 103 | 257 | </div> |
| 104 | 258 | |
| 105 | 259 | <div class="map-section-title">Administración</div> |
| ... | ... | @@ -114,116 +268,128 @@ |
| 114 | 268 | <div class="content-wrapper"> |
| 115 | 269 | <div id="map"></div> |
| 116 | 270 | <div class="top-widget" id="top-widget">📊 MOROSIDAD - ÚLTIMO ADEUDADO</div> |
| 117 | - | |
| 271 | + | |
| 118 | 272 | <div class="legend-card" id="legend"> |
| 119 | 273 | <div class="legend-title">Último Adeudado</div> |
| 120 | 274 | <div class="legend-item"><span class="legend-color" style="background:#71de75;"></span> 🟢 <= 2026</div> |
| 121 | - <div class="legend-item"><span class="legend-color" style="background:#bef264;"></span> 🎾 <= 2025</div> | |
| 122 | - <div class="legend-item"><span class="legend-color" style="background:#ffaa00;"></span> 🟡 <= 2024</div> | |
| 123 | - <div class="legend-item"><span class="legend-color" style="background:#fb923c;"></span> 🟠 <= 2023</div> | |
| 124 | - <div class="legend-item"><span class="legend-color" style="background:#f87171;"></span> 🔴 <= 2022</div> | |
| 125 | - <div class="legend-item"><span class="legend-color" style="background:#e11d48;"></span> 📢 <= 2021</div> | |
| 126 | - <div class="legend-item"><span class="legend-color" style="background:#475569;"></span> 🔘 SIN DEUDA / PRESCRIPTAS</div> | |
| 127 | - <div class="mt-2 pt-2 border-top border-secondary text-muted" style="font-size:0.6rem">Fuente: Sistema SIGEM</div> | |
| 128 | - </div> | |
| 129 | - </div> | |
| 130 | - </div> | |
| 131 | - | |
| 132 | - <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> | |
| 133 | - <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.1/js/bootstrap.bundle.min.js"></script> | |
| 134 | - <script src="https://cdnjs.cloudflare.com/ajax/libs/admin-lte/3.2.0/js/adminlte.min.js"></script> | |
| 135 | - <script src="https://unpkg.com/maplibre-gl@3.6.2/dist/maplibre-gl.js"></script> | |
| 136 | - | |
| 137 | - <script> | |
| 138 | - const entidad = localStorage.getItem('entidad') || '505'; | |
| 139 | - const contextPath = '/gis-geoserver'; | |
| 140 | - let map; | |
| 141 | - | |
| 142 | - async function init() { | |
| 143 | - try { | |
| 144 | - const r = await fetch(`${contextPath}/api/gis/entidad/${entidad}`); | |
| 145 | - const data = await r.json(); | |
| 146 | - const res = await fetch(`${contextPath}/api/gis/entidad/${entidad}/resumen`); | |
| 147 | - const stats = await res.json(); | |
| 148 | - | |
| 149 | - document.getElementById('val-total').textContent = stats.total_lotes.toLocaleString(); | |
| 150 | - document.getElementById('val-morosos').textContent = stats.lotes_con_deuda.toLocaleString(); | |
| 151 | - | |
| 152 | - const center = data.latlong.split(',').map(Number); | |
| 153 | - | |
| 154 | - map = new maplibregl.Map({ | |
| 155 | - container: 'map', | |
| 156 | - style: 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json', | |
| 157 | - center: [center[1], center[0]], | |
| 158 | - zoom: parseInt(data.zoom) || 15, | |
| 159 | - pitch: 0, | |
| 160 | - bearing: 0, | |
| 161 | - dragRotate: false | |
| 162 | - }); | |
| 163 | - | |
| 164 | - map.on('load', () => { | |
| 165 | - // Fuente Vectorial (MVT) compatible con Regla 23 | |
| 166 | - map.addSource('lotes-mvt', { | |
| 167 | - type: 'vector', | |
| 168 | - tiles: [ `${window.location.origin}${contextPath}/geoserver/gwc/service/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&LAYER=sigem:vw_lotes_morosidad_${entidad}&STYLE=&TILEMATRIXSET=GoogleMapsCompatible&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&FORMAT=application/x-protobuf` ], | |
| 169 | - scheme: 'xyz' | |
| 170 | - }); | |
| 171 | - | |
| 172 | - map.addLayer({ | |
| 173 | - id: 'lotes-layer', | |
| 174 | - type: 'line', | |
| 175 | - source: 'lotes-mvt', | |
| 176 | - 'source-layer': `vw_lotes_morosidad_${entidad}`, | |
| 177 | - paint: { 'line-color': '#475569', 'line-width': 0.8 } | |
| 178 | - }); | |
| 179 | - | |
| 180 | - // Fuente PNG (WMS) - Alineada a Regla 5 (EPSG:4326) | |
| 181 | - map.addSource('lotes-wms', { | |
| 182 | - type: 'raster', | |
| 183 | - tiles: [ `${window.location.origin}${contextPath}/geoserver/wms?service=WMS&version=1.1.1&request=GetMap&layers=sigem:vw_lotes_wms_${entidad}&bbox={bbox-epsg-4326}&width=256&height=256&srs=EPSG:4326&styles=morosidad_style_wms&format=image/png&transparent=true` ], | |
| 184 | - tileSize: 256 | |
| 185 | - }); | |
| 186 | - | |
| 187 | - map.addLayer({ | |
| 188 | - id: 'lotes-color-wms', | |
| 189 | - type: 'raster', | |
| 190 | - source: 'lotes-wms', | |
| 191 | - paint: { 'raster-opacity': 0 } | |
| 192 | - }, 'lotes-layer'); | |
| 193 | - }); | |
| 194 | - | |
| 195 | - map.on('click', 'lotes-layer', (e) => { | |
| 196 | - const p = e.features[0].properties; | |
| 197 | - const content = `<div class="p-2"><b class="text-primary">CCC: ${p.ccc || 'N/A'}</b><hr class="my-1">Deuda: Gs. ${Number(p.trb_total_deuda || 0).toLocaleString()}<br>Último Pago: ${p.ultimo_pago || 'Nunca'}</div>`; | |
| 198 | - new maplibregl.Popup().setLngLat(e.lngLat).setHTML(content).addTo(map); | |
| 199 | - }); | |
| 200 | - | |
| 201 | - } catch (e) { | |
| 202 | - console.error("Error cargando dashboard:", e); | |
| 203 | - // Si hay 503, re-intentar en 5s | |
| 204 | - setTimeout(init, 5000); | |
| 205 | - } | |
| 206 | - } | |
| 207 | - | |
| 208 | - function setMapMode(mode) { | |
| 209 | - $('.btn-map-mode').removeClass('active'); | |
| 210 | - const legend = document.getElementById('legend'); | |
| 211 | - const topWidget = document.getElementById('top-widget'); | |
| 212 | - | |
| 213 | - if (mode === 'base' || mode === 'general') { | |
| 214 | - $('#btn-base').addClass('active'); | |
| 215 | - map.setPaintProperty('lotes-color-wms', 'raster-opacity', 0); | |
| 216 | - legend.style.display = 'none'; | |
| 217 | - topWidget.style.display = 'none'; | |
| 218 | - } else { | |
| 219 | - $(`#btn-${mode}`).addClass('active'); | |
| 220 | - map.setPaintProperty('lotes-color-wms', 'raster-opacity', 0.8); | |
| 221 | - legend.style.display = 'block'; | |
| 222 | - topWidget.style.display = 'block'; | |
| 223 | - } | |
| 224 | - } | |
| 225 | - | |
| 226 | - init(); | |
| 227 | - </script> | |
| 275 | + <div class="legend-item"><span class="legend-color" style="background:#bef264;"></span> 🎾 <= | |
| 276 | + 2025</div> | |
| 277 | + <div class="legend-item"><span class="legend-color" style="background:#ffaa00;"></span> | |
| 278 | + 🟡 <= 2024</div> | |
| 279 | + <div class="legend-item"><span class="legend-color" | |
| 280 | + style="background:#fb923c;"></span> 🟠 <= 2023</div> | |
| 281 | + <div class="legend-item"><span class="legend-color" | |
| 282 | + style="background:#f87171;"></span> 🔴 <= 2022</div> | |
| 283 | + <div class="legend-item"><span class="legend-color" | |
| 284 | + style="background:#e11d48;"></span> 📢 <= 2021</div> | |
| 285 | + <div class="legend-item"><span class="legend-color" | |
| 286 | + style="background:#475569;"></span> 🔘 SIN DEUDA | |
| 287 | + / PRESCRIPTAS</div> | |
| 288 | + <div class="mt-2 pt-2 border-top border-secondary text-muted" | |
| 289 | + style="font-size:0.6rem">Fuente: Sistema SIGEM</div> | |
| 290 | + </div> | |
| 291 | + </div> | |
| 292 | + </div> | |
| 293 | + | |
| 294 | + <script | |
| 295 | + src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> | |
| 296 | + <script | |
| 297 | + src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.1/js/bootstrap.bundle.min.js"></script> | |
| 298 | + <script | |
| 299 | + src="https://cdnjs.cloudflare.com/ajax/libs/admin-lte/3.2.0/js/adminlte.min.js"></script> | |
| 300 | + <script src="https://unpkg.com/maplibre-gl@3.6.2/dist/maplibre-gl.js"></script> | |
| 301 | + | |
| 302 | + <script> | |
| 303 | + const entidad = localStorage.getItem('entidad') || '505'; | |
| 304 | + const contextPath = '/gis-geoserver'; | |
| 305 | + let map; | |
| 306 | + | |
| 307 | + async function init() { | |
| 308 | + try { | |
| 309 | + const r = await fetch(`${contextPath}/api/gis/entidad/${entidad}`); | |
| 310 | + const data = await r.json(); | |
| 311 | + const res = await fetch(`${contextPath}/api/gis/entidad/${entidad}/resumen`); | |
| 312 | + const stats = await res.json(); | |
| 313 | + | |
| 314 | + document.getElementById('val-total').textContent = stats.total_lotes.toLocaleString(); | |
| 315 | + document.getElementById('val-morosos').textContent = stats.lotes_con_deuda.toLocaleString(); | |
| 316 | + | |
| 317 | + const center = data.latlong.split(',').map(Number); | |
| 318 | + | |
| 319 | + map = new maplibregl.Map({ | |
| 320 | + container: 'map', | |
| 321 | + style: 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json', | |
| 322 | + center: [center[1], center[0]], | |
| 323 | + zoom: parseInt(data.zoom) || 15, | |
| 324 | + pitch: 0, | |
| 325 | + bearing: 0, | |
| 326 | + dragRotate: false | |
| 327 | + }); | |
| 328 | + | |
| 329 | + map.on('load', () => { | |
| 330 | + // Fuente Vectorial (MVT) compatible con Regla 23 | |
| 331 | + map.addSource('lotes-mvt', { | |
| 332 | + type: 'vector', | |
| 333 | + tiles: [`http://192.168.1.123:8083/geoserver/gwc/service/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&LAYER=sigem:e${entidad}_lotes_activos&STYLE=&TILEMATRIXSET=GoogleMapsCompatible&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&FORMAT=application/x-protobuf`], | |
| 334 | + scheme: 'xyz' | |
| 335 | + }); | |
| 336 | + | |
| 337 | + map.addLayer({ | |
| 338 | + id: 'lotes-layer', | |
| 339 | + type: 'line', | |
| 340 | + source: 'lotes-mvt', | |
| 341 | + 'source-layer': `e${entidad}_lotes_activos`, | |
| 342 | + paint: { 'line-color': '#475569', 'line-width': 0.8 } | |
| 343 | + }); | |
| 344 | + | |
| 345 | + // Fuente PNG (WMS) - Alineada a Regla 5 (EPSG:4326) | |
| 346 | + map.addSource('lotes-wms', { | |
| 347 | + type: 'raster', | |
| 348 | + tiles: [ `http://192.168.1.123:8083/geoserver/sigem/wms?service=WMS&version=1.1.1&request=GetMap&layers=sigem:vw_lotes_morosidad_${entidad}&bbox={bbox-epsg-3857}&width=256&height=256&srs=EPSG:3857&styles=&format=image/png&transparent=true` ], | |
| 349 | + tileSize: 256 | |
| 350 | + }); | |
| 351 | + | |
| 352 | + map.addLayer({ | |
| 353 | + id: 'lotes-color-wms', | |
| 354 | + type: 'raster', | |
| 355 | + source: 'lotes-wms', | |
| 356 | + paint: { 'raster-opacity': 0 } | |
| 357 | + }, 'lotes-layer'); | |
| 358 | + }); | |
| 359 | + | |
| 360 | + map.on('click', 'lotes-layer', (e) => { | |
| 361 | + const p = e.features[0].properties; | |
| 362 | + const content = `<div class="p-2"><b class="text-primary">CCC: ${p.ccc || 'N/A'}</b><hr class="my-1">Deuda: Gs. ${Number(p.trb_total_deuda || 0).toLocaleString()}<br>Último Pago: ${p.ultimo_pago || 'Nunca'}</div>`; | |
| 363 | + new maplibregl.Popup().setLngLat(e.lngLat).setHTML(content).addTo(map); | |
| 364 | + }); | |
| 365 | + | |
| 366 | + } catch (e) { | |
| 367 | + console.error("Error cargando dashboard:", e); | |
| 368 | + // Si hay 503, re-intentar en 5s | |
| 369 | + setTimeout(init, 5000); | |
| 370 | + } | |
| 371 | + } | |
| 372 | + | |
| 373 | + function setMapMode(mode) { | |
| 374 | + $('.btn-map-mode').removeClass('active'); | |
| 375 | + const legend = document.getElementById('legend'); | |
| 376 | + const topWidget = document.getElementById('top-widget'); | |
| 377 | + | |
| 378 | + if (mode === 'base' || mode === 'general') { | |
| 379 | + $('#btn-base').addClass('active'); | |
| 380 | + map.setPaintProperty('lotes-color-wms', 'raster-opacity', 0); | |
| 381 | + legend.style.display = 'none'; | |
| 382 | + topWidget.style.display = 'none'; | |
| 383 | + } else { | |
| 384 | + $(`#btn-${mode}`).addClass('active'); | |
| 385 | + map.setPaintProperty('lotes-color-wms', 'raster-opacity', 0.8); | |
| 386 | + legend.style.display = 'block'; | |
| 387 | + topWidget.style.display = 'block'; | |
| 388 | + } | |
| 389 | + } | |
| 390 | + | |
| 391 | + init(); | |
| 392 | + </script> | |
| 228 | 393 | </body> |
| 229 | -</html> | |
| 394 | + | |
| 395 | +</html> | |
| 230 | 396 | \ No newline at end of file | ... | ... |
src/main/resources/static/mapas.html
| ... | ... | @@ -437,7 +437,7 @@ |
| 437 | 437 | map.addSource('lotes-mvt', { |
| 438 | 438 | type: 'vector', |
| 439 | 439 | tiles: [ |
| 440 | - `${window.location.origin}/gis-geoserver/gwc/service/tms/1.0.0/sigem:vw_lotes_morosidad_${entidad}@XYZ-900913@pbf/{z}/{x}/{y}.pbf` | |
| 440 | + `${window.location.origin}/geoserver/gwc/service/tms/1.0.0/sigem:e${entidad}_lotes_activos@XYZ-900913@pbf/{z}/{x}/{y}.pbf` | |
| 441 | 441 | ], |
| 442 | 442 | scheme: 'tms' |
| 443 | 443 | }); |
| ... | ... | @@ -449,7 +449,7 @@ |
| 449 | 449 | id: 'lotes-layer', |
| 450 | 450 | type: 'fill', |
| 451 | 451 | source: 'lotes-mvt', |
| 452 | - 'source-layer': `vw_lotes_morosidad_${entidad}`, | |
| 452 | + 'source-layer': `e${entidad}_lotes_activos`, | |
| 453 | 453 | paint: { |
| 454 | 454 | 'fill-color': 'rgba(59, 130, 246, 0.1)', // Azul tenue inicial |
| 455 | 455 | 'fill-outline-color': 'rgba(255, 255, 255, 0.3)' // Borde blanco visible |
| ... | ... | @@ -457,23 +457,13 @@ |
| 457 | 457 | }); |
| 458 | 458 | } |
| 459 | 459 | |
| 460 | - // Fuente de Mejoras (MVT) - TMS Nativo de GeoServer | |
| 461 | - if (!map.getSource('mejoras-mvt')) { | |
| 462 | - map.addSource('mejoras-mvt', { | |
| 463 | - type: 'vector', | |
| 464 | - tiles: [ | |
| 465 | - `${window.location.origin}/gis-geoserver/gwc/service/tms/1.0.0/sigem:e${entidad}_mejoras@XYZ-900913@pbf/{z}/{x}/{y}.pbf` | |
| 466 | - ], | |
| 467 | - scheme: 'tms' | |
| 468 | - }); | |
| 469 | - } | |
| 470 | 460 | |
| 471 | 461 | // [PRUEBA CONTROLADA] Fuente Raster WMS (Renderizado en Servidor) |
| 472 | 462 | if (!map.getSource('lotes-wms')) { |
| 473 | 463 | map.addSource('lotes-wms', { |
| 474 | 464 | 'type': 'raster', |
| 475 | 465 | 'tiles': [ |
| 476 | - `${window.location.origin}/gis-geoserver/sigem/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&LAYERS=sigem:vw_lotes_morosidad_${entidad}&STYLES=morosidad_style_wms&FORMAT=image/png&TRANSPARENT=TRUE&WIDTH=256&HEIGHT=256&SRS=EPSG:3857&BBOX={bbox-epsg-3857}` | |
| 466 | + `${window.location.origin}/geoserver/sigem/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&LAYERS=sigem:vw_lotes_morosidad_${entidad}&STYLES=morosidad_style_wms&FORMAT=image/png&TRANSPARENT=TRUE&WIDTH=256&HEIGHT=256&SRS=EPSG:3857&BBOX={bbox-epsg-3857}` | |
| 477 | 467 | ], |
| 478 | 468 | 'tileSize': 256 |
| 479 | 469 | }); |
| ... | ... | @@ -489,19 +479,7 @@ |
| 489 | 479 | }); // Agregamos al final |
| 490 | 480 | } |
| 491 | 481 | |
| 492 | - // Capa de Mejoras (Inicialmente oculta o 2D) | |
| 493 | - if (!map.getLayer('mejoras-layer')) { | |
| 494 | - map.addLayer({ | |
| 495 | - id: 'mejoras-layer', | |
| 496 | - type: 'fill', | |
| 497 | - source: 'mejoras-mvt', | |
| 498 | - 'source-layer': `e${entidad}_mejoras`, | |
| 499 | - paint: { | |
| 500 | - 'fill-color': 'rgba(59, 130, 246, 0.2)', | |
| 501 | - 'fill-outline-color': 'rgba(59, 130, 246, 0.5)' | |
| 502 | - } | |
| 503 | - }); | |
| 504 | - } | |
| 482 | + | |
| 505 | 483 | } |
| 506 | 484 | |
| 507 | 485 | // --- Lógica de Capas Base (Estricto Fondo Nativo) --- | ... | ... |