FEAT: Adiciona registro de consultas em um banco de dados.

This commit is contained in:
tulioperdigao 2025-10-23 15:23:22 -03:00
parent bb1b9912d9
commit 79d2117dc9
7 changed files with 255 additions and 44 deletions

6
.env
View File

@ -3,3 +3,9 @@ API_URL="https://plutao.geogridmaps.com.br/vale/api/v3/viabilidade/raio"
API_KEY="6d717e972ba17c7cf0ab731801b8bbeac2f281e5"
COOKIE="PHPSESSID=6d717e972ba17c7cf0ab731801b8bbeac2f281e5"
PORT="3000"
DATABASE_HOST = 'crash.sothistelecom.com'
DATABASE_PORT = '3306'
DATABASE_NAME = 'viabilidade_data'
DATABASE_USER = 'sothis.viabilidade'
DATABASE_USER_PASSWORD = '4Hn&i$fs71hMoJwy'

81
app.js
View File

@ -8,6 +8,7 @@ const cors = require("cors");
const { fetchJson } = require("./services/jsonService");
const { getMinDistance } = require("./services/distanceService");
const { geocodeWithGoogle } = require("./services/geocodeService");
const { insertConsultaData } = require("./models/databaseModel");
function createApp() {
const app = express();
@ -49,47 +50,47 @@ function createApp() {
const lat = Number(geo.lat);
const lon = Number(geo.lon);
const result = await getMinDistance(lat, lon);
if (result && result.dist !== undefined) {
// preciso criar 2 campos: Link Dedicado e Link Não Dedicado em que o dedicado é viável até 1000m e o não dedicado até 500m
if (result.dist <= 500) {
return res.json({
endereco,
latitude: lat,
longitude: lon,
distancia: result.dist,
dedicado: "Viável",
naoDedicado: "Viável",
});
} else if (result.dist <= 1000) {
return res.json({
endereco,
latitude: lat,
longitude: lon,
distancia: result.dist,
dedicado: "Viável",
naoDedicado: "Não viável",
});
} else {
return res.json({
endereco,
latitude: lat,
longitude: lon,
distancia: result.dist,
dedicado: "Não viável",
naoDedicado: "Não viável",
});
}
// determinar valores de retorno padrão
let distancia = null;
let dedicado = "Não viável";
let naoDedicado = "Não viável";
if (result && result.dist !== undefined && result.dist !== null) {
distancia = result.dist;
// preciso criar 2 campos: Link Dedicado e Link Não Dedicado em que o dedicado é viável até 1000m e o não dedicado até 500m
if (distancia <= 500) {
dedicado = "Viável";
naoDedicado = "Viável";
} else if (distancia <= 1000) {
dedicado = "Viável";
naoDedicado = "Não viável";
} else {
dedicado = "Não viável";
naoDedicado = "Não viável";
}
// quando a consulta não retorna um resultado válido, responder como 'Não viável'
// isso evita que a UI fique presa em "Consultando..." esperando uma resposta
return res.json({
endereco,
latitude: lat,
longitude: lon,
distancia: null,
dedicado: "Não viável",
naoDedicado: "Não viável",
});
} else {
dedicado = "Não viável";
naoDedicado = "Não viável";
}
const response = {
endereco,
latitude: lat,
longitude: lon,
distancia,
dedicado,
naoDedicado,
};
// Inserção no banco: usar fire-and-forget para não atrasar a resposta ao usuário.
// Se preferir garantir que a gravação ocorreu antes de responder, troque a chamada abaixo por:
// await insertConsultaData(cep, uf, cidade, bairro, logradouro);
insertConsultaData(cep, uf, cidade, bairro, logradouro, dedicado, naoDedicado)
.then(() => console.info(`[INFO] Consulta salva para CEP ${cep}`))
.catch((err) => console.error(`[ERROR] Falha ao salvar consulta para CEP ${cep}:`, err));
return res.json(response);
} catch (err) {
console.error(err);
return res.status(500).json({ error: "erro na consulta" });

24
config/databaseConfig.js Normal file
View File

@ -0,0 +1,24 @@
const dotenv = require("dotenv");
dotenv.config();
const mysql = require("mysql2/promise");
const pool = mysql.createPool({
host: process.env.DATABASE_HOST,
port: process.env.DATABASE_PORT,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_USER_PASSWORD,
database: process.env.DATABASE_NAME,
});
pool.getConnection().then((connection) => {
console.info(
"[INFO] Conexão com o banco de dados estabelecida com sucesso."
);
connection.release();
}).catch((error) => {
console.error("[ERROR] Falha ao conectar ao banco de dados:", error);
});
module.exports = pool;

51
models/databaseModel.js Normal file
View File

@ -0,0 +1,51 @@
const pool = require("../config/databaseConfig");
async function insertConsultaData(cep, estado, cidade, bairro, logradouro, dedicado, naoDedicado) {
const query = `INSERT INTO consultas (cep, estado, cidade, bairro, logradouro, dedicado, nao_dedicado, data_consulta) VALUES (?, ?, ?, ?, ?, ?, ?, NOW())`;
const values = [cep, estado, cidade, bairro, logradouro, dedicado, naoDedicado];
try {
// Executa a query de inserção e retornar se foi inserido com sucesso e o id da coluna id_consulta
const [result] = await pool.execute(query, values);
if (result.affectedRows === 1) {
const id = await getConsultaId();
console.info(
`[INFO] Dados de consulta inseridos com sucesso. ID: ${id}`
);
return;
}
} catch (error) {
console.error("[ERROR] Falha ao inserir dados de consulta:", error);
throw error;
}
}
async function getConsultaId() {
const query = `SELECT LAST_INSERT_ID() AS id_consulta`;
try {
const [rows] = await pool.execute(query);
return rows[0].id_consulta;
} catch (error) {
console.error("[ERROR] Falha ao buscar ID da última consulta:", error);
throw error;
}
}
async function getConsultaData(id) {
const query = `SELECT * FROM consultas WHERE id_consulta = ?`;
const values = [id];
try {
const [rows] = await pool.execute(query, values);
return rows[0];
} catch (error) {
console.error("[ERROR] Falha ao buscar dados de consulta:", error);
throw error;
}
}
module.exports = {
insertConsultaData,
getConsultaData
};

128
package-lock.json generated
View File

@ -16,7 +16,8 @@
"express": "^4.18.2",
"fast-csv": "^4.3.6",
"ipaddr.js": "^2.2.0",
"multer": "*"
"multer": "*",
"mysql2": "^3.15.3"
}
},
"node_modules/@fast-csv/format": {
@ -94,6 +95,15 @@
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/aws-ssl-profiles": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
"integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==",
"license": "MIT",
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/axios": {
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
@ -274,6 +284,15 @@
"node": ">=0.4.0"
}
},
"node_modules/denque": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.10"
}
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@ -514,6 +533,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/generate-function": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
"integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
"license": "MIT",
"dependencies": {
"is-property": "^1.0.2"
}
},
"node_modules/generator-function": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.0.tgz",
@ -646,6 +674,12 @@
"node": ">= 10"
}
},
"node_modules/is-property": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
"integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
"license": "MIT"
},
"node_modules/lodash.escaperegexp": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz",
@ -687,6 +721,36 @@
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
"integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ=="
},
"node_modules/long": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
"integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
"license": "Apache-2.0"
},
"node_modules/lru-cache": {
"version": "7.18.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
"integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/lru.min": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.2.tgz",
"integrity": "sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg==",
"license": "MIT",
"engines": {
"bun": ">=1.0.0",
"deno": ">=1.30.0",
"node": ">=8.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wellwelwel"
}
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@ -790,6 +854,54 @@
"node": ">= 10.16.0"
}
},
"node_modules/mysql2": {
"version": "3.15.3",
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.15.3.tgz",
"integrity": "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==",
"license": "MIT",
"dependencies": {
"aws-ssl-profiles": "^1.1.1",
"denque": "^2.1.0",
"generate-function": "^2.3.1",
"iconv-lite": "^0.7.0",
"long": "^5.2.1",
"lru.min": "^1.0.0",
"named-placeholders": "^1.1.3",
"seq-queue": "^0.0.5",
"sqlstring": "^2.3.2"
},
"engines": {
"node": ">= 8.0"
}
},
"node_modules/mysql2/node_modules/iconv-lite": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
"integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/named-placeholders": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz",
"integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==",
"license": "MIT",
"dependencies": {
"lru-cache": "^7.14.1"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
@ -975,6 +1087,11 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/seq-queue": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz",
"integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="
},
"node_modules/serve-static": {
"version": "1.16.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
@ -1062,6 +1179,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/sqlstring": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz",
"integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",

View File

@ -17,6 +17,7 @@
"express": "^4.18.2",
"fast-csv": "^4.3.6",
"ipaddr.js": "^2.2.0",
"multer": "*"
"multer": "*",
"mysql2": "^3.15.3"
}
}

View File

@ -9,7 +9,7 @@ document.getElementById('btnConsultaCep').addEventListener('click', async () =>
try {
const resp = await fetch(`/consulta-cep?cep=${encodeURIComponent(cep)}&numero=${encodeURIComponent(numero)}`);
const data = await resp.json();
if (data.distancia) {
if (data && data.endereco !== undefined) {
// colocar o card-results__container (resultados) com display block
endereco.innerHTML = `<strong>Endereço:</strong> ${data.endereco}.`;
resultados.style.display = 'block';
@ -38,6 +38,8 @@ document.getElementById('btnConsultaCep').addEventListener('click', async () =>
}
} else if (data.error) {
endereco.innerText = 'Erro: ' + data.error;
} else {
endereco.innerText = 'Erro na consulta';
}
} catch (e) {
endereco.innerText = 'Erro na consulta';