Files
dsProject/dsLightRag/static/YunXiao/physics_quiz.js

505 lines
20 KiB
JavaScript
Raw Normal View History

2025-08-28 08:20:31 +08:00
// 题目数据数组
const questions = [
// 简单难度题目 (5道)
{
difficulty: 'easy',
text: '下列哪个物理量是矢量?',
options: ['A. 质量', 'B. 时间', 'C. 位移', 'D. 路程'],
answer: 'C',
explanation: '矢量具有大小和方向,位移是矢量,其他选项均为标量。'
},
{
difficulty: 'easy',
text: '下列哪个物理量是矢量?',
options: ['A. 质量', 'B. 时间', 'C. 位移', 'D. 路程'],
answer: 'C',
explanation: '矢量具有大小和方向,位移是矢量,其他选项均为标量。'
},
{
difficulty: 'easy',
text: '下列哪个物理量是矢量?',
options: ['A. 质量', 'B. 时间', 'C. 位移', 'D. 路程'],
answer: 'C',
explanation: '矢量具有大小和方向,位移是矢量,其他选项均为标量。'
},
{
difficulty: 'easy',
text: '下列哪个物理量是矢量?',
options: ['A. 质量', 'B. 时间', 'C. 位移', 'D. 路程'],
answer: 'C',
explanation: '矢量具有大小和方向,位移是矢量,其他选项均为标量。'
},
{
difficulty: 'easy',
text: '下列哪个物理量是矢量?',
options: ['A. 质量', 'B. 时间', 'C. 位移', 'D. 路程'],
answer: 'C',
explanation: '矢量具有大小和方向,位移是矢量,其他选项均为标量。'
},
// 中等难度题目 (5道)
{
difficulty: 'medium',
text: '关于万有引力定律,下列说法正确的是?',
options: [
'A. 万有引力只存在于天体之间',
'B. 万有引力与物体质量成正比,与距离成反比',
'C. 万有引力的发现者是牛顿',
'D. 地球对苹果的引力大于苹果对地球的引力'
],
answer: 'C',
explanation: '万有引力存在于任何有质量的物体之间A错误万有引力与距离的平方成反比B错误牛顿发现了万有引力定律C正确物体间的引力是相互的大小相等D错误。'
},
{
difficulty: 'medium',
text: '关于万有引力定律,下列说法正确的是?',
options: [
'A. 万有引力只存在于天体之间',
'B. 万有引力与物体质量成正比,与距离成反比',
'C. 万有引力的发现者是牛顿',
'D. 地球对苹果的引力大于苹果对地球的引力'
],
answer: 'C',
explanation: '万有引力存在于任何有质量的物体之间A错误万有引力与距离的平方成反比B错误牛顿发现了万有引力定律C正确物体间的引力是相互的大小相等D错误。'
},
{
difficulty: 'medium',
text: '关于万有引力定律,下列说法正确的是?',
options: [
'A. 万有引力只存在于天体之间',
'B. 万有引力与物体质量成正比,与距离成反比',
'C. 万有引力的发现者是牛顿',
'D. 地球对苹果的引力大于苹果对地球的引力'
],
answer: 'C',
explanation: '万有引力存在于任何有质量的物体之间A错误万有引力与距离的平方成反比B错误牛顿发现了万有引力定律C正确物体间的引力是相互的大小相等D错误。'
},
{
difficulty: 'medium',
text: '关于万有引力定律,下列说法正确的是?',
options: [
'A. 万有引力只存在于天体之间',
'B. 万有引力与物体质量成正比,与距离成反比',
'C. 万有引力的发现者是牛顿',
'D. 地球对苹果的引力大于苹果对地球的引力'
],
answer: 'C',
explanation: '万有引力存在于任何有质量的物体之间A错误万有引力与距离的平方成反比B错误牛顿发现了万有引力定律C正确物体间的引力是相互的大小相等D错误。'
},
{
difficulty: 'medium',
text: '关于万有引力定律,下列说法正确的是?',
options: [
'A. 万有引力只存在于天体之间',
'B. 万有引力与物体质量成正比,与距离成反比',
'C. 万有引力的发现者是牛顿',
'D. 地球对苹果的引力大于苹果对地球的引力'
],
answer: 'C',
explanation: '万有引力存在于任何有质量的物体之间A错误万有引力与距离的平方成反比B错误牛顿发现了万有引力定律C正确物体间的引力是相互的大小相等D错误。'
},
// 困难难度题目 (5道)
{
difficulty: 'hard',
text: '相对论中质量与能量的关系表达式是?',
options: ['A. E=mc²', 'B. F=ma', 'C. E=hv', 'D. P=mv'],
answer: 'A',
explanation: '爱因斯坦的质能方程E=mc²表明质量和能量可以相互转换。'
},
{
difficulty: 'hard',
text: '相对论中质量与能量的关系表达式是?',
options: ['A. E=mc²', 'B. F=ma', 'C. E=hv', 'D. P=mv'],
answer: 'A',
explanation: '爱因斯坦的质能方程E=mc²表明质量和能量可以相互转换。'
},
{
difficulty: 'hard',
text: '相对论中质量与能量的关系表达式是?',
options: ['A. E=mc²', 'B. F=ma', 'C. E=hv', 'D. P=mv'],
answer: 'A',
explanation: '爱因斯坦的质能方程E=mc²表明质量和能量可以相互转换。'
},
{
difficulty: 'hard',
text: '相对论中质量与能量的关系表达式是?',
options: ['A. E=mc²', 'B. F=ma', 'C. E=hv', 'D. P=mv'],
answer: 'A',
explanation: '爱因斯坦的质能方程E=mc²表明质量和能量可以相互转换。'
},
{
difficulty: 'hard',
text: '相对论中质量与能量的关系表达式是?',
options: ['A. E=mc²', 'B. F=ma', 'C. E=hv', 'D. P=mv'],
answer: 'A',
explanation: '爱因斯坦的质能方程E=mc²表明质量和能量可以相互转换。'
},
];
// 当前难度级别,初始为中等
let currentDifficulty = 'medium';
// 已完成的难度
const completedDifficulties = [];
// 各难度得分情况
const scores = {
easy: { score: 0, correct: 0, incorrect: 0 },
medium: { score: 0, correct: 0, incorrect: 0 },
hard: { score: 0, correct: 0, incorrect: 0 }
};
// 学伴功能相关变量
let mediaRecorder; let audioChunks = []; let isRecording = false;
let audioElement = null; let isPlaying = false;
let currentQuestion = null;
// DOM元素
const questionContainer = document.getElementById('question-container');
const submitBtn = document.getElementById('submit-btn');
const resultSection = document.getElementById('result-section');
const totalScoreElement = document.getElementById('total-score');
const correctCountElement = document.getElementById('correct-count');
const incorrectCountElement = document.getElementById('incorrect-count');
const navigationSection = document.getElementById('navigation-section');
const navigationMessage = document.getElementById('navigation-message');
const nextBtn = document.getElementById('next-btn');
const difficultyIndicator = document.querySelector('.difficulty-indicator');
// 学伴功能DOM元素
const recordingIndicator = document.getElementById('recordingIndicator');
const thinkingIndicator = document.getElementById('thinkingIndicator');
const resultContainer = document.getElementById('resultContainer');
const asrResultText = document.getElementById('asrResultText');
const feedbackResultText = document.getElementById('feedbackResultText');
const playAudioBtn = document.getElementById('playAudioBtn');
const audioProgress = document.getElementById('audioProgress');
const progressBar = document.getElementById('progressBar');
const audioTime = document.getElementById('audioTime');
// 初始化页面
document.addEventListener('DOMContentLoaded', () => {
renderQuestions(currentDifficulty);
// 绑定学伴答疑按钮事件
document.addEventListener('click', function(e) {
if (e.target && e.target.classList.contains('ask-xueban-btn')) {
currentQuestion = {
number: e.target.dataset.question,
difficulty: e.target.dataset.difficulty
};
startRecording();
}
});
});
// 渲染指定难度的题目
function renderQuestions(difficulty) {
questionContainer.innerHTML = '';
// 筛选当前难度的题目
const filteredQuestions = questions.filter(q => q.difficulty === difficulty);
// 生成题目HTML
filteredQuestions.forEach((q, index) => {
const questionNumber = index + 1;
const questionElement = document.createElement('div');
questionElement.className = 'question';
questionElement.dataset.difficulty = q.difficulty;
questionElement.dataset.question = questionNumber;
questionElement.innerHTML = `
<div class="question-header">
<div class="question-number">${getDifficultyName(q.difficulty)}难度 - 问题 ${questionNumber}</div>
<div class="question-points">20</div>
</div>
<p class="question-text">${q.text}</p>
<div class="options">
${q.options.map((option, optIndex) => {
const optionLetter = String.fromCharCode(65 + optIndex);
return `
<div class="option">
<input type="radio" name="q${q.difficulty}-${questionNumber}" id="q${q.difficulty}-${questionNumber}-${optionLetter.toLowerCase()}" value="${optionLetter}">
<label for="q${q.difficulty}-${questionNumber}-${optionLetter.toLowerCase()}">${option}</label>
</div>
`;
}).join('')}
</div>
<div class="explanation" id="explanation-${q.difficulty}-${questionNumber}">${q.explanation}</div>
<button class="ask-xueban-btn hidden" data-question="${questionNumber}" data-difficulty="${q.difficulty}">学伴答疑</button>
`;
questionContainer.appendChild(questionElement);
});
}
// 获取难度名称
function getDifficultyName(difficulty) {
const names = {
easy: '简单',
medium: '中等',
hard: '高级'
};
return names[difficulty] || difficulty;
}
// 提交答案
submitBtn.addEventListener('click', () => {
checkAnswers();
submitBtn.disabled = true;
submitBtn.textContent = '已提交';
});
// 检查答案
function checkAnswers() {
let correctCount = 0;
let incorrectCount = 0;
let totalScore = 0;
// 获取当前难度的题目
const currentQuestions = questions.filter(q => q.difficulty === currentDifficulty);
// 检查每道题的答案
currentQuestions.forEach((q, index) => {
const questionNumber = index + 1;
const selectedOption = document.querySelector(`input[name="q${q.difficulty}-${questionNumber}"]:checked`);
const explanationElement = document.getElementById(`explanation-${q.difficulty}-${questionNumber}`);
const optionsContainer = document.querySelector(`div[data-difficulty="${q.difficulty}"][data-question="${questionNumber}"] .options`);
const allOptions = optionsContainer.querySelectorAll('.option');
// 显示解析
explanationElement.classList.add('show');
if (!selectedOption) {
// 未答题
optionsContainer.style.border = '2px solid #f39c12';
return;
}
// 标记正确或错误
const selectedValue = selectedOption.value;
if (selectedValue === q.answer) {
// 正确
selectedOption.closest('.option').classList.add('correct');
correctCount++;
totalScore += 20;
} else {
// 错误
selectedOption.closest('.option').classList.add('incorrect');
// 标记正确答案
allOptions.forEach(option => {
if (option.querySelector(`input[value="${q.answer}"]`)) {
option.classList.add('correct');
}
});
incorrectCount++;
}
});
// 更新当前难度得分
scores[currentDifficulty] = {
score: totalScore,
correct: correctCount,
incorrect: incorrectCount
};
// 添加到已完成难度
if (!completedDifficulties.includes(currentDifficulty)) {
completedDifficulties.push(currentDifficulty);
}
// 显示结果
showResults();
// 显示下一步建议
showNextRecommendation();
}
// 显示结果
function showResults() {
resultSection.style.display = 'block';
// 计算总得分
let totalScore = 0;
let totalCorrect = 0;
let totalIncorrect = 0;
completedDifficulties.forEach(difficulty => {
totalScore += scores[difficulty].score;
totalCorrect += scores[difficulty].correct;
totalIncorrect += scores[difficulty].incorrect;
});
// 更新结果显示
totalScoreElement.textContent = totalScore;
correctCountElement.textContent = totalCorrect;
incorrectCountElement.textContent = totalIncorrect;
// 滚动到结果区域
resultSection.scrollIntoView({ behavior: 'smooth' });
}
// 显示下一步建议
function showNextRecommendation() {
navigationSection.style.display = 'block';
const currentScore = scores[currentDifficulty];
if (currentDifficulty === 'medium') {
if (currentScore.correct >= 3) {
navigationMessage.textContent = `恭喜!您在${getDifficultyName(currentDifficulty)}难度中答对了${currentScore.correct}题,表现优秀,建议挑战高级难度。`;
nextBtn.onclick = () => switchDifficulty('hard');
} else {
navigationMessage.textContent = `您在${getDifficultyName(currentDifficulty)}难度中答对了${currentScore.correct}题,建议先尝试简单难度巩固基础。`;
nextBtn.onclick = () => switchDifficulty('easy');
}
} else if (currentDifficulty === 'easy') {
navigationMessage.textContent = `您已完成${getDifficultyName(currentDifficulty)}难度,建议继续挑战中等难度。`;
nextBtn.onclick = () => switchDifficulty('medium');
} else if (currentDifficulty === 'hard') {
navigationMessage.textContent = `恭喜您完成了所有难度级别!您的总分为${scores.easy.score + scores.medium.score + scores.hard.score}分。`;
nextBtn.style.display = 'none';
}
navigationSection.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
// 切换难度
function switchDifficulty(nextDifficulty) {
currentDifficulty = nextDifficulty;
difficultyIndicator.textContent = `当前难度:${getDifficultyName(nextDifficulty)}`;
difficultyIndicator.className = `difficulty-indicator difficulty-${nextDifficulty}`;
// 重置按钮状态
submitBtn.disabled = false;
submitBtn.textContent = '提交答案';
// 隐藏结果和导航区域
resultSection.style.display = 'none';
navigationSection.style.display = 'none';
// 渲染新难度题目
renderQuestions(nextDifficulty);
// 滚动到页面顶部
window.scrollTo({ top: 0, behavior: 'smooth' });
}
// 学伴功能 - 开始录音
function startRecording() {
if (isRecording) return;
navigator.mediaDevices.getUserMedia({ audio: true })
.then(stream => {
mediaRecorder = new MediaRecorder(stream);
audioChunks = [];
mediaRecorder.ondataavailable = event => {
if (event.data.size > 0) audioChunks.push(event.data);
};
mediaRecorder.onstop = () => {
const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
uploadAudioToServer(audioBlob);
};
mediaRecorder.start();
isRecording = true;
recordingIndicator.style.display = 'flex';
// 设置最长录音时间为60秒
setTimeout(stopRecording, 60000);
})
.catch(error => {
console.error("获取麦克风权限失败:", error);
alert("请授权麦克风权限以使用录音功能");
});
}
// 学伴功能 - 停止录音
function stopRecording() {
if (!isRecording || !mediaRecorder) return;
mediaRecorder.stop();
isRecording = false;
recordingIndicator.style.display = 'none';
if (mediaRecorder.stream) {
mediaRecorder.stream.getTracks().forEach(track => track.stop());
}
}
// 学伴功能 - 上传音频到服务器
function uploadAudioToServer(audioBlob) {
thinkingIndicator.style.display = 'flex';
resultContainer.style.display = 'none';
const formData = new FormData();
formData.append('file', audioBlob, 'recording.wav');
if (currentQuestion) {
formData.append('question_number', currentQuestion.number);
formData.append('difficulty', currentQuestion.difficulty);
}
fetch('/api/xueban/upload-audio', { method: 'POST', body: formData })
.then(response => response.json())
.then(data => {
thinkingIndicator.style.display = 'none';
if (data.success) {
asrResultText.textContent = data.asr_text || '未识别到内容';
feedbackResultText.textContent = data.feedback_text || '无反馈内容';
resultContainer.style.display = 'flex';
if (data.audio_url) {
audioElement = new Audio(data.audio_url);
audioElement.onloadedmetadata = function() { updateAudioTimeDisplay(); };
audioElement.ontimeupdate = function() { updateAudioProgress(); updateAudioTimeDisplay(); };
audioElement.onended = function() { isPlaying = false; updatePlayButton(); };
playAudioBtn.onclick = togglePlayAudio;
audioProgress.onclick = function(e) {
const rect = audioProgress.getBoundingClientRect();
const clickPosition = (e.clientX - rect.left) / rect.width;
audioElement.currentTime = clickPosition * audioElement.duration;
};
}
} else {
alert('音频处理失败: ' + data.message);
}
})
.catch(error => {
thinkingIndicator.style.display = 'none';
alert('上传音频失败: ' + error.message);
});
}
// 学伴功能 - 切换音频播放/暂停
function togglePlayAudio() {
if (!audioElement) return;
isPlaying ? audioElement.pause() : audioElement.play();
isPlaying = !isPlaying;
updatePlayButton();
}
// 学伴功能 - 更新播放按钮状态
function updatePlayButton() {
playAudioBtn.innerHTML = isPlaying ?
`<svg width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M6 19H10V5H6V19ZM14 19H18V5H14V19Z" fill="white"/></svg>` :
`<svg width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M8 5V19L19 12L8 5Z" fill="white"/></svg>`;
}
// 学伴功能 - 更新音频进度条
function updateAudioProgress() {
if (audioElement && audioElement.duration) {
progressBar.style.width = `${(audioElement.currentTime / audioElement.duration) * 100}%`;
}
}
// 学伴功能 - 更新音频时间显示
function updateAudioTimeDisplay() {
if (audioElement && audioElement.duration) {
const currentTime = formatTime(audioElement.currentTime);
const duration = formatTime(audioElement.duration);
audioTime.textContent = `${currentTime} / ${duration}`;
}
}
// 学伴功能 - 格式化时间为 MM:SS
function formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
}