1/** 2 * Screen: export (Export PDF) 3 * Route: 'export' 4 * FULL PREMIUM â aperçu du rapport + bouton impression + contenu print-friendly 5 */ 6(function () { 7 'use strict'; 8 9 function render(el) { 10 App.trackEvent('pdf_export', {}); 11 12 var profile = Storage.getProfile(); 13 var calculations = Storage.getCalculations() || []; 14 var today = _formatDate(new Date()); 15 16 var hasProfile = profile && profile.weight_kg && profile.height_cm && profile.age; 17 18 // Calculs pour le rapport 19 var reportData = hasProfile ? _buildReportData(profile, calculations) : null; 20 21 el.innerHTML = 22 '<div class="bsc-export">' + 23 24 '<header class="bsc-screen-header">' + 25 '<button class="bsc-back-btn" id="bsc-exp-back" aria-label="Retour">â</button>' + 26 '<h1 class="bsc-screen-title">Exporter mon bilan</h1>' + 27 '</header>' + 28 29 // Carte aperçu 30 '<section class="bsc-card bsc-exp-preview">' + 31 '<h2 class="bsc-card-title">Aperçu du rapport</h2>' + 32 '<div class="bsc-exp-preview-card">' + 33 '<div class="bsc-exp-preview-header">' + 34 '<div class="bsc-exp-preview-logo">BSC</div>' + 35 '<div class="bsc-exp-preview-meta">' + 36 '<strong>Bilan Santé Complet</strong>' + 37 '<span>' + today + '</span>' + 38 '</div>' + 39 '</div>' + 40 '<div class="bsc-exp-preview-author">Préparé avec MaCalculatriceEnLigne â document indicatif, ne remplace pas l\'avis d\'un professionnel de santé</div>' + 41 (reportData 42 ? _renderPreviewContent(reportData) 43 : '<p class="bsc-exp-no-profile">Complétez votre profil pour générer un bilan complet.</p>' 44 ) + 45 '</div>' + 46 '</section>' + 47 48 '<section class="bsc-card bsc-exp-actions">' + 49 '<button class="bsc-btn bsc-btn--primary bsc-btn--full bsc-btn--cta" id="bsc-exp-print">' + 50 'ð¨ Imprimer / Sauvegarder en PDF' + 51 '</button>' + 52 '<p class="bsc-exp-print-hint">Astuce\u00a0: dans la boîte de dialogue d\'impression, choisissez «\u00a0Enregistrer au format PDF\u00a0» comme destination.</p>' + 53 '</section>' + 54 55 _ymyl() + 56 57 '</div>' + 58 59 // Contenu masqué destiné à l'impression 60 (reportData ? _buildPrintContent(reportData, today) : ''); 61 62 el.querySelector('#bsc-exp-back').addEventListener('click', function () { App.navigate('home'); }); 63 el.querySelector('#bsc-exp-print').addEventListener('click', function () { 64 window.print(); 65 }); 66 } 67 68 function _buildReportData(profile, calculations) { 69 var imc = Formulas.imcStandard(profile.weight_kg, profile.height_cm); 70 var category = Formulas.omsCategoryLabel(imc); 71 var ageInterp = Formulas.ageAdjustedInterpretation(imc, profile.age); 72 var bmr = Formulas.bmrMifflin(profile.weight_kg, profile.height_cm, profile.age, profile.sex); 73 var pal = Formulas.getPalMultiplier(profile.activity_level); 74 var tdeeVal = Formulas.tdee(bmr, pal); 75 var goal = profile.goal || 'maintain'; 76 var calories = Formulas.calorieTarget(tdeeVal, goal, profile.deficit_kcal || 500); 77 var score = Formulas.healthScore(profile); 78 var lancet = score.lancet; 79 80 var hM = profile.height_cm / 100; 81 var omsLow = Math.round(18.5 * hM * hM * 10) / 10; 82 var omsHigh = Math.round(24.9 * hM * hM * 10) / 10; 83 84 // Projection 85 var projData = null; 86 if (goal !== 'maintain') { 87 var target = profile.target_weight || (goal === 'lose' ? Math.max(profile.weight_kg - 10, 40) : profile.weight_kg + 5); 88 var projRaw = Formulas.weightProjection(profile, target, profile.deficit_kcal || 500, 52); 89 if (projRaw.length > 0) { 90 projData = { weeks: projRaw[projRaw.length - 1].week, target: target }; 91 } 92 } 93 94 return { 95 profile: profile, 96 imc: Math.round(imc * 10) / 10, 97 category: category, 98 ageInterp: ageInterp, 99 bmr: Math.round(bmr), 100 tdee: Math.round(tdeeVal), 101 calories: Math.round(calories), 102 goal: goal, 103 score: score, 104 lancet: lancet, 105 omsLow: omsLow, 106 omsHigh: omsHigh, 107 projection: projData 108 }; 109 } 110 111 function _renderPreviewContent(d) { 112 var rows = [ 113 ['IMC standard (OMS)', d.imc + ' â ' + _esc(d.category)], 114 ['IMC (classification OMS)', d.ageInterp.label],
115 ['Métabolisme basal (Mifflin, estimation)', d.bmr + ' kcal/j'], 116 ['Dépense totale (TDEE, estimation)', d.tdee + ' kcal/j'], 117 ['Objectif calorique (estimation)', d.calories + ' kcal/j'], 118 ['Score santé global', d.score.total + '/100 â ' + d.score.interpretation], 119 ['Commission du Lancet 2025', d.lancet.label], 120 ['Poids correspondant à l\'éventail normal de l\'OMS (IMC 18,5â24,9)', d.omsLow + ' â ' + d.omsHigh + ' kg'] 121 ]; 122 123 if (d.projection) { 124 rows.push(['Projection objectif (estimation)', d.projection.target + ' kg en ' + d.projection.weeks + ' sem.']); 125 } 126 127 return ( 128 '<table class="bsc-exp-preview-table">' + 129 rows.map(function (r) { 130 return '<tr><td class="bsc-exp-preview-key">' + _esc(r[0]) + '</td><td class="bsc-exp-preview-val">' + _esc(r[1]) + '</td></tr>'; 131 }).join('') + 132 '</table>' 133 ); 134 } 135 136 function _buildPrintContent(d, today) { 137 var profile = d.profile; 138 var sexLabel = profile.sex === 'male' ? 'Homme' : 'Femme'; 139 140 return ( 141 '<div class="bsc-print-content" aria-hidden="true">' + 142 '<div class="bsc-print-header">' + 143 '<h1>Bilan Santé Complet</h1>' + 144 '<p>Généré le ' + today + '</p>' + 145 '<p>Préparé avec MaCalculatriceEnLigne â document indicatif, ne remplace pas l\'avis d\'un professionnel de santé</p>' + 146 '</div>' + 147 148 '<section class="bsc-print-section">' + 149 '<h2>Profil</h2>' + 150 '<table class="bsc-print-table">' + 151 '<tr><td>Sexe</td><td>' + _esc(sexLabel) + '</td></tr>' + 152 '<tr><td>Ãge</td><td>' + profile.age + ' ans</td></tr>' + 153 '<tr><td>Taille</td><td>' + profile.height_cm + ' cm</td></tr>' + 154 '<tr><td>Poids actuel</td><td>' + profile.weight_kg + ' kg</td></tr>' + 155 (profile.waist_cm ? '<tr><td>Tour de taille</td><td>' + profile.waist_cm + ' cm</td></tr>' : '') + 156 (profile.body_fat_pct ? '<tr><td>Masse grasse</td><td>' + profile.body_fat_pct + ' %</td></tr>' : '') + 157 '</table>' + 158 '</section>' + 159 160 '<section class="bsc-print-section">' + 161 '<h2>IMC</h2>' + 162 '<table class="bsc-print-table">' + 163 '<tr><td>IMC standard (OMS)</td><td>' + d.imc + ' â ' + _esc(d.category) + '</td></tr>' + 164 '<tr><td>IMC (classification OMS)</td><td>' + _esc(d.ageInterp.label) + '</td></tr>' + 165 '</table>' + 166 '<p>Selon la classification de l\'adulte de l\'OMS (rapport technique n° 894, 2000), un IMC de ' + d.imc + ' correspond à la catégorie « ' + _esc(d.category) + ' ». Cette classification n\'est pas un diagnostic.</p>' + 167 '</section>' + 168 169 '<section class="bsc-print-section">' + 170 '<h2>Métabolisme & Calories</h2>' + 171 '<table class="bsc-print-table">' + 172 '<tr><td>Métabolisme basal (Mifflin-St Jeor, estimation)</td><td>' + d.bmr + ' kcal/j</td></tr>' + 173 '<tr><td>Dépense énergétique totale (TDEE, estimation)</td><td>' + d.tdee + ' kcal/j</td></tr>' + 174 '<tr><td>Objectif calorique (' + _goalLabel(d.goal) + ', estimation)</td><td>' + d.calories + ' kcal/j</td></tr>' + 175 '<tr><td>Poids correspondant à l\'éventail normal de l\'OMS (IMC 18,5â24,9)</td><td>' + d.omsLow + ' â ' + d.omsHigh + ' kg</td></tr>' + 176 '</table>' + 177 '</section>' + 178 179 '<section class="bsc-print-section">' + 180 '<h2>Score Santé â ' + d.score.total + '/100 (' + _esc(d.score.interpretation) + ')</h2>' + 181 '<table class="bsc-print-table">' + 182 d.score.components.map(function (c) { 183 return '<tr><td>' + _esc(c.name) + '</td><td>' + c.score + '/' + c.max + ' â ' + _esc(c.interpretation) + '</td></tr>'; 184 }).join('') + 185 '</table>' + 186 '</section>' + 187 188 '<section class="bsc-print-section">' + 189 '<h2>Commission du Lancet 2025</h2>' + 190 '<p><strong>' + _esc(d.lancet.label) + '</strong></p>' + 191 '<p>' + _esc(d.lancet.description) + '</p>' + 192 '</section>' + 193 194 (d.projection 195 ? '<section class="bsc-print-section">' + 196 '<h2>Projection de poids</h2>' + 197 '<p>Objectif : ' + d.projection.target + ' kg en environ ' + d.projection.weeks + ' semaines (estimation).</p>' + 198 '<p>Cette projection repose sur une règle simplifiée (7 700 kcal â 1 kg). Selon Hall et al. (Lancet 2011), une prédiction précise de l\'évolution du poids doit tenir compte de l\'adaptation de la dépense énergétique, et la réponse du poids à un changement d\'apport est lente : le résultat réel peut différer.</p>' + 199 '</section>' 200 : '' 201 ) + 202 203 '<footer class="bsc-print-footer">' + 204 '<p><strong>Avertissement médical :</strong> Ce rapport fournit des estimations à titre informatif uniquement. ' + 205 'Il ne constitue pas un avis médical, un diagnostic ou un traitement. ' + 206 'Seul un médecin (ou un diététicien) peut interpréter ces résultats.</p>' + 207 '<p>Généré par macalculatriceenligne.com â Données stockées uniquement sur votre appareil (RGPD).</p>' + 208 '</footer>' + 209 210 '</div>' 211 ); 212 } 213 214 function _formatDate(d) { 215 var day = String(d.getDate()).padStart(2, '0');
216 var month = String(d.getMonth() + 1).padStart(2, '0'); 217 var year = d.getFullYear(); 218 return day + '/' + month + '/' + year; 219 } 220 221 function _goalLabel(goal) { 222 var map = { maintain: 'maintien', lose: 'perte de poids', gain: 'prise de poids' }; 223 return map[goal] || goal; 224 } 225 226 function _esc(str) { 227 if (str == null) return ''; 228 return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); 229 } 230 231 function _ymyl() { 232 return '<p class="bsc-ymyl-disclaimer">Ce rapport fournit des estimations à titre informatif uniquement. Il ne constitue pas un avis médical, un diagnostic ou un traitement. Seul un médecin (ou un diététicien) peut interpréter ces résultats.</p>'; 233 } 234 235 App.registerScreen('export', render); 236 237})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.