login.html 8.88 KB
<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Inicie Sesión - Ecosistema SIGEM</title>

  <!-- Google Font: Source Sans Pro -->
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700&display=fallback">
  <!-- Font Awesome -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
  <!-- Theme style AdminLTE 3 -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/admin-lte@3.2/dist/css/adminlte.min.css">
  <style>
      .login-page {
          background: linear-gradient(135deg, #e0eafc 0%, #cfdef3 100%);
      }
      .card-primary.card-outline {
          border-top: 3px solid #0056b3;
      }
      .btn-primary {
          background-color: #0056b3;
          border-color: #0056b3;
      }
      .btn-primary:hover {
          background-color: #004494;
          border-color: #004494;
      }
      .login-logo a {
          color: #333 !important;
      }
      #municipioSearch::placeholder {
          font-size: 0.85rem;
      }
  </style>
</head>
<body class="hold-transition login-page">
<div class="login-box" style="width: 400px;">
  <div class="login-logo">
    <a href="#"><b>SIGEM</b>WEB</a>
  </div>
  <div class="card card-outline card-primary shadow-lg">
    <div class="card-body login-card-body rounded">
      <p class="login-box-msg font-weight-bold" style="color: #555;">Visor Georreferenciado Multi-Tenant</p>

      <form id="loginForm">
        <label for="municipioSearch" class="text-xs text-muted mb-1" style="font-size: 0.8rem; text-transform: uppercase;">1. Entidad (Municipalidad)</label>
        <div class="input-group mb-2">
          <input type="text" id="municipioSearch" class="form-control" placeholder="Digite código o nombre del municipio..." autocomplete="off">
          <div class="input-group-append">
            <div class="input-group-text">
              <span class="fas fa-university"></span>
            </div>
          </div>
        </div>
        <div class="form-group mb-3 position-relative">
          <select id="entidad" class="form-control" required size="4" style="height: 110px; cursor: pointer; font-size: 0.9rem;">
                <option value="" disabled>Cargando municipios...</option>
          </select>
          <div id="loader-entidades" class="text-center p-2" style="position: absolute; top:0; left:0; width:100%; height:100%; background:white; display:none;">
              <div class="spinner-border spinner-border-sm text-primary"></div>
          </div>
        </div>

        <label class="text-xs text-muted mb-1" style="font-size: 0.8rem; text-transform: uppercase;">2. Credenciales</label>
        <div class="input-group mb-3">
          <input type="text" id="username" class="form-control" placeholder="Usuario (ej. operador)" required autocomplete="username">
          <div class="input-group-append">
            <div class="input-group-text">
              <span class="fas fa-user"></span>
            </div>
          </div>
        </div>
        <div class="input-group mb-3">
          <input type="password" id="password" class="form-control" placeholder="Contraseña SIGEM" required autocomplete="current-password">
          <div class="input-group-append">
            <div class="input-group-text">
              <span class="fas fa-lock"></span>
            </div>
          </div>
        </div>

        <div id="error-msg" class="alert alert-danger p-2 mb-3 text-center" style="display:none; font-size: 13px;"></div>

        <div class="row mt-4">
          <div class="col-12">
            <button type="submit" class="btn btn-primary btn-block font-weight-bold" id="btn-login" style="padding: 10px;">
               <span id="btn-text">INICIAR SESIÓN</span>
               <div class="spinner-border spinner-border-sm text-light" id="spinner" role="status" style="display:none; margin: auto;"></div>
            </button>
          </div>
        </div>
      </form>
    </div>
  </div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"></script>

<script>
    const searchInput = document.getElementById('municipioSearch');
    const selectEntidad = document.getElementById('entidad');
    const loader = document.getElementById('loader-entidades');
    let allEntidades = [];

    // Cargar Entidades desde la Base de Datos Remota (.254)
    async function loadEntidades() {
        loader.style.display = 'block';
        try {
            const response = await fetch('/gis-geoserver/api/auth/entidades');
            if (!response.ok) throw new Error("Error al obtener entidades");
            allEntidades = await response.json();
            renderOptions(allEntidades);
        } catch (error) {
            console.error(error);
            selectEntidad.innerHTML = '<option value="" disabled>Error al cargar municipios</option>';
        } finally {
            loader.style.display = 'none';
        }
    }

    function renderOptions(data) {
        selectEntidad.innerHTML = '';
        data.forEach(ent => {
            const opt = document.createElement('option');
            opt.value = ent.entidad;
            opt.textContent = `${ent.entidad} - ${ent.nombre}`;
            selectEntidad.appendChild(opt);
        });
        if (data.length > 0) selectEntidad.selectedIndex = 0;
    }

    searchInput.addEventListener('input', (e) => {
        const text = e.target.value.toLowerCase();
        const filtered = allEntidades.filter(ent => 
            ent.entidad.toString().includes(text) || 
            ent.nombre.toLowerCase().includes(text)
        );
        renderOptions(filtered);
        
        // Si el usuario escribió un código exacto que existe, seleccionarlo
        const exactMatch = allEntidades.find(ent => ent.entidad.toString() === text);
        if (exactMatch) {
            selectEntidad.value = exactMatch.entidad;
        }
    });

    // Carga inicial
    loadEntidades();

    localStorage.removeItem('jwt');

    document.getElementById('loginForm').addEventListener('submit', function(e) {
        e.preventDefault();
        
        const username = document.getElementById('username').value;
        const password = document.getElementById('password').value;
        const searchVal = searchInput.value.trim();
        const errorMsg = document.getElementById('error-msg');
        
        // Regla: Validar si la entidad seleccionada coincide con lo digitado o si hay una seleccionada
        let entidadId = selectEntidad.value;
        
        // Si el buscador tiene algo pero no hay selección válida, intentamos buscar el código exacto
        if (!entidadId && searchVal) {
             const match = allEntidades.find(ent => ent.entidad.toString() === searchVal);
             if (match) entidadId = match.entidad;
        }

        if (!entidadId) {
            errorMsg.innerText = "La MUNICIPALIDAD con código " + (searchVal || "seleccionado") + " no existe.";
            errorMsg.style.display = 'block';
            return;
        }

        const btnText = document.getElementById('btn-text');
        const spinner = document.getElementById('spinner');
        
        errorMsg.style.display = 'none';
        btnText.style.display = 'none';
        spinner.style.display = 'block';
        document.getElementById('btn-login').disabled = true;

        fetch('/gis-geoserver/api/auth/login', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ username, password, entidad: entidadId })
        })
        .then(async response => {
            const data = await response.json();
            if (!response.ok) throw new Error(data.message || "Credenciales incorrectas.");
            return data;
        })
        .then(data => {
            localStorage.setItem('jwt', data.token);     
            localStorage.setItem('user_name', data.nombre);
            localStorage.setItem('entidad', entidadId); 
            localStorage.setItem('entidad_nombre', data.entidadNombre);
            localStorage.setItem('eslogan', data.eslogan);
            localStorage.setItem('responsable', data.responsable);
            localStorage.setItem('entidad_logo', data.entidadLogo);
            
            localStorage.setItem('map_lat', data.lat);
            localStorage.setItem('map_lng', data.lng);
            localStorage.setItem('map_zoom', data.zoom);
            
            window.location.href = "/gis-geoserver/landing";
        })
        .catch(error => {
            errorMsg.innerText = error.message;
            errorMsg.style.display = 'block';
            btnText.style.display = 'block';
            spinner.style.display = 'none';
            document.getElementById('btn-login').disabled = false;
        });
    });
</script>
</body>
</html>
GitLab Appliance - Powered by TurnKey Linux