285 lines
7.3 KiB
JavaScript
285 lines
7.3 KiB
JavaScript
const { app, BrowserWindow, ipcMain, session } = require('electron');
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
const signalR = require('@microsoft/signalr');
|
|
|
|
let mainWindow;
|
|
let config;
|
|
let currentAgent = null;
|
|
let signalRConnection = null;
|
|
let signalRStatus = 'disconnected'; // disconnected, connecting, connected, error
|
|
|
|
// Charger la configuration
|
|
function loadConfig() {
|
|
const configPath = path.join(__dirname, 'config.json');
|
|
const configData = fs.readFileSync(configPath, 'utf8');
|
|
config = JSON.parse(configData);
|
|
}
|
|
|
|
// Créer la fenêtre principale
|
|
function createWindow() {
|
|
mainWindow = new BrowserWindow({
|
|
width: 1400,
|
|
height: 900,
|
|
webPreferences: {
|
|
nodeIntegration: true,
|
|
contextIsolation: false,
|
|
webviewTag: true,
|
|
webSecurity: false
|
|
},
|
|
icon: path.join(__dirname, 'icon.png'),
|
|
title: 'SimpleConnect - Gestion Centralisée des Plannings'
|
|
});
|
|
|
|
// Charger l'interface HTML
|
|
mainWindow.loadFile('index.html');
|
|
|
|
// Ouvrir les DevTools en mode développement
|
|
if (process.env.NODE_ENV === 'development') {
|
|
mainWindow.webContents.openDevTools();
|
|
}
|
|
|
|
// Gérer la fermeture de la fenêtre
|
|
mainWindow.on('closed', () => {
|
|
mainWindow = null;
|
|
});
|
|
}
|
|
|
|
// === GESTION SIGNALR ===
|
|
function initializeSignalR() {
|
|
if (!config.signalR || !config.signalR.enabled) {
|
|
console.log('SignalR désactivé dans la configuration');
|
|
signalRStatus = 'disabled';
|
|
sendSignalRStatus();
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Créer la connexion SignalR
|
|
signalRConnection = new signalR.HubConnectionBuilder()
|
|
.withUrl(config.signalR.serverUrl)
|
|
.withAutomaticReconnect([0, 2000, 5000, 10000, 30000])
|
|
.configureLogging(signalR.LogLevel.Information)
|
|
.build();
|
|
|
|
// Gérer les changements d'état
|
|
signalRConnection.onreconnecting(() => {
|
|
console.log('SignalR: Reconnexion en cours...');
|
|
signalRStatus = 'connecting';
|
|
sendSignalRStatus();
|
|
});
|
|
|
|
signalRConnection.onreconnected(() => {
|
|
console.log('SignalR: Reconnecté');
|
|
signalRStatus = 'connected';
|
|
sendSignalRStatus();
|
|
});
|
|
|
|
signalRConnection.onclose(() => {
|
|
console.log('SignalR: Connexion fermée');
|
|
signalRStatus = 'disconnected';
|
|
sendSignalRStatus();
|
|
});
|
|
|
|
// Démarrer la connexion
|
|
startSignalRConnection();
|
|
|
|
} catch (error) {
|
|
console.error('Erreur initialisation SignalR:', error);
|
|
signalRStatus = 'error';
|
|
sendSignalRStatus();
|
|
}
|
|
}
|
|
|
|
async function startSignalRConnection() {
|
|
try {
|
|
signalRStatus = 'connecting';
|
|
sendSignalRStatus();
|
|
|
|
await signalRConnection.start();
|
|
console.log('SignalR: Connexion établie');
|
|
signalRStatus = 'connected';
|
|
sendSignalRStatus();
|
|
|
|
} catch (error) {
|
|
console.error('Erreur connexion SignalR:', error);
|
|
signalRStatus = 'error';
|
|
sendSignalRStatus();
|
|
|
|
// Réessayer dans 5 secondes
|
|
setTimeout(() => {
|
|
if (signalRConnection && signalRStatus !== 'connected') {
|
|
startSignalRConnection();
|
|
}
|
|
}, 5000);
|
|
}
|
|
}
|
|
|
|
function sendSignalRStatus() {
|
|
if (mainWindow && !mainWindow.isDestroyed()) {
|
|
mainWindow.webContents.send('signalr-status', signalRStatus);
|
|
}
|
|
}
|
|
|
|
// Initialisation de l'application
|
|
app.whenReady().then(() => {
|
|
// Configuration de la session pour éviter les problèmes CORS
|
|
session.defaultSession.webRequest.onBeforeSendHeaders((details, callback) => {
|
|
details.requestHeaders['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';
|
|
callback({ requestHeaders: details.requestHeaders });
|
|
});
|
|
|
|
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
|
|
callback({
|
|
responseHeaders: {
|
|
...details.responseHeaders,
|
|
'Content-Security-Policy': ['default-src * \'unsafe-inline\' \'unsafe-eval\' data: blob:;']
|
|
}
|
|
});
|
|
});
|
|
|
|
loadConfig();
|
|
createWindow();
|
|
|
|
// Initialiser SignalR après le chargement de la config
|
|
initializeSignalR();
|
|
});
|
|
|
|
// Quitter quand toutes les fenêtres sont fermées
|
|
app.on('window-all-closed', () => {
|
|
if (process.platform !== 'darwin') {
|
|
app.quit();
|
|
}
|
|
});
|
|
|
|
// Réactiver l'app sur macOS
|
|
app.on('activate', () => {
|
|
if (mainWindow === null) {
|
|
createWindow();
|
|
}
|
|
});
|
|
|
|
// === IPC HANDLERS ===
|
|
|
|
// Obtenir la configuration
|
|
ipcMain.handle('get-config', () => {
|
|
return config;
|
|
});
|
|
|
|
// Obtenir le statut SignalR
|
|
ipcMain.handle('get-signalr-status', () => {
|
|
return signalRStatus;
|
|
});
|
|
|
|
// Connexion agent
|
|
ipcMain.handle('login-agent', (event, credentials) => {
|
|
const agent = config.agents.find(a =>
|
|
a.email === credentials.email &&
|
|
a.password === credentials.password
|
|
);
|
|
|
|
if (agent) {
|
|
currentAgent = agent;
|
|
// Retourner l'agent avec ses centres assignés
|
|
const centresAssignes = config.centres.filter(c =>
|
|
agent.centresAssignes.includes(c.id)
|
|
);
|
|
return {
|
|
success: true,
|
|
agent: agent,
|
|
centres: centresAssignes
|
|
};
|
|
}
|
|
|
|
return { success: false, message: 'Email ou mot de passe incorrect' };
|
|
});
|
|
|
|
// Déconnexion
|
|
ipcMain.handle('logout', () => {
|
|
currentAgent = null;
|
|
return { success: true };
|
|
});
|
|
|
|
// Obtenir l'agent actuel
|
|
ipcMain.handle('get-current-agent', () => {
|
|
if (!currentAgent) return null;
|
|
|
|
const centresAssignes = config.centres.filter(c =>
|
|
currentAgent.centresAssignes.includes(c.id)
|
|
);
|
|
|
|
return {
|
|
agent: currentAgent,
|
|
centres: centresAssignes
|
|
};
|
|
});
|
|
|
|
// Simuler un appel entrant
|
|
ipcMain.handle('simulate-call', (event, callData) => {
|
|
// Envoyer l'événement d'appel entrant à la fenêtre
|
|
mainWindow.webContents.send('incoming-call', callData);
|
|
return { success: true };
|
|
});
|
|
|
|
// Obtenir les données pour simuler des appels
|
|
ipcMain.handle('get-simulated-calls', () => {
|
|
return config.cti.appelSimules.map(appel => {
|
|
const centre = config.centres.find(c => c.id === appel.centreId);
|
|
return {
|
|
...appel,
|
|
centreNom: centre ? centre.nom : 'Centre inconnu'
|
|
};
|
|
});
|
|
});
|
|
|
|
// Sauvegarder les notes de l'agent
|
|
ipcMain.handle('save-notes', (event, noteData) => {
|
|
const notesDir = path.join(__dirname, 'notes');
|
|
if (!fs.existsSync(notesDir)) {
|
|
fs.mkdirSync(notesDir);
|
|
}
|
|
|
|
const fileName = `notes_${currentAgent.id}_${Date.now()}.json`;
|
|
const filePath = path.join(notesDir, fileName);
|
|
|
|
fs.writeFileSync(filePath, JSON.stringify({
|
|
agent: currentAgent.id,
|
|
timestamp: new Date().toISOString(),
|
|
...noteData
|
|
}, null, 2));
|
|
|
|
return { success: true, file: fileName };
|
|
});
|
|
|
|
// Obtenir l'historique des appels
|
|
ipcMain.handle('get-call-history', () => {
|
|
const historyFile = path.join(__dirname, 'call_history.json');
|
|
if (fs.existsSync(historyFile)) {
|
|
const data = fs.readFileSync(historyFile, 'utf8');
|
|
return JSON.parse(data);
|
|
}
|
|
return [];
|
|
});
|
|
|
|
// Sauvegarder un appel dans l'historique
|
|
ipcMain.handle('save-call-history', (event, callData) => {
|
|
const historyFile = path.join(__dirname, 'call_history.json');
|
|
let history = [];
|
|
|
|
if (fs.existsSync(historyFile)) {
|
|
const data = fs.readFileSync(historyFile, 'utf8');
|
|
history = JSON.parse(data);
|
|
}
|
|
|
|
history.unshift({
|
|
...callData,
|
|
agentId: currentAgent?.id,
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
|
|
// Garder seulement les 100 derniers appels
|
|
history = history.slice(0, 100);
|
|
|
|
fs.writeFileSync(historyFile, JSON.stringify(history, null, 2));
|
|
return { success: true };
|
|
}); |