// ================= VARIABLES GLOBALES ================= let currentExpert = null; let scenariosData = []; let calibrationData = { experts: [] }; const totalExperts = 14; const metrics = ['AR', 'AE', 'ESR', 'SDM', 'SM']; // ================= INITIALISATION ================= document.addEventListener('DOMContentLoaded', function() { console.log('Initialisation du formulaire d\'évaluation des experts...'); initializeUI(); loadAllData(); }); function initializeUI() { // Initialiser la grille d'experts avec des boutons vides const expertGrid = document.getElementById('expertGrid'); let html = ''; for (let i = 1; i <= totalExperts; i++) { html += `
Expert ${i}
`; } expertGrid.innerHTML = html; // Initialiser le texte de progression updateProgressText(0); } function updateProgressText(completedCount) { document.getElementById('progressText').textContent = `${completedCount}/${totalExperts} experts ont complété leur évaluation`; document.getElementById('progressFill').style.width = `${(completedCount / totalExperts) * 100}%`; } async function loadAllData() { showLoading(true); showInfo('Chargement des données en cours...'); try { // Charger les scénarios const scenariosResponse = await fetch('scenarios_list.json'); if (!scenariosResponse.ok) { throw new Error('scenarios_list.json non trouvé ou erreur de chargement'); } const scenariosJson = await scenariosResponse.json(); scenariosData = scenariosJson.scenarios || []; console.log(`${scenariosData.length} scénarios chargés`); // Charger ou créer les données de calibration await loadCalibrationData(); // Initialiser la liste des scénarios initializeScenarioList(); // Mettre à jour la grille des experts avec les données chargées updateExpertGrid(); showLoading(false); showSuccess('Données chargées avec succès'); } catch (error) { console.error('Erreur de chargement:', error); showLoading(false); showInfo(`Erreur lors du chargement: ${error.message}. Vous pouvez continuer avec des données vides.`); // Initialiser avec des données vides if (scenariosData.length === 0) { scenariosData = Array.from({length: 16}, (_, i) => ({ id: i + 1, title: `Scénario ${i + 1}` })); initializeScenarioList(); } updateExpertGrid(); } } async function loadCalibrationData() { try { // Essayer de charger depuis le localStorage d'abord const savedData = localStorage.getItem('calibration_trust_data'); if (savedData) { calibrationData = JSON.parse(savedData); console.log('Données de calibration chargées depuis localStorage:', calibrationData); return; } // Essayer de charger depuis le fichier try { const response = await fetch('calibration-trust.json'); if (response.ok) { calibrationData = await response.json(); console.log('Données de calibration chargées depuis fichier:', calibrationData); // Sauvegarder dans localStorage pour usage futur localStorage.setItem('calibration_trust_data', JSON.stringify(calibrationData)); } else { createEmptyCalibrationData(); } } catch (fileError) { console.log('Fichier calibration-trust.json non trouvé, création de nouvelles données'); createEmptyCalibrationData(); } } catch (error) { console.error('Erreur lors du chargement des données de calibration:', error); createEmptyCalibrationData(); } // S'assurer que nous avons des données pour tous les experts ensureAllExpertsExist(); } function createEmptyCalibrationData() { calibrationData = { experts: [] }; for (let i = 1; i <= totalExperts; i++) { calibrationData.experts.push({ expert_id: i, evaluations: [], last_updated: null }); } console.log('Nouvelles données de calibration créées'); } function ensureAllExpertsExist() { for (let i = 1; i <= totalExperts; i++) { const existingExpert = calibrationData.experts.find(e => e.expert_id === i); if (!existingExpert) { calibrationData.experts.push({ expert_id: i, evaluations: [], last_updated: null }); } } // Trier par ID d'expert calibrationData.experts.sort((a, b) => a.expert_id - b.expert_id); } function updateExpertGrid() { const expertGrid = document.getElementById('expertGrid'); let html = ''; let completedCount = 0; for (let i = 1; i <= totalExperts; i++) { const expert = calibrationData.experts.find(e => e.expert_id === i); const isCompleted = expert && expert.evaluations && expert.evaluations.length === scenariosData.length && expert.evaluations.every(e => metrics.every(m => e[m] !== null && e[m] !== undefined) ); const isCurrent = currentExpert === i; if (isCompleted) completedCount++; html += `
Expert ${i} ${isCompleted ? '✓' : ''}
`; } expertGrid.innerHTML = html; // Mettre à jour la barre de progression updateProgressText(completedCount); } function initializeScenarioList() { const scenarioList = document.getElementById('scenarioList'); let html = ''; scenariosData.forEach((scenario, index) => { html += `
${scenario.title || `Scénario ${scenario.id}`} S${scenario.id}
${metrics.map(metric => `
`).join('')}
`; }); scenarioList.innerHTML = html; } // ================= GESTION DES EXPERTS ================= function selectExpert(expertId) { currentExpert = expertId; document.getElementById('currentExpert').textContent = expertId; // Mettre à jour l'affichage des boutons d'experts const expertButtons = document.querySelectorAll('.expert-btn'); expertButtons.forEach(btn => { btn.classList.remove('active'); if (btn.textContent.includes(`Expert ${expertId}`)) { btn.classList.add('active'); } }); // Afficher le formulaire document.getElementById('evaluationForm').style.display = 'block'; document.getElementById('summaryPanel').classList.remove('active'); // Charger les évaluations existantes loadExpertEvaluations(expertId); } function loadExpertEvaluations(expertId) { const expert = calibrationData.experts.find(e => e.expert_id === expertId); if (!expert || !expert.evaluations || expert.evaluations.length === 0) { // Réinitialiser tous les champs resetForm(); showInfo(`Aucune évaluation trouvée pour l'expert ${expertId}. Commencez une nouvelle évaluation.`); return; } // Remplir les champs avec les évaluations existantes let loadedCount = 0; expert.evaluations.forEach(evaluation => { metrics.forEach(metric => { const selectElement = document.getElementById(`metric-${evaluation.scenario_id}-${metric}`); if (selectElement && evaluation[metric]) { selectElement.value = evaluation[metric]; updateMetricColor(selectElement, evaluation.scenario_id, metric); loadedCount++; } }); }); showSuccess(`${loadedCount} évaluations chargées pour l'expert ${expertId}`); } // ================= GESTION DU FORMULAIRE ================= function updateMetricColor(selectElement, scenarioId, metric) { const value = parseInt(selectElement.value); selectElement.className = ''; if (value >= 4) { selectElement.classList.add('high'); } else if (value >= 3) { selectElement.classList.add('medium'); } else if (value >= 1) { selectElement.classList.add('low'); } } function resetForm() { if (!currentExpert) { showInfo('Veuillez d\'abord sélectionner un expert.'); return; } // Réinitialiser tous les champs de sélection const selectElements = document.querySelectorAll('.metric-input select'); selectElements.forEach(select => { select.value = ''; select.className = ''; }); showInfo('Formulaire réinitialisé. Tous les champs sont vides.'); } async function saveEvaluation() { if (!currentExpert) { showInfo('Veuillez d\'abord sélectionner un expert.'); return; } // Collecter toutes les évaluations const evaluations = []; let allFilled = true; let emptyCount = 0; let filledCount = 0; scenariosData.forEach(scenario => { const evaluation = { scenario_id: scenario.id }; metrics.forEach(metric => { const selectElement = document.getElementById(`metric-${scenario.id}-${metric}`); const value = selectElement ? parseInt(selectElement.value) : null; if (value && !isNaN(value) && value >= 1 && value <= 5) { evaluation[metric] = value; filledCount++; } else { evaluation[metric] = null; allFilled = false; emptyCount++; } }); evaluations.push(evaluation); }); if (filledCount === 0) { showInfo('Aucune évaluation saisie. Veuillez remplir au moins un champ.'); return; } if (!allFilled) { const confirmSave = confirm(`Attention : ${emptyCount} champs sur ${scenariosData.length * 5} ne sont pas remplis. Voulez-vous quand même sauvegarder ?`); if (!confirmSave) { return; } } // Mettre à jour les données de calibration const expertIndex = calibrationData.experts.findIndex(e => e.expert_id === currentExpert); if (expertIndex !== -1) { calibrationData.experts[expertIndex].evaluations = evaluations; calibrationData.experts[expertIndex].last_updated = new Date().toISOString(); } // Sauvegarder dans le localStorage localStorage.setItem('calibration_trust_data', JSON.stringify(calibrationData)); // Sauvegarder dans le fichier calibration-trust.json await saveCalibrationToFile(); // Mettre à jour l'interface updateExpertGrid(); showSummary(); showSuccess(`Évaluations sauvegardées pour l'expert ${currentExpert} ! ${filledCount} valeurs enregistrées.`); } async function saveCalibrationToFile() { try { // Créer un objet Blob avec les données const dataStr = JSON.stringify(calibrationData, null, 2); const dataBlob = new Blob([dataStr], { type: 'application/json' }); // Créer un lien de téléchargement const downloadLink = document.createElement('a'); downloadLink.href = URL.createObjectURL(dataBlob); downloadLink.download = 'calibration-trust.json'; // Déclencher le téléchargement document.body.appendChild(downloadLink); downloadLink.click(); document.body.removeChild(downloadLink); console.log('Données de calibration sauvegardées dans calibration-trust.json'); } catch (error) { console.error('Erreur lors de la sauvegarde du fichier:', error); showInfo('Les données ont été sauvegardées localement mais une erreur est survenue lors de l\'export du fichier.'); } } // ================= RÉSUMÉ ET ANALYSE ================= function showSummary() { if (!currentExpert) return; const expert = calibrationData.experts.find(e => e.expert_id === currentExpert); if (!expert || !expert.evaluations || expert.evaluations.length === 0) { showInfo('Aucune évaluation à afficher.'); return; } // Calculer les statistiques const stats = calculateExpertStatistics(expert); // Mettre à jour le panneau de résumé const summaryGrid = document.getElementById('summaryGrid'); summaryGrid.innerHTML = `

Scénarios évalués

${stats.completedScenarios}/${scenariosData.length}
${stats.completionRate}% complétés

Moyenne AR

${stats.averages.AR.toFixed(2)}
/ 5.0

Moyenne AE

${stats.averages.AE.toFixed(2)}
/ 5.0

Moyenne ESR

${stats.averages.ESR.toFixed(2)}
/ 5.0

Moyenne SDM

${stats.averages.SDM.toFixed(2)}
/ 5.0

Moyenne SM

${stats.averages.SM.toFixed(2)}
/ 5.0

Indice Global

${stats.globalIndex.toFixed(2)}
/ 5.0

Dernière mise à jour

${stats.lastUpdated ? new Date(stats.lastUpdated).toLocaleDateString('fr-FR') : 'N/A'}
Date
`; // Afficher le panneau document.getElementById('summaryPanel').classList.add('active'); document.getElementById('evaluationForm').style.display = 'none'; } function calculateExpertStatistics(expert) { const evaluations = expert.evaluations; // Compter les scénarios complètement évalués (toutes les métriques remplies) const completedScenarios = evaluations.filter(e => metrics.every(m => e[m] !== null && e[m] !== undefined) ).length; const completionRate = scenariosData.length > 0 ? ((completedScenarios / scenariosData.length) * 100).toFixed(1) : '0.0'; // Calculer les moyennes par métrique const averages = {}; metrics.forEach(metric => { const values = evaluations .map(e => e[metric]) .filter(v => v !== null && v !== undefined && !isNaN(v)); averages[metric] = values.length > 0 ? values.reduce((sum, val) => sum + val, 0) / values.length : 0; }); // Calculer l'indice global (moyenne des moyennes) const metricValues = Object.values(averages).filter(v => v > 0); const globalIndex = metricValues.length > 0 ? metricValues.reduce((sum, val) => sum + val, 0) / metricValues.length : 0; return { completedScenarios, completionRate, averages, globalIndex, lastUpdated: expert.last_updated }; } function showConsensusAnalysis() { // Sauvegarder d'abord les données actuelles saveCalibrationToFile(); // Rediriger vers la page d'analyse du consensus window.location.href = 'consensus_building.html?fromEvaluation=true'; } function exportCalibrationData() { saveCalibrationToFile(); showSuccess('Données de calibration exportées dans calibration-trust.json !'); } // ================= FONCTIONS UTILITAIRES ================= function showLoading(show) { document.getElementById('loading').style.display = show ? 'block' : 'none'; } function showInfo(message) { const alertBox = document.getElementById('infoAlert'); const messageElement = document.getElementById('infoMessage'); if (messageElement) { messageElement.textContent = message; } if (alertBox) { alertBox.style.display = 'block'; setTimeout(() => { alertBox.style.display = 'none'; }, 5000); } } function showSuccess(message) { const alertBox = document.getElementById('successAlert'); const messageElement = document.getElementById('successMessage'); if (messageElement) { messageElement.textContent = message; } if (alertBox) { alertBox.style.display = 'block'; setTimeout(() => { alertBox.style.display = 'none'; }, 5000); } } // ================= FONCTIONS D'EXPORT ================= window.resetForm = resetForm; window.saveEvaluation = saveEvaluation; window.selectExpert = selectExpert; window.updateMetricColor = updateMetricColor; window.showConsensusAnalysis = showConsensusAnalysis; window.exportCalibrationData = exportCalibrationData;