Les titres des onglets affichent maintenant le code client (centre.id) au lieu du nom de la file d'attente (centre.nom) pour une identification plus directe et claire du client concerné.
738 lines
26 KiB
JavaScript
738 lines
26 KiB
JavaScript
const { ipcRenderer } = require('electron');
|
|
// Choices est maintenant chargé via CDN dans index.html
|
|
|
|
// Variables globales
|
|
let currentAgent = null;
|
|
let currentCentres = [];
|
|
let activeCenter = null;
|
|
let webviews = {};
|
|
let callStats = {
|
|
calls: 0,
|
|
appointments: 0
|
|
};
|
|
|
|
// === GESTION DE LA CONNEXION ===
|
|
document.addEventListener('DOMContentLoaded', async () => {
|
|
// Initialiser l'indicateur SignalR
|
|
|
|
// Écouter les changements de statut SignalR
|
|
ipcRenderer.on('signalr-status', (event, status) => {
|
|
updateSignalRIndicator(status);
|
|
// Recharger les terminaux à chaque changement de statut
|
|
loadTerminals();
|
|
});
|
|
|
|
// Obtenir le statut initial SignalR
|
|
const initialStatus = await ipcRenderer.invoke('get-signalr-status');
|
|
updateSignalRIndicator(initialStatus);
|
|
|
|
// Charger immédiatement les terminaux pour la page de login
|
|
await loadTerminals();
|
|
|
|
// Vérifier si un agent est déjà connecté
|
|
const agentData = await ipcRenderer.invoke('get-current-agent');
|
|
if (agentData) {
|
|
currentAgent = agentData.agent;
|
|
currentCentres = agentData.centres;
|
|
showMainPage();
|
|
}
|
|
|
|
// Gestionnaire du formulaire de connexion
|
|
const loginForm = document.getElementById('loginForm');
|
|
if (loginForm) {
|
|
loginForm.addEventListener('submit', handleLogin);
|
|
}
|
|
|
|
// Bouton de déconnexion
|
|
const logoutBtn = document.getElementById('logoutBtn');
|
|
if (logoutBtn) {
|
|
logoutBtn.addEventListener('click', handleLogout);
|
|
}
|
|
|
|
// Bouton simulation d'appel
|
|
const simulateBtn = document.getElementById('simulateCallBtn');
|
|
if (simulateBtn) {
|
|
simulateBtn.addEventListener('click', showCallSimulation);
|
|
}
|
|
|
|
// Bouton sauvegarder notes
|
|
const saveNotesBtn = document.getElementById('saveNotesBtn');
|
|
if (saveNotesBtn) {
|
|
saveNotesBtn.addEventListener('click', saveNotes);
|
|
}
|
|
|
|
// Écouter les appels entrants
|
|
ipcRenderer.on('incoming-call', (event, callData) => {
|
|
handleIncomingCall(callData);
|
|
});
|
|
|
|
// Écouter les événements SignalR de basculement de centre
|
|
ipcRenderer.on('switch-to-center', (event, data) => {
|
|
console.log('Basculement vers le centre:', data.centreName);
|
|
|
|
// Trouver le centre et basculer automatiquement
|
|
const centre = currentCentres.find(c => c.id === data.centreId);
|
|
if (centre) {
|
|
selectCenter(data.centreId);
|
|
|
|
// Afficher une notification
|
|
showNotification(`Appel entrant sur ${data.centreName}`, 'info');
|
|
|
|
// Mettre à jour le statut
|
|
updateAgentStatus('EN APPEL');
|
|
}
|
|
});
|
|
|
|
// Écouter la libération de centre après raccrochage
|
|
ipcRenderer.on('release-center', (event, data) => {
|
|
console.log('Libération de la file:', data.queueName);
|
|
|
|
// Mettre à jour le statut
|
|
updateAgentStatus('DISPONIBLE');
|
|
|
|
// Incrementer le compteur d'appels
|
|
callStats.calls++;
|
|
updateCallStats();
|
|
|
|
// Afficher une notification
|
|
showNotification('Appel terminé', 'success');
|
|
});
|
|
});
|
|
|
|
// Connexion via SignalR
|
|
async function handleLogin(e) {
|
|
e.preventDefault();
|
|
|
|
const accessCode = document.getElementById('accessCode').value;
|
|
const password = document.getElementById('password').value;
|
|
const terminal = document.getElementById('terminal').value;
|
|
const forceDisconnect = document.getElementById('forceDisconnect').checked;
|
|
const errorDiv = document.getElementById('loginError');
|
|
const loginBtn = document.querySelector('#loginForm button[type="submit"]');
|
|
|
|
// Vérifier que le terminal est sélectionné et valide
|
|
if (!terminal) {
|
|
errorDiv.textContent = 'Veuillez sélectionner un poste téléphonique';
|
|
return;
|
|
}
|
|
|
|
// Valider que le terminal existe dans la liste
|
|
if (!validateTerminal(terminal)) {
|
|
errorDiv.textContent = 'Poste téléphonique invalide. Veuillez choisir un poste de la liste.';
|
|
return;
|
|
}
|
|
|
|
// Sauvegarder le terminal sélectionné pour la prochaine fois
|
|
localStorage.setItem('last-terminal', terminal);
|
|
|
|
// Désactiver le bouton pendant la connexion
|
|
loginBtn.disabled = true;
|
|
loginBtn.textContent = forceDisconnect ? 'Reconnexion...' : 'Connexion en cours...';
|
|
errorDiv.textContent = '';
|
|
|
|
try {
|
|
// Préparer les credentials pour SignalR
|
|
const credentials = {
|
|
email: accessCode, // Utiliser directement le code agent comme email
|
|
password: password,
|
|
terminal: terminal,
|
|
forceDisconnect: forceDisconnect // Ajouter l'option de déconnexion forcée
|
|
};
|
|
|
|
// Appeler l'authentification SignalR
|
|
const result = await ipcRenderer.invoke('login-agent', credentials);
|
|
|
|
if (result.success) {
|
|
currentAgent = result.agent;
|
|
currentCentres = result.centres;
|
|
errorDiv.textContent = '';
|
|
console.log('Connexion réussie:', currentAgent.name, 'sur le poste', terminal);
|
|
showMainPage();
|
|
} else {
|
|
errorDiv.textContent = result.message || 'Identifiants incorrects';
|
|
loginBtn.disabled = false;
|
|
loginBtn.textContent = 'Se connecter';
|
|
}
|
|
} catch (error) {
|
|
console.error('Erreur lors de la connexion:', error);
|
|
errorDiv.textContent = 'Erreur de connexion. Veuillez réessayer.';
|
|
loginBtn.disabled = false;
|
|
loginBtn.textContent = 'Se connecter';
|
|
}
|
|
}
|
|
|
|
// Déconnexion
|
|
async function handleLogout() {
|
|
if (confirm('Voulez-vous vraiment vous déconnecter ?')) {
|
|
await ipcRenderer.invoke('logout');
|
|
currentAgent = null;
|
|
currentCentres = [];
|
|
activeCenter = null;
|
|
webviews = {};
|
|
showLoginPage();
|
|
}
|
|
}
|
|
|
|
// === GESTION DES PAGES ===
|
|
function showLoginPage() {
|
|
document.getElementById('loginPage').classList.add('active');
|
|
document.getElementById('mainPage').classList.remove('active');
|
|
}
|
|
|
|
function showMainPage() {
|
|
document.getElementById('loginPage').classList.remove('active');
|
|
document.getElementById('mainPage').classList.add('active');
|
|
|
|
// Afficher le nom de l'agent
|
|
document.getElementById('agentName').textContent = currentAgent.name;
|
|
|
|
// Initialiser l'interface
|
|
initializeCenters();
|
|
updateStatus('available');
|
|
}
|
|
|
|
// === GESTION DES CENTRES ===
|
|
function initializeCenters() {
|
|
const centersList = document.getElementById('centersList');
|
|
const centerTabs = document.getElementById('centerTabs');
|
|
const webviewContainer = document.getElementById('webviewContainer');
|
|
|
|
// Vider les contenus existants
|
|
centersList.innerHTML = '';
|
|
centerTabs.innerHTML = '';
|
|
webviewContainer.innerHTML = '';
|
|
|
|
// Créer la liste des centres et les onglets
|
|
currentCentres.forEach(centre => {
|
|
// Élément dans la sidebar
|
|
const centerItem = document.createElement('div');
|
|
centerItem.className = 'center-item';
|
|
centerItem.dataset.centerId = centre.id;
|
|
centerItem.innerHTML = `
|
|
<div class="center-indicator" style="background-color: ${centre.couleur}"></div>
|
|
<div class="center-info">
|
|
<div class="center-name">${centre.nom}</div>
|
|
<div class="center-phone">${centre.telephone}</div>
|
|
</div>
|
|
<div class="center-status" id="status-${centre.id}">●</div>
|
|
`;
|
|
centerItem.addEventListener('click', () => selectCenter(centre.id));
|
|
centersList.appendChild(centerItem);
|
|
|
|
// Onglet
|
|
const tab = document.createElement('div');
|
|
tab.className = 'tab';
|
|
tab.dataset.centerId = centre.id;
|
|
tab.style.borderBottomColor = centre.couleur;
|
|
tab.textContent = centre.id; // Afficher le code du client au lieu du nom
|
|
tab.addEventListener('click', () => selectCenter(centre.id));
|
|
centerTabs.appendChild(tab);
|
|
|
|
// Créer la webview
|
|
const webviewWrapper = document.createElement('div');
|
|
webviewWrapper.className = 'webview-wrapper';
|
|
webviewWrapper.dataset.centerId = centre.id;
|
|
webviewWrapper.style.display = 'none';
|
|
|
|
const webview = document.createElement('webview');
|
|
webview.id = `webview-${centre.id}`;
|
|
webview.src = centre.url;
|
|
webview.className = 'planning-webview';
|
|
webview.setAttribute('partition', `persist:${centre.id}`);
|
|
webview.setAttribute('useragent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36');
|
|
|
|
// Barre d'outils pour la webview
|
|
const toolbar = document.createElement('div');
|
|
toolbar.className = 'webview-toolbar';
|
|
toolbar.innerHTML = `
|
|
<button onclick="navigateWebview('${centre.id}', 'back')">◀</button>
|
|
<button onclick="navigateWebview('${centre.id}', 'forward')">▶</button>
|
|
<button onclick="navigateWebview('${centre.id}', 'reload')">🔄</button>
|
|
<span class="webview-url" id="url-${centre.id}">${centre.url}</span>
|
|
`;
|
|
|
|
webviewWrapper.appendChild(toolbar);
|
|
webviewWrapper.appendChild(webview);
|
|
webviewContainer.appendChild(webviewWrapper);
|
|
|
|
// Stocker la référence de la webview
|
|
webviews[centre.id] = webview;
|
|
|
|
// Gérer les événements de la webview
|
|
webview.addEventListener('dom-ready', () => {
|
|
console.log(`Webview ${centre.nom} prête`);
|
|
document.getElementById(`status-${centre.id}`).style.color = '#4CAF50';
|
|
|
|
// Auto-connexion si credentials disponibles
|
|
if (centre.credentials && centre.credentials.username) {
|
|
// Injecter le script de connexion automatique (à adapter selon le site)
|
|
const loginScript = `
|
|
// Script générique de connexion - à adapter selon le planning
|
|
console.log('Tentative de connexion automatique pour ${centre.nom}');
|
|
`;
|
|
webview.executeJavaScript(loginScript);
|
|
}
|
|
});
|
|
|
|
webview.addEventListener('did-navigate', (e) => {
|
|
document.getElementById(`url-${centre.id}`).textContent = e.url;
|
|
});
|
|
|
|
webview.addEventListener('did-fail-load', (e) => {
|
|
console.error(`Erreur chargement ${centre.nom}:`, e);
|
|
document.getElementById(`status-${centre.id}`).style.color = '#FF5252';
|
|
});
|
|
});
|
|
}
|
|
|
|
// Sélectionner un centre
|
|
function selectCenter(centerId) {
|
|
// Mettre à jour le centre actif
|
|
activeCenter = centerId;
|
|
|
|
// Mettre à jour l'UI
|
|
document.querySelectorAll('.center-item').forEach(item => {
|
|
item.classList.toggle('active', item.dataset.centerId === centerId);
|
|
});
|
|
|
|
document.querySelectorAll('.tab').forEach(tab => {
|
|
tab.classList.toggle('active', tab.dataset.centerId === centerId);
|
|
});
|
|
|
|
// Afficher la bonne webview
|
|
document.querySelectorAll('.webview-wrapper').forEach(wrapper => {
|
|
wrapper.style.display = wrapper.dataset.centerId === centerId ? 'flex' : 'none';
|
|
});
|
|
}
|
|
|
|
// Navigation dans les webviews
|
|
window.navigateWebview = function(centerId, action) {
|
|
const webview = webviews[centerId];
|
|
if (webview) {
|
|
switch(action) {
|
|
case 'back':
|
|
webview.goBack();
|
|
break;
|
|
case 'forward':
|
|
webview.goForward();
|
|
break;
|
|
case 'reload':
|
|
webview.reload();
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
// === GESTION DES APPELS ===
|
|
function handleIncomingCall(callData) {
|
|
const centre = currentCentres.find(c => c.id === callData.centreId);
|
|
if (!centre) return;
|
|
|
|
// Afficher l'alerte
|
|
const alert = document.getElementById('incomingCallAlert');
|
|
alert.classList.add('active');
|
|
|
|
document.getElementById('callCenterName').textContent = centre.nom;
|
|
document.getElementById('callPatientInfo').textContent =
|
|
`${callData.nom || 'Patient'} - ${callData.numero}`;
|
|
|
|
// Jouer un son (à implémenter)
|
|
playNotificationSound();
|
|
|
|
// Gérer l'acceptation de l'appel
|
|
const acceptBtn = document.getElementById('acceptCallBtn');
|
|
acceptBtn.onclick = () => {
|
|
acceptCall(callData, centre);
|
|
};
|
|
|
|
// Auto-accepter après 3 secondes en mode démo
|
|
setTimeout(() => {
|
|
if (alert.classList.contains('active')) {
|
|
acceptCall(callData, centre);
|
|
}
|
|
}, 3000);
|
|
}
|
|
|
|
function acceptCall(callData, centre) {
|
|
// Masquer l'alerte
|
|
document.getElementById('incomingCallAlert').classList.remove('active');
|
|
|
|
// Sélectionner automatiquement le bon centre
|
|
selectCenter(centre.id);
|
|
|
|
// Mettre à jour le statut
|
|
updateStatus('incall', centre.nom);
|
|
|
|
// Incrémenter les stats
|
|
callStats.calls++;
|
|
document.getElementById('callCount').textContent = callStats.calls;
|
|
|
|
// Sauvegarder l'appel dans l'historique
|
|
ipcRenderer.invoke('save-call-history', {
|
|
...callData,
|
|
centreId: centre.id,
|
|
centreName: centre.nom,
|
|
status: 'answered'
|
|
});
|
|
|
|
// Simuler la fin de l'appel après 30 secondes
|
|
setTimeout(() => {
|
|
endCall();
|
|
}, 30000);
|
|
}
|
|
|
|
function endCall() {
|
|
updateStatus('available');
|
|
callStats.appointments++;
|
|
document.getElementById('appointmentCount').textContent = callStats.appointments;
|
|
}
|
|
|
|
// === SIMULATION D'APPELS ===
|
|
function showCallSimulation() {
|
|
const modal = document.getElementById('callSimulationModal');
|
|
modal.style.display = 'block';
|
|
|
|
// Charger les appels simulés
|
|
loadSimulatedCalls();
|
|
|
|
// Fermer la modal
|
|
modal.querySelector('.close').onclick = () => {
|
|
modal.style.display = 'none';
|
|
};
|
|
|
|
// Appel personnalisé
|
|
document.getElementById('customCallBtn').onclick = () => {
|
|
const customCall = {
|
|
numero: prompt('Numéro de téléphone:'),
|
|
nom: prompt('Nom du patient:'),
|
|
centreId: currentCentres[0]?.id
|
|
};
|
|
if (customCall.numero) {
|
|
ipcRenderer.invoke('simulate-call', customCall);
|
|
modal.style.display = 'none';
|
|
}
|
|
};
|
|
}
|
|
|
|
async function loadSimulatedCalls() {
|
|
const calls = await ipcRenderer.invoke('get-simulated-calls');
|
|
const listDiv = document.getElementById('simulatedCallsList');
|
|
|
|
listDiv.innerHTML = calls.map(call => `
|
|
<div class="simulated-call-item" onclick="simulateThisCall('${JSON.stringify(call).replace(/'/g, "\\'")}')">
|
|
<div class="call-name">${call.nom}</div>
|
|
<div class="call-details">${call.numero} - ${call.centreNom}</div>
|
|
</div>
|
|
`).join('');
|
|
}
|
|
|
|
window.simulateThisCall = function(callDataStr) {
|
|
const callData = JSON.parse(callDataStr);
|
|
ipcRenderer.invoke('simulate-call', callData);
|
|
document.getElementById('callSimulationModal').style.display = 'none';
|
|
};
|
|
|
|
// === UTILITAIRES ===
|
|
function updateStatus(status, details = '') {
|
|
const indicator = document.getElementById('statusIndicator');
|
|
const text = document.getElementById('statusText');
|
|
|
|
switch(status) {
|
|
case 'available':
|
|
indicator.className = 'status-indicator available';
|
|
text.textContent = 'Disponible';
|
|
break;
|
|
case 'incall':
|
|
indicator.className = 'status-indicator busy';
|
|
text.textContent = details ? `En appel - ${details}` : 'En appel';
|
|
break;
|
|
case 'offline':
|
|
indicator.className = 'status-indicator offline';
|
|
text.textContent = 'Hors ligne';
|
|
break;
|
|
}
|
|
}
|
|
|
|
function playNotificationSound() {
|
|
// Créer un bip simple avec l'API Web Audio
|
|
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
|
const oscillator = audioContext.createOscillator();
|
|
const gainNode = audioContext.createGain();
|
|
|
|
oscillator.connect(gainNode);
|
|
gainNode.connect(audioContext.destination);
|
|
|
|
oscillator.frequency.value = 800;
|
|
oscillator.type = 'sine';
|
|
gainNode.gain.value = 0.3;
|
|
|
|
oscillator.start();
|
|
oscillator.stop(audioContext.currentTime + 0.2);
|
|
}
|
|
|
|
// Fonction pour mettre à jour le statut de l'agent
|
|
function updateAgentStatus(status) {
|
|
const statusElement = document.getElementById('statusText');
|
|
const indicatorElement = document.getElementById('statusIndicator');
|
|
|
|
if (statusElement && indicatorElement) {
|
|
switch(status) {
|
|
case 'DISPONIBLE':
|
|
updateStatus('available');
|
|
break;
|
|
case 'EN APPEL':
|
|
updateStatus('incall');
|
|
break;
|
|
case 'HORS LIGNE':
|
|
updateStatus('offline');
|
|
break;
|
|
default:
|
|
statusElement.textContent = status;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fonction pour afficher une notification
|
|
function showNotification(message, type = 'info') {
|
|
// Créer un élément de notification temporaire
|
|
const notification = document.createElement('div');
|
|
notification.className = `notification notification-${type}`;
|
|
notification.textContent = message;
|
|
|
|
// Styles de base pour la notification
|
|
notification.style.cssText = `
|
|
position: fixed;
|
|
top: 20px;
|
|
right: 20px;
|
|
padding: 15px 20px;
|
|
background: ${type === 'success' ? '#4caf50' : type === 'error' ? '#f44336' : '#2196f3'};
|
|
color: white;
|
|
border-radius: 5px;
|
|
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
|
z-index: 10000;
|
|
animation: slideIn 0.3s ease;
|
|
`;
|
|
|
|
document.body.appendChild(notification);
|
|
|
|
// Retirer la notification après 3 secondes
|
|
setTimeout(() => {
|
|
notification.style.animation = 'slideOut 0.3s ease';
|
|
setTimeout(() => notification.remove(), 300);
|
|
}, 3000);
|
|
|
|
// Jouer un son si c'est une notification d'appel
|
|
if (type === 'info' && message.includes('Appel entrant')) {
|
|
playNotificationSound();
|
|
}
|
|
}
|
|
|
|
// Fonction pour mettre à jour les statistiques d'appels
|
|
function updateCallStats() {
|
|
const callCountElement = document.getElementById('callCount');
|
|
const appointmentCountElement = document.getElementById('appointmentCount');
|
|
|
|
if (callCountElement) {
|
|
callCountElement.textContent = callStats.calls;
|
|
}
|
|
if (appointmentCountElement) {
|
|
appointmentCountElement.textContent = callStats.appointments;
|
|
}
|
|
}
|
|
|
|
async function saveNotes() {
|
|
const notes = document.getElementById('quickNotes').value;
|
|
if (!notes.trim()) return;
|
|
|
|
const result = await ipcRenderer.invoke('save-notes', {
|
|
content: notes,
|
|
centre: activeCenter
|
|
});
|
|
|
|
if (result.success) {
|
|
alert('Notes sauvegardées !');
|
|
document.getElementById('quickNotes').value = '';
|
|
}
|
|
}
|
|
|
|
// === GESTION DES TERMINAUX ===
|
|
let availableTerminals = []; // Stocker les terminaux disponibles
|
|
let terminalChoices = null; // Instance Choices.js
|
|
|
|
async function loadTerminals() {
|
|
const terminalSelect = document.getElementById('terminal');
|
|
if (!terminalSelect) {
|
|
console.log('Element terminal non trouvé');
|
|
return;
|
|
}
|
|
|
|
console.log('Chargement des terminaux...');
|
|
|
|
try {
|
|
// Récupérer les terminaux depuis le serveur SignalR
|
|
const terminals = await ipcRenderer.invoke('get-terminal-list');
|
|
availableTerminals = terminals || [];
|
|
console.log(`${terminals.length} terminaux récupérés`);
|
|
|
|
// Préparer les options pour Choices.js
|
|
const choicesData = [];
|
|
if (terminals && terminals.length > 0) {
|
|
// Afficher tous les terminaux sans groupement
|
|
terminals.forEach(terminal => {
|
|
choicesData.push({
|
|
value: terminal.toString(),
|
|
label: `Poste ${terminal}`
|
|
});
|
|
});
|
|
}
|
|
|
|
// Détruire l'instance existante si elle existe
|
|
if (terminalChoices) {
|
|
terminalChoices.destroy();
|
|
terminalChoices = null;
|
|
}
|
|
|
|
// Vider le select avant d'initialiser Choices
|
|
terminalSelect.innerHTML = '';
|
|
|
|
// Attendre que Choices soit disponible (chargé via CDN)
|
|
if (typeof window.Choices === 'undefined') {
|
|
console.log('Choices.js pas encore chargé, utilisation du select natif');
|
|
// Fallback : utiliser le select natif
|
|
terminalSelect.innerHTML = '<option value="">Sélectionner un poste...</option>';
|
|
if (terminals && terminals.length > 0) {
|
|
terminals.forEach(terminal => {
|
|
const option = document.createElement('option');
|
|
option.value = terminal;
|
|
option.textContent = `Poste ${terminal}`;
|
|
terminalSelect.appendChild(option);
|
|
});
|
|
}
|
|
// Pas de retry automatique pour éviter une boucle infinie
|
|
return;
|
|
}
|
|
|
|
console.log('Initialisation de Choices.js avec', choicesData.length, 'options');
|
|
|
|
try {
|
|
// Créer une nouvelle instance Choices.js
|
|
terminalChoices = new window.Choices(terminalSelect, {
|
|
searchEnabled: true,
|
|
searchPlaceholderValue: 'Rechercher un poste...',
|
|
itemSelectText: '',
|
|
noResultsText: 'Aucun poste trouvé',
|
|
noChoicesText: 'Aucun poste disponible',
|
|
shouldSort: false,
|
|
searchResultLimit: 20,
|
|
renderChoiceLimit: -1,
|
|
placeholder: true,
|
|
placeholderValue: 'Sélectionner un poste téléphonique',
|
|
choices: choicesData.length > 0 ? choicesData : [{value: '', label: 'Aucun poste disponible', disabled: true}],
|
|
searchFields: ['label', 'value'],
|
|
fuseOptions: {
|
|
includeScore: true,
|
|
threshold: 0.3
|
|
},
|
|
classNames: {
|
|
containerOuter: ['choices', 'choices-terminal'],
|
|
containerInner: 'choices__inner',
|
|
input: 'choices__input',
|
|
inputCloned: 'choices__input--cloned',
|
|
list: 'choices__list',
|
|
listItems: 'choices__list--multiple',
|
|
listSingle: 'choices__list--single',
|
|
listDropdown: 'choices__list--dropdown',
|
|
item: 'choices__item',
|
|
itemSelectable: 'choices__item--selectable',
|
|
itemDisabled: 'choices__item--disabled',
|
|
itemChoice: 'choices__item--choice',
|
|
placeholder: 'choices__placeholder',
|
|
group: 'choices__group',
|
|
groupHeading: 'choices__heading',
|
|
button: 'choices__button',
|
|
activeState: 'is-active',
|
|
focusState: 'is-focused',
|
|
openState: 'is-open',
|
|
disabledState: 'is-disabled',
|
|
highlightedState: 'is-highlighted',
|
|
hiddenState: 'is-hidden',
|
|
flippedState: 'is-flipped',
|
|
loadingState: 'is-loading',
|
|
noResults: 'has-no-results',
|
|
noChoices: 'has-no-choices'
|
|
}
|
|
});
|
|
|
|
console.log('Choices.js initialisé avec succès');
|
|
|
|
// Restaurer la dernière sélection si disponible
|
|
const lastTerminal = localStorage.getItem('last-terminal');
|
|
if (lastTerminal && availableTerminals.map(t => t.toString()).includes(lastTerminal)) {
|
|
terminalChoices.setChoiceByValue(lastTerminal.toString());
|
|
}
|
|
|
|
} catch (choicesError) {
|
|
console.error('Erreur lors de l\'initialisation de Choices.js:', choicesError);
|
|
console.error('Stack:', choicesError.stack);
|
|
// En cas d'erreur, utiliser le select natif
|
|
terminalSelect.innerHTML = '<option value="">Erreur de chargement - voir console</option>';
|
|
if (terminals && terminals.length > 0) {
|
|
terminals.forEach(terminal => {
|
|
const option = document.createElement('option');
|
|
option.value = terminal;
|
|
option.textContent = `Poste ${terminal}`;
|
|
terminalSelect.appendChild(option);
|
|
});
|
|
}
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('Erreur générale chargement des terminaux:', error);
|
|
// En cas d'erreur, utiliser le select natif
|
|
const terminalSelect = document.getElementById('terminal');
|
|
if (terminalSelect) {
|
|
terminalSelect.innerHTML = '<option value="">Erreur de chargement</option>';
|
|
}
|
|
}
|
|
}
|
|
|
|
// Valider que le terminal saisi existe dans la liste
|
|
function validateTerminal(terminal) {
|
|
return availableTerminals.map(t => t.toString()).includes(terminal.toString());
|
|
}
|
|
|
|
// === GESTION INDICATEUR SIGNALR ===
|
|
function updateSignalRIndicator(status) {
|
|
const indicator = document.getElementById('signalrIndicator');
|
|
const text = document.getElementById('signalrText');
|
|
|
|
if (!indicator || !text) return;
|
|
|
|
// Réinitialiser les classes
|
|
indicator.className = 'signalr-indicator';
|
|
|
|
switch(status) {
|
|
case 'connected':
|
|
indicator.classList.add('connected');
|
|
text.textContent = 'Connecté au serveur';
|
|
break;
|
|
case 'connecting':
|
|
indicator.classList.add('connecting');
|
|
text.textContent = 'Connexion en cours...';
|
|
break;
|
|
case 'disconnected':
|
|
indicator.classList.add('disconnected');
|
|
text.textContent = 'Serveur déconnecté';
|
|
break;
|
|
case 'error':
|
|
indicator.classList.add('error');
|
|
text.textContent = 'Erreur de connexion';
|
|
break;
|
|
case 'disabled':
|
|
indicator.classList.add('disabled');
|
|
text.textContent = 'SignalR désactivé';
|
|
break;
|
|
default:
|
|
text.textContent = 'État inconnu';
|
|
}
|
|
} |