adicionado correções ao app colab
This commit is contained in:
parent
99b34b2871
commit
d12f38fbaf
212
main.js
212
main.js
|
|
@ -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 : [];
|
||||||
|
|
||||||
return JSON.parse(await floatingWin.webContents.executeJavaScript("localStorage.getItem('proximos')"));
|
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([]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
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 }) => {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
15
renderer.js
15
renderer.js
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue