Compare commits

...

2 Commits
1.1.2 ... main

8 changed files with 265 additions and 139 deletions

View File

@ -3,6 +3,11 @@ const countSpan = document.getElementById('count');
// Atualiza a contagem e a cor do botão quando recebe do main process
window.electronAPI.onUpdateCount((value) => {
// Se estiver em atendimento, ignora qualquer atualização de contagem
if (floatButton.classList.contains('em-atendimento')) {
return;
}
countSpan.innerHTML = value ?? 0;
// Verifica a contagem para mudar a cor
if (value > 0) {
@ -12,6 +17,40 @@ window.electronAPI.onUpdateCount((value) => {
}
});
// Altera a cor do botão com base no status do atendimento
window.electronAPI.onAtendimentoStatusChanged((status) => {
if (status === 'iniciado') {
const nomeAtendimento = localStorage.getItem('atendimentoAtualNome');
floatButton.classList.remove('has-items');
floatButton.classList.add('em-atendimento');
countSpan.innerHTML = '-'; // Mostra o hífen
if (nomeAtendimento) {
floatButton.setAttribute('title', `Atendendo: ${nomeAtendimento}`);
}
} else { // 'finalizado'
floatButton.classList.remove('em-atendimento');
floatButton.setAttribute('title', 'Chamar próximo da fila');
// Solicita uma atualização imediata da contagem para refletir o estado atual da fila
window.electronAPI.refreshCount();
}
});
// Ao carregar, verifica se já existe um atendimento em andamento
document.addEventListener('DOMContentLoaded', () => {
const atendimentoAtual = localStorage.getItem('atendimentoAtual');
if (atendimentoAtual) {
const nomeAtendimento = localStorage.getItem('atendimentoAtualNome');
floatButton.classList.remove('has-items');
floatButton.classList.add('em-atendimento');
countSpan.innerHTML = '-'; // Mostra o hífen
if (nomeAtendimento) {
floatButton.setAttribute('title', `Atendendo: ${nomeAtendimento}`);
}
} else {
floatButton.setAttribute('title', 'Chamar próximo da fila');
}
});
// Mostra a janela principal ao clicar
floatButton.addEventListener('click', () => {
window.electronAPI.showMainWindow();

View File

@ -2,6 +2,8 @@ const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
onUpdateCount: (callback) => ipcRenderer.on('update-count', (_event, value) => callback(value)),
onAtendimentoStatusChanged: (callback) => ipcRenderer.on('atendimento-status-changed', (_event, status) => callback(status)),
refreshCount: () => ipcRenderer.send('refresh-count'),
showMainWindow: () => ipcRenderer.send('chamar-fila'),
showMenu: () => ipcRenderer.send('show-context-menu')
});

View File

@ -1,17 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self' 'unsafe-inline';
style-src 'self' 'unsafe-inline';
connect-src 'self' ws://autoatend.linco.work:6001 ws://localhost:6001;
connect-src 'self' ws://autoatend.linco.work:6001 ws://localhost:6001 wss://aa.linco.work:443;
">
<title>Tela de Atendimento</title>
<link rel="stylesheet" href="style.css">
<script src="res/js/jquery/jquery.js"></script>
</head>
<body>
<div id="list-view">
<h1>Fila</h1>
@ -47,4 +49,5 @@
<script src="renderer.js"></script>
</body>
</html>

47
main.js
View File

@ -16,7 +16,7 @@ const dataPath = path.join(__dirname, 'data.json'); // Caminho para o JSON (back
const apiUrl = 'https://autoatend.linco.work/api/v1/';
// const apiUrl = 'http://_lara10-autoatend.devel/api/v1/';
const pusherUrl = 'autoatend.linco.work';
const pusherUrl = 'aa.linco.work';
// const pusherUrl = 'localhost';
@ -462,10 +462,8 @@ ipcMain.handle('get-count', async () => {
// Ouvir pedido para mostrar a janela principal
ipcMain.on('chamar-fila', async () => {
const countFila = async () => {
const proximos = JSON.parse(await floatingWin.webContents.executeJavaScript("localStorage.getItem('proximos')")) ?? [];
return proximos.length;
}
// Primeiro, verifica se já existe um atendimento em andamento
const atendimentoAtualId = await floatingWin.webContents.executeJavaScript("localStorage.getItem('atendimentoAtual')");
const showMainWindow = () => {
if (mainWin) {
@ -484,6 +482,19 @@ ipcMain.on('chamar-fila', async () => {
}
}
// 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) {
showMainWindow();
return; // Interrompe a execução aqui
}
// Se não houver atendimento em andamento, continua com a lógica original.
const countFila = async () => {
const proximos = JSON.parse(await floatingWin.webContents.executeJavaScript("localStorage.getItem('proximos')")) ?? [];
return proximos.length;
}
const requestData = async () => {
@ -583,6 +594,14 @@ ipcMain.on('chamar-fila', async () => {
});
// Ouve um pedido da janela flutuante para forçar a atualização da contagem
ipcMain.on('refresh-count', async () => {
if (floatingWin) {
const proximos = JSON.parse(await floatingWin.webContents.executeJavaScript("localStorage.getItem('proximos')")) ?? [];
floatingWin.webContents.send('update-count', proximos.length);
}
});
ipcMain.on('select-atend-id', (itemId) => {
selectedItemId = itemId;
console.log(selectedItemId);
@ -595,9 +614,9 @@ ipcMain.on('iniciar-atendimento', async (event, itemId) => {
const colabId = await floatingWin.webContents.executeJavaScript("localStorage.getItem('idOperator')")
//TODO inicia o atendimento o id do atendimento deve ser requisitado do backend
const url = apiUrl + 'iniciar-atendimento/'+itemId; // URL de exemplo para enviar a solicitação
const url = apiUrl + 'iniciar-atendimento/' + itemId; // URL para enviar a solicitação
// Simula o envio de uma solicitação POST com o ID do item
// envio de uma solicitação POST com o ID do item
const request = net.request({
method: 'GET',
url: url,
@ -632,6 +651,20 @@ ipcMain.on('iniciar-atendimento', async (event, itemId) => {
// A janela principal já mudou a UI ao enviar o evento 'next-step'
});
// Ouve quando um atendimento é iniciado e notifica a janela flutuante
ipcMain.on('atendimento-iniciado', (event, itemId) => {
if (floatingWin) {
floatingWin.webContents.send('atendimento-status-changed', 'iniciado');
}
});
// Ouve quando um atendimento é finalizado e notifica a janela flutuante
ipcMain.on('atendimento-finalizado', () => {
if (floatingWin) {
floatingWin.webContents.send('atendimento-status-changed', 'finalizado');
}
});
// Ouvir clique no botão "Salvar"
ipcMain.on('save-observation', async (event, { itemId, observation }) => {

View File

@ -1,6 +1,6 @@
{
"name": "autoatendcolab",
"version": "1.1.2",
"version": "1.1.3",
"main": "main.js",
"isBuildNow": true,
"scripts": {

View File

@ -14,6 +14,10 @@ contextBridge.exposeInMainWorld('electronAPI', {
//inicia o atendimento atual
iniciaAtendimento: (itemId) => ipcRenderer.send('iniciar-atendimento', itemId),
//notifica sobre o status do atendimento
atendimentoIniciado: (itemId) => ipcRenderer.send('atendimento-iniciado', itemId),
atendimentoFinalizado: () => ipcRenderer.send('atendimento-finalizado'),
showObservation: (callback) => ipcRenderer.on('show-observation', (_event) => callback() ),
//salva a observação do atendimento
saveObservation: (data) => ipcRenderer.send('save-observation', data),

View File

@ -44,11 +44,11 @@ async function initializePusher() {
var pusher = new Pusher(PUSHER_APP_KEY, {
wsHost: host,
wsPort: 6001,
wssPort: 6001,
forceTLS: false,
wsPort: 80,
wssPort: 443,
forceTLS: true,
enableStats: false,
enabledTransports: ['ws','wss'],
enabledTransports: ['wss', 'ws'],
cluster: 'mt1'
});
@ -91,7 +91,11 @@ window.electronAPI.selectAtendID((data)=>{
// Reseta a view para a lista sempre que os dados são carregados ao clicar no botão para abrir a janela
populateList(data);
showListView();
// Garante que o item selecionado (ID e Nome) seja o que veio da chamada, sobrescrevendo o da lista.
selectedItemId = data.id ?? null;
selectedItemName = data.clientName ?? '';
//data.senhaGen
queueNumber.innerHTML = data ? `NA VEZ: <u>${data.clientName.toUpperCase()}</u> - ${data.descricaoServico.toUpperCase()}` : 'Ninguem aguardando atendimento';
selectedItemNameSpan.innerHTML = data ? `<u> ${data.clientName.toUpperCase()} </u> <i style="float:right;">[ ${data.senhaGen} ]</i>` : 'Ninguem aguardando atendimento';
@ -104,6 +108,16 @@ window.electronAPI.showObservation(()=>{
// Função para popular a lista de itens
function populateList(currentData) {
const atendimentoEmAndamentoId = localStorage.getItem('atendimentoAtual');
const atendimentoEmAndamentoNome = localStorage.getItem('atendimentoAtualNome');
if (atendimentoEmAndamentoId) {
itemList.innerHTML = `<li>Atendimento com <strong>${(atendimentoEmAndamentoNome || '').toUpperCase()}</strong> em andamento.</li>`;
queueNumber.innerHTML = `EM ATENDIMENTO: <u>${(atendimentoEmAndamentoNome || '').toUpperCase()}</u>`;
nextButton.disabled = true;
return;
}
let datastorage = localStorage.getItem('proximos');
// Adiciona os outros itens apenas para visualização (opcional)
@ -142,6 +156,19 @@ function populateList(currentData) {
}
// Verifica o estado ao carregar a janela
document.addEventListener('DOMContentLoaded', () => {
const atendimentoEmAndamentoId = localStorage.getItem('atendimentoAtual');
if (atendimentoEmAndamentoId) {
// Se um atendimento está em andamento, a tela de observação deve ser mostrada
selectedItemId = atendimentoEmAndamentoId;
selectedItemName = localStorage.getItem('atendimentoAtualNome');
selectedItemNameSpan.innerHTML = `<u> ${(selectedItemName || '').toUpperCase()} </u>`;
showObservationView();
}
});
//mostra a tela de listagem e permite iniciar o atendimento
function showListView() {
listView.style.display = 'block';
@ -163,6 +190,12 @@ function showObservationView() {
// // Evento do botão "Iniciar atendimento"
nextButton.addEventListener('click', () => {
if (selectedItemId !== null) {
// Salva o estado de atendimento no localStorage
localStorage.setItem('atendimentoAtual', selectedItemId);
localStorage.setItem('atendimentoAtualNome', selectedItemName);
// Notifica o main process e muda a view
window.electronAPI.atendimentoIniciado(selectedItemId);
window.electronAPI.iniciaAtendimento(selectedItemId);
showObservationView(); // Muda para a tela de observação
} else {
@ -181,6 +214,11 @@ logoutButton.addEventListener('click',()=>{
saveButton.addEventListener('click', () => {
const observation = observationText.value;
if (selectedItemId !== null) {
// Limpa o estado de atendimento
localStorage.removeItem('atendimentoAtual');
localStorage.removeItem('atendimentoAtualNome');
window.electronAPI.atendimentoFinalizado();
window.electronAPI.saveObservation({ itemId: selectedItemId, observation: observation });
window.location.reload();
}

View File

@ -78,6 +78,13 @@ body#floating{
animation: pulse-border .5s infinite;
}
/* Nova classe para quando estiver em atendimento */
#float-button.em-atendimento {
background-color: var(--danger-color); /* Vermelho */
border: 4px solid var(--dark-danger-color);
animation: pulse-border .2s infinite; /* Pulso mais rápido */
}
@keyframes pulse-border {
0% {
border-color: var(--medium-gold);