From 99b34b2871d881b9f2bfdf8e2f4a791e46f8fff1 Mon Sep 17 00:00:00 2001 From: Eder Moraes <54563944+edermcastro@users.noreply.github.com> Date: Mon, 27 Apr 2026 00:02:22 -0300 Subject: [PATCH] =?UTF-8?q?corre=C3=A7=C3=B5es=20na=20tela=20de=20login=20?= =?UTF-8?q?colab?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 2 +- login.html | 6 ++-- main.js | 93 ++++++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 76 insertions(+), 25 deletions(-) diff --git a/index.html b/index.html index 0d5edff..19f4d2d 100644 --- a/index.html +++ b/index.html @@ -7,7 +7,7 @@ default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; - connect-src 'self' ws://localhost:3000 http://localhost:3000; + connect-src 'self' ws://localhost:3000 http://localhost:3000 ws://autoatends.linco.work wss://autoatends.linco.work; "> Tela de Atendimento diff --git a/login.html b/login.html index 1fb3558..abc7fd7 100644 --- a/login.html +++ b/login.html @@ -34,14 +34,14 @@ //o campo username deve ser formatado como cpf ou cnpj function formatarCampoCPFCNPJ() { var campo = document.getElementById('username'); - var valor = campo.value.replace(/\D/g, ''); // Remove todos os caracteres não numéricos + var valor = campo.value.replace(/[^a-zA-Z0-9]/g, ''); // Remove apenas o que não for alfanumérico if (valor.length <= 11) { // Formata como CPF - valor = valor.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, '$1.$2.$3-$4'); + valor = valor.replace(/([a-zA-Z0-9]{3})([a-zA-Z0-9]{3})([a-zA-Z0-9]{3})([a-zA-Z0-9]{2})/, '$1.$2.$3-$4'); } else { // Formata como CNPJ - valor = valor.replace(/(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/, '$1.$2.$3/$4-$5'); + valor = valor.replace(/([a-zA-Z0-9]{2})([a-zA-Z0-9]{3})([a-zA-Z0-9]{3})([a-zA-Z0-9]{4})([a-zA-Z0-9]{2})/, '$1.$2.$3/$4-$5'); } campo.value = valor; } diff --git a/main.js b/main.js index 4ca51e0..59d8a74 100644 --- a/main.js +++ b/main.js @@ -15,10 +15,10 @@ let updateWin; const dataPath = path.join(__dirname, 'data.json'); // Caminho para o JSON (backup local) const settingsPath = path.join(app.getPath('userData'), 'settings.json'); // Caminho para as configurações -//! API -const apiUrl = 'http://localhost:3000/api/'; // Adaptado para NestJS +//! api +const apiUrl = 'https://aapi.linco.work/'; //! pusher -const pusherUrl = 'http://localhost:3000'; // Agora aponta para o Socket.io (NestJS) +const pusherUrl = apiUrl; autoUpdater.autoDownload = false; autoUpdater.autoInstallOnAppQuit = true; @@ -113,7 +113,7 @@ async function getFirstData() { const token = await getAuthToken(); const colabId = await floatingWin.webContents.executeJavaScript("localStorage.getItem('idOperator')") - const tenantId = await floatingWin.webContents.executeJavaScript("localStorage.getItem('tenantId')") + const tenantId = await getTenantId(); const url = apiUrl + 'attendance/next-in-line/' + colabId; //! checa se o token e o colabId existem @@ -199,6 +199,29 @@ async function getAuthToken() { }); } +// Função para verificar o tenantId no localStorage +async function getTenantId() { + const checkWindow = async (win) => { + if (win && !win.isDestroyed()) { + try { + const val = await win.webContents.executeJavaScript('localStorage.getItem("tenantId");'); + return (val && val !== 'null' && val !== 'undefined') ? val : null; + } catch (e) { + return null; + } + } + return null; + }; + + // Prioridade para janelas visíveis + let id = await checkWindow(operatorWin); + if (!id) id = await checkWindow(mainWin); + if (!id) id = await checkWindow(floatingWin); + if (!id) id = await checkWindow(loginWin); + + return id; +} + // Função para criar a janela de login function createLoginWindow() { loginWin = new BrowserWindow({ @@ -550,7 +573,7 @@ ipcMain.on('chamar-fila', async () => { const colabId = await getSelectedOperatorId(); const token = await getAuthToken(); - const tenantId = await floatingWin.webContents.executeJavaScript("localStorage.getItem('tenantId')") + const tenantId = await getTenantId(); const url = apiUrl + 'attendance/call-next/' + colabId; const request = net.request({ @@ -664,7 +687,7 @@ ipcMain.on('select-atend-id', (itemId) => { ipcMain.on('iniciar-atendimento', async (event, itemId) => { const token = await getAuthToken(); - const tenantId = await floatingWin.webContents.executeJavaScript("localStorage.getItem('tenantId')") + const tenantId = await getTenantId(); const url = apiUrl + 'attendance/' + itemId + '/start'; // envio de uma solicitação POST com o ID do item @@ -713,7 +736,7 @@ ipcMain.on('save-observation', async (event, { itemId, observation }) => { console.log(`Salvando observação para item ${itemId}: ${observation}`); const token = await getAuthToken(); - const tenantId = await floatingWin.webContents.executeJavaScript("localStorage.getItem('tenantId')") + const tenantId = await getTenantId(); const url = apiUrl + 'attendance/' + itemId + '/finish'; const fmData = JSON.stringify({ @@ -761,7 +784,6 @@ ipcMain.on('logout', () => { localStorage.removeItem("selectedOperator"); localStorage.removeItem("salaOperator"); localStorage.removeItem("servicosOperator"); - localStorage.removeItem("tenantId"); `).then(() => { // Fecha a janela main e abre a janela de operador e inicia o aplicativo mainWin.hide(); @@ -796,10 +818,15 @@ ipcMain.on('login-attempt', async (event, credentials) => { const data = JSON.parse(responseData); if (data.access_token) { + // Tenta encontrar o tenantId em diferentes locais possíveis da resposta + const tenantId = data.tenantId || (data.user && data.user.tenantId) || (data.user && data.user.tenant_id); + + console.log(`Login bem-sucedido. Token presente. TenantId encontrado: ${tenantId}`); + // Login bem-sucedido loginWin.webContents.executeJavaScript(` localStorage.setItem("authToken", "${data.access_token}"); - localStorage.setItem("tenantId", "${data.user.tenantId}"); + localStorage.setItem("tenantId", "${tenantId || ''}"); `).then(() => { // Fecha a janela de login e abre a de seleção de operador event.reply('login-response', { success: true }); @@ -830,8 +857,11 @@ ipcMain.on('login-attempt', async (event, credentials) => { }); }); + // Remove máscara do login (CPF/CNPJ) antes de enviar para a API + const cleanLogin = credentials.login.replace(/[.\-\/]/g, ''); + // Envia as credenciais - request.write(JSON.stringify({ login: credentials.login, password: credentials.password })); + request.write(JSON.stringify({ login: cleanLogin, password: credentials.password })); request.end(); } catch (error) { event.reply('login-response', { @@ -870,6 +900,9 @@ ipcMain.handle('get-operators', async () => { try { // Verifica se existe token de autenticação const token = await getAuthToken(); + const tenantId = await getTenantId(); + + console.log(`Buscando operadores - TenantId: ${tenantId}, Token presente: ${!!token}`); if (!token) { return { @@ -881,26 +914,44 @@ ipcMain.handle('get-operators', async () => { const route = apiUrl + 'collaborators'; - return new Promise((resolve, reject) => { + return new Promise((resolve) => { + const headers = { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}` + }; + + // Garante que o tenantId é uma string válida e não "null" ou "undefined" + if (tenantId && tenantId !== 'null' && tenantId !== 'undefined') { + headers['x-tenant-id'] = tenantId; + } + const request = net.request({ method: 'GET', url: route, - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${token}` - } + headers: headers }); let responseData = ''; request.on('response', (response) => { + let body = ''; response.on('data', (chunk) => { - responseData += chunk.toString(); + body += chunk.toString(); }); response.on('end', () => { + if (response.statusCode !== 200) { + console.error(`Erro na API (${response.statusCode}):`, body); + resolve({ + success: false, + message: `Erro ${response.statusCode}: ${body}`, + operators: [] + }); + return; + } + try { - const data = JSON.parse(responseData); + const data = JSON.parse(body); if (Array.isArray(data)) { const operators = data.map(colab => ({ @@ -915,14 +966,14 @@ ipcMain.handle('get-operators', async () => { operators: operators }); } else { - reject({ + resolve({ success: false, - message: 'Erro ao obter a lista de colaboradores', + message: 'Resposta da API não é uma lista válida', operators: [] }); } } catch (error) { - reject({ + resolve({ success: false, message: 'Erro ao processar resposta do servidor', operators: [] @@ -932,7 +983,7 @@ ipcMain.handle('get-operators', async () => { }); request.on('error', (error) => { - reject({ + resolve({ success: false, message: `Erro de conexão: ${error.message}`, operators: []