Created
January 29, 2026 12:23
-
-
Save daohoamh/92b53015f4b03462b177b4db3d289f45 to your computer and use it in GitHub Desktop.
BMP SmartQuiz 20260129_192336
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="vi"><head> | |
| <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" /> | |
| <meta http-equiv="Pragma" content="no-cache" /> | |
| <meta http-equiv="Expires" content="0" /><meta charset="UTF-8"><title>Đề kiểm tra</title> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script> | |
| <script> | |
| window.MathJax = { | |
| tex: { | |
| inlineMath: [['$','$'], ['\\(','\\)']], | |
| displayMath: [['$$','$$'], ['\\[','\\]']], | |
| processEscapes: true, | |
| processEnvironments: true | |
| }, | |
| options: { | |
| skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre'], | |
| renderActions: { | |
| addMenu: [0, '', ''] | |
| } | |
| }, | |
| startup: { | |
| ready: function() { | |
| console.log('MathJax is ready'); | |
| MathJax.startup.defaultReady(); | |
| // Typeset ngay khi khởi động | |
| MathJax.typesetPromise(); | |
| } | |
| } | |
| }; | |
| </script> | |
| <script> | |
| // === BMP compatibility patch: iOS Safari (passive listeners) + safe localStorage === | |
| var __supportsPassive = false; | |
| try { | |
| var __opts = Object.defineProperty({}, 'passive', { get: function(){ __supportsPassive = true; } }); | |
| window.addEventListener('testPassive', null, __opts); | |
| window.removeEventListener('testPassive', null, __opts); | |
| } catch(e) {} | |
| var __passiveFalse = __supportsPassive ? { passive: false } : false; | |
| (function(){ | |
| try { | |
| if (!window.localStorage) return; | |
| var ls = window.localStorage; | |
| var _set = ls.setItem.bind(ls); | |
| var _get = ls.getItem.bind(ls); | |
| var _rem = ls.removeItem.bind(ls); | |
| ls.setItem = function(k,v){ try{ _set(k,v); } catch(e){} }; | |
| ls.getItem = function(k){ try{ return _get(k); } catch(e){ return null; } }; | |
| ls.removeItem = function(k){ try{ _rem(k); } catch(e){} }; | |
| } catch(e) {} | |
| })(); | |
| // === Safe localStorage helpers (works in iOS private / in-app / iframe) === | |
| function _ls_(){ | |
| // localStorage có thể bị chặn ở một số trình duyệt/in-app/private mode. | |
| // Ta kiểm tra thực sự set/get được hay không. | |
| try { | |
| var ls = window.localStorage; | |
| if (!ls) return null; | |
| var t = "__bmp_ls_test__" + String(Date.now()); | |
| ls.setItem(t, "1"); | |
| ls.removeItem(t); | |
| return ls; | |
| } catch(e){ | |
| return null; | |
| } | |
| } | |
| // Cookie fallback (sync) – dùng khi localStorage không dùng được | |
| function _ckGet(k){ | |
| try{ | |
| var nameEQ = encodeURIComponent(k) + "="; | |
| var ca = (document.cookie || "").split(';'); | |
| for (var i=0;i<ca.length;i++){ | |
| var c = ca[i].trim(); | |
| if (c.indexOf(nameEQ) === 0) return decodeURIComponent(c.substring(nameEQ.length)); | |
| } | |
| }catch(e){} | |
| return null; | |
| } | |
| function _ckSet(k,v){ | |
| try{ | |
| var maxAge = 60*60*24*365; // 1 năm | |
| document.cookie = encodeURIComponent(k) + "=" + encodeURIComponent(String(v)) + "; Max-Age=" + maxAge + "; Path=/; SameSite=Lax"; | |
| }catch(e){} | |
| } | |
| function _ckRemove(k){ | |
| try{ | |
| document.cookie = encodeURIComponent(k) + "=; Max-Age=0; Path=/; SameSite=Lax"; | |
| }catch(e){} | |
| } | |
| function _lsGet(k){ | |
| var ls = _ls_(); | |
| if (ls){ | |
| try { return ls.getItem(k); } catch(e){ /* fallthrough */ } | |
| } | |
| // fallback cookie | |
| return _ckGet(k); | |
| } | |
| function _lsSet(k,v){ | |
| var ls = _ls_(); | |
| if (ls){ | |
| try { ls.setItem(k, v); return; } catch(e){ /* fallthrough */ } | |
| } | |
| _ckSet(k, v); | |
| } | |
| function _lsRemove(k){ | |
| var ls = _ls_(); | |
| if (ls){ | |
| try { ls.removeItem(k); } catch(e){} | |
| } | |
| _ckRemove(k); | |
| } | |
| // TẮT HOÀN TOÀN VUỐT SANG TRÁI/PHẢI CHUYỂN CÂU | |
| var xDown = null; | |
| document.addEventListener('touchstart', function(evt) { | |
| xDown = evt.touches[0].clientX; | |
| }, false); | |
| document.addEventListener('touchmove', function(evt) { | |
| if (!xDown) return; | |
| var xUp = evt.touches[0].clientX; | |
| var xDiff = xDown - xUp; | |
| // Ngăn vuốt trái/phải nếu chuyển động lớn | |
| if (Math.abs(xDiff) > 20) { | |
| evt.preventDefault(); | |
| } | |
| }, __passiveFalse); | |
| </script> | |
| <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> | |
| <style> | |
| :root { | |
| --primary-color: #4361ee; | |
| --secondary-color: #3a0ca3; | |
| --accent-color: #f72585; | |
| --success-color: #4cc9f0; | |
| --warning-color: #f8961e; | |
| --danger-color: #e63946; | |
| --light-color: #f8f9fa; | |
| --dark-color: #212529; | |
| --border-color: #dee2e6; | |
| --shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
| --gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| --neon-glow: 0 0 10px rgba(67, 97, 238, 0.5), 0 0 20px rgba(67, 97, 238, 0.3); | |
| } | |
| * { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| body { | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: var(--dark-color); | |
| line-height: 1.6; | |
| min-height: 100vh; | |
| } | |
| /* ========== ANTI-CHEAT & SECURITY STYLES ========== */ | |
| /* Chống chọn văn bản và copy */ | |
| .quiz-section, .question-container, .question-text, .answers-type1 button, .option-item-type2 { | |
| -webkit-user-select: none; | |
| -moz-user-select: none; | |
| -ms-user-select: none; | |
| user-select: none; | |
| } | |
| /* Cho phép chọn trên input nhập liệu */ | |
| .short-answer-input-type3, input[type="text"], textarea { | |
| -webkit-user-select: text; | |
| -moz-user-select: text; | |
| -ms-user-select: text; | |
| user-select: text; | |
| } | |
| /* Chống chụp màn hình cho mobile */ | |
| @media (max-width: 768px) { | |
| body.quiz-active::before { | |
| content: ""; | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(0, 0, 0, 0.95); | |
| z-index: 9999; | |
| display: none; | |
| pointer-events: none; | |
| } | |
| body.screenshot-detected::before { | |
| display: block; | |
| animation: flashScreen 0.5s ease; | |
| } | |
| } | |
| @keyframes flashScreen { | |
| 0% { opacity: 0; } | |
| 50% { opacity: 1; } | |
| 100% { opacity: 0; } | |
| } | |
| /* Cảnh báo rời màn hình */ | |
| .exit-warning { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(0, 0, 0, 0.9); | |
| z-index: 10000; | |
| display: none; | |
| align-items: center; | |
| justify-content: center; | |
| color: white; | |
| text-align: center; | |
| padding: 20px; | |
| font-size: 1.5rem; | |
| } | |
| .exit-warning.active { | |
| display: flex; | |
| animation: pulseWarning 2s infinite; | |
| } | |
| /* Cảnh báo thoát quá lâu */ | |
| .long-exit-warning { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(220, 53, 69, 0.95); | |
| z-index: 10000; | |
| display: none; | |
| align-items: center; | |
| justify-content: center; | |
| color: white; | |
| text-align: center; | |
| padding: 20px; | |
| font-size: 1.5rem; | |
| animation: pulseDanger 1s infinite; | |
| } | |
| .long-exit-warning.active { | |
| display: flex; | |
| } | |
| @keyframes pulseWarning { | |
| 0%, 100% { background: rgba(220, 53, 69, 0.9); } | |
| 50% { background: rgba(220, 53, 69, 0.7); } | |
| } | |
| @keyframes pulseDanger { | |
| 0%, 100% { background: rgba(220, 53, 69, 0.95); } | |
| 50% { background: rgba(220, 53, 69, 0.7); } | |
| } | |
| /* Fullscreen button */ | |
| .fullscreen-btn { | |
| background: rgba(255, 255, 255, 0.2); | |
| color: white; | |
| border: 1px solid rgba(255, 255, 255, 0.3); | |
| padding: 8px 16px; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| transition: all 0.3s ease; | |
| margin: 0 5px; | |
| } | |
| .fullscreen-btn:hover { | |
| background: rgba(255, 255, 255, 0.3); | |
| transform: translateY(-2px); | |
| } | |
| /* Security info in history */ | |
| .security-info { | |
| background: #2c3e50; | |
| color: white; | |
| padding: 10px 15px; | |
| border-radius: 8px; | |
| margin: 10px 0; | |
| border-left: 4px solid #e74c3c; | |
| } | |
| .security-info.warning { | |
| border-left-color: #f39c12; | |
| } | |
| .security-info.success { | |
| border-left-color: #2ecc71; | |
| } | |
| .security-info.error { | |
| border-left-color: #e74c3c; | |
| } | |
| /* ========== END SECURITY STYLES ========== */ | |
| /* User Info Form */ | |
| #user-info-form { | |
| display: flex; | |
| min-height: 100vh; | |
| align-items: center; | |
| justify-content: center; | |
| background: var(--gradient); | |
| padding: 20px; | |
| } | |
| .form-container { | |
| background: rgba(255, 255, 255, 0.95); | |
| padding: 50px; | |
| border-radius: 20px; | |
| box-shadow: var(--shadow), var(--neon-glow); | |
| max-width: 500px; | |
| width: 100%; | |
| text-align: center; | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| backdrop-filter: blur(10px); | |
| animation: fadeInUp 0.8s ease; | |
| } | |
| @keyframes fadeInUp { | |
| from { | |
| opacity: 0; | |
| transform: translateY(30px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| .form-container h2 { | |
| color: var(--primary-color); | |
| margin-bottom: 10px; | |
| font-size: 2rem; | |
| font-weight: 700; | |
| text-shadow: 0 2px 4px rgba(0,0,0,0.1); | |
| } | |
| .form-subtitle { | |
| color: #666; | |
| margin-bottom: 30px; | |
| font-size: 1.1rem; | |
| } | |
| .form-input { | |
| width: 100%; | |
| padding: 15px 20px; | |
| margin-bottom: 20px; | |
| border: 2px solid var(--border-color); | |
| border-radius: 12px; | |
| font-size: 16px; | |
| transition: all 0.3s ease; | |
| background: var(--light-color); | |
| } | |
| .form-input:focus { | |
| outline: none; | |
| border-color: var(--primary-color); | |
| background: white; | |
| box-shadow: 0 0 0 3px rgba(67, 97, 238, 0.1), var(--neon-glow); | |
| } | |
| #startBtn { | |
| width: 100%; | |
| padding: 16px; | |
| background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); | |
| color: white; | |
| border: none; | |
| border-radius: 12px; | |
| font-size: 18px; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| margin-top: 10px; | |
| box-shadow: 0 4px 15px rgba(67, 97, 238, 0.3); | |
| } | |
| #startBtn:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 6px 20px rgba(67, 97, 238, 0.4); | |
| } | |
| /* Quiz Section */ | |
| #quiz-section { | |
| display: none; | |
| min-height: 100vh; | |
| background: var(--light-color); | |
| } | |
| /* Header */ | |
| \1 | |
| min-height: 72px; | |
| background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); | |
| padding: 18px 24px; | |
| box-shadow: var(--shadow); | |
| border-bottom: 3px solid var(--accent-color); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| color: white; | |
| position: relative; | |
| } | |
| .student-info { | |
| font-size: 1.1rem; | |
| font-weight: 600; | |
| flex: 1; | |
| } | |
| .student-info span { | |
| color: #ffd700; | |
| } | |
| .timer { | |
| background: rgba(255, 255, 255, 0.2); | |
| color: white; | |
| padding: 10px 20px; | |
| border-radius: 25px; | |
| font-weight: bold; | |
| font-size: 1rem; | |
| box-shadow: var(--shadow); | |
| border: 1px solid rgba(255, 255, 255, 0.3); | |
| margin: 0 10px; | |
| } | |
| .header-controls { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| /* Mobile: ẩn nút Fullscreen/Trạng thái dạng dòng ở header */ | |
| .fullscreen-btn, .status-toggle-btn, .history-btn { | |
| background: rgba(255, 255, 255, 0.2); | |
| color: white; | |
| border: 1px solid rgba(255, 255, 255, 0.3); | |
| padding: 8px 16px; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| transition: all 0.3s ease; | |
| white-space: nowrap; | |
| } | |
| .fullscreen-btn:hover, .status-toggle-btn:hover, .history-btn:hover { | |
| background: rgba(255, 255, 255, 0.3); | |
| transform: translateY(-2px); | |
| } | |
| /* Main Container */ | |
| .main-container { | |
| display: flex; | |
| min-height: calc(100vh - 80px); | |
| gap: 20px; | |
| padding: 20px; | |
| max-width: 1400px; | |
| margin: 0 auto; | |
| position: relative; | |
| } | |
| /* Question Container */ | |
| .question-container { | |
| flex: 1; | |
| background: white; | |
| border-radius: 15px; | |
| box-shadow: var(--shadow); | |
| padding: 30px; | |
| border: 1px solid var(--border-color); | |
| position: relative; | |
| animation: slideInLeft 0.5s ease; | |
| transition: all 0.3s ease; | |
| } | |
| .question-container.expanded { | |
| margin-right: 0; | |
| } | |
| @keyframes slideInLeft { | |
| from { | |
| opacity: 0; | |
| transform: translateX(-30px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateX(0); | |
| } | |
| } | |
| .question { | |
| display: none; | |
| } | |
| .question.active { | |
| display: block; | |
| animation: fadeIn 0.5s ease; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(20px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .question h3 { | |
| color: var(--primary-color); | |
| margin-bottom: 15px; | |
| padding-bottom: 10px; | |
| border-bottom: 2px solid var(--primary-color); | |
| font-size: 1.3rem; | |
| display: flex; | |
| align-items: center; | |
| } | |
| .question h3::before { | |
| content: "📝"; | |
| margin-right: 10px; | |
| font-size: 1.2rem; | |
| } | |
| .question-text { | |
| font-size: 1.1rem; | |
| line-height: 1.8; | |
| margin-bottom: 25px; | |
| color: var(--dark-color); | |
| background: var(--light-color); | |
| padding: 20px; | |
| border-radius: 10px; | |
| border-left: 4px solid var(--primary-color); | |
| text-align: justify; | |
| word-wrap: break-word; | |
| white-space: pre-line; | |
| } | |
| /* Answer Styles */ | |
| .answers-type1 { | |
| display: grid; | |
| gap: 8px; | |
| margin-bottom: 20px; | |
| } | |
| .answers-type1 button { | |
| display: flex; | |
| align-items: flex-start; | |
| gap: 12px; | |
| padding: 15px 18px; | |
| border: 2px solid var(--border-color); | |
| border-radius: 10px; | |
| background: white; | |
| cursor: pointer; | |
| text-align: left; | |
| transition: all 0.3s ease; | |
| font-size: 1rem; | |
| } | |
| .answers-type1 button:hover { | |
| border-color: var(--primary-color); | |
| background: #f8fbff; | |
| transform: translateY(-2px); | |
| box-shadow: var(--shadow); | |
| } | |
| .answers-type1 button.selected-button { | |
| border-color: var(--primary-color); | |
| background: linear-gradient(135deg, #4361ee20, #4cc9f020); | |
| box-shadow: 0 4px 12px rgba(67, 97, 238, 0.2); | |
| } | |
| .answer-letter { | |
| width: 32px; | |
| height: 32px; | |
| background: var(--border-color); | |
| border-radius: 50%; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-weight: bold; | |
| flex-shrink: 0; | |
| transition: all 0.3s ease; | |
| } | |
| .selected-button .answer-letter { | |
| background: var(--primary-color); | |
| color: white; | |
| transform: scale(1.1); | |
| } | |
| .answer-text { | |
| flex: 1; | |
| font-size: 1rem; | |
| line-height: 1.5; | |
| } | |
| /* True/False Styles */ | |
| .options-container-type2 { | |
| display: grid; | |
| gap: 12px; | |
| margin-bottom: 20px; | |
| } | |
| .option-item-type2 { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| padding: 16px 18px; | |
| background: white; | |
| border: 2px solid var(--border-color); | |
| border-radius: 10px; | |
| transition: all 0.3s ease; | |
| } | |
| .option-item-type2:hover { | |
| border-color: var(--primary-color); | |
| transform: translateY(-2px); | |
| } | |
| .statement-text { | |
| flex: 1; | |
| font-size: 1rem; | |
| line-height: 1.6; | |
| } | |
| .choice-buttons-type2 { | |
| display: flex; | |
| gap: 8px; | |
| } | |
| .choice-buttons-type2 button { | |
| padding: 8px 16px; | |
| border: 2px solid var(--border-color); | |
| border-radius: 6px; | |
| background: white; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| font-weight: 600; | |
| min-width: 50px; | |
| } | |
| .choice-buttons-type2 button:hover { | |
| border-color: var(--primary-color); | |
| } | |
| .choice-buttons-type2 button.selected { | |
| border-color: var(--primary-color); | |
| background: var(--primary-color); | |
| color: white; | |
| transform: scale(1.05); | |
| } | |
| /* PHẦN II - Nút chọn Đ/S dạng 1 nút tròn */ | |
| .option-item-type2{ | |
| display: flex; | |
| align-items: flex-start; | |
| gap: 10px; | |
| } | |
| .tf-circle{ | |
| width: 34px; | |
| height: 34px; | |
| border-radius: 50%; | |
| border: 2px solid #cfcfcf; | |
| background: #fff; | |
| color: #111; | |
| font-weight: 800; | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| cursor: pointer; | |
| flex: 0 0 34px; | |
| user-select: none; | |
| } | |
| .tf-circle.tf-neutral{ | |
| background:#fff; | |
| border-color:#cfcfcf; | |
| color:#111; | |
| } | |
| .tf-circle.tf-true{ | |
| background:#16a34a; | |
| border-color:#16a34a; | |
| color:#fff; | |
| } | |
| .tf-circle.tf-false{ | |
| background:#dc2626; | |
| border-color:#dc2626; | |
| color:#fff; | |
| } | |
| /* Short Answer */ | |
| .short-answer-input-type3 { | |
| width: 100%; | |
| padding: 14px 18px; | |
| border: 2px solid var(--border-color); | |
| border-radius: 10px; | |
| font-size: 1rem; | |
| margin-top: 10px; | |
| transition: all 0.3s ease; | |
| background: white; | |
| } | |
| .short-answer-input-type3:focus { | |
| outline: none; | |
| border-color: var(--primary-color); | |
| box-shadow: 0 0 0 3px rgba(67, 97, 238, 0.1); | |
| } | |
| /* Navigation Buttons */ | |
| .navigation-buttons { | |
| display: flex; | |
| gap: 15px; | |
| justify-content: center; | |
| margin-top: 30px; | |
| padding: 20px; | |
| background: linear-gradient(135deg, #f8f9fa, #e9ecef); | |
| border-radius: 12px; | |
| border: 1px solid var(--border-color); | |
| flex-wrap: wrap; | |
| } | |
| .nav-btn, .submit-btn, .export-btn, .history-btn { | |
| padding: 12px 24px; | |
| border: none; | |
| border-radius: 8px; | |
| font-size: 14px; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| min-width: 140px; | |
| } | |
| .nav-btn { | |
| background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); | |
| color: white; | |
| } | |
| .nav-btn:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 4px 12px rgba(67, 97, 238, 0.3); | |
| } | |
| .submit-btn { | |
| background: linear-gradient(135deg, var(--warning-color), #e85d04); | |
| color: white; | |
| } | |
| .submit-btn:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 4px 12px rgba(248, 150, 30, 0.3); | |
| } | |
| .export-btn { | |
| background: linear-gradient(135deg, var(--danger-color), #c1121f); | |
| color: white; | |
| } | |
| .export-btn:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 4px 12px rgba(230, 57, 70, 0.3); | |
| } | |
| .history-btn { | |
| background: linear-gradient(135deg, #9d4edd, #7b2cbf); | |
| color: white; | |
| } | |
| .history-btn:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 4px 12px rgba(157, 78, 221, 0.3); | |
| } | |
| /* Mobile Navigation */ | |
| .mobile-nav { | |
| display: none; | |
| justify-content: space-between; | |
| margin-top: 20px; | |
| gap: 10px; | |
| } | |
| .mobile-nav-btn { | |
| flex: 1; | |
| padding: 12px; | |
| border: none; | |
| border-radius: 8px; | |
| background: var(--primary-color); | |
| color: white; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| } | |
| .mobile-nav-btn:hover { | |
| background: var(--secondary-color); | |
| } | |
| .mobile-action-buttons { | |
| display: none; | |
| gap: 10px; | |
| margin-top: 10px; | |
| } | |
| .mobile-action-btn { | |
| flex: 1; | |
| padding: 12px; | |
| border: none; | |
| border-radius: 8px; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| } | |
| .mobile-submit { | |
| background: var(--warning-color); | |
| color: white; | |
| } | |
| .mobile-export { | |
| background: var(--danger-color); | |
| color: white; | |
| } | |
| .mobile-history { | |
| background: #9d4edd; | |
| color: white; | |
| } | |
| /* Sidebar - Answer Status */ | |
| .sidebar { | |
| width: 350px; | |
| background: white; | |
| border-radius: 15px; | |
| box-shadow: var(--shadow); | |
| padding: 25px; | |
| border: 1px solid var(--border-color); | |
| height: fit-content; | |
| position: sticky; | |
| top: 20px; | |
| animation: slideInRight 0.5s ease; | |
| transition: all 0.3s ease; | |
| } | |
| .sidebar.collapsed { | |
| display: none; | |
| } | |
| @keyframes slideInRight { | |
| from { | |
| opacity: 0; | |
| transform: translateX(30px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateX(0); | |
| } | |
| } | |
| .answer-status h3 { | |
| color: var(--primary-color); | |
| margin-bottom: 20px; | |
| padding-bottom: 15px; | |
| border-bottom: 3px solid var(--primary-color); | |
| font-size: 1.3rem; | |
| text-align: center; | |
| } | |
| .status-section { | |
| margin-bottom: 25px; | |
| background: var(--light-color); | |
| padding: 20px; | |
| border-radius: 12px; | |
| border: 1px solid var(--border-color); | |
| } | |
| .status-section h4 { | |
| color: var(--secondary-color); | |
| margin-bottom: 15px; | |
| font-size: 1.1rem; | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .status-section h4::before { | |
| content: ""; | |
| color: var(--primary-color); | |
| font-size: 1.5rem; | |
| } | |
| .status-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(40px, 1fr)); | |
| gap: 6px; | |
| } | |
| .status-btn { | |
| width: 40px; | |
| height: 40px; | |
| border: 2px solid var(--border-color); | |
| border-radius: 6px; | |
| background: white; | |
| cursor: pointer; | |
| font-weight: bold; | |
| transition: all 0.3s ease; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 0.9rem; | |
| } | |
| .status-btn:hover { | |
| border-color: var(--primary-color); | |
| transform: scale(1.05); | |
| } | |
| .status-btn.answered { | |
| background: var(--success-color); | |
| color: white; | |
| border-color: var(--success-color); | |
| } | |
| .status-btn.current { | |
| border-color: var(--primary-color); | |
| background: var(--primary-color); | |
| color: white; | |
| transform: scale(1.1); | |
| } | |
| /* Mobile Status Toggle */ | |
| .mobile-status-toggle { | |
| display: none; | |
| position: fixed; | |
| top: 20px; | |
| right: 20px; | |
| z-index: 1000; | |
| background: var(--primary-color); | |
| color: white; | |
| width: 50px; | |
| height: 50px; | |
| border-radius: 50%; | |
| border: none; | |
| font-size: 1.5rem; | |
| cursor: pointer; | |
| box-shadow: var(--shadow); | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .mobile-status-panel { | |
| display: none; | |
| position: fixed; | |
| top: 80px; | |
| right: 20px; | |
| z-index: 999; | |
| background: white; | |
| border-radius: 12px; | |
| box-shadow: var(--shadow); | |
| padding: 20px; | |
| max-width: 300px; | |
| max-height: 70vh; | |
| overflow-y: auto; | |
| } | |
| .mobile-status-panel.active { | |
| display: block; | |
| } | |
| /* Modal Styles */ | |
| .modal-overlay { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: rgba(0, 0, 0, 0.7); | |
| display: none; | |
| align-items: center; | |
| justify-content: center; | |
| z-index: 1000; | |
| backdrop-filter: blur(5px); | |
| } | |
| .modal-dialog { | |
| background: white; | |
| padding: 40px; | |
| border-radius: 20px; | |
| box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3); | |
| max-width: 500px; | |
| width: 90%; | |
| text-align: center; | |
| border: 3px solid var(--primary-color); | |
| animation: modalAppear 0.3s ease; | |
| } | |
| @keyframes modalAppear { | |
| from { | |
| opacity: 0; | |
| transform: scale(0.8); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: scale(1); | |
| } | |
| } | |
| .modal-dialog h3 { | |
| color: var(--primary-color); | |
| margin-bottom: 20px; | |
| font-size: 1.5rem; | |
| } | |
| .modal-dialog p { | |
| margin-bottom: 25px; | |
| font-size: 1.1rem; | |
| line-height: 1.6; | |
| } | |
| .modal-buttons { | |
| display: flex; | |
| gap: 15px; | |
| justify-content: center; | |
| margin-top: 25px; | |
| } | |
| .modal-ok, .modal-cancel { | |
| padding: 12px 24px; | |
| border: none; | |
| border-radius: 10px; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| min-width: 100px; | |
| } | |
| .modal-ok { | |
| background: var(--primary-color); | |
| color: white; | |
| } | |
| .modal-ok:hover { | |
| background: var(--secondary-color); | |
| transform: translateY(-2px); | |
| } | |
| .modal-cancel { | |
| background: var(--border-color); | |
| color: var(--dark-color); | |
| } | |
| .modal-cancel:hover { | |
| background: #adb5bd; | |
| transform: translateY(-2px); | |
| } | |
| /* Results Section */ | |
| .results-container { | |
| background: white; | |
| padding: 30px; | |
| border-radius: 15px; | |
| box-shadow: var(--shadow); | |
| margin: 20px; | |
| } | |
| .results-header { | |
| text-align: center; | |
| margin-bottom: 30px; | |
| padding-bottom: 20px; | |
| border-bottom: 3px solid var(--primary-color); | |
| } | |
| .results-header h2 { | |
| color: var(--primary-color); | |
| margin-bottom: 10px; | |
| } | |
| .total-score { | |
| font-size: 2rem; | |
| font-weight: bold; | |
| color: var(--success-color); | |
| margin: 20px 0; | |
| } | |
| \1 width: 100%; | |
| overflow-x: auto; | |
| -webkit-overflow-scrolling: touch; | |
| width: 100%; | |
| border-collapse: collapse; | |
| margin: 20px 0; | |
| background: white; | |
| border-radius: 10px; | |
| overflow: hidden; | |
| box-shadow: var(--shadow); | |
| } | |
| .results-table th { | |
| background: var(--primary-color); | |
| color: white; | |
| padding: 15px; | |
| text-align: left; | |
| font-weight: 600; | |
| } | |
| .results-table td { | |
| padding: 12px 15px; | |
| border-bottom: 1px solid var(--border-color); | |
| vertical-align: top; | |
| } | |
| /* ===== MOBILE: Kết quả full width, ưu tiên cột nội dung ===== */ | |
| .results-table{ table-layout: fixed; width:100%; } | |
| .results-table th, .results-table td{ word-break: break-word; } | |
| /* Header: dùng nhãn rút gọn trên mobile để không bị dựng chữ dọc */ | |
| .th-short{ display:none; } | |
| .th-full{ display:inline; } | |
| @media (max-width: 768px){ | |
| .results-table th, .results-table td{ padding: 8px 6px; } | |
| .results-table thead th{ font-size: 13px; line-height: 1.2; white-space:nowrap; word-break:normal; } | |
| .th-full{ display:none; } | |
| .th-short{ display:inline; } | |
| /* Cột 1: Câu */ | |
| .results-table th:nth-child(1), .results-table td:nth-child(1){ | |
| width: 40px; text-align:center; white-space:nowrap; | |
| } | |
| /* Cột 3-6: nới rộng + không xuống dòng */ | |
| .results-table th:nth-child(3), .results-table td:nth-child(3){ | |
| width: 56px; text-align:center; white-space:nowrap; | |
| } | |
| .results-table th:nth-child(4), .results-table td:nth-child(4){ | |
| width: 56px; text-align:center; white-space:nowrap; | |
| } | |
| .results-table th:nth-child(5), .results-table td:nth-child(5){ | |
| width: 44px; text-align:center; white-space:nowrap; | |
| } | |
| .results-table th:nth-child(6), .results-table td:nth-child(6){ | |
| width: 44px; text-align:center; white-space:nowrap; | |
| } | |
| /* Cột 2: Nội dung câu hỏi ăn phần còn lại */ | |
| .results-table th:nth-child(2), .results-table td:nth-child(2){ | |
| width: auto; | |
| } | |
| /* Cell nội dung: rộng + cho phép cao theo nội dung, không tạo khoảng trắng thừa */ | |
| .results-table td:nth-child(2) .question-detail-content{ margin:0; } | |
| .results-table td:nth-child(2) .option-line{ margin-top:2px; } | |
| } | |
| .results-table tr:hover { | |
| background: #f8f9fa; | |
| } | |
| .correct-answer { | |
| color: var(--success-color); | |
| font-weight: bold; | |
| } | |
| .wrong-answer { | |
| color: var(--danger-color); | |
| font-weight: bold; | |
| } | |
| .correct-row { | |
| background-color: #f0fff0 !important; | |
| } | |
| .wrong-row { | |
| background-color: #fff0f0 !important; | |
| } | |
| /* Time Info */ | |
| .time-info { | |
| background: var(--light-color); | |
| padding: 15px; | |
| border-radius: 10px; | |
| margin: 15px 0; | |
| border-left: 4px solid var(--primary-color); | |
| } | |
| .time-info p { | |
| margin: 5px 0; | |
| font-size: 0.95rem; | |
| } | |
| /* Success Message */ | |
| .success-message { | |
| background: linear-gradient(135deg, #4cc9f0, #4361ee); | |
| color: white; | |
| padding: 30px; | |
| border-radius: 15px; | |
| text-align: center; | |
| margin: 20px 0; | |
| box-shadow: var(--shadow); | |
| } | |
| .success-message h3 { | |
| font-size: 1.8rem; | |
| margin-bottom: 15px; | |
| } | |
| .success-message p { | |
| font-size: 1.1rem; | |
| margin-bottom: 10px; | |
| } | |
| /* History Section */ | |
| .history-container { | |
| background: white; | |
| padding: 20px; | |
| border-radius: 15px; | |
| box-shadow: var(--shadow); | |
| margin: 20px 0; | |
| } | |
| .history-item { | |
| background: var(--light-color); | |
| padding: 15px; | |
| border-radius: 10px; | |
| margin-bottom: 15px; | |
| border-left: 4px solid var(--primary-color); | |
| transition: all 0.3s ease; | |
| } | |
| .history-item:hover { | |
| transform: translateY(-2px); | |
| box-shadow: var(--shadow); | |
| } | |
| .history-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 10px; | |
| } | |
| .history-score { | |
| font-size: 1.3rem; | |
| font-weight: bold; | |
| color: var(--success-color); | |
| } | |
| .history-time { | |
| color: #666; | |
| font-size: 0.9rem; | |
| } | |
| .history-details { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
| gap: 10px; | |
| margin-top: 10px; | |
| } | |
| .history-detail { | |
| background: white; | |
| padding: 8px 12px; | |
| border-radius: 6px; | |
| border: 1px solid var(--border-color); | |
| } | |
| /* Apps Script Notification */ | |
| .apps-script-notification { | |
| position: fixed; | |
| top: 20px; | |
| right: 20px; | |
| background: var(--success-color); | |
| color: white; | |
| padding: 15px 20px; | |
| border-radius: 10px; | |
| box-shadow: var(--shadow); | |
| z-index: 1001; | |
| display: none; | |
| animation: slideInRight 0.5s ease; | |
| } | |
| .apps-script-notification.error { | |
| background: var(--danger-color); | |
| } | |
| /* Security Info Modal */ | |
| .security-info-modal { | |
| background: linear-gradient(135deg, #1a237e, #4a148c); | |
| color: white; | |
| padding: 30px; | |
| border-radius: 15px; | |
| text-align: center; | |
| } | |
| .security-info-modal h3 { | |
| font-size: 1.8rem; | |
| margin-bottom: 20px; | |
| color: #bb86fc; | |
| } | |
| .security-info-modal ul { | |
| text-align: left; | |
| margin: 20px 0; | |
| padding-left: 20px; | |
| } | |
| .security-info-modal li { | |
| margin: 10px 0; | |
| font-size: 1.1rem; | |
| } | |
| /* Footer Styles */ | |
| .quiz-footer { | |
| background: linear-gradient(135deg, #343a40, #212529); | |
| color: white; | |
| text-align: center; | |
| padding: 25px 20px; | |
| margin-top: 40px; | |
| border-top: 3px solid #4361ee; | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| } | |
| .footer-content { | |
| max-width: 800px; | |
| margin: 0 auto; | |
| } | |
| .footer-main { | |
| font-size: 1.2rem; | |
| font-weight: bold; | |
| margin-bottom: 10px; | |
| color: #4cc9f0; | |
| } | |
| .teacher-name { | |
| color: #ffd700; | |
| } | |
| .footer-school { | |
| font-size: 1rem; | |
| color: #adb5bd; | |
| line-height: 1.6; | |
| } | |
| .footer-sub { | |
| margin-top: 15px; | |
| padding-top: 15px; | |
| border-top: 1px solid #495057; | |
| color: #6c757d; | |
| font-size: 0.9rem; | |
| } | |
| /* Question Detail Content */ | |
| .question-detail-content { | |
| max-width: 100%; | |
| overflow-wrap: break-word; | |
| word-wrap: break-word; | |
| hyphens: auto; | |
| } | |
| .question-detail-content table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| margin: 10px 0; | |
| } | |
| .question-detail-content td, .question-detail-content th { | |
| border: 1px solid #ddd; | |
| padding: 8px; | |
| text-align: left; | |
| } | |
| /* Container cho bảng trong câu hỏi */ | |
| .table-container { | |
| width: 100%; | |
| overflow-x: auto; | |
| margin: 15px 0; | |
| border: 1px solid #e0e0e0; | |
| border-radius: 8px; | |
| padding: 10px; | |
| background: #fafafa; | |
| box-shadow: 0 2px 4px rgba(0,0,0,0.1); | |
| } | |
| .table-container table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| min-width: 300px; | |
| } | |
| .table-container th, .table-container td { | |
| border: 1px solid #ddd; | |
| padding: 10px 12px; | |
| text-align: left; | |
| vertical-align: top; | |
| } | |
| .table-container th { | |
| background-color: #4361ee; | |
| color: white; | |
| font-weight: 600; | |
| text-align: center; | |
| } | |
| .table-container tr:nth-child(even) { | |
| background-color: #f8f9fa; | |
| } | |
| .table-container tr:hover { | |
| background-color: #e9ecef; | |
| } | |
| /* Đảm bảo hình ảnh trong bảng responsive */ | |
| .table-container img { | |
| max-width: 100%; | |
| height: auto; | |
| } | |
| /* Công thức toán học trong bảng */ | |
| .table-container .math-container { | |
| display: inline-block; | |
| margin: 2px 0; | |
| } | |
| /* Đảm bảo hình ảnh trong câu hỏi responsive */ | |
| .question-detail-content img { | |
| max-width: 100%; | |
| height: auto; | |
| display: block; | |
| margin: 10px auto; | |
| border-radius: 5px; | |
| box-shadow: 0 2px 4px rgba(0,0,0,0.1); | |
| } | |
| /* ===== MathType (vector) inline sizing ===== */ | |
| .question-detail-content img.bmp-math{ | |
| display: inline !important; | |
| margin: 0 !important; | |
| max-width: none !important; | |
| width: auto !important; | |
| height: 1.45em !important; | |
| vertical-align: -0.15em !important; | |
| border-radius: 0 !important; | |
| box-shadow: none !important; | |
| } | |
| /* If some rules force block images, override for math */ | |
| .question-detail-content img.bmp-math{ | |
| display: inline !important; | |
| } | |
| /* ===== End MathType inline sizing ===== */ | |
| /* Công thức toán học */ | |
| .math-container { | |
| overflow-x: auto; | |
| padding: 10px; | |
| margin: 10px 0; | |
| background: #f8f9fa; | |
| border-radius: 5px; | |
| border-left: 3px solid #4361ee; | |
| } | |
| /* Mobile optimization for history detail - IMPROVED */ | |
| @media (max-width: 768px) { | |
| .modal-dialog { | |
| max-width: 95% !important; | |
| width: 95% !important; | |
| margin: 10px auto; | |
| padding: 15px; | |
| } | |
| #history-detail-content .results-table { | |
| font-size: 0.75rem; | |
| display: block; | |
| overflow-x: auto; | |
| white-space: nowrap; | |
| -webkit-overflow-scrolling: touch; | |
| width: 100%; | |
| } | |
| #history-detail-content .results-table table { | |
| min-width: 800px; | |
| width: auto; | |
| } | |
| #history-detail-content .results-table th, | |
| #history-detail-content .results-table td { | |
| padding: 8px 6px; | |
| white-space: normal; | |
| word-wrap: break-word; | |
| max-width: none; | |
| } | |
| \1min-width: 120px; | |
| max-width: none; | |
| } | |
| #history-detail-content .results-table th:nth-child(4), | |
| #history-detail-content .results-table td:nth-child(4), | |
| #history-detail-content .results-table th:nth-child(5), | |
| #history-detail-content .results-table td:nth-child(5) { | |
| min-width: 100px; | |
| max-width: none; | |
| } | |
| /* Đảm bảo nội dung câu hỏi hiển thị đầy đủ */ | |
| #history-detail-content .question-detail-content { | |
| max-width: 100%; | |
| overflow-wrap: break-word; | |
| word-wrap: break-word; | |
| hyphens: auto; | |
| } | |
| #history-detail-content .question-detail-content table { | |
| display: block; | |
| overflow-x: auto; | |
| white-space: nowrap; | |
| -webkit-overflow-scrolling: touch; | |
| min-width: 300px; | |
| } | |
| } | |
| @media (max-width: 480px) { | |
| #history-detail-content .results-table { | |
| font-size: 0.7rem; | |
| } | |
| #history-detail-content .results-table table { | |
| min-width: 700px; | |
| } | |
| #history-detail-content .results-table th, | |
| #history-detail-content .results-table td { | |
| padding: 6px 4px; | |
| } | |
| .modal-dialog { | |
| max-width: 98% !important; | |
| width: 98% !important; | |
| margin: 5px auto; | |
| padding: 10px; | |
| } | |
| } | |
| /* Full width table containers */ | |
| .table-container { | |
| width: 100%; | |
| overflow-x: auto; | |
| margin: 10px 0; | |
| border: 1px solid #e0e0e0; | |
| border-radius: 5px; | |
| padding: 5px; | |
| -webkit-overflow-scrolling: touch; | |
| } | |
| .table-container table { | |
| width: 100%; | |
| min-width: 100%; | |
| } | |
| /* Math formula optimization */ | |
| .math-container { | |
| overflow-x: auto; | |
| padding: 10px; | |
| margin: 10px 0; | |
| background: #f8f9fa; | |
| border-radius: 5px; | |
| border-left: 3px solid #4361ee; | |
| -webkit-overflow-scrolling: touch; | |
| } | |
| /* Mobile table optimization - IMPROVED */ | |
| @media (max-width: 768px) { | |
| .results-table { | |
| font-size: 0.85rem; | |
| display: block; | |
| overflow-x: auto; | |
| white-space: nowrap; | |
| -webkit-overflow-scrolling: touch; | |
| } | |
| .results-table table { | |
| min-width: 700px; /* Đảm bảo bảng đủ rộng */ | |
| width: auto; | |
| } | |
| .results-table th, | |
| .results-table td { | |
| padding: 10px 8px; | |
| white-space: normal; | |
| word-wrap: break-word; | |
| max-width: 200px; | |
| } | |
| .results-table th:nth-child(2), | |
| .results-table td:nth-child(2) { | |
| min-width: 360px; /* Cột nội dung câu hỏi rộng nhất */ | |
| max-width: 520px; | |
| } | |
| .results-table th:nth-child(3), | |
| .results-table td:nth-child(3), | |
| .results-table th:nth-child(4), | |
| .results-table td:nth-child(4), | |
| .results-table th:nth-child(5), | |
| .results-table td:nth-child(5), | |
| .results-table th:nth-child(6), | |
| .results-table td:nth-child(6) { | |
| min-width: 120px; /* Chọn/Đúng/Điểm/KQ */ | |
| max-width: none; | |
| } | |
| .question-detail-content table { | |
| display: block; | |
| overflow-x: auto; | |
| white-space: nowrap; | |
| -webkit-overflow-scrolling: touch; | |
| } | |
| .question-detail-content table { | |
| min-width: 400px; | |
| } | |
| } | |
| @media (max-width: 480px) { | |
| .results-table { | |
| font-size: 0.75rem; | |
| } | |
| .results-table table { | |
| min-width: 600px; | |
| } | |
| .results-table th, | |
| .results-table td { | |
| padding: 8px 6px; | |
| } | |
| .results-table th:nth-child(3), | |
| .results-table td:nth-child(3) { | |
| min-width: 200px; | |
| max-width: 250px; | |
| } | |
| } | |
| /* Tối ưu hiển thị trên máy tính và blogpost */ | |
| @media (min-width: 1024px) { | |
| .question-container { | |
| max-width: 900px; | |
| margin: 0 auto; | |
| } | |
| .main-container { | |
| gap: 30px; | |
| padding: 30px; | |
| } | |
| .question-text { | |
| font-size: 1.15rem; | |
| line-height: 1.8; | |
| } | |
| .sidebar { | |
| width: 350px; | |
| } | |
| .question-container.expanded { | |
| max-width: 1200px; | |
| } | |
| } | |
| /* Responsive */ | |
| @media (max-width: 1024px) { | |
| .main-container { | |
| flex-direction: column; | |
| } | |
| .sidebar { | |
| width: 100%; | |
| position: static; | |
| } | |
| .navigation-buttons { | |
| flex-wrap: wrap; | |
| } | |
| .nav-btn, .submit-btn, .export-btn, .history-btn { | |
| min-width: 110px; | |
| flex: 1; | |
| } | |
| .header { | |
| flex-wrap: wrap; | |
| gap: 10px; | |
| } | |
| .student-info { | |
| order: 1; | |
| width: 100%; | |
| text-align: center; | |
| margin-bottom: 10px; | |
| } | |
| .timer { | |
| order: 2; | |
| } | |
| .header-controls { | |
| order: 3; | |
| justify-content: center; | |
| width: 100%; | |
| } | |
| } | |
| @media (max-width: 768px) { | |
| /* Trên điện thoại: ẩn 2 nút dòng (Fullscreen/Trạng thái) ở header */ | |
| .header-controls{ display:none !important; } | |
| .header { | |
| flex-direction: column; | |
| gap: 15px; | |
| text-align: center; | |
| padding: 15px 20px; | |
| } | |
| .form-container { | |
| padding: 30px 20px; | |
| } | |
| .question-container { | |
| padding: 20px; | |
| } | |
| .answers-type1 button { | |
| padding: 12px 15px; | |
| gap: 10px; | |
| } | |
| .option-item-type2 { | |
| /* Giữ nút Đ/S cùng dòng với phương án trên mobile */ | |
| flex-direction: row; | |
| align-items: flex-start; | |
| gap: 10px; | |
| padding: 14px; | |
| } | |
| /* Cho phép nội dung phương án tự xuống dòng, không đẩy nút tròn ra dòng riêng */ | |
| .statement-text { flex: 1; min-width: 0; } | |
| .tf-circle { flex: 0 0 34px; } | |
| .choice-buttons-type2 { | |
| width: 100%; | |
| justify-content: center; | |
| } | |
| .navigation-buttons { | |
| display: none; | |
| } | |
| .mobile-nav { | |
| display: flex; | |
| } | |
| .mobile-action-buttons { | |
| display: flex; | |
| } | |
| .mobile-status-toggle { | |
| display: flex; | |
| } | |
| .sidebar { | |
| display: none; | |
| } | |
| .status-btn { | |
| width: 35px; | |
| height: 35px; | |
| font-size: 0.8rem; | |
| } | |
| /* Mobile table optimization */ | |
| .results-table { | |
| font-size: 0.85rem; | |
| display: block; | |
| overflow-x: auto; | |
| white-space: nowrap; | |
| } | |
| .results-table th, | |
| .results-table td { | |
| padding: 8px 10px; | |
| } | |
| /* Footer Mobile */ | |
| .footer-main { | |
| font-size: 1.1rem; | |
| } | |
| .footer-school { | |
| font-size: 0.9rem; | |
| } | |
| .footer-sub { | |
| font-size: 0.8rem; | |
| } | |
| .quiz-footer { | |
| padding: 20px 15px; | |
| margin-top: 30px; | |
| } | |
| } | |
| @media (max-width: 480px) { | |
| .question-container { | |
| padding: 15px; | |
| } | |
| .question h3 { | |
| font-size: 1.2rem; | |
| } | |
| .question-text { | |
| padding: 15px; | |
| font-size: 1rem; | |
| } | |
| .answers-type1 { | |
| gap: 6px; | |
| } | |
| .answers-type1 button { | |
| padding: 10px 12px; | |
| } | |
| .answer-letter { | |
| width: 28px; | |
| height: 28px; | |
| font-size: 0.9rem; | |
| } | |
| .mobile-nav-btn, .mobile-action-btn { | |
| padding: 10px; | |
| font-size: 0.9rem; | |
| } | |
| .header-controls { | |
| flex-wrap: wrap; | |
| gap: 5px; | |
| } | |
| .status-toggle-btn, .history-btn { | |
| font-size: 0.8rem; | |
| padding: 6px 12px; | |
| } | |
| /* Mobile table optimization */ | |
| .results-table { | |
| font-size: 0.75rem; | |
| } | |
| .results-table th, | |
| .results-table td { | |
| padding: 6px 8px; | |
| } | |
| /* Footer Mobile Small */ | |
| .footer-main { | |
| font-size: 1rem; | |
| } | |
| .footer-school { | |
| font-size: 0.85rem; | |
| } | |
| .quiz-footer { | |
| padding: 15px 10px; | |
| margin-top: 20px; | |
| } | |
| } | |
| /* Style cho lịch sử chi tiết */ | |
| .history-detail-btn { | |
| background: var(--primary-color); | |
| color: white; | |
| border: none; | |
| padding: 8px 16px; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| margin-top: 10px; | |
| width: 100%; | |
| font-weight: 600; | |
| } | |
| .history-detail-btn:hover { | |
| background: var(--secondary-color); | |
| } | |
| /* Collapse/Expand transitions */ | |
| .sidebar, .question-container { | |
| transition: all 0.3s ease; | |
| } | |
| /* ===== Top Vinh Danh (Login) ===== */ | |
| .lb-card{ | |
| margin-top: 14px; | |
| padding: 14px 14px 12px 14px; | |
| border-radius: 18px; | |
| background: linear-gradient(180deg, #fff7ed 0%, #ffedd5 100%); | |
| border: 1px solid rgba(251,146,60,0.35); | |
| box-shadow: 0 10px 28px rgba(124,45,18,0.12); | |
| } | |
| .lb-head{ | |
| display:flex; | |
| flex-direction:column; | |
| gap: 8px; | |
| margin-bottom: 10px; | |
| /* 3 dòng tiêu đề nền vàng-cam cho nổi bật */ | |
| padding: 10px 12px; | |
| border-radius: 16px; | |
| background: linear-gradient(135deg, #ffb703 0%, #fb8500 100%); | |
| box-shadow: inset 0 0 0 1px rgba(255,255,255,0.22); | |
| } | |
| .lb-head-row{ | |
| display:flex; | |
| align-items:center; | |
| justify-content:center; | |
| gap: 10px; | |
| } | |
| .lb-subrow{ | |
| display:flex; | |
| align-items:center; | |
| justify-content:center; | |
| gap: 10px; | |
| } | |
| .lb-flame{ | |
| font-size: 16px; | |
| line-height: 1; | |
| } | |
| .lb-title{ | |
| font-weight: 950; | |
| color: #ffffff; | |
| font-size: 18px; | |
| letter-spacing: .2px; | |
| margin: 0; | |
| white-space: nowrap; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| } | |
| .lb-sub{ | |
| margin-top: 2px; | |
| color: rgba(255,255,255,0.92); | |
| font-size: 12px; | |
| font-weight: 700; | |
| white-space: nowrap; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| } | |
| .lb-flame{ | |
| font-size: 18px; | |
| line-height: 1; | |
| } | |
| .lb-ctrl{ | |
| display:flex; | |
| align-items:center; | |
| gap:6px; | |
| padding: 6px 8px; | |
| border-radius: 999px; | |
| background: rgba(255,255,255,0.88); | |
| border: 1px solid rgba(255,255,255,0.35); | |
| } | |
| .lb-ctrl label{ | |
| font-size: 12px; | |
| font-weight: 950; | |
| color: rgba(124,45,18,0.9); | |
| } | |
| .lb-ctrl select{ | |
| border: 1px solid rgba(124,45,18,0.18); | |
| border-radius: 999px; | |
| padding: 6px 10px; | |
| font-weight: 950; | |
| color: #7c2d12; | |
| background: #fff; | |
| outline: none; | |
| } | |
| /* Mobile: TỐP VINH DANH 1 dòng; dòng 2 (mô tả) 1 dòng; vòng Top thu nhỏ và xuống dòng 3 */ | |
| @media (max-width: 480px){ | |
| .lb-head{ gap: 6px; } | |
| .lb-head-row{ | |
| flex-direction: column; | |
| gap: 6px; | |
| } | |
| .lb-title{ font-size: 17px; } | |
| .lb-sub{ font-size: 10.5px; } | |
| .lb-subrow{ order: 2; gap: 8px; } | |
| .lb-ctrl{ order: 3; transform: scale(0.92); transform-origin: center; } | |
| } | |
| .lb-box{ | |
| text-align:left; | |
| } | |
| .lb-podium{ | |
| display:grid; | |
| grid-template-columns: repeat(3, 1fr); | |
| gap: 10px; | |
| margin-top: 8px; | |
| margin-bottom: 10px; | |
| } | |
| .lb-pill{ | |
| background: rgba(255,255,255,0.92); | |
| border: 1px solid rgba(124,45,18,0.12); | |
| border-radius: 14px; | |
| padding: 10px 10px 9px 10px; | |
| box-shadow: 0 8px 18px rgba(17,24,39,0.06); | |
| text-align:center; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .lb-pill:before{ | |
| content: ""; | |
| position:absolute; | |
| inset:-40px; | |
| background: radial-gradient(circle at 20% 10%, rgba(255,255,255,0.65), rgba(255,255,255,0) 60%); | |
| transform: rotate(12deg); | |
| } | |
| .lb-pill:nth-child(1){ | |
| background: linear-gradient(180deg, rgba(255,255,255,0.96) 0%, rgba(255,244,214,0.96) 100%); | |
| border-color: rgba(251,191,36,0.40); | |
| box-shadow: 0 12px 26px rgba(251,191,36,0.20); | |
| } | |
| .lb-pill:nth-child(2){ | |
| background: linear-gradient(180deg, rgba(255,255,255,0.96) 0%, rgba(226,232,240,0.95) 100%); | |
| border-color: rgba(148,163,184,0.35); | |
| } | |
| .lb-pill:nth-child(3){ | |
| background: linear-gradient(180deg, rgba(255,255,255,0.96) 0%, rgba(254,215,170,0.95) 100%); | |
| border-color: rgba(251,146,60,0.30); | |
| } | |
| .lb-rank{ | |
| font-weight: 950; | |
| color: #7c2d12; | |
| font-size: 12px; | |
| margin-bottom: 4px; | |
| display:inline-flex; | |
| align-items:center; | |
| justify-content:center; | |
| gap: 6px; | |
| padding: 6px 10px; | |
| border-radius: 999px; | |
| background: rgba(255,255,255,0.78); | |
| border: 1px solid rgba(124,45,18,0.12); | |
| } | |
| .lb-name{ | |
| font-weight: 950; | |
| color: #111827; | |
| font-size: 13px; | |
| line-height: 1.15; | |
| margin: 0; | |
| white-space: normal; | |
| overflow: visible; | |
| text-overflow: unset; | |
| max-width: 100%; | |
| overflow-wrap: anywhere; | |
| word-break: break-word; | |
| } | |
| .lb-meta{ | |
| margin-top: 2px; | |
| font-size: 12px; | |
| color: rgba(17,24,39,0.70); | |
| white-space: nowrap; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| } | |
| .lb-score{ | |
| margin-top: 6px; | |
| font-weight: 950; | |
| color: #7c2d12; | |
| font-size: 13px; | |
| } | |
| .lb-list{ | |
| margin: 6px 0 0 0; | |
| padding-left: 22px; | |
| color:#111827; | |
| text-align:left; | |
| } | |
| .lb-list li{ | |
| margin: 6px 0; | |
| padding: 0; | |
| text-align:left; | |
| line-height: 1.25; | |
| } | |
| .lb-full-btn{ | |
| margin-top: 10px; | |
| width: 100%; | |
| border: 0; | |
| border-radius: 14px; | |
| padding: 12px 14px; | |
| font-weight: 950; | |
| color: #fff; | |
| background: linear-gradient(90deg, #f97316, #fb7185); | |
| box-shadow: 0 12px 22px rgba(249,115,22,0.25); | |
| } | |
| .lb-full-btn:active{ transform: translateY(1px); } | |
| /* Full ranking modal */ | |
| .lb-modal{ | |
| position: fixed; | |
| inset: 0; | |
| display: none; | |
| align-items: center; | |
| justify-content: center; | |
| background: rgba(2,6,23,0.55); | |
| z-index: 99999; | |
| padding: 18px; | |
| } | |
| .lb-modal.show{ display:flex; } | |
| .lb-modal-card{ | |
| width: min(520px, 100%); | |
| max-height: min(78vh, 680px); | |
| overflow: auto; | |
| background: #fff; | |
| border-radius: 16px; | |
| border: 1px solid rgba(17,24,39,0.10); | |
| box-shadow: 0 30px 70px rgba(0,0,0,0.25); | |
| padding: 14px; | |
| } | |
| .lb-modal-title{ | |
| font-weight: 950; | |
| color: #111827; | |
| font-size: 16px; | |
| margin: 0 0 10px 0; | |
| } | |
| .lb-modal-close{ | |
| float:right; | |
| border: 0; | |
| background: #111827; | |
| color:#fff; | |
| border-radius: 10px; | |
| padding: 8px 10px; | |
| font-weight: 900; | |
| } | |
| .lb-modal-table{ | |
| width: 100%; | |
| border-collapse: collapse; | |
| font-size: 13px; | |
| } | |
| .lb-modal-table th, .lb-modal-table td{ | |
| padding: 8px 6px; | |
| border-bottom: 1px solid rgba(17,24,39,0.08); | |
| text-align:left; | |
| } | |
| .lb-modal-table th{ | |
| font-weight: 950; | |
| color:#374151; | |
| font-size: 12px; | |
| } | |
| /* ===== Mobile full-width results + tighter layout ===== */ | |
| @media (max-width: 768px) { | |
| body { margin: 0; padding: 0; } | |
| .main-container { padding: 8px; gap: 10px; max-width: 100vw; width: 100vw; margin: 0; } | |
| .question-container, .sidebar { max-width: 100%; width: 100%; } | |
| .results-table { width: 100%; table-layout: fixed; } | |
| .results-table th, .results-table td { padding: 8px 6px; font-size: 13px; } | |
| .results-table td { word-break: break-word; } | |
| } | |
| /* === BMP Mobile Full Width Fix (v29v15) === */ | |
| @media (max-width: 768px) { | |
| /* Modal/khung lịch sử: full bề rộng màn hình, bỏ bó 2 bên */ | |
| .modal-dialog { | |
| width: 100vw !important; | |
| max-width: 100vw !important; | |
| margin: 0 !important; | |
| border-radius: 0 !important; | |
| } | |
| .modal-content { | |
| width: 100vw !important; | |
| max-width: 100vw !important; | |
| border-radius: 0 !important; | |
| } | |
| /* Khối kết quả/lịch sử: full width */ | |
| .results-container { | |
| margin: 0 !important; | |
| border-radius: 0 !important; | |
| padding: 12px !important; | |
| } | |
| /* Bảng: không ép min-width -> chia cột theo % để cột nội dung rộng nhất */ | |
| .results-table { | |
| display: table !important; | |
| overflow: visible !important; | |
| white-space: normal !important; | |
| } | |
| .results-table table, table.results-table { | |
| width: 100% !important; | |
| min-width: 0 !important; | |
| table-layout: fixed !important; | |
| } | |
| .results-table th, .results-table td { | |
| max-width: none !important; | |
| word-break: break-word !important; | |
| overflow-wrap: anywhere !important; | |
| } | |
| /* Cột: Câu | Nội dung | Đáp án bạn | Đáp án đúng | Điểm | Kết quả */ | |
| .results-table th:nth-child(1), .results-table td:nth-child(1) { width: 10% !important; text-align: center; } | |
| .results-table th:nth-child(2), .results-table td:nth-child(2) { width: 60% !important; text-align: left; } | |
| .results-table th:nth-child(3), .results-table td:nth-child(3) { width: 10% !important; text-align: center; } | |
| .results-table th:nth-child(4), .results-table td:nth-child(4) { width: 10% !important; text-align: center; } | |
| .results-table th:nth-child(5), .results-table td:nth-child(5) { width: 5% !important; text-align: center; } | |
| .results-table th:nth-child(6), .results-table td:nth-child(6) { width: 5% !important; text-align: center; } | |
| /* A.B.C.D thẳng dọc, sát lề trái */ | |
| .option-line { | |
| margin-left: 0 !important; | |
| padding-left: 0 !important; | |
| text-indent: 0 !important; | |
| display: block; | |
| } | |
| } | |
| /* === End Mobile Full Width Fix === */ | |
| /* ===== BMP PATCH: Better contrast on white + revert login leaderboard to simple look ===== */ | |
| .lb-card{ | |
| background: #ffffff !important; | |
| border: 1px solid rgba(0,0,0,.08) !important; | |
| box-shadow: 0 10px 30px rgba(0,0,0,.10) !important; | |
| } | |
| .lb-title{ color:#0f172a !important; } | |
| .lb-sub{ color:#334155 !important; } | |
| .lb-ctrl label{ color:#0f172a !important; } | |
| .lb-box{ | |
| background: #f8fafc !important; | |
| border: 1px solid rgba(15,23,42,.08) !important; | |
| color:#0f172a !important; | |
| } | |
| .lb-row{ | |
| background: #ffffff !important; | |
| border: 1px solid rgba(15,23,42,.10) !important; | |
| box-shadow: none !important; | |
| } | |
| .lb-name{ color:#0f172a !important; text-shadow:none !important; } | |
| .lb-meta{ color:#334155 !important; } | |
| .lb-score{ color:#0f172a !important; } | |
| /* ===== Podium (Top 1-3): điểm màu đỏ + thời gian chữ nhỏ ===== */ | |
| .lb-pill .lb-score-val{ font-weight:950 !important; } | |
| .lb-pill:nth-child(-n+3) .lb-score-val{ color:#dc2626 !important; } | |
| .lb-pill .lb-time{ font-size: 0.85em !important; color:#475569 !important; font-weight:800 !important; } | |
| .header{ | |
| background: linear-gradient(135deg, #0ea5e9, #1d4ed8) !important; | |
| color:#fff !important; | |
| } | |
| .student-info{ | |
| color:#fff !important; | |
| font-weight:800 !important; | |
| text-shadow: 0 1px 10px rgba(0,0,0,.35) !important; | |
| } | |
| .timer{ color:#fff !important; } | |
| .header-controls button{ | |
| background: rgba(255,255,255,.16) !important; | |
| color:#fff !important; | |
| border: 1px solid rgba(255,255,255,.22) !important; | |
| } | |
| /* ===== BLOGSPOT MOBILE FIX: prevent horizontal overflow + force wrap ===== */ | |
| html, body { max-width: 100% !important; overflow-x: hidden !important; } | |
| #quiz-section, .main-container, .question-container { max-width: 100% !important; overflow-x: hidden !important; } | |
| /* Flex items must be allowed to shrink to wrap */ | |
| .answers-type1 button, .option-item-type2 { max-width: 100% !important; } | |
| .answer-text, .statement-text, .question-text { min-width: 0 !important; max-width: 100% !important; } | |
| .question-text, .answer-text, .statement-text, .question-detail-content { | |
| overflow-wrap: anywhere !important; | |
| word-break: break-word !important; | |
| } | |
| .question-container img, .question-container iframe, .question-container video, .question-container svg { | |
| max-width: 100% !important; | |
| height: auto !important; | |
| } | |
| .question-container table, .question-container pre, .question-container code { | |
| max-width: 100% !important; | |
| overflow-x: auto !important; | |
| display: block !important; | |
| -webkit-overflow-scrolling: touch; | |
| } | |
| .mjx-container, mjx-container { max-width: 100% !important; overflow-x: auto !important; overflow-y: hidden !important; } | |
| /* ===== End BLOGSPOT MOBILE FIX ===== */ | |
| </style> | |
| </head> | |
| <body> | |
| <!-- Apps Script Notification --> | |
| <div class="apps-script-notification" id="apps-script-notification"> | |
| <span id="notification-message"></span> | |
| </div> | |
| <!-- Cảnh báo rời màn hình --> | |
| <div class="exit-warning" id="exit-warning"> | |
| <div> | |
| <h2 style="color: #ff6b6b; font-size: 2rem;">⚠️ CẢNH BÁO!</h2> | |
| <p>Bạn đã rời khỏi màn hình thi!</p> | |
| <p style="font-size: 1.2rem;">Hành vi này đã được ghi nhận.</p> | |
| <p>Số lần rời màn hình: <span id="exit-count-display">0</span></p> | |
| <p>Thời gian rời: <span id="exit-time-display">0</span> giây</p> | |
| <button onclick="closeExitWarning()" style="margin-top: 20px; padding: 10px 30px; background: #e74c3c; color: white; border: none; border-radius: 8px; cursor: pointer;"> | |
| Tôi hiểu | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Cảnh báo thoát quá lâu --> | |
| <div class="long-exit-warning" id="long-exit-warning"> | |
| <div> | |
| <h2 style="font-size: 2.5rem;">🚨 CẢNH BÁO NGHIÊM TRỌNG!</h2> | |
| <p style="font-size: 1.5rem;">Bạn đã rời màn hình quá lâu!</p> | |
| <p>Bài thi sẽ tự động nộp sau <span id="countdown">5</span> giây...</p> | |
| <button onclick="closeLongExitWarning()" | |
| style="margin-top: 30px; padding: 15px 40px; background: white; color: #e74c3c; | |
| border: none; border-radius: 10px; font-size: 1.2rem; font-weight: bold; cursor: pointer;"> | |
| QUAY LẠI BÀI THI | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Security Info Modal --> | |
| <div class="modal-overlay" id="security-modal"> | |
| <div class="modal-dialog"> | |
| <div class="security-info-modal"> | |
| <h3>🔒 CHẾ ĐỘ BẢO MẬT</h3> | |
| <p style="font-size: 1.1rem; margin-bottom: 20px;">CHẾ ĐỘ BẢO MẬT ĐÃ ĐƯỢC KÍCH HOẠT:</p> | |
| <ul> | |
| <li>📱 Tự động fullscreen</li> | |
| <li>👁️ Theo dõi rời màn hình</li> | |
| <li>🚫 Chống copy và chụp màn hình</li> | |
| <li>📝 Mọi hành vi gian lận đều được ghi nhận!</li> | |
| <li>⏰ Tự động nộp bài khi thoát quá 5 phút</li> | |
| </ul> | |
| <p style="margin-top: 20px; font-style: italic;">Bài thi sẽ bắt đầu sau khi bạn ấn "Tôi hiểu"</p> | |
| </div> | |
| <div class="modal-buttons"> | |
| <button class="modal-ok" onclick="closeSecurityModal()">Tôi hiểu</button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- User Info Form --> | |
| <div id="user-info-form"> | |
| <div class="form-container"> | |
| <h2 id="quiz-title">Đề kiểm tra</h2> | |
| <div class="form-subtitle">Thời gian: 45 phút</div> | |
| <input type="text" id="fullName" class="form-input" placeholder="Nhập họ và tên" autocomplete="off"> | |
| <input type="text" id="className" class="form-input" placeholder="Nhập lớp" required autocomplete="off"> | |
| <button id="startBtn" type="button" onclick="return startQuizSafe(event)">Bắt đầu làm bài</button> | |
| <button id="historyOutsideBtn" onclick="showHistory()" | |
| style="margin-top: 12px; width: 100%; padding: 12px; | |
| background: linear-gradient(135deg, #9d4edd, #7b2cbf); color: white; | |
| border: none; border-radius: 12px; font-size: 16px; font-weight:700; cursor: pointer;"> | |
| 📋 LỊCH SỬ BÀI LÀM | |
| </button> | |
| <!-- Top vinh danh (hiển thị ngay tại màn hình nhập thông tin) --> | |
| <div class="lb-card" id="login-leaderboard-card" aria-live="polite"> | |
| <div class="lb-head"> | |
| <div class="lb-head-row"> | |
| <div class="lb-title">🏆 TỐP VINH DANH</div> | |
| <div class="lb-ctrl" title="Chọn số lượng hiển thị"> | |
| <label for="lbLimitSel">Top</label> | |
| <select id="lbLimitSel" onchange="try{loadLoginRanking();}catch(e){}"> | |
| <option value="10">10</option> | |
| <option value="15">15</option> | |
| <option value="20">20</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="lb-subrow"> | |
| <span class="lb-flame">🔥</span> | |
| </div> | |
| </div> | |
| <div id="login-ranking-box" class="lb-box">Đang tải xếp hạng...</div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Quiz Section --> | |
| <div id="quiz-section"> | |
| <!-- Header --> | |
| <div class="header"> | |
| <div class="student-info"> | |
| HỌ VÀ TÊN: <span id="student-name"></span> - LỚP: <span id="student-class"></span> | |
| </div> | |
| <div class="timer" id="timer">Còn lại: 45:00</div> | |
| <div class="header-controls"> | |
| <button class="fullscreen-btn" id="fullscreen-btn" onclick="toggleFullscreen()">📱 Fullscreen</button> | |
| <button class="status-toggle-btn" id="status-toggle-btn" onclick="toggleSidebar()">📊 Trạng thái</button> | |
| </div> | |
| </div> | |
| <!-- Mobile: nút tròn Trạng thái (ẩn hai nút dòng ở header) --> | |
| <!-- Main Content --> | |
| <div class="main-container"> | |
| <!-- Question Container --> | |
| <div class="question-container" id="question-container"> | |
| <div id="quiz-content"></div> | |
| <!-- Desktop Navigation --> | |
| <div class="navigation-buttons"> | |
| <button class="nav-btn" onclick="prevQuestion()">Câu trước</button> | |
| <button class="nav-btn" onclick="nextQuestion()">Câu sau</button> | |
| <button class="submit-btn" onclick="submitResults()">Nộp bài</button> | |
| <button class="export-btn" onclick="showResults()">Xuất kết quả</button> | |
| <button class="export-btn" id="export-csv-btn" style="display:none" onclick="exportCSV()">Xuất CSV</button> | |
| </div> | |
| <!-- Mobile Navigation --> | |
| <div class="mobile-nav"> | |
| <button class="mobile-nav-btn" onclick="prevQuestion()">← Câu trước</button> | |
| <button class="mobile-nav-btn" onclick="nextQuestion()">Câu sau →</button> | |
| </div> | |
| <div class="mobile-action-buttons"> | |
| <button class="mobile-action-btn mobile-submit" onclick="submitResults()">Nộp bài</button> | |
| <button class="mobile-action-btn mobile-export" onclick="showResults()">Xuất kết quả</button> | |
| <button class="mobile-action-btn mobile-export" id="export-csv-btn-mobile" style="display:none" onclick="exportCSV()">Xuất CSV</button> | |
| </div> | |
| </div> | |
| <!-- Sidebar - Answer Status --> | |
| <div class="sidebar collapsed" id="sidebar"> | |
| <div class="answer-status"> | |
| <h3>📊 Trạng thái làm bài</h3> | |
| <div class="status-section"> | |
| <h4>🎯 Trắc nghiệm</h4> | |
| <div class="status-grid" id="status-type1"></div> | |
| </div> | |
| <div class="status-section"> | |
| <h4>✅ Đúng/Sai</h4> | |
| <div class="status-grid" id="status-type2"></div> | |
| </div> | |
| <div class="status-section"> | |
| <h4>📝 Điền đáp số</h4> | |
| <div class="status-grid" id="status-type3"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Mobile Status Toggle --> | |
| <button class="mobile-status-toggle" onclick="toggleMobileStatus()">📊</button> | |
| <div class="mobile-status-panel" id="mobile-status-panel"> | |
| <div class="answer-status"> | |
| <h3>📊 Trạng thái làm bài</h3> | |
| <div class="status-section"> | |
| <h4>🎯 Trắc nghiệm</h4> | |
| <div class="status-grid" id="mobile-status-type1"></div> | |
| </div> | |
| <div class="status-section"> | |
| <h4>✅ Đúng/Sai</h4> | |
| <div class="status-grid" id="mobile-status-type2"></div> | |
| </div> | |
| <div class="status-section"> | |
| <h4>📝 Điền đáp số</h4> | |
| <div class="status-grid" id="mobile-status-type3"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Submit Confirm Modal --> | |
| <div class="modal-overlay" id="submit-confirm"> | |
| <div class="modal-dialog"> | |
| <h3>Xác nhận nộp bài</h3> | |
| <p id="confirm-message"></p> | |
| <div class="modal-buttons"> | |
| <button class="modal-ok" onclick="finalizeSubmit()">Nộp bài</button> | |
| <button class="modal-cancel" onclick="cancelSubmit()">Tiếp tục làm</button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Export Confirm Modal --> | |
| <div class="modal-overlay" id="export-confirm"> | |
| <div class="modal-dialog"> | |
| <p id="export-confirm-message" style="margin: 0 0 16px 0;"></p> | |
| <div class="modal-buttons"> | |
| <button class="modal-ok" onclick="confirmExport()">OK</button> | |
| <button class="modal-cancel" onclick="cancelExport()">Hủy</button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Success Modal --> | |
| <div class="modal-overlay" id="success-modal"> | |
| <div class="modal-dialog"> | |
| <div class="success-message" id="success-content"> | |
| <h3>✅ Hoàn thành bài thi!</h3> | |
| <div class="total-score" id="final-score" style="font-size: 2.5rem; margin: 20px 0;">0 điểm</div> | |
| <p>Kết quả của bạn đã được ghi nhận.</p> | |
| <p>Ấn OK để xem chi tiết bài làm.</p> | |
| </div> | |
| <div class="modal-buttons"> | |
| <button class="modal-ok" onclick="closeSuccessModal()">OK</button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Results Modal --> | |
| <div class="modal-overlay" id="results-modal"> | |
| <div class="modal-dialog" style="max-width: 1000px; max-height: 90vh; overflow-y: auto;"> | |
| <h3>📊 Kết quả bài làm</h3> | |
| <div id="results-content"></div> | |
| <div class="modal-buttons"> | |
| <button class="modal-cancel" onclick="openRankingModal()" style="margin-right:10px;">🏆 Xếp hạng</button> | |
| <button class="modal-ok" onclick="closeResultsModal()">Đóng</button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Ranking Modal --> | |
| <div class="modal-overlay" id="ranking-modal"> | |
| <div class="modal-dialog" style="max-width: 720px; max-height: 85vh; overflow-y: auto;"> | |
| <h3>🏆 Xếp hạng</h3> | |
| <div style="font-size:14px; color:#666; margin-bottom:10px;"> | |
| Xếp hạng theo <b>điểm cao</b>, nếu bằng điểm thì <b>thời gian nhanh</b> hơn xếp trên. | |
| </div> | |
| <div id="ranking-content" style="min-height: 60px;"></div> | |
| <div class="modal-buttons"> | |
| <button class="modal-ok" onclick="closeRankingModal()">Đóng</button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- History Modal --> | |
| <div class="modal-overlay" id="history-modal"> | |
| <div class="modal-dialog" style="max-width: 800px; max-height: 90vh; overflow-y: auto;"> | |
| <h3>📋 Lịch sử làm bài</h3> | |
| <div id="history-content"></div> | |
| <div class="modal-buttons"> | |
| <button class="modal-ok" onclick="closeHistoryModal()">Đóng</button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Footer --> | |
| <footer class="quiz-footer"> | |
| <div class="footer-content"> | |
| <div class="footer-main"> | |
| 🎓 Hệ thống được quản lý bởi GV: <strong class="teacher-name">Bùi Minh Phương</strong> | |
| </div> | |
| <div class="footer-school"> | |
| Trường THPT Lạng Giang số 3 | Xã Tiên Lục - Tỉnh Bắc Ninh | |
| </div> | |
| <div class="footer-sub"> | |
| BMP SmartQuiz - Hệ thống tạo đề thi thông minh | |
| </div> | |
| </div> | |
| </footer> | |
| <script> | |
| // Bank data và cấu hình | |
| let bankData = {"part1":{"NB":[{"question":"Gi\u1ea3m ph\u00e2n l\u00e0 h\u00ecnh th\u1ee9c ph\u00e2n b\u00e0o x\u1ea3y ra \u1edf","options":[{"text":"C\u00e1c t\u1ebf b\u00e0o m\u1ea7m sinh d\u1ee5c","is_correct":1},{"text":"T\u1ea5t c\u1ea3 t\u1ebf b\u00e0o sinh d\u01b0\u1ee1ng","is_correct":0},{"text":"M\u1ecdi t\u1ebf b\u00e0o trong c\u01a1 th\u1ec3","is_correct":0},{"text":"T\u1ebf b\u00e0o \u0111\u00e3 bi\u1ec7t h\u00f3a ho\u00e0n to\u00e0n","is_correct":0}],"level":"NB"},{"question":"Tr\u01b0\u1edbc khi b\u01b0\u1edbc v\u00e0o gi\u1ea3m ph\u00e2n, t\u1ebf b\u00e0o tr\u1ea3i qua","options":[{"text":"K\u00ec trung gian \u0111\u1ec3 nh\u00e2n \u0111\u00f4i NST","is_correct":1},{"text":"K\u00ec \u0111\u1ea7u \u0111\u1ec3 ph\u00e2n li NST","is_correct":0},{"text":"Pha M \u0111\u1ec3 ph\u00e2n chia t\u1ebf b\u00e0o","is_correct":0},{"text":"Qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o nguy\u00ean nhi\u1ec5m","is_correct":0}],"level":"NB"},{"question":"Gi\u1ea3m ph\u00e2n g\u1ed3m m\u1ea5y l\u1ea7n ph\u00e2n b\u00e0o li\u00ean ti\u1ebfp","options":[{"text":"Hai l\u1ea7n ph\u00e2n b\u00e0o","is_correct":1},{"text":"M\u1ed9t l\u1ea7n ph\u00e2n b\u00e0o","is_correct":0},{"text":"Ba l\u1ea7n ph\u00e2n b\u00e0o","is_correct":0},{"text":"B\u1ed1n l\u1ea7n ph\u00e2n b\u00e0o","is_correct":0}],"level":"NB"},{"question":"\u1ede k\u00ec \u0111\u1ea7u I c\u1ee7a gi\u1ea3m ph\u00e2n, hi\u1ec7n t\u01b0\u1ee3ng \u0111\u1eb7c tr\u01b0ng l\u00e0","options":[{"text":"C\u00e1c c\u1eb7p NST t\u01b0\u01a1ng \u0111\u1ed3ng ti\u1ebfp h\u1ee3p v\u00e0 trao \u0111\u1ed5i ch\u00e9o","is_correct":1},{"text":"NST x\u1ebfp th\u00e0nh m\u1ed9t h\u00e0ng \u1edf m\u1eb7t ph\u1eb3ng x\u00edch \u0111\u1ea1o","is_correct":0},{"text":"Hai cromatid ch\u1ecb em t\u00e1ch nhau","is_correct":0},{"text":"M\u00e0ng nh\u00e2n h\u00ecnh th\u00e0nh l\u1ea1i","is_correct":0}],"level":"NB"},{"question":"Trao \u0111\u1ed5i ch\u00e9o x\u1ea3y ra gi\u1eefa","options":[{"text":"Hai cromatid kh\u00f4ng ch\u1ecb em trong c\u1eb7p NST t\u01b0\u01a1ng \u0111\u1ed3ng","is_correct":1},{"text":"Hai cromatid ch\u1ecb em c\u1ee7a c\u00f9ng m\u1ed9t NST","is_correct":0},{"text":"Hai NST \u0111\u01a1n kh\u00f4ng t\u01b0\u01a1ng \u0111\u1ed3ng","is_correct":0},{"text":"Hai cromatid c\u1ee7a hai t\u1ebf b\u00e0o kh\u00e1c nhau","is_correct":0}],"level":"NB"},{"question":"\u1ede k\u00ec gi\u1eefa I c\u1ee7a gi\u1ea3m ph\u00e2n, c\u00e1c c\u1eb7p NST t\u01b0\u01a1ng \u0111\u1ed3ng","options":[{"text":"X\u1ebfp th\u00e0nh hai h\u00e0ng tr\u00ean m\u1eb7t ph\u1eb3ng x\u00edch \u0111\u1ea1o","is_correct":1},{"text":"X\u1ebfp th\u00e0nh m\u1ed9t h\u00e0ng nh\u01b0 nguy\u00ean ph\u00e2n","is_correct":0},{"text":"B\u1eaft \u0111\u1ea7u t\u00e1ch nhau t\u1ea1i t\u00e2m \u0111\u1ed9ng","is_correct":0},{"text":"D\u00e3n xo\u1eafn ho\u00e0n to\u00e0n","is_correct":0}],"level":"NB"},{"question":"S\u1ef1 ph\u00e2n li c\u1ee7a c\u00e1c c\u1eb7p NST t\u01b0\u01a1ng \u0111\u1ed3ng di\u1ec5n ra \u1edf","options":[{"text":"K\u00ec sau I","is_correct":1},{"text":"K\u00ec \u0111\u1ea7u I","is_correct":0},{"text":"K\u00ec gi\u1eefa II","is_correct":0},{"text":"K\u00ec cu\u1ed1i II","is_correct":0}],"level":"NB"},{"question":"K\u1ebft th\u00fac gi\u1ea3m ph\u00e2n I, m\u1ed7i t\u1ebf b\u00e0o con c\u00f3","options":[{"text":"B\u1ed9 NST \u0111\u01a1n b\u1ed9i nh\u01b0ng v\u1eabn \u1edf tr\u1ea1ng th\u00e1i k\u00e9p","is_correct":1},{"text":"B\u1ed9 NST l\u01b0\u1ee1ng b\u1ed9i \u1edf tr\u1ea1ng th\u00e1i \u0111\u01a1n","is_correct":0},{"text":"B\u1ed9 NST l\u01b0\u1ee1ng b\u1ed9i \u1edf tr\u1ea1ng th\u00e1i k\u00e9p","is_correct":0},{"text":"B\u1ed9 NST \u0111\u01a1n b\u1ed9i \u1edf tr\u1ea1ng th\u00e1i \u0111\u01a1n","is_correct":0}],"level":"NB"},{"question":"Gi\u1ea3m ph\u00e2n II v\u1ec1 b\u1ea3n ch\u1ea5t gi\u1ed1ng v\u1edbi","options":[{"text":"Nguy\u00ean ph\u00e2n","is_correct":1},{"text":"Th\u1ee5 tinh","is_correct":0},{"text":"Nh\u00e2n \u0111\u00f4i DNA","is_correct":0},{"text":"Ph\u00e2n b\u00e0o amit","is_correct":0}],"level":"NB"},{"question":"\u1ede k\u00ec sau II c\u1ee7a gi\u1ea3m ph\u00e2n","options":[{"text":"Hai cromatid ch\u1ecb em c\u1ee7a m\u1ed7i NST t\u00e1ch nhau","is_correct":1},{"text":"C\u00e1c c\u1eb7p NST t\u01b0\u01a1ng \u0111\u1ed3ng ph\u00e2n li","is_correct":0},{"text":"NST ti\u1ebfp h\u1ee3p v\u00e0 trao \u0111\u1ed5i ch\u00e9o","is_correct":0},{"text":"M\u00e0ng nh\u00e2n b\u1eaft \u0111\u1ea7u ti\u00eau bi\u1ebfn","is_correct":0}],"level":"NB"},{"question":"K\u1ebft th\u00fac gi\u1ea3m ph\u00e2n II, t\u1eeb m\u1ed9t t\u1ebf b\u00e0o ban \u0111\u1ea7u t\u1ea1o ra","options":[{"text":"B\u1ed1n t\u1ebf b\u00e0o con \u0111\u01a1n b\u1ed9i","is_correct":1},{"text":"Hai t\u1ebf b\u00e0o con l\u01b0\u1ee1ng b\u1ed9i","is_correct":0},{"text":"Hai t\u1ebf b\u00e0o con \u0111\u01a1n b\u1ed9i","is_correct":0},{"text":"B\u1ed1n t\u1ebf b\u00e0o con l\u01b0\u1ee1ng b\u1ed9i","is_correct":0}],"level":"NB"},{"question":"C\u00e1c t\u1ebf b\u00e0o con sau gi\u1ea3m ph\u00e2n","options":[{"text":"C\u00f3 b\u1ed9 NST \u0111\u01a1n b\u1ed9i v\u00e0 kh\u00e1c nhau v\u1ec1 ki\u1ec3u gen","is_correct":1},{"text":"C\u00f3 b\u1ed9 NST l\u01b0\u1ee1ng b\u1ed9i v\u00e0 gi\u1ed1ng nhau","is_correct":0},{"text":"C\u00f3 ki\u1ec3u gen gi\u1ed1ng h\u1ec7t t\u1ebf b\u00e0o m\u1eb9","is_correct":0},{"text":"Kh\u00f4ng mang th\u00f4ng tin di truy\u1ec1n","is_correct":0}],"level":"NB"},{"question":"Nguy\u00ean nh\u00e2n t\u1ea1o ra s\u1ef1 \u0111a d\u1ea1ng di truy\u1ec1n trong gi\u1ea3m ph\u00e2n l\u00e0","options":[{"text":"Ph\u00e2n li \u0111\u1ed9c l\u1eadp v\u00e0 trao \u0111\u1ed5i ch\u00e9o NST","is_correct":1},{"text":"Nh\u00e2n \u0111\u00f4i DNA tr\u01b0\u1edbc ph\u00e2n b\u00e0o","is_correct":0},{"text":"Ph\u00e2n chia t\u1ebf b\u00e0o ch\u1ea5t","is_correct":0},{"text":"H\u00ecnh th\u00e0nh thoi ph\u00e2n b\u00e0o","is_correct":0}],"level":"NB"},{"question":"\u1ede \u0111\u1ed9ng v\u1eadt, k\u1ebft qu\u1ea3 gi\u1ea3m ph\u00e2n c\u1ee7a t\u1ebf b\u00e0o sinh tinh l\u00e0","options":[{"text":"T\u1ea1o ra b\u1ed1n tinh tr\u00f9ng","is_correct":1},{"text":"T\u1ea1o ra m\u1ed9t tinh tr\u00f9ng v\u00e0 ba th\u1ec3 c\u1ef1c","is_correct":0},{"text":"T\u1ea1o ra hai tinh tr\u00f9ng","is_correct":0},{"text":"T\u1ea1o ra m\u1ed9t tinh tr\u00f9ng","is_correct":0}],"level":"NB"},{"question":"\u1ede ng\u01b0\u1eddi, t\u1ebf b\u00e0o sinh tr\u1ee9ng sau gi\u1ea3m ph\u00e2n t\u1ea1o ra","options":[{"text":"M\u1ed9t tr\u1ee9ng v\u00e0 ba th\u1ec3 c\u1ef1c","is_correct":1},{"text":"B\u1ed1n tr\u1ee9ng c\u00f3 k\u00edch th\u01b0\u1edbc b\u1eb1ng nhau","is_correct":0},{"text":"Hai tr\u1ee9ng v\u00e0 hai th\u1ec3 c\u1ef1c","is_correct":0},{"text":"M\u1ed9t tr\u1ee9ng v\u00e0 m\u1ed9t th\u1ec3 c\u1ef1c","is_correct":0}],"level":"NB"},{"question":"Y\u1ebfu t\u1ed1 n\u00e0o sau \u0111\u00e2y l\u00e0 y\u1ebfu t\u1ed1 di truy\u1ec1n \u1ea3nh h\u01b0\u1edfng \u0111\u1ebfn gi\u1ea3m ph\u00e2n","options":[{"text":"Ho\u1ea1t \u0111\u1ed9ng c\u1ee7a c\u00e1c gen ki\u1ec3m so\u00e1t ph\u00e2n b\u00e0o","is_correct":1},{"text":"\u00c1nh s\u00e1ng chi\u1ebfu v\u00e0o ban \u0111\u00eam","is_correct":0},{"text":"Ch\u1ebf \u0111\u1ed9 t\u01b0\u1edbi n\u01b0\u1edbc cho c\u00e2y","is_correct":0},{"text":"Nhi\u1ec7t \u0111\u1ed9 m\u00f4i tr\u01b0\u1eddng ngo\u00e0i","is_correct":0}],"level":"NB"},{"question":"Tu\u1ed5i t\u00e1c c\u1ee7a con ng\u01b0\u1eddi \u1ea3nh h\u01b0\u1edfng \u0111\u1ebfn gi\u1ea3m ph\u00e2n v\u00ec","options":[{"text":"L\u00e0m t\u0103ng nguy c\u01a1 r\u1ed1i lo\u1ea1n ph\u00e2n li NST","is_correct":1},{"text":"L\u00e0m t\u0103ng t\u1ed1c \u0111\u1ed9 gi\u1ea3m ph\u00e2n","is_correct":0},{"text":"L\u00e0m gi\u1ea3m s\u1ed1 l\u1ea7n ph\u00e2n b\u00e0o","is_correct":0},{"text":"Kh\u00f4ng \u1ea3nh h\u01b0\u1edfng \u0111\u1ebfn ph\u00e2n b\u00e0o","is_correct":0}],"level":"NB"},{"question":"\u00dd ngh\u0129a sinh h\u1ecdc quan tr\u1ecdng c\u1ee7a gi\u1ea3m ph\u00e2n l\u00e0","options":[{"text":"T\u1ea1o giao t\u1eed v\u00e0 duy tr\u00ec \u1ed5n \u0111\u1ecbnh b\u1ed9 NST lo\u00e0i","is_correct":1},{"text":"L\u00e0m t\u0103ng s\u1ed1 l\u01b0\u1ee3ng t\u1ebf b\u00e0o c\u01a1 th\u1ec3","is_correct":0},{"text":"Gi\u00fap c\u01a1 th\u1ec3 sinh tr\u01b0\u1edfng v\u00e0 ph\u00e1t tri\u1ec3n","is_correct":0},{"text":"Thay th\u1ebf c\u00e1c t\u1ebf b\u00e0o gi\u00e0 ch\u1ebft","is_correct":0}],"level":"NB"},{"question":"Gi\u1ea3m ph\u00e2n k\u1ebft h\u1ee3p v\u1edbi th\u1ee5 tinh c\u00f3 vai tr\u00f2","options":[{"text":"T\u1ea1o bi\u1ebfn d\u1ecb t\u1ed5 h\u1ee3p v\u00e0 duy tr\u00ec \u0111\u1eb7c tr\u01b0ng di truy\u1ec1n lo\u00e0i","is_correct":1},{"text":"L\u00e0m gi\u1ea3m d\u1ea7n s\u1ed1 l\u01b0\u1ee3ng NST qua c\u00e1c th\u1ebf h\u1ec7","is_correct":0},{"text":"Lo\u1ea1i b\u1ecf ho\u00e0n to\u00e0n c\u00e1c \u0111\u1ed9t bi\u1ebfn gen","is_correct":0},{"text":"T\u1ea1o ra c\u00e1c t\u1ebf b\u00e0o sinh d\u01b0\u1ee1ng m\u1edbi","is_correct":0}],"level":"NB"},{"question":"S\u1ef1 ti\u1ebfp h\u1ee3p v\u00e0 trao \u0111\u1ed5i ch\u00e9o c\u00e1c \u0111o\u1ea1n chromatid c\u1ee7a c\u1eb7p NST k\u00e9p t\u01b0\u01a1ng \u0111\u1ed3ng x\u1ea3y ra \u1edf","options":[{"text":"k\u00ec \u0111\u1ea7u I","is_correct":1},{"text":"k\u00ec sau I.","is_correct":0},{"text":"k\u00ec gi\u1eefa I","is_correct":0},{"text":"k\u00ec cu\u1ed1i I.","is_correct":0}],"level":"NB"},{"question":"\u1ede sinh v\u1eadt nh\u00e2n th\u1ef1c, gi\u1ea3m ph\u00e2n \u0111\u01b0\u1ee3c g\u1ecdi l\u00e0","options":[{"text":"ph\u00e2n b\u00e0o nguy\u00ean nhi\u1ec5m","is_correct":0},{"text":"ph\u00e2n b\u00e0o gi\u1ea3m nhi\u1ec5m","is_correct":1},{"text":"ph\u00e2n b\u00e0o tr\u1ef1c ph\u00e2n","is_correct":0},{"text":"ph\u00e2n chia t\u1ebf b\u00e0o ch\u1ea5t","is_correct":0}],"level":"NB"},{"question":"Qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n g\u1ed3m m\u1ea5y l\u1ea7n nh\u00e2n \u0111\u00f4i v\u00e0 m\u1ea5y l\u1ea7n ph\u00e2n b\u00e0o?","options":[{"text":"2 l\u1ea7n nh\u00e2n \u0111\u00f4i, 1 l\u1ea7n ph\u00e2n b\u00e0o.","is_correct":0},{"text":"1 l\u1ea7n nh\u00e2n \u0111\u00f4i, 1 l\u1ea7n ph\u00e2n b\u00e0o.","is_correct":0},{"text":"1 l\u1ea7n nh\u00e2n \u0111\u00f4i, 2 l\u1ea7n ph\u00e2n b\u00e0o.","is_correct":1},{"text":"2 l\u1ea7n nh\u00e2n \u0111\u00f4i, 2 l\u1ea7n ph\u00e2n b\u00e0o.","is_correct":0}],"level":"NB"},{"question":"K\u1ebft th\u00fac qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n, s\u1ed1 NST c\u00f3 trong m\u1ed7i t\u1ebf b\u00e0o con l\u00e0:","options":[{"text":"L\u01b0\u1ee1ng b\u1ed9i \u1edf tr\u1ea1ng th\u00e1i \u0111\u01a1n.","is_correct":0},{"text":"\u0110\u01a1n b\u1ed9i \u1edf tr\u1ea1ng th\u00e1i \u0111\u01a1n.","is_correct":1},{"text":"L\u01b0\u1ee1ng b\u1ed9i \u1edf tr\u1ea1ng th\u00e1i k\u00e9p.","is_correct":0},{"text":"\u0110\u01a1n b\u1ed9i \u1edf tr\u1ea1ng th\u00e1i k\u00e9p.","is_correct":0}],"level":"NB"},{"question":"\u0110\u1eb7c \u0111i\u1ec3m n\u00e0o sau \u0111\u00e2y ch\u1ec9 c\u00f3 \u1edf k\u00ec cu\u1ed1i c\u1ee7a gi\u1ea3m ph\u00e2n 1 m\u00e0 kh\u00f4ng c\u00f3 \u1edf k\u00ec cu\u1ed1i c\u1ee7a gi\u1ea3m ph\u00e2n 2?","options":[{"text":"M\u00e0ng nh\u00e2n xu\u1ea5t hi\u1ec7n.","is_correct":0},{"text":"Thoi t\u01a1 v\u00f4 s\u1eafc bi\u1ebfn m\u1ea5t.","is_correct":0},{"text":"NST \u1edf d\u1ea1ng s\u1ee3i \u0111\u01a1n.","is_correct":0},{"text":"C\u00e1c NST \u1edf d\u1ea1ng s\u1ee3i k\u00e9p.","is_correct":1}],"level":"NB"},{"question":"\u00dd ngh\u0129a v\u1ec1 m\u1eb7t di truy\u1ec1n c\u1ee7a s\u1ef1 trao \u0111\u1ed5i ch\u00e9o NST l\u00e0","options":[{"text":"L\u00e0m t\u0103ng s\u1ed1 l\u01b0\u1ee3ng NST trong t\u1ebf b\u00e0o.","is_correct":0},{"text":"T\u1ea1o ra s\u1ef1 \u1ed5n \u0111\u1ecbnh v\u1ec1 th\u00f4ng tin di truy\u1ec1n.","is_correct":0},{"text":"T\u1ea1o ra nhi\u1ec1u lo\u1ea1i giao t\u1eed, g\u00f3p ph\u1ea7n t\u1ea1o ra s\u1ef1 \u0111a d\u1ea1ng sinh h\u1ecdc","is_correct":1},{"text":"Duy tr\u00ec t\u00ednh \u0111\u1eb7c tr\u01b0ng v\u1ec1 c\u1ea5u tr\u00fac NST.","is_correct":0}],"level":"NB"},{"question":"\u0110\u1eb7c \u0111i\u1ec3m n\u00e0o sau \u0111\u00e2y c\u00f3 \u1edf gi\u1ea3m ph\u00e2n m\u00e0 kh\u00f4ng c\u00f3 \u1edf nguy\u00ean ph\u00e2n?","options":[{"text":"X\u1ea3y ra s\u1ef1 ti\u1ebfp h\u1ee3p v\u00e0 c\u00f3 th\u1ec3 c\u00f3 hi\u1ec7n t\u01b0\u1ee3ng trao \u0111\u1ed5i ch\u00e9o.","is_correct":1},{"text":"C\u00f3 s\u1ef1 ph\u00e2n chia c\u1ee7a t\u1ebf b\u00e0o ch\u1ea5t.","is_correct":0},{"text":"C\u00f3 s\u1ef1 ph\u00e2n chia nh\u00e2n.","is_correct":0},{"text":"NST t\u1ef1 nh\u00e2n \u0111\u00f4i \u1edf k\u00ec trung gian th\u00e0nh c\u00e1c NST k\u00e9p.","is_correct":0}],"level":"NB"},{"question":"Gi\u1ea3m ph\u00e2n ch\u1ec9 x\u1ea3y ra \u1edf lo\u1ea1i t\u1ebf b\u00e0o n\u00e0o sau \u0111\u00e2y?","options":[{"text":"T\u1ebf b\u00e0o sinh d\u01b0\u1ee1ng.","is_correct":0},{"text":"T\u1ebf b\u00e0o giao t\u1eed.","is_correct":0},{"text":"T\u1ebf b\u00e0o sinh d\u1ee5c ch\u00edn.","is_correct":1},{"text":"H\u1ee3p t\u1eed.","is_correct":0}],"level":"NB"},{"question":"Trong gi\u1ea3m ph\u00e2n, s\u1ef1 t\u1ef1 nh\u00e2n \u0111\u00f4i c\u1ee7a NST x\u1ea3y ra \u1edf:","options":[{"text":"K\u00ec trung gian c\u1ee7a l\u1ea7n ph\u00e2n b\u00e0o I.","is_correct":1},{"text":"K\u00ec gi\u1eefa c\u1ee7a l\u1ea7n ph\u00e2n b\u00e0o I.","is_correct":0},{"text":"K\u00ec trung gian c\u1ee7a l\u1ea7n ph\u00e2n b\u00e0o II.","is_correct":0},{"text":"K\u00ec gi\u1eefa c\u1ee7a l\u1ea7n ph\u00e2n b\u00e0o II.","is_correct":0}],"level":"NB"},{"question":"T\u1eebng NST k\u00e9p t\u00e1ch nhau \u1edf t\u00e2m \u0111\u1ed9ng th\u00e0nh 2 NST \u0111\u01a1n ph\u00e2n li v\u1ec1 2 c\u1ef1c c\u1ee7a t\u1ebf b\u00e0o. NST b\u1eaft \u0111\u1ea7u th\u00e1o xo\u1eafn. Q\u00faa tr\u00ecnh n\u00e0y l\u00e0 \u1edf k\u00ec n\u00e0o c\u1ee7a nguy\u00ean ph\u00e2n?","options":[{"text":"K\u00ec \u0111\u1ea7u.","is_correct":0},{"text":"K\u00ec gi\u1eefa","is_correct":0},{"text":"K\u00ec sau.","is_correct":1},{"text":"K\u00ec cu\u1ed1i.","is_correct":0}],"level":"NB"},{"question":"Ph\u00e1t bi\u1ec3u n\u00e0o sau \u0111\u00e2y \u0111\u00fang v\u1edbi s\u1ef1 ph\u00e2n li c\u1ee7a c\u00e1c NST \u1edf k\u00ec sau I c\u1ee7a gi\u1ea3m ph\u00e2n?","options":[{"text":"Ph\u00e2n li c\u00e1c NST \u0111\u01a1n.","is_correct":0},{"text":"Ph\u00e2n li c\u00e1c NST k\u00e9p, kh\u00f4ng t\u00e1ch t\u00e2m \u0111\u1ed9ng.","is_correct":1},{"text":"NST ch\u1ec9 di chuy\u1ec3n v\u1ec1 1 c\u1ef1c c\u1ee7a t\u1ebf b\u00e0o.","is_correct":0},{"text":"T\u00e1ch t\u00e2m \u0111\u1ed9ng r\u1ed3i m\u1edbi ph\u00e2n li.","is_correct":0}],"level":"NB"},{"question":"\u1ede th\u1eddi k\u00ec \u0111\u1ea7u gi\u1ea3m ph\u00e2n 2 kh\u00f4ng c\u00f3 hi\u1ec7n t\u01b0\u1ee3ng:","options":[{"text":"NST co ng\u1eafn v\u00e0 hi\u1ec7n r\u00f5 d\u1ea7n.","is_correct":0},{"text":"NST ti\u1ebfp h\u1ee3p v\u00e0 trao \u0111\u1ed5i ch\u00e9o.","is_correct":1},{"text":"m\u00e0ng nh\u00e2n ph\u1ed3ng l\u00ean v\u00e0 bi\u1ebfn m\u1ea5t.","is_correct":0},{"text":"thoi t\u01a1 v\u00f4 s\u1eafc b\u1eaft \u0111\u1ea7u h\u00ecnh th\u00e0nh.","is_correct":0}],"level":"NB"},{"question":"Qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n di\u1ec5n ra \u1edf lo\u1ea1i t\u1ebf b\u00e0o n\u00e0o sau \u0111\u00e2y?","options":[{"text":"H\u1ee3p t\u1eed.","is_correct":0},{"text":"T\u1ebf b\u00e0o sinh d\u1ee5c ch\u00edn.","is_correct":1},{"text":"T\u1ebf b\u00e0o sinh d\u1ee5c s\u01a1 khai.","is_correct":0},{"text":"T\u1ebf b\u00e0o sinh d\u01b0\u1ee1ng.","is_correct":0}],"level":"NB"},{"question":"\u1ede giai \u0111o\u1ea1n n\u00e0o sau \u0111\u00e2y NST c\u00f3 d\u1ea1ng s\u1ee3i \u0111\u01a1n?","options":[{"text":"K\u00ec sau gi\u1ea3m ph\u00e2n 2.","is_correct":1},{"text":"K\u00ec \u0111\u1ea7u gi\u1ea3m ph\u00e2n 2.","is_correct":0},{"text":"K\u00ec sau gi\u1ea3m ph\u00e2n 1.","is_correct":0},{"text":"K\u00ec gi\u1eefa gi\u1ea3m ph\u00e2n 2.","is_correct":0}],"level":"NB"},{"question":"Hi\u1ec7n t\u01b0\u1ee3ng ti\u1ebfp h\u1ee3p v\u00e0 c\u00f3 th\u1ec3 d\u1eabn t\u1edbi trao \u0111\u1ed5i ch\u00e9o gi\u1eefa c\u00e1c cr\u00f4mat\u00edt trong c\u1eb7p NST t\u01b0\u01a1ng \u0111\u1ed3ng \u0111\u01b0\u1ee3c di\u1ec5n ra v\u00e0o giai \u0111o\u1ea1n n\u00e0o sau \u0111\u00e2y?","options":[{"text":"K\u00ec \u0111\u1ea7u c\u1ee7a gi\u1ea3m ph\u00e2n 2.","is_correct":0},{"text":"K\u00ec sau c\u1ee7a gi\u1ea3m ph\u00e2n 2.","is_correct":0},{"text":"K\u00ec \u0111\u1ea7u c\u1ee7a gi\u1ea3m ph\u00e2n 1.","is_correct":1},{"text":"K\u00ec sau c\u1ee7a gi\u1ea3m ph\u00e2n 1.","is_correct":0}],"level":"NB"},{"question":"Ho\u1ea1t \u0111\u1ed9ng n\u00e0o sau \u0111\u00e2y x\u1ea3y ra \u1edf k\u00ec sau c\u1ee7a qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n 1?","options":[{"text":"M\u1ed7i NST k\u00e9p trong c\u1eb7p t\u01b0\u01a1ng \u0111\u1ed3ng ph\u00e2n li \u0111\u1ed9c l\u1eadp v\u1ec1 hai c\u1ef1c t\u1ebf b\u00e0o.","is_correct":0},{"text":"NST co ng\u1eafn c\u1ef1c \u0111\u1ea1i v\u00e0 x\u1ebfp hai h\u00e0ng ngang tr\u00ean m\u1eb7t ph\u1eb3ng x\u00edch \u0111\u1ea1o.","is_correct":0},{"text":"M\u1ed7i NST k\u00e9p t\u00e1ch nhau ra th\u00e0nh hai NST \u0111\u01a1n, ti\u1ebfn v\u1ec1 hai c\u1ef1c t\u1ebf b\u00e0o.","is_correct":1},{"text":"M\u00e0ng t\u1ebf b\u00e0o eo l\u1ea1i v\u00e0 h\u00ecnh th\u00e0nh hai t\u1ebf b\u00e0o m\u1edbi c\u00f3 b\u1ed9 NST gi\u1ea3m \u0111i m\u1ed9t n\u1eeda","is_correct":0}],"level":"NB"},{"question":"Trong qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n, ng\u01b0\u1eddi ta quan s\u00e1t th\u1ea5y c\u00e1c NST k\u00e9p trong t\u1ebf b\u00e0o \u1edf bao nhi\u00eau giai \u0111o\u1ea1n sau \u0111\u00e2y?\nI. K\u00ec \u0111\u1ea7u I.II. K\u00ec sau I.III. K\u00ec cu\u1ed1i I.\nIV. K\u00ec gi\u1eefa IIV. K\u00ec sau II.VI. K\u00ec cu\u1ed1i II.","options":[{"text":"2.","is_correct":0},{"text":"3.","is_correct":0},{"text":"4.","is_correct":1},{"text":"5.","is_correct":0}],"level":"NB"},{"question":"Ph\u00e2n b\u00e0o 1 c\u1ee7a gi\u1ea3m ph\u00e2n \u0111\u01b0\u1ee3c g\u1ecdi l\u00e0 ph\u00e2n b\u00e0o gi\u1ea3m nhi\u1ec5m v\u00ec nguy\u00ean nh\u00e2n n\u00e0o sau \u0111\u00e2y?","options":[{"text":"\u1ede k\u00ec cu\u1ed1i, b\u1ed9 nhi\u1ec5m s\u1eafc th\u1ec3 c\u00f3 d\u1ea1ng s\u1ee3i k\u00e9p, d\u00e3n xo\u1eafn.","is_correct":0},{"text":"M\u1ed7i t\u1ebf b\u00e0o con \u0111\u1ec1u c\u00f3 b\u1ed9 nhi\u1ec5m s\u1eafc th\u1ec3 \u0111\u01a1n b\u1ed9i.","is_correct":0},{"text":"H\u00e0m l\u01b0\u1ee3ng DNA c\u1ee7a t\u1ebf b\u00e0o con b\u1eb1ng m\u1ed9t n\u1eefa t\u1ebf b\u00e0o m\u1eb9.","is_correct":0},{"text":"B\u1ed9 NST c\u1ee7a t\u1ebf b\u00e0o con b\u1eb1ng m\u1ed9t n\u1eeda so v\u1edbi t\u1ebf b\u00e0o m\u1eb9.","is_correct":1}],"level":"NB"},{"question":"Tr\u01b0\u1eddng h\u1ee3p n\u00e0o sau \u0111\u00e2y \u0111\u01b0\u1ee3c g\u1ecdi l\u00e0 gi\u1ea3m ph\u00e2n?","options":[{"text":"T\u1ebf b\u00e0o m\u1eb9 2n t\u1ea1o ra c\u00e1c t\u1ebf b\u00e0o con c\u00f3 b\u1ed9 NST 2n.","is_correct":0},{"text":"T\u1ebf b\u00e0o m\u1eb9 4n t\u1ea1o ra c\u00e1c t\u1ebf b\u00e0o con c\u00f3 b\u1ed9 NST 2n.","is_correct":1},{"text":"T\u1ebf b\u00e0o m\u1eb9 n t\u1ea1o ra c\u00e1c t\u1ebf b\u00e0o con c\u00f3 b\u1ed9 NST n.","is_correct":0},{"text":"T\u1ebf b\u00e0o vi khu\u1ea9n t\u1ea1o ra c\u00e1c t\u1ebf b\u00e0o vi khu\u1ea9n.","is_correct":0}],"level":"NB"},{"question":"Khi n\u00f3i v\u1ec1 ph\u00e2n b\u00e0o gi\u1ea3m ph\u00e2n, ph\u00e1t bi\u1ec3u n\u00e0o sau \u0111\u00e2y \u0111\u00fang?","options":[{"text":"T\u1ea5t c\u1ea3 m\u1ecdi t\u1ebf b\u00e0o \u0111\u1ec1u c\u00f3 th\u1ec3 ti\u1ebfn h\u00e0nh gi\u1ea3m ph\u00e2n.","is_correct":0},{"text":"T\u1eeb 1 t\u1ebf b\u00e0o 2n qua gi\u1ea3m ph\u00e2n b\u00ecnh th\u01b0\u1eddng s\u1ebd t\u1ea1o ra 4 t\u1ebf b\u00e0o n.","is_correct":1},{"text":"Qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n lu\u00f4n t\u1ea1o ra t\u1ebf b\u00e0o con c\u00f3 b\u1ed9 NST \u0111\u01a1n b\u1ed9i.","is_correct":0},{"text":"S\u1ef1 ph\u00e2n b\u00e0o gi\u1ea3m ph\u00e2n lu\u00f4n d\u1eabn t\u1edbi qu\u00e1 tr\u00ecnh t\u1ea1o giao t\u1eed.","is_correct":0}],"level":"NB"}],"TH":[{"question":"Gi\u1ea3m ph\u00e2n ch\u1ec9 x\u1ea3y ra \u1edf t\u1ebf b\u00e0o m\u1ea7m sinh d\u1ee5c v\u00ec","options":[{"text":"Gi\u1ea3m ph\u00e2n t\u1ea1o giao t\u1eed mang b\u1ed9 NST \u0111\u01a1n b\u1ed9i","is_correct":1},{"text":"C\u00e1c t\u1ebf b\u00e0o kh\u00e1c kh\u00f4ng ch\u1ee9a DNA","is_correct":0},{"text":"T\u1ebf b\u00e0o sinh d\u01b0\u1ee1ng kh\u00f4ng c\u00f3 NST","is_correct":0},{"text":"T\u1ebf b\u00e0o m\u1ea7m kh\u00f4ng c\u1ea7n nguy\u00ean ph\u00e2n","is_correct":0}],"level":"TH"},{"question":"Vi\u1ec7c NST nh\u00e2n \u0111\u00f4i tr\u01b0\u1edbc khi b\u01b0\u1edbc v\u00e0o gi\u1ea3m ph\u00e2n c\u00f3 \u00fd ngh\u0129a l\u00e0","options":[{"text":"\u0110\u1ea3m b\u1ea3o m\u1ed7i giao t\u1eed v\u1eabn nh\u1eadn \u0111\u1ee7 th\u00f4ng tin di truy\u1ec1n","is_correct":1},{"text":"L\u00e0m t\u0103ng s\u1ed1 l\u01b0\u1ee3ng NST trong t\u1ebf b\u00e0o con","is_correct":0},{"text":"Chu\u1ea9n b\u1ecb cho trao \u0111\u1ed5i ch\u00e9o di\u1ec5n ra","is_correct":0},{"text":"T\u1ea1o \u0111i\u1ec1u ki\u1ec7n cho t\u1ebf b\u00e0o ph\u00e2n chia nhanh","is_correct":0}],"level":"TH"},{"question":"Trao \u0111\u1ed5i ch\u00e9o ch\u1ec9 x\u1ea3y ra \u1edf k\u00ec \u0111\u1ea7u I v\u00ec","options":[{"text":"L\u00fac n\u00e0y c\u00e1c NST t\u01b0\u01a1ng \u0111\u1ed3ng \u0111\u00e3 ti\u1ebfp h\u1ee3p s\u00e1t nhau","is_correct":1},{"text":"NST \u0111\u00e3 ph\u00e2n li v\u1ec1 hai c\u1ef1c t\u1ebf b\u00e0o","is_correct":0},{"text":"M\u00e0ng nh\u00e2n \u0111\u00e3 h\u00ecnh th\u00e0nh tr\u1edf l\u1ea1i","is_correct":0},{"text":"NST \u0111\u00e3 d\u00e3n xo\u1eafn ho\u00e0n to\u00e0n","is_correct":0}],"level":"TH"},{"question":"S\u1ef1 ph\u00e2n li \u0111\u1ed9c l\u1eadp c\u1ee7a c\u00e1c c\u1eb7p NST t\u01b0\u01a1ng \u0111\u1ed3ng trong gi\u1ea3m ph\u00e2n I d\u1eabn \u0111\u1ebfn","options":[{"text":"C\u00e1c giao t\u1eed t\u1ea1o ra c\u00f3 t\u1ed5 h\u1ee3p NST kh\u00e1c nhau","is_correct":1},{"text":"S\u1ed1 l\u01b0\u1ee3ng NST trong t\u1ebf b\u00e0o t\u0103ng l\u00ean","is_correct":0},{"text":"C\u00e1c t\u1ebf b\u00e0o con gi\u1ed1ng h\u1ec7t t\u1ebf b\u00e0o m\u1eb9","is_correct":0},{"text":"C\u00e1c giao t\u1eed c\u00f3 ki\u1ec3u gen gi\u1ed1ng nhau","is_correct":0}],"level":"TH"},{"question":"Gi\u1ea3m ph\u00e2n II \u0111\u01b0\u1ee3c coi l\u00e0 gi\u1ed1ng nguy\u00ean ph\u00e2n v\u00ec","options":[{"text":"\u0110\u1ec1u c\u00f3 s\u1ef1 ph\u00e2n li cromatid ch\u1ecb em","is_correct":1},{"text":"\u0110\u1ec1u l\u00e0m gi\u1ea3m s\u1ed1 l\u01b0\u1ee3ng NST","is_correct":0},{"text":"\u0110\u1ec1u x\u1ea3y ra ti\u1ebfp h\u1ee3p NST","is_correct":0},{"text":"\u0110\u1ec1u t\u1ea1o t\u1ebf b\u00e0o l\u01b0\u1ee1ng b\u1ed9i","is_correct":0}],"level":"TH"},{"question":"Sau gi\u1ea3m ph\u00e2n I, NST v\u1eabn \u1edf tr\u1ea1ng th\u00e1i k\u00e9p v\u00ec","options":[{"text":"Hai cromatid ch\u1ecb em ch\u01b0a t\u00e1ch nhau","is_correct":1},{"text":"DNA ch\u01b0a \u0111\u01b0\u1ee3c nh\u00e2n \u0111\u00f4i","is_correct":0},{"text":"NST ch\u01b0a ti\u1ebfp h\u1ee3p","is_correct":0},{"text":"NST ch\u01b0a x\u1ebfp tr\u00ean m\u1eb7t ph\u1eb3ng x\u00edch \u0111\u1ea1o","is_correct":0}],"level":"TH"},{"question":"Vi\u1ec7c gi\u1ea3m s\u1ed1 l\u01b0\u1ee3ng NST \u0111i m\u1ed9t n\u1eeda trong gi\u1ea3m ph\u00e2n c\u00f3 \u00fd ngh\u0129a","options":[{"text":"Duy tr\u00ec \u1ed5n \u0111\u1ecbnh b\u1ed9 NST c\u1ee7a lo\u00e0i qua c\u00e1c th\u1ebf h\u1ec7","is_correct":1},{"text":"L\u00e0m t\u0103ng nhanh s\u1ed1 l\u01b0\u1ee3ng NST","is_correct":0},{"text":"T\u1ea1o t\u1ebf b\u00e0o sinh d\u01b0\u1ee1ng m\u1edbi","is_correct":0},{"text":"Chu\u1ea9n b\u1ecb cho nguy\u00ean ph\u00e2n ti\u1ebfp theo","is_correct":0}],"level":"TH"},{"question":"N\u1ebfu kh\u00f4ng c\u00f3 trao \u0111\u1ed5i ch\u00e9o, h\u1eadu qu\u1ea3 tr\u1ef1c ti\u1ebfp l\u00e0","options":[{"text":"Gi\u1ea3m s\u1ef1 \u0111a d\u1ea1ng di truy\u1ec1n c\u1ee7a giao t\u1eed","is_correct":1},{"text":"Gi\u1ea3m s\u1ed1 l\u01b0\u1ee3ng t\u1ebf b\u00e0o t\u1ea1o ra","is_correct":0},{"text":"Kh\u00f4ng x\u1ea3y ra gi\u1ea3m ph\u00e2n","is_correct":0},{"text":"NST kh\u00f4ng ph\u00e2n li \u0111\u01b0\u1ee3c","is_correct":0}],"level":"TH"},{"question":"\u1ede \u0111\u1ed9ng v\u1eadt, gi\u1ea3m ph\u00e2n t\u1ea1o ra nhi\u1ec1u tinh tr\u00f9ng nh\u01b0ng ch\u1ec9 m\u1ed9t tr\u1ee9ng v\u00ec","options":[{"text":"S\u1ef1 ph\u00e2n chia t\u1ebf b\u00e0o ch\u1ea5t di\u1ec5n ra kh\u00f4ng \u0111\u1ec1u \u1edf sinh tr\u1ee9ng","is_correct":1},{"text":"Sinh tr\u1ee9ng di\u1ec5n ra ch\u1eadm h\u01a1n sinh tinh","is_correct":0},{"text":"Tinh tr\u00f9ng c\u1ea7n nhi\u1ec1u DNA h\u01a1n tr\u1ee9ng","is_correct":0},{"text":"Tr\u1ee9ng kh\u00f4ng c\u1ea7n nh\u00e2n","is_correct":0}],"level":"TH"},{"question":"S\u1ef1 kh\u00e1c nhau v\u1ec1 ki\u1ec3u gen gi\u1eefa c\u00e1c t\u1ebf b\u00e0o con sau gi\u1ea3m ph\u00e2n ch\u1ee7 y\u1ebfu do","options":[{"text":"Trao \u0111\u1ed5i ch\u00e9o v\u00e0 ph\u00e2n li \u0111\u1ed9c l\u1eadp c\u1ee7a NST","is_correct":1},{"text":"Nh\u00e2n \u0111\u00f4i DNA tr\u01b0\u1edbc ph\u00e2n b\u00e0o","is_correct":0},{"text":"Ph\u00e2n chia t\u1ebf b\u00e0o ch\u1ea5t","is_correct":0},{"text":"H\u00ecnh th\u00e0nh thoi ph\u00e2n b\u00e0o","is_correct":0}],"level":"TH"},{"question":"N\u1ebfu c\u00e1c c\u1eb7p NST t\u01b0\u01a1ng \u0111\u1ed3ng kh\u00f4ng ph\u00e2n li \u1edf gi\u1ea3m ph\u00e2n I th\u00ec","options":[{"text":"C\u00f3 th\u1ec3 t\u1ea1o giao t\u1eed th\u1eeba ho\u1eb7c thi\u1ebfu NST","is_correct":1},{"text":"Gi\u1ea3m ph\u00e2n v\u1eabn di\u1ec5n ra b\u00ecnh th\u01b0\u1eddng","is_correct":0},{"text":"Ch\u1ec9 \u1ea3nh h\u01b0\u1edfng \u0111\u1ebfn gi\u1ea3m ph\u00e2n II","is_correct":0},{"text":"Kh\u00f4ng \u1ea3nh h\u01b0\u1edfng \u0111\u1ebfn th\u1ebf h\u1ec7 sau","is_correct":0}],"level":"TH"},{"question":"Tu\u1ed5i c\u1ee7a ng\u01b0\u1eddi m\u1eb9 c\u00e0ng cao th\u00ec nguy c\u01a1 sinh con m\u1eafc h\u1ed9i ch\u1ee9ng Down t\u0103ng v\u00ec","options":[{"text":"X\u00e1c su\u1ea5t r\u1ed1i lo\u1ea1n ph\u00e2n li NST trong gi\u1ea3m ph\u00e2n t\u0103ng","is_correct":1},{"text":"S\u1ed1 l\u01b0\u1ee3ng NST trong tr\u1ee9ng t\u0103ng","is_correct":0},{"text":"Gi\u1ea3m ph\u00e2n di\u1ec5n ra nhanh h\u01a1n","is_correct":0},{"text":"DNA kh\u00f4ng \u0111\u01b0\u1ee3c nh\u00e2n \u0111\u00f4i","is_correct":0}],"level":"TH"},{"question":"C\u00e1c y\u1ebfu t\u1ed1 m\u00f4i tr\u01b0\u1eddng c\u00f3 th\u1ec3 \u1ea3nh h\u01b0\u1edfng \u0111\u1ebfn gi\u1ea3m ph\u00e2n v\u00ec","options":[{"text":"C\u00f3 th\u1ec3 l\u00e0m r\u1ed1i lo\u1ea1n ho\u1ea1t \u0111\u1ed9ng c\u1ee7a thoi ph\u00e2n b\u00e0o","is_correct":1},{"text":"L\u00e0m thay \u0111\u1ed5i s\u1ed1 l\u01b0\u1ee3ng gen trong t\u1ebf b\u00e0o","is_correct":0},{"text":"Ng\u0103n c\u1ea3n s\u1ef1 ti\u1ebfp h\u1ee3p NST","is_correct":0},{"text":"L\u00e0m m\u1ea5t ho\u00e0n to\u00e0n kh\u1ea3 n\u0103ng ph\u00e2n b\u00e0o","is_correct":0}],"level":"TH"},{"question":"N\u1ebfu gi\u1ea3m ph\u00e2n di\u1ec5n ra sai l\u1ec7ch nh\u01b0ng th\u1ee5 tinh v\u1eabn x\u1ea3y ra th\u00ec","options":[{"text":"C\u00f3 th\u1ec3 t\u1ea1o h\u1ee3p t\u1eed mang b\u1ed9 NST b\u1ea5t th\u01b0\u1eddng","is_correct":1},{"text":"H\u1ee3p t\u1eed lu\u00f4n b\u1ecb ti\u00eau bi\u1ebfn","is_correct":0},{"text":"Kh\u00f4ng h\u00ecnh th\u00e0nh h\u1ee3p t\u1eed","is_correct":0},{"text":"H\u1ee3p t\u1eed v\u1eabn ho\u00e0n to\u00e0n b\u00ecnh th\u01b0\u1eddng","is_correct":0}],"level":"TH"},{"question":"\u00dd ngh\u0129a ti\u1ebfn h\u00f3a c\u1ee7a gi\u1ea3m ph\u00e2n th\u1ec3 hi\u1ec7n \u1edf vi\u1ec7c","options":[{"text":"T\u1ea1o ngu\u1ed3n bi\u1ebfn d\u1ecb t\u1ed5 h\u1ee3p cho ch\u1ecdn l\u1ecdc t\u1ef1 nhi\u00ean","is_correct":1},{"text":"L\u00e0m t\u0103ng nhanh s\u1ed1 l\u01b0\u1ee3ng c\u00e1 th\u1ec3","is_correct":0},{"text":"Duy tr\u00ec k\u00edch th\u01b0\u1edbc c\u01a1 th\u1ec3 \u1ed5n \u0111\u1ecbnh","is_correct":0},{"text":"Gi\u1ea3m t\u1ec9 l\u1ec7 \u0111\u1ed9t bi\u1ebfn gen","is_correct":0}],"level":"TH"},{"question":"Gi\u1ea3m ph\u00e2n kh\u00e1c nguy\u00ean ph\u00e2n c\u01a1 b\u1ea3n \u1edf \u0111i\u1ec3m","options":[{"text":"C\u00f3 hai l\u1ea7n ph\u00e2n b\u00e0o nh\u01b0ng ch\u1ec9 m\u1ed9t l\u1ea7n nh\u00e2n \u0111\u00f4i DNA","is_correct":1},{"text":"Ch\u1ec9 x\u1ea3y ra \u1edf t\u1ebf b\u00e0o sinh d\u01b0\u1ee1ng","is_correct":0},{"text":"Lu\u00f4n t\u1ea1o ra t\u1ebf b\u00e0o l\u01b0\u1ee1ng b\u1ed9i","is_correct":0},{"text":"Kh\u00f4ng li\u00ean quan \u0111\u1ebfn sinh s\u1ea3n","is_correct":0}],"level":"TH"},{"question":"N\u1ebfu m\u1ed9t lo\u00e0i sinh s\u1ea3n h\u1eefu t\u00ednh kh\u00f4ng c\u00f3 gi\u1ea3m ph\u00e2n th\u00ec","options":[{"text":"S\u1ed1 l\u01b0\u1ee3ng NST s\u1ebd t\u0103ng d\u1ea7n qua c\u00e1c th\u1ebf h\u1ec7","is_correct":1},{"text":"Kh\u00f4ng x\u1ea3y ra th\u1ee5 tinh","is_correct":0},{"text":"Giao t\u1eed kh\u00f4ng h\u00ecnh th\u00e0nh","is_correct":0},{"text":"DNA kh\u00f4ng \u0111\u01b0\u1ee3c nh\u00e2n \u0111\u00f4i","is_correct":0}],"level":"TH"},{"question":"Ph\u00e2n li \u0111\u1ed9c l\u1eadp c\u1ee7a c\u00e1c c\u1eb7p NST t\u01b0\u01a1ng \u0111\u1ed3ng x\u1ea3y ra v\u00ec","options":[{"text":"C\u00e1c c\u1eb7p NST x\u1ebfp ng\u1eabu nhi\u00ean tr\u00ean m\u1eb7t ph\u1eb3ng x\u00edch \u0111\u1ea1o","is_correct":1},{"text":"NST lu\u00f4n x\u1ebfp theo m\u1ed9t tr\u1eadt t\u1ef1 c\u1ed1 \u0111\u1ecbnh","is_correct":0},{"text":"Thoi ph\u00e2n b\u00e0o k\u00e9o NST c\u00f9ng chi\u1ec1u","is_correct":0},{"text":"NST kh\u00f4ng ch\u1ecbu t\u00e1c \u0111\u1ed9ng c\u1ee7a m\u00f4i tr\u01b0\u1eddng","is_correct":0}],"level":"TH"},{"question":"Gi\u1ea3m ph\u00e2n g\u00f3p ph\u1ea7n duy tr\u00ec \u1ed5n \u0111\u1ecbnh b\u1ed9 NST lo\u00e0i v\u00ec","options":[{"text":"Gi\u1ea3m ph\u00e2n l\u00e0m gi\u1ea3m NST, th\u1ee5 tinh kh\u00f4i ph\u1ee5c l\u1ea1i","is_correct":1},{"text":"Gi\u1ea3m ph\u00e2n t\u1ea1o t\u1ebf b\u00e0o l\u01b0\u1ee1ng b\u1ed9i","is_correct":0},{"text":"Gi\u1ea3m ph\u00e2n l\u00e0m t\u0103ng s\u1ed1 l\u01b0\u1ee3ng NST","is_correct":0},{"text":"Gi\u1ea3m ph\u00e2n kh\u00f4ng li\u00ean quan \u0111\u1ebfn th\u1ee5 tinh","is_correct":0}],"level":"TH"},{"question":"Gh\u00e9p n\u1ed9i dung \u1edf c\u1ed9t b\u00ean ph\u1ea3i v\u1edbi n\u1ed9i dung \u1edf c\u1ed9t b\u00ean tr\u00e1i \u0111\u1ec3 tr\u1edf th\u00e0nh m\u1ed9t c\u00e2u c\u00f3 n\u1ed9i dung \u0111\u00fang v\u1ec1 di\u1ec5n bi\u1ebfn c\u00e1c k\u00ec c\u1ee7a gi\u1ea3m ph\u00e2n I:\n\u003ctable class=\"bmp-table\" border=\"1\" cellspacing=\"0\" cellpadding=\"6\" style=\"border-collapse:collapse; width:100%;\"\u003e\u003ctr\u003e\u003ctd\u003e1. K\u00ec \u0111\u1ea7u I\u003c/td\u003e\u003ctd\u003ea C\u00e1c NST k\u00e9p d\u00e3n xo\u1eafn, ph\u00e2n chia t\u1ebf b\u00e0o ch\u1ea5t.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e2. K\u00ec gi\u1eefa I\u003c/td\u003e\u003ctd\u003eb M\u1ed7i NST k\u00e9p trong c\u1eb7p t\u01b0\u01a1ng \u0111\u1ed3ng ph\u00e2n li v\u1ec1 m\u1ed9t c\u1ef1c t\u1ebf b\u00e0o.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e3. K\u00ec sau I\u003c/td\u003e\u003ctd\u003ec C\u00e1c NST k\u00e9p t\u01b0\u01a1ng \u0111\u1ed3ng x\u1ebfp 2 h\u00e0ng \u1edf m\u1eb7t ph\u1eb3ng x\u00edch \u0111\u1ea1o.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e4. K\u00ec cu\u1ed1i I\u003c/td\u003e\u003ctd\u003ed C\u00e1c NST k\u00e9p b\u1eaft c\u1eb7p t\u01b0\u01a1ng \u0111\u1ed3ng, c\u00f3 th\u1ec3 x\u1ea3y ra trao \u0111\u1ed5i ch\u00e9o.\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e","options":[{"text":"1-a, 2-b, 3-c, 4-d","is_correct":0},{"text":"1-d, 2-c, 3-b, 4-a","is_correct":1},{"text":"1-d, 2-b, 3-c, 4-a","is_correct":0},{"text":"1-a, 2-c, 3-d, 4-b","is_correct":0}],"level":"TH"},{"question":"Gh\u00e9p n\u1ed9i dung \u1edf c\u1ed9t b\u00ean ph\u1ea3i v\u1edbi n\u1ed9i dung \u1edf c\u1ed9t b\u00ean tr\u00e1i \u0111\u1ec3 tr\u1edf th\u00e0nh m\u1ed9t c\u00e2u c\u00f3 n\u1ed9i dung \u0111\u00fang v\u1ec1 di\u1ec5n bi\u1ebfn c\u00e1c k\u00ec c\u1ee7a gi\u1ea3m ph\u00e2n II:\n\u003ctable class=\"bmp-table\" border=\"1\" cellspacing=\"0\" cellpadding=\"6\" style=\"border-collapse:collapse; width:100%;\"\u003e\u003ctr\u003e\u003ctd\u003e1. K\u00ec \u0111\u1ea7u II\u003c/td\u003e\u003ctd\u003ea C\u00e1c nhi\u1ec5m s\u1eafc th\u1ec3 k\u00e9p t\u1eadp trung th\u00e0nh 1 h\u00e0ng \u1edf m\u1eb7t ph\u1eb3ng x\u00edch \u0111\u1ea1o.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e2. K\u00ec gi\u1eefa II\u003c/td\u003e\u003ctd\u003eb M\u00e0ng nh\u00e2n xu\u1ea5t hi\u1ec7n, ph\u00e2n chia t\u1ebf b\u00e0o ch\u1ea5t, ph\u00e1t sinh giao t\u1eed.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e3. K\u00ec sau II\u003c/td\u003e\u003ctd\u003ec C\u00e1c chromatid t\u00e1ch nhau \u1edf t\u00e2m \u0111\u1ed9ng \u0111i v\u1ec1 2 c\u1ef1c c\u1ee7a t\u1ebf b\u00e0o.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e4. K\u00ec cu\u1ed1i II\u003c/td\u003e\u003ctd\u003ed M\u00e0ng nh\u00e2n ti\u00eau bi\u1ebfn, thoi ph\u00e2n b\u00e0o h\u00ecnh th\u00e0nh.\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e","options":[{"text":"1-a, 2-b, 3-c, 4-d","is_correct":0},{"text":"1-d, 2-c, 3-b, 4-a","is_correct":0},{"text":"1-d, 2-b, 3-c, 4-a","is_correct":1},{"text":"1-a, 2-d, 3-d, 4-c","is_correct":0}],"level":"TH"},{"question":"N\u1ebfu c\u00f3 24 NST k\u00e9p trong m\u1ed9t t\u1ebf b\u00e0o \u1edf k\u00ec cu\u1ed1i I c\u1ee7a gi\u1ea3m ph\u00e2n th\u00ec s\u1ed1 nhi\u1ec5m s\u1eafc th\u1ec3 l\u01b0\u1ee1ng b\u1ed9i l\u00e0","options":[{"text":"2n = 48.","is_correct":1},{"text":"2n = 24.","is_correct":0},{"text":"2n = 6.","is_correct":0},{"text":"2n = 12.","is_correct":0}],"level":"TH"},{"question":"N\u1ebfu c\u00f3 8 NST \u0111\u01a1n trong m\u1ed9t t\u1ebf b\u00e0o \u1edf k\u00ec cu\u1ed1i II c\u1ee7a gi\u1ea3m ph\u00e2n th\u00ec b\u1ed9 NST trong t\u1ebf b\u00e0o ban \u0111\u1ea7u l\u00e0","options":[{"text":"2n = 24.","is_correct":0},{"text":"2n = 48.","is_correct":0},{"text":"2n = 16.","is_correct":1},{"text":"2n = 4.","is_correct":0}],"level":"TH"},{"question":"\u1ede k\u00ec gi\u1eefa I, quan s\u00e1t c\u00f3 96 chromatid, K\u1ebft th\u00fac gi\u1ea3m ph\u00e2n, m\u1ed7i t\u1ebf b\u00e0o ban \u0111\u1ea7u c\u00f3 b\u1ed9 NST l\u00e0","options":[{"text":"n = 24.","is_correct":1},{"text":"2n = 24.","is_correct":0},{"text":"n = 48.","is_correct":0},{"text":"2n = 48.","is_correct":0}],"level":"TH"},{"question":"N\u1ebfu c\u00f3 16 NST \u0111\u01a1n trong m\u1ed9t t\u1ebf b\u00e0o \u1edf k\u00ec sau II c\u1ee7a gi\u1ea3m ph\u00e2n th\u00ec b\u1ed9 NST trong t\u1ebf b\u00e0o ban \u0111\u1ea7u l\u00e0","options":[{"text":"2n = 16.","is_correct":1},{"text":"2n = 8.","is_correct":0},{"text":"2n = 32.","is_correct":0},{"text":"2n = 48.","is_correct":0}],"level":"TH"},{"question":"M\u1ed9t nh\u00f3m t\u1ebf b\u00e0o sinh tinh tham gia gi\u1ea3m ph\u00e2n \u0111\u00e3 t\u1ea1o ra 512 tinh tr\u00f9ng. S\u1ed1 t\u1ebf b\u00e0o sinh tinh l\u00e0","options":[{"text":"16.","is_correct":0},{"text":"32.","is_correct":0},{"text":"64.","is_correct":0},{"text":"128.","is_correct":1}],"level":"TH"},{"question":"M\u1ed9t nh\u00f3m t\u1ebf b\u00e0o sinh tr\u1ee9ng tham gia qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n t\u1ea1o ra 512 tr\u1ee9ng. S\u1ed1 t\u1ebf b\u00e0o sinh tr\u1ee9ng l\u00e0","options":[{"text":"16.","is_correct":0},{"text":"32.","is_correct":0},{"text":"128.","is_correct":0},{"text":"512.","is_correct":1}],"level":"TH"},{"question":"\u1ede ng\u01b0\u1eddi (2n = 46), s\u1ed1 nhi\u1ec5m s\u1eafc th\u1ec3 trong 1 t\u1ebf b\u00e0o \u1edf k\u00ec gi\u1eefa I c\u1ee7a gi\u1ea3m ph\u00e2n l\u00e0","options":[{"text":"8 \u0111\u01a1n.","is_correct":0},{"text":"46 k\u00e9p.","is_correct":1},{"text":"46 \u0111\u01a1n.","is_correct":0},{"text":"92 \u0111\u01a1n.","is_correct":0}],"level":"TH"},{"question":"\u1ede Tr\u00e2u (2n = 48), s\u1ed1 nhi\u1ec5m s\u1eafc th\u1ec3 trong 1 t\u1ebf b\u00e0o \u1edf k\u00ec gi\u1eefa II c\u1ee7a gi\u1ea3m ph\u00e2n l\u00e0","options":[{"text":"24 k\u00e9p.","is_correct":1},{"text":"48 k\u00e9p.","is_correct":0},{"text":"48 \u0111\u01a1n.","is_correct":0},{"text":"24 \u0111\u01a1n.","is_correct":0}],"level":"TH"},{"question":"\u1ede Ru\u1ed3i gi\u1ea5m (2n = 8), s\u1ed1 nhi\u1ec5m s\u1eafc th\u1ec3 trong 1 t\u1ebf b\u00e0o \u1edf k\u00ec sau II c\u1ee7a gi\u1ea3m ph\u00e2n l\u00e0","options":[{"text":"4 \u0111\u01a1n.","is_correct":0},{"text":"16 \u0111\u01a1n.","is_correct":0},{"text":"8 \u0111\u01a1n.","is_correct":1},{"text":"8 k\u00e9p.","is_correct":0}],"level":"TH"},{"question":"\u1ede G\u00e0 (2n = 78), s\u1ed1 nhi\u1ec5m s\u1eafc th\u1ec3 trong 1 t\u1ebf b\u00e0o sau khi k\u1ebft th\u00fac k\u00ec cu\u1ed1i I c\u1ee7a gi\u1ea3m ph\u00e2n l\u00e0","options":[{"text":"39 \u0111\u01a1n.","is_correct":0},{"text":"39 k\u00e9p.","is_correct":1},{"text":"78 k\u00e9p.","is_correct":0},{"text":"39 \u0111\u01a1n.","is_correct":0}],"level":"TH"},{"question":"M\u1ed9t t\u1ebf b\u00e0o sinh d\u1ee5c gi\u1ea3m ph\u00e2n v\u00e0o k\u00ec gi\u1eefa c\u1ee7a gi\u1ea3m ph\u00e2n I th\u1ea5y c\u00f3 96 s\u1ee3i cromatit. K\u1ebft th\u00fac gi\u1ea3m ph\u00e2n t\u1ea1o c\u00e1c giao t\u1eed, trong m\u1ed7i t\u1ebf b\u00e0o giao t\u1eed c\u00f3 s\u1ed1 NST l\u00e0:","options":[{"text":"24.","is_correct":1},{"text":"48.","is_correct":0},{"text":"36.","is_correct":0},{"text":"12.","is_correct":0}],"level":"TH"},{"question":"Ru\u1ed3i gi\u1ea5m 2n= 8. V\u00e0o k\u00ec sau c\u1ee7a gi\u1ea3m ph\u00e2n 1 c\u00f3 1 c\u1eb7p NST kh\u00f4ng ph\u00e2n li. K\u1ebft th\u00fac l\u1ea7n gi\u1ea3m ph\u00e2n 1 s\u1ebd t\u1ea1o ra:","options":[{"text":"hai t\u1ebf b\u00e0o con, m\u1ed7i t\u1ebf b\u00e0o \u0111\u1ec1u c\u00f3 4 NST \u0111\u01a1n.","is_correct":0},{"text":"hai t\u1ebf b\u00e0o con, m\u1ed7i t\u1ebf b\u00e0o \u0111\u1ec1u c\u00f3 4 NST k\u00e9p.","is_correct":0},{"text":"m\u1ed9t t\u1ebf b\u00e0o c\u00f3 3 NST k\u00e9p, m\u1ed9t t\u1ebf b\u00e0o c\u00f3 5 NST k\u00e9p.","is_correct":1},{"text":"m\u1ed9t t\u1ebf b\u00e0o c\u00f3 2 NST \u0111\u01a1n, m\u1ed9t t\u1ebf b\u00e0o c\u00f3 5 NST \u0111\u01a1n.","is_correct":0}],"level":"TH"},{"question":"\u1ede k\u00ec sau II, trong m\u1ed7i t\u1ebf b\u00e0o c\u00f3","options":[{"text":"8 NST k\u00e9p, 16 cromatit, 8 t\u00e2m \u0111\u1ed9ng.","is_correct":0},{"text":"4 NST \u0111\u01a1n, 0 cromatit, 4 t\u00e2m \u0111\u1ed9ng.","is_correct":0},{"text":"8 NST \u0111\u01a1n, 0 cromatit, 8 t\u00e2m \u0111\u1ed9ng.","is_correct":1},{"text":"16 NST k\u00e9p, 32 cromatit, 16 t\u00e2m \u0111\u1ed9ng.","is_correct":0}],"level":"TH"},{"question":"M\u1ed9t t\u1ebf b\u00e0o c\u00f3 h\u00e0m l\u01b0\u1ee3ng DNA nh\u00e2n l\u00e0 3,8 pg. T\u1ebf b\u00e0o n\u00e0y qua m\u1ed9t l\u1ea7n ph\u00e2n b\u00e0o b\u00ecnh th\u01b0\u1eddng t\u1ea1o ra hai t\u1ebf b\u00e0o con \u0111\u1ec1u c\u00f3 h\u00e0m l\u01b0\u1ee3ng DNA nh\u00e2n l\u00e0 3,8 pg. T\u1ebf b\u00e0o tr\u00ean \u0111\u00e3 kh\u00f4ng tr\u1ea3i qua qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o n\u00e0o sau \u0111\u00e2y?","options":[{"text":"Nguy\u00ean ph\u00e2n.","is_correct":0},{"text":"Gi\u1ea3m ph\u00e2n 1.","is_correct":0},{"text":"Gi\u1ea3m ph\u00e2n 2.","is_correct":1},{"text":"Tr\u1ef1c ph\u00e2n.","is_correct":0}],"level":"TH"},{"question":"Cho c\u00e1c ph\u00e1t bi\u1ec3u sau:\n1.Di\u1ec5n ra hai l\u1ea7n ph\u00e2n b\u00e0o li\u00ean ti\u1ebfp.\n2.N\u00f3 ch\u1ec9 di\u1ec5n ra \u1edf c\u00e1c lo\u00e0i sinh v\u1eadt h\u1eefu t\u00ednh.\n3.\u1ede k\u00ec gi\u1eefa 1 c\u00f3 nhi\u1ec1u ki\u1ec3u s\u1eafp x\u1ebfp NST.\n4.\u1ede k\u00ec \u0111\u1ea7u 1 c\u00f3 s\u1ef1 trao \u0111\u1ed5i ch\u00e9o gi\u1eefa c\u00e1c NST t\u01b0\u01a1ng \u0111\u1ed3ng.\nC\u00f3 bao nhi\u00eau ph\u00e1t \u0111i\u1ec3u \u0111\u00fang v\u1edbi nguy\u00ean nh\u00e2n qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n \u0111\u01b0\u1ee3c nhi\u1ec1u lo\u1ea1i giao t\u1eed?","options":[{"text":"1, 2, 3.","is_correct":0},{"text":"3, 4.","is_correct":1},{"text":"2, 3, 4.","is_correct":0},{"text":"1, 2, 3, 4.","is_correct":0}],"level":"TH"},{"question":"Nh\u1eefng ph\u00e1t bi\u1ec3u n\u00e0o sau \u0111\u00e2y l\u00e0 \u0111\u00fang khi n\u00f3i v\u1ec1 gi\u1ea3m ph\u00e2n?\n(a)Giai \u0111o\u1ea1n th\u1ef1c ch\u1ea5t l\u00e0m gi\u1ea3m \u0111i m\u1ed9t n\u1eeda s\u1ed1 l\u01b0\u1ee3ng NST \u1edf c\u00e1c t\u1ebf b\u00e0o con l\u00e0 gi\u1ea3m ph\u00e2n I.\n(b)Trong gi\u1ea3m ph\u00e2n c\u00f3 2 l\u1ea7n nh\u00e2n \u0111\u00f4i NST \u1edf hai k\u00ec trung gian.\n(c)Gi\u1ea3m ph\u00e2n sinh ra c\u00e1c t\u1ebf b\u00e0o con c\u00f3 s\u1ed1 l\u01b0\u1ee3ng NST gi\u1ea3m \u0111i m\u1ed9t n\u1eeda so v\u1edbi t\u1ebf b\u00e0o m\u1eb9.\n(d)B\u1ed1n t\u1ebf b\u00e0o con \u0111\u01b0\u1ee3c sinh ra \u0111\u1ec1u c\u00f3 n NST gi\u1ed1ng nhau v\u1ec1 c\u1ea5u tr\u00fac\nNh\u1eefng ph\u01b0\u01a1ng \u00e1n tr\u1ea3 l\u1eddi \u0111\u00fang l\u00e0","options":[{"text":"(a), (b).","is_correct":0},{"text":"(a), (c).","is_correct":1},{"text":"(a), (b), (c).","is_correct":0},{"text":"(a), (b), (c), (d).","is_correct":0}],"level":"TH"},{"question":"Khi n\u00f3i v\u1ec1 ph\u00e2n b\u00e0o gi\u1ea3m ph\u00e2n, ph\u00e1t bi\u1ec3u n\u00e0o sau \u0111\u00e2y l\u00e0 \u0111\u00fang?","options":[{"text":"M\u1ed7i t\u1ebf b\u00e0o c\u00f3 th\u1ec3 ti\u1ebfn h\u00e0nh gi\u1ea3m ph\u00e2n hai ho\u1eb7c nhi\u1ec1u l\u1ea7n.","is_correct":0},{"text":"Gi\u1ea3m ph\u00e2n tr\u1ea3i qua 2 l\u1ea7n ph\u00e2n b\u00e0o nh\u01b0ng NST ch\u1ec9 nh\u00e2n \u0111\u00f4i 1 l\u1ea7n.","is_correct":1},{"text":"Ph\u00e2n b\u00e0o gi\u1ea3m ph\u00e2n di\u1ec5n ra \u1edf m\u1ecdi t\u1ebf b\u00e0o c\u1ee7a c\u01a1 quan sinh d\u1ee5c","is_correct":0},{"text":"Ph\u00e2n b\u00e0o gi\u1ea3m ph\u00e2n kh\u00f4ng c\u00f3 qu\u00e1 tr\u00ecnh ph\u00e2n chia t\u1ebf b\u00e0o ch\u1ea5t.","is_correct":0}],"level":"TH"},{"question":"H\u00e0m l\u01b0\u1ee3ng DNA nh\u00e2n trong m\u1ed9t t\u1ebf b\u00e0o sinh tinh c\u1ee7a m\u1ed9t lo\u00e0i \u0111\u1ed9ng v\u1eadt l\u00e0 6,6pg. Trong tr\u01b0\u1eddng h\u1ee3p ph\u00e2n b\u00e0o b\u00ecnh th\u01b0\u1eddng, h\u00e0m l\u01b0\u1ee3ng DNA nh\u00e2n c\u1ee7a m\u1ed7i t\u1ebf b\u00e0o khi \u0111ang \u1edf k\u00ec sau c\u1ee7a gi\u1ea3m ph\u00e2n II l\u00e0 bao nhi\u00eau?","options":[{"text":"6,6pg.","is_correct":1},{"text":"3,3pg.","is_correct":0},{"text":"13,2pg.","is_correct":0},{"text":"26,4pg.","is_correct":0}],"level":"TH"},{"question":"H\u00ecnh v\u1ebd d\u01b0\u1edbi \u0111\u00e2y m\u00f4 t\u1ea3 s\u1ef1 ph\u00e2n b\u00e0o c\u1ee7a m\u1ed9t t\u1ebf b\u00e0o c\u00f3 b\u1ed9 NST 2n = 8. N\u00f3 \u0111ang \u1edf giai \u0111o\u1ea1n n\u00e0o c\u1ee7a qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o?\n\u003cimg src=\"bmp_asset://img_9b3f91aea8c5d15d.png\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e","options":[{"text":"K\u00ec sau c\u1ee7a nguy\u00ean ph\u00e2n.","is_correct":0},{"text":"K\u00ec sau c\u1ee7a gi\u1ea3m ph\u00e2n 1.","is_correct":0},{"text":"K\u00ec gi\u1eefa c\u1ee7a gi\u1ea3m ph\u00e2n 1.","is_correct":0},{"text":"K\u00ec sau c\u1ee7a gi\u1ea3m ph\u00e2n 2.","is_correct":1}],"level":"TH"},{"question":"\u0110\u1eb7c \u0111i\u1ec3m n\u00e0o sau \u0111\u00e2y ch\u1ec9 c\u00f3 \u1edf k\u00ec sau c\u1ee7a gi\u1ea3m ph\u00e2n 1 m\u00e0 kh\u00f4ng c\u00f3 \u1edf c\u00e1c k\u00ec kh\u00e1c c\u1ee7a ph\u00e2n b\u00e0o gi\u1ea3m ph\u00e2n?","options":[{"text":"NST \u1edf d\u1ea1ng k\u00e9p g\u1eafn l\u00ean thoi v\u00f4 s\u1eafc v\u00e0 \u0111\u01b0\u1ee3c ph\u00e2n li v\u1ec1 hai c\u1ef1c t\u1ebf b\u00e0o.","is_correct":1},{"text":"M\u1ed7i NST c\u00f3 hai t\u00e2m \u0111\u1ed9ng v\u00e0 tr\u01b0\u1ee3t v\u1ec1 hai c\u1ef1c t\u1ebf b\u00e0o.","is_correct":0},{"text":"NST \u1edf d\u1ea1ng s\u1ee3i \u0111\u01a1n b\u00e1m thoi v\u00f4 s\u1eafc v\u00e0 \u0111\u01b0\u1ee3c ph\u00e2n li v\u1ec1 hai c\u1ef1c t\u1ebf b\u00e0o.","is_correct":0},{"text":"NST nh\u1ea3 xo\u1eafn c\u1ef1c \u0111\u1ea1i \u0111\u1ec3 tr\u1edf v\u1ec1 tr\u1ea1ng th\u00e1i s\u1ee3i m\u1ea3nh.","is_correct":0}],"level":"TH"},{"question":"\u1ede c\u01a1 th\u1ec3 ng\u01b0\u1eddi, s\u1ef1 ph\u00e2n b\u00e0o gi\u1ea3m ph\u00e2n c\u00f3 nh\u1eefng \u00fd ngh\u0129a n\u00e0o sau \u0111\u00e2y?\nI. T\u1ea1o ra giao t\u1eed \u0111\u01a1n b\u1ed9i, qua th\u1ee5 tinh kh\u00f4i ph\u1ee5c l\u1ea1i b\u1ed9 NST 2n c\u1ee7a lo\u00e0i.\nII. Gi\u00fap c\u01a1 quan sinh d\u1ee5c sinh tr\u01b0\u1edfng v\u00e0 ph\u00e1t tri\u1ec3n.\nIII. Gi\u00fap c\u01a1 th\u1ec3 t\u0103ng k\u00edch th\u01b0\u1edbc v\u00e0 kh\u1ed1i l\u01b0\u1ee3ng.\nIV. T\u1ea1o ra nhi\u1ec1u lo\u1ea1i giao t\u1eed mang t\u1ed5 h\u1ee3p gen kh\u00e1c nhau.","options":[{"text":"I, II.","is_correct":0},{"text":"I, III.","is_correct":0},{"text":"I, IV.","is_correct":1},{"text":"II, III, IV.","is_correct":0}],"level":"TH"},{"question":"\u0110\u1eb7c \u0111i\u1ec3m n\u00e0o sau \u0111\u00e2y ch\u1ec9 c\u00f3 \u1edf k\u00ec gi\u1eefa c\u1ee7a gi\u1ea3m ph\u00e2n 1 m\u00e0 kh\u00f4ng c\u00f3 \u1edf k\u00ec gi\u1eefa c\u1ee7a nguy\u00ean ph\u00e2n?","options":[{"text":"NST x\u1ebfp th\u00e0nh hai h\u00e0ng ngang tr\u00ean m\u1eb7t ph\u1eb3ng x\u00edch \u0111\u1ea1o c\u1ee7a t\u01a1 v\u00f4 s\u1eafc","is_correct":1},{"text":"NST c\u00f3 h\u00ecnh d\u1ea1ng \u0111\u1eb7c tr\u01b0ng cho lo\u00e0i.","is_correct":0},{"text":"Thoi t\u01a1 v\u00f4 s\u1eafc h\u00ecnh th\u00e0nh ho\u00e0n ch\u1ec9nh.","is_correct":0},{"text":"NST x\u1ebfp th\u00e0nh m\u1ed9t h\u00e0ng ngang tr\u00ean m\u1eb7t ph\u1eb3ng x\u00edch \u0111\u1ea1o c\u1ee7a t\u01a1 v\u00f4 s\u1eafc","is_correct":0}],"level":"TH"},{"question":"\u0110\u1eb7c \u0111i\u1ec3m c\u1ee7a ph\u00e2n b\u00e0o II trong gi\u1ea3m ph\u00e2n l\u00e0","options":[{"text":"t\u01b0\u01a1ng t\u1ef1 nh\u01b0 qu\u00e1 tr\u00ecnh nguy\u00ean ph\u00e2n.","is_correct":1},{"text":"th\u1ec3 hi\u1ec7n b\u1ea3n ch\u1ea5t gi\u1ea3m ph\u00e2n.","is_correct":0},{"text":"s\u1ed1 NST trong t\u1ebf b\u00e0o l\u00e0 n \u1edf m\u1ed7i k\u00ec.","is_correct":0},{"text":"c\u00f3 x\u1ea3y ra ti\u1ebfp h\u1ee3p NST.","is_correct":0}],"level":"TH"},{"question":"k\u00ec sau I c\u1ee7a gi\u1ea3m ph\u00e2n, hai NST k\u00e9p c\u00f9ng c\u1eb7p t\u01b0\u01a1ng \u0111\u1ed3ng c\u00f3 hi\u1ec7n t\u01b0\u1ee3ng n\u00e0o sau \u0111\u00e2y?","options":[{"text":"Hai chi\u1ebfc c\u00f9ng v\u1ec1 1 c\u1ef1c t\u1ebf b\u00e0o.","is_correct":0},{"text":"M\u1ed9t chi\u1ebfc v\u1ec1 c\u1ef1c v\u00e0 1 chi\u1ebfc \u1edf gi\u1eefa t\u1ebf b\u00e0o.","is_correct":0},{"text":"M\u1ed7i chi\u1ebfc v\u1ec1 m\u1ed9t c\u1ef1c t\u1ebf b\u00e0o.","is_correct":1},{"text":"\u0110\u1ec1u n\u1eb1m \u1edf gi\u1eefa t\u1ebf b\u00e0o.","is_correct":0}],"level":"TH"},{"question":"M\u1ed9t t\u1ebf b\u00e0o c\u00f3 b\u1ed9 NST 2n = 20 ti\u1ebfn h\u00e0nh gi\u1ea3m ph\u00e2n b\u00ecnh th\u01b0\u1eddng. Ph\u00e1t bi\u1ec3u n\u00e0o sau \u0111\u00e2y sai?","options":[{"text":"V\u00e0o k\u00ec gi\u1eefa c\u1ee7a gi\u1ea3m ph\u00e2n 1, t\u1ebf b\u00e0o c\u00f3 40 cr\u00f4mat\u00edt.","is_correct":0},{"text":"V\u00e0o k\u00ec \u0111\u1ea7u c\u1ee7a gi\u1ea3m ph\u00e2n 2, m\u1ed7i t\u1ebf b\u00e0o c\u00f3 10 t\u00e2m \u0111\u1ed9ng.","is_correct":0},{"text":"V\u00e0o k\u00ec sau c\u1ee7a gi\u1ea3m ph\u00e2n 2, t\u1ebf b\u00e0o c\u00f3 10 NST \u0111\u01a1n.","is_correct":1},{"text":"V\u00e0o k\u00ec sau c\u1ee7a gi\u1ea3m ph\u00e2n 1, c\u00e1c NST \u0111\u1ec1u \u1edf d\u1ea1ng k\u00e9p.","is_correct":0}],"level":"TH"},{"question":"M\u1ed9t t\u1ebf b\u00e0o c\u00f3 h\u00e0m l\u01b0\u1ee3ng DNA nh\u00e2n l\u00e0 3,8 pg. T\u1ebf b\u00e0o n\u00e0y qua m\u1ed9t l\u1ea7n ph\u00e2n b\u00e0o b\u00ecnh th\u01b0\u1eddng t\u1ea1o ra hai t\u1ebf b\u00e0o con \u0111\u1ec1u c\u00f3 h\u00e0m l\u01b0\u1ee3ng DNA nh\u00e2n l\u00e0 3,8 pg. S\u1ef1 ph\u00e2n b\u00e0o tr\u00ean kh\u00f4ng ph\u1ea3i l\u00e0 qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o n\u00e0o sau \u0111\u00e2y?","options":[{"text":"Nguy\u00ean ph\u00e2n.","is_correct":0},{"text":"Gi\u1ea3m ph\u00e2n 1.","is_correct":0},{"text":"Gi\u1ea3m ph\u00e2n 2.","is_correct":1},{"text":"Tr\u1ef1c ph\u00e2n.","is_correct":0}],"level":"TH"},{"question":"\u1ede ng\u01b0\u1eddi c\u00f3 2n = 46, m\u1ed9t t\u1ebf b\u00e0o sinh tinh di\u1ec5n ra qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n. C\u00f3 bao nhi\u00eau ph\u00e1t bi\u1ec3u sau \u0111\u00e2y \u0111\u00fang?\nI. \u1ede k\u00ec \u0111\u1ea7u I trong t\u1ebf b\u00e0o c\u00f3 92 cromatit.\nII. \u1ede \u0111\u1ea7u k\u00ec cu\u1ed1i II trong t\u1ebf b\u00e0o c\u00f3 23 NST \u0111\u01a1n.\nIII. K\u1ebft th\u00fac qu\u00e1 tr\u00ecnh tr\u00ean h\u00ecnh th\u00e0nh n\u00ean 4 giao t\u1eed.\nIV. Trong su\u1ed1t qu\u00e1 tr\u00ecnh tr\u00ean trong t\u1ebf b\u00e0o lu\u00f4n t\u1ed3n t\u1ea1i c\u1eb7p NST t\u01b0\u01a1ng \u0111\u1ed3ng.","options":[{"text":"4.","is_correct":0},{"text":"1.","is_correct":0},{"text":"2.","is_correct":0},{"text":"3.","is_correct":1}],"level":"TH"},{"question":"V\u00ec sao k\u1ebft th\u00fac ph\u00e2n b\u00e0o gi\u1ea3m ph\u00e2n, t\u1ebf b\u00e0o con c\u00f3 b\u1ed9 NST b\u1eb1ng m\u1ed9t n\u1eeda t\u1ebf b\u00e0o m\u1eb9?","options":[{"text":"Gi\u1ea3m ph\u00e2n di\u1ec5n ra hai l\u1ea7n ph\u00e2n b\u00e0o li\u00ean ti\u1ebfp.","is_correct":0},{"text":"T\u1eeb 1 t\u1ebf b\u00e0o m\u1eb9 t\u1ea1o ra 4 t\u1ebf b\u00e0o con.","is_correct":0},{"text":"NST nh\u00e2n \u0111\u00f4i 1 l\u1ea7n nh\u01b0ng ph\u00e2n li 2 l\u1ea7n.","is_correct":1},{"text":"Gi\u1ea3m ph\u00e2n g\u1eafn li\u1ec1n v\u1edbi qu\u00e1 tr\u00ecnh t\u1ea1o giao t\u1eed.","is_correct":0}],"level":"TH"},{"question":"Qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n t\u1ea1o ra \u0111\u01b0\u1ee3c nhi\u1ec1u lo\u1ea1i giao t\u1eed l\u00e0 do nh\u1eefng nguy\u00ean nh\u00e2n n\u00e0o sau \u0111\u00e2y?\nI. Di\u1ec5n ra hai l\u1ea7n ph\u00e2n b\u00e0o li\u00ean ti\u1ebfp.\nII. N\u00f3 di\u1ec5n ra \u1edf c\u00e1c lo\u00e0i sinh s\u1ea3n h\u1eefu t\u00ednh.\nIII. \u1ede k\u00ec gi\u1eefa 1 c\u00f3 nhi\u1ec1u ki\u1ec3u s\u1eafp x\u1ebfp NST.\nIV. \u1ede k\u00ec \u0111\u1ea7u 1 c\u00f3 s\u1ef1 trao \u0111\u1ed5i ch\u00e9o gi\u1eefa c\u00e1c NST t\u01b0\u01a1ng \u0111\u1ed3ng.","options":[{"text":"I, II, III.","is_correct":0},{"text":"III, IV.","is_correct":1},{"text":"II, III, IV.","is_correct":0},{"text":"I, II, III, IV.","is_correct":0}],"level":"TH"},{"question":"Nh\u1eefng ph\u00e1t bi\u1ec3u n\u00e0o sau \u0111\u00e2y l\u00e0 \u0111\u00fang khi n\u00f3i v\u1ec1 gi\u1ea3m ph\u00e2n?\n(a) Giai \u0111o\u1ea1n th\u1ef1c ch\u1ea5t l\u00e0m gi\u1ea3m \u0111i m\u1ed9t n\u1eeda s\u1ed1 l\u01b0\u1ee3ng NST \u1edf c\u00e1c t\u1ebf b\u00e0o con l\u00e0 gi\u1ea3m ph\u00e2n I.\n(b)Trong gi\u1ea3m ph\u00e2n c\u00f3 2 l\u1ea7n nh\u00e2n \u0111\u00f4i NST \u1edf hai k\u00ec trung gian.\n(c)Gi\u1ea3m ph\u00e2n sinh ra c\u00e1c t\u1ebf b\u00e0o con c\u00f3 s\u1ed1 l\u01b0\u1ee3ng NST gi\u1ea3m \u0111i m\u1ed9t n\u1eeda so v\u1edbi t\u1ebf b\u00e0o m\u1eb9.\n(d)B\u1ed1n t\u1ebf b\u00e0o con \u0111\u01b0\u1ee3c sinh ra \u0111\u1ec1u c\u00f3 n NST gi\u1ed1ng nhau v\u1ec1 c\u1ea5u tr\u00fac\nNh\u1eefng ph\u01b0\u01a1ng \u00e1n tr\u1ea3 l\u1eddi \u0111\u00fang l\u00e0","options":[{"text":"(a), (b)","is_correct":0},{"text":"(a), (c)","is_correct":1},{"text":"(a), (b), (c)","is_correct":0},{"text":"(a), (b), (c), (d)","is_correct":0}],"level":"TH"},{"question":"Trong gi\u1ea3m ph\u00e2n, \u1edf k\u00ec sau I v\u00e0 k\u00ec sau II c\u00f3 \u0111i\u1ec3m gi\u1ed1ng nhau l\u00e0","options":[{"text":"C\u00e1c NST \u0111\u1ec1u \u1edf tr\u1ea1ng th\u00e1i \u0111\u01a1n.","is_correct":0},{"text":"C\u00e1c NST \u0111\u1ec1u \u1edf tr\u1ea1ng th\u00e1i k\u00e9p.","is_correct":0},{"text":"C\u00f3 s\u1ef1 d\u00e3n xo\u1eafn c\u1ee7a c\u00e1c NST.","is_correct":0},{"text":"C\u00f3 s\u1ef1 ph\u00e2n li c\u00e1c NST v\u1ec1 2 c\u1ef1c t\u1ebf b\u00e0o.","is_correct":1}],"level":"TH"},{"question":"Ph\u00e2n b\u00e0o 1 c\u1ee7a gi\u1ea3m ph\u00e2n \u0111\u01b0\u1ee3c g\u1ecdi l\u00e0 ph\u00e2n b\u00e0o gi\u1ea3m nhi\u00eam v\u00ec nguy\u00ean nh\u00e2n n\u00e0o sau \u0111\u00e2y?","options":[{"text":"\u1ede k\u00ec cu\u1ed1i c\u00f9ng, b\u1ed9 nhi\u1ec5m s\u1eafc th\u1ec3 c\u00f3 d\u1ea1ng s\u1ee3i k\u00e9p, nh\u1ea3 xo\u1eafn.","is_correct":0},{"text":"M\u1ed7i t\u1ebf b\u00e0o con \u0111\u1ec1u c\u00f3 b\u1ed9 nhi\u1ec5m s\u1eafc th\u1ec3 \u0111\u01a1n b\u1ed9i.","is_correct":0},{"text":"H\u00e0m l\u01b0\u1ee3ng DNA c\u1ee7a t\u1ebf b\u00e0o con b\u1eb1ng m\u1ed9t n\u1eeda t\u1ebf b\u00e0o m\u1eb9.","is_correct":0},{"text":"B\u1ed9 nhi\u1ec5m s\u1eafc th\u1ec3 c\u1ee7a t\u1ebf b\u00e0o con b\u1eb1ng m\u1ed9t n\u1eeda so v\u1edbi t\u1ebf b\u00e0o m\u1eb9.","is_correct":1}],"level":"TH"},{"question":"Khi n\u00f3i v\u1ec1 gi\u1ea3m ph\u00e2n, ph\u00e1t bi\u1ec3u n\u00e0o sau \u0111\u00e2y l\u00e0 \u0111\u00fang?","options":[{"text":"M\u1ed7i t\u1ebf b\u00e0o c\u00f3 th\u1ec3 ti\u1ebfn h\u00e0nh gi\u1ea3m ph\u00e2n 1 l\u1ea7n ho\u1eb7c nhi\u1ec1u l\u1ea7n.","is_correct":0},{"text":"Gi\u1ea3m ph\u00e2n tr\u1ea3i quan hai l\u1ea7n ph\u00e2n b\u00e0o nh\u01b0ng NST ch\u1ec9 nh\u00e2n \u0111\u00f4i 1 l\u1ea7n.","is_correct":1},{"text":"Ph\u00e2n b\u00e0o gi\u1ea3m ph\u00e2n di\u1ec5n ra \u1edf m\u1ecdi t\u1ebf b\u00e0o c\u1ee7a c\u01a1 quan sinh d\u1ee5c","is_correct":0},{"text":"Ph\u00e2n b\u00e0o gi\u1ea3m ph\u00e2n kh\u00f4ng qu\u00e1 tr\u00ecnh ph\u00e2n chia t\u1ebf b\u00e0o ch\u1ea5t.","is_correct":0}],"level":"TH"},{"question":"\u1ede m\u1ed9t lo\u00e0i \u0111\u1ed9ng v\u1eadt, 12 t\u1ebf b\u00e0o sinh d\u1ee5c ch\u00edn ti\u1ebfn h\u00e0nh gi\u1ea3m ph\u00e2n \u0111\u00e3 t\u1ea1o ra bao nhi\u00eau t\u1ebf b\u00e0o con?","options":[{"text":"24.","is_correct":0},{"text":"48.","is_correct":1},{"text":"36.","is_correct":0},{"text":"96.","is_correct":0}],"level":"TH"},{"question":"C\u00f3 5 t\u1ebf b\u00e0o sinh d\u1ee5c ch\u00edn. N\u1ebfu \u0111\u00f3 l\u00e0 c\u00e1c t\u1ebf b\u00e0o ch\u00edn sinh d\u1ee5c c\u1ee7a con c\u00e1i th\u00ec sau gi\u1ea3m ph\u00e2n, s\u1ed1 lo\u1ea1i giao t\u1eed t\u1ed1i \u0111a thu \u0111\u01b0\u1ee3c l\u00e0","options":[{"text":"20.","is_correct":0},{"text":"10.","is_correct":0},{"text":"5.","is_correct":1},{"text":"1.","is_correct":0}],"level":"TH"}],"VD":[{"question":"Cho h\u00ecnh \u1ea3nh v\u1ec1 m\u1ed9t giai \u0111o\u1ea1n trong qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o c\u1ee7a m\u1ed9t t\u1ebf b\u00e0o l\u01b0\u1ee1ng b\u1ed9i 2n b\u00ecnh th\u01b0\u1eddng (t\u1ebf b\u00e0o A) trong c\u01a1 th\u1ec3 \u0111\u1ef1c \u1edf m\u1ed9t lo\u00e0i v\u00e0 m\u1ed9t s\u1ed1 nh\u1eadn x\u00e9t t\u01b0\u01a1ng \u1ee9ng nh\u01b0 sau:\n\u003cimg src=\"bmp_asset://img_cf0e93f17a6d8f74.png\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e\n(1)T\u1ebf b\u00e0o A mang c\u00f3 ch\u1ee9a \u00edt nh\u1ea5t l\u00e0 hai c\u1eb7p gen d\u1ecb h\u1ee3p.\n(2)B\u1ed9 NST l\u01b0\u1ee1ng b\u1ed9i b\u00ecnh th\u01b0\u1eddng c\u1ee7a lo\u00e0i l\u00e0 2n = 8.\n(3)T\u1ebf b\u00e0o A c\u00f3 x\u1ea3y ra trao \u0111\u1ed5i ch\u00e9o trong qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n 1.\n(4)T\u1ebf b\u00e0o A t\u1ea1o ra t\u1ed1i \u0111a l\u00e0 4 lo\u1ea1i giao t\u1eed kh\u00e1c nhau v\u1ec1 c\u00e1c gen \u0111ang x\u00e9t.\n(5)T\u1ebf b\u00e0o A kh\u00f4ng th\u1ec3 t\u1ea1o \u0111\u01b0\u1ee3c giao t\u1eed b\u00ecnh th\u01b0\u1eddng.\nBi\u1ebft \u0111\u1ed9t bi\u1ebfn n\u1ebfu c\u00f3 ch\u1ec9 x\u1ea3y ra 1 l\u1ea7n, s\u1ed1 ph\u00e1t bi\u1ec3u \u0111\u00fang l\u00e0:","options":[{"text":"1.","is_correct":0},{"text":"2.","is_correct":0},{"text":"3.","is_correct":1},{"text":"4.","is_correct":0}],"level":"VD"},{"question":"Theo \u0111\u00f5i s\u1ef1 ph\u00e2n b\u00e0o c\u1ee7a 1 c\u01a1 th\u1ec3 l\u01b0\u1ee1ng b\u1ed9i, ng\u01b0\u1eddi ta v\u1ebd \u0111\u01b0\u1ee3c s\u01a1 \u0111\u1ed3 minh h\u1ecda sau \u0111\u00e2y:\n\u003cimg src=\"bmp_asset://img_ce81f44b2774f246.png\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e\nH\u00ecnh n\u00e0y m\u00f4 t\u1ea3:","options":[{"text":"R\u1ed1i lo\u1ea1n ph\u00e2n ly NST \u1edf k\u00ec sau c\u1ee7a gi\u1ea3m ph\u00e2n I ho\u1eb7c r\u1ed1i lo\u1ea1n ph\u00e2n li NST \u1edf k\u00ec sau nguy\u00ean ph\u00e2n.","is_correct":0},{"text":"R\u1ed1i lo\u1ea1n ph\u00e2n ly NST \u1edf k\u00ec sau c\u1ee7a gi\u1ea3m ph\u00e2n II ho\u1eb7c r\u1ed1i lo\u1ea1n ph\u00e2n li NST \u1edf k\u00ec sau nguy\u00ean ph\u00e2n.","is_correct":0},{"text":"R\u1ed1i lo\u1ea1n ph\u00e2n ly NST \u1edf k\u00ec sau c\u1ee7a gi\u1ea3m ph\u00e2n I.","is_correct":0},{"text":"R\u1ed1i lo\u1ea1n ph\u00e2n ly NST \u1edf k\u00ec sau c\u1ee7a gi\u1ea3m ph\u00e2n II.","is_correct":1}],"level":"VD"},{"question":"H\u00ecnh v\u1ebd sau \u0111\u00e2y m\u00f4 t\u1ea3 ba t\u1ebf b\u00e0o b\u00ecnh th\u01b0\u1eddng c\u1ee7a c\u00e1c c\u01a1 th\u1ec3 d\u1ecb h\u1ee3p \u0111ang \u1edf k\u1ef3 sau c\u1ee7a qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o.\n\u003cimg src=\"bmp_asset://img_2896dcfc0dd529c6.png\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e\nC\u00f3 bao nhi\u00eau ph\u00e1t bi\u1ec3u \u0111\u00fang trong c\u00e1c ph\u00e1t bi\u1ec3u sau \u0111\u00fang?\n(1)T\u1ebf b\u00e0o 1 v\u00e0 t\u1ebf b\u00e0o 2 c\u00f3 th\u1ec3 l\u00e0 c\u1ee7a c\u00f9ng m\u1ed9t c\u01a1 th\u1ec3.\n(2)K\u1ebft th\u00fac qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o, t\u1ebf b\u00e0o 2 t\u1ea1o ra hai t\u1ebf b\u00e0o v\u1edbi c\u1ea5u tr\u00fac NST gi\u1ed1ng nhau.\n(3)N\u1ebfu t\u1ebf b\u00e0o 1 v\u00e0 t\u1ebf b\u00e0o 2 thu\u1ed9c hai c\u01a1 th\u1ec3 kh\u00e1c nhau th\u00ec NST trong t\u1ebf b\u00e0o sinh d\u01b0\u1ee1ng c\u1ee7a c\u01a1 th\u1ec3 c\u00f3 t\u1ebf b\u00e0o 2 c\u00f3 th\u1ec3 g\u1ea5p \u0111\u00f4i b\u1ed9 NST trong t\u1ebf b\u00e0o sinh d\u01b0\u1ee1ng c\u1ee7a c\u01a1 th\u1ec3 c\u00f3 t\u1ebf b\u00e0o 1.\n(4)T\u1ebf b\u00e0o 1 v\u00e0 t\u1ebf b\u00e0o 3 c\u00f3 th\u1ec3 l\u00e0 c\u1ee7a c\u00f9ng m\u1ed9t c\u01a1 th\u1ec3.","options":[{"text":"1.","is_correct":0},{"text":"3.","is_correct":1},{"text":"2.","is_correct":0},{"text":"4","is_correct":0}],"level":"VD"},{"question":"S\u01a1 \u0111\u1ed3 sau \u0111\u00e2y bi\u1ec3u di\u1ec5n h\u00e0m l\u01b0\u1ee3ng DNA trong m\u1ed9t t\u1ebf b\u00e0o sinh v\u1eadt nh\u00e2n th\u1ef1c 2n tr\u1ea3i qua m\u1ed9t qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o n\u00e0o \u0111\u00f3.\n\u003cimg src=\"bmp_asset://img_9e5a39396ec52906.png\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e\nD\u1ef1a v\u00e0o s\u01a1 \u0111\u1ed3 h\u00e3y cho bi\u1ebft trong c\u00e1c ph\u00e1t bi\u1ec3u sau \u0111\u00e2y c\u00f3 bao nhi\u00eau ph\u00e1t bi\u1ec3u \u0111\u00fang:\n(a)\u0110\u00e2y l\u00e0 qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o gi\u1ea3m nhi\u1ec5m.\n(b)Giai \u0111o\u1ea1n I v\u00e0 II thu\u1ed9c k\u00ec trung gian c\u1ee7a gi\u1ea3m ph\u00e2n I.\n(c)To\u00e0n b\u1ed9 giai \u0111o\u1ea1n II thu\u1ed9c pha G2 c\u1ee7a k\u00ec trung gian.\n(d)\u0110\u1ea7u giai \u0111o\u1ea1n III, NST \u1edf \u0111ang \u1edf tr\u1ea1ng th\u00e1i k\u00e9p.\n(e)\u0110\u1ea7u giai \u0111o\u1ea1n IV, NST \u1edf d\u1ea1ng s\u1ee3i m\u1ea3nh \u0111\u1ed3ng th\u1eddi c\u00f3 s\u1ef1 co ng\u1eafn, d\u00e3n xo\u1eafn.\n(f)Cu\u1ed1i giai \u0111o\u1ea1n VI, trong t\u1ebf b\u00e0o c\u00f3 2n NST \u0111\u01a1n.","options":[{"text":"2.","is_correct":0},{"text":"3.","is_correct":1},{"text":"5.","is_correct":0},{"text":"4.","is_correct":0}],"level":"VD"},{"question":"\u0110i\u1ec3m so s\u00e1nh gi\u1eefa nguy\u00ean ph\u00e2n v\u00e0 gi\u1ea3m ph\u00e2n n\u00e0o l\u00e0 \u0111\u00fang?\n1.Nguy\u00ean ph\u00e2n ch\u1ec9 x\u1ea3y ra \u1edf t\u1ebf b\u00e0o sinh d\u01b0\u1ee1ng v\u00e0 gi\u1ea3m ph\u00e2n ch\u1ec9 x\u1ea3y ra \u1edf t\u1ebf b\u00e0o sinh d\u1ee5c\n2.C\u00e1ch s\u1eafp x\u1ebfp c\u1ee7a c\u00e1c NST k\u00e9p trong k\u00ec gi\u1eefa c\u1ee7a nguy\u00ean ph\u00e2n v\u00e0 k\u00ec gi\u1eefa gi\u1ea3m ph\u00e2n I kh\u00e1c nhau.\n3.C\u1ea3 hai \u0111\u1ec1u c\u00f3 trao \u0111\u1ed5i ch\u00e9o.\n4.S\u1ef1 ph\u00e2n li NST trong nguy\u00ean ph\u00e2n v\u00e0 s\u1ef1 ph\u00e2n li NST k\u00ec sau I.\n5.\u1ede m\u1ed7i t\u1ebf b\u00e0o con, nguy\u00ean ph\u00e2n c\u00f3 v\u1eadt ch\u1ea5t di truy\u1ec1n \u1ed5n \u0111\u1ecbnh, c\u00f2n v\u1eadt ch\u1ea5t di truy\u1ec1n \u0111i 1 n\u1eeda \u1edf gi\u1ea3m ph\u00e2n.\n6.C\u1ea3 hai \u0111\u1ec1u l\u00e0 m\u1ed9t trong nh\u1eefng c\u01a1 ch\u1ebf gi\u00fap b\u1ed9 NST \u0111\u1eb7c tr\u01b0ng cho lo\u00e0i sinh s\u1ea3n h\u1eefu t\u00ednh \u0111\u01b0\u1ee3c duy tr\u00ec \u1ed5n \u0111\u1ecbnh qua c\u00e1c th\u1ebf h\u1ec7.\n7.Nguy\u00ean ph\u00e2n kh\u00f4ng c\u00f3 trao \u0111\u1ed5i ch\u00e9o v\u00e0 gi\u1ea3m ph\u00e2n c\u00f3 trao \u0111\u1ed5i ch\u00e9o.","options":[{"text":"2, 3, 5, 6, 7.","is_correct":0},{"text":"1, 2, 4, 5, 6.","is_correct":0},{"text":"2, 3, 4, 5, 6.","is_correct":1},{"text":"1, 2, 4, 5, 7.","is_correct":0}],"level":"VD"},{"question":"H\u00ecnh b\u00ean m\u00f4 t\u1ea3 m\u1ed9t giai \u0111o\u1ea1n ph\u00e2n b\u00e0o c\u1ee7a m\u1ed9t t\u1ebf b\u00e0o nh\u00e2n th\u1ef1c l\u01b0\u1ee1ng b\u1ed9i. Bi\u1ebft r\u1eb1ng, 4 nhi\u1ec5m s\u1eafc th\u1ec3 \u0111\u01a1n trong m\u1ed7i nh\u00f3m c\u00f3 h\u00ecnh d\u1ea1ng, k\u00edch th\u01b0\u1edbc kh\u00e1c nhau. D\u01b0\u1edbi \u0111\u00e2y l\u00e0 c\u00e1c k\u1ebft lu\u1eadn r\u00fat ra t\u1eeb h\u00ecnh b\u00ean:\n\u003cimg src=\"bmp_asset://img_03568d9b59eb02a4.png\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e\n(1)B\u1ed9 NST c\u1ee7a lo\u00e0i 2n = 4.\n(2)H\u00ecnh tr\u00ean bi\u1ec3u di\u1ec5n m\u1ed9t giai \u0111o\u1ea1n c\u1ee7a gi\u1ea3m ph\u00e2n II.\n(3)H\u00ecnh tr\u00ean bi\u1ec3u di\u1ec5n m\u1ed9t t\u1ebf b\u00e0o \u0111ang \u1edf k\u00ec sau nguy\u00ean ph\u00e2n.\n(4)T\u1ebf b\u00e0o kh\u00f4ng th\u1ec3 \u0111\u1ea1t \u0111\u1ebfn tr\u1ea1ng th\u00e1i n\u00e0y n\u1ebfu protein \u0111\u1ed9ng c\u01a1 vi \u1ed1ng b\u1ecb \u1ee9c ch\u1ebf.\n(5)Qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o n\u00e0y x\u1ea3y ra \u1edf t\u1ebf b\u00e0o th\u1ef1c v\u1eadt.\nC\u00f3 bao nhi\u00eau k\u1ebft lu\u1eadn \u0111\u00fang?","options":[{"text":"1.","is_correct":0},{"text":"3.","is_correct":0},{"text":"4.","is_correct":0},{"text":"2.","is_correct":1}],"level":"VD"},{"question":"Nh\u1eefng ho\u1ea1t \u0111\u1ed9ng ch\u1ee7 y\u1ebfu n\u00e0o c\u1ee7a nhi\u1ec5m s\u1eafc th\u1ec3 t\u1ea1o n\u00ean l\u01b0\u1ee3ng bi\u1ebfn d\u1ecb to l\u1edbn c\u1ee7a sinh v\u1eadt sinh s\u1ea3n h\u1eefu t\u00ednh?\n1.Ph\u00e2n ly c\u1ee7a c\u00e1c cromatit ch\u1ecb em t\u1ea1i k\u1ef3 sau gi\u1ea3m ph\u00e2n II.\n2.Ph\u00e2n ly c\u1ee7a c\u1eb7p nhi\u1ec5m s\u1eafc th\u1ec3 t\u01b0\u01a1ng \u0111\u1ed3ng t\u1ea1i k\u1ef3 sau gi\u1ea3m ph\u00e2n I.\n3.Trao \u0111\u1ed5i ch\u00e9o gi\u1eefa c\u00e1c nhi\u1ec5m s\u1eafc th\u1ec3 t\u01b0\u01a1ng \u0111\u1ed3ng t\u1ea1i k\u00ec \u0111\u1ea7u gi\u1ea3m ph\u00e2n I.\n4.X\u1ebfp h\u00e0ng \u0111\u1ed9c l\u1eadp c\u1ee7a c\u00e1c c\u1eb7p NST t\u01b0\u01a1ng \u0111\u1ed3ng kh\u00e1c nhau tr\u00ean m\u1eb7t ph\u1eb3ng x\u00edch \u0111\u1ea1o t\u1ea1i k\u1ef3 gi\u1eefa gi\u1ea3m ph\u00e2n I.","options":[{"text":"1 v\u00e0 2.","is_correct":0},{"text":"2 v\u00e0 3.","is_correct":0},{"text":"3 v\u00e0 4.","is_correct":1},{"text":"2 v\u00e0 4.","is_correct":0}],"level":"VD"},{"question":"\u1ede ru\u1ed3i gi\u1ea5m (2n=8). M\u1ed9t t\u1ebf b\u00e0o sinh tinh th\u1ef1c hi\u1ec7n qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n t\u1ea1o giao t\u1eed. M\u1ed9t s\u1ed1 nh\u1eadn x\u00e9t \u0111\u01b0a ra nh\u01b0 sau:\n1.\u1ede k\u00ec \u0111\u1ea7u c\u1ee7a qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n I c\u00f3 8 nhi\u1ec5m s\u1eafc th\u1ec3 k\u00e9p.\n2.\u1ede k\u00ec sau c\u1ee7a qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n I c\u00f3 8 nhi\u1ec5m s\u1eafc th\u1ec3 k\u00e9p.\n3.\u1ede k\u00ec gi\u1eefa c\u1ee7a qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n I c\u00f3 16 t\u00e2m \u0111\u1ed9ng.\n4.\u1ede k\u00ec \u0111\u1ea7u c\u1ee7a qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n II, m\u1ed7i t\u1ebf b\u00e0o con ch\u1ee9a 8 nhi\u1ec5m s\u1eafc th\u1ec3 \u0111\u01a1n.\n5.\u1ede k\u00ec gi\u1eefa c\u1ee7a qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n II, m\u1ed7i t\u1ebf b\u00e0o con c\u00f3 8 cromatit.\n6.\u1ede k\u00ec sau c\u1ee7a qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n II, m\u1ed7i t\u1ebf b\u00e0o con c\u00f3 8 cromatit.\n7.\u1ede k\u00ec sau c\u1ee7a qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n II, m\u1ed7i t\u1ebf b\u00e0o con c\u00f3 ch\u1ee9a 4 t\u00e2m \u0111\u1ed9ng.\nNh\u1eefng nh\u1eadn x\u00e9t \u0111\u00fang:","options":[{"text":"1, 3, 4.","is_correct":0},{"text":"1, 2, 5.","is_correct":1},{"text":"3, 4, 7.","is_correct":0},{"text":"2, 4, 6.","is_correct":0}],"level":"VD"},{"question":"Khi quan s\u00e1t qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o c\u1ee7a m\u1ed9t t\u1ebf b\u00e0o sinh d\u01b0\u1ee1ng \u1edf m\u1ed9t lo\u00e0i sinh v\u1eadt, m\u1ed9t h\u1ecdc sinh \u0111\u00e3 v\u1ebd l\u1ea1i s\u01a1 \u0111\u1ed3 sau:\n\u003cimg src=\"bmp_asset://img_4b52bf245b7302ee.png\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e\nCho c\u00e1c ph\u00e1t bi\u1ec3u sau:\n(1)B\u1ed9 nhi\u1ec5m s\u1eafc th\u1ec3 c\u1ee7a lo\u00e0i n\u00e0y l\u00e0 2n = 8.\n(2)\u1ede giai \u0111o\u1ea1n b t\u1ebf b\u00e0o \u0111ang c\u00f3 8 ph\u00e2n t\u1eed DNA thu\u1ed9c 2 c\u1eb7p nhi\u1ec5m s\u1eafc th\u1ec3.\n(3)Th\u1ee9 t\u1ef1 c\u00e1c giai \u0111o\u1ea1n x\u1ea3y ra l\u00e0 a, b, d, c, e.\n(4)T\u1ebf b\u00e0o \u0111\u01b0\u1ee3c quan s\u00e1t l\u00e0 t\u1ebf b\u00e0o c\u1ee7a m\u1ed9t lo\u00e0i \u0111\u1ed9ng v\u1eadt.\nS\u1ed1 ph\u00e1t bi\u1ec3u \u0111\u00fang l\u00e0:","options":[{"text":"3.","is_correct":0},{"text":"1.","is_correct":1},{"text":"4.","is_correct":0},{"text":"2.","is_correct":0}],"level":"VD"},{"question":"Hai t\u1ebf b\u00e0o d\u01b0\u1edbi \u0111\u00e2y l\u00e0 c\u1ee7a c\u00f9ng m\u1ed9t c\u01a1 th\u1ec3 l\u01b0\u1ee1ng b\u1ed9i c\u00f3 ki\u1ec3u gen AaBb \u0111ang th\u1ef1c hi\u1ec7n qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n.\n\u003cimg src=\"bmp_asset://img_94d25b78d6b633c9.png\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e\nKh\u1eb3ng \u0111\u1ecbnh n\u00e0o sau \u0111\u00e2y kh\u00f4ng \u0111\u00fang?","options":[{"text":"T\u1ebf b\u00e0o 1 \u0111ang \u1edf k\u00ec gi\u1eefa c\u1ee7a gi\u1ea3m ph\u00e2n l c\u00f2n t\u1ebf b\u00e0o 2 \u0111ang \u1edf k\u00ec gi\u1eefa c\u1ee7a qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n II.","is_correct":0},{"text":"N\u1ebfu 2 cromatide ch\u1ee9a gen a c\u1ee7a t\u1ebf b\u00e0o 2 kh\u00f4ng t\u00e1ch nhau ra th\u00ec s\u1ebd t\u1ea1o ra c\u00e1c t\u1ebf b\u00e0o con b\u1ecb \u0111\u1ed9t bi\u1ebfn l\u1ec7ch b\u1ed9i.","is_correct":0},{"text":"Sau khi k\u1ebft th\u00fac to\u00e0n b\u1ed9 qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o b\u00ecnh th\u01b0\u1eddng, h\u00e0m l\u01b0\u1ee3ng DNA trong m\u1ed7i t\u1ebf b\u00e0o con sinh ra t\u1eeb t\u1ebf b\u00e0o 1 v\u00e0 t\u1ebf b\u00e0o 2 b\u1eb1ng nhau.","is_correct":0},{"text":"K\u1ebft th\u00fac qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n b\u00ecnh th\u01b0\u1eddng, t\u1ebf b\u00e0o 1 s\u1ebd h\u00ecnh th\u00e0nh n\u00ean 4 lo\u1ea1i giao t\u1eed c\u00f3 ki\u1ec3u gen l\u00e0: AB, Ab, aB, ab","is_correct":1}],"level":"VD"}],"VDC":[]},"part2":{"NB":[],"TH":[],"VD":[{"question":"Khi n\u00f3i v\u1ec1 \u0111i\u1ec3m kh\u00e1c nhau gi\u1eefa k\u00ec gi\u1eefa c\u1ee7a nguy\u00ean ph\u00e2n v\u00e0 k\u00ec gi\u1eefa I c\u1ee7a gi\u1ea3m ph\u00e2n, ph\u00e1t bi\u1ec3u n\u00e0o \u0111\u00fang, ph\u00e1t bi\u1ec3u n\u00e0o sai?","statements":["Thoi ph\u00e2n b\u00e0o t\u1eeb m\u1ed7i c\u1ef1c ch\u1ec9 \u0111\u00ednh v\u00e0o t\u00e2m \u0111\u1ed9ng c\u1ee7a m\u1ed9t NST k\u00e9p c\u1ee7a c\u1eb7p NST k\u00e9p t\u01b0\u01a1ng \u0111\u1ed3ng.","C\u00e1c c\u1eb7p nhi\u1ec5m s\u1eafc th\u1ec3 k\u00e9p t\u01b0\u01a1ng \u0111\u1ed3ng t\u1eadp trung th\u00e0nh 2 h\u00e0ng \u1edf m\u1eb7t ph\u1eb3ng x\u00edch \u0111\u1ea1o.","Thoi ph\u00e2n b\u00e0o \u0111\u01b0\u1ee3c h\u00ecnh th\u00e0nh, m\u00e0ng nh\u00e2n ti\u00eau bi\u1ebfn.","C\u00e1c nhi\u1ec5m s\u1eafc th\u1ec3 k\u00e9p co xo\u1eafn c\u1ef1c \u0111\u1ea1i."],"answers":["\u0110","\u0110","S","S"],"level":"VD"},{"question":"\u1ede ng\u01b0\u1eddi (2n = 46), ph\u00e2n t\u00edch h\u00e0m l\u01b0\u1ee3ng DNA trong m\u1ed9t t\u1ebf b\u00e0o qua c\u00e1c th\u1eddi k\u00ec ph\u00e2n b\u00e0o ng\u01b0\u1eddi ta v\u1ebd \u0111\u01b0\u1ee3c \u0111\u1ed3 th\u1ecb d\u01b0\u1edbi \u0111\u00e2y. D\u1ef1a v\u00e0o \u0111\u1ed3 th\u1ecb, m\u1ed7i m\u1ec7nh \u0111\u1ec1 sau l\u00e0 \u0111\u00fang hay sai?\n\u003cimg src=\"bmp_asset://img_db9613c9594e71c6.jpg\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e","statements":["\u0110\u1ed3 th\u1ecb n\u00e0y m\u00f4 t\u1ea3 s\u1ef1 ph\u00e1t tri\u1ec3n c\u1ee7a 1 t\u1ebf b\u00e0o sinh d\u1ee5c)","\u1ede giai \u0111o\u1ea1n a, c, e thu\u1ed9c k\u00ec cu\u1ed1i c\u1ee7a nguy\u00ean ph\u00e2n.","Giai \u0111o\u1ea1n b, d, g c\u00f3 th\u1ec3 thu\u1ed9c k\u00ec gi\u1eefa c\u1ee7a nguy\u00ean ph\u00e2n.","Giai \u0111o\u1ea1n h, i thu\u1ed9c k\u00ec cu\u1ed1i c\u1ee7a gi\u1ea3m ph\u00e2n I."],"answers":["\u0110","\u0110","S","S"],"level":"VD"},{"question":"M\u1ed7i nh\u1eadn \u0111\u1ecbnh sau l\u00e0 \u0111\u00fang hay sai khi n\u00f3i v\u1ec1 \u00fd ngh\u0129a c\u1ee7a qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n?","statements":["T\u1ea1o nhi\u1ec1u bi\u1ebfn d\u1ecb t\u1ed5 h\u1ee3p l\u00e0m sinh gi\u1edbi th\u00eam phong ph\u00fa, \u0111a d\u1ea1ng.","L\u00e0 c\u01a1 ch\u1ebf sinh s\u1ea3n \u1edf sinh v\u1eadt \u0111\u01a1n b\u00e0o, sinh s\u1ea3n v\u00f4 t\u00ednh \u1edf sinh v\u1eadt \u0111a b\u00e0o.","Trong sinh s\u1ea3n h\u1eefu t\u00ednh, c\u00f9ng v\u1edbi nguy\u00ean ph\u00e2n v\u00e0 th\u1ee5 tinh g\u00f3p ph\u1ea7n duy tr\u00ec \u1ed5n \u0111\u1ecbnh b\u1ed9 nhi\u1ec5m s\u1eafc th\u1ec3 \u0111\u1eb7c tr\u01b0ng c\u1ee7a lo\u00e0i.","T\u1ea1o s\u1ef1 \u0111a d\u1ea1ng di truy\u1ec1n, cung c\u1ea5p nguy\u00ean li\u1ec7u cho ch\u1ecdn gi\u1ed1ng v\u00e0 ti\u1ebfn h\u00f3a, gi\u00fap c\u00e1c lo\u00e0i th\u00edch nghi t\u1ed1t h\u01a1n v\u1edbi m\u00f4i tr\u01b0\u1eddng s\u1ed1ng lu\u00f4n bi\u1ebfn \u0111\u1ed5i."],"answers":["\u0110","S","\u0110","\u0110"],"level":"VD"},{"question":"M\u1ed7i nh\u1eadn \u0111\u1ecbnh sau l\u00e0 \u0111\u00fang hay sai khi n\u00f3i v\u1ec1 l\u00ed do c\u1ee7a s\u1ef1 \u0111a d\u1ea1ng di truy\u1ec1n trong sinh s\u1ea3n h\u1eefu t\u00ednh?","statements":["S\u1ef1 ph\u00e2n li \u0111\u1ed9c l\u1eadp v\u00e0 t\u1ed5 h\u1ee3p t\u1ef1 do c\u1ee7a c\u00e1c nhi\u1ec5m s\u1eafc th\u1ec3 trong gi\u1ea3m ph\u00e2n v\u00e0 th\u1ee5 tinh.","S\u1ef1 ph\u00e2n li \u0111\u1ed3ng \u0111\u1ec1u c\u1ee7a c\u00e1c nhi\u1ec5m s\u1eafc th\u1ec3 trong nguy\u00ean ph\u00e2n v\u00e0 gi\u1ea3m ph\u00e2n.","S\u1ef1 duy tr\u00ec \u1ed5n \u0111\u1ecbnh b\u1ed9 nhi\u1ec5m s\u1eafc th\u1ec3 l\u01b0\u1ee1ng b\u1ed9i trong qu\u00e1 tr\u00ecnh nguy\u00ean ph\u00e2n.","S\u1ef1 trao \u0111\u1ed5i ch\u00e9o c\u00e1c \u0111o\u1ea1n chromatid c\u1ee7a c\u1eb7p nhi\u1ec5m s\u1eafc th\u1ec3 t\u01b0\u01a1ng \u0111\u1ed3ng."],"answers":["\u0110","S","S","\u0110"],"level":"VD"},{"question":"M\u1ed7i nh\u1eadn \u0111\u1ecbnh sau l\u00e0 \u0111\u00fang hay sai khi n\u00f3i v\u1ec1 \u0111i\u1ec3m gi\u1ed1ng nhau gi\u1eefa nguy\u00ean ph\u00e2n v\u00e0 gi\u1ea3m ph\u00e2n?","statements":["S\u1ed1 l\u1ea7n ph\u00e2n chia t\u1ebf b\u00e0o.","S\u1ed1 l\u1ea7n nh\u00e2n \u0111\u00f4i DNA v\u00e0 nhi\u1ec5m s\u1eafc th\u1ec3.","S\u1ef1 trao \u0111\u1ed5i ch\u00e9o c\u00e1c \u0111o\u1ea1n chromatid c\u1ee7a c\u1eb7p nhi\u1ec5m s\u1eafc th\u1ec3 t\u01b0\u01a1ng \u0111\u1ed3ng.","C\u00e1ch s\u1eafp x\u1ebfp c\u00e1c nhi\u1ec5m s\u1eafc th\u1ec3 tr\u00ean thoi ph\u00e2n b\u00e0o \u1edf k\u00ec gi\u1eefa v\u00e0 k\u00ec gi\u1eefa II."],"answers":["S","\u0110","S","\u0110"],"level":"VD"},{"question":"Quan s\u00e1t h\u00ecnh (1) \u0111\u1ebfn h\u00ecnh (8) v\u00e0 cho bi\u1ebft m\u1ed7i m\u1ec7nh \u0111\u1ec1 sau l\u00e0 \u0111\u00fang hay sai?\n\u003cimg src=\"bmp_asset://img_cf9ecb58897919dd.png\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e","statements":["T\u1ebf b\u00e0o \u1edf h\u00ecnh (1) l\u00e0 m\u1ed9t t\u1ebf b\u00e0o sinh d\u01b0\u1ee1ng v\u00e0 \u0111ang \u1edf k\u00ec gi\u1eefa c\u1ee7a gi\u1ea3m ph\u00e2n ph\u00e2n I.","C\u00e1c t\u1ebf b\u00e0o \u1edf h\u00ecnh (2), (4), (8) l\u00e0 t\u1ebf b\u00e0o sinh d\u01b0\u1ee1ng v\u00e0 \u0111ang \u1edf k\u00ec sau c\u1ee7a nguy\u00ean ph\u00e2n.","T\u1ebf b\u00e0o \u1edf h\u00ecnh (5) l\u00e0 m\u1ed9t t\u1ebf b\u00e0o sinh d\u1ee5c \u0111ang \u1edf k\u00ec gi\u1eefa c\u1ee7a gi\u1ea3m ph\u00e2n II.","Lo\u00e0i A v\u00e0 lo\u00e0i B \u0111\u1ec1u c\u00f3 b\u1ed9 nhi\u1ec5m s\u1eafc th\u1ec3 2n = 8."],"answers":["S","S","\u0110","S"],"level":"VD"},{"question":"H\u00ecnh b\u00ean d\u01b0\u1edbi m\u00f4 t\u1ea3 kh\u00e1i qu\u00e1t qu\u00e1 tr\u00ecnh ph\u00e2n chia c\u1ee7a m\u1ed9t t\u1ebf b\u00e0o. M\u1ed7i m\u1ec7nh \u0111\u1ec1 sau l\u00e0 \u0111\u00fang hay sai?\n\u003cimg src=\"bmp_asset://img_5e2bfb9afc99780f.png\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e","statements":["Tr\u1eadt t\u1ef1 ch\u00ednh x\u00e1c v\u1ec1 c\u00e1c giai \u0111o\u1ea1n c\u1ee7a qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o n\u00e0y l\u00e0 A \uf0e0 B \uf0e0 G \uf0e0 F \uf0e0 E \uf0e0 C \uf0e0 D","\u0110\u00e2y l\u00e0 qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n.","Giai \u0111o\u1ea1n E \u0111ang \u1edf k\u00ec gi\u1eefa I c\u1ee7a qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n.","Giai \u0111o\u1ea1n C \u0111ang \u1edf k\u00ec sau c\u1ee7a qu\u00e1 tr\u00ecnh nguy\u00ean ph\u00e2n."],"answers":["\u0110","\u0110","S","S"],"level":"VD"},{"question":"Ng\u1ef1a c\u00f3 b\u1ed9 nhi\u00ea\u0303m s\u0103\u0301c th\u00ea\u0309 2n = 64 v\u00e0 l\u1eeba c\u00f3 b\u1ed9 nhi\u00ea\u0303m s\u0103\u0301c th\u00ea\u0309 2n = 62, m\u1ed7i nh\u1eadn \u0111\u1ecbnh sau \u0111\u00e2y l\u00e0 \u0110\u00fang hay Sai?\n\u003cimg src=\"bmp_asset://img_8c45eca074a94c05.png\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e","statements":["Qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n x\u1ea3y ra b\u00ecnh th\u01b0\u1eddng th\u00ec giao t\u1eed c\u1ee7a ng\u1ef1a c\u00f3 b\u1ed9 NST n=32.","Trong qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n t\u1ea1o giao t\u1eed c\u1ee7a con l\u1eeba, \u1edf k\u00ec sau gi\u1ea3m ph\u00e2n II quan s\u00e1t th\u1ea5y 62 cromatit.","Con la sinh s\u1ea3n b\u00ecnh th\u01b0\u1eddng.","Con la c\u00f3 b\u1ed9 NST l\u01b0\u1ee1ng b\u1ed9i l\u00e0 2n= 63."],"answers":["\u0110","S","S","\u0110"],"level":"VD"},{"question":"H\u00ecnh sau m\u00f4 t\u1ea3 m\u1ed9t t\u1ebf b\u00e0o \u0111\u1ed9ng v\u1eadt \u0111ang ph\u00e2n b\u00e0o b\u00ecnh th\u01b0\u1eddng. T\u1eeb c\u00e1c th\u00f4ng tin m\u00f4 t\u1ea3 trong h\u00ecnh, c\u00e1c ph\u00e1t bi\u1ec3u sau l\u00e0 \u0111\u00fang hay sai?\n\u003cimg src=\"bmp_asset://img_17bb0bab3e835ac4.png\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e","statements":["N\u1ebfu c\u00e1c NST k\u00e9p trong t\u1ebf b\u00e0o \u0111\u1ec1u kh\u00f4ng t\u01b0\u01a1ng \u0111\u1ed3ng v\u1edbi nhau; th\u00ec k\u1ebft th\u00fac ph\u00e2n b\u00e0o, 2 t\u1ebf b\u00e0o con t\u1ea1o ra c\u00f3 th\u1ec3 ph\u00e1t tri\u1ec3n th\u00e0nh giao t\u1eed.","T\u1ebf b\u00e0o \u0111ang \u1edf k\u00ec gi\u1eefa c\u1ee7a qu\u00e1 tr\u00ecnh nguy\u00ean ph\u00e2n ho\u1eb7c gi\u1ea3m ph\u00e2n II.","T\u1ebf b\u00e0o n\u00e0y c\u00f3 th\u1ec3 l\u00e0 t\u1ebf b\u00e0o c\u1ee7a m\u1ed9t c\u01a1 th\u1ec3 ru\u1ed3i gi\u1ea5m.","T\u1ebf b\u00e0o n\u00e0y l\u00e0 t\u1ebf b\u00e0o soma)"],"answers":["\u0110","\u0110","\u0110","S"],"level":"VD"},{"question":"Quan s\u00e1t qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o c\u1ee7a m\u1ed9t t\u1ebf b\u00e0o \u1edf m\u1ed9t lo\u00e0i \u0111\u1ed9ng v\u1eadt l\u01b0\u1ee1ng b\u1ed9i, th\u1ea5y di\u1ec5n bi\u1ebfn b\u1ed9 NST \u0111ang di\u1ec5n ra theo h\u00ecnh b\u00ean. Trong \u0111\u00f3 A, a; B, b l\u00e0 k\u00ed hi\u1ec7u c\u1ee7a t\u1eebng NST trong b\u1ed9 NST l\u01b0\u1ee1ng b\u1ed9i. H\u00e3y cho bi\u1ebft ph\u00e1t bi\u1ec3u n\u00e0o \u0111\u00fang, ph\u00e1t bi\u1ec3u n\u00e0o sai?\n\u003cimg src=\"bmp_asset://img_1e24efe60bce134d.png\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e","statements":["T\u1ebf b\u00e0o \u0111ang \u1edf k\u00ec gi\u1eefa c\u1ee7a qu\u00e1 tr\u00ecnh nguy\u00ean ph\u00e2n.","S\u1ef1 kh\u00f4ng ph\u00e2n ly c\u1ee7a c\u00e1c NST \u0111\u01a1n t\u1ea1o ra t\u1eeb NST k\u00e9p B) B c\u00f3 th\u1ec3 t\u1ea1o ra c\u00e1c t\u1ebf b\u00e0o con mang th\u00e0nh ph\u1ea7n NST g\u1ed3m AabBB v\u00e0 AaBb)","N\u1ebfu qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o l\u00e0 b\u00ecnh th\u01b0\u1eddng, c\u00e1c t\u1ebf b\u00e0o con t\u1ea1o ra c\u00f3 th\u00e0nh ph\u1ea7n NST g\u1ed3m AaBb)","T\u1ea1i k\u00ec trung gian, m\u00f4i tr\u01b0\u1eddng n\u1ed9i b\u00e0o \u0111\u00e3 cung c\u1ea5p nguy\u00ean li\u1ec7u t\u01b0\u01a1ng \u0111\u01b0\u01a1ng 4 NST \u0111\u01a1n \u0111\u1ec3 gi\u00fap t\u1ebf b\u00e0o nh\u00e2n \u0111\u00f4i NST."],"answers":["\u0110","S","\u0110","\u0110"],"level":"VD"},{"question":"Hai t\u1ebf b\u00e0o d\u01b0\u1edbi \u0111\u00e2y l\u00e0 c\u00f9ng c\u1ee7a m\u1ed9t c\u01a1 th\u1ec3 l\u01b0\u1ee1ng b\u1ed9i c\u00f3 ki\u1ec3u gen AaBb \u0111ang th\u1ef1c hi\u1ec7n qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o b\u00ecnh th\u01b0\u1eddng. T\u1eeb c\u00e1c th\u00f4ng tin trong h\u00ecnh, cho bi\u1ebft m\u1ed7i m\u1ec7nh \u0111\u1ec1 sau l\u00e0 \u0111\u00fang hay sai?\n\u003cimg src=\"bmp_asset://img_5aaf0968959a33c1.jpg\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e","statements":["C\u01a1 th\u1ec3 n\u00e0y c\u00f3 2n = 8 NST.","Ti\u1ec1n th\u00e2n c\u1ee7a t\u1ebf b\u00e0o 2 l\u00e0 m\u1ed9t t\u1ebf b\u00e0o c\u00f3 c\u00e1ch s\u1eafp x\u1ebfp NST gi\u1ed1ng t\u1ebf b\u00e0o 1.","C\u1ea3 2 t\u1ebf b\u00e0o \u0111\u1ec1u \u0111ang ti\u1ebfn h\u00e0nh gi\u1ea3m ph\u00e2n.","Khi k\u1ebft th\u00fac l\u1ea7n ph\u00e2n chia \u0111ang ti\u1ebfn h\u00e0nh, t\u1ebf b\u00e0o 1 c\u00f3 th\u1ec3 t\u1ea1o ra t\u1ebf b\u00e0o con c\u00f3 h\u00e0m l\u01b0\u1ee3ng DNA t\u01b0\u01a1ng \u0111\u01b0\u01a1ng t\u1ebf b\u00e0o 2."],"answers":["S","S","\u0110","\u0110"],"level":"VD"},{"question":"Khi quan s\u00e1t qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o b\u00ecnh th\u01b0\u1eddng \u1edf m\u1ed9t t\u1ebf b\u00e0o (t\u1ebf b\u00e0o A) c\u1ee7a m\u1ed9t lo\u00e0i d\u01b0\u1edbi k\u00ednh hi\u1ec3n vi, ng\u01b0\u1eddi ta b\u1eaft g\u1eb7p hi\u1ec7n t\u01b0\u1ee3ng \u0111\u01b0\u1ee3c m\u00f4 t\u1ea3 \u1edf h\u00ecnh b\u00ean d\u01b0\u1edbi. M\u1ed7i m\u1ec7nh \u0111\u1ec1 sau l\u00e0 \u0111\u00fang hay sai?\n\u003cimg src=\"bmp_asset://img_69d17efca1df62c5.png\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e","statements":["T\u1ebf b\u00e0o A khi k\u1ebft th\u00fac qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o t\u1ea1o ra c\u00e1c t\u1ebf b\u00e0o con c\u00f3 b\u1ed9 nhi\u1ec5m s\u1eafc th\u1ec3 n = 2.","T\u1ebf b\u00e0o A \u0111ang \u1edf k\u00ec gi\u1eefa c\u1ee7a qu\u00e1 tr\u00ecnh nguy\u00ean ph\u00e2n.","M\u1ed7i gen tr\u00ean NST c\u1ee7a t\u1ebf b\u00e0o A trong giai \u0111o\u1ea1n n\u00e0y \u0111\u1ec1u c\u00f3 2 alen.","S\u1ed1 t\u00e2m \u0111\u1ed9ng trong t\u1ebf b\u00e0o A \u1edf giai \u0111o\u1ea1n n\u00e0y l\u00e0 8."],"answers":["\u0110","S","S","S"],"level":"VD"},{"question":"H\u00ecnh v\u1ebd sau \u0111\u00e2y m\u00f4 t\u1ea3 ba t\u1ebf b\u00e0o \u0111ang trong qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o. Theo quan s\u00e1t, m\u1ed7i m\u1ec7nh \u0111\u1ec1 sau l\u00e0 \u0111\u00fang hay sai?\n\u003cimg src=\"bmp_asset://img_e2bdf8bfbbf9c6fa.jpg\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e","statements":["T\u1ebf b\u00e0o 2 \u0111ang \u1edf k\u00ec sau c\u1ee7a gi\u1ea3m ph\u00e2n II.","T\u1ebf b\u00e0o 1 v\u00e0 3 c\u00f3 th\u1ec3 thu\u1ed9c c\u00f9ng m\u1ed9t c\u01a1 th\u1ec3 (2n = 4).","T\u1ebf b\u00e0o 1, 2 c\u00f3 th\u1ec3 thu\u1ed9c c\u00f9ng m\u1ed9t c\u01a1 th\u1ec3 (2n= 8).","C\u1ea3 3 t\u1ebf b\u00e0o c\u00f3 th\u1ec3 \u0111\u1ec1u l\u00e0 t\u1ebf b\u00e0o sinh d\u01b0\u1ee1ng."],"answers":["S","\u0110","\u0110","S"],"level":"VD"},{"question":"S\u01a1 \u0111\u1ed3 sau \u0111\u00e2y bi\u1ec3u di\u1ec5n h\u00e0m l\u01b0\u1ee3ng DNA trong m\u1ed9t t\u1ebf b\u00e0o sinh d\u01b0\u1ee1ng 2n tr\u1ea3i qua m\u1ed9t qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o n\u00e0o \u0111\u00f3. D\u1ef1a v\u00e0o s\u01a1 \u0111\u1ed3 h\u00e3y cho bi\u1ebft m\u1ec7nh \u0111\u1ec1 n\u00e0o \u0111\u00fang, m\u1ec7nh \u0111\u1ec1 n\u00e0o sai?\n\u003cimg src=\"bmp_asset://img_31d40397a7a57174.jpg\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e","statements":["Giai \u0111o\u1ea1n I v\u00e0 II c\u00f3 th\u1ec3 thu\u1ed9c k\u00ec trung gian.","Giai \u0111o\u1ea1n III c\u00f3 th\u1ec3 thu\u1ed9c k\u00ec sau c\u1ee7a gi\u1ea3m ph\u00e2n I.","Giai \u0111o\u1ea1n IV c\u00f3 th\u1ec3 thu\u1ed9c k\u00ec \u0111\u1ea7u, k\u00ec gi\u1eefa gi\u1ea3m ph\u00e2n II.","Giai \u0111o\u1ea1n V, VI c\u00f3 th\u1ec3 thu\u1ed9c k\u00ec cu\u1ed1i c\u1ee7a gi\u1ea3m ph\u00e2n II."],"answers":["\u0110","\u0110","\u0110","S"],"level":"VD"},{"question":"Hai t\u1ebf b\u00e0o d\u01b0\u1edbi \u0111\u00e2y l\u00e0 c\u1ee7a c\u00f9ng m\u1ed9t c\u01a1 th\u1ec3 l\u01b0\u1ee1ng b\u1ed9i c\u00f3 ki\u1ec3u gen AaBb \u0111ang th\u1ef1c hi\u1ec7n qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n. H\u00e3y cho bi\u1ebft m\u1ed7i m\u1ec7nh \u0111\u1ec1 sau l\u00e0 \u0111\u00fang hay sai?\n\u003cimg src=\"bmp_asset://img_b0433a80511f4bfb.jpg\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e","statements":["Sau khi k\u1ebft th\u00fac to\u00e0n b\u1ed9 qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o b\u00ecnh th\u01b0\u1eddng, h\u00e0m l\u01b0\u1ee3ng DNA trong m\u1ed7i t\u1ebf b\u00e0o con sinh ra t\u1eeb t\u1ebf b\u00e0o 1 v\u00e0 t\u1ebf b\u00e0o 2 b\u1eb1ng nhau.","K\u1ebft th\u00fac qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n b\u00ecnh th\u01b0\u1eddng, t\u1ebf b\u00e0o 1 s\u1ebd h\u00ecnh th\u00e0nh n\u00ean 4 lo\u1ea1i giao t\u1eed c\u00f3 ki\u1ec3u gen l\u00e0: AB, Ab, aB, ab)","N\u1ebfu 2 cromatide ch\u1ee9a gen a c\u1ee7a t\u1ebf b\u00e0o 2 kh\u00f4ng t\u00e1ch nhau ra th\u00ec s\u1ebd t\u1ea1o ra c\u00e1c t\u1ebf b\u00e0o con b\u1ecb \u0111\u1ed9t bi\u1ebfn l\u1ec7ch b\u1ed9i."],"answers":["S","\u0110","S"],"level":"VD"},{"question":"Cho h\u00ecnh v\u1ebd sau \u0111\u00e2y m\u00f4 t\u1ea3 hai t\u1ebf b\u00e0o \u1edf hai c\u01a1 th\u1ec3 l\u01b0\u1ee1ng b\u1ed9i \u0111ang ph\u00e2n b\u00e0o. D\u1ef1a v\u00e0o h\u00ecnh v\u1ebd h\u00e3y cho bi\u1ebft m\u1ed7i m\u1ec7nh \u0111\u1ec1 sau l\u00e0 \u0111\u00fang hay sai?\n\u003cimg src=\"bmp_asset://img_43b0abbcb8154fb8.png\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e","statements":["Khi k\u1ebft th\u00fac qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o \u1edf hai t\u1ebf b\u00e0o tr\u00ean th\u00ec t\u1eeb t\u1ebf b\u00e0o 1 t\u1ea1o ra hai t\u1ebf b\u00e0o \u0111\u01a1n b\u1ed9i, t\u1eeb t\u1ebf b\u00e0o 2 t\u1ea1o ra hai t\u1ebf b\u00e0o l\u01b0\u1ee1ng b\u1ed9i.","T\u1ebf b\u00e0o 1 \u0111ang \u1edf k\u00ec sau c\u1ee7a gi\u1ea3m ph\u00e2n II, t\u1ebf b\u00e0o 2 \u0111ang \u1edf k\u00ec sau c\u1ee7a nguy\u00ean ph\u00e2n.","B\u1ed9 nhi\u1ec5m s\u1eafc th\u1ec3 c\u1ee7a t\u1ebf b\u00e0o 1 l\u00e0 2n = 8, b\u1ed9 nhi\u1ec5m s\u1eafc th\u1ec3 c\u1ee7a t\u1ebf b\u00e0o 2 l\u00e0 2n = 4.","Hai t\u1ebf b\u00e0o \u0111\u1ec1u \u0111ang \u1edf k\u00ec sau c\u1ee7a nguy\u00ean ph\u00e2n."],"answers":["\u0110","\u0110","\u0110","S"],"level":"VD"},{"question":"H\u00ecnh b\u00ean d\u01b0\u1edbi m\u00f4 t\u1ea3 m\u1ed9t giai \u0111o\u1ea1n ph\u00e2n b\u00e0o c\u1ee7a m\u1ed9t t\u1ebf b\u00e0o nh\u00e2n th\u1ef1c l\u01b0\u1ee1ng b\u1ed9i. Bi\u1ebft r\u1eb1ng, 4 nhi\u1ec5m s\u1eafc th\u1ec3 \u0111\u01a1n trong m\u1ed7i nh\u00f3m c\u00f3 h\u00ecnh d\u1ea1ng, k\u00edch th\u01b0\u1edbc kh\u00e1c nhau. M\u1ec7nh \u0111\u1ec1 n\u00e0o \u0111\u00fang, m\u1ec7nh \u0111\u1ec1 n\u00e0o sai?\n\u003cimg src=\"bmp_asset://img_58978e3e17749cd3.jpg\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e","statements":["Qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o n\u00e0y x\u1ea3y ra \u1edf t\u1ebf b\u00e0o th\u1ef1c v\u1eadt.","H\u00ecnh tr\u00ean bi\u1ec3u di\u1ec5n m\u1ed9t giai \u0111o\u1ea1n c\u1ee7a gi\u1ea3m ph\u00e2n II.","H\u00ecnh tr\u00ean bi\u1ec3u di\u1ec5n m\u1ed9t t\u1ebf b\u00e0o \u0111ang \u1edf k\u00ec sau nguy\u00ean ph\u00e2n.","T\u1ebf b\u00e0o kh\u00f4ng th\u1ec3 \u0111\u1ea1t \u0111\u1ebfn tr\u1ea1ng th\u00e1i n\u00e0y n\u1ebfu protein \u0111\u1ed9ng c\u01a1 vi \u1ed1ng b\u1ecb \u1ee9c ch\u1ebf."],"answers":["S","\u0110","S","\u0110"],"level":"VD"},{"question":"M\u1ed7i nh\u1eadn \u0111\u1ecbnh sau l\u00e0 \u0111\u00fang hay sai khi n\u00f3i v\u1ec1 nh\u1eefng ho\u1ea1t \u0111\u1ed9ng ch\u1ee7 y\u1ebfu c\u1ee7a nhi\u1ec5m s\u1eafc th\u1ec3 t\u1ea1o n\u00ean l\u01b0\u1ee3ng bi\u1ebfn d\u1ecb to l\u1edbn c\u1ee7a sinh v\u1eadt sinh s\u1ea3n h\u1eefu t\u00ednh?","statements":["Ph\u00e2n ly c\u1ee7a c\u00e1c cromatit ch\u1ecb em t\u1ea1i k\u1ef3 sau gi\u1ea3m ph\u00e2n II.","X\u1ebfp h\u00e0ng \u0111\u1ed9c l\u1eadp c\u1ee7a c\u00e1c c\u1eb7p NST t\u01b0\u01a1ng \u0111\u1ed3ng kh\u00e1c nhau tr\u00ean m\u1eb7t ph\u1eb3ng x\u00edch \u0111\u1ea1o t\u1ea1i k\u1ef3 gi\u1eefa gi\u1ea3m ph\u00e2n I.","Ph\u00e2n ly c\u1ee7a c\u1eb7p nhi\u1ec5m s\u1eafc th\u1ec3 t\u01b0\u01a1ng \u0111\u1ed3ng t\u1ea1i k\u1ef3 sau gi\u1ea3m ph\u00e2n I.","Trao \u0111\u1ed5i ch\u00e9o gi\u1eefa c\u00e1c nhi\u1ec5m s\u1eafc th\u1ec3 t\u01b0\u01a1ng \u0111\u1ed3ng t\u1ea1i k\u00ec \u0111\u1ea7u gi\u1ea3m ph\u00e2n I."],"answers":["S","\u0110","S","S"],"level":"VD"},{"question":"\u1ede ng\u01b0\u1eddi c\u00f3 2n = 46, m\u1ed9t t\u1ebf b\u00e0o sinh tinh (tinh b\u00e0o l) di\u1ec5n ra qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n. M\u1ed7i m\u1ec7nh \u0111\u1ec1 sau l\u00e0 \u0111\u00fang hay sai?","statements":["\u1ede k\u00ec \u0111\u1ea7u I trong t\u1ebf b\u00e0o c\u00f3 92 cromatit.","K\u1ebft th\u00fac qu\u00e1 tr\u00ecnh tr\u00ean h\u00ecnh th\u00e0nh n\u00ean 4 giao t\u1eed.","\u1ede \u0111\u1ea7u k\u00ec cu\u1ed1i II trong t\u1ebf b\u00e0o c\u00f3 23 NST \u0111\u01a1n.","Trong su\u1ed1t qu\u00e1 tr\u00ecnh tr\u00ean trong t\u1ebf b\u00e0o lu\u00f4n t\u1ed3n t\u1ea1i c\u1eb7p NST t\u01b0\u01a1ng \u0111\u1ed3ng."],"answers":["\u0110","\u0110","S","S"],"level":"VD"},{"question":"Cho h\u00ecnh \u1ea3nh v\u1ec1 m\u1ed9t giai \u0111o\u1ea1n trong qu\u00e1 tr\u00ecnh ph\u00e2n b\u00e0o c\u1ee7a m\u1ed9t t\u1ebf b\u00e0o l\u01b0\u1ee1ng b\u1ed9i 2n b\u00ecnh th\u01b0\u1eddng (t\u1ebf b\u00e0o A) trong c\u01a1 th\u1ec3 \u0111\u1ef1c \u1edf m\u1ed9t lo\u00e0i v\u00e0 m\u1ed9t s\u1ed1 ph\u00e1t bi\u1ec3u t\u01b0\u01a1ng \u1ee9ng nh\u01b0 sau. Ph\u00e1t bi\u1ec3u n\u00e0o \u0111\u00fang, ph\u00e1t bi\u1ec3u n\u00e0o sai?\n\u003cimg src=\"bmp_asset://img_9bf0fcd110941ce5.png\" alt=\"H\u00ecnh\" style=\"max-width: 100%; height: auto;\" /\u003e","statements":["T\u1ebf b\u00e0o A t\u1ea1o ra t\u1ed1i \u0111a l\u00e0 4 lo\u1ea1i giao t\u1eed kh\u00e1c nhau v\u1ec1 c\u00e1c gen \u0111ang x\u00e9t.","T\u1ebf b\u00e0o A c\u00f3 x\u1ea3y ra trao \u0111\u1ed5i ch\u00e9o trong qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n 1.","T\u1ebf b\u00e0o A mang c\u00f3 ch\u1ee9a \u00edt nh\u1ea5t l\u00e0 hai c\u1eb7p gen d\u1ecb h\u1ee3p.","T\u1ebf b\u00e0o A kh\u00f4ng th\u1ec3 t\u1ea1o \u0111\u01b0\u1ee3c giao t\u1eed b\u00ecnh th\u01b0\u1eddng."],"answers":["S","\u0110","\u0110","\u0110"],"level":"VD"}],"VDC":[]},"part3":{"NB":[],"TH":[],"VD":[{"question":"S\u1ef1 ki\u1ec7n n\u00e0o sau \u0111\u00e2y ch\u1ec9 x\u1ea3y ra \u1edf Gi\u1ea3m ph\u00e2n I m\u00e0 kh\u00f4ng x\u1ea3y ra \u1edf Gi\u1ea3m ph\u00e2n II? (1-C\u00e1c NST co xo\u1eafn, 2-Thoi ph\u00e2n b\u00e0o h\u00ecnh th\u00e0nh, 3-C\u00e1c c\u1eb7p NST t\u01b0\u01a1ng \u0111\u1ed3ng ti\u1ebfp h\u1ee3p v\u00e0 c\u00f3 th\u1ec3 trao \u0111\u1ed5i ch\u00e9o, 4-C\u00e1c NST x\u1ebfp tr\u00ean m\u1eb7t ph\u1eb3ng x\u00edch \u0111\u1ea1o)","answer":"3","level":"VD"},{"question":"\u1ede k\u00ec gi\u1eefa I c\u1ee7a gi\u1ea3m ph\u00e2n, c\u00e1c nhi\u1ec5m s\u1eafc th\u1ec3 c\u00f3 \u0111\u1eb7c \u0111i\u1ec3m s\u1eafp x\u1ebfp nh\u01b0 th\u1ebf n\u00e0o tr\u00ean m\u1eb7t ph\u1eb3ng x\u00edch \u0111\u1ea1o? (1-T\u1eebng NST k\u00e9p x\u1ebfp th\u00e0nh m\u1ed9t h\u00e0ng, 2-C\u00e1c c\u1eb7p NST t\u01b0\u01a1ng \u0111\u1ed3ng x\u1ebfp th\u00e0nh hai h\u00e0ng, 3-T\u1eebng NST \u0111\u01a1n x\u1ebfp th\u00e0nh m\u1ed9t h\u00e0ng, 4-C\u00e1c c\u1eb7p NST t\u01b0\u01a1ng \u0111\u1ed3ng x\u1ebfp th\u00e0nh m\u1ed9t h\u00e0ng)","answer":"2","level":"VD"},{"question":"K\u1ebft qu\u1ea3 c\u1ee7a qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n t\u1eeb m\u1ed9t t\u1ebf b\u00e0o m\u1ea7m sinh d\u1ee5c (2n) l\u00e0 t\u1ea1o ra? (1-Hai t\u1ebf b\u00e0o con (2n) gi\u1ed1ng h\u1ec7t nhau, 2-B\u1ed1n t\u1ebf b\u00e0o con (n) gi\u1ed1ng h\u1ec7t nhau, 3-Hai t\u1ebf b\u00e0o con (n) kh\u00e1c nhau v\u1ec1 di truy\u1ec1n, 4-B\u1ed1n t\u1ebf b\u00e0o con (n) c\u00f3 th\u1ec3 kh\u00e1c nhau v\u1ec1 di truy\u1ec1n)","answer":"4","level":"VD"},{"question":"Trong qu\u00e1 tr\u00ecnh ph\u00e1t sinh giao t\u1eed \u1edf \u0111\u1ed9ng v\u1eadt, s\u1ef1 ki\u1ec7n n\u00e0o sau \u0111\u00e2y m\u00f4 t\u1ea3 \u0111\u00fang v\u1ec1 ph\u00e1t sinh no\u00e3n (tr\u1ee9ng)? (1-T\u1eeb m\u1ed9t t\u1ebf b\u00e0o sinh tr\u1ee9ng t\u1ea1o ra b\u1ed1n tr\u1ee9ng c\u00f3 k\u00edch th\u01b0\u1edbc b\u1eb1ng nhau, 2-T\u1eeb m\u1ed9t t\u1ebf b\u00e0o sinh tr\u1ee9ng t\u1ea1o ra m\u1ed9t tr\u1ee9ng v\u00e0 ba th\u1ec3 c\u1ef1c, 3-T\u1eeb m\u1ed9t t\u1ebf b\u00e0o sinh tr\u1ee9ng t\u1ea1o ra hai tr\u1ee9ng v\u00e0 hai th\u1ec3 c\u1ef1c, 4-T\u1eeb m\u1ed9t t\u1ebf b\u00e0o sinh tr\u1ee9ng t\u1ea1o ra b\u1ed1n t\u1ebf b\u00e0o con \u0111\u1ec1u ph\u00e1t tri\u1ec3n th\u00e0nh tr\u1ee9ng)","answer":"2","level":"VD"},{"question":"Y\u1ebfu t\u1ed1 n\u00e0o sau \u0111\u00e2y \u0111\u01b0\u1ee3c \u0111\u1ec1 c\u1eadp trong b\u00e0i l\u00e0 c\u00f3 \u1ea3nh h\u01b0\u1edfng \u0111\u1ebfn qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n \u1edf ng\u01b0\u1eddi, l\u00e0m t\u0103ng t\u1ec9 l\u1ec7 sinh con m\u1eafc h\u1ed9i ch\u1ee9ng Down khi tu\u1ed5i m\u1eb9 cao? (1-Ch\u1ebf \u0111\u1ed9 dinh d\u01b0\u1ee1ng, 2-Hormone sinh d\u1ee5c, 3-Tu\u1ed5i t\u00e1c c\u1ee7a ng\u01b0\u1eddi m\u1eb9, 4-Nhi\u1ec7t \u0111\u1ed9 m\u00f4i tr\u01b0\u1eddng)","answer":"3","level":"VD"},{"question":"Khi n\u00f3i v\u1ec1 c\u00e1c s\u1ef1 ki\u1ec7n \u1edf k\u00ec sau c\u1ee7a gi\u1ea3m ph\u00e2n, c\u00f3 bao nhi\u00eau ph\u00e1t bi\u1ec3u sau \u0111\u00e2y l\u00e0 \u0111\u00fang?\n(1) \u1ede k\u00ec sau I, c\u00e1c NST k\u00e9p trong c\u1eb7p t\u01b0\u01a1ng \u0111\u1ed3ng ph\u00e2n li v\u1ec1 hai c\u1ef1c c\u1ee7a t\u1ebf b\u00e0o.\n(2) \u1ede k\u00ec sau II, c\u00e1c chromatid ch\u1ecb em trong t\u1eebng NST k\u00e9p t\u00e1ch nhau ra\n(3) \u1ede k\u00ec sau I, s\u1ed1 l\u01b0\u1ee3ng NST c\u1ee7a t\u1ebf b\u00e0o v\u1eabn \u1edf tr\u1ea1ng th\u00e1i 2n k\u00e9p.\n(4) \u1ede k\u00ec sau II, c\u00e1c NST \u0111\u01a1n ph\u00e2n li v\u1ec1 hai c\u1ef1c c\u1ee7a t\u1ebf b\u00e0o.","answer":"3","level":"VD"},{"question":"So s\u00e1nh Gi\u1ea3m ph\u00e2n I v\u00e0 Gi\u1ea3m ph\u00e2n II:\n(1) \u1ede k\u00ec gi\u1eefa I c\u00e1c c\u1eb7p NST t\u01b0\u01a1ng \u0111\u1ed3ng x\u1ebfp th\u00e0nh 2 h\u00e0ng, \u1edf k\u00ec gi\u1eefa II c\u00e1c NST k\u00e9p x\u1ebfp th\u00e0nh 1 h\u00e0ng.\n(2) K\u00ec \u0111\u1ea7u I c\u00f3 s\u1ef1 ti\u1ebfp h\u1ee3p v\u00e0 trao \u0111\u1ed5i ch\u00e9o, k\u00ec \u0111\u1ea7u II kh\u00f4ng c\u00f3.\n(3) K\u00ec sau I c\u00f3 s\u1ef1 ph\u00e2n li c\u1ee7a NST k\u00e9p, k\u00ec sau II c\u00f3 s\u1ef1 ph\u00e2n li c\u1ee7a chromatid ch\u1ecb em.\n(4) Tr\u01b0\u1edbc Gi\u1ea3m ph\u00e2n I c\u00f3 k\u00ec trung gian nh\u00e2n \u0111\u00f4i NST, tr\u01b0\u1edbc Gi\u1ea3m ph\u00e2n II kh\u00f4ng c\u00f3 k\u00ec trung gian ho\u1eb7c k\u00ec trung gian r\u1ea5t ng\u1eafn v\u00e0 kh\u00f4ng nh\u00e2n \u0111\u00f4i NST.\nNh\u1eefng ph\u00e1t bi\u1ec3u n\u00e0o \u0111\u00fang (vi\u1ebft s\u1ed1 t\u1eeb nh\u1ecf \u2192 l\u1edbn)?","answer":"1234","level":"VD"},{"question":"C\u00e1c c\u01a1 ch\u1ebf n\u00e0o sau \u0111\u00e2y t\u1ea1o ra s\u1ef1 \u0111a d\u1ea1ng di truy\u1ec1n (bi\u1ebfn d\u1ecb t\u1ed5 h\u1ee3p) trong qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n?\n(1) S\u1ef1 nh\u00e2n \u0111\u00f4i c\u1ee7a NST \u1edf k\u00ec trung gian.\n(2) S\u1ef1 trao \u0111\u1ed5i ch\u00e9o gi\u1eefa c\u00e1c chromatid kh\u00e1c ngu\u1ed3n trong c\u1eb7p NST t\u01b0\u01a1ng \u0111\u1ed3ng \u1edf k\u00ec \u0111\u1ea7u I.\n(3) S\u1ef1 ph\u00e2n li ng\u1eabu nhi\u00ean v\u00e0 t\u1ed5 h\u1ee3p t\u1ef1 do c\u1ee7a c\u00e1c c\u1eb7p NST t\u01b0\u01a1ng \u0111\u1ed3ng \u1edf k\u00ec sau I.\n(4) S\u1ef1 ph\u00e2n li c\u1ee7a c\u00e1c chromatid ch\u1ecb em \u1edf k\u00ec sau II.\nNh\u1eefng ph\u00e1t bi\u1ec3u n\u00e0o \u0111\u00fang (vi\u1ebft s\u1ed1 t\u1eeb l\u1edbn \u2192 nh\u1ecf)?","answer":"32","level":"VD"},{"question":"\u00dd ngh\u0129a c\u1ee7a qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n l\u00e0 g\u00ec?\n(1) T\u1ea1o ra c\u00e1c giao t\u1eed c\u00f3 b\u1ed9 NST \u0111\u01a1n b\u1ed9i (n).\n(2) Kh\u00f4i ph\u1ee5c l\u1ea1i b\u1ed9 NST l\u01b0\u1ee1ng b\u1ed9i (2n) \u0111\u1eb7c tr\u01b0ng cho lo\u00e0i.\n(3) L\u00e0 c\u01a1 s\u1edf cho sinh s\u1ea3n h\u1eefu t\u00ednh, \u0111\u1ea3m b\u1ea3o duy tr\u00ec b\u1ed9 NST c\u1ee7a lo\u00e0i qua c\u00e1c th\u1ebf h\u1ec7.\n(4) T\u1ea1o ra ngu\u1ed3n bi\u1ebfn d\u1ecb t\u1ed5 h\u1ee3p phong ph\u00fa cho qu\u00e1 tr\u00ecnh ti\u1ebfn h\u00f3a v\u00e0 ch\u1ecdn gi\u1ed1ng.\nNh\u1eefng ph\u00e1t bi\u1ec3u n\u00e0o sai (vi\u1ebft s\u1ed1 t\u1eeb nh\u1ecf \u2192 l\u1edbn)?","answer":"2","level":"VD"},{"question":"Khi n\u00f3i v\u1ec1 c\u00e1c y\u1ebfu t\u1ed1 \u1ea3nh h\u01b0\u1edfng \u0111\u1ebfn gi\u1ea3m ph\u00e2n:\n(1) Ch\u1ebf \u0111\u1ed9 chi\u1ebfu s\u00e1ng th\u00edch h\u1ee3p c\u00f3 th\u1ec3 k\u00edch th\u00edch s\u1ef1 ra hoa \u1edf m\u1ed9t s\u1ed1 lo\u00e0i th\u1ef1c v\u1eadt.\n(2) Hormone sinh d\u1ee5c c\u00f3 vai tr\u00f2 quan tr\u1ecdng trong qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n v\u00e0 sinh s\u1ea3n \u1edf \u0111\u1ed9ng v\u1eadt.\n(3) Tu\u1ed5i c\u1ee7a ng\u01b0\u1eddi ph\u1ee5 n\u1eef c\u00e0ng cao th\u00ec qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n c\u00e0ng d\u1ec5 x\u1ea3y ra r\u1ed1i lo\u1ea1n.\n(4) M\u1ecdi y\u1ebfu t\u1ed1 m\u00f4i tr\u01b0\u1eddng \u0111\u1ec1u \u1ee9c ch\u1ebf qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n.\nC\u00f3 bao nhi\u00eau ph\u00e1t bi\u1ec3u \u0111\u00fang?","answer":"3","level":"VD"},{"question":"\u0110\u1eb7c \u0111i\u1ec3m n\u00e0o sau \u0111\u00e2y l\u00e0 c\u1ee7a k\u00ec cu\u1ed1i I, k\u1ebft th\u00fac qu\u00e1 tr\u00ecnh gi\u1ea3m ph\u00e2n I?\n(1) T\u1ebf b\u00e0o m\u1eb9 ph\u00e2n chia th\u00e0nh 4 t\u1ebf b\u00e0o con \u0111\u01a1n b\u1ed9i.\n(2) T\u1ea1o ra hai t\u1ebf b\u00e0o con c\u00f3 s\u1ed1 l\u01b0\u1ee3ng NST gi\u1ea3m \u0111i m\u1ed9t n\u1eeda nh\u01b0ng v\u1eabn \u1edf tr\u1ea1ng th\u00e1i k\u00e9p.\n(3) C\u00e1c chromatid ch\u1ecb em t\u00e1ch nhau ra\n(4) C\u00e1c c\u1eb7p NST t\u01b0\u01a1ng \u0111\u1ed3ng b\u1eaft \u0111\u1ea7u ti\u1ebfp h\u1ee3p.","answer":"2","level":"VD"},{"question":"So s\u00e1nh qu\u00e1 tr\u00ecnh ph\u00e1t sinh tinh v\u00e0 ph\u00e1t sinh tr\u1ee9ng \u1edf ng\u01b0\u1eddi:\n(1) C\u1ea3 hai qu\u00e1 tr\u00ecnh \u0111\u1ec1u b\u1eaft \u0111\u1ea7u t\u1eeb t\u1ebf b\u00e0o m\u1ea7m sinh d\u1ee5c l\u01b0\u1ee1ng b\u1ed9i.\n(2) Ph\u00e1t sinh tinh t\u1ea1o ra 4 tinh tr\u00f9ng, ph\u00e1t sinh tr\u1ee9ng t\u1ea1o ra 4 tr\u1ee9ng.\n(3) S\u1ef1 ph\u00e2n chia t\u1ebf b\u00e0o ch\u1ea5t trong ph\u00e1t sinh tinh l\u00e0 \u0111\u1ed3ng \u0111\u1ec1u, trong ph\u00e1t sinh tr\u1ee9ng l\u00e0 kh\u00f4ng \u0111\u1ed3ng \u0111\u1ec1u.\n(4) C\u1ea3 hai \u0111\u1ec1u l\u00e0 k\u1ebft qu\u1ea3 c\u1ee7a qu\u00e1 tr\u00ecnh nguy\u00ean ph\u00e2n.\nC\u00f3 bao nhi\u00eau ph\u00e1t bi\u1ec3u sai?","answer":"2.","level":"VD"},{"question":"Cho c\u00e1c s\u1ef1 ki\u1ec7n sau di\u1ec5n ra trong gi\u1ea3m ph\u00e2n:\n(1) C\u00e1c c\u1eb7p nhi\u1ec5m s\u1eafc th\u1ec3 t\u01b0\u01a1ng \u0111\u1ed3ng x\u1ebfp th\u00e0nh hai h\u00e0ng tr\u00ean m\u1eb7t ph\u1eb3ng x\u00edch \u0111\u1ea1o.\n(2) C\u00e1c nhi\u1ec5m s\u1eafc th\u1ec3 \u0111\u01a1n d\u00e3n xo\u1eafn, m\u00e0ng nh\u00e2n h\u00ecnh th\u00e0nh t\u1ea1o ra c\u00e1c t\u1ebf b\u00e0o con \u0111\u01a1n b\u1ed9i.\n(3) C\u00e1c c\u1eb7p nhi\u1ec5m s\u1eafc th\u1ec3 t\u01b0\u01a1ng \u0111\u1ed3ng ti\u1ebfp h\u1ee3p v\u00e0 c\u00f3 th\u1ec3 x\u1ea3y ra trao \u0111\u1ed5i ch\u00e9o.\n(4) C\u00e1c nhi\u1ec5m s\u1eafc th\u1ec3 k\u00e9p x\u1ebfp th\u00e0nh m\u1ed9t h\u00e0ng tr\u00ean m\u1eb7t ph\u1eb3ng x\u00edch \u0111\u1ea1o.\n(5) C\u00e1c nhi\u1ec5m s\u1eafc th\u1ec3 k\u00e9p trong c\u1eb7p t\u01b0\u01a1ng \u0111\u1ed3ng ph\u00e2n li v\u1ec1 hai c\u1ef1c\nTr\u00ecnh t\u1ef1 di\u1ec5n ra \u0111\u00fang c\u1ee7a c\u00e1c s\u1ef1 ki\u1ec7n tr\u00ean l\u00e0:","answer":"31542","level":"VD"},{"question":"S\u1eafp x\u1ebfp c\u00e1c s\u1ef1 ki\u1ec7n t\u1ea1o ra \u0111a d\u1ea1ng di truy\u1ec1n v\u00e0 h\u00ecnh th\u00e0nh giao t\u1eed:\n(1) S\u1ef1 ph\u00e2n li \u0111\u1ed9c l\u1eadp c\u1ee7a c\u00e1c c\u1eb7p nhi\u1ec5m s\u1eafc th\u1ec3 t\u01b0\u01a1ng \u0111\u1ed3ng.\n(2) S\u1ef1 trao \u0111\u1ed5i ch\u00e9o gi\u1eefa c\u00e1c chromatid\n(3) T\u1ebf b\u00e0o ho\u00e0n th\u00e0nh gi\u1ea3m ph\u00e2n II t\u1ea1o ra c\u00e1c t\u1ebf b\u00e0o \u0111\u01a1n b\u1ed9i.\n(4) C\u00e1c t\u1ebf b\u00e0o \u0111\u01a1n b\u1ed9i bi\u1ec7t h\u00f3a th\u00e0nh giao t\u1eed (tinh tr\u00f9ng/tr\u1ee9ng).\nTr\u00ecnh t\u1ef1 h\u1ee3p l\u00fd c\u1ee7a c\u00e1c s\u1ef1 ki\u1ec7n l\u00e0:","answer":"2134","level":"VD"},{"question":"\u1ede m\u1ed9t lo\u00e0i \u0111\u1ed9ng v\u1eadt, 12 t\u1ebf b\u00e0o sinh d\u1ee5c ch\u00edn ti\u1ebfn h\u00e0nh gi\u1ea3m ph\u00e2n \u0111\u00e3 t\u1ea1o ra bao nhi\u00eau t\u1ebf b\u00e0o con?","answer":"48","level":"VD"},{"question":"M\u1ed9t t\u1ebf b\u00e0o sinh d\u01b0\u1ee1ng b\u00ecnh th\u01b0\u1eddng \u0111ang \u1edf k\u00ec sau c\u1ee7a gi\u1ea3m ph\u00e2n II, ng\u01b0\u1eddi ta \u0111\u1ebfm \u0111\u01b0\u1ee3c 22 nhi\u1ec5m s\u1eafc th\u1ec3. B\u1ed9 nhi\u1ec5m s\u1eafc th\u1ec3 l\u01b0\u1ee1ng b\u1ed9i b\u00ecnh th\u01b0\u1eddng c\u1ee7a lo\u00e0i n\u00e0y l\u00e0","answer":"22","level":"VD"},{"question":"M\u1ed9t t\u1ebf b\u00e0o sinh d\u1ee5c s\u01a1 khai \u0111\u01b0\u1ee3c nguy\u00ean ph\u00e2n 4 l\u1ea7n. T\u1ea5t c\u1ea3 c\u00e1c t\u1ebf b\u00e0o con t\u1ea1o ra \u0111\u1ec1u tr\u1edf th\u00e0nh c\u00e1c t\u1ebf b\u00e0o sinh tinh. T\u1ed5ng s\u1ed1 tinh tr\u00f9ng \u0111\u00e3 \u0111\u01b0\u1ee3c t\u1ea1o ra l\u00e0 bao nhi\u00eau?","answer":"64","level":"VD"},{"question":"N\u1ebfu c\u00f3 24 NST k\u00e9p trong m\u1ed9t t\u1ebf b\u00e0o \u1edf k\u00ec cu\u1ed1i I c\u1ee7a gi\u1ea3m ph\u00e2n th\u00ec s\u1ed1 nhi\u1ec5m s\u1eafc th\u1ec3 l\u01b0\u1ee1ng b\u1ed9i l\u00e0","answer":"48","level":"VD"},{"question":"N\u1ebfu c\u00f3 8 NST \u0111\u01a1n trong m\u1ed9t t\u1ebf b\u00e0o \u1edf k\u00ec cu\u1ed1i II c\u1ee7a gi\u1ea3m ph\u00e2n th\u00ec b\u1ed9 NST trong t\u1ebf b\u00e0o ban \u0111\u1ea7u l\u00e0","answer":"16","level":"VD"},{"question":"\u1ede k\u00ec gi\u1eefa I, quan s\u00e1t c\u00f3 96 chromatid, K\u1ebft th\u00fac gi\u1ea3m ph\u00e2n, m\u1ed7i t\u1ebf b\u00e0o ban \u0111\u1ea7u c\u00f3 b\u1ed9 NST l\u00e0","answer":"24","level":"VD"},{"question":"N\u1ebfu c\u00f3 16 NST \u0111\u01a1n trong m\u1ed9t t\u1ebf b\u00e0o \u1edf k\u00ec sau II c\u1ee7a gi\u1ea3m ph\u00e2n th\u00ec b\u1ed9 NST trong t\u1ebf b\u00e0o ban \u0111\u1ea7u l\u00e0","answer":"16","level":"VD"}],"VDC":[]}}; | |
| let pickCounts = {"part1":{"NB":3,"TH":4,"VD":1,"VDC":0},"part2":{"NB":0,"TH":0,"VD":1,"VDC":0},"part3":{"NB":0,"TH":0,"VD":1,"VDC":0}}; | |
| let shuffleOptions = {"shuffle_q_type1":true,"shuffle_a_type1":true,"shuffle_q_type2":true,"shuffle_a_type2":true,"shuffle_q_type3":true}; | |
| (function __bmpNormalizeShuffleOptions__(){ | |
| function toBool(v){ | |
| if (v === true || v === false) return v; | |
| if (v === 1 || v === 0) return v === 1; | |
| if (typeof v === 'string'){ | |
| const s = v.trim().toLowerCase(); | |
| if (s === 'true' || s === '1') return true; | |
| if (s === 'false' || s === '0' || s === '') return false; | |
| } | |
| return !!v; | |
| } | |
| const keys = ['shuffle_q_type1','shuffle_a_type1','shuffle_q_type2','shuffle_a_type2','shuffle_q_type3']; | |
| if (!shuffleOptions || typeof shuffleOptions !== 'object') shuffleOptions = {}; | |
| keys.forEach(k=>{ | |
| if (Object.prototype.hasOwnProperty.call(shuffleOptions, k)) shuffleOptions[k] = toBool(shuffleOptions[k]); | |
| }); | |
| })(); | |
| let userAnswers = {}; | |
| let startTime, endTime, totalTime; | |
| let timerInterval; | |
| let endTimeMs = null; // mốc kết thúc (ms) để đếm ngược theo thời gian thực | |
| // TẮT banner khôi phục phiên (theo yêu cầu) | |
| window.__BMP_SHOW_RESUME_BANNER__ = false; | |
| const totalMinutes = 45; | |
| let totalTimeSeconds = totalMinutes * 60; // Tổng thời gian làm bài tính bằng giây | |
| let timeLeft = totalTimeSeconds; // Thời gian còn lại | |
| let currentQuizData = []; // Dữ liệu đề hiện tại | |
| let currentSessionId = null; // ID phiên làm bài hiện tại | |
| function _bmp_b64bytes(s){ try{ const bin = atob(s); const out = new Uint8Array(bin.length); for(let i=0;i<bin.length;i++) out[i]=bin.charCodeAt(i); return out; }catch(e){ return new Uint8Array(0);} } | |
| function _bmp_xorBytes(data, keyStr){ | |
| try{ | |
| const key = new TextEncoder().encode(String(keyStr||"")); | |
| if(!key.length) return data; | |
| const out = new Uint8Array(data.length); | |
| for(let i=0;i<data.length;i++) out[i]=data[i]^key[i%key.length]; | |
| return out; | |
| }catch(e){ return data; } | |
| } | |
| function _bmp_bytesToUtf8(bytes){ | |
| try{ return new TextDecoder("utf-8").decode(bytes); }catch(e){} | |
| try{ | |
| // fallback cũ | |
| let s=""; for(let i=0;i<bytes.length;i++) s+=String.fromCharCode(bytes[i]); | |
| return decodeURIComponent(escape(s)); | |
| }catch(e){ return ""; } | |
| } | |
| function _bmp_deobf(b64, keyStr){ | |
| const b = _bmp_b64bytes(b64); | |
| const x = _bmp_xorBytes(b, keyStr); | |
| return _bmp_bytesToUtf8(x); | |
| } | |
| function _bmp_getAppsScriptUrl(){ | |
| const k = "1769689416016" + "|" + "1769689416016" + "|BMP"; | |
| return _bmp_deobf("WUNCSUUCFhtCVUJYRggfUFlWUVRcGlJZXR5bHSE/P0IYRRZ3c19NUlRJBl05aANgFHJSSlFoVVdrGzN1BhFnTmIJB39NZklxX2cABGhFYVtianJXQGRARkU+dSgDe09mTE9+UmJbUGFFZg98UBlcTl1a", k); | |
| } | |
| function _bmp_getApiToken(){ | |
| const k = "1769689416016" + "|" + "1769689416016" + "|BMP"; | |
| return _bmp_deobf("AlYOCVIMC1YEVVQFAk8FAw8IAgwAAwcCBVAATHsoZgA=", k); | |
| } | |
| const appsScriptUrl = _bmp_getAppsScriptUrl(); | |
| window.currentQuizId = "1769689416016"; | |
| const ansSalt = "1769689416016"; | |
| const authEnabled = true; | |
| const allowedStudents = {"119b9633":1,"6ed964ab":1,"6ad87483":1,"a85d3a44":1,"98150e66":1,"c5bf2d0b":1,"264ca129":1,"1dbe990a":1,"3b0f7242":1,"56f178da":1,"9edb6586":1,"b7c375b0":1,"0d42f4a8":1,"ba0a12c6":1,"7293cb2a":1,"e63fb97a":1,"4cac9e58":1,"c839044e":1,"e6ce266a":1,"2d834d09":1,"50b4020f":1,"efc6d6c2":1,"a41148a6":1,"d93cdecc":1,"44c27a90":1,"25a06b9d":1,"e6ecbe63":1,"ecadaab3":1,"3b48ebb5":1,"b87dc879":1,"e579b7bb":1,"1d3390e2":1,"91cc9636":1,"ab41551f":1,"5a52ea45":1,"a1a51ebc":1,"c0db61ac":1,"b73b1485":1,"3d3245c3":1,"be74e0a6":1,"ff806ebe":1,"9d8b808a":1,"9d12d5fa":1,"69842106":1,"d20a4fde":1,"dda29795":1,"0d9c8b23":1,"37f31f61":1,"85d4bbbb":1,"f547ac81":1,"9c03aecb":1,"75695e46":1,"659d5836":1,"892ea5ab":1,"e20e32d9":1,"a124a043":1,"79ab09fd":1,"eee5f9ee":1,"03d23caa":1,"8627ddfd":1,"b24a23e3":1,"ea222be3":1,"0c44e7af":1,"e73fcc46":1,"80074cda":1,"690cc1bb":1,"51df65dd":1,"10e79a4f":1,"a67306e1":1,"3ae30c9e":1,"eaa07492":1,"6d813672":1,"b9cf2d78":1,"d407945d":1,"d00df4c5":1,"a8556587":1,"756ed11b":1,"a41d9839":1,"d19c8297":1,"f644cf44":1,"ddaacdd6":1,"ca83a3b4":1,"43189c40":1,"66fbf412":1,"34e0abdc":1,"33013bc4":1,"4f58d34a":1,"64acd6cc":1,"40bddb4c":1,"4114fc52":1,"5a46fa38":1,"70006c1a":1,"827679c2":1,"73b29a5d":1,"58b7716f":1,"f11183c4":1,"204baa62":1,"321caddf":1,"faa07baf":1,"4fa87719":1,"a85d12af":1,"f3f99361":1,"517767cd":1,"60b122f7":1,"69d58b53":1,"e5db4270":1,"7f9a3380":1,"36682d3b":1,"6759bb4d":1,"031bd7c7":1,"b130fa55":1,"1152b049":1,"a6965597":1,"50064161":1,"ceb32f23":1,"33349d1c":1,"7dcd3500":1,"f787c57c":1,"16a1bfa8":1,"f8d02e0e":1,"a48d38fc":1,"b87796b0":1,"4370037a":1,"c469f442":1,"99e29ff2":1,"3c5a6ac3":1,"e71629f5":1,"6b2d3ffd":1,"7afb093d":1,"85e59894":1,"7db0acde":1,"e1d1db3f":1,"0fbbbac1":1,"b596d788":1,"4a573878":1,"b956607c":1,"623ccbc8":1,"174635eb":1,"e96c38cd":1,"443a919c":1,"db95e808":1,"6b5ed22e":1,"861acbac":1,"482264f5":1,"d72f3a09":1,"0c4cccff":1,"1783429d":1,"a412e0e3":1,"879781f7":1,"006f9be1":1,"365bc295":1,"5c32261b":1,"4b2383e1":1,"2d6efef3":1,"d67f970d":1,"cf73ceac":1,"ef658ad0":1,"5436c349":1,"6be1e6eb":1,"113ce0f7":1,"c99a8c01":1,"af6ddb6f":1,"51f279b3":1,"17bed095":1,"f865ce23":1,"3aa5a5c1":1,"6d6a23e7":1,"985636dc":1,"e36b764a":1,"23957b9b":1,"b9100745":1,"cf55b3be":1,"a75af1ec":1,"ce1bdb1e":1,"f01e4aa4":1,"fb7bbed7":1,"5f39f925":1,"6c60aef8":1,"f6ae56ee":1,"c935d848":1,"be28c876":1,"0685ff03":1,"b3027069":1,"bc1dfff3":1,"fd14d5e1":1,"5de2457b":1,"394dceb9":1,"282e63d2":1,"0a4db4ea":1,"04fe634a":1,"fd6c9842":1,"b86b4176":1,"5af11354":1,"9f6b8b20":1,"ae14b25e":1,"fb7a10d0":1,"de124508":1,"6f5e1c31":1,"19b5c95b":1,"8826053c":1,"2fbb3e56":1,"f1dbb4b2":1,"9c96c16a":1,"c6da9409":1,"3cc2c15b":1,"e76db9eb":1,"aa19c6eb":1,"7d037057":1,"62f1f1a5":1,"a956ed9c":1,"0fa85028":1,"4a073247":1,"e8f443a3":1,"d4d8895d":1,"0875f5ff":1,"49cd7351":1,"44aeadfb":1,"33d31f57":1,"a95267d1":1,"2e35425c":1,"0f65aba6":1,"b7592769":1,"011063c7":1,"5dff3c20":1,"e2036710":1,"91a6cbdf":1,"fa74bac9":1,"4ee98541":1,"fa5a9a75":1,"c8c911f5":1,"0f730cb1":1,"c6c336ad":1,"a78d4e73":1,"a83f0b33":1,"cb2ae139":1,"89c93705":1,"ea6dd8c1":1,"14cd7b60":1,"a791174e":1,"278931a1":1,"774d46ed":1,"7a987f1e":1,"25522000":1,"f7d9d711":1,"d91ffc9d":1,"21430870":1,"5192598c":1,"5e270b88":1,"121c400c":1,"5649ce33":1,"bebb9939":1,"d9724cac":1,"735e512a":1,"389ead11":1,"c602f0b1":1,"16d19810":1,"da96bc40":1,"f40e9496":1,"188b5808":1,"56482baa":1,"1d3d24da":1,"fc370d02":1,"01dabf18":1,"ef6d3250":1,"e61110fa":1,"5066766f":1,"0c5854f1":1,"0297735f":1,"1269f833":1,"edde3666":1,"afd507c4":1}; | |
| const allowedStudentsExact = []; | |
| const requireExact = true; | |
| // ===== BMP PATCH (v29v16): Chuẩn hoá Unicode tên HS để chấp nhận Hòa/Hoà, thừa khoảng trắng, hoa/thường ===== | |
| function _bmp_norm_vi(s){ | |
| s = (s==null?"":String(s)); | |
| try{ if (s.normalize) s = s.normalize('NFC'); }catch(e){} | |
| // Chuẩn các kiểu gõ oà/òa (và tương tự) | |
| s = s | |
| .replace(/òa/g,"oà").replace(/óa/g,"oá").replace(/ọa/g,"oạ").replace(/ỏa/g,"oả").replace(/õa/g,"oã") | |
| .replace(/Òa/g,"Oà").replace(/Óa/g,"Oá").replace(/Ọa/g,"Oạ").replace(/Ỏa/g,"Oả").replace(/Õa/g,"Oã"); | |
| s = s.replace(/\s+/g,' ').trim(); | |
| return s.toUpperCase(); | |
| } | |
| let _allowedExactSet = null; | |
| function _buildAllowedExactSet(){ | |
| if(_allowedExactSet) return; | |
| _allowedExactSet = new Set(); | |
| try{ | |
| if(Array.isArray(allowedStudentsExact)){ | |
| for(const it of allowedStudentsExact){ | |
| if(!it) continue; | |
| const n = _bmp_norm_vi(it.name||""); | |
| const c = _bmp_norm_vi(it.class||""); | |
| if(n && c) _allowedExactSet.add(c + "|" + n); | |
| } | |
| } | |
| }catch(e){} | |
| } | |
| function allowedStudentsExactMapHas(clsKey, nameKey){ | |
| _buildAllowedExactSet(); | |
| if(!_allowedExactSet) return false; | |
| return _allowedExactSet.has(_bmp_norm_vi(clsKey) + "|" + _bmp_norm_vi(nameKey)); | |
| } | |
| // ====== Answer obfuscation decode helpers ====== | |
| function _fnv1a32(str) { | |
| var h = 2166136261 >>> 0; | |
| var imul = (Math.imul || function(a, b) { | |
| var ah = (a >>> 16) & 0xffff, al = a & 0xffff; | |
| var bh = (b >>> 16) & 0xffff, bl = b & 0xffff; | |
| return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0)) | 0; | |
| }); | |
| str = String(str || ""); | |
| for (var i = 0; i < str.length; i++) { | |
| h ^= str.charCodeAt(i); | |
| h = (imul(h, 16777619)) >>> 0; | |
| } | |
| return h >>> 0; | |
| } | |
| // ===== Student auth (class + name) ===== | |
| function _toHex8(n) { | |
| n = (Number(n) >>> 0); | |
| var s = n.toString(16); | |
| while (s.length < 8) s = "0" + s; | |
| return s; | |
| } | |
| function _stripDiacritics(s) { | |
| s = String(s || ""); | |
| // Fallback-safe Vietnamese mapping (works even if String.normalize is missing) | |
| s = s.replace(/Đ/g, "D").replace(/đ/g, "d"); | |
| s = s.replace(/[ÀÁẠẢÃÂẦẤẬẨẪĂẰẮẶẲẴ]/g, "A"); | |
| s = s.replace(/[àáạảãâầấậẩẫăằắặẳẵ]/g, "a"); | |
| s = s.replace(/[ÈÉẸẺẼÊỀẾỆỂỄ]/g, "E"); | |
| s = s.replace(/[èéẹẻẽêềếệểễ]/g, "e"); | |
| s = s.replace(/[ÌÍỊỈĨ]/g, "I"); | |
| s = s.replace(/[ìíịỉĩ]/g, "i"); | |
| s = s.replace(/[ÒÓỌỎÕÔỒỐỘỔỖƠỜỚỢỞỠ]/g, "O"); | |
| s = s.replace(/[òóọỏõôồốộổỗơờớợởỡ]/g, "o"); | |
| s = s.replace(/[ÙÚỤỦŨƯỪỨỰỬỮ]/g, "U"); | |
| s = s.replace(/[ùúụủũưừứựửữ]/g, "u"); | |
| s = s.replace(/[ỲÝỴỶỸ]/g, "Y"); | |
| s = s.replace(/[ỳýỵỷỹ]/g, "y"); | |
| // Remove remaining combining marks (if any) | |
| try { | |
| if (s.normalize) s = s.normalize("NFD"); | |
| s = s.replace(/[\u0300-\u036f]/g, ""); | |
| } catch(e) {} | |
| return s; | |
| } | |
| // ===== CSV EXPORT (CHỈ GV: Bùi Minh Phương - Lớp A) ===== | |
| function _isTeacherAccount() { | |
| const n = _stripDiacritics((document.getElementById('student-name')?.textContent || document.getElementById('fullName')?.value || '')).toLowerCase().trim(); | |
| const c = _stripDiacritics((document.getElementById('student-class')?.textContent || document.getElementById('className')?.value || '')).toLowerCase().trim(); | |
| return (n === 'bui minh phuong' && c === 'a'); | |
| } | |
| function _updateCsvButtonsVisibility() { | |
| const show = _isTeacherAccount(); | |
| const ids = ['export-csv-btn', 'export-csv-btn-mobile']; | |
| ids.forEach(function(id){ | |
| const el = document.getElementById(id); | |
| if (el) el.style.display = show ? 'inline-flex' : 'none'; | |
| }); | |
| } | |
| function _csvStoreKey() { | |
| try { | |
| const qid = (currentQuizData && (currentQuizData.quizId || currentQuizData.id)) ? String(currentQuizData.quizId || currentQuizData.id) : 'default'; | |
| return 'bmp_csv_records_' + qid; | |
| } catch (e) { | |
| return 'bmp_csv_records_default'; | |
| } | |
| } | |
| function _loadCsvRecords() { | |
| try { | |
| const raw = _lsGet(_csvStoreKey()); | |
| const arr = raw ? JSON.parse(raw) : []; | |
| return Array.isArray(arr) ? arr : []; | |
| } catch (e) { | |
| return []; | |
| } | |
| } | |
| function _saveCsvRecords(arr) { | |
| try { _lsSet(_csvStoreKey(), JSON.stringify(arr || [])); } catch(e){} | |
| } | |
| function _appendCsvRecord(results) { | |
| try { | |
| const arr = _loadCsvRecords(); | |
| const rec = { | |
| timestamp: new Date().toISOString(), | |
| quizId: String((currentQuizData && (currentQuizData.quizId || currentQuizData.id)) || ''), | |
| quizTitle: String((currentQuizData && (currentQuizData.quizTitle || currentQuizData.title)) || ''), | |
| studentName: String(document.getElementById('student-name')?.textContent || ''), | |
| className: String(document.getElementById('student-class')?.textContent || ''), | |
| score: Number(results?.score10 || 0), | |
| scoreRaw: Number(results?.totalScore || 0), | |
| score10: Number(results?.score10 || 0), | |
| totalQuestions: Number(results?.totalQuestions || Object.keys(userAnswers || {}).length || 0), | |
| totalTime: Number(totalTime || 0), | |
| startTime: startTime ? new Date(startTime).toISOString() : '', | |
| endTime: endTime ? new Date(endTime).toISOString() : '', | |
| autoSubmit: String(results?.autoSubmitReason || results?.autoSubmit || 'NO'), | |
| sessionId: String(currentSessionId || ''), | |
| screenExitCount: Number(screenExitCount || 0), | |
| totalHiddenTime: Number(totalHiddenTime || 0), | |
| screenOffCount: Number(screenOffCount || 0), | |
| totalScreenOffTime: Number(totalScreenOffTime || 0) | |
| }; | |
| arr.push(rec); | |
| // giới hạn 500 bản ghi để tránh phình localStorage | |
| if (arr.length > 500) arr.splice(0, arr.length - 500); | |
| _saveCsvRecords(arr); | |
| } catch (e) {} | |
| } | |
| function exportCSV() { | |
| if (!_isTeacherAccount()) { | |
| alert('⛔ Chức năng này chỉ dành cho tài khoản GV: "Bùi Minh Phương" - Lớp "A".'); | |
| return; | |
| } | |
| const rows = _loadCsvRecords(); | |
| if (!rows.length) { | |
| alert('Chưa có dữ liệu CSV trong máy này.'); | |
| return; | |
| } | |
| const header = [ | |
| 'timestamp','quizId','quizTitle','studentName','className', | |
| 'score','totalQuestions','totalTime','startTime','endTime','autoSubmit','sessionId', | |
| 'screenExitCount','totalHiddenTime','screenOffCount','totalScreenOffTime' | |
| ]; | |
| function esc(v){ | |
| const s = (v === null || v === undefined) ? '' : String(v); | |
| if (/[",\n\r]/.test(s)) return '"' + s.replace(/"/g,'""') + '"'; | |
| return s; | |
| } | |
| let csv = header.join(',') + '\n'; | |
| rows.forEach(function(r){ | |
| const line = header.map(function(k){ return esc(r[k]); }).join(','); | |
| csv += line + '\n'; | |
| }); | |
| const blob = new Blob([csv], {type:'text/csv;charset=utf-8;'}); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| const qid = rows[rows.length-1].quizId || 'quiz'; | |
| const d = new Date(); | |
| const y = d.getFullYear(); | |
| const m = String(d.getMonth()+1).padStart(2,'0'); | |
| const da = String(d.getDate()).padStart(2,'0'); | |
| a.href = url; | |
| a.download = 'KQ_' + qid + '_' + y + m + da + '.csv'; | |
| document.body.appendChild(a); | |
| a.click(); | |
| setTimeout(function(){ | |
| try { URL.revokeObjectURL(url); } catch(e){} | |
| try { a.remove(); } catch(e){} | |
| }, 0); | |
| } | |
| // ===== END CSV EXPORT ===== | |
| function _normAuthName(s) { | |
| s = String(s || "").trim().replace(/\s+/g, " "); | |
| s = _stripDiacritics(s); | |
| return s.toUpperCase(); | |
| } | |
| function _normAuthNameLoose(s) { | |
| // bỏ hết khoảng trắng/ký tự đặc biệt để chống lệch do nhập/Excel | |
| s = String(s || "").trim().replace(/\s+/g, " "); | |
| s = _stripDiacritics(s); | |
| s = s.replace(/[^0-9A-Za-z]+/g, ""); | |
| return s.toUpperCase(); | |
| } | |
| function _normAuthClass(s) { | |
| s = String(s || "").trim().replace(/\s+/g, ""); | |
| s = _stripDiacritics(s); | |
| return s.toUpperCase(); | |
| } | |
| function _normAuthClassLoose(s) { | |
| s = String(s || "").trim().replace(/\s+/g, ""); | |
| s = _stripDiacritics(s); | |
| s = s.replace(/[^0-9A-Za-z]+/g, ""); | |
| return s.toUpperCase(); | |
| } | |
| function _authHashStrict(name, cls) { | |
| var key = _normAuthClass(cls) + "|" + _normAuthName(name); | |
| return _toHex8(_fnv1a32(key)); | |
| } | |
| function _authHashLoose(name, cls) { | |
| var key = _normAuthClassLoose(cls) + "|" + _normAuthNameLoose(name); | |
| return _toHex8(_fnv1a32(key)); | |
| } | |
| function isStudentAllowed(name, cls) { | |
| if (!authEnabled) return true; | |
| var h1 = _authHashStrict(name, cls); | |
| if (allowedStudents && allowedStudents[h1]) return true; | |
| var h2 = _authHashLoose(name, cls); | |
| return !!(allowedStudents && allowedStudents[h2]); | |
| } | |
| function _keyByte(seed) { | |
| return ((_fnv1a32(String(seed || "") + "|" + String(ansSalt || "")) ^ 0xA5) & 255) >>> 0; | |
| } | |
| function _b64urlToBytes(b64) { | |
| b64 = String(b64 || "").replace(/-/g, "+").replace(/_/g, "/"); | |
| while (b64.length % 4) b64 += "="; | |
| var bin = ""; | |
| try { bin = atob(b64); } catch (e) { return []; } | |
| var out = []; | |
| for (var i = 0; i < bin.length; i++) out.push(bin.charCodeAt(i) & 255); | |
| return out; | |
| } | |
| function _decodeInt(code, seed) { | |
| var bytes = _b64urlToBytes(code); | |
| if (!bytes.length) return 0; | |
| var kb = _keyByte(seed); | |
| return (bytes[0] ^ kb) & 255; | |
| } | |
| function _decodeMask32(code, seed) { | |
| var bytes = _b64urlToBytes(code); | |
| var kb = _keyByte(seed); | |
| var v = 0; | |
| for (var i = 0; i < bytes.length && i < 4; i++) { | |
| v |= (((bytes[i] ^ kb) & 255) << (8 * i)); | |
| } | |
| return (v >>> 0); | |
| } | |
| function _decodeTFAnswers(code, questionSeed, n) { | |
| n = Number(n) || 0; | |
| var seed = String(questionSeed || "") + "|tf|" + String(n); | |
| var mask = _decodeMask32(code, seed); | |
| var arr = []; | |
| for (var i = 0; i < n; i++) arr.push(((mask >>> i) & 1) === 1); | |
| return arr; | |
| } | |
| function _decodeShortAnswer(code, questionSeed) { | |
| var seed = String(questionSeed || "") + "|sa"; | |
| var bytes = _b64urlToBytes(code); | |
| if (!bytes.length) return ""; | |
| var kb = _keyByte(seed); | |
| for (var i = 0; i < bytes.length; i++) bytes[i] = (bytes[i] ^ kb) & 255; | |
| try { | |
| if (window.TextDecoder) return new TextDecoder("utf-8").decode(new Uint8Array(bytes)); | |
| } catch (e) {} | |
| var s = ""; | |
| for (var j = 0; j < bytes.length; j++) s += String.fromCharCode(bytes[j]); | |
| try { return decodeURIComponent(escape(s)); } catch (e2) { return s; } | |
| } | |
| // URL Google Apps Script | |
| // Score configuration | |
| const SCORES = { | |
| type1: 0.25, | |
| type2_1: 0.1, | |
| type2_2: 0.25, | |
| type2_3: 0.5, | |
| type2_4: 1.0, | |
| type3: 0.25 | |
| }; | |
| // Biến để theo dõi trạng thái sidebar | |
| let sidebarVisible = false; | |
| // Tạo quizId duy nhất cho mỗi file HTML | |
| const quizId = "Đề kiểm tra" + "_" + "1769689416016"; | |
| // Biến cho phép xem chi tiết - QUAN TRỌNG: KIỂM TRA GIÁ TRỊ TỪ CẤU HÌNH | |
| const allow_view_detail = true; | |
| // ========== TÍNH NĂNG TỰ ĐỘNG NỘP KHI THOÁT ========== | |
| let fullscreenEnabled = false; | |
| let screenExitCount = 0; | |
| let quizInProgress = false; // chỉ theo dõi khi đang làm bài | |
| let quizSubmitted = false; // đã nộp bài (không cảnh báo/không đếm) | |
| let resultsSent = false; // chống gửi lặp | |
| let hiddenTime = null; | |
| let totalHiddenTime = 0; // Thời gian thoát màn hình (rời app/tab) | |
| let maxHiddenTime = 0; | |
| let exitEvents = []; | |
| let screenOffCount = 0; // Số lần tắt màn hình/khóa máy | |
| let totalScreenOffTime = 0; // Tổng thời gian tắt màn hình (giây) | |
| let maxScreenOffTime = 0; | |
| let screenOffEvents = []; | |
| let _bmp_lastBlurAt = 0; | |
| let _bmp_hiddenReason = null; // 'EXIT' | 'SCREEN_OFF' | |
| let isFirstVisibilityChange = true; | |
| let lastHiddenTime = null; | |
| let maxHiddenAllowed = 60; // 1 phút = 60 giây | |
| let longExitTimeout = null; | |
| // ========== FIXED TIMER FUNCTIONS ========== | |
| // ĐÃ SỬA: Timer sử dụng thời gian thực thay vì decrement biến | |
| function startTimer(keepExistingStartTime = false) { | |
| // Dọn interval cũ nếu có | |
| if (timerInterval) { | |
| try { clearInterval(timerInterval); } catch(e) {} | |
| timerInterval = null; | |
| } | |
| // Bắt đầu phiên làm bài | |
| quizInProgress = true; | |
| quizSubmitted = false; | |
| resultsSent = false; | |
| // Reset thống kê thoát màn hình cho mỗi lượt làm bài | |
| screenExitCount = 0; | |
| totalHiddenTime = 0; | |
| screenOffCount = 0; | |
| totalScreenOffTime = 0; | |
| maxScreenOffTime = 0; | |
| maxHiddenTime = 0; | |
| isFirstVisibilityChange = false; // không bỏ qua lần thoát đầu tiên | |
| // Với bài mới: set startTime mới | |
| // Với resume: giữ startTime cũ (hoặc tính theo timeLeft) | |
| const nowMs = Date.now(); | |
| if (!keepExistingStartTime || !startTime) { | |
| startTime = new Date(nowMs); | |
| // Bài mới: endTime = now + totalTime | |
| endTimeMs = nowMs + (totalTimeSeconds * 1000); | |
| } else { | |
| // Resume: ưu tiên timeLeft hiện có (đã được tính lại theo thời gian thực ở initQuiz) | |
| // Nếu timeLeft không hợp lệ thì fallback theo startTime | |
| if (typeof timeLeft === 'number' && isFinite(timeLeft) && timeLeft > 0) { | |
| endTimeMs = nowMs + (timeLeft * 1000); | |
| } else { | |
| endTimeMs = startTime.getTime() + (totalTimeSeconds * 1000); | |
| } | |
| } | |
| // Cập nhật UI ngay lập tức (để không bị đứng "1 nhịp") | |
| updateTimer(); | |
| // Chỉ update UI mỗi giây | |
| timerInterval = setInterval(updateTimer, 1000); | |
| } | |
| // Đếm ngược theo thời gian thực (dựa trên mốc endTimeMs) | |
| function updateTimer() { | |
| if (!endTimeMs) return; | |
| const diffMs = endTimeMs - Date.now(); | |
| timeLeft = Math.max(0, Math.ceil(diffMs / 1000)); | |
| if (timeLeft <= 0) { | |
| try { clearInterval(timerInterval); } catch(e) {} | |
| timerInterval = null; | |
| timeLeft = 0; | |
| // Hiển thị 00:00 trước khi autosubmit | |
| document.getElementById('timer').textContent = `Còn lại: 0:00`; | |
| autoSubmit(); | |
| return; | |
| } | |
| const minutes = Math.floor(timeLeft / 60); | |
| const seconds = timeLeft % 60; | |
| document.getElementById('timer').textContent = `Còn lại: ${minutes}:${seconds.toString().padStart(2, '0')}`; | |
| // Lưu session mỗi 30 giây | |
| const elapsedSeconds = Math.floor((Date.now() - startTime.getTime()) / 1000); | |
| if (elapsedSeconds > 0 && elapsedSeconds % 30 === 0) { | |
| saveCurrentSession(); | |
| } | |
| } | |
| // ========== SECURITY & ANTI-CHEAT FUNCTIONS ========== | |
| // Fullscreen functions | |
| function toggleFullscreen() { | |
| if (!fullscreenEnabled) { | |
| enterFullscreen(); | |
| } else { | |
| exitFullscreen(); | |
| } | |
| } | |
| function enterFullscreen() { | |
| const elem = document.documentElement; | |
| if (elem.requestFullscreen) { | |
| elem.requestFullscreen(); | |
| } else if (elem.webkitRequestFullscreen) { | |
| elem.webkitRequestFullscreen(); | |
| } else if (elem.msRequestFullscreen) { | |
| elem.msRequestFullscreen(); | |
| } | |
| fullscreenEnabled = true; | |
| document.getElementById('fullscreen-btn').textContent = '📱 Thoát Fullscreen'; | |
| document.body.classList.add('quiz-active'); | |
| } | |
| function exitFullscreen() { | |
| if (document.exitFullscreen) { | |
| document.exitFullscreen(); | |
| } else if (document.webkitExitFullscreen) { | |
| document.webkitExitFullscreen(); | |
| } else if (document.msExitFullscreen) { | |
| document.msExitFullscreen(); | |
| } | |
| fullscreenEnabled = false; | |
| document.getElementById('fullscreen-btn').textContent = '📱 Fullscreen'; | |
| document.body.classList.remove('quiz-active'); | |
| } | |
| // Fullscreen change detection | |
| document.addEventListener('fullscreenchange', handleFullscreenChange); | |
| document.addEventListener('webkitfullscreenchange', handleFullscreenChange); | |
| document.addEventListener('msfullscreenchange', handleFullscreenChange); | |
| function handleFullscreenChange() { | |
| fullscreenEnabled = !!(document.fullscreenElement || | |
| document.webkitFullscreenElement || | |
| document.msFullscreenElement); | |
| if (fullscreenEnabled) { | |
| document.getElementById('fullscreen-btn').textContent = '📱 Thoát Fullscreen'; | |
| document.body.classList.add('quiz-active'); | |
| } else { | |
| document.getElementById('fullscreen-btn').textContent = '📱 Fullscreen'; | |
| document.body.classList.remove('quiz-active'); | |
| } | |
| } | |
| // Screen exit detection - CẢI THIỆN: Theo dõi thoát quá lâu | |
| // Phân biệt: rời màn hình (blur/switch app/tab) vs tắt màn hình/khóa máy. | |
| window.addEventListener('blur', function(){ | |
| if (!quizInProgress || quizSubmitted || !startTime || _isLoginOrDetailScreen()) return; | |
| _bmp_lastBlurAt = Date.now(); | |
| }); | |
| document.addEventListener('visibilitychange', function() { | |
| // Chỉ theo dõi & cảnh báo khi ĐANG làm bài (màn hình câu hỏi), ĐÃ BẮT ĐẦU và CHƯA nộp | |
| if (!quizInProgress || quizSubmitted || !startTime || _isLoginOrDetailScreen()) return; | |
| if (document.hidden) { | |
| // Người dùng rời màn hình (có thể là chuyển app/tab hoặc tắt màn hình/khóa máy) | |
| lastHiddenTime = new Date(); | |
| if (startTime) { | |
| hiddenTime = new Date(); | |
| } | |
| // Heuristic: | |
| // - Nếu trước đó vừa có blur => coi là "thoát màn hình" (chuyển app/tab) | |
| // - Nếu không có blur gần đây => coi là "màn hình tắt/khóa" | |
| const nowMs = Date.now(); | |
| const dt = nowMs - (_bmp_lastBlurAt || 0); | |
| _bmp_hiddenReason = (dt >= 0 && dt <= 350) ? 'EXIT' : 'SCREEN_OFF'; | |
| } else { | |
| // Người dùng quay lại | |
| if (lastHiddenTime && startTime) { | |
| const now = new Date(); | |
| const hiddenDuration = Math.floor((now - lastHiddenTime) / 1000); | |
| // Kiểm tra nếu rời màn hình/tắt màn hình quá lâu (> maxHiddenAllowed giây) | |
| // Áp dụng cho cả 2 trường hợp EXIT và SCREEN_OFF | |
| if (hiddenDuration > maxHiddenAllowed) { | |
| autoSubmitDueToLongExit(); | |
| return; | |
| } | |
| if (hiddenTime) { | |
| const hiddenSeconds = Math.floor((now - hiddenTime) / 1000); | |
| // Log sự kiện | |
| try { | |
| if (_bmp_hiddenReason === 'SCREEN_OFF') { | |
| maxScreenOffTime = Math.max(maxScreenOffTime, hiddenSeconds); | |
| screenOffEvents.push({ start: (lastHiddenTime ? lastHiddenTime.toISOString() : ""), end: now.toISOString(), seconds: hiddenSeconds }); | |
| } else { | |
| maxHiddenTime = Math.max(maxHiddenTime, hiddenSeconds); | |
| exitEvents.push({ start: (lastHiddenTime ? lastHiddenTime.toISOString() : ""), end: now.toISOString(), seconds: hiddenSeconds }); | |
| } | |
| } catch (e) {} | |
| if (hiddenSeconds >= 1) { | |
| // Lưu thời điểm thoát để cảnh báo chính xác | |
| try { | |
| window._lastExitStartISO = (lastHiddenTime ? lastHiddenTime.toISOString() : ""); | |
| window._lastExitEndISO = now.toISOString(); | |
| } catch (e) {} | |
| if (_bmp_hiddenReason === 'SCREEN_OFF') { | |
| screenOffCount++; | |
| totalScreenOffTime += hiddenSeconds; | |
| _lsSet('screen_off_count', screenOffCount); | |
| // (tuỳ chọn) hiện cảnh báo giống "thoát màn hình" | |
| if (hiddenSeconds > 60) showLongExitWarning(hiddenSeconds); | |
| else showExitWarning(hiddenSeconds); | |
| } else { | |
| screenExitCount++; | |
| totalHiddenTime += hiddenSeconds; | |
| _lsSet('screen_exit_count', screenExitCount); | |
| if (hiddenSeconds > 60) showLongExitWarning(hiddenSeconds); | |
| else showExitWarning(hiddenSeconds); | |
| } | |
| } | |
| } | |
| } | |
| hiddenTime = null; | |
| lastHiddenTime = null; | |
| isFirstVisibilityChange = false; | |
| _bmp_hiddenReason = null; | |
| } | |
| }); | |
| // Hiển thị cảnh báo rời màn hình | |
| function showExitWarning(duration) { | |
| document.getElementById('exit-count-display').textContent = screenExitCount; | |
| var st = window._lastExitStartISO ? fmtDateTime(window._lastExitStartISO) : ''; | |
| var en = window._lastExitEndISO ? fmtDateTime(window._lastExitEndISO) : ''; | |
| document.getElementById('exit-time-display').textContent = (st && en) ? (st + ' → ' + en + ' (' + duration + 's)') : (duration + 's'); | |
| document.getElementById('exit-warning').classList.add('active'); | |
| // Tự động đóng sau 8 giây | |
| setTimeout(() => { | |
| closeExitWarning(); | |
| }, 8000); | |
| } | |
| function closeExitWarning() { | |
| document.getElementById('exit-warning').classList.remove('active'); | |
| } | |
| // Hiển thị cảnh báo thoát quá lâu | |
| function showLongExitWarning(duration) { | |
| const minutes = Math.floor(duration / 60); | |
| const seconds = duration % 60; | |
| // Cập nhật thông tin | |
| document.getElementById('exit-count-display').textContent = screenExitCount; | |
| var st = window._lastExitStartISO ? fmtDateTime(window._lastExitStartISO) : ''; | |
| var en = window._lastExitEndISO ? fmtDateTime(window._lastExitEndISO) : ''; | |
| var dur = `${minutes} phút ${seconds} giây`; | |
| document.getElementById('exit-time-display').textContent = (st && en) ? (st + ' → ' + en + ' (' + dur + ')') : dur; | |
| // Hiển thị cảnh báo nghiêm trọng nếu > 4 phút | |
| if (duration > 240) { // 4 phút | |
| document.getElementById('long-exit-warning').classList.add('active'); | |
| // Bắt đầu đếm ngược | |
| let countdown = 5; | |
| document.getElementById('countdown').textContent = countdown; | |
| longExitTimeout = setInterval(() => { | |
| countdown--; | |
| document.getElementById('countdown').textContent = countdown; | |
| if (countdown <= 0) { | |
| clearInterval(longExitTimeout); | |
| autoSubmitDueToLongExit(); | |
| } | |
| }, 1000); | |
| } else { | |
| // Hiển thị cảnh báo thông thường | |
| showExitWarning(duration); | |
| } | |
| } | |
| function closeLongExitWarning() { | |
| const warningDiv = document.getElementById('long-exit-warning'); | |
| warningDiv.classList.remove('active'); | |
| if (longExitTimeout) { | |
| clearInterval(longExitTimeout); | |
| longExitTimeout = null; | |
| } | |
| // Reset thời gian thoát | |
| lastHiddenTime = null; | |
| } | |
| // Hàm tự động nộp do thoát quá lâu | |
| function autoSubmitDueToLongExit() { | |
| // Không tự gửi/nộp khi đang ở màn hình đăng nhập hoặc xem chi tiết | |
| if (!quizInProgress || quizSubmitted) return; | |
| if (_isLoginOrDetailScreen()) return; | |
| clearInterval(timerInterval); | |
| endTime = new Date(); | |
| totalTime = Math.floor((endTime - startTime) / 1000); // Tính thời gian thực tế | |
| calculateResults(); | |
| const results = window.quizResults; | |
| // Thêm thông tin tự động nộp | |
| results.autoSubmitReason = "THOÁT QUÁ LÂU"; | |
| results.hiddenDuration = Math.floor((endTime - lastHiddenTime) / 1000); | |
| saveQuizHistory(results); | |
| // Gửi lên Google Sheets - ĐÃ SỬA: Thêm retry mechanism | |
| resultsSent = true; | |
| sendResultsToGoogleSheet(results).then(success => { | |
| if (!success) { | |
| console.warn("Không thể gửi kết quả lên Google Sheets, nhưng đã lưu cục bộ"); | |
| } | |
| }); | |
| // QUAN TRỌNG: Reset hoàn toàn trạng thái bài thi | |
| resetQuizState(); | |
| clearCurrentSession(); | |
| // Hiển thị thông báo | |
| showAutoSubmitModal(); | |
| } | |
| // Hàm reset trạng thái bài thi - MỚI THÊM | |
| function resetQuizState() { | |
| userAnswers = {}; | |
| startTime = null; | |
| endTime = null; | |
| totalTime = 0; | |
| timeLeft = totalTimeSeconds; | |
| currentQuizData = []; | |
| currentSessionId = null; | |
| screenExitCount = 0; | |
| totalHiddenTime = 0; | |
| lastHiddenTime = null; | |
| hiddenTime = null; | |
| isFirstVisibilityChange = true; | |
| // Reset giao diện | |
| document.getElementById('quiz-section').style.display = 'none'; | |
| document.getElementById('user-info-form').style.display = 'block'; | |
| try{ loadLoginRanking(); }catch(e){} | |
| document.getElementById('fullName').value = ''; | |
| document.getElementById('className').value = ''; | |
| // Clear timer | |
| if (timerInterval) { | |
| clearInterval(timerInterval); | |
| timerInterval = null; | |
| } | |
| // Exit fullscreen | |
| if (fullscreenEnabled) { | |
| exitFullscreen(); | |
| } | |
| } | |
| // Modal tự động nộp bài | |
| function showAutoSubmitModal() { | |
| const results = window.quizResults; | |
| const hiddenDuration = results.hiddenDuration || 0; | |
| const minutes = Math.floor(hiddenDuration / 60); | |
| const seconds = hiddenDuration % 60; | |
| document.getElementById('success-content').innerHTML = ` | |
| <h3>⏰ BÀI THI ĐÃ TỰ ĐỘNG NỘP!</h3> | |
| <div class="total-score" id="final-score" style="font-size: 2.5rem; margin: 20px 0;">${results.totalScore} điểm</div> | |
| <p><strong>Lý do:</strong> Bạn đã rời màn hình quá lâu!</p> | |
| <p><strong>Thời gian rời:</strong> ${minutes} phút ${seconds} giây</p> | |
| <p><strong>Số lần rời màn hình:</strong> ${screenExitCount} lần</p> | |
| <p>Kết quả của bạn đã được ghi nhận.</p> | |
| <p>Ấn OK để xem chi tiết bài làm.</p> | |
| `; | |
| document.getElementById('success-modal').style.display = 'flex'; | |
| } | |
| // Cảnh báo khi người dùng cố tình chụp màn hình | |
| document.addEventListener('keyup', function(e) { | |
| if (e.key === 'PrintScreen' || (e.ctrlKey && e.key === 's')) { | |
| showScreenshotWarning(); | |
| } | |
| }); | |
| // Cảnh báo chụp màn hình | |
| function showScreenshotWarning() { | |
| document.body.classList.add('screenshot-detected'); | |
| setTimeout(() => { | |
| document.body.classList.remove('screenshot-detected'); | |
| }, 1000); | |
| // Ghi log | |
| const screenshotLogs = JSON.parse(_lsGet('screenshot_logs') || '[]'); | |
| screenshotLogs.push(new Date().toISOString()); | |
| _lsSet('screenshot_logs', JSON.stringify(screenshotLogs)); | |
| } | |
| // Chống copy text | |
| document.addEventListener('copy', function(e) { | |
| if (!document.body.classList.contains('allow-copy')) { | |
| e.preventDefault(); | |
| alert('⚠️ Tính năng copy đã bị vô hiệu hóa trong bài thi!'); | |
| return false; | |
| } | |
| }); | |
| document.addEventListener('cut', function(e) { | |
| if (!document.body.classList.contains('allow-copy')) { | |
| e.preventDefault(); | |
| return false; | |
| } | |
| }); | |
| document.addEventListener('paste', function(e) { | |
| if (!document.body.classList.contains('allow-paste')) { | |
| e.preventDefault(); | |
| alert('⚠️ Tính năng paste đã bị vô hiệu hóa trong bài thi!'); | |
| return false; | |
| } | |
| }); | |
| // Chống chuột phải | |
| document.addEventListener('contextmenu', function(e) { | |
| if (!document.body.classList.contains('allow-context-menu')) { | |
| e.preventDefault(); | |
| return false; | |
| } | |
| }); | |
| // Prevent drag and drop | |
| document.addEventListener('dragstart', function(e) { | |
| if (!document.body.classList.contains('allow-drag')) { | |
| e.preventDefault(); | |
| return false; | |
| } | |
| }); | |
| // Close security modal | |
| function closeSecurityModal() { | |
| document.getElementById('security-modal').style.display = 'none'; | |
| } | |
| // ========== END SECURITY FUNCTIONS ========== | |
| // Hàm định dạng nội dung câu hỏi | |
| function formatQuestionContent(content) { | |
| if (!content) return ''; | |
| let formatted = content; | |
| // Pattern 1: \( ... \) -> convert to $...$ to avoid backslash escaping issues in JSON/JS strings | |
| formatted = formatted.replace(/\\\(([^]*?)\\\)/g, function(match, formula) { | |
| return `<span class="math-container">$${formula}$</span>`; | |
| }); | |
| // Pattern 2: $ ... $ -> keep $...$ (MathJax is configured to process $ $) | |
| // IMPORTANT: Do NOT convert to \( \) here; that can end up as stray parentheses when strings are escaped. | |
| formatted = formatted.replace(/\$([^]*?)\$/g, function(match, formula) { | |
| return `<span class="math-container">$${formula}$</span>`; | |
| }); | |
| // Xử lý xuống dòng | |
| formatted = formatted.replace(/\n/g, '<br>'); | |
| // Xoá dòng trắng thừa (tránh khoảng trắng giữa lời dẫn và phương án) | |
| formatted = formatted.replace(/(<br>\s*){2,}/g, '<br>'); | |
| // Xử lý bảng | |
| const lines = formatted.split('<br>'); | |
| let newFormatted = []; | |
| let inTable = false; | |
| let tableRows = []; | |
| for (let i = 0; i < lines.length; i++) { | |
| let line = lines[i]; | |
| // Bắt đầu bảng | |
| if (line.trim().startsWith('Bảng:') && !inTable) { | |
| inTable = true; | |
| tableRows = []; | |
| continue; | |
| } | |
| // Đang trong bảng và dòng có dấu | | |
| if (inTable && line.includes('|')) { | |
| tableRows.push(line); | |
| continue; | |
| } | |
| // Kết thúc bảng | |
| if (inTable && !line.includes('|')) { | |
| if (tableRows.length > 0) { | |
| let tableHTML = '<div class="table-container"><table>'; | |
| for (let row of tableRows) { | |
| let columns = row.split('|').map(col => col.trim()); | |
| tableHTML += '<tr>'; | |
| for (let cell of columns) { | |
| tableHTML += `<td>${cell}</td>`; | |
| } | |
| tableHTML += '</tr>'; | |
| } | |
| tableHTML += '</table></div>'; | |
| newFormatted.push(tableHTML); | |
| } | |
| inTable = false; | |
| tableRows = []; | |
| } | |
| // Dòng bình thường | |
| if (!inTable && line.trim() !== '') { | |
| newFormatted.push(line); | |
| } | |
| } | |
| // Xử lý bảng ở cuối | |
| if (inTable && tableRows.length > 0) { | |
| let tableHTML = '<div class="table-container"><table>'; | |
| for (let row of tableRows) { | |
| let columns = row.split('|').map(col => col.trim()); | |
| tableHTML += '<tr>'; | |
| for (let cell of columns) { | |
| tableHTML += `<td>${cell}</td>`; | |
| } | |
| tableHTML += '</tr>'; | |
| } | |
| tableHTML += '</table></div>'; | |
| newFormatted.push(tableHTML); | |
| } | |
| return newFormatted.join('<br>'); | |
| } | |
| // Hàm refresh MathJax | |
| function refreshMathJax() { | |
| if (window.MathJax) { | |
| MathJax.typesetClear(); | |
| MathJax.typesetPromise().catch(function(err) { | |
| console.log('MathJax typeset error:', err); | |
| setTimeout(refreshMathJax, 500); | |
| }); | |
| } | |
| } | |
| // Lưu trữ lịch sử | |
| function getStudentKey() { | |
| return `quiz_history_${quizId}`; | |
| } | |
| // Lưu phiên làm bài hiện tại | |
| function getCurrentSessionKey() { | |
| const fullName = document.getElementById('fullName').value.trim() || | |
| document.getElementById('student-name').textContent || | |
| 'Unknown'; | |
| const className = document.getElementById('className').value.trim() || | |
| document.getElementById('student-class').textContent || | |
| 'Unknown'; | |
| return `quiz_session_${quizId}_${fullName}_${className}`; | |
| } | |
| /** Remove leading a) b) c) d) or (a) etc from True/False statements for display */ | |
| function cleanTFStmt(stmt) { | |
| if (stmt === null || stmt === undefined) return ''; | |
| let s = String(stmt); | |
| // Remove leading markers like "a) ", "A. ", "(b) ", "[c] ", "d:" ... | |
| s = s.replace(/^\s*[\(\[\{]?\s*[a-dA-D]\s*[\)\]\}\.\:\-]\s*/,''); | |
| s = s.replace(/^\s*[a-dA-D]\s*[\)\.\:\-]\s*/,''); | |
| return s; | |
| } | |
| function saveQuizHistory(result) { | |
| const key = getStudentKey(); | |
| const history = loadQuizHistory(); | |
| // Tạo bản ghi hoàn toàn mới với tất cả dữ liệu | |
| const newRecord = { | |
| sessionId: currentSessionId, | |
| timestamp: new Date().toISOString(), | |
| startTime: startTime ? new Date(startTime).toISOString() : null, | |
| endTime: endTime ? new Date(endTime).toISOString() : null, | |
| totalTime: totalTime, | |
| score: result.totalScore, | |
| studentName: document.getElementById('student-name').textContent, | |
| className: document.getElementById('student-class').textContent, | |
| quizData: JSON.parse(JSON.stringify(currentQuizData)), // Deep copy | |
| userAnswers: JSON.parse(JSON.stringify(userAnswers)), // Deep copy | |
| autoSubmit: result.autoSubmitReason || false, | |
| hiddenDuration: result.hiddenDuration || 0, | |
| securityInfo: { | |
| screenExitCount: screenExitCount, | |
| totalHiddenTime: totalHiddenTime, | |
| screenOffCount: screenOffCount, | |
| totalScreenOffTime: totalScreenOffTime, | |
| screenOffCount: screenOffCount, | |
| totalScreenOffTime: totalScreenOffTime, | |
| maxHiddenTime: maxHiddenTime, | |
| exitEvents: exitEvents, | |
| screenshotLogs: JSON.parse(_lsGet('screenshot_logs') || '[]') | |
| } | |
| }; | |
| // (FIX) Không lưu trùng 2 lần cùng 1 bài (theo sessionId) | |
| const existingIndex = history.findIndex(r => r && r.sessionId === newRecord.sessionId); | |
| if (existingIndex >= 0) { | |
| history[existingIndex] = newRecord; | |
| } else { | |
| history.push(newRecord); | |
| } | |
| // Giữ tối đa 10 bản ghi (tăng từ 5 lên 10) | |
| if (history.length > 10) { | |
| const truncated = history.slice(history.length - 10); | |
| _lsSet(key, JSON.stringify(truncated)); | |
| } else { | |
| _lsSet(key, JSON.stringify(history)); | |
| } | |
| // (FIX) Không reset thống kê thoát màn hình ở đây. | |
| // Thống kê sẽ chỉ reset khi bắt đầu lượt làm bài mới (startTimer). | |
| } | |
| function loadQuizHistory() { | |
| const key = getStudentKey(); | |
| const history = _lsGet(key); | |
| return history ? JSON.parse(history) : []; | |
| } | |
| function clearCurrentSession() { | |
| const key = getCurrentSessionKey(); | |
| _lsRemove(key); | |
| } | |
| function saveCurrentSession() { | |
| const key = getCurrentSessionKey(); | |
| const sessionData = { | |
| sessionId: currentSessionId, | |
| startTime: startTime, | |
| timeLeft: timeLeft, | |
| userAnswers: userAnswers, | |
| currentQuizData: currentQuizData, | |
| studentName: document.getElementById('student-name').textContent, | |
| className: document.getElementById('student-class').textContent, | |
| sidebarVisible: sidebarVisible, | |
| screenExitCount: screenExitCount, | |
| totalHiddenTime: totalHiddenTime, | |
| lastSave: new Date().toISOString() | |
| }; | |
| _lsSet(key, JSON.stringify(sessionData)); | |
| } | |
| function loadCurrentSession() { | |
| const key = getCurrentSessionKey(); | |
| const session = _lsGet(key); | |
| return session ? JSON.parse(session) : null; | |
| } | |
| // Hiển thị thông báo | |
| function showNotification(message, isError = false) { | |
| const notification = document.getElementById('apps-script-notification'); | |
| const messageEl = document.getElementById('notification-message'); | |
| messageEl.textContent = message; | |
| notification.style.display = 'block'; | |
| if (isError) { | |
| notification.classList.add('error'); | |
| } else { | |
| notification.classList.remove('error'); | |
| } | |
| setTimeout(() => { | |
| notification.style.display = 'none'; | |
| }, 5000); | |
| } | |
| // ========== GOOGLE SHEETS SYNC (Blogger-safe) ========== | |
| // Lưu hàng đợi các bài chưa gửi được (mạng yếu / bị chặn / đóng tab) | |
| const PENDING_SHEET_QUEUE_KEY = "BMP_SmartQuiz_pendingSheetQueue_v1"; | |
| function _isValidAppsScriptUrl(url) { | |
| if (!url || typeof url !== "string") return false; | |
| const u = url.trim(); | |
| // Web app URL phải dạng: https://script.google.com/macros/s/<DEPLOYMENT_ID>/exec | |
| return /^https:\/\/script\.google\.com\/macros\/s\/[-\w]+\/exec(\?.*)?$/i.test(u); | |
| } | |
| function _getPendingQueue() { | |
| try { | |
| return JSON.parse(_lsGet(PENDING_SHEET_QUEUE_KEY) || "[]"); | |
| } catch (e) { | |
| return []; | |
| } | |
| } | |
| function _setPendingQueue(arr) { | |
| try { | |
| _lsSet(PENDING_SHEET_QUEUE_KEY, JSON.stringify(arr || [])); | |
| } catch (e) {} | |
| } | |
| function _enqueuePending(payload) { | |
| const q = _getPendingQueue(); | |
| // Tránh trùng session | |
| if (!q.some(x => x && x.sessionId && x.sessionId === payload.sessionId)) { | |
| q.push(payload); | |
| _setPendingQueue(q); | |
| } | |
| } | |
| // Gửi payload lên Apps Script theo cách "simple request" để hạn chế lỗi CORS/preflight | |
| function _sleep(ms) { | |
| return new Promise(function(resolve){ setTimeout(resolve, ms); }); | |
| } | |
| function _bmp_buildSubmitUrl(){ | |
| try{ | |
| var url = String(appsScriptUrl || "").trim(); | |
| if(!url) return url; | |
| var sep = (url.indexOf('?')>=0 ? '&' : '?'); | |
| url = url + sep + "mode=submit"; | |
| // token kèm query để Apps Script có thể kiểm tra ngay cả khi body bị chặn/CORS | |
| var tok = ""; | |
| try { tok = (typeof _bmp_getApiToken === 'function') ? _bmp_getApiToken() : ""; } catch(e) {} | |
| if (tok) url += "&token=" + encodeURIComponent(tok); | |
| return url; | |
| }catch(e){ return String(appsScriptUrl || "").trim(); } | |
| } | |
| var _BMP_SUBMIT_URL = null; | |
| function _getSubmitUrl(){ | |
| if (_BMP_SUBMIT_URL !== null) return _BMP_SUBMIT_URL; | |
| _BMP_SUBMIT_URL = _bmp_buildSubmitUrl(); | |
| return _BMP_SUBMIT_URL; | |
| } | |
| function _postToAppsScript(payload) { | |
| var body = JSON.stringify(payload); | |
| var submitUrl = _getSubmitUrl(); | |
| // 1) Ưu tiên sendBeacon (ổn định khi nộp bài/đóng tab trên mobile) | |
| try { | |
| if (navigator.sendBeacon) { | |
| var blob = new Blob([body], { type: "text/plain;charset=utf-8" }); | |
| var ok = navigator.sendBeacon(submitUrl, blob); | |
| if (ok) return Promise.resolve(true); // đã xếp hàng gửi | |
| } | |
| } catch (e) {} | |
| // 2) Fallback fetch (keepalive giúp gửi nốt khi tab sắp đóng) | |
| try { | |
| return fetch(submitUrl, { | |
| method: "POST", | |
| mode: "no-cors", | |
| keepalive: true, | |
| headers: { "Content-Type": "text/plain;charset=utf-8" }, | |
| body: body | |
| }).then(function() { | |
| return true; | |
| }).catch(function() { | |
| return false; | |
| }); | |
| } catch (e) { | |
| return Promise.resolve(false); | |
| } | |
| } | |
| function _resendPendingQueue() { | |
| if (!_isValidAppsScriptUrl(appsScriptUrl)) return; | |
| var queue = _getPendingQueue(); | |
| if (!queue.length) return; | |
| var remain = []; | |
| var i = 0; | |
| function step() { | |
| if (i >= queue.length) { | |
| _setPendingQueue(remain); | |
| if (remain.length === 0) { | |
| showNotification("✅ Đã gửi lại các bài còn tồn (nếu có)."); | |
| } else { | |
| console.warn("Còn bài chưa gửi được:", remain.length); | |
| } | |
| return; | |
| } | |
| var payload = queue[i]; | |
| i += 1; | |
| return _postToAppsScript(payload).then(function(ok) { | |
| if (!ok) remain.push(payload); | |
| // giãn nhẹ để tránh spam | |
| return _sleep(250).then(step); | |
| }); | |
| } | |
| return step(); | |
| } | |
| // Thử gửi lại queue ngay khi trang tải xong | |
| window.addEventListener("load", () => { | |
| _resendPendingQueue(); | |
| }); | |
| // Gửi kết quả đến Google Apps Script - FIX TRIỆT ĐỂ cho Blogspot | |
| // ===== Build question-level stats (đúng/sai/bỏ trống) để gửi lên Google Sheets ===== | |
| function buildQuestionStats(results){ | |
| try{ | |
| var qStats = []; | |
| var ua = (results && results.userAnswers) ? results.userAnswers : {}; | |
| var qd = (results && results.quizData) ? results.quizData : []; | |
| for(var i=0;i<qd.length;i++){ | |
| var q = qd[i] || {}; | |
| var qNum = (q.q_num || (i+1)); | |
| var ans = ua[qNum] || {}; | |
| var type = ans.type || (q.type === "type1" ? 1 : q.type === "type2" ? 2 : 3); | |
| var isBlank = false; | |
| var isCorrect = !!ans.correct; | |
| if(type === 1){ | |
| isBlank = (ans.answer === null || ans.answer === undefined); | |
| }else if(type === 2){ | |
| var arr = ans.answers || []; | |
| isBlank = !arr || !arr.some(function(x){ return x!==null && x!==undefined; }); | |
| }else{ | |
| var s = (ans.answer || "").toString().trim(); | |
| isBlank = (s === ""); | |
| } | |
| qStats.push({ | |
| qNum: qNum, | |
| part: q.part || "", | |
| level: q.level || "", | |
| type: type, | |
| blank: isBlank ? 1 : 0, | |
| correct: isCorrect ? 1 : 0, | |
| score: (ans.score !== undefined && ans.score !== null) ? ans.score : 0 | |
| }); | |
| } | |
| return qStats; | |
| }catch(e){ | |
| return []; | |
| } | |
| } | |
| function sendResultsToGoogleSheet(results, retryCount) { | |
| if (retryCount === undefined) retryCount = 0; | |
| var maxRetries = 2; | |
| // Validate URL | |
| if (!_isValidAppsScriptUrl(appsScriptUrl)) { | |
| console.log("Apps Script URL chưa đúng:", appsScriptUrl); | |
| showNotification("❌ Chưa cấu hình đúng URL Google Apps Script (phải là link /exec).", true); | |
| return Promise.resolve(false); | |
| } | |
| // ====== ANTI-SPAM: KHÔNG gửi kết quả nếu học sinh CHƯA thực sự bắt đầu làm bài ====== | |
| // Điều kiện bắt đầu hợp lệ: đã có startTime và có dữ liệu câu hỏi | |
| const _startedOk = !!(startTime && currentQuizData && currentQuizData.length > 0); | |
| if (!_startedOk) { | |
| console.warn("Bỏ qua gửi kết quả: chưa bắt đầu làm bài (đang ở màn hình đăng nhập hoặc session rác)."); | |
| return Promise.resolve(false); | |
| } | |
| // ====== CLIENT DEDUPE: tránh gửi trùng 1 phiên (submit/xuất kết quả) ====== | |
| // Khóa theo: quizId + studentKey + sessionId | |
| var __sentKey = null; | |
| try { | |
| __sentKey = "BMP_SENT_" + String("1769689416016") + "_" + String(getStudentKey()) + "_" + String(currentSessionId || ""); | |
| if (__sentKey && localStorage.getItem(__sentKey) === "1") { | |
| console.warn("Bỏ qua gửi: phiên này đã gửi trước đó:", __sentKey); | |
| return Promise.resolve(true); | |
| } | |
| } catch(e) {} | |
| // ====== STRICT ANTI-SPAM (chặt): chặn nộp "rỗng" siêu nhanh ====== | |
| // Không ghi nhận nếu: | |
| // - thời gian làm < 15s | |
| // - không chọn đáp án nào | |
| // - không có thoát màn hình | |
| // - không phải autoSubmit do hết giờ / thoát quá lâu | |
| const _elapsedSec = Number(results && results.totalTime ? results.totalTime : 0) || 0; | |
| const _answered = Number(results && (results.answeredCount ?? results.totalAnswered ?? results.totalAnsweredCount) ? (results.answeredCount ?? results.totalAnswered ?? results.totalAnsweredCount) : 0) || 0; | |
| const _exitC = Number(screenExitCount || 0) || 0; | |
| const _hiddenS = Number(totalHiddenTime || 0) || 0; | |
| const _auto = String((results && results.autoSubmitReason) ? results.autoSubmitReason : "NO").toUpperCase(); | |
| if (_auto === "NO" && _elapsedSec < 15 && _answered <= 0 && _exitC <= 0 && _hiddenS <= 0 && Number(results.totalScore||0) <= 0) { | |
| console.warn("STRICT: Bỏ qua gửi kết quả rỗng <15s (chống spam)."); | |
| return Promise.resolve(false); | |
| } | |
| var payload = { | |
| studentName: document.getElementById("student-name").textContent, | |
| className: document.getElementById("student-class").textContent, | |
| score: results.totalScore, | |
| totalTime: results.totalTime, | |
| totalQuestions: currentQuizData.length, | |
| timestamp: new Date().toISOString(), | |
| sessionId: currentSessionId, | |
| startedQuiz: true, | |
| // answeredCount giúp Apps Script lọc spam (0 time / 0 answer) | |
| answeredCount: (results.answeredCount !== undefined ? results.answeredCount : (results.totalAnswered !== undefined ? results.totalAnswered : null)), | |
| autoSubmit: results.autoSubmitReason || "NO", | |
| // ==== THỜI GIAN BẮT ĐẦU/KẾT THÚC (gửi nhiều key để tương thích Apps Script cũ/mới) | |
| startTime: (startTime ? startTime.toISOString() : ""), | |
| endTime: (endTime ? endTime.toISOString() : new Date().toISOString()), | |
| startTimestamp: (startTime ? startTime.toISOString() : ""), | |
| endTimestamp: (endTime ? endTime.toISOString() : new Date().toISOString()), | |
| timeStart: (startTime ? startTime.toISOString() : ""), | |
| timeEnd: (endTime ? endTime.toISOString() : new Date().toISOString()), | |
| // ==== SỐ LẦN THOÁT + THỜI GIAN THOÁT (giây) - gửi nhiều alias | |
| screenExitCount: screenExitCount, | |
| exitCount: screenExitCount, | |
| exit_count: screenExitCount, | |
| soLanThoatManHinh: screenExitCount, | |
| totalHiddenTime: totalHiddenTime, | |
| hiddenTime: totalHiddenTime, | |
| hidden_time: totalHiddenTime, | |
| totalHiddenSeconds: totalHiddenTime, | |
| tongThoiGianThoat: totalHiddenTime, | |
| securityInfo: { | |
| apiToken: _bmp_getApiToken(), | |
| screenExitCount: screenExitCount, | |
| totalHiddenTime: totalHiddenTime, | |
| startTime: (startTime ? startTime.toISOString() : ""), | |
| endTime: (endTime ? endTime.toISOString() : new Date().toISOString()) | |
| }, | |
| quizTitle: "Đề kiểm tra", | |
| quizId: "1769689416016", | |
| apiToken: _bmp_getApiToken(), | |
| questionStats: buildQuestionStats(results), | |
| userAgent: navigator.userAgent || "" | |
| }; | |
| return _postToAppsScript(payload).then(function(ok) { | |
| if (ok) { | |
| showNotification("✅ Đã gửi (hoặc xếp hàng gửi) lên Google Sheets!"); | |
| try { if (__sentKey) localStorage.setItem(__sentKey, "1"); } catch(e) {} | |
| return true; | |
| } | |
| // Nếu _postToAppsScript trả false, coi như thất bại mạng | |
| _enqueuePending(payload); | |
| if (retryCount < maxRetries) { | |
| showNotification("⚠️ Mạng bị chặn/yếu. Đang thử lại lần " + (retryCount + 1) + "...", true); | |
| return _sleep(1000).then(function() { | |
| return sendResultsToGoogleSheet(results, retryCount + 1); | |
| }); | |
| } else { | |
| showNotification("⚠️ Đã lưu cục bộ + đưa vào hàng đợi. Khi có mạng, hệ thống sẽ tự gửi lại lên Google Sheets.", true); | |
| return false; | |
| } | |
| }).catch(function(error) { | |
| console.error("Lỗi khi gửi kết quả:", error); | |
| _enqueuePending(payload); | |
| if (retryCount < maxRetries) { | |
| showNotification("⚠️ Mạng bị chặn/yếu. Đang thử lại lần " + (retryCount + 1) + "...", true); | |
| return _sleep(1000).then(function() { | |
| return sendResultsToGoogleSheet(results, retryCount + 1); | |
| }); | |
| } else { | |
| showNotification("⚠️ Đã lưu cục bộ + đưa vào hàng đợi. Khi có mạng, hệ thống sẽ tự gửi lại lên Google Sheets.", true); | |
| return false; | |
| } | |
| }); | |
| } | |
| // Toggle sidebar trên desktop | |
| function toggleSidebar() { | |
| const sidebar = document.getElementById('sidebar'); | |
| const questionContainer = document.getElementById('question-container'); | |
| sidebarVisible = !sidebarVisible; | |
| if (sidebarVisible) { | |
| sidebar.classList.remove('collapsed'); | |
| questionContainer.classList.add('expanded'); | |
| } else { | |
| sidebar.classList.add('collapsed'); | |
| questionContainer.classList.remove('expanded'); | |
| } | |
| saveCurrentSession(); | |
| } | |
| // Tạo đề ngẫu nhiên từ bank | |
| function createRandomQuiz() { | |
| const bank = { | |
| part1: {}, | |
| part2: {}, | |
| part3: {} | |
| }; | |
| for (const level in bankData.part1) { | |
| bank.part1[level] = bankData.part1[level].map(q => ({ | |
| question: q.question, | |
| options: q.options.map(opt => ({ | |
| text: opt.text, | |
| is_correct: opt.is_correct | |
| })), | |
| level: q.level | |
| })); | |
| } | |
| for (const level in bankData.part2) { | |
| bank.part2[level] = bankData.part2[level].map(q => ({ | |
| question: q.question, | |
| statements: q.statements, | |
| answers: q.answers, | |
| level: q.level | |
| })); | |
| } | |
| for (const level in bankData.part3) { | |
| bank.part3[level] = bankData.part3[level].map(q => ({ | |
| question: q.question, | |
| answer: q.answer, | |
| level: q.level | |
| })); | |
| } | |
| const selected = []; | |
| // Helper: chọn ngẫu nhiên nhưng có thể giữ thứ tự theo đề gốc khi không xáo trộn câu hỏi | |
| function _pickSubset(available, need, keepOrder){ | |
| const n = Math.min(need, available.length); | |
| if (n <= 0) return []; | |
| // Nếu lấy hết và cần giữ thứ tự: trả nguyên danh sách theo thứ tự gốc | |
| if (keepOrder && n === available.length) return available.slice(); | |
| const picked = []; | |
| const used = new Set(); | |
| while (picked.length < n && used.size < available.length){ | |
| const idx = Math.floor(Math.random() * available.length); | |
| if (!used.has(idx)){ | |
| used.add(idx); | |
| picked.push({idx, q: available[idx]}); | |
| } | |
| } | |
| if (keepOrder){ | |
| picked.sort((a,b)=>a.idx-b.idx); | |
| } | |
| return picked.map(it=>it.q); | |
| } | |
| // PHẦN I - Trắc nghiệm | |
| for (const level in pickCounts.part1) { | |
| const need = pickCounts.part1[level]; | |
| if (need > 0) { | |
| const available = (bank.part1[level] || []).slice(); | |
| if (available.length > 0) { | |
| const keepOrder = !shuffleOptions.shuffle_q_type1; | |
| const selectedQuestions = _pickSubset(available, need, keepOrder); | |
| for (const q of selectedQuestions) { | |
| selected.push({ | |
| type: "type1", | |
| part: 1, | |
| question: q.question, | |
| options: q.options.map(opt => ({ text: opt.text, is_correct: opt.is_correct })), | |
| level: q.level, | |
| correct_answer: getCorrectAnswerMCQ(q) | |
| }); | |
| } | |
| } | |
| } | |
| } | |
| // PHẦN II - Đúng/Sai | |
| for (const level in pickCounts.part2) { | |
| const need = pickCounts.part2[level]; | |
| if (need > 0) { | |
| const available = (bank.part2[level] || []).slice(); | |
| if (available.length > 0) { | |
| const keepOrder = !shuffleOptions.shuffle_q_type2; | |
| const selectedQuestions = _pickSubset(available, need, keepOrder); | |
| for (const q of selectedQuestions) { | |
| selected.push({ | |
| type: "type2", | |
| part: 2, | |
| question: q.question, | |
| statements: (q.statements || []).slice(), | |
| answers: (q.answers || []).slice(), | |
| level: q.level | |
| }); | |
| } | |
| } | |
| } | |
| } | |
| // PHẦN III - Điền đáp số | |
| for (const level in pickCounts.part3) { | |
| const need = pickCounts.part3[level]; | |
| if (need > 0) { | |
| const available = (bank.part3[level] || []).slice(); | |
| if (available.length > 0) { | |
| const keepOrder = !shuffleOptions.shuffle_q_type3; | |
| const selectedQuestions = _pickSubset(available, need, keepOrder); | |
| for (const q of selectedQuestions) { | |
| selected.push({ | |
| type: "type3", | |
| part: 3, | |
| question: q.question, | |
| answer: q.answer, | |
| level: q.level | |
| }); | |
| } | |
| } | |
| } | |
| } | |
| let part1Questions = selected.filter(q => q.part === 1); | |
| let part2Questions = selected.filter(q => q.part === 2); | |
| let part3Questions = selected.filter(q => q.part === 3); | |
| if (shuffleOptions.shuffle_q_type1) shuffleArray(part1Questions); | |
| if (shuffleOptions.shuffle_q_type2) shuffleArray(part2Questions); | |
| if (shuffleOptions.shuffle_q_type3) shuffleArray(part3Questions); | |
| if (shuffleOptions.shuffle_a_type1) { | |
| part1Questions.forEach(q => { | |
| const correctIndex = q.options.findIndex(opt => opt.is_correct === 1); | |
| const correctText = q.options[correctIndex].text; | |
| shuffleArray(q.options); | |
| const newCorrectIndex = q.options.findIndex(opt => opt.text === correctText); | |
| q.options.forEach((opt, idx) => { | |
| opt.is_correct = idx === newCorrectIndex ? 1 : 0; | |
| }); | |
| q.correct_answer = getCorrectAnswerMCQ(q); | |
| }); | |
| } | |
| if (shuffleOptions.shuffle_a_type2) { | |
| part2Questions.forEach(q => { | |
| const pairs = q.statements.map((stmt, idx) => ({ | |
| statement: stmt, | |
| answer: q.answers[idx] | |
| })); | |
| shuffleArray(pairs); | |
| q.statements = pairs.map(p => p.statement); | |
| q.answers = pairs.map(p => p.answer); | |
| }); | |
| } | |
| const finalData = part1Questions.concat(part2Questions, part3Questions); | |
| finalData.forEach((q, idx) => { | |
| q.q_num = idx + 1; | |
| }); | |
| return finalData; | |
| } | |
| function getCorrectAnswerMCQ(question) { | |
| const correctOption = question.options.find(opt => opt.is_correct === 1); | |
| if (correctOption) { | |
| const index = question.options.indexOf(correctOption); | |
| return String.fromCharCode(65 + index); | |
| } | |
| return "A"; | |
| } | |
| function shuffleArray(array) { | |
| for (let i = array.length - 1; i > 0; i--) { | |
| const j = Math.floor(Math.random() * (i + 1)); | |
| [array[i], array[j]] = [array[j], array[i]]; | |
| } | |
| } | |
| // Initialize quiz với đề ngẫu nhiên | |
| function initQuiz() { | |
| const currentSession = loadCurrentSession(); | |
| const fullName = document.getElementById('fullName').value.trim(); | |
| const className = document.getElementById('className').value.trim(); | |
| // KIỂM TRA NẾU CÓ PHIÊN LÀM BÀI BỊ GIÁN ĐOẠN | |
| if (currentSession && | |
| currentSession.studentName === fullName && | |
| currentSession.className === className) { | |
| // Kiểm tra thời gian đã trôi qua kể từ lần lưu cuối | |
| const lastSave = new Date(currentSession.lastSave); | |
| const now = new Date(); | |
| const elapsedSeconds = Math.floor((now - lastSave) / 1000); | |
| // SỬA LỖI: Chỉ khôi phục trong 15 giây, quá thời gian thì yêu cầu đăng nhập mới | |
| if (elapsedSeconds > 15) { // Đã sửa từ 60 xuống 15 | |
| // Hiển thị thông báo và không cho tiếp tục | |
| alert(`⏰ Bài thi của bạn đã tự động nộp do thoát quá lâu (${Math.floor(elapsedSeconds/60)} phút).\n\nVui lòng bắt đầu bài thi mới.`); | |
| // Xóa session cũ | |
| clearCurrentSession(); | |
| // Quay lại màn hình đăng nhập | |
| document.getElementById('quiz-section').style.display = 'none'; | |
| document.getElementById('user-info-form').style.display = 'block'; | |
| document.getElementById('fullName').value = ''; | |
| document.getElementById('className').value = ''; | |
| // Reset timer | |
| if (timerInterval) { | |
| clearInterval(timerInterval); | |
| timerInterval = null; | |
| } | |
| return; | |
| } | |
| // KHÔI PHỤC PHIÊN LÀM BÀI TRƯỚC ĐÓ (chỉ trong 15s đầu) | |
| currentSessionId = currentSession.sessionId; | |
| startTime = new Date(currentSession.startTime); | |
| // ĐÃ SỬA: Tính thời gian còn lại dựa trên thời gian thực | |
| const elapsedSinceStart = Math.floor((now - startTime) / 1000); | |
| timeLeft = Math.max(0, totalTimeSeconds - elapsedSinceStart); | |
| // Nếu hết giờ hoặc không có tiến độ (session rác) thì bắt đầu mới, không khôi phục | |
| const __ua = currentSession.userAnswers || {}; | |
| const __hasProgress = (function(){ try { return Object.keys(__ua).length > 0; } catch(e){ return false; } })(); | |
| if (timeLeft <= 0 || !__hasProgress) { | |
| try { clearCurrentSession(); } catch(e) {} | |
| createNewSession(); | |
| return; | |
| } | |
| userAnswers = currentSession.userAnswers; | |
| currentQuizData = currentSession.currentQuizData; | |
| sidebarVisible = currentSession.sidebarVisible || false; | |
| screenExitCount = currentSession.screenExitCount || 0; | |
| totalHiddenTime = currentSession.totalHiddenTime || 0; | |
| screenOffCount = currentSession.screenOffCount || 0; | |
| totalScreenOffTime = currentSession.totalScreenOffTime || 0; | |
| document.getElementById('student-name').textContent = currentSession.studentName; | |
| document.getElementById('student-class').textContent = currentSession.className; | |
| _updateCsvButtonsVisibility(); | |
| renderQuestions(); | |
| renderAnswerStatus(); | |
| updateStatusDisplay(); | |
| currentQuestion = 1; | |
| showQuestion(currentQuestion); | |
| if (sidebarVisible) { | |
| toggleSidebar(); | |
| } | |
| startTimer(true); | |
| restoreAnswerStates(); | |
| // Hiển thị thông báo tiếp tục bài thi | |
| if (window.__BMP_SHOW_RESUME_BANNER__) { | |
| showNotification(`📝 Đã khôi phục bài thi từ ${lastSave.timeStr}. Còn ${(Math.floor(timeLeft/60)).toString().padStart(2,'0')}:${(timeLeft%60).toString().padStart(2,'0')} phút. Tiếp tục làm bài!`); | |
| } | |
| console.log("✅ Đã khôi phục phiên làm bài trước đó"); | |
| } else { | |
| // TẠO PHIÊN LÀM BÀI MỚI | |
| createNewSession(); | |
| } | |
| } | |
| // Hàm tạo phiên làm bài mới | |
| function createNewSession() { | |
| // Tạo sessionId độc lập với timestamp và random string | |
| currentSessionId = Date.now().toString() + '_' + Math.random().toString(36).substr(2, 9) + '_' + | |
| (document.getElementById('fullName').value.trim() || 'Unknown').replace(/\s+/g, '_'); | |
| currentQuizData = createRandomQuiz(); | |
| userAnswers = {}; | |
| currentQuizData.forEach((q, index) => { | |
| const qIndex = index + 1; | |
| // (FIX) Tính maxScore để quy đổi về thang 10 (tránh maxScore=0 -> 0/10) | |
| try { | |
| if (q.type === 'type1') { | |
| maxScore += __bmp_parseScore(SCORES.type1 || 0) || 0; | |
| } else if (q.type === 'type2') { | |
| const m2 = Math.max( | |
| __bmp_parseScore(SCORES.type2_1 || 0) || 0, | |
| __bmp_parseScore(SCORES.type2_2 || 0) || 0, | |
| __bmp_parseScore(SCORES.type2_3 || 0) || 0, | |
| __bmp_parseScore(SCORES.type2_4 || 0) || 0 | |
| ); | |
| maxScore += (isFinite(m2) ? m2 : 0); | |
| } else if (q.type === 'type3') { | |
| maxScore += __bmp_parseScore(SCORES.type3 || 0) || 0; | |
| } | |
| } catch (e) {} | |
| // Max score per question (for scaling to /10) | |
| try { | |
| if (q.type === 'type1') { | |
| maxScore += __bmp_parseScore(SCORES.type1 || 0); | |
| } else if (q.type === 'type2') { | |
| // Type2: choose the highest configured score | |
| const m2 = Math.max( | |
| __bmp_parseScore(SCORES.type2_1 || 0), | |
| __bmp_parseScore(SCORES.type2_2 || 0), | |
| __bmp_parseScore(SCORES.type2_3 || 0), | |
| __bmp_parseScore(SCORES.type2_4 || 0) | |
| ); | |
| maxScore += (isFinite(m2) ? m2 : 0); | |
| } else if (q.type === 'type3') { | |
| maxScore += __bmp_parseScore(SCORES.type3 || 0); | |
| } | |
| } catch(e) {} | |
| if (q.type === "type1") { | |
| userAnswers[qIndex] = { | |
| type: 1, | |
| answer: null, | |
| correct: null, | |
| score: 0, | |
| correctAnswer: q.correct_answer, | |
| sessionId: currentSessionId // Thêm sessionId vào từng câu trả lời | |
| }; | |
| } else if (q.type === "type2") { | |
| userAnswers[qIndex] = { | |
| type: 2, | |
| answers: Array(q.statements.length).fill(null), | |
| correct: null, | |
| score: 0, | |
| correctAnswers: q.answers || [], | |
| sessionId: currentSessionId | |
| }; | |
| } else if (q.type === "type3") { | |
| userAnswers[qIndex] = { | |
| type: 3, | |
| answer: "", | |
| correct: null, | |
| score: 0, | |
| correctAnswer: q.answer || "", | |
| sessionId: currentSessionId | |
| }; | |
| } | |
| }); | |
| // Reset timer hoàn toàn | |
| timeLeft = totalTimeSeconds; | |
| startTime = null; | |
| endTime = null; | |
| totalTime = 0; | |
| renderQuestions(); | |
| renderAnswerStatus(); | |
| updateStatusDisplay(); | |
| currentQuestion = 1; | |
| showQuestion(currentQuestion); | |
| // ===== BMP FIX: đảm bảo đã BẮT ĐẦU làm bài cho phiên mới (khởi tạo startTime) ===== | |
| try { | |
| if (!startTime) { startTimer(false); } | |
| } catch (e) { | |
| try { startTimer(); } catch (e2) {} | |
| } | |
| console.log("✅ Đã tạo phiên làm bài mới với ID:", currentSessionId); | |
| } | |
| // Khôi phục trạng thái câu trả lời | |
| function restoreAnswerStates() { | |
| currentQuizData.forEach((q, index) => { | |
| const qIndex = index + 1; | |
| const userAnswer = userAnswers[qIndex]; | |
| if (q.type === "type1" && userAnswer.answer !== null) { | |
| const questionElem = document.getElementById(`question-${qIndex}`); | |
| if (questionElem) { | |
| const buttons = questionElem.querySelectorAll('.answers-type1 button'); | |
| if (buttons[userAnswer.answer]) { | |
| buttons[userAnswer.answer].classList.add('selected-button'); | |
| } | |
| } | |
| } else if (q.type === "type2") { | |
| const questionElem = document.getElementById(`question-${qIndex}`); | |
| if (questionElem) { | |
| userAnswer.answers.forEach((ans, stmtIndex) => { | |
| const btn = document.getElementById(`tfbtn-${qIndex}-${stmtIndex}`); | |
| if (!btn) return; | |
| if (ans !== null) { | |
| btn.textContent = ans; | |
| btn.classList.add('selected'); | |
| } else { | |
| btn.textContent = 'Đ'; | |
| btn.classList.remove('selected'); | |
| } | |
| }); | |
| } | |
| } else if (q.type === "type3" && userAnswer.answer !== "") { | |
| const questionElem = document.getElementById(`question-${qIndex}`); | |
| if (questionElem) { | |
| const input = questionElem.querySelector('.short-answer-input-type3'); | |
| if (input) { | |
| input.value = userAnswer.answer; | |
| } | |
| } | |
| part3Score += userAnswer.score; | |
| } | |
| }); | |
| } | |
| // Render questions từ currentQuizData | |
| function renderQuestions() { | |
| const container = document.getElementById('quiz-content'); | |
| let html = ''; | |
| currentQuizData.forEach((q, index) => { | |
| const qIndex = index + 1; | |
| if (q.type === "type1") { | |
| html += ` | |
| <div class="question" id="question-${qIndex}"> | |
| <h3>Câu ${qIndex}</h3> | |
| <div class="question-text question-detail-content">${formatQuestionContent(q.question)}</div> | |
| <div class="answers-type1"> | |
| ${q.options.map((opt, optIdx) => ` | |
| <button onclick="selectAnswer(${qIndex}, ${optIdx})"> | |
| <div class="answer-letter">${String.fromCharCode(65 + optIdx)}</div> | |
| <div class="answer-text question-detail-content">${formatQuestionContent(opt.text)}</div> | |
| </button> | |
| `).join('')} | |
| </div> | |
| </div>`; | |
| } else if (q.type === "type2") { | |
| html += ` | |
| <div class="question" id="question-${qIndex}"> | |
| <h3>Câu ${qIndex}</h3> | |
| <div class="question-text question-detail-content">${formatQuestionContent(q.question)}</div> | |
| <div class="options-container-type2"> | |
| ${q.statements.map((stmt, stmtIdx) => ` | |
| <div class="option-item-type2"> | |
| <button class="tf-circle tf-neutral" id="tfbtn-${qIndex}-${stmtIdx}" onclick="toggleTF(${qIndex}, ${stmtIdx})">Đ/S</button> | |
| <div class="statement-text question-detail-content">${formatQuestionContent(cleanTFStmt(stmt))}</div> | |
| </div> | |
| `).join('')} | |
| </div> | |
| </div>`; | |
| } else if (q.type === "type3") { | |
| html += ` | |
| <div class="question" id="question-${qIndex}"> | |
| <h3>Câu ${qIndex}</h3> | |
| <div class="question-text question-detail-content">${formatQuestionContent(q.question)}</div> | |
| <input type="text" class="short-answer-input-type3" | |
| oninput="updateShortAnswer(${qIndex}, this.value)" | |
| placeholder="Nhập đáp số..."> | |
| </div>`; | |
| } | |
| }); | |
| container.innerHTML = html; | |
| syncTFButtons(); | |
| setTimeout(fixQuestionDisplay, 50); | |
| } | |
| // Hàm kiểm tra và sửa lỗi hiển thị câu hỏi | |
| function fixQuestionDisplay() { | |
| const questions = document.querySelectorAll('.question'); | |
| questions.forEach((question, index) => { | |
| const qIndex = index + 1; | |
| question.id = `question-${qIndex}`; | |
| const questionText = question.querySelector('.question-text'); | |
| if (questionText) { | |
| const originalContent = questionText.innerHTML; | |
| questionText.innerHTML = formatQuestionContent(originalContent.replace(/<br>/g, '\n')); | |
| } | |
| }); | |
| setTimeout(() => { | |
| refreshMathJax(); | |
| }, 100); | |
| } | |
| // Render answer status | |
| function renderAnswerStatus() { | |
| renderStatusGrid('status-type1', 1); | |
| renderStatusGrid('status-type2', 2); | |
| renderStatusGrid('status-type3', 3); | |
| renderStatusGrid('mobile-status-type1', 1); | |
| renderStatusGrid('mobile-status-type2', 2); | |
| renderStatusGrid('mobile-status-type3', 3); | |
| } | |
| function renderStatusGrid(containerId, type) { | |
| const container = document.getElementById(containerId); | |
| let html = ''; | |
| const questions = currentQuizData.filter(q => { | |
| if (type === 1) return q.type === "type1"; | |
| if (type === 2) return q.type === "type2"; | |
| if (type === 3) return q.type === "type3"; | |
| return false; | |
| }); | |
| questions.forEach((q, index) => { | |
| const qIndex = currentQuizData.indexOf(q) + 1; | |
| html += `<button class="status-btn" onclick="showQuestion(${qIndex})">${qIndex}</button>`; | |
| }); | |
| container.innerHTML = html; | |
| } | |
| // Update status display | |
| function updateStatusDisplay() { | |
| updateStatusForType(1); | |
| updateStatusForType(2); | |
| updateStatusForType(3); | |
| } | |
| function updateStatusForType(type) { | |
| const containers = [ | |
| 'status-type1', 'status-type2', 'status-type3', | |
| 'mobile-status-type1', 'mobile-status-type2', 'mobile-status-type3' | |
| ].filter(id => id.includes(`type${type}`)); | |
| const questions = currentQuizData.filter(q => { | |
| if (type === 1) return q.type === "type1"; | |
| if (type === 2) return q.type === "type2"; | |
| if (type === 3) return q.type === "type3"; | |
| return false; | |
| }); | |
| containers.forEach(containerId => { | |
| const container = document.getElementById(containerId); | |
| const buttons = container.getElementsByClassName('status-btn'); | |
| for (let i = 0; i < questions.length; i++) { | |
| const qIndex = currentQuizData.indexOf(questions[i]) + 1; | |
| const btn = buttons[i]; | |
| const answer = userAnswers[qIndex]; | |
| btn.classList.remove('answered', 'current'); | |
| if (qIndex === currentQuestion) { | |
| btn.classList.add('current'); | |
| } | |
| if (answer) { | |
| let answered = false; | |
| if (type === 1 && answer.answer !== null) { | |
| answered = true; | |
| } else if (type === 2 && answer.answers.some(a => a !== null)) { | |
| answered = true; | |
| } else if (type === 3 && answer.answer.trim() !== "") { | |
| answered = true; | |
| } | |
| if (answered) { | |
| btn.classList.add('answered'); | |
| } | |
| } | |
| } | |
| }); | |
| } | |
| // Navigation | |
| let currentQuestion = 1; | |
| function showQuestion(index) { | |
| const totalQuestions = currentQuizData.length; | |
| if (index < 1) index = 1; | |
| if (index > totalQuestions) index = totalQuestions; | |
| document.querySelectorAll('.question').forEach(q => { | |
| q.classList.remove('active'); | |
| }); | |
| const questionElem = document.getElementById(`question-${index}`); | |
| if (questionElem) { | |
| questionElem.classList.add('active'); | |
| currentQuestion = index; | |
| updateStatusDisplay(); | |
| if (window.innerWidth <= 768) { | |
| document.getElementById('mobile-status-panel').classList.remove('active'); | |
| } | |
| // Lưu session khi chuyển câu | |
| saveCurrentSession(); | |
| } | |
| } | |
| function nextQuestion() { | |
| showQuestion(currentQuestion + 1); | |
| } | |
| function prevQuestion() { | |
| showQuestion(currentQuestion - 1); | |
| } | |
| // Answer selection | |
| function selectAnswer(qIndex, optionIndex) { | |
| const question = document.getElementById(`question-${qIndex}`); | |
| const buttons = question.querySelectorAll('.answers-type1 button'); | |
| buttons.forEach(btn => btn.classList.remove('selected-button')); | |
| if (buttons[optionIndex]) { | |
| buttons[optionIndex].classList.add('selected-button'); | |
| userAnswers[qIndex].answer = optionIndex; | |
| updateStatusDisplay(); | |
| saveCurrentSession(); | |
| } | |
| } | |
| function setTFChoice(qIndex, stmtIndex, choice) { | |
| if (!userAnswers[qIndex]) return; | |
| userAnswers[qIndex].answers[stmtIndex] = choice; | |
| const btn = document.getElementById(`tfbtn-${qIndex}-${stmtIndex}`); | |
| if (btn) { | |
| btn.textContent = choice; // 'Đ' hoặc 'S' | |
| btn.classList.remove('tf-neutral', 'tf-true', 'tf-false'); | |
| if (choice === 'Đ') btn.classList.add('tf-true'); | |
| else if (choice === 'S') btn.classList.add('tf-false'); | |
| else btn.classList.add('tf-neutral'); | |
| } | |
| updateStatusDisplay(); | |
| saveCurrentSession(); | |
| } | |
| function setTFNeutral(qIndex, stmtIndex) { | |
| const btn = document.getElementById(`tfbtn-${qIndex}-${stmtIndex}`); | |
| if (btn) { | |
| btn.textContent = 'Đ/S'; | |
| btn.classList.remove('tf-true', 'tf-false'); | |
| btn.classList.add('tf-neutral'); | |
| } | |
| } | |
| function syncTFButtons() { | |
| // Đồng bộ UI nút Đ/S của Phần II theo userAnswers (khi load session / render lại) | |
| if (!currentQuizData || !currentQuizData.questions) return; | |
| currentQuizData.questions.forEach((q, idx0) => { | |
| const qIndex = idx0 + 1; | |
| if (q.type === "type2" && userAnswers[qIndex] && Array.isArray(userAnswers[qIndex].answers)) { | |
| q.statements.forEach((_, stmtIdx) => { | |
| const choice = userAnswers[qIndex].answers[stmtIdx]; | |
| if (choice === 'Đ' || choice === 'S') { | |
| setTFChoice(qIndex, stmtIdx, choice); | |
| } else { | |
| setTFNeutral(qIndex, stmtIdx); | |
| } | |
| }); | |
| } | |
| }); | |
| } | |
| function toggleTF(qIndex, stmtIndex) { | |
| if (!userAnswers[qIndex]) return; | |
| const current = userAnswers[qIndex].answers[stmtIndex]; | |
| // Ấn 1 lần: Đ, ấn 2 lần: S, rồi luân phiên | |
| const next = (current === 'Đ') ? 'S' : 'Đ'; | |
| setTFChoice(qIndex, stmtIndex, next); | |
| } | |
| function updateShortAnswer(qIndex, value) { | |
| if (userAnswers[qIndex]) { | |
| userAnswers[qIndex].answer = value; | |
| updateStatusDisplay(); | |
| saveCurrentSession(); | |
| } | |
| } | |
| function autoSubmit() { | |
| clearInterval(timerInterval); | |
| endTime = new Date(); | |
| totalTime = Math.floor((endTime - startTime) / 1000); // Tính thời gian thực tế | |
| calculateResults(); | |
| const results = window.quizResults; | |
| results.autoSubmitReason = "HẾT GIỜ"; | |
| saveQuizHistory(results); | |
| // Gửi lên Google Sheets - ĐÃ SỬA: Thêm retry mechanism | |
| sendResultsToGoogleSheet(results).then(success => { | |
| if (!success) { | |
| console.warn("Không thể gửi kết quả lên Google Sheets, nhưng đã lưu cục bộ"); | |
| } | |
| }); | |
| resetQuizState(); | |
| clearCurrentSession(); | |
| // Cập nhật modal thành công | |
| document.getElementById('success-content').innerHTML = ` | |
| <h3>⏰ HẾT GIỜ LÀM BÀI!</h3> | |
| <div class="total-score" id="final-score" style="font-size: 2.5rem; margin: 20px 0;">${results.totalScore} điểm</div> | |
| <p>Thời gian làm bài đã hết.</p> | |
| <p>Bài thi đã được tự động nộp.</p> | |
| <p>Ấn OK để xem chi tiết bài làm.</p> | |
| `; | |
| document.getElementById('success-modal').style.display = 'flex'; | |
| } | |
| // Start quiz - CẢI THIỆN: Hiển thị modal bảo mật thay vì alert | |
| function startQuizSafe(ev){ | |
| try{ | |
| if (typeof startQuiz === 'function') return startQuiz(ev); | |
| alert("⚠️ Không thể bắt đầu vì JS chưa tải xong (startQuiz missing).\n\nHãy tải lại trang hoặc mở bằng Chrome/Safari."); | |
| }catch(e){ | |
| try{ alert("Lỗi khi bắt đầu: " + (e && e.message ? e.message : e)); }catch(_){} | |
| } | |
| return false; | |
| } | |
| // Báo lỗi JS (chỉ hiện 1 lần) để dễ bắt bệnh trên iPhone/thiết bị lạ | |
| if (!window.__bmp_js_err_hooked)if (!window.__bmp_js_err_hooked) { | |
| window.__bmp_js_err_hooked = true; | |
| window.onerror = function(){ return false; }; | |
| } | |
| function startQuiz() { | |
| const fullName = document.getElementById('fullName').value.trim(); | |
| const className = document.getElementById('className').value.trim(); | |
| if (!fullName || !className) { | |
| alert('Vui lòng nhập đầy đủ họ tên và lớp!'); | |
| return; | |
| } | |
| // ===== BMP PATCH: Bắt buộc nhập ĐÚNG Họ tên + Lớp theo file Excel (có dấu) ===== | |
| if (requireExact && Array.isArray(allowedStudentsExact) && allowedStudentsExact.length > 0) { | |
| const keyN = _bmp_norm_vi(fullName); | |
| const keyC = _bmp_norm_vi(className); | |
| const ok = allowedStudentsExactMapHas(keyC, keyN); | |
| if (!ok) { | |
| alert('⛔ Không có trong danh sách!📌 Em cần gõ Họ tên + Lớp phải trùng với danh sách đã cấp.'); | |
| return; | |
| } | |
| } else if (authEnabled) { | |
| // fallback theo cơ chế hash cũ (khi không có danh sách exact) | |
| if (!isStudentAllowed(fullName, className)) { | |
| alert('⛔ Không có trong danh sách lớp!\n\nVui lòng nhập ĐÚNG Họ tên và Lớp theo danh sách đã cấp.'); | |
| return; | |
| } | |
| } | |
| // KIỂM TRA XEM CÓ PHIÊN LÀM BÀI ĐANG ACTIVE KHÔNG (TẮT POPUP - TỰ XỬ LÝ) | |
| const currentSession = loadCurrentSession(); | |
| if (currentSession && currentSession.timeLeft > 0) { | |
| // Xác định session "thật" hay session rác (do cache cũ/nhập thông tin nhưng chưa làm) | |
| const hasAnswers = !!(currentSession.userAnswers && Object.keys(currentSession.userAnswers).length > 0); | |
| const started = !!currentSession.startTime || (typeof totalTimeSeconds === 'number' && currentSession.timeLeft < totalTimeSeconds); | |
| let lastSaveAgeSec = 0; | |
| try { | |
| if (currentSession.lastSave) { | |
| lastSaveAgeSec = Math.floor((Date.now() - new Date(currentSession.lastSave).getTime()) / 1000); | |
| if (!isFinite(lastSaveAgeSec) || lastSaveAgeSec < 0) lastSaveAgeSec = 0; | |
| } | |
| } catch (e) { lastSaveAgeSec = 0; } | |
| // Quy tắc: | |
| // - Nếu có đáp án hoặc đã bắt đầu và (lưu gần đây) => tự động tiếp tục (không hỏi) | |
| // - Còn lại => xóa session cũ im lặng và bắt đầu mới | |
| const canAutoResume = (hasAnswers || started) && (lastSaveAgeSec <= 6 * 60 * 60); // <= 6 giờ | |
| if (canAutoResume) { | |
| document.getElementById('student-name').textContent = currentSession.studentName || fullName; | |
| document.getElementById('student-class').textContent = currentSession.className || className; | |
| _updateCsvButtonsVisibility(); | |
| document.getElementById('user-info-form').style.display = 'none'; | |
| document.getElementById('quiz-section').style.display = 'block'; | |
| initQuiz(); // initQuiz sẽ tự restore | |
| return; | |
| } else { | |
| clearCurrentSession(); | |
| } | |
| } | |
| // Kiểm tra lịch sử bài làm trước đó | |
| const history = loadQuizHistory(); | |
| const _nKey = _bmp_norm_vi(fullName); | |
| const _cKey = _bmp_norm_vi(className); | |
| const previousSessions = history.filter(record => | |
| _bmp_norm_vi(record.studentName) === _nKey && _bmp_norm_vi(record.className) === _cKey | |
| ); | |
| if (previousSessions.length > 0) { | |
| const lastSession = previousSessions[previousSessions.length - 1]; | |
| const lastDate = new Date(lastSession.timestamp).toLocaleString('vi-VN'); | |
| const lastScore = lastSession.score; | |
| if (confirm( | |
| `📋 BẠN ĐÃ CÓ BÀI LÀM TRƯỚC ĐÂY!\n\n` + | |
| `📅 Thời gian: ${lastDate}\n` + | |
| `📊 Điểm số: ${lastScore}\n\n` + | |
| `Bạn có muốn:\n` + | |
| `• "OK": Làm bài mới\n` + | |
| `• "Cancel": Xem lại lịch sử bài làm trước` | |
| )) { | |
| // Người dùng chọn làm bài mới | |
| proceedWithNewQuiz(fullName, className); | |
| } else { | |
| // Người dùng chọn xem lịch sử | |
| showHistory(); | |
| return; | |
| } | |
| } else { | |
| // Không có lịch sử trước đó | |
| proceedWithNewQuiz(fullName, className); | |
| } | |
| } | |
| // iOS: đảm bảo nút Bắt đầu luôn nhận tap/click | |
| (function(){ | |
| function bindStart(){ | |
| var btn = document.getElementById('startBtn'); | |
| if (!btn) return; | |
| var fired = false; | |
| var handler = function(ev){ | |
| if (fired) return; | |
| fired = true; | |
| try { startQuiz(); } catch(e) { try{ alert('Lỗi khi bắt đầu bài làm: ' + e); }catch(e2){} } | |
| setTimeout(function(){ fired = false; }, 350); | |
| if (ev && ev.preventDefault) ev.preventDefault(); | |
| }; | |
| try { btn.addEventListener('click', handler, false); } catch(e) {} | |
| try { btn.addEventListener('touchend', handler, false); } catch(e) {} | |
| } | |
| if (document.readyState === 'loading') { | |
| document.addEventListener('DOMContentLoaded', bindStart); | |
| } else { | |
| bindStart(); | |
| try { setTimeout(function(){ try{ loadLoginRanking(); }catch(e){} }, 700); } catch(e) {} | |
| } | |
| })(); | |
| function proceedWithNewQuiz(fullName, className) { | |
| // Reset security variables | |
| screenExitCount = 0; | |
| totalHiddenTime = 0; | |
| isFirstVisibilityChange = true; | |
| lastHiddenTime = null; | |
| hiddenTime = null; | |
| document.getElementById('student-name').textContent = fullName; | |
| document.getElementById('student-class').textContent = className; | |
| _updateCsvButtonsVisibility(); | |
| document.getElementById('user-info-form').style.display = 'none'; | |
| document.getElementById('quiz-section').style.display = 'block'; | |
| // Hiển thị modal bảo mật trước | |
| document.getElementById('security-modal').style.display = 'flex'; | |
| // Khởi tạo quiz nhưng chưa bắt đầu timer | |
| initQuiz(); | |
| // Tự động đóng modal sau 5 giây nếu người dùng không ấn | |
| setTimeout(() => { | |
| if (document.getElementById('security-modal').style.display === 'flex') { | |
| closeSecurityModal(); | |
| startTimer(); | |
| enterFullscreen(); | |
| } | |
| }, 5000); | |
| } | |
| // Xử lý khi đóng modal bảo mật | |
| function closeSecurityModal() { | |
| document.getElementById('security-modal').style.display = 'none'; | |
| startTimer(); | |
| enterFullscreen(); | |
| } | |
| // Submit results | |
| function submitResults() { | |
| // ===== BMP GUARD: không cho nộp quá sớm / chưa làm xong ===== | |
| try { | |
| if (!startTime) { showNotification("⚠️ Bạn chưa bắt đầu làm bài.", true); return; } | |
| var elapsed = Math.floor((new Date() - startTime) / 1000); | |
| var MIN_MANUAL_SECONDS = 25; | |
| if (elapsed < MIN_MANUAL_SECONDS) { | |
| showNotification("⛔ Chưa đủ " + MIN_MANUAL_SECONDS + " giây làm bài nên chưa được nộp / xuất kết quả.", true); | |
| return; | |
| } | |
| // kiểm tra làm xong: tất cả câu đều có đáp án (Phần II phải đủ a,b,c,d; Phần III không được để trống) | |
| var totalQ = (currentQuizData && currentQuizData.length) ? currentQuizData.length : Object.keys(userAnswers || {}).length; | |
| var okAll = true; | |
| for (var i=0;i<(currentQuizData||[]).length;i++){ | |
| var q = currentQuizData[i] || {}; | |
| var qIndex = (q.q_num || (i+1)); | |
| var ua = userAnswers[qIndex]; | |
| if (!ua) { okAll = false; break; } | |
| var t = ua.type || (q.type==="type1"?1:(q.type==="type2"?2:3)); | |
| if (t === 1) { if (ua.answer === null || ua.answer === undefined) { okAll = false; break; } } | |
| else if (t === 2) { | |
| if (!ua.answers || ua.answers.length < (q.statements ? q.statements.length : 4)) { okAll = false; break; } | |
| for (var k=0;k<(q.statements ? q.statements.length : ua.answers.length);k++){ | |
| if (ua.answers[k] === null || ua.answers[k] === undefined) { okAll = false; break; } | |
| } | |
| if (!okAll) break; | |
| } else { | |
| var v = (ua.answer != null) ? String(ua.answer).trim() : ""; | |
| if (!v) { okAll = false; break; } | |
| } | |
| } | |
| if (!okAll) { | |
| showNotification("⛔ Bạn chưa làm xong tất cả câu hỏi nên chưa được nộp / xuất kết quả.", true); | |
| return; | |
| } | |
| } catch (e) {} | |
| // Chỉ gửi/ghi nhận đúng 1 lần cho mỗi lượt nộp | |
| if (resultsSent) { | |
| console.log("Đã gửi kết quả trước đó - bỏ qua gửi lặp."); | |
| showNotification("ℹ️ Kết quả đã được gửi trước đó.", false); | |
| return; | |
| } | |
| quizSubmitted = true; | |
| quizInProgress = false; | |
| endTime = new Date(); | |
| totalTime = Math.floor((endTime - startTime) / 1000); // Tính thời gian thực tế | |
| const answeredCount = Object.values(userAnswers).filter(ans => { | |
| if (ans.type === 1) return ans.answer !== null; | |
| if (ans.type === 2) return ans.answers.some(a => a !== null); | |
| if (ans.type === 3) return ans.answer.trim() !== ""; | |
| }).length; | |
| const totalQuestions = Object.keys(userAnswers).length; | |
| const unansweredCount = totalQuestions - answeredCount; | |
| document.getElementById('confirm-message').innerHTML = ` | |
| <p>Tổng số câu: <strong>${totalQuestions}</strong></p> | |
| <p>Đã làm: <strong>${answeredCount}</strong> câu</p> | |
| <p>Chưa làm: <strong>${unansweredCount}</strong> câu</p> | |
| <p>Bạn có chắc muốn nộp bài?</p> | |
| `; | |
| document.getElementById('submit-confirm').style.display = 'flex'; | |
| } | |
| function finalizeSubmit() { | |
| clearInterval(timerInterval); | |
| document.getElementById('submit-confirm').style.display = 'none'; | |
| calculateResults(); | |
| var results = window.quizResults; | |
| saveQuizHistory(results); | |
| _appendCsvRecord(results); | |
| // Hiển thị kết quả NGAY (không chờ gửi mạng) để tránh một số trình duyệt/điện thoại bị "đứng" | |
| showSuccessModal(); | |
| // Gửi lên Google Sheets ở nền (không block UI) | |
| try { | |
| sendResultsToGoogleSheet(results).then(function(ok) { | |
| if (!ok) { | |
| showNotification("⚠️ Kết quả đã được lưu cục bộ nhưng chưa thể gửi lên Google Sheets. Sẽ tự gửi lại khi có mạng.", true); | |
| } | |
| }).catch(function() { | |
| showNotification("⚠️ Kết quả đã được lưu cục bộ nhưng chưa thể gửi lên Google Sheets. Sẽ tự gửi lại khi có mạng.", true); | |
| }); | |
| } catch (e) { | |
| showNotification("⚠️ Kết quả đã được lưu cục bộ nhưng chưa thể gửi lên Google Sheets. Sẽ tự gửi lại khi có mạng.", true); | |
| } | |
| // Không reset ngay để còn xem chi tiết. Khi đóng bảng kết quả sẽ tự đưa về màn hình nhập thông tin. | |
| } | |
| function cancelSubmit() { | |
| document.getElementById('submit-confirm').style.display = 'none'; | |
| } | |
| // Calculate results | |
| function calculateResults() { | |
| let totalScore = 0; | |
| let maxScore = 0; | |
| // Breakdown by part | |
| let part1Score = 0, part2Score = 0, part3Score = 0; | |
| let part1Max = 0, part2Max = 0, part3Max = 0; | |
| // (FIX) Parse score robustly (supports "0,25" and empty strings) | |
| const __bmp_parseScore = (v) => { | |
| if (v === null || v === undefined) return 0; | |
| if (typeof v === 'string') { | |
| const t = v.trim(); | |
| if (!t) return 0; | |
| const norm = t.replace(',', '.'); // decimal comma -> dot | |
| const n = parseFloat(norm); | |
| return (isFinite(n) ? n : 0); | |
| } | |
| const n = Number(v); | |
| return (isFinite(n) ? n : 0); | |
| }; | |
| // Parse score config safely (supports decimal comma) | |
| const __S1 = __bmp_parseScore(SCORES.type1); | |
| const __S2_1 = __bmp_parseScore(SCORES.type2_1); | |
| const __S2_2 = __bmp_parseScore(SCORES.type2_2); | |
| const __S2_3 = __bmp_parseScore(SCORES.type2_3); | |
| const __S2_4 = __bmp_parseScore(SCORES.type2_4); | |
| const __S2_MAX = Math.max(__S2_1, __S2_2, __S2_3, __S2_4); | |
| const __S3 = __bmp_parseScore(SCORES.type3); | |
| currentQuizData.forEach((q, index) => { | |
| const qIndex = index + 1; | |
| const userAnswer = userAnswers[qIndex]; | |
| if (q.type === "type1") { | |
| // Part I (trắc nghiệm) | |
| part1Max += __S1; maxScore += __S1; | |
| const correctOptionIndex = q.options.findIndex(opt => opt.is_correct === 1); | |
| userAnswer.correct = (userAnswer.answer === correctOptionIndex); | |
| if (userAnswer.correct) { | |
| userAnswer.score = __S1; | |
| totalScore += userAnswer.score; | |
| } else { | |
| userAnswer.score = 0; | |
| } | |
| part1Score += userAnswer.score; | |
| } else if (q.type === "type2") { | |
| // Part II (đúng/sai) | |
| part2Max += __S2_MAX; maxScore += __S2_MAX; | |
| let correctCount = 0; | |
| const totalStatements = q.statements.length; | |
| for (let i = 0; i < totalStatements; i++) { | |
| if (userAnswer.answers[i] === q.answers[i]) { | |
| correctCount++; | |
| } | |
| } | |
| userAnswer.correctCount = correctCount; | |
| userAnswer.totalStatements = totalStatements; | |
| userAnswer.correct = (correctCount === totalStatements); | |
| if (correctCount === 1) { | |
| userAnswer.score = __S2_1; | |
| } else if (correctCount === 2) { | |
| userAnswer.score = __S2_2; | |
| } else if (correctCount === 3) { | |
| userAnswer.score = __S2_3; | |
| } else if (correctCount === 4) { | |
| userAnswer.score = __S2_4; | |
| } else { | |
| userAnswer.score = 0; | |
| } | |
| totalScore += userAnswer.score; | |
| part2Score += userAnswer.score; | |
| } else if (q.type === "type3") { | |
| // Part III (điền đáp số) | |
| part3Max += __S3; maxScore += __S3; | |
| // Phần III (điền đáp số): KHÔNG tính điểm nếu chưa nhập đáp án. | |
| const normalizeAnswer = (ans) => { | |
| return (ans || "").toString().toLowerCase().replace(/[.,]/g, "").trim(); | |
| }; | |
| const userAns = normalizeAnswer(userAnswer.answer); | |
| const correctAns = normalizeAnswer(q.answer); | |
| // Nếu bỏ trống -> xem như CHƯA TRẢ LỜI, không đúng, không điểm | |
| const isAnswered = (userAns !== ""); | |
| userAnswer.unanswered = !isAnswered; | |
| if (!isAnswered) { | |
| userAnswer.correct = false; | |
| userAnswer.score = 0; | |
| } else { | |
| userAnswer.correct = (userAns === correctAns); | |
| if (userAnswer.correct) { | |
| userAnswer.score = __S3; | |
| totalScore += userAnswer.score; | |
| } else { | |
| userAnswer.score = 0; | |
| } | |
| } | |
| part3Score += userAnswer.score; | |
| } | |
| }); | |
| window.quizResults = { | |
| totalScore: Math.round(totalScore * 100) / 100, | |
| maxScore: Math.round(maxScore * 100) / 100, | |
| score10: (() => { | |
| const ms = (isFinite(maxScore) ? maxScore : 0); | |
| if (ms > 0) return Math.round((totalScore / ms * 10) * 100) / 100; | |
| return 0; | |
| })(), | |
| partBreakdown: (() => { | |
| const ms = (isFinite(maxScore) ? maxScore : 0); | |
| const safe = (x) => (isFinite(x) ? x : 0); | |
| const p1 = safe(part1Score), p2 = safe(part2Score), p3 = safe(part3Score); | |
| const m1 = safe(part1Max), m2 = safe(part2Max), m3 = safe(part3Max); | |
| const p1_10 = (ms>0) ? Math.round((p1/ms*10)*100)/100 : 0; | |
| const p2_10 = (ms>0) ? Math.round((p2/ms*10)*100)/100 : 0; | |
| const p3_10 = (ms>0) ? Math.round((p3/ms*10)*100)/100 : 0; | |
| return { raw1: Math.round(p1*100)/100, max1: Math.round(m1*100)/100, p1_10, | |
| raw2: Math.round(p2*100)/100, max2: Math.round(m2*100)/100, p2_10, | |
| raw3: Math.round(p3*100)/100, max3: Math.round(m3*100)/100, p3_10, | |
| maxAll: Math.round(ms*100)/100 }; | |
| })(), | |
| userAnswers: userAnswers, | |
| quizData: currentQuizData, | |
| startTime: startTime, | |
| endTime: endTime, | |
| totalTime: totalTime, | |
| securityInfo: { | |
| apiToken: _bmp_getApiToken(), | |
| screenExitCount: screenExitCount, | |
| totalHiddenTime: totalHiddenTime | |
| } | |
| }; | |
| } | |
| function fmtDateTime(x){ | |
| try{ | |
| if (!x) return ""; | |
| var d = (x instanceof Date) ? x : new Date(x); | |
| if (isNaN(d.getTime())) return ""; | |
| return d.toLocaleString('vi-VN'); | |
| }catch(e){ return ""; } | |
| } | |
| function fmtDurationSec(sec){ | |
| sec = Math.max(0, parseInt(sec || 0, 10) || 0); | |
| var m = Math.floor(sec/60), s = sec%60; | |
| return m + " phút " + s + "s"; | |
| } | |
| // ===== Export confirm (Xuất kết quả) ===== | |
| let __exportConfirmCb = null; | |
| function openExportConfirm(messageHtml, onOk) { | |
| __exportConfirmCb = (typeof onOk === 'function') ? onOk : null; | |
| const msg = document.getElementById('export-confirm-message'); | |
| if (msg) msg.innerHTML = messageHtml || "Bạn có chắc là muốn xuất kết quả?"; | |
| const modal = document.getElementById('export-confirm'); | |
| if (modal) modal.style.display = 'flex'; | |
| } | |
| function confirmExport() { | |
| const modal = document.getElementById('export-confirm'); | |
| if (modal) modal.style.display = 'none'; | |
| const cb = __exportConfirmCb; | |
| __exportConfirmCb = null; | |
| if (cb) { try { cb(); } catch(e) {} } | |
| } | |
| function cancelExport() { | |
| const modal = document.getElementById('export-confirm'); | |
| if (modal) modal.style.display = 'none'; | |
| __exportConfirmCb = null; | |
| } | |
| // ===== END Export confirm ===== | |
| // Show results | |
| function showResults(hideTotalScore = false, _skipConfirm = false) { | |
| // ===== BMP GUARD: không cho xuất kết quả quá sớm / chưa làm xong (chỉ khi đang làm bài) ===== | |
| try { | |
| var MIN_MANUAL_SECONDS = 25; | |
| if (!quizSubmitted && quizInProgress && !resultsSent) { | |
| if (!startTime) { showNotification("⚠️ Bạn chưa bắt đầu làm bài.", true); return; } | |
| var elapsed = Math.floor((new Date() - startTime) / 1000); | |
| if (elapsed < MIN_MANUAL_SECONDS) { | |
| showNotification("⛔ Chưa đủ " + MIN_MANUAL_SECONDS + " giây làm bài nên chưa được nộp / xuất kết quả.", true); | |
| return; | |
| } | |
| // kiểm tra làm xong (giống nộp bài) | |
| var okAll = true; | |
| for (var i=0;i<(currentQuizData||[]).length;i++){ | |
| var q = currentQuizData[i] || {}; | |
| var qIndex = (q.q_num || (i+1)); | |
| var ua = userAnswers[qIndex]; | |
| if (!ua) { okAll = false; break; } | |
| var t = ua.type || (q.type==="type1"?1:(q.type==="type2"?2:3)); | |
| if (t === 1) { if (ua.answer === null || ua.answer === undefined) { okAll = false; break; } } | |
| else if (t === 2) { | |
| if (!ua.answers || ua.answers.length < (q.statements ? q.statements.length : 4)) { okAll = false; break; } | |
| for (var k=0;k<(q.statements ? q.statements.length : ua.answers.length);k++){ | |
| if (ua.answers[k] === null || ua.answers[k] === undefined) { okAll = false; break; } | |
| } | |
| if (!okAll) break; | |
| } else { | |
| var v = (ua.answer != null) ? String(ua.answer).trim() : ""; | |
| if (!v) { okAll = false; break; } | |
| } | |
| } | |
| if (!okAll) { | |
| showNotification("⛔ Bạn chưa làm xong tất cả câu hỏi nên chưa được nộp / xuất kết quả.", true); | |
| return; | |
| } | |
| } | |
| } catch(e) {} | |
| // Xác nhận khi HS bấm "Xuất kết quả" trong lúc đang làm bài (vì sẽ khóa bài làm) | |
| if (!_skipConfirm && !resultsSent && !quizSubmitted) { | |
| openExportConfirm( | |
| 'Bạn có chắc là muốn xuất kết quả, vì sao khi xuất kết quả thì không làm bài được nữa', | |
| function(){ showResults(hideTotalScore, true); } | |
| ); | |
| return; | |
| } | |
| // HS ấn "Xuất kết quả" cũng được tính như "Nộp bài": lưu lịch sử + gửi về Google Sheets (chỉ 1 lần) | |
| if (!resultsSent) { | |
| quizSubmitted = true; | |
| quizInProgress = false; | |
| try { clearInterval(timerInterval); } catch (e) {} | |
| endTime = new Date(); | |
| try { | |
| totalTime = Math.floor((endTime - startTime) / 1000); | |
| } catch (e) { | |
| totalTime = totalTime || 0; | |
| } | |
| calculateResults(); | |
| const _results = window.quizResults || {}; | |
| // Bổ sung chắc chắn các trường thời gian (để lịch sử hiển thị đúng) | |
| _results.endTime = endTime; | |
| _results.totalTime = (typeof totalTime === 'number') ? totalTime : (_results.totalTime || 0); | |
| // Lưu lịch sử (local) trước, rồi gửi nền | |
| try { saveQuizHistory(_results); } catch (e) {} | |
| resultsSent = true; | |
| try { | |
| sendResultsToGoogleSheet(_results).then(function(ok) { | |
| if (!ok) { | |
| showNotification("⚠️ Kết quả đã được lưu cục bộ nhưng chưa thể gửi lên Google Sheets. Sẽ tự gửi lại khi có mạng.", true); | |
| } | |
| }).catch(function() { | |
| showNotification("⚠️ Kết quả đã được lưu cục bộ nhưng chưa thể gửi lên Google Sheets. Sẽ tự gửi lại khi có mạng.", true); | |
| }); | |
| } catch (e) { | |
| showNotification("⚠️ Kết quả đã được lưu cục bộ nhưng chưa thể gửi lên Google Sheets. Sẽ tự gửi lại khi có mạng.", true); | |
| } | |
| } else { | |
| // Đã gửi trước đó => chỉ hiển thị lại kết quả | |
| calculateResults(); | |
| } | |
| const results = window.quizResults; | |
| let html = ` | |
| <div class="results-container"> | |
| <div class="results-header"> | |
| <h2>📊 KẾT QUẢ BÀI LÀM</h2> | |
| `; | |
| if (!hideTotalScore) { | |
| html += `<div class="total-score">Tổng điểm: ${results.totalScore} <span style="opacity:.9;">(Quy đổi: ${results.score10}/10)</span></div>`; | |
| const pb = results.partBreakdown || {}; | |
| html += `<div class="part-breakdown" style="margin-top:6px; font-size:0.98em; line-height:1.4;">` | |
| + `Phần I: ${pb.raw1 ?? ""}/${pb.max1 ?? ""} (→ ${(pb.p1_10 ?? 0)}/10)<br>` | |
| + `Phần II: ${pb.raw2 ?? ""}/${pb.max2 ?? ""} (→ ${(pb.p2_10 ?? 0)}/10)<br>` | |
| + `Phần III: ${pb.raw3 ?? ""}/${pb.max3 ?? ""} (→ ${(pb.p3_10 ?? 0)}/10)` | |
| + `</div>`; | |
| } | |
| html += ` | |
| </div> | |
| <div class="time-info"> | |
| <p><strong>Họ và tên:</strong> ${document.getElementById('student-name').textContent}</p> | |
| <p><strong>Lớp:</strong> ${document.getElementById('student-class').textContent}</p> | |
| <p><strong>Thời gian bắt đầu:</strong> ${fmtDateTime(results.startTime)}</p> | |
| <p><strong>Thời gian kết thúc:</strong> ${fmtDateTime(results.endTime)}</p> | |
| <p><strong>Tổng thời gian làm bài:</strong> ${Math.floor(results.totalTime / 60)} phút ${results.totalTime % 60} giây</p> | |
| <p><strong>Số lần rời màn hình:</strong> ${((results.securityInfo||{}).screenExitCount)||0} lần</p> | |
| <p><strong>Tổng thời gian rời màn hình:</strong> ${fmtDurationSec(((results.securityInfo||{}).totalHiddenTime)||0)}</p> | |
| ${results.autoSubmitReason ? `<p><strong>Lý do nộp bài:</strong> ${results.autoSubmitReason}</p>` : ''} | |
| </div> | |
| <div class="ranking-inline" style="margin:16px 0; padding:14px; background:#fff8e6; border-radius:12px; border:1px solid #ffe1a6;"> | |
| <div style="display:flex; flex-direction:column; gap:10px;"> | |
| <h3 style="margin:0; color:#b45309;">🏆 TỐP VINH DANH</h3> | |
| <div style="display:flex; align-items:center; gap:10px; flex-wrap:wrap;"> | |
| <div class="lb-ctrl"> | |
| <span class="lb-flame">👥</span><span style="font-weight:800;">Lớp</span> | |
| <select id="lbClassSelect" onchange="applyRankingInlineFilters()" style="border:none; outline:none; background:transparent; font-weight:800; cursor:pointer;"> | |
| <option value="TẤT CẢ">TẤT CẢ</option> | |
| </select> | |
| </div> | |
| <div class="lb-ctrl"> | |
| <span class="lb-flame">🔝</span><span style="font-weight:800;">Top</span> | |
| <select id="lbTopSelect" onchange="applyRankingInlineFilters()" style="border:none; outline:none; background:transparent; font-weight:800; cursor:pointer;"> | |
| <option value="10" selected>Top 10</option> | |
| <option value="20">Top 20</option> | |
| </select> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="ranking-inline-box" style="margin-top:10px; color:#555;">Đang tải xếp hạng...</div> | |
| </div> | |
| <table class="results-table"> | |
| <thead> | |
| <tr> | |
| <th>Câu</th> | |
| <th>Nội dung câu hỏi</th> | |
| <th><span class="th-full">Đáp án chọn</span><span class="th-short">Chọn</span></th> | |
| <th><span class="th-full">Đáp án đúng</span><span class="th-short">Đúng</span></th> | |
| <th><span class="th-full">Điểm</span><span class="th-short">Điểm</span></th> | |
| <th><span class="th-full">Kết quả</span><span class="th-short">KQ</span></th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| `; | |
| currentQuizData.forEach((q, index) => { | |
| const qIndex = index + 1; | |
| const userAnswer = results.userAnswers[qIndex]; | |
| if (q.type === "type1") { | |
| const correctOptionIndex = q.options.findIndex(opt => opt.is_correct === 1); | |
| const userAnswerText = (userAnswer && userAnswer.answer !== null && userAnswer.answer !== undefined) ? (String.fromCharCode(65 + userAnswer.answer) + '.') : ''; | |
| const correctAnswerText = (correctOptionIndex >= 0) ? (String.fromCharCode(65 + correctOptionIndex) + '.') : ''; | |
| const userAnswerDetail = userAnswer.answer !== null ? q.options[userAnswer.answer].text : "Chưa trả lời"; | |
| const correctAnswerDetail = correctOptionIndex >= 0 ? q.options[correctOptionIndex].text : "Không xác định"; | |
| html += ` | |
| <tr class="${userAnswer.correct ? 'correct-row' : 'wrong-row'}"> | |
| <td>${qIndex}</td> | |
| <td><strong>Câu hỏi:</strong> <div class="question-detail-content">${formatQuestionContent(q.question)}</div>${q.options.map((opt, idx) => | |
| `<div class="option-line question-detail-content">${String.fromCharCode(65 + idx)}. ${formatQuestionContent(opt.text)} ${opt.is_correct ? '✓' : ''}</div>` | |
| ).join('')} | |
| </td> | |
| <td class="${userAnswer.correct ? 'correct-answer' : 'wrong-answer'}"> | |
| ${userAnswerText} | |
| </td> | |
| <td>${correctAnswerText}</td> | |
| <td>${userAnswer.score}</td> | |
| <td class="${userAnswer.correct ? 'correct-answer' : 'wrong-answer'}">${userAnswer.correct ? 'Đ' : 'S'}</td> | |
| </tr> | |
| `; | |
| } else if (q.type === "type2") { | |
| const userAnswersText = userAnswer.answers.map((ans, i) => | |
| ans !== null ? `${String.fromCharCode(97 + i)}) ${ans}` : `${String.fromCharCode(97 + i)}) Chưa trả lời` | |
| ).join('<br>'); | |
| const correctAnswersText = q.answers.map((ans, i) => | |
| `${String.fromCharCode(97 + i)}) ${ans}` | |
| ).join('<br>'); | |
| const statementsDetail = q.statements.map((stmt, i) => | |
| `<div class="option-line question-detail-content">${String.fromCharCode(97 + i)}) ${formatQuestionContent(stmt)}</div>` | |
| ).join(''); | |
| html += ` | |
| <tr class="${userAnswer.correct ? 'correct-row' : 'wrong-row'}"> | |
| <td>${qIndex}</td> | |
| <td><strong>Câu hỏi:</strong> <div class="question-detail-content">${formatQuestionContent(q.question)}</div>${statementsDetail}</td> | |
| <td class="${userAnswer.correct ? 'correct-answer' : 'wrong-answer'}">${userAnswersText}</td> | |
| <td>${correctAnswersText}</td> | |
| <td>${userAnswer.score}</td> | |
| <td class="${userAnswer.correct ? 'correct-answer' : 'wrong-answer'}"> | |
| ${userAnswer.correct ? '✓ Đúng' : `✗ Sai (${userAnswer.correctCount}/${userAnswer.totalStatements})`} | |
| </td> | |
| </tr> | |
| `; | |
| } else if (q.type === "type3") { | |
| const userAnswerText = userAnswer.answer || "Chưa trả lời"; | |
| html += ` | |
| <tr class="${userAnswer.correct ? 'correct-row' : 'wrong-row'}"> | |
| <td>${qIndex}</td> | |
| <td><strong>Câu hỏi:</strong> <div class="question-detail-content">${formatQuestionContent(q.question)}</div></td> | |
| <td class="${userAnswer.correct ? 'correct-answer' : 'wrong-answer'}">${userAnswerText}</td> | |
| <td>${q.answer}</td> | |
| <td>${userAnswer.score}</td> | |
| <td class="${userAnswer.correct ? 'correct-answer' : 'wrong-answer'}">${userAnswer.correct ? 'Đ' : 'S'}</td> | |
| </tr> | |
| `; | |
| } | |
| }); | |
| html += ` | |
| </tbody> | |
| </table> | |
| <div style="margin-top: 20px; padding: 15px; background: #f8f9fa; border-radius: 10px;"> | |
| <h3 style="color: var(--primary-color); margin-bottom: 10px;">📋 Thang điểm</h3> | |
| <p><strong>Phần I - Trắc nghiệm:</strong> Mỗi câu ${SCORES.type1} điểm</p> | |
| <p><strong>Phần II - Đúng/Sai:</strong> Đúng 1 ý: ${SCORES.type2_1}đ, 2 ý: ${SCORES.type2_2}đ, 3 ý: ${SCORES.type2_3}đ, 4 ý: ${SCORES.type2_4}đ</p> | |
| <p><strong>Phần III - Điền đáp số:</strong> Mỗi câu ${SCORES.type3} điểm</p> | |
| </div> | |
| </div> | |
| `; | |
| document.getElementById('results-content').innerHTML = html; | |
| document.getElementById('results-modal').style.display = 'flex'; | |
| try{ loadRankingInline(); }catch(e){} | |
| setTimeout(refreshMathJax, 500); | |
| } | |
| // Close results modal and return to login screen | |
| function closeResultsModal() { | |
| document.getElementById('results-modal').style.display = 'none'; | |
| document.getElementById('quiz-section').style.display = 'none'; | |
| document.getElementById('user-info-form').style.display = 'block'; | |
| document.getElementById('fullName').value = ''; | |
| document.getElementById('className').value = ''; | |
| // Reset hoàn toàn trạng thái để lần sau làm bài không bị "dính" dữ liệu cũ | |
| try { resetQuizState(); } catch(e) {} | |
| clearCurrentSession(); | |
| } | |
| // ===== Inline Ranking (Top vinh danh) ===== | |
| function loadRankingInline() { | |
| var box = document.getElementById('ranking-inline-box'); | |
| if (!box) return; | |
| // Reset cache (per session) | |
| if (!window.__bmpRankAll) window.__bmpRankAll = []; | |
| if (!window.__bmpRankLoadedOnce) window.__bmpRankLoadedOnce = false; | |
| if (!appsScriptUrl || appsScriptUrl.indexOf('script.google.com') === -1) { | |
| box.innerHTML = '<div style="color:#c00;">Chưa cấu hình Apps Script.</div>'; | |
| return; | |
| } | |
| box.textContent = 'Đang tải xếp hạng...'; | |
| var cb = 'bmpRankInlineCb_' + String(Date.now()) + '_' + String(Math.floor(Math.random()*1e6)); | |
| window[cb] = function(resp){ | |
| try { | |
| var items = (resp && (resp.items || resp.data)) ? (resp.items || resp.data) : []; | |
| window.__bmpRankAll = Array.isArray(items) ? items : []; | |
| window.__bmpRankLoadedOnce = true; | |
| populateRankingClassOptions(window.__bmpRankAll); | |
| applyRankingInlineFilters(); | |
| } finally { | |
| try { delete window[cb]; } catch(e) { window[cb]=undefined; } | |
| } | |
| }; | |
| // Lấy dư dữ liệu (limit lớn) để lọc theo lớp + top ở phía client | |
| var url = appsScriptUrl + '?mode=rank&quizId=' + encodeURIComponent(quizId) + '&limit=200&callback=' + encodeURIComponent(cb); | |
| var s = document.createElement('script'); | |
| s.src = url; | |
| s.onerror = function(){ box.innerHTML = '<div style="color:#c00;">Không tải được xếp hạng.</div>'; }; | |
| document.body.appendChild(s); | |
| } | |
| // Populate select lớp từ dữ liệu xếp hạng | |
| function populateRankingClassOptions(items) { | |
| try { | |
| var sel = document.getElementById('lbClassSelect'); | |
| if (!sel) return; | |
| var current = sel.value || 'TẤT CẢ'; | |
| // Collect unique class names | |
| var map = {}; | |
| for (var i=0; i<(items||[]).length; i++){ | |
| var it = items[i] || {}; | |
| var cls = it.className || it.class || it.lop || it.class_id || ''; | |
| cls = String(cls || '').trim(); | |
| if (cls) map[cls] = true; | |
| } | |
| var classes = Object.keys(map).sort(function(a,b){ return a.localeCompare(b,'vi'); }); | |
| // Rebuild options (keep "TẤT CẢ" first) | |
| var html = '<option value="TẤT CẢ">TẤT CẢ</option>'; | |
| for (var j=0; j<classes.length; j++){ | |
| var c = _escapeHtml(classes[j]); | |
| html += '<option value="'+c+'">'+c+'</option>'; | |
| } | |
| sel.innerHTML = html; | |
| // Restore selection if possible | |
| var found = false; | |
| for (var k=0; k<sel.options.length; k++){ | |
| if (sel.options[k].value === current){ found = true; break; } | |
| } | |
| sel.value = found ? current : 'TẤT CẢ'; | |
| } catch(e){} | |
| } | |
| function _rankPick(it, a, b, c){ | |
| try{ | |
| if (it && it[a]!=null) return it[a]; | |
| if (it && it[b]!=null) return it[b]; | |
| if (it && it[c]!=null) return it[c]; | |
| }catch(e){} | |
| return null; | |
| } | |
| // Apply filters from selects and render inline ranking | |
| function applyRankingInlineFilters() { | |
| var box = document.getElementById('ranking-inline-box'); | |
| if (!box) return; | |
| var items = window.__bmpRankAll || []; | |
| if (!items.length) { | |
| box.innerHTML = '<div style="color:#666;">Chưa có dữ liệu xếp hạng.</div>'; | |
| return; | |
| } | |
| var clsSel = document.getElementById('lbClassSelect'); | |
| var topSel = document.getElementById('lbTopSelect'); | |
| var clsFilter = clsSel ? String(clsSel.value || 'TẤT CẢ').trim() : 'TẤT CẢ'; | |
| var limit = topSel ? parseInt(String(topSel.value||'10'), 10) : 10; | |
| if (!isFinite(limit) || limit <= 0) limit = 10; | |
| // Filter by class | |
| var filtered = []; | |
| for (var i=0; i<items.length; i++){ | |
| var it = items[i] || {}; | |
| var cls = String(_rankPick(it,'className','class','lop') || '').trim(); | |
| if (clsFilter === 'TẤT CẢ' || cls === clsFilter) filtered.push(it); | |
| } | |
| if (!filtered.length) { | |
| box.innerHTML = '<div style="color:#666;">Chưa có bài nộp để vinh danh.</div>'; | |
| return; | |
| } | |
| // Sort: score desc, time asc | |
| filtered.sort(function(a,b){ | |
| var sa = Number(_rankPick(a,'score','totalScore','diem') || 0); | |
| var sb = Number(_rankPick(b,'score','totalScore','diem') || 0); | |
| if (sb !== sa) return (sb - sa); | |
| var ta = Number(_rankPick(a,'totalTime','timeSec','t') || 0); | |
| var tb = Number(_rankPick(b,'totalTime','timeSec','t') || 0); | |
| return (ta - tb); | |
| }); | |
| var view = filtered.slice(0, Math.min(limit, filtered.length)); | |
| renderRankingInline({ items: view }, clsFilter, limit); | |
| } | |
| function renderRankingInline(resp, clsFilter, limit) { | |
| var box = document.getElementById('ranking-inline-box'); | |
| if (!box) return; | |
| var items = (resp && (resp.items || resp.data)) ? (resp.items || resp.data) : []; | |
| if (!items.length) { | |
| box.innerHTML = '<div style="color:#666;">Chưa có dữ liệu xếp hạng.</div>'; | |
| return; | |
| } | |
| // Header line | |
| var title = ''; | |
| try { | |
| if (clsFilter && clsFilter !== 'TẤT CẢ') title = 'Lớp <strong>' + _escapeHtml(clsFilter) + '</strong>'; | |
| else title = 'Tất cả lớp'; | |
| if (limit) title += ' • Top ' + String(limit); | |
| } catch(e){} | |
| var html = '<div style="margin-bottom:6px; color:#6b7280; font-weight:800;">'+title+'</div>'; | |
| html += '<ol style="margin:0; padding-left:18px;">'; | |
| for (var i=0; i<items.length; i++){ | |
| var it = items[i] || {}; | |
| var name = String(_rankPick(it,'name','studentName','fullName') || '').trim(); | |
| var cls = String(_rankPick(it,'className','class','lop') || '').trim(); | |
| var score = _rankPick(it,'score','totalScore','diem'); | |
| var tsec = _rankPick(it,'totalTime','timeSec','t'); | |
| name = _escapeHtml(name); | |
| cls = _escapeHtml(cls); | |
| var scoreText = (score==null || score===undefined) ? '' : _escapeHtml(String(score)); | |
| var medal = (i===0?'🥇':(i===1?'🥈':(i===2?'🥉':''))); | |
| html += '<li style="margin:6px 0;">' + | |
| '<strong>'+medal+' '+name+'</strong>' + | |
| (cls?(' <span style="color:#6b7280;">('+cls+')</span>'):'') + | |
| (scoreText?(' — <span style="color:#111; font-weight:900;">'+scoreText+'</span>đ'):''); | |
| if (tsec!=null && tsec!==undefined && String(tsec)!=='') { | |
| html += ' • <span style="color:#666;">'+fmtDurationSec(Number(tsec))+'</span>'; | |
| } | |
| html += '</li>'; | |
| } | |
| html += '</ol>'; | |
| box.innerHTML = html; | |
| } | |
| function renderLoginRanking(resp) { | |
| var box = document.getElementById('login-ranking-box'); | |
| if (!box) return; | |
| var items = (resp && (resp.items || resp.data)) ? (resp.items || resp.data) : []; | |
| if (!items.length) { | |
| box.innerHTML = '<div style="color:#666;">Chưa có bài nộp để vinh danh.</div>'; | |
| return; | |
| } | |
| function pick(it, keyA, keyB, keyC){ | |
| return (it && it[keyA]!=null)? it[keyA] : ((it && it[keyB]!=null)? it[keyB] : (it? it[keyC]: null)); | |
| } | |
| var html = ''; | |
| html += '<div class="lb-podium">'; | |
| for (var i=0; i<3 && i<items.length; i++){ | |
| var it = items[i] || {}; | |
| var name = _escapeHtml(String(pick(it,'name','studentName','fullName') || '')); | |
| var cls = _escapeHtml(String(pick(it,'className','class','lop') || '')); | |
| var score = pick(it,'score','totalScore','diem'); | |
| var tsec = pick(it,'totalTime','timeSec','t'); | |
| var medal = (i===0?'🥇':(i===1?'🥈':'🥉')); | |
| html += '<div class="lb-pill">' + | |
| '<div class="lb-rank">'+medal+' TOP '+(i+1)+'</div>' + | |
| '<div class="lb-name">'+name+'</div>' + | |
| '<div class="lb-meta">'+(cls?('('+cls+')'):'')+'</div>' + | |
| '<div class="lb-score">' | |
| + (score!=null ? ('<span class="lb-score-val">'+_escapeHtml(String(score))+'đ</span>') : '') | |
| + (tsec!=null ? (' <span class="lb-time">• '+_escapeHtml(fmtDurationSec(Number(tsec)))+'</span>') : '') | |
| + '</div>' + | |
| '</div>'; | |
| } | |
| html += '</div>'; | |
| if (items.length > 3) { | |
| html += '<ol class="lb-list" start="4">'; | |
| for (var j=3; j<items.length; j++){ | |
| var it2 = items[j] || {}; | |
| var name2 = _escapeHtml(String(pick(it2,'name','studentName','fullName') || '')); | |
| var cls2 = _escapeHtml(String(pick(it2,'className','class','lop') || '')); | |
| var score2 = pick(it2,'score','totalScore','diem'); | |
| var tsec2 = pick(it2,'totalTime','timeSec','t'); | |
| html += '<li><strong style="color:#111;">'+name2+'</strong> ' + | |
| (cls2?('<span style="color:#6b7280;">('+cls2+')</span> '):'') + | |
| '— <span style="font-weight:900; color:#7c2d12;">'+(score2!=null?score2:'')+'đ</span>' + | |
| (tsec2!=null?(' <span style="color:#6b7280;">• '+fmtDurationSec(Number(tsec2))+'</span>'):'') + | |
| '</li>'; | |
| } | |
| html += '</ol>'; | |
| } | |
| box.innerHTML = html; | |
| try { setTimeout(fitTopPodiumNames, 0); } catch(e) {} | |
| } | |
| function fitTopPodiumNames(){ | |
| try{ | |
| var nodes = document.querySelectorAll('.lb-podium .lb-pill:nth-child(-n+3) .lb-name'); | |
| if (!nodes || !nodes.length) return; | |
| for (var i = 0; i < nodes.length; i++) { | |
| var el = nodes[i]; | |
| if (!el) continue; | |
| var txt = (el.textContent || '').trim(); | |
| // Show full name (no ellipsis), allow wrapping. | |
| el.style.whiteSpace = 'normal'; | |
| el.style.overflow = 'visible'; | |
| el.style.textOverflow = 'unset'; | |
| el.style.maxWidth = '100%'; | |
| el.style.wordBreak = 'break-word'; | |
| el.style.overflowWrap = 'anywhere'; | |
| el.style.lineHeight = '1.15'; | |
| // Auto reduce font size a bit for very long names. | |
| var base = 13; | |
| if (txt.length > 34) base = 10; | |
| else if (txt.length > 28) base = 11; | |
| else if (txt.length > 22) base = 12; | |
| el.style.fontSize = base + 'px'; | |
| } | |
| } catch (e) {} | |
| } | |
| function openFullRanking(){ | |
| var modal = document.getElementById('lb-modal'); | |
| var content = document.getElementById('lb-modal-content'); | |
| var items = (window.__LAST_LOGIN_RANKING__ || []); | |
| if (!modal || !content) return; | |
| if (!items.length){ | |
| content.innerHTML = '<div style="color:#6b7280;">Chưa có dữ liệu xếp hạng.</div>'; | |
| } else { | |
| var rows = ''; | |
| rows += '<table class="lb-modal-table"><thead><tr><th>Hạng</th><th>Họ và tên</th><th>Lớp</th><th>Điểm</th><th>Thời gian</th></tr></thead><tbody>'; | |
| for (var i=0; i<items.length; i++){ | |
| var it = items[i] || {}; | |
| var name = _escapeHtml(String((it.name||it.studentName||it.fullName||'') )); | |
| var cls = _escapeHtml(String((it.className||it.class||it.lop||'') )); | |
| var score = (it.score!=null?it.score:(it.totalScore!=null?it.totalScore:it.diem)); | |
| var tsec = (it.totalTime!=null?it.totalTime:(it.timeSec!=null?it.timeSec:it.t)); | |
| rows += '<tr>' + | |
| '<td style="font-weight:950;">'+(i+1)+'</td>' + | |
| '<td>'+name+'</td>' + | |
| '<td>'+cls+'</td>' + | |
| '<td style="font-weight:950; color:#7c2d12;">'+(score!=null?(String(score)+'đ'):'')+'</td>' + | |
| '<td>'+(tsec!=null?fmtDurationSec(Number(tsec)):'')+'</td>' + | |
| '</tr>'; | |
| } | |
| rows += '</tbody></table>'; | |
| content.innerHTML = rows; | |
| } | |
| modal.classList.add('show'); | |
| } | |
| function closeFullRanking(){ | |
| var modal = document.getElementById('lb-modal'); | |
| if (modal) modal.classList.remove('show'); | |
| } | |
| function loadLoginRanking() { | |
| var box = document.getElementById('login-ranking-box'); | |
| if (!box) return; | |
| if (!appsScriptUrl || appsScriptUrl.indexOf('http') !== 0) { | |
| box.innerHTML = '<div style="color:#c00;">Chưa cấu hình Apps Script URL.</div>'; | |
| return; | |
| } | |
| var quizId = String((window.currentQuizId || "") || ""); | |
| var limit = (function(){ | |
| try{ | |
| var el=document.getElementById('lbLimitSel'); | |
| var v=el?Number(el.value):10; | |
| if(!v||!isFinite(v)) v=10; | |
| try{ | |
| var st=document.getElementById('lb-subtext'); | |
| if(st){ | |
| st.textContent = 'Top '+String(v)+' điểm cao • nhanh hơn xếp trên'; | |
| /* Nếu Blogspot/đoạn khác lỡ đưa entity dạng "•" thì ép về ký tự • */ | |
| st.textContent = String(st.textContent).replace(/•/g,'•'); | |
| } | |
| }catch(e){} | |
| return v; | |
| }catch(e){return 10;} | |
| })(); | |
| box.textContent = 'Đang tải xếp hạng...'; | |
| // JSONP để vượt CORS | |
| var cb = 'bmpLoginRankCb_' + String(Date.now()) + '_' + String(Math.floor(Math.random()*1e6)); | |
| window[cb] = function(resp) { | |
| try { renderLoginRanking(resp); } | |
| finally { try { delete window[cb]; } catch(e) { window[cb] = undefined; } } | |
| }; | |
| var url = appsScriptUrl; | |
| url += (url.indexOf('?') >= 0 ? '&' : '?') + | |
| 'mode=rank' + | |
| '&quizId=' + encodeURIComponent(quizId) + | |
| '&limit=' + encodeURIComponent(String(limit)) + | |
| '&callback=' + encodeURIComponent(cb); | |
| var s = document.createElement('script'); | |
| s.src = url; | |
| s.async = true; | |
| s.onload = function(){ try{ if(s && s.parentNode) s.parentNode.removeChild(s); }catch(e){} }; | |
| s.onerror = function(){ | |
| box.innerHTML = '<div style="color:#666;">Không tải được xếp hạng (kiểm tra mạng).</div>'; | |
| try { delete window[cb]; } catch(e) {} | |
| }; | |
| document.body.appendChild(s); | |
| } | |
| // ===== BLOGSPOT MOBILE FIX: decode bullet entities that get double-escaped ===== | |
| (function(){ | |
| function decodeBulletEntities(){ | |
| try{ | |
| var lb = document.getElementById('lb-subtext'); | |
| if(lb){ | |
| var t = lb.innerHTML || lb.textContent || ''; | |
| t = String(t).replace(/&#8226;|•|&#x2022;|•/g, '•'); | |
| // Use textContent to avoid Blogspot escaping again | |
| lb.textContent = t.replace(/\s+/g,' ').replace(/ \• /g,' • '); | |
| } | |
| // Walk text nodes across body to catch cases where Blogspot escaped into plain text | |
| var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false); | |
| var node; | |
| while((node = walker.nextNode())){ | |
| var v = node.nodeValue; | |
| if(!v) continue; | |
| if(v.indexOf('#8226') !== -1 || v.indexOf('#x2022') !== -1 || v.indexOf('&#8226') !== -1){ | |
| node.nodeValue = String(v).replace(/&#8226;|•|&#x2022;|•/g, '•'); | |
| } | |
| } | |
| }catch(e){} | |
| } | |
| if (document.readyState === 'loading') { | |
| document.addEventListener('DOMContentLoaded', function(){ | |
| decodeBulletEntities(); | |
| setTimeout(decodeBulletEntities, 200); | |
| setTimeout(decodeBulletEntities, 800); | |
| }); | |
| } else { | |
| decodeBulletEntities(); | |
| setTimeout(decodeBulletEntities, 200); | |
| setTimeout(decodeBulletEntities, 800); | |
| } | |
| window.addEventListener('load', function(){ | |
| decodeBulletEntities(); | |
| setTimeout(decodeBulletEntities, 200); | |
| }); | |
| })(); | |
| // ===== End BLOGSPOT MOBILE FIX ===== | |
| // ===== Auto-load Top Vinh Danh on Login Screen (no click needed) ===== | |
| (function(){ | |
| function _safeLoad(){ | |
| try { if (typeof loadLoginRanking === 'function') loadLoginRanking(); } catch(e) {} | |
| } | |
| if (document.readyState === 'loading') { | |
| document.addEventListener('DOMContentLoaded', function(){ | |
| _safeLoad(); | |
| setTimeout(_safeLoad, 800); | |
| }); | |
| } else { | |
| _safeLoad(); | |
| setTimeout(_safeLoad, 800); | |
| } | |
| // refresh leaderboard periodically | |
| setInterval(_safeLoad, 30000); | |
| })(); | |
| // ===== Ranking (Leaderboard) via Apps Script JSONP ===== | |
| function openRankingModal() { | |
| try { | |
| document.getElementById('ranking-modal').style.display = 'flex'; | |
| loadRanking(); | |
| } catch(e) {} | |
| } | |
| function closeRankingModal() { | |
| try { document.getElementById('ranking-modal').style.display = 'none'; } catch(e) {} | |
| } | |
| function _escapeHtml(s) { | |
| s = String(s || ""); | |
| return s.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"); | |
| } | |
| function loadRanking() { | |
| var box = document.getElementById('ranking-content'); | |
| if (!box) return; | |
| if (!appsScriptUrl || appsScriptUrl.indexOf('http') !== 0) { | |
| box.innerHTML = '<div style="color:#c00;">Chưa cấu hình Apps Script URL để lấy xếp hạng.</div>'; | |
| return; | |
| } | |
| var quizId = String((window.currentQuizId || "1769689416016") || ""); | |
| var limit = (function(){try{var el=document.getElementById('lbLimitSel');var v=el?Number(el.value):10;if(!v||!isFinite(v)) v=10;return v;}catch(e){return 10;}})(); | |
| box.innerHTML = '<div style="color:#666;">Đang tải xếp hạng...</div>'; | |
| // JSONP để vượt CORS trên Blogspot | |
| var cbName = "__bmp_rank_cb_" + (new Date().getTime()); | |
| window[cbName] = function(resp) { | |
| try { | |
| renderRanking(resp); | |
| } finally { | |
| try { delete window[cbName]; } catch(e) { window[cbName] = null; } | |
| } | |
| }; | |
| var url = appsScriptUrl; | |
| url += (url.indexOf('?') >= 0 ? '&' : '?') + | |
| 'mode=rank' + | |
| '&quizId=' + encodeURIComponent(quizId) + | |
| '&limit=' + encodeURIComponent(String(limit)) + | |
| '&callback=' + encodeURIComponent(cbName); | |
| var s = document.createElement('script'); | |
| s.src = url; | |
| s.async = true; | |
| s.onerror = function() { | |
| box.innerHTML = '<div style="color:#c00;">Không tải được xếp hạng. Vui lòng kiểm tra deploy Apps Script.</div>'; | |
| }; | |
| document.body.appendChild(s); | |
| } | |
| function renderRanking(resp) { | |
| var box = document.getElementById('ranking-content'); | |
| if (!box) return; | |
| if (!resp || resp.ok === false) { | |
| box.innerHTML = '<div style="color:#c00;">Không có dữ liệu xếp hạng.</div>'; | |
| return; | |
| } | |
| var items = resp.items || resp.data || []; | |
| if (!items.length) { | |
| box.innerHTML = '<div style="color:#666;">Chưa có bài nộp để xếp hạng.</div>'; | |
| return; | |
| } | |
| var html = '<table style="width:100%; border-collapse:collapse;">' + | |
| '<tr>' + | |
| '<th style="text-align:left; padding:8px; border-bottom:1px solid #ddd;">#</th>' + | |
| '<th style="text-align:left; padding:8px; border-bottom:1px solid #ddd;">Họ tên</th>' + | |
| '<th style="text-align:left; padding:8px; border-bottom:1px solid #ddd;">Lớp</th>' + | |
| '<th style="text-align:right; padding:8px; border-bottom:1px solid #ddd;">Điểm</th>' + | |
| '<th style="text-align:right; padding:8px; border-bottom:1px solid #ddd;">Thời gian</th>' + | |
| '</tr>'; | |
| for (var i=0; i<items.length; i++) { | |
| var it = items[i] || {}; | |
| html += '<tr>' + | |
| '<td style="padding:8px; border-bottom:1px solid #eee;">' + _escapeHtml(it.rank || (i+1)) + '</td>' + | |
| '<td style="padding:8px; border-bottom:1px solid #eee;">' + _escapeHtml(it.name || it.studentName || "") + '</td>' + | |
| '<td style="padding:8px; border-bottom:1px solid #eee;">' + _escapeHtml(it.className || it.class || "") + '</td>' + | |
| '<td style="padding:8px; border-bottom:1px solid #eee; text-align:right;">' + _escapeHtml(it.score) + '</td>' + | |
| '<td style="padding:8px; border-bottom:1px solid #eee; text-align:right;">' + _escapeHtml(it.time || it.totalTimeText || "") + '</td>' + | |
| '</tr>'; | |
| } | |
| html += '</table>'; | |
| box.innerHTML = html; | |
| } | |
| // Show success modal với điểm số | |
| function showSuccessModal() { | |
| const results = window.quizResults; | |
| document.getElementById('final-score').textContent = results.totalScore + ' điểm'; | |
| document.getElementById('success-modal').style.display = 'flex'; | |
| } | |
| function closeSuccessModal() { | |
| document.getElementById('success-modal').style.display = 'none'; | |
| showResults(false); | |
| } | |
| // Show history - ĐÃ SỬA: Sắp xếp lịch sử đúng thứ tự (mới nhất lên đầu) | |
| function showHistory() { | |
| const history = loadQuizHistory(); | |
| let html = ` | |
| <div class="history-container"> | |
| <h3 style="color: var(--primary-color); margin-bottom: 20px; text-align: center;">📋 LỊCH SỬ LÀM BÀI</h3> | |
| `; | |
| if (history.length === 0) { | |
| html += `<p style="text-align: center; color: #666; padding: 20px;">Chưa có lịch sử làm bài</p>`; | |
| } else { | |
| // SỬA LỖI: Sắp xếp lịch sử theo thời gian mới nhất trước (giảm dần) | |
| const sortedHistory = history.slice().sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp)); | |
| sortedHistory.forEach((record, index) => { | |
| const date = new Date(record.timestamp).toLocaleString('vi-VN'); | |
| const timeSpent = `${Math.floor(record.totalTime / 60)} phút ${record.totalTime % 60} giây`; | |
| const security = record.securityInfo || {}; | |
| // Tính số thứ tự (lần làm thứ mấy) - LẦN 1 Ở DƯỚI CÙNG, MỚI NHẤT Ở TRÊN CÙNG | |
| const attemptNumber = sortedHistory.length - index; | |
| let securityStatus = 'success'; | |
| let securityMessage = 'Bình thường'; | |
| if (record.autoSubmit) { | |
| securityStatus = 'error'; | |
| securityMessage = `🚨 Tự động nộp: ${record.autoSubmit}`; | |
| } else if (security.screenExitCount > 3) { | |
| securityStatus = 'warning'; | |
| securityMessage = `⚠️ Có ${security.screenExitCount} lần rời màn hình`; | |
| } | |
| html += ` | |
| <div class="history-item"> | |
| <div class="history-header"> | |
| <div> | |
| <h4>${record.studentName}</h4> | |
| <div style="color: #666; font-size: 0.9rem;">Lớp: ${record.className}</div> | |
| <div style="color: #999; font-size: 0.8rem; margin-top: 3px;">Lần làm thứ: ${attemptNumber}</div> | |
| </div> | |
| <div class="history-score">${record.score} điểm</div> | |
| </div> | |
| <div class="history-time">${date}</div> | |
| <div class="security-info ${securityStatus}"> | |
| <strong>🔒 TRẠNG THÁI BẢO MẬT:</strong> ${securityMessage}<br> | |
| <small>Số lần rời màn hình: ${security.screenExitCount || 0} | | |
| Thời gian rời: ${security.totalHiddenTime || 0}s</small> | |
| </div> | |
| <div class="history-details"> | |
| <div class="history-detail">⏱️ Thời gian: ${timeSpent}</div> | |
| <div class="history-detail">📊 Số câu: ${record.quizData.length}</div> | |
| <div class="history-detail">✅ Hoàn thành: ${Object.values(record.userAnswers).filter(ans => | |
| (ans.type === 1 && ans.answer !== null) || | |
| (ans.type === 2 && ans.answers.some(a => a !== null)) || | |
| (ans.type === 3 && ans.answer.trim() !== "") | |
| ).length}/${record.quizData.length}</div> </div> | |
| <!-- QUAN TRỌNG: CHỈ HIỆN NÚT XEM CHI TIẾT KHI allow_view_detail = true --> | |
| ${allow_view_detail === true ? ` | |
| <button class="nav-btn" style="margin-top: 10px; width: 100%;" | |
| onclick="viewHistoryDetail(${index})">📖 Xem chi tiết</button> | |
| ` : ` | |
| <div class="security-info warning" style="margin-top: 10px;"> | |
| <strong>⚠️ CHỨC NĂNG ĐÃ BỊ VÔ HIỆU HÓA</strong><br> | |
| <small>Giáo viên đã tắt tính năng xem chi tiết bài làm</small> | |
| </div> | |
| `} | |
| </div> | |
| `; | |
| }); | |
| } | |
| html += `</div>`; | |
| document.getElementById('history-content').innerHTML = html; | |
| document.getElementById('history-modal').style.display = 'flex'; | |
| } | |
| // View history detail - ĐÃ SỬA LỖI HIỂN THỊ ĐÚNG BÀI THI | |
| function viewHistoryDetail(historyIndex) { | |
| // KIỂM TRA XEM CÓ ĐƯỢC PHÉP XEM CHI TIẾT KHÔNG | |
| if (allow_view_detail !== true) { | |
| alert("⚠️ Chức năng xem chi tiết bài làm đã bị vô hiệu hóa bởi giáo viên!"); | |
| return; | |
| } | |
| const history = loadQuizHistory(); | |
| // SỬA LỖI: Sắp xếp lịch sử theo thời gian mới nhất trước (giống showHistory) | |
| const sortedHistory = history.slice().sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp)); | |
| // Đảm bảo index hợp lệ | |
| if (historyIndex < 0 || historyIndex >= sortedHistory.length) { | |
| alert("Không tìm thấy dữ liệu bài làm!"); | |
| return; | |
| } | |
| const record = sortedHistory[historyIndex]; | |
| // QUAN TRỌNG: Tìm bản ghi gốc từ history (chưa sắp xếp) dựa trên sessionId | |
| // Điều này đảm bảo chúng ta lấy đúng bản ghi với dữ liệu đầy đủ | |
| const originalRecord = history.find(item => item.sessionId === record.sessionId); | |
| // Nếu không tìm thấy bản ghi gốc, sử dụng record đã tìm được | |
| const displayRecord = originalRecord || record; | |
| // Tạo modal hiển thị chi tiết | |
| showHistoryDetailModal(displayRecord, historyIndex, sortedHistory.length); | |
| } | |
| // Hàm mới để hiển thị modal chi tiết - TÁCH RIÊNG ĐỂ DỄ QUẢN LÝ | |
| function showHistoryDetailModal(record, historyIndex, totalRecords) { | |
| const security = record.securityInfo || {}; | |
| // Tính số thứ tự (lần làm thứ mấy) - mới nhất là 1 | |
| const attemptNumber = totalRecords - historyIndex; | |
| // Tạo sessionId duy nhất để phân biệt rõ ràng | |
| const uniqueSessionId = record.sessionId || (record.timestamp + "_" + record.studentName); | |
| // KIỂM TRA DỮ LIỆU | |
| console.log("DEBUG - Chi tiết bài làm:", { | |
| sessionId: record.sessionId, | |
| timestamp: record.timestamp, | |
| studentName: record.studentName, | |
| quizDataLength: (record.quizData && record.quizData.length ? record.quizData.length : 0), | |
| userAnswersLength: record.userAnswers ? Object.keys(record.userAnswers).length : 0 | |
| }); | |
| let html = ` | |
| <div class="results-container" style="width: 100%; max-width: 100%;"> | |
| <div class="results-header"> | |
| <h2 style="font-size: 1.5rem; text-align: center;">📊 CHI TIẾT BÀI LÀM</h2> | |
| <div style="color: #666; font-size: 0.9rem; margin-top: 5px;"> | |
| ID: ${uniqueSessionId} | Lần làm thứ: ${attemptNumber} | |
| </div> | |
| <div style="color: #999; font-size: 0.8rem; margin-top: 3px;"> | |
| Thời gian: ${new Date(record.timestamp).toLocaleString('vi-VN')} | |
| </div> | |
| </div> | |
| <div class="time-info" style="margin: 15px 0; padding: 15px;"> | |
| <p><strong>Họ và tên:</strong> ${record.studentName}</p> | |
| <p><strong>Lớp:</strong> ${record.className}</p> | |
| <p><strong>Thời gian làm bài:</strong> ${new Date(record.timestamp).toLocaleString('vi-VN')}</p> | |
| <p><strong>Tổng thời gian làm bài:</strong> ${Math.floor(record.totalTime / 60)} phút ${record.totalTime % 60} giây</p> | |
| <p><strong>Tổng điểm:</strong> <span style="color: var(--success-color); font-weight: bold; font-size: 1.2rem;">${record.score}</span></p> | |
| <p><strong>Số lần rời màn hình:</strong> ${security.screenExitCount || 0}</p> | |
| <p><strong>Tổng thời gian rời màn hình:</strong> ${security.totalHiddenTime || 0} giây</p> | |
| ${record.autoSubmit ? `<p><strong>Lý do nộp bài:</strong> <span style="color: #e74c3c; font-weight: bold;">${record.autoSubmit}</span></p>` : ''} | |
| ${record.hiddenDuration ? `<p><strong>Thời gian rời cuối cùng:</strong> ${Math.floor(record.hiddenDuration / 60)} phút ${record.hiddenDuration % 60} giây</p>` : ''} | |
| </div> | |
| <div style="overflow-x: auto; width: 100%;"> | |
| <table class="results-table" style="min-width: 800px; width: 100%;"> | |
| <thead> | |
| <tr> | |
| <th style="min-width: 50px;">Câu</th> | |
| <th style="min-width: 300px;">Nội dung câu hỏi</th> | |
| <th style="min-width: 150px;">Đáp án của bạn</th> | |
| <th style="min-width: 150px;">Đáp án đúng</th> | |
| <th style="min-width: 60px;">Điểm</th> | |
| <th style="min-width: 80px;">Kết quả</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| `; | |
| // Đảm bảo record.quizData tồn tại | |
| if (!record.quizData || !Array.isArray(record.quizData)) { | |
| html += ` | |
| <tr> | |
| <td colspan="7" style="text-align: center; color: #999; padding: 20px;"> | |
| Không có dữ liệu câu hỏi chi tiết | |
| </td> | |
| </tr> | |
| `; | |
| } else { | |
| // QUAN TRỌNG: Sử dụng đúng record được truyền vào (không phải từ sortedHistory) | |
| record.quizData.forEach((q, index) => { | |
| const qIndex = index + 1; | |
| const userAnswer = record.userAnswers ? record.userAnswers[qIndex] : null; | |
| if (!q || !userAnswer) { | |
| html += ` | |
| <tr> | |
| <td>${qIndex}</td> | |
| <td colspan="6" style="color: #999;">Không có dữ liệu</td> | |
| </tr> | |
| `; | |
| return; | |
| } | |
| if (q.type === "type1") { | |
| const correctOptionIndex = q.options ? q.options.findIndex(opt => opt.is_correct === 1) : -1; | |
| const userAnswerText = (userAnswer && userAnswer.answer !== null && userAnswer.answer !== undefined) ? (String.fromCharCode(65 + userAnswer.answer) + '.') : ''; | |
| const correctAnswerText = (correctOptionIndex >= 0) ? (String.fromCharCode(65 + correctOptionIndex) + '.') : ''; | |
| const userAnswerDetail = userAnswer.answer !== null && q.options && q.options[userAnswer.answer] ? q.options[userAnswer.answer].text : "Chưa trả lời"; | |
| const correctAnswerDetail = correctOptionIndex >= 0 && q.options && q.options[correctOptionIndex] ? q.options[correctOptionIndex].text : "Không xác định"; | |
| html += ` | |
| <tr class="${userAnswer.correct ? 'correct-row' : 'wrong-row'}"> | |
| <td>${qIndex}</td> | |
| <td><strong>Câu hỏi:</strong> <div class="question-detail-content">${formatQuestionContent(q.question || '')}</div><br> | |
| ${q.options ? q.options.map((opt, idx) => | |
| `<div class="option-line question-detail-content">${String.fromCharCode(65 + idx)}. ${formatQuestionContent(opt.text || '')} ${opt.is_correct ? '✓' : ''}</div>` | |
| ).join('') : ''} | |
| </td> | |
| <td class="${userAnswer.correct ? 'correct-answer' : 'wrong-answer'}"> | |
| ${userAnswerText} | |
| </td> | |
| <td>${correctAnswerText}</td> | |
| <td>${userAnswer.score || 0}</td> | |
| <td class="${userAnswer.correct ? 'correct-answer' : 'wrong-answer'}">${userAnswer.correct ? 'Đ' : 'S'}</td> | |
| </tr> | |
| `; | |
| } else if (q.type === "type2") { | |
| const userAnswersText = userAnswer.answers ? userAnswer.answers.map((ans, i) => | |
| ans !== null ? `${String.fromCharCode(97 + i)}) ${ans}` : `${String.fromCharCode(97 + i)}) Chưa trả lời` | |
| ).join('<br>') : "Không có dữ liệu"; | |
| const correctAnswersText = q.answers ? q.answers.map((ans, i) => | |
| `${String.fromCharCode(97 + i)}) ${ans}` | |
| ).join('<br>') : "Không có dữ liệu"; | |
| const statementsDetail = q.statements ? q.statements.map((stmt, i) => | |
| `<div class="option-line question-detail-content">${String.fromCharCode(97 + i)}) ${formatQuestionContent(stmt || '')}</div>` | |
| ).join('') : ''; | |
| html += ` | |
| <tr class="${userAnswer.correct ? 'correct-row' : 'wrong-row'}"> | |
| <td>${qIndex}</td> | |
| <td><strong>Câu hỏi:</strong> <div class="question-detail-content">${formatQuestionContent(q.question || '')}</div><br>${statementsDetail}</td> | |
| <td class="${userAnswer.correct ? 'correct-answer' : 'wrong-answer'}">${userAnswersText}</td> | |
| <td>${correctAnswersText}</td> | |
| <td>${userAnswer.score || 0}</td> | |
| <td class="${userAnswer.correct ? 'correct-answer' : 'wrong-answer'}"> | |
| ${userAnswer.correct ? '✓ Đúng' : `✗ Sai (${userAnswer.correctCount || 0}/${userAnswer.totalStatements || 0})`} | |
| </td> | |
| </tr> | |
| `; | |
| } else if (q.type === "type3") { | |
| const userAnswerText = userAnswer.answer || "Chưa trả lời"; | |
| html += ` | |
| <tr class="${userAnswer.correct ? 'correct-row' : 'wrong-row'}"> | |
| <td>${qIndex}</td> | |
| <td><strong>Câu hỏi:</strong> <div class="question-detail-content">${formatQuestionContent(q.question || '')}</div></td> | |
| <td class="${userAnswer.correct ? 'correct-answer' : 'wrong-answer'}">${userAnswerText}</td> | |
| <td>${q.answer || "Không có đáp án"}</td> | |
| <td>${userAnswer.score || 0}</td> | |
| <td class="${userAnswer.correct ? 'correct-answer' : 'wrong-answer'}">${userAnswer.correct ? 'Đ' : 'S'}</td> | |
| </tr> | |
| `; | |
| } | |
| }); | |
| } | |
| html += ` | |
| </tbody> | |
| </table> | |
| </div> | |
| `; | |
| const detailModal = document.createElement('div'); | |
| detailModal.className = 'modal-overlay'; | |
| detailModal.style.display = 'flex'; | |
| detailModal.style.alignItems = 'flex-start'; | |
| detailModal.style.paddingTop = '20px'; | |
| detailModal.innerHTML = ` | |
| <div class="modal-dialog" style="max-width: 95vw; width: 95vw; max-height: 90vh; overflow-y: auto; margin: 0 auto;"> | |
| <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;"> | |
| <h3 style="margin: 0; color: var(--primary-color);">📊 CHI TIẾT BÀI LÀM - LẦN ${attemptNumber}</h3> | |
| <button onclick="this.closest('.modal-overlay').remove()" | |
| style="background: var(--danger-color); color: white; border: none; border-radius: 50%; width: 30px; height: 30px; cursor: pointer; font-weight: bold;"> | |
| × | |
| </button> | |
| </div> | |
| <div id="history-detail-content" style="width: 100%;">${html}</div> | |
| </div> | |
| `; | |
| document.body.appendChild(detailModal); | |
| setTimeout(() => { | |
| refreshMathJax(); | |
| }, 500); | |
| } | |
| function closeHistoryModal() { | |
| document.getElementById('history-modal').style.display = 'none'; | |
| } | |
| // Mobile controls | |
| function toggleMobileStatus() { | |
| const panel = document.getElementById('mobile-status-panel'); | |
| panel.classList.toggle('active'); | |
| } | |
| // Auto-refresh MathJax when showing questions | |
| const originalShowQuestion = showQuestion; | |
| showQuestion = function(index) { | |
| originalShowQuestion(index); | |
| setTimeout(refreshMathJax, 100); | |
| setTimeout(refreshMathJax, 500); | |
| setTimeout(refreshMathJax, 1000); | |
| }; | |
| // Initialize when page loads | |
| window.addEventListener('load', function() { | |
| // KHÔNG tự động vào màn hình làm bài / KHÔNG tự động chạy timer khi vừa mở trang. | |
| // Chỉ bắt đầu (hoặc tiếp tục) khi học sinh bấm "Bắt đầu làm bài". | |
| initQuiz(); | |
| }); | |
| function _isLoginOrDetailScreen() { | |
| try { | |
| const login = document.getElementById('user-info-form'); | |
| const detail = document.getElementById('history-detail'); | |
| const quiz = document.getElementById('quiz-section'); | |
| const loginVisible = login && login.style.display !== 'none'; | |
| const detailVisible = detail && detail.style.display !== 'none'; | |
| const quizVisible = quiz && quiz.style.display !== 'none'; | |
| return loginVisible || detailVisible || !quizVisible; | |
| } catch(e) { | |
| return false; | |
| } | |
| } | |
| // Lưu phiên làm bài khi đóng trang và cảnh báo | |
| window.addEventListener('beforeunload', function(e) { | |
| // Chỉ xử lý khi đang LÀM BÀI (màn hình câu hỏi) và CHƯA nộp | |
| if (quizInProgress && !quizSubmitted && !_isLoginOrDetailScreen() && startTime && timeLeft > 0) { | |
| // Hiển thị cảnh báo | |
| e.preventDefault(); | |
| e.returnValue = '⚠️ BÀI THI ĐANG DIỄN RA!\n\nNếu bạn rời đi, bài thi sẽ được lưu tự động.\nNếu thoát quá 5 phút, bài thi sẽ tự động nộp!'; | |
| // Lưu session trước khi đóng | |
| saveCurrentSession(); | |
| // Nếu đã thoát quá 5 phút trước đó, tự động nộp | |
| if (lastHiddenTime) { | |
| const now = new Date(); | |
| const hiddenDuration = Math.floor((now - lastHiddenTime) / 1000); | |
| if (hiddenDuration > maxHiddenAllowed) { | |
| autoSubmitDueToLongExit(); | |
| } | |
| } | |
| } | |
| }); | |
| // Xử lý khi tab bị đóng hoặc trình duyệt bị tắt | |
| window.addEventListener('pagehide', function() { | |
| // Chỉ xử lý khi đang LÀM BÀI (màn hình câu hỏi) và CHƯA nộp | |
| if (quizInProgress && !quizSubmitted && !_isLoginOrDetailScreen() && startTime && timeLeft > 0) { | |
| saveCurrentSession(); | |
| if (lastHiddenTime) { | |
| const now = new Date(); | |
| const hiddenDuration = Math.floor((now - lastHiddenTime) / 1000); | |
| if (hiddenDuration > maxHiddenAllowed) { | |
| autoSubmitDueToLongExit(); | |
| } | |
| } | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment