commit 83a8402bb7cefafb97a75e92041139ad9f0b709c Author: paolo Date: Tue May 12 21:05:35 2026 +0200 Aggiunti file javascript diff --git a/Automazione DATI COC.user.js b/Automazione DATI COC.user.js new file mode 100644 index 0000000..8ad2fcf --- /dev/null +++ b/Automazione DATI COC.user.js @@ -0,0 +1,189 @@ +// ==UserScript== +// @name Automazione DATI COC +// @namespace http://tampermonkey.net/ +// @version 7.0 +// @description Polling 2.5s, Nessun refresh dopo upload, Dati persistenti in memoria +// @match *://www.ilportaledellautomobilista.it/immatricolazioni/* +// @grant GM_xmlhttpRequest +// @grant GM_setValue +// @grant GM_getValue +// @grant GM_addStyle +// @connect localhost +// ==/UserScript== + +(function() { + 'use strict'; + + // --- CONFIGURAZIONE --- + const SEARCH_URL = "https://www.ilportaledellautomobilista.it/immatricolazioni/certificatoConformitaDatiTecniciVE/Read_initAction.action?pageStatus=SEARCH"; + const LOCAL_GET_URL = "https://localhost/hook/dati4.php"; + const LOCAL_POST_URL = "https://localhost/hook/ans4.php"; + const POLLING_MS = 2500; + + const clean = (val) => (val === "." || val === undefined || val === null) ? "" : val; + + // --- STILE UI (Allineato a Destra) --- + GM_addStyle(` + #m-container { position: fixed; right: 3cm; top: 5cm; z-index: 9999; display: flex; flex-direction: column; gap: 10px; } + .m-btn { padding: 12px 18px; border: none; border-radius: 5px; color: white; font-weight: bold; cursor: pointer; box-shadow: 2px 2px 5px rgba(0,0,0,0.3); font-family: sans-serif; min-width: 220px; } + #btn-compila { background-color: #ffc107; color: #000; } + #btn-upload { background-color: #dc3545; cursor: not-allowed; opacity: 0.6; } + #btn-upload.active { background-color: #28a745; cursor: pointer; opacity: 1; } + #status-info { background: white; padding: 5px; font-size: 10px; border: 1px solid #ccc; text-align: center; border-radius: 3px; } + `); + + // --- CREAZIONE MENU --- + const container = document.createElement('div'); + container.id = 'm-container'; + + const infoBox = document.createElement('div'); + infoBox.id = 'status-info'; + infoBox.innerText = 'In attesa di dati...'; + + const btnCompila = document.createElement('button'); + btnCompila.className = 'm-btn'; + btnCompila.id = 'btn-compila'; + btnCompila.innerText = '1. CERCA VEICOLI'; + + const btnUpload = document.createElement('button'); + btnUpload.className = 'm-btn'; + btnUpload.id = 'btn-upload'; + btnUpload.innerText = '2. ATTESA TABELLA...'; + btnUpload.disabled = true; + + container.appendChild(infoBox); + container.appendChild(btnCompila); + container.appendChild(btnUpload); + document.body.appendChild(container); + + // Aggiorna l'etichetta info se ci sono dati salvati + const aggiornaInfoUI = () => { + const d = GM_getValue("lastTaskData"); + if(d) infoBox.innerText = "Dati pronti: " + (d.valore1 || "Caricati"); + }; + aggiornaInfoUI(); + + // --- CONTROLLO TABELLA REAL-TIME --- + setInterval(() => { + const table = document.getElementById('listTable'); + const rows = table ? table.querySelectorAll('tbody tr') : []; + if (table && rows.length > 0) { + btnUpload.classList.add('active'); + btnUpload.disabled = false; + btnUpload.innerText = '2. INVIA DATI (Pronto)'; + } else { + btnUpload.classList.remove('active'); + btnUpload.disabled = true; + btnUpload.innerText = '2. ATTESA TABELLA...'; + } + }, 1000); + + // --- FUNZIONE POLLING --- + function startPolling() { + GM_xmlhttpRequest({ + method: "GET", + url: LOCAL_GET_URL, + nocache: true, + onload: function(response) { + try { + const data = JSON.parse(response.responseText); + if (data.tipo === "DATI-COC" && data.task === "fare") { + console.log("Nuovo task ricevuto:", data); + + // Salviamo i dati (sovrascrivendo i precedenti) + GM_setValue("lastTaskData", data); + aggiornaInfoUI(); + + // Comunichiamo al server che il task è stato preso in carico + aggiornaStatoTask(data); + + // Esecuzione automatica solo se siamo nella pagina corretta + if (window.location.href.includes("pageStatus=SEARCH")) { + eseguiAutomazione(data); + } else { + window.location.href = SEARCH_URL; + } + } + } catch (e) { } + setTimeout(startPolling, POLLING_MS); + }, + onerror: () => setTimeout(startPolling, POLLING_MS) + }); + } + + function aggiornaStatoTask(originalData) { + let updateData = {...originalData}; + updateData.task = "COMPLETATO"; + GM_xmlhttpRequest({ + method: "POST", + url: LOCAL_GET_URL, + headers: { "Content-Type": "application/json" }, + data: JSON.stringify(updateData) + }); + } + + function eseguiAutomazione(params) { + const familyInput = document.querySelector('input[name*="VEFrom.descrizioneFamigliaVeicolo"]'); + if (familyInput) { + const inputs = document.querySelectorAll('input'); + inputs.forEach(input => { + if (input.name.includes("VEFrom.descrizioneFamigliaVeicolo")) input.value = clean(params.valore1); + if (input.name.includes("VEFrom.descrizioneVarianteVeicolo")) input.value = clean(params.valore2); + if (input.name.includes("VE.codiceOmologazioneEuropea")) input.value = clean(params.valore3); + if (input.name.includes("VE.codiceMarchioVeicolo")) input.value = clean(params.valore4); + if (input.name.includes("progressivoCostruttoreVeicolo")) input.value = clean(params.valore5); + }); + + const btnSearch = document.getElementById('RicercaCertificatoConformitaDatiTecniciVE_button_value_searchElement'); + if (btnSearch) btnSearch.click(); + } + } + + function validaELeggiTabella() { + const table = document.getElementById('listTable'); + if (!table) return; + + const rows = table.querySelectorAll('tbody tr'); + let records = []; + rows.forEach(row => { + const cells = Array.from(row.querySelectorAll('td')) + .filter(td => !td.querySelector('input[type="radio"]')) + .map(td => td.innerText.trim()); + if (cells.length > 0) records.push(cells); + }); + + GM_xmlhttpRequest({ + method: "POST", + url: LOCAL_POST_URL, + headers: { "Content-Type": "application/json" }, + data: JSON.stringify({ tabella_dati: records }), + onload: function(response) { + try { + const res = JSON.parse(response.responseText); + if (res.status === "ok") { + // alert("INVIO RIUSCITO: " + res.messaggio); + // NOTA: Non cancelliamo GM_setValue né ricarichiamo la pagina qui. + } else { + alert("ERRORE PHP: " + res.messaggio); + } + } catch (e) { + alert("Dati inviati al server."); + } + } + }); + } + + btnCompila.addEventListener('click', () => { + const d = GM_getValue("lastTaskData"); + if(d) { + eseguiAutomazione(d); + } else { + alert("Nessun dato in memoria. Attendi il caricamento automatico dal server."); + } + }); + + btnUpload.addEventListener('click', validaELeggiTabella); + + startPolling(); + +})(); \ No newline at end of file diff --git a/Capture URL Transitions.user.js b/Capture URL Transitions.user.js new file mode 100644 index 0000000..0c39151 --- /dev/null +++ b/Capture URL Transitions.user.js @@ -0,0 +1,59 @@ +// ==UserScript== +// @name Capture URL Transitions +// @namespace http://tampermonkey.net/ +// @version 1.0 +// @description Salva tutti i cambi di URL e i parametri authcode in una variabile globale +// @author Tu +// @match https://www.ilportaledeltrasporto.it/* +// @run-at document-start +// @grant none +// ==/UserScript== + +(function() { + 'use strict'; + + // Variabile globale dove verranno salvati tutti i passaggi + window.capturedURLs = []; + + function logURL(method) { + const currentURL = window.location.href; + const entry = { + timestamp: new Date().toLocaleTimeString(), + method: method, + url: currentURL + }; + + window.capturedURLs.push(entry); + + // Stampa in console così puoi vederlo in tempo reale + console.log(`%chttps://medium.com/data-science/the-capture-recapture-method-dc9985b928da: %c${currentURL}`, "color: orange; font-weight: bold;", "color: cyan;"); + + // Se contiene l'authcode, evidenzialo con un alert o un log speciale + if (currentURL.includes('authcode')) { + console.error("!!! TROVATO AUTHCODE !!!", currentURL); + } + } + + // Intercettiamo i metodi usati dalle Single Page Application (React) + const originalPushState = history.pushState; + const originalReplaceState = history.replaceState; + + history.pushState = function() { + originalPushState.apply(this, arguments); + logURL('pushState'); + }; + + history.replaceState = function() { + originalReplaceState.apply(this, arguments); + logURL('replaceState'); + }; + + // Intercettiamo i tasti avanti/indietro del browser + window.addEventListener('popstate', function() { + logURL('popstate'); + }); + + // Registriamo l'URL iniziale + logURL('initial-load'); + +})(); \ No newline at end of file diff --git a/Click _Gestisci le istanze_.user.js b/Click _Gestisci le istanze_.user.js new file mode 100644 index 0000000..82188d6 --- /dev/null +++ b/Click _Gestisci le istanze_.user.js @@ -0,0 +1,54 @@ +// ==UserScript== +// @name Click "Gestisci le istanze" +// @namespace http://tampermonkey.net/ +// @version 3.0 +// @description Cerca e preme il pulsante con testo specifico +// @author YourName +// @match https://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa* +// @grant none +// ==/UserScript== + +(function() { + 'use strict'; + + // Funzione per cercare e cliccare + function findAndClick() { + // Recupera tutti i pulsanti nella pagina + const buttons = Array.from(document.querySelectorAll('button')); + + // Cerca il pulsante che contiene il testo desiderato (case-sensitive) + const targetButton = buttons.find(btn => + btn.textContent.trim().includes("Gestisci le istanze") + ); + + if (targetButton) { + console.log("Pulsante 'Gestisci le istanze' trovato! Clicco..."); + + // Focus e click per massima compatibilità + targetButton.focus(); + targetButton.click(); + + // Restituisce true se ha trovato il pulsante + return true; + } + return false; + } + + // Usiamo un MutationObserver: è più efficiente del timer perché + // "osserva" i cambiamenti del sito e interviene appena appare il tasto + const observer = new MutationObserver((mutations, obs) => { + if (findAndClick()) { + obs.disconnect(); // Una volta cliccato, smette di osservare + } + }); + + // Inizia a osservare i cambiamenti nel body della pagina + observer.observe(document.body, { + childList: true, + subtree: true + }); + + // Eseguiamo anche un controllo immediato al caricamento + window.addEventListener('load', findAndClick); + +})(); \ No newline at end of file diff --git a/Correggi Offset COLLAUDO Portale.user.js b/Correggi Offset COLLAUDO Portale.user.js new file mode 100644 index 0000000..4332922 --- /dev/null +++ b/Correggi Offset COLLAUDO Portale.user.js @@ -0,0 +1,118 @@ +// ==UserScript== +// @name Correggi Offset COLLAUDO Portale +// @namespace http://tampermonkey.net/ +// @version 1.0 +// @description Correzione puntuale: elimina sfasamento in testa e recupera coda dal campo successivo +// @author Gemini+Gatto. +// @match https://www.ilportaledellautomobilista.it/revisioni/certificatoApprovazioneVeicolo/* +// @grant none +// ==/UserScript== + +(function() { + 'use strict'; + + // 0. STATO DI ESECUZIONE (Salvato nella sessione del browser) + // Usiamo sessionStorage così se l'utente ricarica la pagina, lo stato si resetta. + let giaEseguito = false; + + // --- 1. CONFIGURAZIONE FILTRI --- + const targetPhrase = "Dettaglio Certificato Approvazione Veicolo"; + //const targetDomain = "www.ilportaledeltrasporto.it"; + + // --- 2. VERIFICA CONDIZIONI DI ATTIVAZIONE --- + + if (!document.body.innerText.includes(targetPhrase)) { + console.log("Script disattivato: Frase specifica non trovata nella pagina."); + return; + } + + function correggiValorePerValore() { + const baseID = "DettaglioCertificatoApprovazioneVeicolo_richiestaCertificatoApprovazioneVeicoloView_righeDescrittiveList_"; + const numCampi = 12; // Da 0 a 11 (a-l) + let v = []; + + if (giaEseguito) { + console.warn("Tentativo duplicato: USCITA o ricaricamento pagina in corso..."); + console.log("Script disattivato: Gia apportate modifiche."); + // window.location.reload(); // Forza il refresh (F5) + return; + } + + // 1. Carichiamo i valori attuali in un array v (v[0]=a, v[1]=b, ..., v[11]=l) + for (let i = 0; i < numCampi; i++) { + let el = document.getElementById(baseID + i + "_"); + v.push(el ? el.value : ""); + } + + console.log("Valori letti prima della correzione:", v); + + let v_corr = new Array(numCampi); + + // 2. Applicazione della strategia definita dall'utente + // a_corr = a inalterato + v_corr[0] = v[0]; + + // Da b a k (indici da 1 a 10) + // b_corr (i=1): elimina 1 char, aggiunge primi 1 di c (v[2]) + // c_corr (i=2): elimina 2 char, aggiunge primi 2 di d (v[3]) + // ... + for (let i = 1; i <= 10; i++) { + let n_da_eliminare = i; + let n_da_recuperare = i; + + // Prendiamo il campo corrente, togliamo l'inizio + let parte_restante = v[i].substring(n_da_eliminare); + + // Prendiamo i caratteri "scivolati" dal campo successivo + let coda_recuperata = v[i+1].substring(0, n_da_recuperare); + + // Componiamo il valore corretto + v_corr[i] = parte_restante + coda_recuperata; + + console.log(`Debug Cella ${i}: rimosse ${n_da_eliminare} in testa, aggiunte ${n_da_recuperare} da cella successiva.`); + } + + // l_corr (l'ultimo campo, indice 11) - presumibilmente resta la parte rimanente o inalterato + v_corr[11] = v[11].substring(11); + + // 3. Scrittura dei valori corretti nei campi HTML + for (let i = 0; i < numCampi; i++) { + let el = document.getElementById(baseID + i + "_"); + if (el) { + // Assicuriamoci che non superi mai i 36 caratteri (limite database) + el.value = v_corr[i].substring(0, 36); + el.style.backgroundColor = "#e8f5e9"; // Feedback visivo (verde) + el.style.border = "1px solid #2e7d32"; + } + } + + giaEseguito = true; + + // alert("Correzione applicata secondo lo schema definito."); + } + + // Creazione del Pulsante (3cm da destra, 8cm dall'alto) + const btn = document.createElement('button'); + btn.type = "button"; + btn.innerHTML = "CORREGGI"; + btn.style.cssText = ` + position: fixed; + right: 3cm; + top: 4cm; + z-index: 10000; + padding: 12px 20px; + background-color: #ff5722; + color: white; + border: 2px solid #e64a19; + font-weight: bold; + cursor: pointer; + box-shadow: 0 4px 6px rgba(0,0,0,0.3); + `; + + btn.onclick = (e) => { + e.preventDefault(); + correggiValorePerValore(); + }; + + document.body.appendChild(btn); +})(); \ No newline at end of file diff --git a/DOC_NRAP & AB_NRAP portale trasporto v4.5 WORKING..user.js b/DOC_NRAP & AB_NRAP portale trasporto v4.5 WORKING..user.js new file mode 100644 index 0000000..2f60437 --- /dev/null +++ b/DOC_NRAP & AB_NRAP portale trasporto v4.5 WORKING..user.js @@ -0,0 +1,645 @@ +// ==UserScript== +// @name DOC_NRAP & AB_NRAP portale trasporto v4.5 WORKING. +// @namespace http://tampermonkey.net/ +// @version 4.5 +// @description Automazione DOC_NRAP e AB_NRAP con gestione modale di conferma +// @author Tu +// @match *://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/* +// @grant GM_xmlhttpRequest +// @connect localhost +// @run-at document-end +// ==/UserScript== + +(function() { + 'use strict'; + + // --- VARIABILI DI STATO --- + let TELAIO = ''; + let VALORE2 = '0'; + let VALORE3 = ''; + let TIPO_ATTUALE = ''; + let taskAttivo = false; + let downloadInCorso = false; + let completatoLocalmente = false; + const ENDPOINT_GET = 'http://localhost/hook/dati2.php'; + + // --- HELPER FUNCTIONS --- + + // Funzione per discriminare lo stato delle schede/tessere + + function getTessereStatus() { + let stati = { Tess1: "Sconosciuto", Tess2: "Sconosciuto", Tess3: "Sconosciuto" }; + + const cardContainers = document.querySelectorAll('.CardComponent.d-flex.col'); + + // Se non ci sono tessere, esci silenziosamente senza fare log di errore + if (cardContainers.length === 0) { + return null; // Restituiamo null per capire che non siamo nella dashboard + } + + cardContainers.forEach((container, index) => { + const article = container.querySelector('article.Card'); + const h2 = container.querySelector('.cardText h2'); + + if (article && h2) { + const titolo = h2.innerText.trim().toLowerCase(); + let statoRilevato = "Sconosciuto"; + + // Verifica lo stato dalle classi dell'elemento article + if (article.classList.contains('Active')) statoRilevato = "Attivo"; + else if (article.classList.contains('Locked')) statoRilevato = "Bloccato"; + else if (article.classList.contains('Completed')) statoRilevato = "Completato"; + + // Mappatura precisa basata sul testo dell'H2 + if (titolo.includes("verifica documentazione")) { + stati.Tess1 = statoRilevato; + } else if (titolo.includes("visita e prova")) { + stati.Tess2 = statoRilevato; + } else if (titolo.includes("abilitazione telaio")) { + stati.Tess3 = statoRilevato; + } + + // console.log(`[TM] Rilevata Tessera: "${h2.innerText.trim()}" | Stato: ${statoRilevato}`); + } + }); + + return stati; + } + + function getTessereStatus_old() { + let stati = { + Tess1: "Sconosciuto", + Tess2: "Sconosciuto", + Tess3: "Sconosciuto" + }; + + // Seleziona i contenitori basandosi sulla classe che hai indicato + const cardContainers = document.querySelectorAll('.CardComponent.d-flex.col'); + + if (cardContainers.length === 0) { + console.warn("[TM] Nessun contenitore CardComponent trovato."); + return stati; + } + + cardContainers.forEach((container, index) => { + const article = container.querySelector('article.Card'); + const h2 = container.querySelector('.cardText h2'); + + if (article && h2) { + const titolo = h2.innerText.trim().toLowerCase(); + let statoRilevato = "Sconosciuto"; + + // Verifica lo stato dalle classi dell'elemento article + if (article.classList.contains('Active')) statoRilevato = "Attivo"; + else if (article.classList.contains('Locked')) statoRilevato = "Bloccato"; + else if (article.classList.contains('Completed')) statoRilevato = "Completato"; + + // Mappatura precisa basata sul testo dell'H2 + if (titolo.includes("verifica documentazione")) { + stati.Tess1 = statoRilevato; + } else if (titolo.includes("visita e prova")) { + stati.Tess2 = statoRilevato; + } else if (titolo.includes("abilitazione telaio")) { + stati.Tess3 = statoRilevato; + } + + // console.log(`[TM] Rilevata Tessera: "${h2.innerText.trim()}" | Stato: ${statoRilevato}`); + } + }); + + return stati; + } + + // Pulizia stringhe: rimuove ogni spazio (inizio, fine, centro) e porta in maiuscolo + function cleanString(str) { + if (!str) return ""; + return str.toString().replace(/\s+/g, '').toUpperCase(); + } + + // Click sicuro per elementi React + function clickReactSafe(element) { + if (!element || typeof element.dispatchEvent !== 'function') return; + const opts = { bubbles: true, cancelable: true, view: window.unsafeWindow || window }; + try { + element.dispatchEvent(new MouseEvent('mousedown', opts)); + element.dispatchEvent(new MouseEvent('mouseup', opts)); + element.click(); + } catch (e) { + element.dispatchEvent(new Event('mousedown', { bubbles: true })); + element.dispatchEvent(new Event('mouseup', { bubbles: true })); + element.click(); + } + } + + /** + * Premere il pulsante "Procedi" della tessera ennesima (1-based). + * @param {number} n - Indice della tessera (1 per la prima, 2 per la seconda, ecc.) + */ + function Procedi(n) { + console.log(`[TM] Test Procedi(${n}) avviato...`); + + // CORREZIONE: Le classi devono essere unite dai punti senza spazi + // perché appartengono allo stesso elemento div + const cardContainers = document.querySelectorAll('.CardComponent.d-flex.col'); + + if (cardContainers.length === 0) { + console.error("[TM] ERRORE: Nessun contenitore trovato. Verificare il selettore .CardComponent.d-flex.col"); + return; + } + + console.log(`[TM] Tessere trovate in pagina: ${cardContainers.length}`); + + // Controllo indice + if (n < 1 || n > cardContainers.length) { + console.error(`[TM] ERRORE: Indice ${n} non valido. Tessere disponibili: ${cardContainers.length}`); + return; + } + + // Selezioniamo la tessera corretta (n-1) + const targetCard = cardContainers[n - 1]; + console.log(`[TM] Opero sulla tessera #${n}:`, targetCard.querySelector('h2')?.innerText); + + // Cerchiamo il pulsante Procedi + // Nota: nell'HTML inviato la classe del footer è "cardFooter" (minuscolo/maiuscolo come nel DOM) + const btnProcedi = Array.from(targetCard.querySelectorAll('button')) + .find(b => b.textContent.trim().toUpperCase() === 'PROCEDI'); + + if (!btnProcedi) { + console.error(`[TM] Pulsante 'Procedi' non trovato nella tessera #${n}.`); + return; + } + + if (btnProcedi.disabled) { + console.warn(`[TM] Il pulsante della tessera #${n} è DISABILITATO.`); + return; + } + + console.log(`[TM] Click sulla tessera #${n}...`); + clickReactSafe(btnProcedi); + }; + + // Input sicuro per elementi React + + function setInputReactSafe(element, value) { + if (!element) return; + + // Determina se è un input o una textarea per usare il prototipo corretto + const prototype = element.tagName === 'TEXTAREA' + ? HTMLTextAreaElement.prototype + : HTMLInputElement.prototype; + + const setter = Object.getOwnPropertyDescriptor(prototype, 'value').set; + + element.focus(); + setter.call(element, value); + + // Trigger degli eventi per far capire a React che il testo è cambiato + element.dispatchEvent(new Event('input', { bubbles: true })); + element.dispatchEvent(new Event('change', { bubbles: true })); + element.dispatchEvent(new Event('blur', { bubbles: true })); + } + + function setInputReactSafe_old(input, value) { + if (!input) return; + const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set; + input.focus(); + setter.call(input, value); + input.dispatchEvent(new Event('input', { bubbles: true })); + input.dispatchEvent(new Event('change', { bubbles: true })); + } + + // Gestione della modale di conferma per AB_NRAP + function gestisciModaleConferma() { + const modale = document.querySelector('.ModalsPortal__container.mx-auto'); + if (modale) { + const btnConfermaModale = Array.from(modale.querySelectorAll('button')) + .find(b => { + const spans = b.querySelectorAll('span'); + return Array.from(spans).some(s => s.textContent.trim() === "Conferma"); + }); + + if (btnConfermaModale) { + console.log("[TM] Pulsante 'Conferma' trovato nella modale. Clicco..."); + clickReactSafe(btnConfermaModale); + // Attendiamo che la modale si chiuda e il sistema elabori prima di segnare fine task + setTimeout(segnaComeCompletato, 3000); + return true; + } + } + return false; + } + + // --- LOGICA SERVER --- + function avviaDownloadDocumenti() { + if (downloadInCorso) return; + + const tuttiIBottoni = Array.from(document.querySelectorAll('button.DocumentsSection__file-btn')); + if (tuttiIBottoni.length === 0) return; + + downloadInCorso = true; + const titoliGiaVisti = new Set(); + let delayDoc = 0; + + tuttiIBottoni.forEach((btn, index, array) => { + const riga = btn.closest('tr'); + const titolo = riga ? riga.innerText.trim().split('\t')[0] : btn.innerText.trim(); + + if (!titoliGiaVisti.has(titolo)) { + titoliGiaVisti.add(titolo); + + setTimeout(() => { + console.log(`[TM] 1. Avvio Download: ${titolo}`); + clickReactSafe(btn); + + // --- SEQUENZA MODALE --- + + // STEP A: Click Esporta File (dopo 1.2 secondi) + setTimeout(() => { + const btnEsporta = Array.from(document.querySelectorAll('button.btn-primary.btn-xs')); + + if (btnEsporta) { + console.log(`[TM] 2. Click Esporta File per: ${titolo}`); + clickReactSafe(btnEsporta); + } + + // STEP B: Click Chiudi Modale (dopo altri 1.5 secondi dal click esporta) + setTimeout(() => { + const btnChiudiModale = document.querySelector('button.ModalContent__header--btn'); + if (btnChiudiModale) { + console.log(`[TM] 3. Chiusura modale per: ${titolo}`); + clickReactSafe(btnChiudiModale); + } + }, 1500); + + }, 1200); + // ----------------------- + + if (index === array.length - 1) { + setTimeout(segnaComeCompletato, 5000); + } + }, delayDoc); + + delayDoc += 3000; + } + }); + } + + function fetchDati() { + GM_xmlhttpRequest({ + method: "GET", + url: ENDPOINT_GET, + onload: function(response) { + try { + const data = JSON.parse(response.responseText); + const targetHome = 'https://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/le-mie-istanze'; + + // Cerca questo blocco dentro fetchDati() e sostituiscilo: + + if (data.tipo === 'RESET_NRAP') { + console.log("[TM] Ricevuto comando RESET. Fermo i task e avviso il server..."); + + // 1. Impostiamo lo stato su RESET così segnaComeCompletato() sa cosa inviare + TIPO_ATTUALE = 'RESET_NRAP'; + TELAIO = ''; + VALORE2 = '0'; + VALORE3 = ''; + + // 2. Chiamiamo la funzione che già possiedi per notificare il server + segnaComeCompletato(); + + // 3. Opzionale: Torna in home solo se non ci sei già + if (window.location.href !== targetHome) { + window.location.href = targetHome; + } + return; + } + + if ((data.tipo === 'DOC_NRAP' || data.tipo === 'AB_NRAP') && data.task === 'fare') { + + if (TELAIO !== '' && TELAIO !== data.valore1) { + TELAIO = data.valore1; + window.location.href = targetHome; + return; + } + + if (TELAIO !== data.valore1 || TIPO_ATTUALE !== data.tipo) { + TELAIO = data.valore1; + VALORE2 = data.valore2; + VALORE3 = data.valore3; + TIPO_ATTUALE = data.tipo; + completatoLocalmente = false; + console.log(`[TM] Ricevuto task ${TIPO_ATTUALE} per: ${TELAIO}`); + } + + if (!completatoLocalmente) { + taskAttivo = true; + eseguiAutomazione(); + } + // Dentro l'else di fetchDati (quando data.task NON è 'fare') + } else { + if (taskAttivo) { + console.log("[TM] Nessun task attivo dal server, rilascio il controllo manuale."); + } + taskAttivo = false; + completatoLocalmente = false; // Rimuovi o commenta questa riga se vuoi evitare loop continui + } + } catch (e) { + console.error("[TM] Errore parsing dati", e); + } + } + }); + } + + function segnaComeCompletato() { + if (completatoLocalmente) return; + completatoLocalmente = true; + taskAttivo = false; + + const payload = { + tipo: TIPO_ATTUALE, + task: "COMPLETATO", + valore1: TELAIO, + valore2: VALORE2, + valore3: VALORE3 + }; + + GM_xmlhttpRequest({ + method: "POST", + url: ENDPOINT_GET, + data: JSON.stringify(payload), + headers: { "Content-Type": "application/json" }, + onload: function() { + console.log(`[TM] Task ${TIPO_ATTUALE} completato sul server.`); + downloadInCorso = false; + } + }); + } + + // --- AUTOMAZIONE PAGINE --- + + function eseguiAutomazione() { + // Se il task non è attivo o abbiamo già finito su questa pagina, esci subito + if (!taskAttivo || completatoLocalmente) return; + + const url = window.location.href; + + // --- 1. Pagina di Ricerca --- + if (url.includes('le-mie-istanze')) { + const input = document.getElementById('numeroTelaio'); + const btnCerca = Array.from(document.querySelectorAll('button')).find(b => b.textContent.includes('Cerca')); + const btnTabella = document.querySelector('button.action-button-table'); + + if (input && TELAIO !== '' && cleanString(input.value) !== cleanString(TELAIO)) { + setInputReactSafe(input, TELAIO); + setTimeout(() => { if(btnCerca) clickReactSafe(btnCerca); }, 800); + } + if (btnTabella) setTimeout(() => clickReactSafe(btnTabella), 1500); + return; // Fine logica ricerca + } + + // --- 2. Gestione Dashboard vs Dettaglio --- + // Recuperiamo lo stato delle tessere. getTessereStatus() ora deve restituire null + // se non trova i contenitori (come spiegato prima), evitando log di errore. + const situazione = getTessereStatus(); + + // CASO A: Siamo nella Dashboard (Tessere visibili) + if (situazione !== null && !url.includes('dettaglio-istanza') && !url.includes('abilitazione-telaio')) { + const btnProcedi = Array.from(document.querySelectorAll('button')).find(b => b.textContent.trim() === 'Procedi'); + + if (btnProcedi && !btnProcedi.disabled) { + if (TIPO_ATTUALE === 'DOC_NRAP' && situazione.Tess1 === "Attivo") { + console.log("[TM] Dashboard: Apro Tessera 1 (Documentazione)"); + setTimeout(() => { Procedi(1); }, 1000); + } else if (TIPO_ATTUALE === 'AB_NRAP' && situazione.Tess3 === "Attivo") { + console.log("[TM] Dashboard: Apro Tessera 3 (Abilitazione)"); + setTimeout(() => { Procedi(3); }, 1000); + } + } + return; // Esci: abbiamo gestito la dashboard + } + + // CASO B: Siamo nella Pagina di Dettaglio/Compilazione (Abilitazione o Download) + if (url.includes('dettaglio-istanza') || url.includes('abilitazione-telaio')) { + + // Sotto-caso: Compilazione Dati (AB_NRAP) + if (TIPO_ATTUALE === 'AB_NRAP') { + const inputCodImmat = document.getElementById('Codice immatricolazione'); + const inputNota = document.getElementById('Nota*') || document.getElementById('Nota'); + + if (inputCodImmat && inputNota) { + console.log("[TM] Pagina compilazione rilevata. Inserisco dati..."); + + // Inserimento dati con logica React + setInputReactSafe(inputCodImmat, VALORE2); + setInputReactSafe(inputNota, VALORE3); + + // Forza il focus out per "fissare" il valore in React + inputCodImmat.dispatchEvent(new Event('blur', { bubbles: true })); + inputNota.dispatchEvent(new Event('blur', { bubbles: true })); + + console.log("[TM] Compilazione eseguita. Ora l'Observer si ferma."); + + // BLOCCA L'OBSERVER: impostando a true, questa intera funzione + // si fermerà al primo IF nei cicli successivi. + completatoLocalmente = true; + } + } + + // Sotto-caso: Download Documenti (DOC_NRAP) + else if (TIPO_ATTUALE === 'DOC_NRAP') { + if (downloadInCorso) return; + + if (parseInt(VALORE2) > 0) { + console.log("[TM] Pagina documenti rilevata. Avvio download..."); + avviaDownloadDocumenti(); + } else { + console.log("[TM] Nessun documento richiesto (Valore2=0). Chiudo."); + segnaComeCompletato(); + } + } + } + } + + function eseguiAutomazione_old() { + if (!taskAttivo || completatoLocalmente) return; + + const url = window.location.href; + + // 1. Pagina di Ricerca + if (url.includes('le-mie-istanze')) { + const input = document.getElementById('numeroTelaio'); + const btnCerca = Array.from(document.querySelectorAll('button')).find(b => b.textContent.includes('Cerca')); + const btnTabella = document.querySelector('button.action-button-table'); + + if (input && TELAIO !== '' && cleanString(input.value) !== cleanString(TELAIO)) { + setInputReactSafe(input, TELAIO); + setTimeout(() => { if(btnCerca) clickReactSafe(btnCerca); }, 800); + } + if (btnTabella) setTimeout(() => clickReactSafe(btnTabella), 1500); + //if (btnTabella) console.log("Pulsante Tabella trovato! esegui il comando a mano"); + } + + // --- 2. Pagina Dashboard (Tessere) --- + if (url.includes('/abilitazione/') && !url.includes('dettaglio-istanza')) { + const situazione = getTessereStatus(); + const btnProcedi = Array.from(document.querySelectorAll('button')).find(b => b.textContent.trim() === 'Procedi'); + + if (btnProcedi && !btnProcedi.disabled) { + if (TIPO_ATTUALE === 'DOC_NRAP' && situazione.Tess1 === "Attivo") { + setTimeout(() => { Procedi(1); }, 1000); + } else if (TIPO_ATTUALE === 'AB_NRAP' && situazione.Tess3 === "Attivo") { + setTimeout(() => { Procedi(3); }, 1000); + } + } + } + + // --- 3. Pagina di Abilitazione (Dettaglio) --- + if (url.includes('/abilitazione/') && url.includes('/abilitazione-telaio')) { + + if (TIPO_ATTUALE === 'AB_NRAP') { + const inputCodImmat = document.getElementById('Codice immatricolazione'); + // Cerca la nota sia con che senza asterisco + const inputNota = document.getElementById('Nota*') || document.getElementById('Nota'); + console.log("[TM] Pagina di abilitazione rilevata. Compilo..."); + if (inputCodImmat && inputNota) { + console.log("[TM] Pagina di abilitazione rilevata. Compilo..."); + + //setInputReactSafe(inputCodImmat, VALORE2); + //setInputReactSafe(inputNota, VALORE3); + + console.log("[TM] Dati inseriti. Ora mi fermo e ti lascio il controllo."); + + // IMPORTANTE: Segniamo come completato localmente solo la "scrittura" + // così l'Observer smette di chiamare eseguiAutomazione() per questa pagina. + completatoLocalmente = true; + } + } + + if (TIPO_ATTUALE === 'DOC_NRAP') { + if (downloadInCorso) return; + if (parseInt(VALORE2) > 0) { + avviaDownloadDocumenti(); + } else { + segnaComeCompletato(); + } + } + } + } + + function eseguiAutomazione2() { + if (!taskAttivo || completatoLocalmente) return; + const situazione = getTessereStatus(); + + // GUARDIA: Se tutte le tessere sono "Bloccato" o "Sconosciuto", + // probabilmente React sta ancora caricando. Fermati e aspetta il prossimo ciclo. + if (situazione.Tess1 === "Bloccato" && situazione.Tess2 === "Bloccato") { + return; + } + + const url = window.location.href; + + // 1. Pagina di Ricerca + if (url.includes('le-mie-istanze')) { + const input = document.getElementById('numeroTelaio'); + const btnCerca = Array.from(document.querySelectorAll('button')).find(b => b.textContent.includes('Cerca')); + const btnTabella = document.querySelector('button.action-button-table'); + + if (input && TELAIO !== '' && cleanString(input.value) !== cleanString(TELAIO)) { + setInputReactSafe(input, TELAIO); + setTimeout(() => { if(btnCerca) clickReactSafe(btnCerca); }, 800); + } + if (btnTabella) setTimeout(() => clickReactSafe(btnTabella), 1500); + //if (btnTabella) console.log("Pulsante Tabella trovato! esegui il comando a mano"); + } + + // 2. Pagina Intermedia (Abilitazione / Dashboard) + if (url.includes('/abilitazione/') && !url.includes('dettaglio-istanza')) { + + const btnProcedi = Array.from(document.querySelectorAll('button')).find(b => b.textContent.trim() === 'Procedi'); + + if (btnProcedi && !btnProcedi.disabled) { + + // --- LOGICA SELETTIVA --- + + if (TIPO_ATTUALE === 'DOC_NRAP') { + console.log("Stato tessere al click:", situazione); + if (situazione.Tess1 === "Attivo" && situazione.Tess3 === "Bloccato") { + console.log("[TM] DOC_NRAP: Tessera 1 pronta. Procedo apertura documenti..."); + setTimeout(() => { Procedi(1); }, 1000); + } else if (situazione.Tess1 === "Completato"){ + console.warn("[TM] DOC_NRAP: Vista documentazione"); + } else if (situazione.Tess1 === "Bloccato"){ + console.warn("[TM] DOC_NRAP: Documentazione bloccata, attendere"); + } + } + + else if (TIPO_ATTUALE === 'AB_NRAP') { + // Logica specifica per AB_NRAP (es. solo se Tess3 è Attiva) + if (situazione.Tess3 === "Attivo") { + console.log("[TM] DOC_NRAP: Tessera 3 Ok si procede a validazione..."); + setTimeout(() => { Procedi(3); }, 1000); + } + } + + } + } + + // 3. Pagina Dettaglio Istanza + if (url.includes('dettaglio-istanza')) { + const situazioneInDettaglio = getTessereStatus(); + + // CASO A: Operazione AB_NRAP (Solo inserimento dati, NO clic automatico) + if (TIPO_ATTUALE === 'AB_NRAP') { + const inputCodImmat = document.getElementById('Codice immatricolazione'); + const inputNota = document.getElementById('Nota*'); + + let datiInseriti = false; + + // 1. Inserimento Codice Immatricolazione (Valore2) + if (inputCodImmat.value !== VALORE2) { + console.log("[TM] Inserisco Codice Immatricolazione:", VALORE2); + setInputReactSafe(inputCodImmat, VALORE2); + datiInseriti = true; + } + + // 2. Inserimento Nota (Valore3) + if (inputNota.value !== VALORE3) { + console.log("[TM] Inserisco Nota:", VALORE3); + setInputReactSafe(inputNota, VALORE3); + datiInseriti = true; + } + + // 3. Feedback visivo e stop + if (datiInseriti) { + console.log("[TM] Campi compilati. Attendo interazione manuale per il tasto Conferma."); + // Non facciamo nulla: il ciclo MutationObserver continuerà a girare + // ma non troverà discrepanze nei valori e non farà clic. + } + } + + // CASO B: Operazione DOC_NRAP (Download) + else if (TIPO_ATTUALE === 'DOC_NRAP') { + if (downloadInCorso) return; // Se sto già scaricando, NON rientrare nella funzione + if (parseInt(VALORE2) > 0) { + avviaDownloadDocumenti(); + //console.log("Avvio download documenti. Stato attuale tessere:", situazione); + } else { + console.log("[TM] Valore2 <= 1, chiusura task senza download."); + segnaComeCompletato(); + } + } + + } + } + + // --- INITIALIZATION --- + + const observer = new MutationObserver(() => { + if (taskAttivo) eseguiAutomazione(); + }); + observer.observe(document.body, { childList: true, subtree: true }); + + setInterval(fetchDati, 2500); + fetchDati(); + +})(); \ No newline at end of file diff --git a/EUCARIS php Bridge - VERSIONE ANTI-LOOP.user.js b/EUCARIS php Bridge - VERSIONE ANTI-LOOP.user.js new file mode 100644 index 0000000..3dd036d --- /dev/null +++ b/EUCARIS php Bridge - VERSIONE ANTI-LOOP.user.js @@ -0,0 +1,118 @@ +// ==UserScript== +// @name EUCARIS php Bridge - VERSIONE ANTI-LOOP +// @namespace http://tampermonkey.net/ +// @version 7.1 +// @description Navigazione forzata con blocco dei ricarichi infiniti +// @author GATTO + Gemini +// @match *://www.ilportaledellautomobilista.it/Info/* +// @grant GM_xmlhttpRequest +// @grant GM_setValue +// @grant GM_getValue +// @connect 192.168.1.33 +// @run-at document-end +// ==/UserScript== + +(function() { + 'use strict'; + + const PHP_URL = "http://192.168.1.33/hook/dati1.php"; + const URL_STEP_1 = "/Info/info/CreateGraph_home.action?SESSION_INFO_NODO_CORRENTE=N370&CRITERIO=99&METODO=/criteria-page/home.jsp"; + const URL_STEP_2 = "/Info/info/CreateGraph_getFunzioneSelezionata.action?SESSION_INFO_NODO_CORRENTE=N371"; + const URL_HOME = "/Info/info/CreateGraph_home.action?SESSION_INFO_NODO_CORRENTE=N21&CRITERIO=99&METODO=/criteria-page/home.js"; + + let isRedirecting = false; + + // --- FUNZIONE DI SALTO SICURA (EVITA LOOP) --- + function safeRedirect(targetPath) { + const fullTarget = window.location.origin + targetPath; + if (window.location.href !== fullTarget) { + console.log("Reindirizzamento a: " + targetPath); + isRedirecting = true; + window.location.href = fullTarget; + } else { + console.log("Già a destinazione, evito il loop."); + } + } + + function autofillEucaris() { + const telaioDaInserire = GM_getValue("ultimo_telaio", null); + + if (window.location.href.includes("N371") && telaioDaInserire) { + const radio = document.getElementById("CreateGraph_getFunzioneSelezionata_criterio77"); + const inputTelaio = document.getElementById("CreateGraph_getFunzioneSelezionata_criteri_77__telaio"); + const inputStato = document.getElementById("CreateGraph_getFunzioneSelezionata_criteri_77__idStato"); + const btnConfirm = document.getElementById("CreateGraph_getFunzioneSelezionata_button_value_confirm"); + + if (radio) radio.checked = true; + if (inputTelaio) inputTelaio.value = telaioDaInserire; + if (inputStato) inputStato.value = "MCI"; + + if (inputTelaio && inputTelaio.value !== "") { + GM_setValue("ultimo_telaio", null); + if (btnConfirm) { + setTimeout(() => { btnConfirm.click(); }, 800); + } + } + } + } + + function checkTask() { + if (isRedirecting) return; + + GM_xmlhttpRequest({ + method: "GET", + url: PHP_URL + "?nocache=" + new Date().getTime(), + onload: function(response) { + try { + const data = JSON.parse(response.responseText); + if (data.task && data.task.toLowerCase() === "fare") { + if (data.valore1 && data.tipo.toUpperCase() === "EUCARIS") { + GM_setValue("ultimo_telaio", data.valore1); + } + eseguiSalto(data); + } + } catch (e) { } + } + }); + } + + function eseguiSalto(data) { + const tipo = data.tipo.toUpperCase(); + const currentUrl = window.location.href; + + if (tipo === "EUCARIS") { + // Se non sono ancora in N370 o N371, vai a Step 1 + if (!currentUrl.includes("N370") && !currentUrl.includes("N371")) { + safeRedirect(URL_STEP_1); + } + // Se sono in N370, segnalo completato e vado a Step 2 + else if (currentUrl.includes("N370")) { + isRedirecting = true; + const update = { ...data, task: "completato" }; + GM_xmlhttpRequest({ + method: "POST", + url: PHP_URL, + data: JSON.stringify(update), + headers: { "Content-Type": "application/json" }, + onload: () => { safeRedirect(URL_STEP_2); } + }); + } + } + else if (tipo === "RESET") { + if (!currentUrl.includes("N21")) { // Salta a home solo se non ci sei già + isRedirecting = true; + const update = { ...data, task: "completato" }; + GM_xmlhttpRequest({ + method: "POST", + url: PHP_URL, + data: JSON.stringify(update), + headers: { "Content-Type": "application/json" }, + onload: () => { safeRedirect(URL_HOME); } + }); + } + } + } + + autofillEucaris(); + setInterval(checkTask, 3000); // Leggermente più lento per dare tempo alla pagina di stabilizzarsi +})(); \ No newline at end of file diff --git a/Estrattore Manuale Tabella Portale Trasporto.user.js b/Estrattore Manuale Tabella Portale Trasporto.user.js new file mode 100644 index 0000000..e03c1ce --- /dev/null +++ b/Estrattore Manuale Tabella Portale Trasporto.user.js @@ -0,0 +1,92 @@ +// ==UserScript== +// @name Estrattore Manuale Tabella Portale Trasporto +// @namespace http://tampermonkey.net/ +// @version 2.0 +// @description Aggiornamento dati tramite tasto Cerca senza ricaricare la pagina +// @author Gemini +// @match https://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/le-mie-istanze* +// @grant GM_xmlhttpRequest +// @connect 192.168.1.33 +// ==/UserScript== + +(function() { + 'use strict'; + + const CONFIG = { + endpoint: 'http://192.168.1.33/hook/ans2.php', + interval: 6000 // 6 secondi tra un invio e l'altro + }; + + console.log("%c Script in modalità Manuale Attivo. Imposta i filtri e lo script farà il resto.", "color: #00DBFF; font-weight: bold;"); + + function eseguiCiclo() { + // 1. Cerca il pulsante "Cerca" + const buttons = Array.from(document.querySelectorAll('button')); + const searchButton = buttons.find(btn => + btn.innerText.trim().toUpperCase() === "CERCA" + ); + + if (searchButton) { + console.log("Aggiornamento dati (clic su Cerca)..."); + searchButton.click(); + + // 2. Aspetta che la tabella si aggiorni (4 secondi) + setTimeout(() => { + estraiEInvia(); + }, 4000); + } else { + console.warn("Pulsante 'Cerca' non trovato. Riprovo tra 20 secondi."); + setTimeout(eseguiCiclo, CONFIG.interval); + } + } + + function estraiEInvia() { + const rows = document.querySelectorAll('[role="row"]'); + const results = []; + + rows.forEach(row => { + const cells = row.querySelectorAll('[role="cell"]'); + if (cells.length >= 5) { + const idIstanza = cells[0].innerText.trim(); + if (idIstanza !== "" && idIstanza.toLowerCase() !== "identificativo istanza") { + results.push({ + identificativo: idIstanza, + data_inserimento: cells[1]?.innerText.trim(), + stato: cells[2]?.innerText.trim(), + tipologia: cells[3]?.innerText.trim(), + targa_telaio: cells[4]?.innerText.trim() + }); + } + } + }); + + if (results.length > 0) { + console.log(`Invio di ${results.length} record in corso...`); + + GM_xmlhttpRequest({ + method: "POST", + url: CONFIG.endpoint, + headers: { "Content-Type": "application/json" }, + data: JSON.stringify(results), + onload: function(response) { + console.log("%c OK: Dati inviati con successo.", "color: #00FF00;"); + // 3. Programma il prossimo ciclo senza ricaricare la pagina + setTimeout(eseguiCiclo, CONFIG.interval); + }, + onerror: function(err) { + console.error("Errore invio server locale. Riprovo tra 20 secondi."); + setTimeout(eseguiCiclo, CONFIG.interval); + } + }); + } else { + console.warn("Nessun dato trovato in tabella. Riprovo nel prossimo ciclo."); + setTimeout(eseguiCiclo, CONFIG.interval); + } + } + + // Avvio del primo ciclo dopo 5 secondi dal caricamento della pagina + // per darti il tempo di impostare i filtri se vuoi, + // altrimenti lo script girerà con i filtri che trova. + setTimeout(eseguiCiclo, 5000); + +})(); \ No newline at end of file diff --git a/Estrattore Tabella Portale Trasporto - Fixed.user.js b/Estrattore Tabella Portale Trasporto - Fixed.user.js new file mode 100644 index 0000000..9812667 --- /dev/null +++ b/Estrattore Tabella Portale Trasporto - Fixed.user.js @@ -0,0 +1,120 @@ +// ==UserScript== +// @name Estrattore Tabella Portale Trasporto - Fixed +// @namespace http://tampermonkey.net/ +// @version 3.2 +// @description Risolto loop infinito su tabella vuota +// @author Gemini +// @match https://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/le-mie-istanze* +// @grant GM_xmlhttpRequest +// @connect 192.168.1.33 +// ==/UserScript== + +(function() { + 'use strict'; + + const CONFIG = { + commandEndpoint: 'http://192.168.1.33/hook/dati3.php', + answerEndpoint: 'http://192.168.1.33/hook/ans3.php', + pollingInterval: 1000, + searchDelay: 1500 + }; + + function checkCommand() { + GM_xmlhttpRequest({ + method: "GET", + url: CONFIG.commandEndpoint, + headers: { "Cache-Control": "no-cache" }, + onload: function(response) { + try { + const res = JSON.parse(response.responseText); + if (res.tipo === "DATI_NRAP" && res.task === "fare") { + console.log("%c [COMANDO] Ricevuto 'fare'.", "color: #FFA500; font-weight: bold;"); + eseguiCiclo(); + } else { + setTimeout(checkCommand, CONFIG.pollingInterval); + } + } catch (e) { + setTimeout(checkCommand, CONFIG.pollingInterval); + } + }, + onerror: () => setTimeout(checkCommand, CONFIG.pollingInterval) + }); + } + + function eseguiCiclo() { + const buttons = Array.from(document.querySelectorAll('button')); + const searchButton = buttons.find(btn => btn.innerText.trim().toUpperCase() === "CERCA"); + + if (searchButton) { + console.log("[ACTION] Click Cerca..."); + searchButton.click(); + setTimeout(estraiEInvia, CONFIG.searchDelay); + } else { + console.error("[ERRORE] Tasto Cerca non trovato."); + // Resettiamo comunque per evitare loop se il tasto sparisce + impostaStatoFinale("ERRORE_BOTTONE"); + } + } + + function estraiEInvia() { + const rows = document.querySelectorAll('[role="row"]'); + const results = []; + + rows.forEach(row => { + const cells = row.querySelectorAll('[role="cell"]'); + if (cells.length >= 5) { + const idIstanza = cells[0].innerText.trim(); + if (idIstanza !== "" && idIstanza.toLowerCase() !== "identificativo istanza") { + results.push({ + identificativo: idIstanza, + data_inserimento: cells[1]?.innerText.trim(), + stato: cells[2]?.innerText.trim(), + tipologia: cells[3]?.innerText.trim(), + targa_telaio: cells[4]?.innerText.trim() + }); + } + } + }); + + if (results.length > 0) { + console.log(`[DATA] Invio ${results.length} record...`); + GM_xmlhttpRequest({ + method: "POST", + url: CONFIG.answerEndpoint, + headers: { "Content-Type": "application/json" }, + data: JSON.stringify(results), + onload: () => { + console.log("%c [SUCCESS] Dati inviati.", "color: #00FF00;"); + impostaStatoFinale("COMPLETATO"); + }, + onerror: () => setTimeout(checkCommand, CONFIG.pollingInterval) + }); + } else { + // MODIFICA CRUCIALE: Se la tabella è vuota, impostiamo comunque COMPLETATO + // per fermare il loop, indicando che non ci sono record. + console.warn("[WARN] Tabella vuota. Fermo il comando."); + impostaStatoFinale("COMPLETATO_VUOTO"); + } + } + + function impostaStatoFinale(nuovoStato) { + GM_xmlhttpRequest({ + method: "POST", + url: CONFIG.commandEndpoint, + headers: { "Content-Type": "application/json" }, + data: JSON.stringify({ + tipo: "DATI_NRAP", + task: nuovoStato, // Sarà COMPLETATO, COMPLETATO_VUOTO o ERRORE + valore1: "0", + valore2: "0", + valore3: "0" + }), + onload: function() { + console.log(`%c [STATUS] Comando chiuso con stato: ${nuovoStato}`, "color: #FFF; background: #333;"); + setTimeout(checkCommand, CONFIG.pollingInterval); + } + }); + } + + checkCommand(); +})(); \ No newline at end of file diff --git a/OTP NTFY Console (Token) (1).user.js b/OTP NTFY Console (Token) (1).user.js new file mode 100644 index 0000000..7cf5f5a --- /dev/null +++ b/OTP NTFY Console (Token) (1).user.js @@ -0,0 +1,183 @@ +// ==UserScript== +// @name OTP NTFY Console (Token) +// @namespace http://tampermonkey.net/ +// @version 2.2 +// @description Pannello OTP sicuro con Bearer Token e monitoraggio live +// @author Gemini + Gatto +// @match *://www.ilportaledellautomobilista.it/* +// @grant GM_notification +// @grant GM_setClipboard +// ==/UserScript== + +(function() { + 'use strict'; + + // --- CONFIGURAZIONE SICURA --- + const BASE_URL = "ntfy.dati-web.it"; + // <--- INCOLLA QUI IL TUO TOKEN tk_... + const NTFY_TOKEN = "tk_mh1ox5scgkorten10a7baelpehh6p"; + + let currentTopic = localStorage.getItem('otp_topic'); + let mode = localStorage.getItem('otp_mode'); + const OTP_REGEX = /(?:^|\s)(\S{8})(?=\s|$)/; + + function injectInterface() { + const logo = document.getElementById('logo-portale'); + if (!logo) { + setTimeout(injectInterface, 500); + return; + } + + const parentLink = logo.closest('a'); + const anchorPoint = parentLink ? parentLink : logo; + + if (document.getElementById('otp-embedded-panel')) return; + + const navPanel = document.createElement('div'); + navPanel.id = "otp-embedded-panel"; + + // Stile del pannello + navPanel.style = ` + display: inline-flex; + align-items: center; + gap: 4px; + margin-left: 330px; + margin-top: 16px; + padding: 0 10px; + background: #ffffff; + border: 1px dashed #0056b3; + border-radius: 6px; + vertical-align: middle; + height: 60px; + font-family: Arial, sans-serif; + box-sizing: border-box; + cursor: default; + pointer-events:auto; + position: relative; + z-index: 10; + min-width: 340px !important; + max-width: 420px !important; + box-shadow: 0 2px 5px rgba(0,0,0,0.1) !important; + line-height: normal; + color: #333 !important; +` ; + navPanel.innerHTML = ` +
+ + +
+ +
+ +
+ + +
+ +
+ +
+
---
+
STABILE
+
+ `; + + anchorPoint.parentNode.insertBefore(navPanel, anchorPoint.nextSibling); + + // Salvataggio impostazioni + document.getElementById('saveConfig').addEventListener('click', () => { + localStorage.setItem('otp_topic', document.getElementById('topicInput').value.trim()); + localStorage.setItem('otp_mode', document.querySelector('input[name="otpMode"]:checked').value); + location.reload(); + }); + + startListening(); + } + + async function startListening() { + const statusLabel = document.getElementById('statusLabel'); + + try { + const response = await fetch(`https://${BASE_URL}/${currentTopic}/json`, { + headers: { + "Authorization": `Bearer ${NTFY_TOKEN}` + } + }); + + if (response.status === 401 || response.status === 403) { + statusLabel.innerText = "ERRORE TOKEN"; + statusLabel.style.color = "red"; + return; + } + + if (!response.ok) throw new Error("Errore connessione"); + + statusLabel.innerText = "ONLINE"; + statusLabel.style.color = "#28a745"; + + const reader = response.body.getReader(); + const decoder = new TextDecoder(); + + while (true) { + const { value, done } = await reader.read(); + if (done) break; + + const chunk = decoder.decode(value); + const lines = chunk.split('\n'); + + for (const line of lines) { + if (!line.trim()) continue; + try { + const data = JSON.parse(line); + if (data.event === 'message' && data.message) { + const match = data.message.match(OTP_REGEX); + if (match) handleOTP(match[1]); + } + } catch (e) { console.error("Errore parsing JSON", e); } + } + } + } catch (err) { + statusLabel.innerText = "RE-CONNECTING..."; + statusLabel.style.color = "orange"; + setTimeout(startListening, 5000); + } + } + + function handleOTP(newOtp) { + document.getElementById('lastCodeLabel').innerText = newOtp; + GM_setClipboard(newOtp); + + // Notifica di sistema + GM_notification({ + title: "OTP Infocert", + text: `Codice: ${newOtp} (Copiato)`, + timeout: 5000 + }); + +// Se la modalità è "Digita", inserisce l'OTP nel campo attualmente selezionato (focus) +if (document.querySelector('input[name="otpMode"]:checked').value === 'type') { + const activeInput = document.activeElement; + + // Verifichiamo che l'elemento attivo sia effettivamente un campo di testo + if (activeInput && (activeInput.tagName === 'INPUT' || activeInput.tagName === 'TEXTAREA')) { + activeInput.value = newOtp; + + // Simula l'evento di input per attivare eventuali validazioni/script della pagina + activeInput.dispatchEvent(new Event('input', { bubbles: true })); + activeInput.dispatchEvent(new Event('change', { bubbles: true })); + } else { + console.warn("Nessun campo di testo selezionato al momento dell'inserimento."); + } +} + } + + if (document.readyState === "complete" || document.readyState === "interactive") { + injectInterface(); + } else { + document.addEventListener("DOMContentLoaded", injectInterface); + } +})(); \ No newline at end of file diff --git a/OTP NTFY Console (Token).user.js b/OTP NTFY Console (Token).user.js new file mode 100644 index 0000000..bb6f4ad --- /dev/null +++ b/OTP NTFY Console (Token).user.js @@ -0,0 +1,169 @@ +// ==UserScript== +// @name OTP NTFY Console (Token) +// @namespace http://tampermonkey.net/ +// @version 2.1 +// @description Pannello OTP sicuro con Bearer Token e monitoraggio live +// @author Gemini + Gatto +// @match *://www.ilportaledellautomobilista.it/* +// @grant GM_notification +// @grant GM_setClipboard +// ==/UserScript== + +(function() { + 'use strict'; + + // --- CONFIGURAZIONE SICURA --- + const BASE_URL = "ntfy.dati-web.it"; + // <--- INCOLLA QUI IL TUO TOKEN tk_... + const NTFY_TOKEN = "tk_mh1ox5scgkorten10a7baelpehh6p"; + + let currentTopic = localStorage.getItem('otp_topic') || "OTP-Gatto"; + let mode = localStorage.getItem('otp_gatto_mode') || "notify"; + const OTP_REGEX = /(?:^|\s)(\S{8})(?=\s|$)/; + + function injectInterface() { + const logo = document.getElementById('logo-portale'); + if (!logo) { + setTimeout(injectInterface, 500); + return; + } + + const parentLink = logo.closest('a'); + const anchorPoint = parentLink ? parentLink : logo; + + if (document.getElementById('otp-embedded-panel')) return; + + const navPanel = document.createElement('div'); + navPanel.id = "otp-embedded-panel"; + + // Stile del pannello + navPanel.style = ` + display: inline-flex; + align-items: center; + gap: 12px; + margin-left: 300px; + margin-top: 16px; + padding: 0 15px; + background: #f8f9fa; + border: 2px solid #0056b3; + border-radius: 8px; + height: 60px; + min-width: 320px; + font-family: 'Segoe UI', Arial, sans-serif; + box-shadow: 0 2px 5px rgba(0,0,0,0.1); + z-index: 9999; + `; + + navPanel.innerHTML = ` +
+ + +
+ +
+ +
+ + +
+ +
+ +
+
---
+
STABILE
+
+ `; + + anchorPoint.parentNode.insertBefore(navPanel, anchorPoint.nextSibling); + + // Salvataggio impostazioni + document.getElementById('saveConfig').addEventListener('click', () => { + localStorage.setItem('otp_topic', document.getElementById('topicInput').value.trim()); + localStorage.setItem('otp_gatto_mode', document.querySelector('input[name="otpMode"]:checked').value); + location.reload(); + }); + + startListening(); + } + + async function startListening() { + const statusLabel = document.getElementById('statusLabel'); + + try { + const response = await fetch(`https://${BASE_URL}/${currentTopic}/json`, { + headers: { + "Authorization": `Bearer ${NTFY_TOKEN}` + } + }); + + if (response.status === 401 || response.status === 403) { + statusLabel.innerText = "ERRORE TOKEN"; + statusLabel.style.color = "red"; + return; + } + + if (!response.ok) throw new Error("Errore connessione"); + + statusLabel.innerText = "ONLINE"; + statusLabel.style.color = "#28a745"; + + const reader = response.body.getReader(); + const decoder = new TextDecoder(); + + while (true) { + const { value, done } = await reader.read(); + if (done) break; + + const chunk = decoder.decode(value); + const lines = chunk.split('\n'); + + for (const line of lines) { + if (!line.trim()) continue; + try { + const data = JSON.parse(line); + if (data.event === 'message' && data.message) { + const match = data.message.match(OTP_REGEX); + if (match) handleOTP(match[1]); + } + } catch (e) { console.error("Errore parsing JSON", e); } + } + } + } catch (err) { + statusLabel.innerText = "RE-CONNECTING..."; + statusLabel.style.color = "orange"; + setTimeout(startListening, 5000); + } + } + + function handleOTP(newOtp) { + document.getElementById('lastCodeLabel').innerText = newOtp; + GM_setClipboard(newOtp); + + // Notifica di sistema + GM_notification({ + title: "OTP Infocert", + text: `Codice: ${newOtp} (Copiato)`, + timeout: 5000 + }); + + // Se la modalità è "Digita", prova a inserirlo nel primo campo input vuoto trovato + if (document.querySelector('input[name="otpMode"]:checked').value === 'type') { + const otpInput = document.querySelector('input[type="text"], input[maxlength="8"]'); + if (otpInput) { + otpInput.value = newOtp; + otpInput.dispatchEvent(new Event('input', { bubbles: true })); + } + } + } + + if (document.readyState === "complete" || document.readyState === "interactive") { + injectInterface(); + } else { + document.addEventListener("DOMContentLoaded", injectInterface); + } +})(); \ No newline at end of file diff --git a/OTP Portale Automobilista, Multi-Tab OK require.user.js b/OTP Portale Automobilista, Multi-Tab OK require.user.js new file mode 100644 index 0000000..2f13b12 --- /dev/null +++ b/OTP Portale Automobilista, Multi-Tab OK require.user.js @@ -0,0 +1,14 @@ +// ==UserScript== +// @name OTP Portale Automobilista, Multi-Tab OK require +// @namespace http://tampermonkey.net/ +// @version 4.4 +// @description Versione ottimizzata per evitare notifiche multiple con più schede aperte +// @author Gemini +// @match *://www.ilportaledellautomobilista.it/* +// @connect dati-web.it +// @connect umctv.altervista.org +// @require https://umctv.altervista.org/Scripts/OTP_Multi-Tab.js +// @grant GM_xmlhttpRequest +// @grant GM_notification +// @grant GM_setClipboard +// ==/UserScript== \ No newline at end of file diff --git a/OTP Portale Automobilista, Multi-Tab OK require.user.js-2d2741c2671aeb7b4ea66d0374401b49-OTP_Multi-Tab.js b/OTP Portale Automobilista, Multi-Tab OK require.user.js-2d2741c2671aeb7b4ea66d0374401b49-OTP_Multi-Tab.js new file mode 100644 index 0000000..6463f5c --- /dev/null +++ b/OTP Portale Automobilista, Multi-Tab OK require.user.js-2d2741c2671aeb7b4ea66d0374401b49-OTP_Multi-Tab.js @@ -0,0 +1,158 @@ +(function() { + 'use strict'; + + const API_URL = "https://umctv.altervista.org/hook/OTP.php"; + const POLLING_RATE = 8000; + + function injectInterface() { + const logo = document.getElementById('logo-portale'); + if (!logo) { + setTimeout(injectInterface, 500); + return; + } + + const parentLink = logo.closest('a'); + const anchorPoint = parentLink ? parentLink : logo; + + if (document.getElementById('otp-embedded-panel')) return; + + const navPanel = document.createElement('div'); + navPanel.id = "otp-embedded-panel"; + navPanel.style = ` + display: inline-flex; + align-items: center; + gap: 6px; + margin-left: 300px; + margin-top: 25px; + padding: 0 10px; + background: #ffffff; + border: 1px dashed #0056b3; + border-radius: 4px; + vertical-align: middle; + height: 56px; + font-family: Arial, sans-serif; + box-sizing: border-box; + cursor: default; + pointer-events: auto; + position: relative; + z-index: 10; + `; + + navPanel.innerHTML = ` +
OTP
LOG
+ +
+ + +
+
+
+
---
+
In ascolto
+
+ `; + + anchorPoint.parentNode.insertBefore(navPanel, anchorPoint.nextSibling); + startMonitoring(); + } + + function startMonitoring() { + const authInput = document.getElementById('authCode'); + const statusLabel = document.getElementById('statusLabel'); + const lastCodeLabel = document.getElementById('lastCodeLabel'); + + authInput.value = localStorage.getItem('otp_secret_vault') || ""; + + // Carichiamo l'ultimo OTP dal localStorage (condiviso tra tab) + let lastOtp = localStorage.getItem('last_detected_otp') || ""; + if (lastOtp) { + lastCodeLabel.innerText = lastOtp; + } + + function checkOTP() { + const secret = localStorage.getItem('otp_secret_vault'); + if (!secret || secret.length <= 4) { + statusLabel.innerText = "Inactive(NoSecret)"; + statusLabel.style.color = "#f0ad4e"; + return; + } + + GM_xmlhttpRequest({ + method: "GET", + url: `${API_URL}?codice=${encodeURIComponent(secret)}`, + timeout: 4000, + onload: function(response) { + try { + const data = JSON.parse(response.responseText); + const match = data.sms.match(/\d{8}/); + + if (match) { + const currentOtp = match[0]; + + // Controllo critico: leggiamo il valore aggiornato globalmente + const globalLastOtp = localStorage.getItem('last_detected_otp'); + + if (currentOtp !== globalLastOtp) { + // Questa tab ha rilevato il nuovo codice per prima! + localStorage.setItem('last_detected_otp', currentOtp); + + lastCodeLabel.innerText = currentOtp; + GM_setClipboard(currentOtp); + statusLabel.innerText = "Copiato!"; + statusLabel.style.color = "#007bff"; + + GM_notification({ + title: "OTP Ricevuto!", + text: `codice ${currentOtp} copiato negli appunti.`, + timeout: 3000 + }); + + setTimeout(() => { + statusLabel.innerText = "In ascolto"; + statusLabel.style.color = "#28a745"; + }, 4000); + } + } + } catch (e) {} + } + }); + } + + // Listener per aggiornare l'interfaccia se un'altra tab riceve l'OTP + window.addEventListener('storage', (e) => { + if (e.key === 'last_detected_otp' && e.newValue) { + lastCodeLabel.innerText = e.newValue; + statusLabel.innerText = "Aggiornato"; + setTimeout(() => { + statusLabel.innerText = "In ascolto"; + }, 2000); + } + }); + + document.getElementById('saveBtn').addEventListener('click', (e) => { + e.preventDefault(); e.stopPropagation(); + localStorage.setItem('otp_secret_vault', authInput.value); + statusLabel.innerText = "Salvato!"; + setTimeout(() => { statusLabel.innerText = "In ascolto"; }, 1500); + }); + + document.getElementById('resetBtn').addEventListener('click', (e) => { + e.preventDefault(); e.stopPropagation(); + localStorage.removeItem('otp_secret_vault'); + localStorage.removeItem('last_detected_otp'); + authInput.value = ""; + lastCodeLabel.innerText = "---"; + statusLabel.innerText = "Reset"; + statusLabel.style.color = "#dc3545"; + }); + + setInterval(checkOTP, POLLING_RATE); + checkOTP(); + } + + if (document.readyState === "complete" || document.readyState === "interactive") { + injectInterface(); + } else { + document.addEventListener("DOMContentLoaded", injectInterface); + } +})(); \ No newline at end of file diff --git a/Portaledeltrasporto - Full Automation + PDF Download.user.js b/Portaledeltrasporto - Full Automation + PDF Download.user.js new file mode 100644 index 0000000..f15fe78 --- /dev/null +++ b/Portaledeltrasporto - Full Automation + PDF Download.user.js @@ -0,0 +1,104 @@ +// ==UserScript== +// @name Portaledeltrasporto - Full Automation + PDF Download +// @namespace http://tampermonkey.net/ +// @version 3.0 +// @description Ricerca, Procedi e Download automatico PDF rinominati col Telaio +// @author Tu +// @match *://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/* +// @grant none +// @run-at document-end +// ==/UserScript== + +(function() { + 'use strict'; + + const TELAIO = 'VR3UPHNE7R5039330'; + let downloadEseguiti = false; // Per evitare loop di download infiniti + + function clickReactSafe(element) { + if (!element) return; + const opts = { bubbles: true, cancelable: true, view: window }; + element.dispatchEvent(new MouseEvent('mousedown', opts)); + element.dispatchEvent(new MouseEvent('mouseup', opts)); + element.click(); + } + + function setInputReactSafe(input, value) { + const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set; + input.focus(); + setter.call(input, value); + input.dispatchEvent(new Event('input', { bubbles: true })); + input.dispatchEvent(new Event('change', { bubbles: true })); + input.blur(); + } + + function gestisciDownload() { + if (downloadEseguiti) return; + + // Cerchiamo i link che hanno l'icona download (spesso sono dentro bottoni o link con svg) + const righeTabella = document.querySelectorAll('tr'); + let count = 0; + + righeTabella.forEach((riga) => { + const link = riga.querySelector('a, button[class*="download"]'); + if (link && (link.href || link.onclick || riga.querySelector('svg'))) { + count++; + downloadEseguiti = true; + + setTimeout(() => { + // Prendiamo il nome del documento dalla prima colonna della riga + const descrizioneDoc = riga.cells[0]?.innerText.trim().replace(/[/\\?%*:|"<>]/g, '-') || 'Documento'; + const nomeFile = `${TELAIO}_${descrizioneDoc}.pdf`; + + console.log(`[TM] Scarico: ${nomeFile}`); + + // Se è un link diretto ( con href) + if (link.href && link.href !== 'javascript:void(0)') { + const a = document.createElement('a'); + a.href = link.href; + a.download = nomeFile; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + } else { + // Se è un bottone React/Angular che genera il file al volo + clickReactSafe(link); + } + }, count * 1200); // Ritardo progressivo di 1.2s per ogni file + } + }); + } + + function eseguiAutomazione() { + const url = window.location.href; + + // FASE 1: RICERCA + if (url.includes('le-mie-istanze')) { + const input = document.getElementById('numeroTelaio'); + const btnCerca = Array.from(document.querySelectorAll('button')).find(b => b.textContent.includes('Cerca')); + const btnTabella = document.querySelector('button.action-button-table'); + + if (input && input.value !== TELAIO) { + setInputReactSafe(input, TELAIO); + setTimeout(() => { if(btnCerca) clickReactSafe(btnCerca); }, 500); + } + if (btnTabella) clickReactSafe(btnTabella); + } + + // FASE 2: PROCEDI + if (url.includes('/abilitazione/') && !url.includes('dettaglio-istanza')) { + const btnProcedi = Array.from(document.querySelectorAll('button')).find(b => b.textContent.trim() === 'Procedi'); + if (btnProcedi && !btnProcedi.disabled) clickReactSafe(btnProcedi); + } + + // FASE 3: DOWNLOAD NELLA PAGINA DETTAGLIO + if (url.includes('dettaglio-istanza')) { + gestisciDownload(); + } + } + + const observer = new MutationObserver(() => eseguiAutomazione()); + observer.observe(document.body, { childList: true, subtree: true }); + + setTimeout(eseguiAutomazione, 1000); +})(); \ No newline at end of file diff --git a/Portaledeltrasporto CON MOD AL DOWNLOAD WORKING2- Full Automation v3.3.user.js b/Portaledeltrasporto CON MOD AL DOWNLOAD WORKING2- Full Automation v3.3.user.js new file mode 100644 index 0000000..ed5a458 --- /dev/null +++ b/Portaledeltrasporto CON MOD AL DOWNLOAD WORKING2- Full Automation v3.3.user.js @@ -0,0 +1,392 @@ +// ==UserScript== +// @name Portaledeltrasporto CON MOD AL DOWNLOAD WORKING2- Full Automation v3.3 +// @namespace http://tampermonkey.net/ +// @version 3.5 +// @description Fix MouseEvent + Remote Hook Integration +// @author Tu +// @match *://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/* +// @grant GM_xmlhttpRequest +// @connect 192.168.1.33 +// @run-at document-end +// ==/UserScript== + +(function() { + 'use strict'; + + let TELAIO = ''; + let VALORE2 = '0'; + let taskAttivo = false; + let downloadInCorso = false; + let completatoLocalmente = false; // Flag per evitare loop dopo il completamento + const ENDPOINT_GET = 'http://192.168.1.33/hook/dati2.php'; + + function fetchDati_veryold() { + GM_xmlhttpRequest({ + method: "GET", + url: ENDPOINT_GET, + onload: function(response) { + try { + const data = JSON.parse(response.responseText); + if (data.tipo === 'DOC_NRAP' && data.task === 'fare') { + // Se è un nuovo telaio, resettiamo il flag di completamento + if (TELAIO !== data.valore1) { + TELAIO = data.valore1; + VALORE2 = data.valore2; + completatoLocalmente = false; + console.log(`[TM] Nuovo task ricevuto per telaio: ${TELAIO}`); + } + + if (!completatoLocalmente) { + taskAttivo = true; + eseguiAutomazione(); + } + } else { + taskAttivo = false; + completatoLocalmente = false; + } + } catch (e) { + console.error("[TM] Errore parsing dati", e); + } + } + }); + } + + function fetchDati_old() { + GM_xmlhttpRequest({ + method: "GET", + url: ENDPOINT_GET, + onload: function(response) { + try { + const data = JSON.parse(response.responseText); + if (data.tipo === 'DOC_NRAP' && data.task === 'fare') { + + // --- LOGICA DI REINDIRIZZAMENTO --- + const targetUrl = 'https://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/le-mie-istanze'; + if (!window.location.href.includes('le-mie-istanze') && + !window.location.href.includes('dettaglio-istanza') && + !window.location.href.includes('/abilitazione/')) { + + console.log("[TM] Nuovo task rilevato, vado alla pagina di ricerca..."); + window.location.href = targetUrl; + return; // Interrompiamo l'esecuzione qui, la pagina cambierà + } + // ---------------------------------- + + if (TELAIO !== data.valore1) { + TELAIO = data.valore1; + VALORE2 = data.valore2; + completatoLocalmente = false; + console.log(`[TM] Nuovo task ricevuto per telaio: ${TELAIO}`); + } + + if (!completatoLocalmente) { + taskAttivo = true; + eseguiAutomazione(); + } + } else { + taskAttivo = false; + completatoLocalmente = false; + } + } catch (e) { + console.error("[TM] Errore parsing dati", e); + } + } + }); + } + + function fetchDati() { + GM_xmlhttpRequest({ + method: "GET", + url: ENDPOINT_GET, + onload: function(response) { + try { + const data = JSON.parse(response.responseText); + const targetHome = 'https://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/le-mie-istanze'; + + // --- LOGICA DI RESET SPECIFICA --- + // if (data.task === 'reset') { + if (data.tipo === 'RESET_NRAP') { + console.log("[TM] Ricevuto comando RESET. Ritorno alla home e pulizia variabili."); + TELAIO = ''; + VALORE2 = '0'; + completatoLocalmente = false; + taskAttivo = false; + + // Se non siamo già in home, ci spostiamo + if (window.location.href !== targetHome) { + window.location.href = targetHome; + } + return; // Esce dalla funzione, non esegue altro + } + // --------------------------------- + + if (data.tipo === 'DOC_NRAP' && data.task === 'fare') { + // Se il telaio cambia mentre siamo operativi, forziamo il redirect + if (TELAIO !== '' && TELAIO !== data.valore1) { + console.log(`[TM] Cambio telaio rilevato (${TELAIO} -> ${data.valore1}). Redirect.`); + TELAIO = data.valore1; + window.location.href = targetHome; + return; + } + + // Aggiornamento dati task + if (TELAIO !== data.valore1) { + TELAIO = data.valore1; + VALORE2 = data.valore2; + completatoLocalmente = false; + } + + if (!completatoLocalmente) { + taskAttivo = true; + eseguiAutomazione(); + } + } else { + taskAttivo = false; + completatoLocalmente = false; + } + } catch (e) { + console.error("[TM] Errore parsing dati", e); + } + } + }); + } + + function segnaComeCompletato_old() { + completatoLocalmente = true; + taskAttivo = false; + GM_xmlhttpRequest({ + method: "POST", + url: ENDPOINT_GET, + data: JSON.stringify({ task: "completato", valore1: TELAIO }), + headers: { "Content-Type": "application/json" }, + onload: function() { + console.log("[TM] Server aggiornato: task completato."); + downloadInCorso = false; + } + }); + } + + function segnaComeCompletato() { + completatoLocalmente = true; + taskAttivo = false; + + // Prepariamo l'oggetto completo con i valori aggiornati + const payload = { + tipo: "DOC_NRAP", + task: "completato", // Unica variabile che cambia davvero + valore1: TELAIO, + valore2: VALORE2, + valore3: "0" + }; + + GM_xmlhttpRequest({ + method: "POST", + url: ENDPOINT_GET, + data: JSON.stringify(payload), + headers: { "Content-Type": "application/json" }, + onload: function(response) { + console.log("[TM] Server aggiornato con tutti i campi. Task: completato."); + downloadInCorso = false; + }, + onerror: function(err) { + console.error("[TM] Errore nell'invio dei dati al server", err); + } + }); + } + + // FIX: Funzione click corretta per evitare l'errore 'view' member + function clickReactSafe_OLD(element) { + if (!element) return; + const opts = { bubbles: true, cancelable: true, view: window.unsafeWindow || window }; + + // Se il costruttore standard fallisce, usiamo il metodo più compatibile + try { + element.dispatchEvent(new MouseEvent('mousedown', opts)); + element.dispatchEvent(new MouseEvent('mouseup', opts)); + element.click(); + } catch (e) { + // Fallback per browser restrittivi + element.dispatchEvent(new Event('mousedown', { bubbles: true })); + element.dispatchEvent(new Event('mouseup', { bubbles: true })); + element.click(); + } + } + + function clickReactSafe(element) { + // Se l'elemento non esiste, esci silenziosamente senza generare errori + if (!element || typeof element.dispatchEvent !== 'function') { + console.warn("[TM] Tentativo di click su un elemento non valido o non trovato."); + return; + } + + const opts = { bubbles: true, cancelable: true, view: window.unsafeWindow || window }; + + try { + element.dispatchEvent(new MouseEvent('mousedown', opts)); + element.dispatchEvent(new MouseEvent('mouseup', opts)); + element.click(); + } catch (e) { + element.dispatchEvent(new Event('mousedown', { bubbles: true })); + element.dispatchEvent(new Event('mouseup', { bubbles: true })); + element.click(); + } +} + + function setInputReactSafe(input, value) { + if (!input) return; + const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set; + input.focus(); + setter.call(input, value); + input.dispatchEvent(new Event('input', { bubbles: true })); + input.dispatchEvent(new Event('change', { bubbles: true })); + } + + function avviaDownloadDocumenti() { + if (downloadInCorso) return; + + const tuttiIBottoni = Array.from(document.querySelectorAll('button.DocumentsSection__file-btn')); + if (tuttiIBottoni.length === 0) return; + + downloadInCorso = true; + const titoliGiaVisti = new Set(); + let delayDoc = 0; + + tuttiIBottoni.forEach((btn, index, array) => { + const riga = btn.closest('tr'); + const titolo = riga ? riga.innerText.trim().split('\t')[0] : btn.innerText.trim(); + + if (!titoliGiaVisti.has(titolo)) { + titoliGiaVisti.add(titolo); + + setTimeout(() => { + console.log(`[TM] 1. Avvio Download: ${titolo}`); + clickReactSafe(btn); + + // --- SEQUENZA MODALE --- + + // STEP A: Click Esporta File (dopo 1.2 secondi) + setTimeout(() => { + //const btnEsporta = Array.from(document.querySelectorAll('button.btn-primary.btn-xs')) + const btnEsporta = Array.from(document.querySelectorAll('button.btn-primary.btn-xs')); + //.find(b => b.textContent.includes('Esporta File')); + + if (btnEsporta) { + console.log(`[TM] 2. Click Esporta File per: ${titolo}`); + clickReactSafe(btnEsporta); + } + + // STEP B: Click Chiudi Modale (dopo altri 1.5 secondi dal click esporta) + setTimeout(() => { + const btnChiudiModale = document.querySelector('button.ModalContent__header--btn'); + if (btnChiudiModale) { + console.log(`[TM] 3. Chiusura modale per: ${titolo}`); + clickReactSafe(btnChiudiModale); + } + }, 1500); + + }, 1200); + // ----------------------- + + // Se è l'ultimo documento + if (index === array.length - 1) { + setTimeout(segnaComeCompletato, 5000); // Aumentato a 5s per sicurezza + } + }, delayDoc); + + // Aumentiamo il delay totale tra un file e l'altro a 5 secondi + // per coprire l'intera sequenza (Download -> Esporta -> Chiudi) + delayDoc += 3000; + } + }); + } + + function avviaDownloadDocumenti_old() { + if (downloadInCorso) return; + + const tuttiIBottoni = Array.from(document.querySelectorAll('button.DocumentsSection__file-btn')); + if (tuttiIBottoni.length === 0) return; + + downloadInCorso = true; + const titoliGiaVisti = new Set(); + let delayDoc = 0; + + tuttiIBottoni.forEach((btn, index, array) => { + const riga = btn.closest('tr'); + const titolo = riga ? riga.innerText.trim().split('\t')[0] : btn.innerText.trim(); + + if (!titoliGiaVisti.has(titolo)) { + titoliGiaVisti.add(titolo); + + setTimeout(() => { + console.log(`[TM] Download: ${titolo}`); + clickReactSafe(btn); + + // --- NUOVA LOGICA CHIUSURA MODALE --- + setTimeout(() => { + const btnChiudiModale = document.querySelector('button.ModalContent__header--btn'); + if (btnChiudiModale) { + console.log(`[TM] Chiusura modale per: ${titolo}`); + clickReactSafe(btnChiudiModale); + } + }, 1000); // Aspetta 1 secondo dopo il click di download + // ------------------------------------ + + // Se è l'ultimo documento unico trovato + if (index === array.length - 1) { + setTimeout(segnaComeCompletato, 1500); + } + }, delayDoc); + + // Ho aumentato leggermente il delay tra un file e l'altro (3.5s invece di 2.5s) + // per dare tempo alla modale di aprirsi, restare aperta 1s e chiudersi. + delayDoc += 1500; + } + }); + } + + function eseguiAutomazione() { + if (!taskAttivo || completatoLocalmente) return; + + const url = window.location.href; + + // FASE 1: RICERCA + if (url.includes('le-mie-istanze')) { + const input = document.getElementById('numeroTelaio'); + const btnCerca = Array.from(document.querySelectorAll('button')).find(b => b.textContent.includes('Cerca')); + const btnTabella = document.querySelector('button.action-button-table'); + + if (input && TELAIO !== '' && input.value !== TELAIO) { + setInputReactSafe(input, TELAIO); + setTimeout(() => { if(btnCerca) clickReactSafe(btnCerca); }, 800); + } + if (btnTabella) setTimeout(() => clickReactSafe(btnTabella), 1500); + } + + // FASE 2: PROCEDI + if (url.includes('/abilitazione/') && !url.includes('dettaglio-istanza')) { + const btnProcedi = Array.from(document.querySelectorAll('button')).find(b => b.textContent.trim() === 'Procedi'); + if (btnProcedi && !btnProcedi.disabled) setTimeout(() => clickReactSafe(btnProcedi), 1000); + } + + // FASE 3: DOWNLOAD + if (url.includes('dettaglio-istanza')) { + if (parseInt(VALORE2) > 0) { + if (document.querySelector('button.DocumentsSection__file-btn')) { + avviaDownloadDocumenti(); + } + } else { + console.log("[TM] Valore2 <= 1, chiusura task senza download."); + segnaComeCompletato(); + } + } + } + + const observer = new MutationObserver(() => { + if (taskAttivo) eseguiAutomazione(); + }); + observer.observe(document.body, { childList: true, subtree: true }); + + // Polling ogni 4 secondi + setInterval(fetchDati, 2500); + fetchDati(); +})(); \ No newline at end of file diff --git a/Portaledeltrasporto WORKING - Full Automation (SPA Fix).user.js b/Portaledeltrasporto WORKING - Full Automation (SPA Fix).user.js new file mode 100644 index 0000000..f7d12c1 --- /dev/null +++ b/Portaledeltrasporto WORKING - Full Automation (SPA Fix).user.js @@ -0,0 +1,86 @@ +// ==UserScript== +// @name Portaledeltrasporto WORKING - Full Automation (SPA Fix) +// @namespace http://tampermonkey.net/ +// @version 2.5 +// @description Automazione completa dalla ricerca al tasto Procedi, ottimizzata per React/SPA. +// @author Tu +// @match *://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/* +// @grant none +// @run-at document-end +// ==/UserScript== + +(function() { + 'use strict'; + + const TELAIO = 'VR3UPHNE7R5039330'; + + // Funzione universale per cliccare in modo che React se ne accorga + function clickReactSafe(element) { + if (!element) return; + console.log('[TM] Clicco elemento:', element.textContent.trim() || 'Bottone Azione'); + + const opts = { bubbles: true, cancelable: true, view: window }; + element.dispatchEvent(new MouseEvent('mousedown', opts)); + element.dispatchEvent(new MouseEvent('mouseup', opts)); + element.click(); + } + + function setInputReactSafe(input, value) { + const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set; + input.focus(); + setter.call(input, value); + input.dispatchEvent(new Event('input', { bubbles: true })); + input.dispatchEvent(new Event('change', { bubbles: true })); + input.blur(); + } + + // LOGICA PRINCIPALE + function eseguiAutomazione() { + const url = window.location.href; + + // --- FASE 1: RICERCA --- + if (url.includes('le-mie-istanze')) { + const input = document.getElementById('numeroTelaio'); + const btnCerca = Array.from(document.querySelectorAll('button')).find(b => b.textContent.includes('Cerca')); + const btnTabella = document.querySelector('button.action-button-table'); + + // Se c'è l'input e non è ancora stato scritto il telaio + if (input && input.value !== TELAIO) { + setInputReactSafe(input, TELAIO); + console.log('[TM] Telaio inserito'); + setTimeout(() => { if(btnCerca) clickReactSafe(btnCerca); }, 500); + } + + // Se appare il bottone nella tabella, cliccalo + if (btnTabella) { + clickReactSafe(btnTabella); + } + } + + // --- FASE 2: PROCEDI --- + if (url.includes('/abilitazione/')) { + const btnProcedi = Array.from(document.querySelectorAll('button')) + .find(b => b.textContent.trim() === 'Procedi'); + + if (btnProcedi && !btnProcedi.disabled) { + clickReactSafe(btnProcedi); + } + } + } + + // IL SEGRETO PER LE SPA: Osserva i cambiamenti del DOM + // Invece di refreshare, lo script si accorge se appaiono nuovi pezzi di pagina + const observer = new MutationObserver(() => { + eseguiAutomazione(); + }); + + observer.observe(document.body, { + childList: true, + subtree: true + }); + + // Primo avvio + setTimeout(eseguiAutomazione, 1000); + + console.log('[TM] Monitoraggio SPA attivo...'); +})(); \ No newline at end of file diff --git a/Portaledeltrasporto WORKING2- Full Automation v3.2.user.js b/Portaledeltrasporto WORKING2- Full Automation v3.2.user.js new file mode 100644 index 0000000..a1bd6ef --- /dev/null +++ b/Portaledeltrasporto WORKING2- Full Automation v3.2.user.js @@ -0,0 +1,104 @@ +// ==UserScript== +// @name Portaledeltrasporto WORKING2- Full Automation v3.2 +// @namespace http://tampermonkey.net/ +// @version 3.2 +// @description Automazione completa con filtro duplicati e selettore classe documenti +// @author Tu +// @match *://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/* +// @grant none +// @run-at document-end +// ==/UserScript== + +(function() { + 'use strict'; + + const TELAIO = 'VF1RJB00675897644'; + let downloadInCorso = false; + + function clickReactSafe(element) { + if (!element) return; + const opts = { bubbles: true, cancelable: true, view: window }; + element.dispatchEvent(new MouseEvent('mousedown', opts)); + element.dispatchEvent(new MouseEvent('mouseup', opts)); + element.click(); + } + + function setInputReactSafe(input, value) { + const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set; + input.focus(); + setter.call(input, value); + input.dispatchEvent(new Event('input', { bubbles: true })); + input.dispatchEvent(new Event('change', { bubbles: true })); + } + + function avviaDownloadDocumenti() { + if (downloadInCorso) return; + + // Seleziona i bottoni con la classe specifica indicata + const tuttiIBottoni = Array.from(document.querySelectorAll('button.DocumentsSection__file-btn')); + + if (tuttiIBottoni.length === 0) return; + + downloadInCorso = true; + const titoliGiaVisti = new Set(); + let delayDoc = 0; + + console.log(`[TM] Analisi documenti per classe DocumentsSection__file-btn...`); + + tuttiIBottoni.forEach((btn) => { + // Risaliamo alla riga o al contenitore per leggere il testo descrittivo + // Solitamente il testo è nel primo elemento della riga (td) o in un elemento precedente + const riga = btn.closest('tr'); + const titolo = riga ? riga.innerText.trim().split('\t')[0] : btn.innerText.trim(); + + if (!titoliGiaVisti.has(titolo)) { + titoliGiaVisti.add(titolo); + + setTimeout(() => { + console.log(`[TM] Scaricamento unico: ${titolo}`); + clickReactSafe(btn); + }, delayDoc); + + delayDoc += 2500; // 2.5 secondi tra un download e l'altro + } else { + console.log(`[TM] Salto duplicato: ${titolo}`); + } + }); + } + + function eseguiAutomazione() { + const url = window.location.href; + + // FASE 1: RICERCA + if (url.includes('le-mie-istanze')) { + const input = document.getElementById('numeroTelaio'); + const btnCerca = Array.from(document.querySelectorAll('button')).find(b => b.textContent.includes('Cerca')); + const btnTabella = document.querySelector('button.action-button-table'); + + if (input && input.value !== TELAIO) { + setInputReactSafe(input, TELAIO); + setTimeout(() => { if(btnCerca) clickReactSafe(btnCerca); }, 800); + } + if (btnTabella) setTimeout(() => clickReactSafe(btnTabella), 1200); + } + + // FASE 2: PROCEDI + if (url.includes('/abilitazione/') && !url.includes('dettaglio-istanza')) { + const btnProcedi = Array.from(document.querySelectorAll('button')).find(b => b.textContent.trim() === 'Procedi'); + if (btnProcedi && !btnProcedi.disabled) setTimeout(() => clickReactSafe(btnProcedi), 1000); + } + + // FASE 3: DOWNLOAD (Dettaglio) + if (url.includes('dettaglio-istanza')) { + // Verifichiamo che i bottoni siano effettivamente presenti nel DOM + if (document.querySelector('button.DocumentsSection__file-btn')) { + avviaDownloadDocumenti(); + } + } + } + + const observer = new MutationObserver(() => eseguiAutomazione()); + observer.observe(document.body, { childList: true, subtree: true }); + + setTimeout(eseguiAutomazione, 2000); +})(); \ No newline at end of file diff --git a/Pulsante NRAP Convalida - Footer.user.js b/Pulsante NRAP Convalida - Footer.user.js new file mode 100644 index 0000000..26430a2 --- /dev/null +++ b/Pulsante NRAP Convalida - Footer.user.js @@ -0,0 +1,91 @@ +// ==UserScript== +// @name Pulsante NRAP Convalida - Footer +// @namespace http://tampermonkey.net/ +// @version 1.0 +// @description Inserisce il pulsante "Convalida" nell'header blu, allineato a destra +// @author Gemini+Gatto. +// @match *://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/* +// @grant none +// ==/UserScript== + +(function() { + 'use strict'; + + function injectButtonInHeader() { + // 1. Cerchiamo l'header blu (HeaderComponent) + const header = document.querySelector('header.HeaderComponent'); + + // 2. Cerchiamo il pulsante originale nel footer per sapere se dobbiamo mostrare il nostro + const allButtons = document.querySelectorAll('footer button, .FooterNavComponent button'); + let originalBtn = null; + for (let btn of allButtons) { + if (btn.textContent.toLowerCase().includes('convalida')) { + originalBtn = btn; + break; + } + } + + const existingBtn = document.querySelector('#quick-convalida-header'); + + // Se non c'è il tasto originale nel footer, nascondiamo il nostro + if (!originalBtn) { + if (existingBtn) existingBtn.style.display = 'none'; + return; + } + + // 3. Se l'header esiste e il tasto non c'è ancora, lo creiamo + if (header && !existingBtn) { + // Rendiamo l'header "relative" per poter posizionare il tasto "absolute" dentro di esso + header.style.position = 'relative'; + + const btn = document.createElement('button'); + btn.id = 'quick-convalida-header'; + btn.innerHTML = '✅ CONVALIDA DOCUMENTAZIONE'; + + // STILE: Posizionato a destra, dentro la zona blu + btn.style.cssText = ` + position: absolute; + right: 56px; /* Distanza dal bordo destro */ + top: 78%; /* Centratura verticale rispetto all'header */ + transform: translateY(-50%); + padding: 8px 20px; + background-color: #28a745; /* Verde che stacca sul blu */ + color: white; + border: 1px solid #ffffff; + border-radius: 4px; + font-size: 14px; + font-weight: bold; + cursor: pointer; + z-index: 9999; + box-shadow: 0 2px 5px rgba(0,0,0,0.2); + white-space: nowrap; + `; + + // Azione al click + btn.onclick = function(e) { + e.preventDefault(); + // Ricerchiamo il tasto originale "fresco" nel footer + const target = Array.from(document.querySelectorAll('footer button')) + .find(b => b.textContent.toLowerCase().includes('convalida')); + if (target) { + console.log("Tampermonkey: Clicco Convalida originale..."); + target.click(); + } else { + alert("Pulsante originale non trovato nel footer!"); + } + }; + + header.appendChild(btn); + } else if (existingBtn) { + // Se esiste già, assicuriamoci che sia visibile + existingBtn.style.display = 'block'; + } + } + + // Monitoraggio continuo per gestire i cambi pagina di React + const observer = new MutationObserver(injectButtonInHeader); + observer.observe(document.body, { childList: true, subtree: true }); + + setInterval(injectButtonInHeader, 1000); + injectButtonInHeader(); +})(); \ No newline at end of file diff --git a/Riempimento Automatico Telaio - Portale Trasporto.user.js b/Riempimento Automatico Telaio - Portale Trasporto.user.js new file mode 100644 index 0000000..0ac02d8 --- /dev/null +++ b/Riempimento Automatico Telaio - Portale Trasporto.user.js @@ -0,0 +1,44 @@ +// ==UserScript== +// @name Riempimento Automatico Telaio - Portale Trasporto +// @namespace http://tampermonkey.net/ +// @version 1.3 +// @description Inserimento automatico del numero telaio con gestione metadata avanzata +// @author Tu +// @match https://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/* +// @icon https://www.google.com/s2/favicons?sz=64&domain=ilportaledeltrasporto.it +// @grant none +// @run-at document-end +// @noframes +// ==/UserScript== + +(function() { + 'use strict'; + + function inserisciTelaio() { + const inputTelaio = document.getElementById('numeroTelaio'); + + if (inputTelaio) { + alert("✅ Campo trovato! Ora provo a inserire il valore."); + // Mettiamo il focus sul campo (simula il click dell'utente) + //inputTelaio.focus(); + + // Inseriamo il valore + inputTelaio.value = 'WAUZZZFU8SN090884'; + + // Eventi necessari per far capire ai framework moderni (Angular/React) che il valore è cambiato + // inputTelaio.dispatchEvent(new Event('input', { bubbles: true })); + // inputTelaio.dispatchEvent(new Event('change', { bubbles: true })); + + // Togliamo il focus + // inputTelaio.blur(); + + console.log("Metadata applicati e Telaio inserito."); + } else { + // Riprova se il caricamento della SPA è lento + setTimeout(inserisciTelaio, 500); + } + } + + // Avvio della logica + inserisciTelaio(); +})(); \ No newline at end of file diff --git a/Riempimento Telaio LE MIE ISTANZE - Focus Avanzato.user.js b/Riempimento Telaio LE MIE ISTANZE - Focus Avanzato.user.js new file mode 100644 index 0000000..be49aaf --- /dev/null +++ b/Riempimento Telaio LE MIE ISTANZE - Focus Avanzato.user.js @@ -0,0 +1,44 @@ +// ==UserScript== +// @name Riempimento Telaio LE MIE ISTANZE - Focus Avanzato +// @namespace http://tampermonkey.net/ +// @version 1.5 +// @description Inserisce il telaio simulando l'interazione mouse/tastiera +// @author Tu +// @match https://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/le-mie-istanze* +// @grant none +// @run-at document-end +// @noframes +// ==/UserScript== + +(function() { + 'use strict'; + + function inserisciConFocus() { + const input = document.getElementById('numeroTelaio'); + + if (input) { + // 1. Simula il click del mouse per attivare i listener del sito (data-focus-mouse) + input.dispatchEvent(new MouseEvent('mousedown', { bubbles: true })); + input.dispatchEvent(new MouseEvent('mouseup', { bubbles: true })); + input.click(); + input.focus(); + + // 2. Inserisce il valore + input.value = 'WAUZZZFU8SN090884'; + + // 3. Simula la digitazione per i framework (Angular/React/Vue) + input.dispatchEvent(new Event('input', { bubbles: true })); + input.dispatchEvent(new Event('change', { bubbles: true })); + + // 4. Simula l'uscita dal campo (spesso abilita il tasto Cerca) + input.dispatchEvent(new Event('blur', { bubbles: true })); + + console.log("Inserimento completato con simulazione focus."); + } else { + setTimeout(inserisciConFocus, 1000); + } + } + + // Un piccolo ritardo iniziale per lasciare che il sito carichi i suoi script + setTimeout(inserisciConFocus, 1500); +})(); \ No newline at end of file diff --git a/Robot WORKING Portale - FIX CONNESSIONE.user.js b/Robot WORKING Portale - FIX CONNESSIONE.user.js new file mode 100644 index 0000000..e4038ed --- /dev/null +++ b/Robot WORKING Portale - FIX CONNESSIONE.user.js @@ -0,0 +1,117 @@ +// ==UserScript== +// @name Robot WORKING Portale - FIX CONNESSIONE +// @namespace http://tampermonkey.net/ +// @description Inserimento, Estrazione Tabella e invio a PHP per Firebird +// @version 3.3 +// @match *://www.ilportaledellautomobilista.it/immatricolazioni/* +// @grant GM_xmlhttpRequest +// @connect 192.168.1.33 +// ==/UserScript== + +(function() { + 'use strict'; + + const ENDPOINT_GET = "http://192.168.1.33/hook/dati4.php"; + const ENDPOINT_POST = "http://192.168.1.33/hook/ans4.php"; + const TARGET_HOME = "https://www.ilportaledellautomobilista.it/immatricolazioni/certificatoConformitaDatiTecniciVE/Read_initAction.action?pageStatus=SEARCH"; + + let completatoLocalmente = false; + + console.log("[TM] Inizio monitoraggio..."); + + const clean = (val) => (val === "." || !val) ? "" : val.toString().trim(); + + function fetchDati() { + if (completatoLocalmente) return; + + GM_xmlhttpRequest({ + method: "GET", + url: ENDPOINT_GET, + nocache: true, + onload: function(response) { + try { + const data = JSON.parse(response.responseText); + + if (data.tipo === 'DATI_COC' && data.task === 'fare') { + // CONTROLLO FONDAMENTALE: C'è la tabella risultati? + const tabella = document.getElementById('listTable'); + + if (tabella) { + // Se c'è la tabella, estraiamo e chiudiamo il task sul DB + completatoLocalmente = true; + estraiESalva(data.valore1); + } + else if (window.location.href.includes("pageStatus=SEARCH") || window.location.href.endsWith("Read_initAction.action")) { + // Se siamo nel form e NON c'è ancora la tabella, compiliamo e clicchiamo + inserisciDati(data); + } + } + } catch (e) { console.error("Errore JSON", e); } + } + }); + } + + function inserisciDati(d) { + // Evitiamo click multipli se abbiamo già cliccato in questa sessione + if (window.alreadyClicked) return; + + console.log("[TM] Compilazione form..."); + const mappa = { + "VEFrom.descrizioneFamigliaVeicolo": d.valore1, + "VEFrom.descrizioneVarianteVeicolo": d.valore2, + "VE.codiceOmologazioneEuropea": d.valore3, + "VE.codiceMarchioVeicolo": d.valore4, + "progressivoCostruttoreVeicolo": d.valore5 + }; + + let trovato = false; + Object.keys(mappa).forEach(key => { + let input = document.querySelector(`input[name*="${key}"]`); + if (input) { + input.value = clean(mappa[key]); + trovato = true; + } + }); + + if (trovato) { + const btn = document.getElementById('RicercaCertificatoConformitaDatiTecniciVE_button_value_searchElement'); + if (btn) { + console.log("[TM] Click Ricerca!"); + window.alreadyClicked = true; + btn.click(); + } + } + } + + function estraiESalva(v1) { + console.log("[TM] Tabella trovata. Invio dati al DB..."); + const rows = document.querySelectorAll('#listTable tbody tr'); + let risultati = []; + + rows.forEach(row => { + const celle = Array.from(row.querySelectorAll('td')) + .filter(td => !td.querySelector('input[type="radio"]')) + .map(td => td.innerText.trim()); + if (celle.length > 0) risultati.push(celle); + }); + + GM_xmlhttpRequest({ + method: "POST", + url: ENDPOINT_POST, + headers: { "Content-Type": "application/json" }, + data: JSON.stringify({ + tipo: "SALVATAGGIO_DB", + task: "COMPLETATO", + riferimento: v1, + tabella_dati: risultati + }), + onload: function() { + console.log("[TM] Task inviato al server. Torno alla Home."); + // Aspettiamo 2 secondi per sicurezza prima di tornare alla home + setTimeout(() => { window.location.href = TARGET_HOME; }, 2000); + } + }); + } + + setInterval(fetchDati, 3000); +})(); \ No newline at end of file