package handlers import ( "ankao/internal/database" "ankao/internal/models" "encoding/json" "net/http" "time" "github.com/gin-gonic/gin" ) // GetWrongQuestions 获取错题列表 func GetWrongQuestions(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { c.JSON(http.StatusUnauthorized, gin.H{ "success": false, "message": "未登录", }) return } db := database.GetDB() var wrongQuestions []models.WrongQuestion // 查询参数 isMastered := c.Query("is_mastered") // "true" 或 "false" questionType := c.Query("type") // 题型筛选 query := db.Where("user_id = ?", userID).Preload("PracticeQuestion") // 筛选是否已掌握 if isMastered == "true" { query = query.Where("is_mastered = ?", true) } else if isMastered == "false" { query = query.Where("is_mastered = ?", false) } // 按最后错误时间倒序 if err := query.Order("last_wrong_time DESC").Find(&wrongQuestions).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "message": "查询失败", }) return } // 转换为DTO dtos := make([]models.WrongQuestionDTO, 0, len(wrongQuestions)) for _, wq := range wrongQuestions { // 题型筛选 - 直接比较type字段 if questionType != "" && wq.PracticeQuestion.Type != questionType { continue } // 解析答案 var wrongAnswer, correctAnswer interface{} json.Unmarshal([]byte(wq.WrongAnswer), &wrongAnswer) json.Unmarshal([]byte(wq.CorrectAnswer), &correctAnswer) dto := models.WrongQuestionDTO{ ID: wq.ID, QuestionID: wq.QuestionID, Question: convertToDTO(wq.PracticeQuestion), WrongAnswer: wrongAnswer, CorrectAnswer: correctAnswer, WrongCount: wq.WrongCount, LastWrongTime: wq.LastWrongTime, IsMastered: wq.IsMastered, } dtos = append(dtos, dto) } c.JSON(http.StatusOK, gin.H{ "success": true, "data": dtos, "total": len(dtos), }) } // GetWrongQuestionStats 获取错题统计 func GetWrongQuestionStats(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { c.JSON(http.StatusUnauthorized, gin.H{ "success": false, "message": "未登录", }) return } db := database.GetDB() var wrongQuestions []models.WrongQuestion if err := db.Where("user_id = ?", userID).Preload("PracticeQuestion").Find(&wrongQuestions).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "message": "查询失败", }) return } stats := models.WrongQuestionStats{ TotalWrong: len(wrongQuestions), Mastered: 0, NotMastered: 0, TypeStats: make(map[string]int), CategoryStats: make(map[string]int), } for _, wq := range wrongQuestions { if wq.IsMastered { stats.Mastered++ } else { stats.NotMastered++ } // 统计题型 - 直接使用type字段 stats.TypeStats[wq.PracticeQuestion.Type]++ // 统计分类 stats.CategoryStats[wq.PracticeQuestion.TypeName]++ } c.JSON(http.StatusOK, gin.H{ "success": true, "data": stats, }) } // MarkWrongQuestionMastered 标记错题为已掌握 func MarkWrongQuestionMastered(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { c.JSON(http.StatusUnauthorized, gin.H{ "success": false, "message": "未登录", }) return } wrongQuestionID := c.Param("id") db := database.GetDB() var wrongQuestion models.WrongQuestion if err := db.Where("id = ? AND user_id = ?", wrongQuestionID, userID).First(&wrongQuestion).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{ "success": false, "message": "错题不存在", }) return } wrongQuestion.IsMastered = true if err := db.Save(&wrongQuestion).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "message": "更新失败", }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "已标记为掌握", }) } // ClearWrongQuestions 清空错题本 func ClearWrongQuestions(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { c.JSON(http.StatusUnauthorized, gin.H{ "success": false, "message": "未登录", }) return } db := database.GetDB() // 删除用户所有错题记录 if err := db.Where("user_id = ?", userID).Delete(&models.WrongQuestion{}).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "message": "清空失败", }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "错题本已清空", }) } // recordWrongQuestion 记录错题(内部函数,在答题错误时调用) func recordWrongQuestion(userID, questionID uint, userAnswer, correctAnswer interface{}) error { db := database.GetDB() // 将答案序列化为JSON wrongAnswerJSON, _ := json.Marshal(userAnswer) correctAnswerJSON, _ := json.Marshal(correctAnswer) // 查找是否已存在该错题 var existingWrong models.WrongQuestion result := db.Where("user_id = ? AND question_id = ?", userID, questionID).First(&existingWrong) if result.Error == nil { // 已存在,更新错误次数和时间 existingWrong.WrongCount++ existingWrong.LastWrongTime = time.Now() existingWrong.WrongAnswer = string(wrongAnswerJSON) existingWrong.CorrectAnswer = string(correctAnswerJSON) existingWrong.IsMastered = false // 重新标记为未掌握 return db.Save(&existingWrong).Error } // 不存在,创建新记录 newWrong := models.WrongQuestion{ UserID: userID, QuestionID: questionID, WrongAnswer: string(wrongAnswerJSON), CorrectAnswer: string(correctAnswerJSON), WrongCount: 1, LastWrongTime: time.Now(), IsMastered: false, } return db.Create(&newWrong).Error } // GetRandomWrongQuestion 获取随机错题进行练习 func GetRandomWrongQuestion(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { c.JSON(http.StatusUnauthorized, gin.H{ "success": false, "message": "未登录", }) return } db := database.GetDB() var wrongQuestion models.WrongQuestion // 随机获取一个错题 if err := db.Where("user_id = ?", userID).Order("RANDOM()").Preload("PracticeQuestion").First(&wrongQuestion).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{ "success": false, "message": "暂无错题", }) return } // 转换为DTO返回 dto := convertToDTO(wrongQuestion.PracticeQuestion) c.JSON(http.StatusOK, gin.H{ "success": true, "data": dto, }) } // DeleteWrongQuestion 删除单个错题 func DeleteWrongQuestion(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { c.JSON(http.StatusUnauthorized, gin.H{ "success": false, "message": "未登录", }) return } wrongQuestionID := c.Param("id") db := database.GetDB() // 删除错题(确保只能删除自己的错题) result := db.Where("id = ? AND user_id = ?", wrongQuestionID, userID).Delete(&models.WrongQuestion{}) if result.Error != nil { c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "message": "删除失败", }) return } if result.RowsAffected == 0 { c.JSON(http.StatusNotFound, gin.H{ "success": false, "message": "错题不存在", }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "已删除", }) }