Files
SimpleClient-releases/cti-simulator.js
Pierre Marx d6f89ed686 refactor: nettoyage du code et correction de bugs mineurs
- Correction de l'ouverture des DevTools uniquement en mode développement
- Fix de la détection du mode développement pour le simulateur CTI via IPC
- Suppression de la boucle de retry infinie pour Choices.js
- Suppression du code mort (fonction updateSignalRStatus vide)
- Amélioration de la gestion d'erreur avec fallback natif pour Choices.js
2025-09-04 13:43:26 -04:00

313 lines
11 KiB
JavaScript

// Module de simulation CTI (Computer Telephony Integration)
// Ce module simule l'intégration téléphonique pour les tests
class CTISimulator {
constructor() {
this.isRunning = false;
this.autoCallInterval = null;
this.callHistory = [];
}
// Démarrer la simulation automatique d'appels
startAutoSimulation(intervalSeconds = 60) {
if (this.isRunning) return;
this.isRunning = true;
console.log(`Simulation CTI démarrée - Appels toutes les ${intervalSeconds} secondes`);
// Premier appel après 10 secondes
setTimeout(() => {
this.generateRandomCall();
}, 10000);
// Puis appels réguliers
this.autoCallInterval = setInterval(() => {
if (Math.random() > 0.3) { // 70% de chance d'avoir un appel
this.generateRandomCall();
}
}, intervalSeconds * 1000);
}
// Arrêter la simulation
stopAutoSimulation() {
if (this.autoCallInterval) {
clearInterval(this.autoCallInterval);
this.autoCallInterval = null;
}
this.isRunning = false;
console.log('Simulation CTI arrêtée');
}
// Générer un appel aléatoire
async generateRandomCall() {
const config = await ipcRenderer.invoke('get-config');
const simulatedCalls = config.cti.appelSimules;
if (!simulatedCalls || simulatedCalls.length === 0) return;
// Sélectionner un appel au hasard
const randomCall = simulatedCalls[Math.floor(Math.random() * simulatedCalls.length)];
// Vérifier que l'agent a accès à ce centre
const currentAgent = await ipcRenderer.invoke('get-current-agent');
if (!currentAgent || !currentAgent.agent.centresAssignes.includes(randomCall.centreId)) {
// Essayer avec un autre appel
const validCalls = simulatedCalls.filter(call =>
currentAgent.agent.centresAssignes.includes(call.centreId)
);
if (validCalls.length > 0) {
const validCall = validCalls[Math.floor(Math.random() * validCalls.length)];
this.triggerIncomingCall(validCall);
}
} else {
this.triggerIncomingCall(randomCall);
}
}
// Déclencher un appel entrant
triggerIncomingCall(callData) {
console.log('Appel entrant simulé:', callData);
// Ajouter des métadonnées
const enrichedCall = {
...callData,
id: this.generateCallId(),
timestamp: new Date().toISOString(),
duration: 0,
status: 'ringing'
};
// Ajouter à l'historique
this.callHistory.push(enrichedCall);
// Déclencher l'événement
ipcRenderer.invoke('simulate-call', enrichedCall);
}
// Générer un ID unique pour l'appel
generateCallId() {
return `CALL-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
}
// Obtenir les statistiques des appels
getCallStats() {
const now = new Date();
const todayStart = new Date(now.setHours(0, 0, 0, 0));
const todayCalls = this.callHistory.filter(call =>
new Date(call.timestamp) >= todayStart
);
return {
total: this.callHistory.length,
today: todayCalls.length,
answered: todayCalls.filter(c => c.status === 'answered').length,
missed: todayCalls.filter(c => c.status === 'missed').length,
average_duration: this.calculateAverageDuration(todayCalls)
};
}
// Calculer la durée moyenne des appels
calculateAverageDuration(calls) {
const answered = calls.filter(c => c.duration > 0);
if (answered.length === 0) return 0;
const total = answered.reduce((sum, call) => sum + call.duration, 0);
return Math.round(total / answered.length);
}
// Simuler différents scénarios d'appels
simulateScenarios() {
const scenarios = [
{
name: 'Appel urgent',
setup: () => {
this.triggerIncomingCall({
numero: '+33699887766',
nom: 'URGENT - Marie LAMBERT',
centreId: 'centre1',
priority: 'high',
motif: 'Consultation urgente cardiologie'
});
}
},
{
name: 'Patient régulier',
setup: () => {
this.triggerIncomingCall({
numero: '+33612345678',
nom: 'Jean DUPUIS (Patient régulier)',
centreId: 'centre2',
priority: 'normal',
motif: 'Suivi mensuel',
lastVisit: '2024-11-15'
});
}
},
{
name: 'Nouveau patient',
setup: () => {
this.triggerIncomingCall({
numero: '+33755443322',
nom: 'Sophie MARTIN',
centreId: 'centre3',
priority: 'normal',
motif: 'Première consultation',
isNew: true
});
}
},
{
name: 'Appel pour résultats',
setup: () => {
this.triggerIncomingCall({
numero: '+33688776655',
nom: 'Paul BERNARD',
centreId: 'centre4',
priority: 'low',
motif: 'Demande résultats radiologie',
examDate: '2024-12-20'
});
}
}
];
return scenarios;
}
// Interface de test pour le développement
showTestPanel() {
const testPanel = document.createElement('div');
testPanel.id = 'cti-test-panel';
testPanel.className = 'cti-test-panel';
testPanel.innerHTML = `
<h3>Panneau de test CTI</h3>
<div class="test-controls">
<button onclick="ctiSimulator.generateRandomCall()">Appel aléatoire</button>
<button onclick="ctiSimulator.startAutoSimulation(30)">Démarrer auto (30s)</button>
<button onclick="ctiSimulator.stopAutoSimulation()">Arrêter auto</button>
</div>
<div class="test-scenarios">
<h4>Scénarios</h4>
${this.simulateScenarios().map(s =>
`<button onclick="ctiSimulator.runScenario('${s.name}')">${s.name}</button>`
).join('')}
</div>
<div class="test-stats">
<h4>Statistiques</h4>
<div id="cti-stats"></div>
</div>
`;
// Ajouter les styles
if (!document.getElementById('cti-test-styles')) {
const styles = document.createElement('style');
styles.id = 'cti-test-styles';
styles.innerHTML = `
.cti-test-panel {
position: fixed;
right: 20px;
bottom: 20px;
width: 300px;
background: white;
border: 1px solid #ddd;
border-radius: 8px;
padding: 15px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
z-index: 9999;
}
.cti-test-panel h3 {
margin-bottom: 10px;
color: #333;
font-size: 16px;
}
.cti-test-panel h4 {
margin: 10px 0 5px 0;
color: #666;
font-size: 14px;
}
.test-controls button,
.test-scenarios button {
margin: 5px;
padding: 5px 10px;
background: #667eea;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
}
.test-controls button:hover,
.test-scenarios button:hover {
background: #5a6fd8;
}
#cti-stats {
font-size: 12px;
color: #666;
}
`;
document.head.appendChild(styles);
}
document.body.appendChild(testPanel);
this.updateStats();
}
// Exécuter un scénario
runScenario(name) {
const scenario = this.simulateScenarios().find(s => s.name === name);
if (scenario) {
scenario.setup();
}
}
// Mettre à jour les statistiques
updateStats() {
const stats = this.getCallStats();
const statsDiv = document.getElementById('cti-stats');
if (statsDiv) {
statsDiv.innerHTML = `
<div>Total: ${stats.total} appels</div>
<div>Aujourd'hui: ${stats.today}</div>
<div>Répondus: ${stats.answered}</div>
<div>Manqués: ${stats.missed}</div>
<div>Durée moy: ${stats.average_duration}s</div>
`;
}
}
}
// Créer une instance globale
const ctiSimulator = new CTISimulator();
// Exposer pour les tests en développement
// Dans le contexte renderer, vérifier si on est en mode développement via une variable globale
window.ctiSimulator = ctiSimulator;
// Afficher le panneau de test si en mode développement
ipcRenderer.invoke('is-development').then(isDev => {
if (isDev) {
document.addEventListener('DOMContentLoaded', () => {
setTimeout(() => {
const mainPage = document.getElementById('mainPage');
if (mainPage && mainPage.classList.contains('active')) {
ctiSimulator.showTestPanel();
}
}, 2000);
});
}
});
// Démarrer la simulation automatique après connexion (optionnel)
ipcRenderer.on('agent-logged-in', () => {
// Démarrer la simulation après 5 secondes
setTimeout(() => {
ctiSimulator.startAutoSimulation(90); // Un appel toutes les 90 secondes
}, 5000);
});
// Arrêter la simulation à la déconnexion
ipcRenderer.on('agent-logged-out', () => {
ctiSimulator.stopAutoSimulation();
});