1/* Bưá»c Äá» xuất nhúng và o luá»ng ÄÄng ký tại trưá»ng. 2 Phần quyết Äá»nh dùng trá»±c tiếp bá» luáºt cá»§a trang de-xuat-xet-tuyen.html Äá» 3 hai nÆ¡i không thá» tÃnh ra hai phương án khác nhau từ cùng má»t bá» Äiá»m. */ 4import { 5 MON_TRU_KHOI_TB, 6 SO_MON_LOP12, 7 MON_THI_BAT_BUOC, 8 MON_THI_TU_CHON, 9 soDiem, 10 hienDiem, 11 layMonPT2, 12 timToHopPT2, 13 soMonXet, 14 tinhTbLop12, 15 tinhTbThiTN, 16 xepDeXuat 17} from './de-xuat-xet-tuyen.js?v=20260817-3'; 18import { TEN_PHUONG_THUC } from './to-hop-xet-tuyen.js?v=20260817-2'; 19 20const escapeHtml = (value) => String(value ?? '') 21 .replace(/&/g, '&') 22 .replace(/</g, '<') 23 .replace(/>/g, '>') 24 .replace(/"/g, '"') 25 .replace(/'/g, '''); 26 27const state = { 28 level: '', 29 skipPt2: false 30}; 31 32const getLevel = () => document.getElementById('nganh')?.selectedOptions?.[0]?.dataset.trinhdo || ''; 33 34const clearAppliedSelection = () => { 35 if (!document.body.classList.contains('registration-at-school')) return; 36 const method = document.getElementById('phuongthuc'); 37 const combination = document.getElementById('tohop'); 38 if (method) method.value = ''; 39 if (combination) combination.value = ''; 40 [1, 2, 3].forEach((index) => { 41 const input = document.getElementById(`diem_m${index}`); 42 if (input) input.value = ''; 43 }); 44}; 45 46const hideResult = (container) => { 47 const result = container.querySelector('#at_school_rec_result'); 48 if (!result) return; 49 result.hidden = true; 50 result.innerHTML = ''; 51}; 52 53const invalidateResult = (container) => { 54 hideResult(container); 55 clearAppliedSelection(); 56}; 57 58const renderShell = (container) => { 59 container.innerHTML = ` 60 <div class="at-school-auto-head"> 61 <i class="fa-solid fa-wand-magic-sparkles"></i> 62 <div> 63 <h3 id="tai-truong-auto-title">Äá» xuất phương thức và tá» hợp</h3> 64 <p>Dùng cùng quy trình và cách tÃnh cá»§a mục âÄá» xuất phương thức & tá» hợpâ.</p> 65 </div> 66 </div> 67 68 <section class="at-school-rec-step" id="at_school_rec_pt2"> 69 <h4><i class="fa-solid fa-book"></i> 1. Lá»p 12 há»c những môn nà o?</h4> 70 <p class="at-school-rec-sub">Chá»n những môn có há»c và có Äiá»m trong há»c bạ lá»p 12, rá»i nháºp Äiá»m trung bình cả nÄm cá»§a môn Äó.</p> 71 <div id="at_school_rec_subjects"></div> 72 <label class="at-school-rec-skip"> 73 <input type="checkbox" id="at_school_rec_skip_pt2"> 74 <span>Không há»c nhóm môn nà y â bá» qua xét há»c bạ PT2</span> 75 </label> 76 <div class="at-school-rec-note" id="at_school_rec_pt2_note" hidden></div> 77 <button type="button" class="at-school-rec-secondary" id="at_school_rec_open_pt3"> 78 <i class="fa-solid fa-plus"></i> TÃnh thêm phương thức kết hợp PT3 79 </button> 80 </section> 81 82 <section class="at-school-rec-step" id="at_school_rec_pt3" hidden> 83 <h4><i class="fa-solid fa-calculator"></i> 2. Äiá»m cho phương thức kết hợp và Äiá»m thi</h4> 84 <p class="at-school-rec-sub">PT3 dùng Äiá»m trung bình cả nÄm lá»p 12, <b class="at-school-rec-danger">không tÃnh ${escapeHtml(MON_TRU_KHOI_TB)}</b>.</p> 85 <label for="at_school_rec_subject_count">Lá»p 12 có bao nhiêu môn có Äiá»m sau khi trừ GDQP-AN?</label> 86 <select class="form-control" id="at_school_rec_subject_count"> 87 <option value="">-- Chá»n sá» môn --</option> 88 ${SO_MON_LOP12.map(number => `<option value="${number}">${number} môn</option>`).join('')} 89 </select> 90 <div id="at_school_rec_grade12_scores"></div> 91 <div class="at-school-rec-average">Trung bình cả nÄm lá»p 12: <b id="at_school_rec_grade12_average">chưa Äá»§ Äiá»m</b></div> 92 93 <p class="at-school-rec-exam-title"><b>Äiá»m thi tá»t nghiá»p THPT</b> â Äúng 4 môn: Toán, Ngữ vÄn và hai môn tá»± chá»n.</p> 94 <div id="at_school_rec_exam_scores"></div> 95 <div class="at-school-rec-average">Trung bình 4 môn thi tá»t nghiá»p: <b id="at_school_rec_exam_average">
95chưa Äá»§ 4 môn</b></div> 96 </section> 97 98 <button type="button" class="at-school-auto-action" id="at_school_rec_calculate"> 99 <i class="fa-solid fa-ranking-star"></i> Xem Äá» xuất và áp dụng 100 </button> 101 <div class="at-school-auto-result" id="at_school_rec_result" hidden aria-live="polite"></div>`; 102}; 103 104const getSelectedPt2Subjects = (container) => state.skipPt2 105 ? [] 106 : [...container.querySelectorAll('.at-school-rec-subject:checked')].map(input => input.value); 107 108const getTranscriptScores = (container) => { 109 const scores = {}; 110 if (state.skipPt2) return scores; 111 container.querySelectorAll('.at-school-rec-transcript-score').forEach((input) => { 112 if (!input.disabled && soDiem(input.value) !== null) scores[input.dataset.subject] = soDiem(input.value); 113 }); 114 return scores; 115}; 116 117const updatePt2Note = (container) => { 118 const note = container.querySelector('#at_school_rec_pt2_note'); 119 if (!note) return; 120 if (state.skipPt2) { 121 note.hidden = false; 122 note.className = 'at-school-rec-note is-warning'; 123 note.innerHTML = `<b>Äã bá» qua phương thức xét há»c bạ PT2.</b><br> 124 Tiếp tục nháºp Äiá»m á» phần phương thức kết hợp PT3 bên dưá»i.`; 125 return; 126 } 127 128 const selected = getSelectedPt2Subjects(container); 129 if (!selected.length) { 130 note.hidden = true; 131 return; 132 } 133 const combinations = timToHopPT2(state.level, selected); 134 note.hidden = false; 135 note.className = `at-school-rec-note ${combinations.length ? 'is-success' : 'is-warning'}`; 136 note.innerHTML = combinations.length 137 ? `<b>Dùng ÄÆ°á»£c phương thức xét há»c bạ PT2.</b><br> 138 Ghép ÄÆ°á»£c ${combinations.length} tá» hợp: ${combinations.map(item => escapeHtml(item.value)).join(' · ')}.` 139 : `<b>Chưa ghép ÄÆ°á»£c tá» hợp PT2.</b><br> 140 Báºc nà y cần Äá»§ ${soMonXet(state.level)} môn trong cùng má»t tá» hợp; vẫn có thá» xét bằng PT3.`; 141}; 142 143const renderPt2Subjects = (container) => { 144 const host = container.querySelector('#at_school_rec_subjects'); 145 if (!host || !state.level) return; 146 host.innerHTML = layMonPT2(state.level).map((subject) => ` 147 <label class="at-school-rec-subject-row"> 148 <input type="checkbox" class="at-school-rec-subject" value="${escapeHtml(subject)}"${subject === 'Toán' ? ' checked' : ''}> 149 <span>${escapeHtml(subject)}</span> 150 <input type="text" inputmode="decimal" autocomplete="off" 151 class="at-school-rec-transcript-score" data-subject="${escapeHtml(subject)}" 152 placeholder="Äiá»m TB cả nÄm"${subject === 'Toán' ? '' : ' disabled'}> 153 </label>`).join('') 154 + `<div class="at-school-rec-note is-info">Má»i tá» hợp Äá»u có môn Toán nên Toán ÄÆ°á»£c chá»n sẵn.</div>`; 155 updatePt2Note(container); 156}; 157 158const updateGrade12Average = (container) => { 159 const scores = [...container.querySelectorAll('.at-school-rec-grade12-score')].map(input => input.value); 160 const average = tinhTbLop12(scores); 161 const output = container.querySelector('#at_school_rec_grade12_average'); 162 if (output) output.textContent = average === null ? 'chưa Äá»§ Äiá»m' : hienDiem(average); 163}; 164 165const renderGrade12Scores = (container) => { 166 const host = container.querySelector('#at_school_rec_grade12_scores'); 167 const count = Number(container.querySelector('#at_school_rec_subject_count')?.value) || 0; 168 if (!host) return; 169 if (!count) { 170 host.innerHTML = ''; 171 updateGrade12Average(container); 172 return; 173 } 174 175 const transcript = getTranscriptScores(container); 176 const knownSubjects = ['Toán', ...Object.keys(transcript).filter(subject => subject !== 'Toán')]; 177 host.innerHTML = Array.from({ length: count }, (_, index) => { 178 const subject = knownSubjects[index] || ''; 179 const value = subject && transcript[subject] !== undefined ? hienDiem(transcript[subject]) : ''; 180 return `<div class="at-school-rec-score-row">
181 <span>${escapeHtml(subject || `Môn thứ ${index + 1}`)}</span> 182 <input type="text" inputmode="decimal" autocomplete="off" 183 class="at-school-rec-grade12-score"${index === 0 ? ' id="at_school_rec_grade12_math"' : ''} 184 value="${escapeHtml(value)}" placeholder="Äiá»m TB cả nÄm"> 185 </div>`; 186 }).join('') + `<div class="at-school-rec-note is-warning"><b>Nháºp Äá»§ ${count} môn, không nháºp ${escapeHtml(MON_TRU_KHOI_TB)}.</b></div>`; 187 updateGrade12Average(container); 188}; 189 190const updateExamAverage = (container) => { 191 const scores = [...container.querySelectorAll('.at-school-rec-exam-score')].map(input => input.value); 192 const average = tinhTbThiTN(scores); 193 const output = container.querySelector('#at_school_rec_exam_average'); 194 if (output) output.textContent = average === null ? 'chưa Äá»§ 4 môn' : hienDiem(average); 195}; 196 197const renderExamScores = (container) => { 198 const host = container.querySelector('#at_school_rec_exam_scores'); 199 if (!host || host.children.length) return; 200 host.innerHTML = MON_THI_BAT_BUOC.map(subject => ` 201 <div class="at-school-rec-score-row"> 202 <span>${escapeHtml(subject)}</span> 203 <input type="text" inputmode="decimal" autocomplete="off" 204 class="at-school-rec-exam-score" data-subject="${escapeHtml(subject)}" placeholder="Äiá»m thi"> 205 </div>`).join('') 206 + [1, 2].map(index => ` 207 <div class="at-school-rec-score-row has-select"> 208 <select class="at-school-rec-exam-subject" data-slot="${index}"> 209 <option value="">-- Môn tá»± chá»n ${index} --</option> 210 ${MON_THI_TU_CHON.map(subject => `<option value="${escapeHtml(subject)}">${escapeHtml(subject)}</option>`).join('')} 211 </select> 212 <input type="text" inputmode="decimal" autocomplete="off" 213 class="at-school-rec-exam-score" data-slot="${index}" placeholder="Äiá»m thi"> 214 </div>`).join('') 215 + `<div class="at-school-rec-note is-info">Chưa thi thì Äá» trá»ng cả bá»n ô; há» thá»ng vẫn xét các phương án không cần Äiá»m thi.</div>`; 216 updateExamAverage(container); 217}; 218 219const openPt3 = (container) => { 220 const section = container.querySelector('#at_school_rec_pt3'); 221 if (section) section.hidden = false; 222 renderExamScores(container); 223}; 224 225const setSkipPt2 = (container, skip) => { 226 state.skipPt2 = Boolean(skip); 227 const host = container.querySelector('#at_school_rec_subjects'); 228 host?.classList.toggle('is-disabled', state.skipPt2); 229 host?.querySelectorAll('.at-school-rec-subject').forEach((input) => { 230 input.disabled = state.skipPt2; 231 }); 232 host?.querySelectorAll('.at-school-rec-transcript-score').forEach((input) => { 233 const checked = host.querySelector(`.at-school-rec-subject[value="${CSS.escape(input.dataset.subject || '')}"]`)?.checked; 234 input.disabled = state.skipPt2 || !checked; 235 }); 236 updatePt2Note(container); 237 if (state.skipPt2) openPt3(container); 238}; 239 240const collectData = (container) => { 241 const transcript = getTranscriptScores(container); 242 if (transcript.Toán === undefined) { 243 const math = soDiem(container.querySelector('#at_school_rec_grade12_math')?.value); 244 if (math !== null) transcript.Toán = math; 245 } 246 247 const exam = {}; 248 container.querySelectorAll('.at-school-rec-exam-score').forEach((input) => { 249 const subject = input.dataset.subject 250 || container.querySelector(`.at-school-rec-exam-subject[data-slot="${input.dataset.slot || ''}"]`)?.value 251 || ''; 252 const score = soDiem(input.value); 253 if (subject && score !== null) exam[subject] = score; 254 }); 255 256 const grade12Scores = [...container.querySelectorAll('.at-school-rec-grade12-score')].map(input => input.value); 257 const examScores = [...container.querySelectorAll('.at-school-rec-exam-score')].map(input => input.value); 258 return { 259 hocBa: transcript, 260 tbLop12: tinhTbLop12(grade12Scores), 261 thiTN: exam, 262 tbThiTN: tinhTbThiTN(examScores) 263 }; 264}; 265
266const applyRecommendation = (top) => { 267 const method = document.getElementById('phuongthuc'); 268 const combination = document.getElementById('tohop'); 269 if (!method || !combination || !top) return false; 270 271 method.value = top.pt; 272 window.handleNganhVaPhuongThucChange?.(); 273 if (![...combination.options].some(option => option.value === top.toHop)) return false; 274 combination.value = top.toHop; 275 window.handleToHopChange?.(); 276 top.chiTiet.forEach((item, index) => { 277 const input = document.getElementById(`diem_m${index + 1}`); 278 if (input) input.value = hienDiem(item.diem); 279 }); 280 window.updateScoreLive?.(); 281 return true; 282}; 283 284const renderRecommendation = (container) => { 285 const result = container.querySelector('#at_school_rec_result'); 286 if (!result || !state.level) return; 287 if (!timToHopPT2(state.level, getSelectedPt2Subjects(container)).length) openPt3(container); 288 289 const { du, thieu } = xepDeXuat(state.level, collectData(container)); 290 result.hidden = false; 291 if (!du.length) { 292 clearAppliedSelection(); 293 const missing = [...new Set(thieu.flatMap(item => item.thieu))]; 294 result.className = 'at-school-auto-result is-error'; 295 result.innerHTML = `<b>Chưa tÃnh ÄÆ°á»£c phương án vì còn thiếu Äiá»m.</b> 296 ${missing.length ? `<br><small>Thiếu: ${escapeHtml(missing.join(', '))}</small>` : ''}`; 297 return; 298 } 299 300 const top = du[0]; 301 if (!applyRecommendation(top)) { 302 result.className = 'at-school-auto-result is-error'; 303 result.innerHTML = '<b>Không áp dụng ÄÆ°á»£c tá» hợp Äá» xuất và o há» sÆ¡.</b>'; 304 return; 305 } 306 307 const remaining = du.slice(1); 308 result.className = 'at-school-auto-result'; 309 result.innerHTML = ` 310 <div class="at-school-rec-result-head"> 311 <div> 312 <span>Nên chá»n</span> 313 <b>${escapeHtml(top.pt)} â ${escapeHtml(TEN_PHUONG_THUC[top.pt] || top.pt)}</b> 314 <strong>${escapeHtml(top.toHop)}</strong> 315 </div> 316 <em>${hienDiem(top.tongCacMon)}</em> 317 </div> 318 <div class="at-school-rec-result-detail">${top.chiTiet.map(item => `${escapeHtml(item.mon)}: <b>${hienDiem(item.diem)}</b>`).join(' · ')} 319 <br>Trung bình: <b>${hienDiem(top.diemTb)}</b></div> 320 <p><i class="fa-solid fa-circle-check"></i> Äã áp dụng phương thức, tá» hợp và Äiá»m và o há» sÆ¡ tại trưá»ng.</p> 321 ${remaining.length ? `<details><summary>Xem ${remaining.length} phương án Äá»§ Äiá»m còn lại</summary> 322 ${remaining.map(item => `<div class="at-school-rec-other"><b>${escapeHtml(item.pt)}</b> â ${escapeHtml(item.toHop)}: ${hienDiem(item.tongCacMon)}</div>`).join('')} 323 </details>` : ''}`; 324}; 325 326const resetForMajor = (container) => { 327 state.level = getLevel(); 328 state.skipPt2 = false; 329 renderShell(container); 330 renderPt2Subjects(container); 331 clearAppliedSelection(); 332}; 333 334const mountAtSchoolRecommendation = () => { 335 const container = document.getElementById('tai-truong-auto-xet-tuyen'); 336 if (!container) return; 337 resetForMajor(container); 338 339 container.addEventListener('input', (event) => { 340 invalidateResult(container); 341 if (event.target.matches('.at-school-rec-transcript-score')) updatePt2Note(container); 342 if (event.target.matches('.at-school-rec-grade12-score')) updateGrade12Average(container); 343 if (event.target.matches('.at-school-rec-exam-score')) updateExamAverage(container); 344 }); 345 346 container.addEventListener('change', (event) => { 347 invalidateResult(container); 348 if (event.target.matches('.at-school-rec-subject')) { 349 const score = [...container.querySelectorAll('.at-school-rec-transcript-score')] 350 .find(input => input.dataset.subject === event.target.value); 351 if (score) { 352 score.disabled = !event.target.checked; 353 if (!event.target.checked) score.value = ''; 354 } 355 updatePt2Note(container); 356 } else if (event.target.id === 'at_school_rec_skip_pt2') { 357 setSkipPt2(container, event.target.checked); 358 } else if (event.target.id === 'at_school_rec_subject_count') { 359 renderGrade12Scores(container); 360 } else if (event.target.matches('.at-school-rec-exam-subject')) { 361 updateExamAverage(container); 362 } 363 }); 364 365 container.addEventListener('click', (event) => { 366 const button = event.target.closest('button'); 367 if (!button) return; 368 if (button.id === 'at_school_rec_open_pt3') openPt3(container); 369 if (button.id === 'at_school_rec_calculate') renderRecommendation(container); 370 }); 371 372 document.getElementById('nganh')?.addEventListener('change', () => resetForMajor(container)); 373 374 window.syncAtSchoolAutoSelectionMode = (enabled) => { 375 hideResult(container); 376 if (enabled) resetForMajor(container); 377 }; 378 379 if (document.body.classList.contains('registration-at-school')) resetForMajor(container); 380}; 381 382if (typeof document !== 'undefined') { 383 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', mountAtSchoolRecommendation); 384 else mountAtSchoolRecommendation(); 385}
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.