TFO.html 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. <!DOCTYPE html>
  2. <html lang="it">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Mappa con Bootstrap Italia e Overlay Edifici</title>
  7. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"
  8. integrity="sha512-9usAa10IRO0HhonpyAIVpjrylPvoDwiPUiKdWk5t3PyolY1cOd4DSE0Ga+ri4AuTroPR5aQvXU9xC6qOPnzFeg=="
  9. crossorigin="anonymous" referrerpolicy="no-referrer" />
  10. <link href="https://cdn.jsdelivr.net/npm/bootstrap-italia@2.13.4/dist/css/bootstrap-italia.min.css" rel="stylesheet">
  11. <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" />
  12. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css" />
  13. <style>
  14. /* Stile per la riga blu scuro */
  15. .top-bar {
  16. background-color: #004080; /* Blu scuro */
  17. color: white;
  18. padding: 0.5rem 0;
  19. text-align: left; /* Allineamento a sinistra */
  20. font-size: 0.9rem;
  21. }
  22. .table-responsive {
  23. overflow-x: auto;
  24. /* Aggiungi scroll orizzontale se la tabella è troppo larga */
  25. }
  26. .header, .footer {
  27. background-color: #0066CC; /* Blu istituzionale */
  28. color: white;
  29. padding: 1rem 0;
  30. }
  31. .main-content {
  32. background-color: #f8f9fa; /* Grigio chiaro */
  33. padding: 2rem 0;
  34. }
  35. /* Stile per il logo "PW" dentro un cerchio */
  36. .logo {
  37. font-family: 'Georgia', serif;
  38. font-size: 1.5rem;
  39. width: 50px; height: 50px;
  40. background-color: white;
  41. color: #0066CC;
  42. border-radius: 50%;
  43. margin-right: 10px;
  44. display: inline-flex;
  45. align-items: center;
  46. justify-content: center;
  47. }
  48. #map { height: 500px; width: 100%; }
  49. #coordinate-inputs { margin-top: 10px; width: 50%; }
  50. /* Stile per i link con sottolineatura solo al passaggio del mouse */
  51. .link-underline-hover {
  52. text-decoration: none; /* Rimuove la sottolineatura di base */
  53. }
  54. .link-underline-hover:hover {
  55. text-decoration: underline; /* Aggiunge la sottolineatura solo al passaggio del mouse */
  56. }
  57. /* Aggiusta l'allineamento del logo e titolo */
  58. .header-title {
  59. font-size: 1.5rem;
  60. display: inline-block;
  61. margin-left: 10px;
  62. }
  63. .header-content {
  64. display: flex;
  65. align-items: center;
  66. }
  67. /* Stili per la tabella dei dati */
  68. .data-table {
  69. display: flex;
  70. flex-direction: column;
  71. }
  72. .table th, .table td {
  73. font-size: 16px; /* Riduce la dimensione del testo */
  74. }
  75. h2 {
  76. font-size: 22px; /* Riduce la dimensione della scritta "Dati Inseriti" */
  77. }
  78. .d-flex {
  79. display: flex;
  80. }
  81. .justify-content-end {
  82. justify-content: flex-end;
  83. }
  84. .mt-2 {
  85. margin-top: 0.5rem;
  86. }
  87. .mt-3 {
  88. margin-top: 1rem;
  89. }
  90. .social-icons a {
  91. color: white;
  92. font-size: 24px;
  93. margin-right: 10px;
  94. }
  95. </style>
  96. </head>
  97. <body>
  98. <!-- Riga blu scuro con scritto "Project Work" allineata a sinistra -->
  99. <div class="top-bar">
  100. <div class="container">
  101. Project Work
  102. </div>
  103. </div>
  104. <header class="header">
  105. <div class="container">
  106. <div class="row align-items-center">
  107. <div class="col">
  108. <!-- Logo "PW" dentro un cerchio e titolo accanto -->
  109. <div class="col d-flex">
  110. <!-- Logo "PW" dentro un cerchio, ora cliccabile -->
  111. <a href="./mappa_logout.html" class="logo-link">
  112. <div class="logo">PW</div>
  113. </a>
  114. <h1 class="header-title">TFO - Terminazioni Fibra Ottica</h1>
  115. </div>
  116. </div>
  117. <div class="col-auto d-flex align-items-center">
  118. <a href="./ADMIN.html" class="text-white me-3 link-underline-hover">Gestione Dati Immobiliari</a>
  119. <a href="./TFO.html" class="text-white me-3 link-underline-hover">TFO</a>
  120. <a href="./buildings.html" class="text-white me-3 link-underline-hover">Registrazione degli Edifici</a>
  121. <a href="./mappa_login.html" class="btn btn-light">Logout</a>
  122. </div>
  123. </div>
  124. </div>
  125. </header>
  126. <main>
  127. <div class="container mt-4">
  128. <h1 style="font-size: 1.5rem;">Registrazione delle terminazioni di fibra ottica</h1>
  129. <!-- Barra di ricerca -->
  130. <div class="row">
  131. <div class="col-md-9">
  132. <div class="mb-3">
  133. <label for="addressInput" class="form-label">Indirizzo:</label>
  134. <input type="text" class="form-control" id="addressInput">
  135. </div>
  136. </div>
  137. <div class="col-md-3">
  138. <button type="button" class="btn btn-primary mt-4" id="searchButton">Cerca</button>
  139. </div>
  140. </div>
  141. <div class="main-content">
  142. <div class="container">
  143. <div class="row justify-content-center">
  144. <div class="col-md-12">
  145. <div id="map"></div>
  146. </div>
  147. </div>
  148. </div>
  149. </div>
  150. <p class="mt-4">Compila il modulo sottostante per registrare una nuova terminazione di fibra ottica:</p>
  151. <fo class="container-fluid">
  152. <div class="row justify-content-center">
  153. <div class="col-md-12">
  154. <div class="card">
  155. <div class="card-body">
  156. <div class="row">
  157. <div class="col-md-9">
  158. <div class="mb-3">
  159. <label for="addressInputForm" class="form-label">Indirizzo:</label>
  160. <input type="text" class="form-control" id="addressInputForm">
  161. </div>
  162. </div>
  163. </div>
  164. <div class="col-md-9">
  165. <div class="mb-3">
  166. <label for="latInput" class="form-label">Latitudine:</label>
  167. <input type="number" class="form-control" id="latInput" min="-90" max="90"/>
  168. </div>
  169. </div>
  170. <div class="col-md-9">
  171. <div class="ms-md-6 mb-3">
  172. <label for="lngInput" class="form-label">Longitudine:</label>
  173. <input type="number" class="form-control" id="lngInput" min="-180" max="180"/>
  174. </div>
  175. </div>
  176. <div class="col-md-9">
  177. <div class="ms-md-6 mb-3">
  178. <label for="codiceCatastaleInput" class="form-label">Codice Catastale:</label>
  179. <input type="text" class="form-control" id="codiceCatastaleInput">
  180. </div>
  181. </div>
  182. <div class="col-md-9">
  183. <div class="mb-3">
  184. <label for="dataPredisposizione" class="form-label">Data Predisposizione</label>
  185. <input type="date" class="form-control" id="dataPredisposizione">
  186. </div>
  187. </div>
  188. <div class="col-md-9">
  189. <div class="mb-3">
  190. <label for="scala" class="form-label">Scala</label>
  191. <input type="text" class="form-control" id="scala">
  192. </div>
  193. </div>
  194. <div class="col-md-9">
  195. <div class="mb-3">
  196. <label for="piano" class="form-label">Piano</label>
  197. <input type="text" class="form-control" id="piano">
  198. </div>
  199. </div>
  200. <div class="col-md-9">
  201. <div class="mb-3">
  202. <label for="interno" class="form-label">Interno</label>
  203. <input type="text" class="form-control" id="interno">
  204. </div>
  205. </div>
  206. </div>
  207. <div class="row">
  208. <div class="col-md-9">
  209. <div class="mb-3">
  210. <label for="operatore" class="form-label">Identificativo Operatore</label>
  211. <select class="form-select" id="operatore">
  212. <option value="1">Operatore 1</option>
  213. <option value="2">Operatore 2</option>
  214. </select>
  215. </div>
  216. </div>
  217. <div class="col-md-9">
  218. <div class="mb-3">
  219. <label for="terminazione" class="form-label">Codice Terminazione</label>
  220. <input type="text" class="form-control" id="terminazione">
  221. </div>
  222. </div>
  223. <div class="col-md-9">
  224. <div class="mb-3">
  225. <label for="nota" class="form-label">Note</label>
  226. <input type="text" class="form-control" id="nota">
  227. </div>
  228. </div>
  229. </div>
  230. <div class="row">
  231. <div class="col-md-2">
  232. <button class="btn btn-primary w-100" onclick="aggiungiRiga()">Aggiungi</button>
  233. </div>
  234. <div class="col-md-2">
  235. <button class="btn btn-secondary w-100" type="button" onclick="resettaForm()">Annulla</button>
  236. </div>
  237. </div>
  238. </div>
  239. </div>
  240. </div>
  241. <div class="col-md-12 mt-4">
  242. <div class="data-table">
  243. <h2>Dati Inseriti</h2>
  244. <div class="table-responsive">
  245. <table class="table">
  246. <thead>
  247. <tr>
  248. <th>Indirizzo</th>
  249. <th>Latitudine</th>
  250. <th>Longitudine</th>
  251. <th>Codice Catastale</th>
  252. <th>Data Predisposizione</th>
  253. <th>Scala</th>
  254. <th>Piano</th>
  255. <th>Interno</th>
  256. <th>Operatore</th>
  257. <th>Terminazione</th>
  258. <th>Note</th>
  259. <th>Azioni</th>
  260. </tr>
  261. </thead>
  262. <tbody id="buildingTableBody">
  263. <!-- Le righe della tabella saranno aggiunte dinamicamente -->
  264. </tbody>
  265. </table>
  266. </div>
  267. <!-- Contenitore per il pulsante "Invia" -->
  268. <div class="d-flex justify-content-end mt-3">
  269. <button class="btn btn-success">Invia</button>
  270. </div>
  271. </div>
  272. </div>
  273. </div>
  274. </div>
  275. </div>
  276. <!-- Widget ElevenLabs ConvAI -->
  277. <div id="ai-widget-container" style="position: fixed; bottom: 20px; right: 20px;">
  278. <elevenlabs-convai agent-id="2MJWbkNuIGTHNI71hKfL"></elevenlabs-convai>
  279. </div>
  280. </main>
  281. <footer id="footer" class="it-footer bg-black mt-5" role="contentinfo">
  282. <div class="it-footer-main py-3">
  283. <div class="container">
  284. <section class="py-4">
  285. <div class="row">
  286. <div class="col-lg-3 col-md-3 col-sm-6 pb-2">
  287. <div class="link-list-wrapper">
  288. <h2 class="h5">Esplora SINFI</h2>
  289. <ul id="footer-menu-col-1" class="link-list">
  290. <li id="menu-item-sinfi-1" class="menu-item">
  291. <a class="list-item" href="https://sinfi.it/portal/sinfi-menu/che-cose/">Cos'è SINFI</a>
  292. </li>
  293. <li id="menu-item-sinfi-2" class="menu-item">
  294. <a class="list-item" href="https://sinfi.it/realms/master/protocol/openid-connect/auth?client_id=sinfi_user_service&response_type=code&redirect_uri=https://sinfi.it/sinfi_gateway/labs_keycloak/post_login/&scope=email&state=">Infrastrutture Registrate</a>
  295. </li>
  296. <li id="menu-item-sinfi-3" class="menu-item">
  297. <a class="list-item" href="https://sinfi.it/portal/sinfi-menu/riferimenti-normativi/">Normative di Riferimento</a>
  298. </li>
  299. <li id="menu-item-sinfi-4" class="menu-item">
  300. <a class="list-item" href="https://sinfi.it/realms/master/protocol/openid-connect/auth?client_id=sinfi_user_service&response_type=code&redirect_uri=https://sinfi.it/sinfi_gateway/labs_keycloak/post_login/&scope=email&state=">Open Data SINFI</a>
  301. </li>
  302. </ul>
  303. </div>
  304. </div>
  305. <div class="col-lg-3 col-md-3 col-sm-6 pb-2">
  306. <div class="link-list-wrapper">
  307. <h2 class="h5">Aiuto e Supporto</h2>
  308. <ul id="footer-menu-col-2" class="link-list">
  309. <li id="menu-item-aiuto-1" class="menu-item">
  310. <a class="list-item" href="./instructions.html">Istruzioni</a>
  311. </li>
  312. <li id="menu-item-aiuto-2" class="menu-item">
  313. <a class="list-item" href="./faq.html">FAQ - Domande Frequenti</a>
  314. </li>
  315. <li id="menu-item-aiuto-3" class="menu-item">
  316. <a class="list-item" href="./techsup.html">Segnalazioni e Supporto Tecnico</a>
  317. </li>
  318. </ul>
  319. </div>
  320. </div>
  321. <!-- Colonna "Community" con i loghi dei social -->
  322. <div class="col-lg-3 col-md-3 col-sm-6 pb-2">
  323. <div class="link-list-wrapper">
  324. <h2 class="h5">Community</h2>
  325. <div class="social-icons">
  326. <a href="https://www.linkedin.com" target="_blank" class="me-3"><i class="fab fa-linkedin"></i></a>
  327. <a href="https://www.youtube.com" target="_blank" class="me-3"><i class="fab fa-youtube"></i></a>
  328. <a href="https://www.facebook.com" target="_blank" class="me-3"><i class="fab fa-facebook"></i></a>
  329. <a href="https://www.instagram.com" target="_blank" class="me-3"><i class="fab fa-instagram"></i></a>
  330. </div>
  331. </div>
  332. </div>
  333. <div class="col-lg-3 col-md-3 col-sm-6 pb-2">
  334. <div class="link-list-wrapper">
  335. <h2 class="h5">SINFI</h2>
  336. <ul id="footer-menu-col-4" class="link-list">
  337. <li id="menu-item-377" class="menu-item">
  338. <a target="_blank" href="https://sinfi.it/portal/">Vai al sito ufficiale SINFI</a>
  339. </li>
  340. </ul>
  341. </div>
  342. </div>
  343. </div>
  344. </section>
  345. </div>
  346. </div>
  347. <div class="it-footer-small-prints clearfix">
  348. <div class="container">
  349. <nav class="menu-footer-menu-ita-container" aria-label="link utili">
  350. <ul id="menu-footer-menu-ita" class="it-footer-small-prints-list list-inline mb-0 d-flex flex-column flex-md-row">
  351. <li id="menu-item-413" class="menu-item list-inline-item"><a href="/media-policy/">Media Policy</a></li>
  352. <li id="menu-item-453" class="menu-item list-inline-item"><a href="/note-legali/">Privacy Policy &amp; Note Legali</a></li>
  353. <li id="menu-item-1310" class="menu-item list-inline-item"><a target="_blank" href="https://form.agid.gov.it/view/9df3de50-7a42-11ef-8989-9dcab5eaa914">Dichiarazione di accessibilità</a></li>
  354. <li id="menu-item-411" class="menu-item list-inline-item"><a href="/mappa-del-sito/">Mappa del sito</a></li>
  355. <li id="menu-item-1277" class="menu-item list-inline-item"><a href="/open-data-spid/">Open Data SPID</a></li>
  356. </ul>
  357. </nav>
  358. </div>
  359. </div>
  360. </footer>
  361. <!-- Scripts -->
  362. <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  363. <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
  364. <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
  365. <script src="https://cdn.jsdelivr.net/npm/bootstrap-italia@2.8.1/dist/js/bootstrap-italia.bundle.min.js"></script>
  366. <!-- Includi lo script di ElevenLabs -->
  367. <script src="https://elevenlabs.io/convai-widget/index.js" async type="text/javascript"></script>
  368. <script>
  369. // Inizializzazione Mappa
  370. var map = L.map('map').setView([41.9028, 12.4964], 13);
  371. L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  372. attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
  373. }).addTo(map);
  374. // Variabile per memorizzare il marker corrente
  375. let marker;
  376. var lastModifiedField = document.getElementById('addressInput');
  377. var buildings = [];
  378. var edificiLayer = L.layerGroup().addTo(map);
  379. var zoomLivello = 16;
  380. // Listener per il tasto Invio nel campo di ricerca
  381. document.getElementById('addressInput').addEventListener('keydown', function (event) {
  382. if (event.keyCode === 13) {
  383. event.preventDefault();
  384. document.getElementById('searchButton').click();
  385. }
  386. });
  387. document.getElementById('searchButton').addEventListener('click', function () {
  388. const address = document.getElementById('addressInput').value;
  389. if (address) {
  390. fetch(`https://nominatim.openstreetmap.org/search?q=${encodeURIComponent(address)}&format=json`)
  391. .then(response => response.json())
  392. .then(data => {
  393. if (data && data.length > 0) {
  394. const lat = parseFloat(data[0].lat);
  395. const lon = parseFloat(data[0].lon);
  396. if (marker) {
  397. map.removeLayer(marker);
  398. }
  399. marker = L.marker([lat, lon]).addTo(map)
  400. .bindPopup(`Indirizzo: ${data[0].display_name}`)
  401. .openPopup();
  402. map.setView([lat, lon], 18);
  403. document.getElementById('latInput').value = lat;
  404. document.getElementById('lngInput').value = lon;
  405. // Copia l'indirizzo trovato nel campo sotto la mappa
  406. document.getElementById('addressInputForm').value = data[0].display_name;
  407. } else {
  408. alert('Indirizzo non trovato.');
  409. }
  410. })
  411. .catch(error => {
  412. console.error('Errore durante la geocodifica:', error);
  413. alert('Si è verificato un errore durante la ricerca dell\'indirizzo.');
  414. });
  415. } else {
  416. alert('Inserisci un indirizzo.');
  417. }
  418. });
  419. // Gestione del click sulla mappa
  420. map.on('click', function (e) {
  421. const lat = e.latlng.lat;
  422. const lng = e.latlng.lng;
  423. // Rimuovi il marker precedente (se esiste)
  424. if (marker) {
  425. map.removeLayer(marker);
  426. }
  427. // Aggiungi un nuovo marker sulla mappa
  428. marker = L.marker([lat, lng]).addTo(map)
  429. .bindPopup(`Coordinate: ${lat}, ${lng}`)
  430. .openPopup();
  431. // Riempie i campi di input per latitudine e longitudine
  432. document.getElementById('latInput').value = lat;
  433. document.getElementById('lngInput').value = lng;
  434. // Ottieni l'indirizzo dalle coordinate
  435. getAddress(lat, lng);
  436. });
  437. async function caricaEdifici() {
  438. if (map.getZoom() >= 16) {
  439. var bounds = map.getBounds();
  440. var bbox = bounds.getSouthWest().lat + ',' + bounds.getSouthWest().lng + ',' + bounds.getNorthEast().lat + ',' + bounds.getNorthEast().lng;
  441. var query = `
  442. [out:json];
  443. (
  444. way["building"](${bbox});
  445. relation["building"](${bbox});
  446. );
  447. out geom;
  448. out tags;
  449. `;
  450. try {
  451. const data = await $.ajax({
  452. url: 'https://overpass-api.de/api/interpreter',
  453. data: { data: query },
  454. dataType: 'json'
  455. });
  456. edificiLayer.clearLayers();
  457. data.elements.forEach(function(element) {
  458. if (element.type === 'way' && element.geometry) {
  459. var latlngs = element.geometry.map(function(coord) {
  460. return [coord.lat, coord.lon];
  461. });
  462. var polygon = L.polygon(latlngs).addTo(edificiLayer);
  463. // Genera un numero casuale tra 0 e 3
  464. var statoEdificio = true;
  465. // Assegna il colore in base allo stato
  466. var colorePoligono;
  467. switch (statoEdificio) {
  468. case false:
  469. colorePoligono = 'yellow';
  470. break;
  471. case true:
  472. colorePoligono = 'green';
  473. break;
  474. }
  475. // Applica lo stile al poligono
  476. polygon.setStyle({ fillColor: colorePoligono, color: colorePoligono });
  477. polygon.on('click', async function() {
  478. var buildingType = element.tags && element.tags.building ? element.tags.building : 'Sconosciuto';
  479. try {
  480. await getAddress(latlngs[0][0], latlngs[0][1]);
  481. var popupContent = 'Coordinate: ' + latlngs[0][0] + ', ' + latlngs[0][1] + '<br>' +
  482. 'Tipo edificio: ' + buildingType + '<br>' +
  483. 'Indirizzo: ' + document.getElementById('addressInput').value + '<br>' +
  484. 'Stato: ' + statoEdificio + '<br>' +
  485. 'Codice Catastale: nessuno';
  486. polygon.bindPopup(popupContent).openPopup();
  487. } catch (error) {
  488. console.error("Errore nel recupero dell'indirizzo:", error);
  489. var popupContent = 'Coordinate: ' + latlngs[0][0] + ', ' + latlngs[0][1] + '<br>' +
  490. 'Tipo edificio: ' + buildingType + '<br>' +
  491. 'Indirizzo: Indirizzo non disponibile<br>' +
  492. 'Stato: ' + statoEdificio + '<br>' +
  493. 'Codice Catastale: nessuno';
  494. polygon.bindPopup(popupContent).openPopup();
  495. }
  496. var codiceCatasto = element.tags && element.tags.codice_catasto ? element.tags.codice_catasto : "nessuno";
  497. document.getElementById('codiceCatastaleInput').value = codiceCatasto;
  498. });
  499. } else if (element.type === 'relation' && element.members) {
  500. // Gestione delle relazioni (edifici complessi)
  501. // Da implementare
  502. }
  503. });
  504. } catch (error) {
  505. console.error('Errore durante il caricamento degli edifici:', error);
  506. // Gestisci l'errore (ad esempio, mostra un messaggio all'utente)
  507. }
  508. } else {
  509. edificiLayer.clearLayers();
  510. }
  511. }
  512. // Funzione per ottenere l'indirizzo dalle coordinate
  513. async function getAddress(lat, lng) {
  514. try {
  515. const response = await fetch(`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${lat}&lon=${lng}`);
  516. const data = await response.json();
  517. if (data.address) {
  518. const displayName = data.display_name;
  519. document.getElementById('addressInput').value = displayName;
  520. document.getElementById('addressInputForm').value = displayName; // Aggiorna anche il campo del form
  521. } else {
  522. document.getElementById('addressInput').value = "Indirizzo non trovato";
  523. document.getElementById('addressInputForm').value = "Indirizzo non trovato"; // Aggiorna anche il campo del form
  524. }
  525. } catch (error) {
  526. console.error("Errore nel geocoding inverso:", error);
  527. document.getElementById('addressInput').value = "Errore nel geocoding inverso";
  528. document.getElementById('addressInputForm').value = "Errore nel geocoding inverso"; // Aggiorna anche il campo del form
  529. }
  530. }
  531. async function prendiIndirizzo(lat, lng) {
  532. try {
  533. const response = await fetch(`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${lat}&lon=${lng}`);
  534. const data = await response.json();
  535. if (data.address) {
  536. return data.display_name;
  537. } else {
  538. return "Indirizzo non trovato";
  539. }
  540. } catch (error) {
  541. console.error("Errore nel geocoding inverso:", error);
  542. return "Indirizzo non disponibile";
  543. }
  544. }
  545. function debounce(func, delay) {
  546. let timeoutId;
  547. return function(...args) {
  548. clearTimeout(timeoutId);
  549. timeoutId = setTimeout(() => {
  550. func.apply(this, args);
  551. }, delay);
  552. };
  553. }
  554. const debouncedCaricaEdifici = debounce(caricaEdifici, 300);
  555. // Gestione dell'input manuale delle coordinate
  556. document.getElementById('latInput').addEventListener('blur', function () {
  557. const lat = parseFloat(this.value);
  558. const lng = parseFloat(document.getElementById('lngInput').value);
  559. if (!isNaN(lat) && !isNaN(lng)) {
  560. map.setView([lat, lng], 16);
  561. if (marker) {
  562. map.removeLayer(marker);
  563. }
  564. marker = L.marker([lat, lng]).addTo(map)
  565. .bindPopup(`Coordinate: ${lat}, ${lng}`)
  566. .openPopup();
  567. getAddress(lat, lng);
  568. }
  569. });
  570. document.getElementById('lngInput').addEventListener('blur', function () {
  571. const lat = parseFloat(document.getElementById('latInput').value);
  572. const lng = parseFloat(this.value);
  573. if (!isNaN(lat) && !isNaN(lng)) {
  574. map.setView([lat, lng], 16);
  575. if (marker) {
  576. map.removeLayer(marker);
  577. }
  578. marker = L.marker([lat, lng]).addTo(map)
  579. .bindPopup(`Coordinate: ${lat}, ${lng}`)
  580. .openPopup();
  581. getAddress(lat, lng);
  582. }
  583. });
  584. // Funzione per aggiungere una riga alla tabella
  585. function aggiungiRiga() {
  586. const indirizzo = document.getElementById('addressInput').value;
  587. const latitudine = document.getElementById('latInput').value;
  588. const longitudine = document.getElementById('lngInput').value;
  589. const codiceCatastale = document.getElementById('codiceCatastaleInput').value;
  590. const dataPredisposizione = document.getElementById('dataPredisposizione').value;
  591. const scala = document.getElementById('scala').value;
  592. const piano = document.getElementById('piano').value;
  593. const interno = document.getElementById('interno').value;
  594. const operatore = document.getElementById('operatore').value;
  595. const terminazione = document.getElementById('terminazione').value;
  596. const nota = document.getElementById('nota').value;
  597. // Controllo se tutti i campi sono compilati
  598. if (!indirizzo || !latitudine || !longitudine || !dataPredisposizione ||
  599. !codiceCatastale || !scala || !piano || !interno || !operatore || !terminazione ) {
  600. alert("Compila tutti i campi prima di aggiungere la TFO!");
  601. return; // Blocca l'inserimento
  602. }
  603. // Crea una nuova riga nella tabella
  604. const tabella = document.querySelector(".table tbody");
  605. const nuovaRiga = tabella.insertRow();
  606. // Crea le celle della riga e inserisci i valori
  607. const celle = [];
  608. for (let i = 0; i < 11; i++) {
  609. celle.push(nuovaRiga.insertCell());
  610. }
  611. celle[0].textContent = indirizzo;
  612. celle[1].textContent = latitudine;
  613. celle[2].textContent = longitudine;
  614. celle[3].textContent = codiceCatastale;
  615. celle[4].textContent = dataPredisposizione;
  616. celle[5].textContent = scala;
  617. celle[6].textContent = piano;
  618. celle[7].textContent = interno;
  619. celle[8].textContent = operatore;
  620. celle[9].textContent = terminazione;
  621. celle[10].textContent = nota;
  622. // Aggiungi i pulsanti di modifica e cancellazione
  623. const azioniCell = nuovaRiga.insertCell();
  624. azioniCell.innerHTML = `
  625. <div class="d-flex gap-2">
  626. <button class="btn btn-sm btn-primary" onclick="modificaRiga(this)"><i class="fas fa-edit"></i></button>
  627. <button class="btn btn-sm btn-danger" onclick="cancellaDato(this)"><i class="fas fa-trash"></i></button>
  628. </div>
  629. `;
  630. // Resetta i campi del form dopo l'inserimento
  631. resettaForm();
  632. }
  633. // Funzione per modificare una riga
  634. function modificaRiga(button) {
  635. const riga = button.closest('tr'); // Trova la riga più vicina al pulsante
  636. const celle = riga.cells;
  637. // Popola i campi del form con i dati della riga
  638. document.getElementById("addressInput").value = celle[0].textContent;
  639. document.getElementById("latInput").value = celle[1].textContent;
  640. document.getElementById("lngInput").value = celle[2].textContent;
  641. document.getElementById("codiceCatastaleInput").value = celle[3].textContent;
  642. document.getElementById("dataPredisposizione").value = celle[4].textContent;
  643. document.getElementById("scala").value = celle[5].textContent;
  644. document.getElementById("piano").value = celle[6].textContent;
  645. document.getElementById("interno").value = celle[7].textContent;
  646. document.getElementById("operatore").value = celle[8].textContent;
  647. document.getElementById("terminazione").value = celle[9].textContent;
  648. document.getElementById("nota").value = celle[10].textContent;
  649. // Rimuovi la riga dalla tabella
  650. riga.remove();
  651. }
  652. // Funzione per cancellare una riga
  653. function cancellaDato(button) {
  654. // Chiedi conferma all'utente
  655. if (confirm("Sei sicuro di voler eliminare questo dato?")) {
  656. // L'utente ha confermato, procedi con l'eliminazione
  657. const riga = button.closest("tr");
  658. if (riga) {
  659. riga.remove();
  660. alert("Dato eliminato con successo.");
  661. }
  662. } else {
  663. // L'utente ha annullato l'eliminazione
  664. alert("Eliminazione annullata.");
  665. }
  666. }
  667. // Funzione per resettare il form
  668. function resettaForm() {
  669. document.getElementById('addressInputForm').value = '';
  670. document.getElementById('addressInput').value = '';
  671. document.getElementById('latInput').value = '';
  672. document.getElementById('lngInput').value = '';
  673. document.getElementById('codiceCatastaleInput').value = '';
  674. document.getElementById('dataPredisposizione').value = '';
  675. document.getElementById('scala').value = '';
  676. document.getElementById('piano').value = '';
  677. document.getElementById('interno').value = '';
  678. document.getElementById('operatore').value = '1';
  679. document.getElementById('terminazione').value = '';
  680. document.getElementById('nota').value = '';
  681. }
  682. // Aggiungi un listener per il movimento della mappa
  683. map.on('moveend', debouncedCaricaEdifici);
  684. // Carica gli edifici iniziali
  685. caricaEdifici();
  686. </script>
  687. </body>
  688. </html>