From 7c407db78b31988eb20ee80066bf1ecebc204f38 Mon Sep 17 00:00:00 2001 From: yanlongqi Date: Tue, 4 Nov 2025 22:23:00 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=A4=E6=96=AD=E9=A2=98?= =?UTF-8?q?=E5=92=8C=E5=A1=AB=E7=A9=BA=E9=A2=98=E7=9A=84=E7=AD=94=E9=A2=98?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 主要修复 - 修复判断题答案验证:前端提交时将字符串转换为布尔值 - 修复判断题答案显示:支持布尔值和字符串格式的正确显示 - 修复判断题选项顺序:保持"正确"在前、"错误"在后 - 修复填空题答案残留:题目切换时自动清空填空输入框 - 优化填空题验证:去除前后空格,添加详细日志 ## 技术细节 - Question.tsx: 判断题提交前将 "true"/"false" 转为 boolean - AnswerResult.tsx: formatAnswer 函数支持 boolean 类型 - QuestionCard.tsx: 判断题不排序,填空题切换时重置状态 - practice_handler.go: 填空题比较前 TrimSpace,添加调试日志 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- internal/handlers/practice_handler.go | 13 ++++++++++--- web/src/components/AnswerResult.tsx | 19 ++++++++++++++----- web/src/components/QuestionCard.tsx | 14 ++++++++++++-- web/src/pages/Question.tsx | 8 +++++++- 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/internal/handlers/practice_handler.go b/internal/handlers/practice_handler.go index 0f0802b..7c1e5ab 100644 --- a/internal/handlers/practice_handler.go +++ b/internal/handlers/practice_handler.go @@ -8,6 +8,7 @@ import ( "net/http" "sort" "strconv" + "strings" "time" "github.com/gin-gonic/gin" @@ -277,12 +278,18 @@ func checkPracticeAnswer(questionType string, userAnswer, correctAnswer interfac userArr, ok1 := toStringArray(userAnswer) correctArr, ok2 := toStringArray(correctAnswer) if !ok1 || !ok2 || len(userArr) != len(correctArr) { + log.Printf("填空题验证失败 - 数组转换或长度不匹配: ok1=%v, ok2=%v, userLen=%d, correctLen=%d", + ok1, ok2, len(userArr), len(correctArr)) return false } - // 逐个比较填空答案 + // 逐个比较填空答案(去除前后空格) for i := range correctArr { - if userArr[i] != correctArr[i] { + userTrimmed := strings.TrimSpace(userArr[i]) + correctTrimmed := strings.TrimSpace(correctArr[i]) + if userTrimmed != correctTrimmed { + log.Printf("填空题验证失败 - 第%d个答案不匹配: user='%s', correct='%s'", + i+1, userTrimmed, correctTrimmed) return false } } @@ -335,7 +342,7 @@ func convertToDTO(question models.PracticeQuestion) models.PracticeQuestionDTO { dto.Answer = answer } - // 判断题自动生成选项 + // 判断题自动生成选项(正确在前,错误在后) if question.Type == "true-false" { dto.Options = []models.Option{ {Key: "true", Value: "正确"}, diff --git a/web/src/components/AnswerResult.tsx b/web/src/components/AnswerResult.tsx index d4bf185..d30abba 100644 --- a/web/src/components/AnswerResult.tsx +++ b/web/src/components/AnswerResult.tsx @@ -17,14 +17,23 @@ const AnswerResult: React.FC = ({ questionType, }) => { // 格式化答案显示(判断题特殊处理) - const formatAnswer = (answer: string | string[]) => { - const answerStr = Array.isArray(answer) ? answer.join(', ') : answer - + const formatAnswer = (answer: string | string[] | boolean) => { + // 处理判断题的布尔值和字符串 if (questionType === 'true-false') { - return answerStr === 'true' ? '正确' : answerStr === 'false' ? '错误' : answerStr + if (typeof answer === 'boolean') { + return answer ? '正确' : '错误' + } + if (typeof answer === 'string') { + return answer === 'true' ? '正确' : answer === 'false' ? '错误' : answer + } } - return answerStr + // 处理数组答案 + if (Array.isArray(answer)) { + return answer.join(', ') + } + + return String(answer) } return ( diff --git a/web/src/components/QuestionCard.tsx b/web/src/components/QuestionCard.tsx index 1560e20..bc23c74 100644 --- a/web/src/components/QuestionCard.tsx +++ b/web/src/components/QuestionCard.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react' +import React, { useState, useEffect } from 'react' import { Card, Space, Tag, Typography, Radio, Checkbox, Input, Button } from 'antd' import type { Question, AnswerResult as AnswerResultType } from '../types/question' import AnswerResult from './AnswerResult' @@ -32,6 +32,13 @@ const QuestionCard: React.FC = ({ }) => { const [fillAnswers, setFillAnswers] = useState([]) + // 当题目ID变化时,重置填空题答案 + useEffect(() => { + if (question.type === 'fill-in-blank') { + setFillAnswers([]) + } + }, [question.id, question.type]) + // 渲染填空题内容 const renderFillContent = () => { const content = question.content @@ -118,7 +125,10 @@ const QuestionCard: React.FC = ({ } // 单选题和判断题 - const sortedOptions = [...question.options].sort((a, b) => a.key.localeCompare(b.key)) + // 判断题不排序,保持后端返回的顺序(正确在前,错误在后) + const sortedOptions = question.type === 'true-false' + ? question.options + : [...question.options].sort((a, b) => a.key.localeCompare(b.key)) return ( { setLoading(true); try { + // 处理判断题答案:将字符串 "true"/"false" 转换为布尔值 + let answerToSubmit = selectedAnswer; + if (currentQuestion.type === "true-false" && typeof selectedAnswer === "string") { + answerToSubmit = selectedAnswer === "true"; + } + const res = await questionApi.submitAnswer({ question_id: currentQuestion.id, - answer: selectedAnswer, + answer: answerToSubmit, }); if (res.success && res.data) {