/* global uibuilder */ uibuilder.start(); // Navegación entre pantallas function mostrarPantalla(id) { document.querySelectorAll('.pantalla').forEach(div => div.classList.toggle('visible', div.id === id) ); } let currentTopic = ""; let result = []; //****************************************************RECEPCION DE MENSAJES DESDE NODE_RED ***************************************************************** */ uibuilder.onChange('msg', msg => { if (msg.payload && msg.payload.pantalla) { mostrarPantalla('pantalla-' + msg.payload.pantalla); } if (msg.semaforo) { document.getElementById('estado').style.backgroundColor = msg.semaforo; } if (msg.payload && msg.payload.pantalla === 'snapshot') { // Limpiar datos visibles document.getElementById('camara').textContent = '---'; document.getElementById('placa').textContent = '----'; document.getElementById('fecha').textContent = '----'; // Mostrar imagen vacía document.getElementById('foto').src = ""; } if (msg.payload && msg.payload.pantalla === 'contexto') { // Limpiar datos visibles document.getElementById('camara_contexto').textContent = '---'; document.getElementById('fecha_contexto').textContent = '----'; // Mostrar imagen vacía document.getElementById('foto_contexto').src = ""; } if (msg.payload && msg.payload.pantalla === 'escuchar' && msg.buttons != true) { // Limpiar datos visibles document.getElementById('camara_escuchar').textContent = '---'; document.getElementById('placa_escuchar').textContent = '----'; document.getElementById('fecha_escuchar').textContent = '----'; document.getElementById('contador').textContent = `0 / 0`; // Mostrar imagen vacía document.getElementById('foto_escuchar').src = ""; } // nuevo paara camara de contexto if (msg.hasOwnProperty("picture_contexto")) { if (msg.context_cam) { document.getElementById('foto_contexto').src = msg.picture_contexto; document.getElementById('fecha_contexto').textContent = msg.fecha_contexto || ''; document.getElementById('camara_contexto').textContent = "Contexto" || '---'; } } if (msg.hasOwnProperty("picture")) { //uibuilder.send({ payload: msg.payload.Picture.Plate.PlateNumber, topic: msg.payload.Picture.SnapInfo.DeviceID }); if (msg.snapshot_cam) { document.getElementById('foto').src = msg.picture; document.getElementById('placa').textContent = msg.plate || '----'; document.getElementById('fecha').textContent = msg.plate_time || ''; document.getElementById('camara').textContent = msg.camera_id || '---'; } else if (msg.escuchar_cam){ document.getElementById('foto_escuchar').src = msg.picture; document.getElementById('placa_escuchar').textContent = msg.plate || '----'; document.getElementById('fecha_escuchar').textContent = msg.plate_time || ''; document.getElementById('camara_escuchar').textContent = msg.camera_id || '---'; const total = msg.snapshot_indexmax || 0; const actual = (msg.snapshot_readindex || 0) + 1; document.getElementById('contador').textContent = `${actual} / ${total}`; } } else if (msg.payload?.pantalla === 'tipos') { mostrarPantalla('pantalla-tipos'); if (msg.payload.tiposDatos) { tiposDatos = msg.payload.tiposDatos; } } if (msg.barrera) { mostrarBarreraAbierta() } else{ mostrarBarreraCerrada() } // tabla dinamica if (msg.topic == "general" || msg.topic == "conexion" || msg.topic == "camara" || msg.topic == "sensores" || msg.topic == "mensajes" || msg.topic == "tiempos"){ if (!msg.tabla || !Array.isArray(msg.tabla)) return; const tbody = document.getElementById('config-table-body'); tbody.innerHTML = ''; currentTopic = msg.topic || 'general'; msg.tabla.forEach(item => { //generamos dinamixamente la tabla que vera el usuario en el dispositivo (PC o smartphone). // notese que la celda 2 de cada fila es del tipo editable. const row = document.createElement('tr'); const cell1 = document.createElement('td'); cell1.textContent = item.parametro; const cell2 = document.createElement('td'); cell2.contentEditable = true; cell2.textContent = item.valor; row.appendChild(cell1); row.appendChild(cell2); tbody.appendChild(row); // enviamos la tabla al elemento html (config-table-body) }); } // configuracion del pop up de notificaciones if (msg.modalText) { document.getElementById('modal-text').textContent = msg.modalText; const btnSi = document.getElementById('btn-modal-si'); const btnNo = document.getElementById('btn-modal-no'); if (msg.modalType === "notificacion") { btnSi.textContent = 'OK'; btnNo.style.display = 'none'; window.modalCallback = null; } else { btnSi.textContent = 'Sí'; btnNo.style.display = 'inline-block'; window.modalCallback = msg.modalCallback || null; } document.getElementById('confirm-modal').style.display = 'block'; } // ======================================== Datos para la Pantalla Principal ======================================================================== if (msg.hasOwnProperty("peso")) document.getElementById('peso').textContent = msg.peso || 0; //if (msg.semaforo_color) document.getElementById('semaforo-color').style.backgroundColor = msg.semaforo_color; const led = document.getElementById('semaforo-color'); if (msg.semaforo_color) { led.style.backgroundColor = msg.semaforo_color; led.classList.add('led'); } else { led.style.backgroundColor = '#ccc'; led.classList.remove('led'); } if (msg.hasOwnProperty("matricula")) document.getElementById('matricula').textContent = msg.matricula; if (msg.hasOwnProperty("peso_estable_flag")) document.getElementById('peso-estable').textContent = msg.peso_estable_flag ? 'SI' : 'NO'; if (msg.hasOwnProperty("vial")) document.getElementById('vial').textContent = msg.vial; if (msg.hasOwnProperty("totem_id")) document.getElementById('totem-id').textContent = msg.totem_id; if (msg.hasOwnProperty("iplan")) document.getElementById('iplan').textContent = msg.iplan; if (msg.hasOwnProperty("ipsupervisor")) document.getElementById('ipsupervisor').textContent = msg.ipsupervisor; // ======== Sensor de distancia añadido por david======== if (msg.hasOwnProperty("distance")) { const dist = msg.distance; const dmin = msg.distance_min; const maxRange = 4000; document.getElementById('sensor-dist').textContent = (dist !== null && dist !== undefined) ? dist + ' mm' : '--- mm'; if (dmin !== null && dmin !== undefined) { document.getElementById('sensor-dmin').textContent = dmin + ' mm'; } if (dist !== null && dist !== undefined) { const fillPct = Math.min((dist / maxRange) * 100, 100); const fill = document.getElementById('sensor-fill'); fill.style.width = fillPct + '%'; } } }); //****************************************************************************************************************************************************** */ // Detectar clics en botones document.addEventListener('click', ev => { if (ev.target.matches('button[data-action]')) { const action = ev.target.getAttribute('data-action'); console.log('⏺ Acción botón:', action); uibuilder.send({ payload: { seccion: action } }); } }); // Mostrar pantalla tipos document.addEventListener('click', ev => { if (ev.target.matches('button[data-action="tipos"]')) { mostrarPantalla('pantalla-tipos'); } }); document.getElementById('btn-add-param').addEventListener('click', agregarParametro); document.getElementById('btn-guardar-tipo').addEventListener('click', () => { window.modalCallback = guardarTipo; document.getElementById('modal-text').textContent = `¿Deseas guardar los cambios de Tipo ${tipoActual}?`; document.getElementById('confirm-modal').style.display = 'block'; }); document.getElementById('btn-cancelar-tipo').addEventListener('click', () => { uibuilder.send({ payload: { accion: "cancelar_tipo", tipo: tipoActual } }); volverATipos(); }); document.getElementById('btn-volver-tipos').addEventListener('click', () => { volverATipos(); // esto limpia la tabla con los parametros del Tipo en el que estemos uibuilder.send({ payload: { seccion: "volver_tipos" } }); }); let tipoActual = null; let tiposDatos = {}; // aquí se guarda la configuración temporal //******************************************* FUNCIONES ******************************************************** */ // Acciones a partir de botones en html function sendRow() {// Aqui llega cuando se hace click en el boton Actualizar de las tablas dinamicas // recoge el contenido de la tabla en ese instante y saca Notificacion de guardar con opcion Si o No const rows = document.querySelectorAll('#config-table-body tr'); result = []; // inicializamos result para poner exactamente la tabla actual /* rows.forEach(row => { const parametro = row.cells[0].textContent.trim(); let valor = row.cells[1].textContent.trim(); // normaliza a booleano si corresponde if (valor === "true") valor = true; if (valor === "false") valor = false; result.push({ parametro, valor }); }); */ //Modificacion de la lectura de la tabla para asegurar que los numeros son mantenidos como numeros y no como texto // al igual que los valores booleanos. rows.forEach(row => { const parametro = row.cells[0].textContent.trim(); let valor = row.cells[1].textContent.trim(); if (/^(true|false)$/i.test(valor)) { valor = valor.toLowerCase() === "true"; } else if (/^-?\d+$/.test(valor)) { valor = parseInt(valor, 10); } else if (/^-?\d+\.\d+$/.test(valor)) { valor = parseFloat(valor); } result.push({ parametro, valor }); }); // Mostramos directamente la confirmación y definimos la callback. "topic" contiene el nombre de la tabla donde se guardan los valores que vienen en "result" mostrarConfirmacion("¿Deseas guardar los cambios?", () => { uibuilder.send({ payload: { table: result, seccion: "respuesta" }, topic: currentTopic, origen: "actualizar" }); }); } function sendCancel() { // boton Cancelar de las tablas dinamicas uibuilder.send({ payload: {seccion:'cancel-table'}, topic: currentTopic }); } function confirmGuardar() { // Respuesta Afirmativa del Modal de tabla dinamica document.getElementById('confirm-modal').style.display = 'none'; if (typeof window.modalCallback === 'function') { const cb = window.modalCallback; window.modalCallback = null; // limpia para la siguiente vez cb(); // ejecuta } else if (typeof window.modalCallback === 'string') { uibuilder.send({ payload: { table: result }, modalCallback: window.modalCallback, origen: "modal" }); } } /* function confirmGuardar() { // Respuesta Afirmativa del Modal de tabla dinamica uibuilder.send({ payload: { table: result }, topic: currentTopic, origen: "modal-tabla" }); document.getElementById('confirm-modal').style.display = 'none'; } */ function cancelarGuardar() { // Respuesta Negativa del Modal de tabla dinamica result = []; document.getElementById('confirm-modal').style.display = 'none'; } // Funciones para icono barrera function mostrarBarreraAbierta() { const icono = document.getElementById('icono-barrera'); icono.src = "/barrera_abierta.png"; /* setTimeout(() => { mostrarBarreraCerrada(); }, 1000); // 1 segundo */ } function mostrarBarreraCerrada() { const icono = document.getElementById('icono-barrera'); icono.src = "/barrera_cerrada.png"; } //************************* FUNCIONES DE TIPOS DE CONFIGURACION *****************************/ function seleccionarTipo(n) { tipoActual = n; document.getElementById('titulo-tipo').textContent = `TIPO ${n}`; document.getElementById('tipo-configuracion').style.display = 'block'; const contenedor = document.getElementById('parametros'); contenedor.innerHTML = ''; const datos = tiposDatos[n] || []; // ya es un array datos.forEach(d => { const row = crearFilaParametro(d.parametro, d.valor); contenedor.appendChild(row); }); } function agregarParametro() { const contenedor = document.getElementById('parametros'); if (contenedor.children.length >= 8) return; const row = crearFilaParametro('', ''); contenedor.appendChild(row); } function crearFilaParametro(parametro, valor) { const div = document.createElement('div'); div.className = 'parametro-row'; // Input para el nombre del parámetro const inputParam = document.createElement('input'); inputParam.placeholder = 'Parámetro'; inputParam.value = parametro; // Input para el valor: checkbox o texto let inputValor; if (valor === true || valor === false || valor === "true" || valor === "false") { inputValor = document.createElement('input'); inputValor.type = 'checkbox'; inputValor.checked = (valor === true || valor === "true"); } else { inputValor = document.createElement('input'); inputValor.placeholder = 'Valor'; inputValor.value = valor; } inputParam.classList.add('parametro'); inputValor.classList.add('valor'); // Botón para eliminar la fila const btnDelete = document.createElement('button'); btnDelete.textContent = '-'; btnDelete.className = 'btn rojo'; btnDelete.style.flex = '0 0 40px'; btnDelete.style.width = '40px'; btnDelete.style.height = '40px'; btnDelete.style.marginLeft = '4px'; btnDelete.style.zIndex = '1'; btnDelete.addEventListener('click', (e) => { e.stopPropagation(); e.preventDefault(); window.modalCallback = () => div.remove(); document.getElementById('modal-text').textContent = '¿Deseas eliminar este parámetro?'; document.getElementById('confirm-modal').style.display = 'block'; return false; }); // Añadir los elementos a la fila div.appendChild(inputParam); div.appendChild(inputValor); div.appendChild(btnDelete); return div; } function crearFilaParametro_viejo(parametro, valor) { // Crea un nuevo elemento en la tabla del Tipo que estemos trabajando con dos campos y un boton de borrado const div = document.createElement('div'); div.className = 'parametro-row'; const inputParam = document.createElement('input'); inputParam.placeholder = 'Parámetro'; inputParam.value = parametro; const inputValor = document.createElement('input'); inputValor.placeholder = 'Valor'; inputValor.value = valor; const btnDelete = document.createElement('button'); btnDelete.textContent = '-'; btnDelete.className = 'btn rojo'; btnDelete.style.width = '40px'; btnDelete.style.height = '40px'; btnDelete.onclick = () => { // gestion de la alerta para el borrado, haciendo uso del modal que tenemos en html window.modalCallback = () => div.remove(); document.getElementById('modal-text').textContent = '¿Deseas eliminar este parámetro?'; document.getElementById('confirm-modal').style.display = 'block'; }; div.appendChild(inputParam); div.appendChild(inputValor); div.appendChild(btnDelete); return div; } function guardarTipo() { const contenedor = document.getElementById('parametros'); const filas = contenedor.querySelectorAll('.parametro-row'); const datos = []; filas.forEach(fila => { const [param, val] = fila.querySelectorAll('input'); let valor; if (val.type === 'checkbox') { valor = val.checked; } else { valor = val.value.trim(); } if (param.value.trim()) { datos.push({ parametro: param.value.trim(), valor }); } }); /* filas.forEach(fila => { const [param, val] = fila.querySelectorAll('input'); if (param.value.trim()) { datos.push({ parametro: param.value.trim(), valor: val.value.trim() }); } }); */ tiposDatos[tipoActual] = datos; uibuilder.send({ payload: { tipo: tipoActual, datos }, topic: "tipoconfig" }); // el topic nos sirve para seleccionar en el proximo nodo la funcion de guardar los datos volverATipos(); // 🔷 salimos de la pantalla del tipo actual } function volverATipos() { document.getElementById('tipo-configuracion').style.display = 'none'; tipoActual = null; } //==========================================FUNCIONES PARA MANEJAR LAS NOTIFICACIONES ====================================================== function mostrarConfirmacion(texto, callback) { document.getElementById('modal-text').textContent = texto; // Restablece estado normal del modal const btnSi = document.getElementById('btn-modal-si'); const btnNo = document.getElementById('btn-modal-no'); btnSi.textContent = 'Sí'; btnNo.style.display = 'inline-block'; window.modalCallback = callback; document.getElementById('confirm-modal').style.display = 'block'; } function mostrarNotificacion(texto) { document.getElementById('modal-text').textContent = texto; const btnSi = document.getElementById('btn-modal-si'); const btnNo = document.getElementById('btn-modal-no'); btnSi.textContent = 'OK'; btnNo.style.display = 'none'; window.modalCallback = null; document.getElementById('confirm-modal').style.display = 'block'; } /* Cuando necesitemos un modal clásico (Sí/No), por ejemplo para confirmar actualización: mostrarConfirmacion("¿Deseas guardar los cambios?", () => { uibuilder.send({ payload: { table: result, seccion:"respuesta" }, topic: currentTopic, origen: "actualizar" }); }); Cuando necesitemos simplemente notificar un error: mostrarNotificacion("La IP introducida es inválida, por favor corrígela."); */