adicionado correções ao app colab

This commit is contained in:
Eder Moraes 2026-04-27 02:12:42 -03:00
parent 99b34b2871
commit d12f38fbaf
3 changed files with 131 additions and 99 deletions

212
main.js
View File

@ -100,7 +100,7 @@ async function fetchDataFromAPI() {
//! as outras é o websockt que solicita a chamada de requisições em busca de alterações //! as outras é o websockt que solicita a chamada de requisições em busca de alterações
const updData = setInterval(() => { const updData = setInterval(() => {
getDataAndUpdateFloatingBtn(); getDataAndUpdateFloatingBtn();
}, 3000); }, 30000);
const updVersion = setTimeout(() => { const updVersion = setTimeout(() => {
if (pjson.isBuildNow) { if (pjson.isBuildNow) {
@ -110,68 +110,80 @@ async function fetchDataFromAPI() {
} }
async function getFirstData() { async function getFirstData() {
const token = await getAuthToken(); const token = await getAuthToken();
const colabId = await floatingWin.webContents.executeJavaScript("localStorage.getItem('idOperator')") const colabId = await getSelectedOperatorId();
const tenantId = await getTenantId(); const tenantId = await getTenantId();
const url = apiUrl + 'attendance/next-in-line/' + colabId; const url = apiUrl + 'attendance/next-in-line/' + colabId;
//! checa se o token e o colabId existem if (!token || !colabId) {
if (!token && !colabId) { console.warn("Token or colabId not found in localStorage. API requests will not be made."); return; } console.warn("Token or colabId not found. Skipping API request.");
return [];
}
//! faz o request return new Promise((resolve) => {
const request = net.request({ const request = net.request({
method: 'GET', method: 'GET',
url: url, url: url,
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token, 'Authorization': 'Bearer ' + token,
'x-tenant-id': tenantId 'x-tenant-id': tenantId
}
});
//! busca pela resposta
request.on('response', (response) => {
let rawData = '';
response.on('data', (chunk) => { rawData += chunk; });
response.on('end', () => {
try {
const parsedData = JSON.parse(rawData);
let proximos = Array.isArray(parsedData) ? parsedData : [];
if (response.statusCode === 200) {
floatingWin.webContents.executeJavaScript("localStorage.setItem('proximos','" + JSON.stringify(proximos) + "')");
let count = proximos.length;
floatingWin.webContents.send('update-count', count);
} else {
console.error(`Erro na requisição: Status code ${response.statusCode}`, parsedData);
}
} catch (error) {
console.error("Erro ao analisar a resposta JSON:", error);
mainWin.webContents.send('api-error', {
message: `Erro ao processar resposta do servidor.`
});
} }
}); });
});
request.on('error', (error) => {
console.error("Erro na requisição:", error);
});
request.end(); request.on('response', (response) => {
let rawData = '';
response.on('data', (chunk) => { rawData += chunk; });
response.on('end', async () => {
try {
const parsedData = JSON.parse(rawData);
let proximos = Array.isArray(parsedData) ? parsedData : [];
if (response.statusCode === 200) {
const proximosStr = JSON.stringify(proximos);
// Sincroniza o localStorage de todas as janelas importantes
const updateStorageScript = `localStorage.setItem('proximos', ${JSON.stringify(proximosStr)})`;
if (floatingWin && !floatingWin.isDestroyed()) {
floatingWin.webContents.executeJavaScript(updateStorageScript);
floatingWin.webContents.send('update-count', proximos.length);
}
// SÓ atualiza a janela principal se NÃO houver atendimento em andamento
floatingWin.webContents.executeJavaScript("localStorage.getItem('atendimentoAtual')").then(atendimentoAtualId => {
if (!atendimentoAtualId && mainWin && !mainWin.isDestroyed()) {
mainWin.webContents.executeJavaScript(updateStorageScript);
mainWin.webContents.send('load-data', proximos);
}
resolve(proximos);
}).catch(err => {
console.error("Erro ao verificar atendimento atual:", err);
resolve(proximos);
});
} else {
console.error(`Erro API: ${response.statusCode}`);
resolve([]);
}
} catch (error) {
console.error("Erro JSON:", error);
resolve([]);
}
});
});
return JSON.parse(await floatingWin.webContents.executeJavaScript("localStorage.getItem('proximos')")); request.on('error', (error) => {
console.error("Erro rede:", error);
resolve([]);
});
request.end();
});
} }
// Função para coletar a lista de atendimentos do servidor, vai ser chamada uma vez e a cada 30s // Atualiza a função de monitoramento para realmente buscar dados a cada 30s (ou o que desejar)
async function getDataAndUpdateFloatingBtn() { async function getDataAndUpdateFloatingBtn() {
await getFirstData();
const stored = await floatingWin.webContents.executeJavaScript("localStorage.getItem('proximos')");
const proximos = JSON.parse(stored || '[]');
let count = proximos.length;
//lista a contagem no botão flutuante
floatingWin.webContents.send('update-count', count);
} }
// Função para verificar se o token existe no localStorage // Função para verificar se o token existe no localStorage
@ -503,9 +515,12 @@ async function getSelectedOperatorId() {
} }
ipcMain.handle('get-pusher-config', async () => { ipcMain.handle('get-pusher-config', async () => {
// Obtenha sua chave e host de forma segura aqui (ambiente, .env, etc.) // Garante que o host não termine com barra para o Socket.io
const PUSHER_HOST = process.env.PUSHER_HOST || pusherUrl; let host = pusherUrl;
return { host: PUSHER_HOST }; if (host && host.endsWith('/')) {
host = host.slice(0, -1);
}
return { host: host };
}); });
ipcMain.on('update_version', async (event, arg) => { ipcMain.on('update_version', async (event, arg) => {
@ -532,8 +547,13 @@ ipcMain.handle('get-count', async () => {
return data.length; return data.length;
}); });
let isCallingNext = false;
// Ouvir pedido para mostrar a janela principal // Ouvir pedido para mostrar a janela principal
ipcMain.on('chamar-fila', async () => { ipcMain.on('chamar-fila', async () => {
// Evita múltiplas chamadas simultâneas
if (isCallingNext) return;
isCallingNext = true;
// Primeiro, verifica se já existe um atendimento em andamento // Primeiro, verifica se já existe um atendimento em andamento
const atendimentoAtualId = await floatingWin.webContents.executeJavaScript("localStorage.getItem('atendimentoAtual')"); const atendimentoAtualId = await floatingWin.webContents.executeJavaScript("localStorage.getItem('atendimentoAtual')");
@ -556,21 +576,13 @@ ipcMain.on('chamar-fila', async () => {
} }
// Se um atendimento já estiver em andamento, apenas mostra a janela principal. // Se um atendimento já estiver em andamento, apenas mostra a janela principal.
// A lógica em renderer.js cuidará de exibir a tela de observação.
if (atendimentoAtualId) { if (atendimentoAtualId) {
showMainWindow(); showMainWindow();
return; // Interrompe a execução aqui isCallingNext = false;
} return;
// Se não houver atendimento em andamento, continua com a lógica original.
const countFila = async () => {
const stored = await floatingWin.webContents.executeJavaScript("localStorage.getItem('proximos')");
const proximos = JSON.parse(stored || '[]');
return proximos.length;
} }
const requestData = async () => { const requestData = async () => {
const colabId = await getSelectedOperatorId(); const colabId = await getSelectedOperatorId();
const token = await getAuthToken(); const token = await getAuthToken();
const tenantId = await getTenantId(); const tenantId = await getTenantId();
@ -588,36 +600,33 @@ ipcMain.on('chamar-fila', async () => {
request.on('response', (response) => { request.on('response', (response) => {
let rawData = ''; let rawData = '';
response.on('data', (chunk) => { rawData += chunk; });
response.on('data', (chunk) => {
rawData += chunk;
});
response.on('end', () => { response.on('end', () => {
isCallingNext = false;
try { try {
const parsedData = JSON.parse(rawData); const parsedData = JSON.parse(rawData);
if (response.statusCode === 201 || response.statusCode === 200) { if (response.statusCode === 201 || response.statusCode === 200) {
if (parsedData) { if (parsedData) {
mainWin.webContents.send('select-atend-id', parsedData); mainWin.webContents.send('select-atend-id', parsedData);
if (parsedData.status === 'Fila' || parsedData.status === 'Chamado') { showMainWindow(); } else if (parsedData.status === 'Fila' || parsedData.status === 'Chamado') {
if (parsedData.status === 'Atendendo') { showMainWindow();
let options2 = { } else if (parsedData.status === 'Atendendo') {
'title': 'Precisa finalizar antes de chamar o próximo.', let options2 = {
'message': 'Em andamento', 'title': 'Precisa finalizar antes de chamar o próximo.',
'detail': 'Já possui um atendimento em andamento (Atendendo: ' + parsedData.clientName + '), continue e finalize por favor!', 'message': 'Em andamento',
'type': 'error', 'detail': 'Já possui um atendimento em andamento (Atendendo: ' + parsedData.clientName + '), continue e finalize por favor!',
'noLink': true, 'type': 'error',
'buttons': ['Depois', 'Continuar'], 'buttons': ['Depois', 'Continuar'],
};
dialog.showMessageBox(floatingWin, options2).then(result => {
if (result.response) {
mainWin.webContents.send('show-observation');
showMainWindow();
} else {
mainWin.hide();
}; };
dialog.showMessageBox(floatingWin, options2).then(result => { });
if (result.response) { }
mainWin.webContents.send('show-observation');
showMainWindow();
} else {
mainWin.hide();
};
});
}
} else { } else {
mainWin.webContents.send('select-atend-id', null); mainWin.webContents.send('select-atend-id', null);
} }
@ -637,6 +646,7 @@ ipcMain.on('chamar-fila', async () => {
}); });
request.on('error', (error) => { request.on('error', (error) => {
isCallingNext = false;
console.error("Erro na requisição:", error); console.error("Erro na requisição:", error);
mainWin.webContents.send('api-error', { mainWin.webContents.send('api-error', {
message: `Erro ao chamar atendimento: ${error.message}` message: `Erro ao chamar atendimento: ${error.message}`
@ -646,7 +656,11 @@ ipcMain.on('chamar-fila', async () => {
request.end(); request.end();
}; };
const countFilaValue = async () => {
const stored = await floatingWin.webContents.executeJavaScript("localStorage.getItem('proximos')");
const proximos = JSON.parse(stored || '[]');
return proximos.length;
}
let options = { let options = {
'title': 'Incie o atendimento quando o cliente chegar na sala.', 'title': 'Incie o atendimento quando o cliente chegar na sala.',
@ -656,17 +670,20 @@ ipcMain.on('chamar-fila', async () => {
'buttons': ['Não', 'Sim'], 'buttons': ['Não', 'Sim'],
}; };
const count = await countFilaValue();
if (await countFila()) { if (count > 0) {
dialog.showMessageBox(floatingWin, options).then(result => { dialog.showMessageBox(floatingWin, options).then(result => {
if (result.response) { if (result.response === 1) { // 1 é 'Sim'
requestData(); requestData();
}; } else {
isCallingNext = false;
}
}); });
} else { } else {
requestData(); // Se a fila estiver vazia, apenas abre a janela principal para visualização
showMainWindow();
isCallingNext = false;
} }
}); });
// Ouve um pedido da janela flutuante para forçar a atualização da contagem // Ouve um pedido da janela flutuante para forçar a atualização da contagem
@ -730,6 +747,13 @@ ipcMain.on('atendimento-finalizado', () => {
} }
}); });
// Ouve atualização da fila vinda do renderer (via socket)
ipcMain.on('update-queue', (event, data) => {
// Sempre busca dados frescos da API quando o socket notifica mudança,
// pois o socket pode enviar apenas o objeto da mudança e não a lista completa.
getFirstData();
});
// Ouvir clique no botão "Salvar" // Ouvir clique no botão "Salvar"
ipcMain.on('save-observation', async (event, { itemId, observation }) => { ipcMain.on('save-observation', async (event, { itemId, observation }) => {

View File

@ -18,6 +18,9 @@ contextBridge.exposeInMainWorld('electronAPI', {
atendimentoIniciado: (itemId) => ipcRenderer.send('atendimento-iniciado', itemId), atendimentoIniciado: (itemId) => ipcRenderer.send('atendimento-iniciado', itemId),
atendimentoFinalizado: () => ipcRenderer.send('atendimento-finalizado'), atendimentoFinalizado: () => ipcRenderer.send('atendimento-finalizado'),
//notifica o main process sobre atualização na fila vinda do socket
updateQueue: (data) => ipcRenderer.send('update-queue', data),
showObservation: (callback) => ipcRenderer.on('show-observation', (_event) => callback() ), showObservation: (callback) => ipcRenderer.on('show-observation', (_event) => callback() ),
//salva a observação do atendimento //salva a observação do atendimento
saveObservation: (data) => ipcRenderer.send('save-observation', data), saveObservation: (data) => ipcRenderer.send('save-observation', data),

View File

@ -17,12 +17,15 @@ let selectedItemId = null;
let selectedItemName = ''; let selectedItemName = '';
window.electronAPI.onLoadData((data) => { window.electronAPI.onLoadData((data) => {
// Se já estiver em atendimento, ignora atualizações da lista para evitar flickering no botão
if (localStorage.getItem('atendimentoAtual')) {
return;
}
nextButton.disabled = true; nextButton.disabled = true;
if (!data) { if (!data) {
return; return;
} }
// Reseta a view para a lista sempre que os dados são carregados populateList(data);
populateList(data[0]);
}); });
async function initializeSocket() { async function initializeSocket() {
@ -51,9 +54,10 @@ async function initializeSocket() {
// Evento que substitui o bind do Pusher // Evento que substitui o bind do Pusher
socket.on('queueUpdate', (data) => { socket.on('queueUpdate', (data) => {
console.log('Atualização de fila recebida:', data); console.log('Notificação de fila recebida:', data);
localStorage.setItem('proximos', JSON.stringify(data)); // Avisa o processo principal que houve mudança.
populateList(data); // O main vai buscar a lista completa e atualizar todas as janelas.
window.electronAPI.updateQueue();
}); });
socket.on('error', (err) => { socket.on('error', (err) => {
@ -182,6 +186,7 @@ nextButton.addEventListener('click', () => {
localStorage.setItem('atendimentoAtualNome', selectedItemName); localStorage.setItem('atendimentoAtualNome', selectedItemName);
// Notifica o main process e muda a view // Notifica o main process e muda a view
// IMPORTANTE: iniciaAtendimento deve apenas mudar o status na API, não chamar o próximo.
window.electronAPI.atendimentoIniciado(selectedItemId); window.electronAPI.atendimentoIniciado(selectedItemId);
window.electronAPI.iniciaAtendimento(selectedItemId); window.electronAPI.iniciaAtendimento(selectedItemId);
showObservationView(); // Muda para a tela de observação showObservationView(); // Muda para a tela de observação