La sirve la web en /telegram/ y la abre el bot con un boton web_app (Bot API 6.0).
Mapa con marcador arrastrable y circulo de radio, y devuelve {lat,lon,km} con
WebApp.sendData(). Sin backend: no habla con Meteor ni necesita sesion. Leaflet
vendorizado en public/telegram/vendor para no depender de una CDN.
Sustituye al flujo de cinco pasos del bot de 2018. Detalle en
tcef-notifications/docs/legacy-bot.md §10.
129 lines
5.7 KiB
HTML
129 lines
5.7 KiB
HTML
<!doctype html>
|
|
<html lang="es">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
<title>Zona a vigilar</title>
|
|
<!--
|
|
Mini App de Telegram para elegir la zona vigilada (fase 8).
|
|
|
|
Sustituye al flujo de cinco pasos del bot de 2018 (compartir ubicación o escribir el pueblo →
|
|
geocodificación de Google → mapa de confirmación → menú de cinco radios fijos). Aquí se marca
|
|
el punto en el mapa y se elige el radio que se quiera.
|
|
|
|
Es una página ESTÁTICA a propósito: no habla con el servidor de la web ni necesita sesión. El
|
|
resultado se devuelve con `Telegram.WebApp.sendData()`, que Telegram entrega al bot como un
|
|
mensaje de servicio del propio chat — así que no hay que validar `initData` en ningún sitio ni
|
|
exponer un endpoint nuevo. Leaflet va vendorizado en ./vendor para no depender de una CDN
|
|
(la del bot puede abrirse desde redes con poca cobertura).
|
|
-->
|
|
<link rel="stylesheet" href="vendor/leaflet.css">
|
|
<script src="https://telegram.org/js/telegram-web-app.js"></script>
|
|
<script src="vendor/leaflet.js"></script>
|
|
<style>
|
|
:root { color-scheme: light dark; }
|
|
html, body { margin: 0; height: 100%; font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; }
|
|
body { display: flex; flex-direction: column; background: var(--tg-theme-bg-color, #fff); color: var(--tg-theme-text-color, #000); }
|
|
#map { flex: 1 1 auto; min-height: 0; }
|
|
.panel { padding: 12px 16px calc(12px + env(safe-area-inset-bottom)); display: grid; gap: 10px; }
|
|
.fila { display: flex; align-items: center; gap: 12px; }
|
|
.fila label { font-size: 15px; white-space: nowrap; }
|
|
#km { flex: 1 1 auto; }
|
|
#valor { font-variant-numeric: tabular-nums; font-weight: 600; min-width: 4.5em; text-align: right; }
|
|
button { font: inherit; font-weight: 600; padding: 12px; border: 0; border-radius: 10px; cursor: pointer;
|
|
background: var(--tg-theme-button-color, #2ea6ff); color: var(--tg-theme-button-text-color, #fff); }
|
|
button[disabled] { opacity: .5; cursor: default; }
|
|
.ayuda { font-size: 13px; opacity: .7; margin: 0; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="map"></div>
|
|
<div class="panel">
|
|
<p class="ayuda" id="ayuda">Toca el mapa o arrastra el marcador para elegir la zona que quieres vigilar.</p>
|
|
<div class="fila">
|
|
<label for="km">Radio</label>
|
|
<input id="km" type="range" min="1" max="100" step="1" value="10">
|
|
<span id="valor">10 km</span>
|
|
</div>
|
|
<button id="enviar" disabled>Guardar zona</button>
|
|
</div>
|
|
|
|
<script>
|
|
(function () {
|
|
var tg = window.Telegram && window.Telegram.WebApp;
|
|
if (tg) { tg.ready(); tg.expand(); }
|
|
|
|
// El idioma lo dice Telegram; si no, español. Solo hay tres cadenas, no vale la pena i18next.
|
|
var LANG = ((tg && tg.initDataUnsafe && tg.initDataUnsafe.user && tg.initDataUnsafe.user.language_code) || 'es').slice(0, 2);
|
|
var T = {
|
|
es: { ayuda: 'Toca el mapa o arrastra el marcador para elegir la zona que quieres vigilar.', radio: 'Radio', guardar: 'Guardar zona' },
|
|
en: { ayuda: 'Tap the map or drag the marker to choose the area you want to watch.', radio: 'Radius', guardar: 'Save area' },
|
|
gl: { ayuda: 'Toca o mapa ou arrastra o marcador para escoller a zona que queres vixiar.', radio: 'Raio', guardar: 'Gardar zona' },
|
|
pt: { ayuda: 'Toca no mapa ou arrasta o marcador para escolher a zona a vigiar.', radio: 'Raio', guardar: 'Guardar zona' }
|
|
}[LANG] || null;
|
|
if (T) {
|
|
document.getElementById('ayuda').textContent = T.ayuda;
|
|
document.querySelector('label[for=km]').textContent = T.radio;
|
|
document.getElementById('enviar').textContent = T.guardar;
|
|
}
|
|
|
|
L.Icon.Default.prototype.options.imagePath = 'vendor/images/';
|
|
|
|
var map = L.map('map', { zoomControl: true }).setView([40.4168, -3.7038], 6);
|
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
|
maxZoom: 19,
|
|
attribution: '© OpenStreetMap'
|
|
}).addTo(map);
|
|
|
|
var marcador = null;
|
|
var circulo = null;
|
|
var km = Number(document.getElementById('km').value);
|
|
var boton = document.getElementById('enviar');
|
|
var valor = document.getElementById('valor');
|
|
|
|
function pinta(latlng) {
|
|
if (!marcador) {
|
|
marcador = L.marker(latlng, { draggable: true }).addTo(map);
|
|
marcador.on('dragend', function () { pinta(marcador.getLatLng()); });
|
|
circulo = L.circle(latlng, { radius: km * 1000, color: '#e2504f', weight: 2, fillOpacity: 0.15 }).addTo(map);
|
|
} else {
|
|
marcador.setLatLng(latlng);
|
|
circulo.setLatLng(latlng);
|
|
}
|
|
circulo.setRadius(km * 1000);
|
|
boton.disabled = false;
|
|
}
|
|
|
|
map.on('click', function (e) { pinta(e.latlng); });
|
|
|
|
document.getElementById('km').addEventListener('input', function (e) {
|
|
km = Number(e.target.value);
|
|
valor.textContent = km + ' km';
|
|
if (circulo) circulo.setRadius(km * 1000);
|
|
});
|
|
|
|
// Arranque: si el navegador da la posición, se centra ahí y se propone ya una zona.
|
|
if (navigator.geolocation) {
|
|
navigator.geolocation.getCurrentPosition(function (pos) {
|
|
var ll = L.latLng(pos.coords.latitude, pos.coords.longitude);
|
|
map.setView(ll, 11);
|
|
pinta(ll);
|
|
}, function () { /* sin permiso: se elige a mano */ }, { timeout: 8000 });
|
|
}
|
|
|
|
boton.addEventListener('click', function () {
|
|
if (!marcador) return;
|
|
var ll = marcador.getLatLng();
|
|
var datos = JSON.stringify({ v: 1, lat: Number(ll.lat.toFixed(6)), lon: Number(ll.lng.toFixed(6)), km: km });
|
|
if (tg && tg.sendData) {
|
|
tg.sendData(datos); // Telegram cierra la ventana y entrega esto al bot
|
|
} else {
|
|
// Fuera de Telegram (abrir la URL en un navegador normal) no hay a quién enviárselo.
|
|
boton.disabled = true;
|
|
document.getElementById('ayuda').textContent = 'Esta página solo funciona abierta desde el bot de Telegram.';
|
|
}
|
|
});
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|