fix: 修复多选题提交后页面崩溃
All checks were successful
continuous-integration/drone/push Build is passing

- formatCorrectAnswer: 增加空值保护和 try-catch
- checkObjectiveAnswer: 增加 options 数组校验
- recordWrongAnswer: 使用 dialogQuestion 快照,增加错误处理
This commit is contained in:
yuliang_guo
2026-01-30 15:16:12 +08:00
parent ef7a41ba01
commit c0d0331422

View File

@@ -772,32 +772,48 @@ const submitAnswer = () => {
const checkObjectiveAnswer = (): boolean => { const checkObjectiveAnswer = (): boolean => {
const q = currentQuestion.value const q = currentQuestion.value
if (q.type === 'single' || q.type === 'multiple') { if (!q) {
const correctIndexes = q.options console.error('checkObjectiveAnswer: currentQuestion 为空')
.map((opt: any, idx: number) => opt.isCorrect ? idx : -1) return false
.filter((idx: number) => idx !== -1)
// 调试日志:显示正确答案索引和用户选择
console.log(`🔍 客观题判断 - 题目: "${q.title.substring(0, 30)}..."`)
console.log(` 选项详情:`, q.options.map((opt: any, idx: number) => ({
index: idx,
letter: String.fromCharCode(65 + idx),
isCorrect: opt.isCorrect,
content: opt.content?.substring(0, 20) + '...'
})))
console.log(` 正确答案索引: [${correctIndexes.join(', ')}]`)
console.log(` 用户选择索引: [${userAnswer.selected.join(', ')}]`)
const isCorrect = JSON.stringify(userAnswer.selected.sort()) === JSON.stringify(correctIndexes.sort())
console.log(` 判断结果: ${isCorrect ? '✅正确' : '❌错误'}`)
return isCorrect
} else if (q.type === 'judge') {
console.log(`🔍 判断题判断 - 正确答案: ${q.correctAnswer}, 用户答案: ${userAnswer.judge}`)
return userAnswer.judge === q.correctAnswer
} }
return false try {
if (q.type === 'single' || q.type === 'multiple') {
// 增加空值保护
if (!q.options || !Array.isArray(q.options)) {
console.error('checkObjectiveAnswer: options 无效', q.options)
return false
}
const correctIndexes = q.options
.map((opt: any, idx: number) => opt?.isCorrect ? idx : -1)
.filter((idx: number) => idx !== -1)
// 调试日志:显示正确答案索引和用户选择
console.log(`🔍 客观题判断 - 题目: "${q.title?.substring(0, 30) || '无标题'}..."`)
console.log(` 选项详情:`, q.options.map((opt: any, idx: number) => ({
index: idx,
letter: String.fromCharCode(65 + idx),
isCorrect: opt?.isCorrect,
content: opt?.content?.substring(0, 20) + '...'
})))
console.log(` 正确答案索引: [${correctIndexes.join(', ')}]`)
console.log(` 用户选择索引: [${userAnswer.selected.join(', ')}]`)
const isCorrect = JSON.stringify([...userAnswer.selected].sort()) === JSON.stringify([...correctIndexes].sort())
console.log(` 判断结果: ${isCorrect ? '✅正确' : '❌错误'}`)
return isCorrect
} else if (q.type === 'judge') {
console.log(`🔍 判断题判断 - 正确答案: ${q.correctAnswer}, 用户答案: ${userAnswer.judge}`)
return userAnswer.judge === q.correctAnswer
}
return false
} catch (error) {
console.error('checkObjectiveAnswer 出错:', error)
return false
}
} }
/** /**
@@ -863,18 +879,29 @@ const checkSubjectiveAnswer = async (question: any): Promise<boolean> => {
* 记录错题到数据库 * 记录错题到数据库
*/ */
const recordWrongAnswer = async () => { const recordWrongAnswer = async () => {
const q = currentQuestion.value // 使用 dialogQuestion已保存的题目快照而不是 currentQuestion
const q = dialogQuestion.value || currentQuestion.value
if (!q) {
console.error('recordWrongAnswer: 题目数据为空')
return
}
// 获取用户答案 // 获取用户答案
let userAnswerText = '' let userAnswerText = ''
if (q.type === 'single' || q.type === 'multiple') { try {
userAnswerText = userAnswer.selected.map(idx => String.fromCharCode(65 + idx)).join(',') if (q.type === 'single' || q.type === 'multiple') {
} else if (q.type === 'judge') { userAnswerText = userAnswer.selected.map(idx => String.fromCharCode(65 + idx)).join(',')
userAnswerText = userAnswer.judge ? '正确' : '错误' } else if (q.type === 'judge') {
} else if (q.type === 'blank') { userAnswerText = userAnswer.judge ? '正确' : '错误'
userAnswerText = userAnswer.blank } else if (q.type === 'blank') {
} else if (q.type === 'essay') { userAnswerText = userAnswer.blank || ''
userAnswerText = userAnswer.essay } else if (q.type === 'essay') {
userAnswerText = userAnswer.essay || ''
}
} catch (e) {
console.error('获取用户答案失败:', e)
userAnswerText = ''
} }
try { try {
@@ -883,10 +910,10 @@ const recordWrongAnswer = async () => {
round: currentRound.value, // 记录当前轮次 round: currentRound.value, // 记录当前轮次
question_id: null, // AI生成的题目没有question_id question_id: null, // AI生成的题目没有question_id
knowledge_point_id: q.knowledge_point_id || null, knowledge_point_id: q.knowledge_point_id || null,
question_content: q.title, question_content: q.title || '',
correct_answer: formatCorrectAnswer(q), correct_answer: formatCorrectAnswer(q),
user_answer: userAnswerText, user_answer: userAnswerText,
question_type: q.type // 新增:记录题型 question_type: q.type || '' // 新增:记录题型
}) })
} catch (error: any) { } catch (error: any) {
console.error('记录错题失败:', error) console.error('记录错题失败:', error)
@@ -1181,35 +1208,45 @@ const renderMarkdown = (content: string): string => {
* 格式化正确答案 * 格式化正确答案
*/ */
const formatCorrectAnswer = (question: any) => { const formatCorrectAnswer = (question: any) => {
if (question.type === 'single' || question.type === 'multiple') { if (!question) return ''
// 如果有correctAnswer字段来自Dify的原始correct
if (question.correctAnswer) { try {
// 多选题格式优化:将 "Axxx、Bxxx" 或 "Axxx,Bxxx" 改为换行显示 if (question.type === 'single' || question.type === 'multiple') {
// 使用更精确的匹配:提取完整的选项格式 X内容 // 如果有correctAnswer字段来自Dify的原始correct
const optionPattern = /([A-Za-z][:])([^A-Za-z]*?)(?=(?:[,、]?[A-Za-z][:])|$)/g if (question.correctAnswer) {
const matches = [...question.correctAnswer.matchAll(optionPattern)] // 多选题格式优化:将 "Axxx、Bxxx" 或 "Axxx,Bxxx" 改为换行显示
if (matches.length > 1) { // 使用更精确的匹配:提取完整的选项格式 X内容
// 多个选项,换行显示 const optionPattern = /([A-Za-z][:])([^A-Za-z]*?)(?=(?:[,、]?[A-Za-z][:])|$)/g
return matches.map(m => m[1] + m[2].trim()).join('\n') const matches = [...String(question.correctAnswer).matchAll(optionPattern)]
if (matches.length > 1) {
// 多个选项,换行显示
return matches.map(m => m[1] + m[2].trim()).join('\n')
}
return question.correctAnswer
} }
return question.correctAnswer // 否则从options中提取增加空值保护
if (!question.options || !Array.isArray(question.options)) {
return ''
}
return question.options
.map((opt: any, idx: number) => opt?.isCorrect ? String.fromCharCode(65 + idx) : null)
.filter((v: any) => v)
.join('、')
} else if (question.type === 'judge') {
// 优先使用correctAnswerTextDify原始值"正确"或"错误"
if (question.correctAnswerText) {
return question.correctAnswerText
}
// 备用从boolean转换
return question.correctAnswer ? '正确' : '错误'
} else if (question.type === 'blank' || question.type === 'essay') {
return question.correctAnswer || ''
} }
// 否则从options中提取 return ''
return question.options } catch (error) {
.map((opt: any, idx: number) => opt.isCorrect ? String.fromCharCode(65 + idx) : null) console.error('formatCorrectAnswer 出错:', error, question)
.filter((v: any) => v)
.join('、')
} else if (question.type === 'judge') {
// 优先使用correctAnswerTextDify原始值"正确"或"错误"
if (question.correctAnswerText) {
return question.correctAnswerText
}
// 备用从boolean转换
return question.correctAnswer ? '正确' : '错误'
} else if (question.type === 'blank' || question.type === 'essay') {
return question.correctAnswer || '' return question.correctAnswer || ''
} }
return ''
} }
/** /**