Version initiale
This commit is contained in:
309
cti-simulator.js
Normal file
309
cti-simulator.js
Normal file
@@ -0,0 +1,309 @@
|
||||
// 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
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
window.ctiSimulator = ctiSimulator;
|
||||
// Afficher le panneau de test après connexion
|
||||
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();
|
||||
});
|
||||
Reference in New Issue
Block a user