package learning import ( "context" "time" "github.com/flipped-aurora/gin-vue-admin/server/global" "github.com/flipped-aurora/gin-vue-admin/server/model/learning" learningReq "github.com/flipped-aurora/gin-vue-admin/server/model/learning/request" ) type WrongQuestionService struct{} // CreateWrongQuestion 创建错题记录 func (wrongQuestionService *WrongQuestionService) CreateWrongQuestion(ctx context.Context, wrongQuestion *learning.WrongQuestion) (err error) { // 检查是否已存在该用户对该题目的错题记录 var existingRecord learning.WrongQuestion err = global.GVA_DB.WithContext(ctx).Where("user_id = ? AND question_id = ?", wrongQuestion.UserId, wrongQuestion.QuestionId).First(&existingRecord).Error if err == nil { // 如果已存在,更新错误次数和最后错误时间 existingRecord.WrongCount++ existingRecord.LastWrongAt = time.Now() existingRecord.WrongAnswer = wrongQuestion.WrongAnswer existingRecord.IsMastered = false // 重新答错,标记为未掌握 existingRecord.MasteredAt = time.Time{} return wrongQuestionService.UpdateWrongQuestion(ctx, existingRecord) } // 设置默认值 if wrongQuestion.LastWrongAt.IsZero() { wrongQuestion.LastWrongAt = time.Now() } if wrongQuestion.WrongCount == 0 { wrongQuestion.WrongCount = 1 } err = global.GVA_DB.WithContext(ctx).Create(wrongQuestion).Error return err } // DeleteWrongQuestion 删除错题记录 func (wrongQuestionService *WrongQuestionService) DeleteWrongQuestion(ctx context.Context, ID string) (err error) { err = global.GVA_DB.WithContext(ctx).Delete(&learning.WrongQuestion{}, ID).Error return err } // DeleteWrongQuestionByIds 批量删除错题记录 func (wrongQuestionService *WrongQuestionService) DeleteWrongQuestionByIds(ctx context.Context, IDs []string) (err error) { err = global.GVA_DB.WithContext(ctx).Delete(&[]learning.WrongQuestion{}, "id in ?", IDs).Error return err } // UpdateWrongQuestion 更新错题记录 func (wrongQuestionService *WrongQuestionService) UpdateWrongQuestion(ctx context.Context, wrongQuestion learning.WrongQuestion) (err error) { err = global.GVA_DB.WithContext(ctx).Model(&learning.WrongQuestion{}).Where("id = ?", wrongQuestion.ID).Updates(&wrongQuestion).Error return err } // GetWrongQuestion 根据ID获取错题记录 func (wrongQuestionService *WrongQuestionService) GetWrongQuestion(ctx context.Context, ID string) (wrongQuestion learning.WrongQuestion, err error) { err = global.GVA_DB.WithContext(ctx).Where("id = ?", ID).First(&wrongQuestion).Error if err != nil { return } // 手动查询关联的题目信息 wrongQuestionService.loadQuestionInfo(ctx, &wrongQuestion) return } // GetWrongQuestionInfoList 分页获取错题记录列表 func (wrongQuestionService *WrongQuestionService) GetWrongQuestionInfoList(ctx context.Context, info learningReq.WrongQuestionSearch) (list []learning.WrongQuestion, total int64, err error) { limit := info.PageSize offset := info.PageSize * (info.Page - 1) // 创建db db := global.GVA_DB.WithContext(ctx).Model(&learning.WrongQuestion{}) var wrongQuestions []learning.WrongQuestion // 如果有条件搜索 下方会自动创建搜索语句 if info.StartCreatedAt != nil && info.EndCreatedAt != nil { db = db.Where("created_at BETWEEN ? AND ?", info.StartCreatedAt, info.EndCreatedAt) } if info.UserId != 0 { db = db.Where("user_id = ?", info.UserId) } if info.QuestionId != 0 { db = db.Where("question_id = ?", info.QuestionId) } if info.IsMastered { db = db.Where("is_mastered = ?", info.IsMastered) } err = db.Count(&total).Error if err != nil { return } if limit != 0 { db = db.Limit(limit).Offset(offset) } err = db.Order("last_wrong_at desc").Find(&wrongQuestions).Error if err != nil { return wrongQuestions, total, err } // 批量加载关联的题目信息 for i := range wrongQuestions { wrongQuestionService.loadQuestionInfo(ctx, &wrongQuestions[i]) } return wrongQuestions, total, err } // GetUserWrongQuestions 获取用户的错题列表 func (wrongQuestionService *WrongQuestionService) GetUserWrongQuestions(ctx context.Context, userId uint, onlyUnmastered bool) (list []learning.WrongQuestion, err error) { db := global.GVA_DB.WithContext(ctx).Where("user_id = ?", userId) if onlyUnmastered { db = db.Where("is_mastered = ?", false) } err = db.Order("last_wrong_at desc").Find(&list).Error // 批量加载关联的题目信息 for i := range list { wrongQuestionService.loadQuestionInfo(ctx, &list[i]) } return } // MarkAsMastered 标记题目为已掌握 func (wrongQuestionService *WrongQuestionService) MarkAsMastered(ctx context.Context, userId uint, wrongQuestionId uint) (err error) { updates := map[string]interface{}{ "is_mastered": true, "mastered_at": time.Now(), } err = global.GVA_DB.WithContext(ctx).Model(&learning.WrongQuestion{}). Where("id = ? AND user_id = ?", wrongQuestionId, userId). Updates(updates).Error return err } // GetWrongQuestionStatistics 获取用户错题统计 func (wrongQuestionService *WrongQuestionService) GetWrongQuestionStatistics(ctx context.Context, userId uint) (stats learningReq.WrongQuestionStatistics, err error) { // 总错题数 var totalWrongQuestions int64 err = global.GVA_DB.WithContext(ctx).Model(&learning.WrongQuestion{}).Where("user_id = ?", userId).Count(&totalWrongQuestions).Error if err != nil { return } stats.TotalWrongQuestions = int(totalWrongQuestions) // 已掌握题目数 var masteredQuestions int64 err = global.GVA_DB.WithContext(ctx).Model(&learning.WrongQuestion{}).Where("user_id = ? AND is_mastered = ?", userId, true).Count(&masteredQuestions).Error if err != nil { return } stats.MasteredQuestions = int(masteredQuestions) // 未掌握题目数 stats.UnmasteredQuestions = stats.TotalWrongQuestions - stats.MasteredQuestions // 平均错误次数 var result struct { AverageWrongCount float64 } err = global.GVA_DB.WithContext(ctx).Model(&learning.WrongQuestion{}). Select("AVG(wrong_count) as average_wrong_count"). Where("user_id = ?", userId). Scan(&result).Error if err != nil { return } stats.AverageWrongCount = int(result.AverageWrongCount) return } // loadQuestionInfo 加载题目信息 func (wrongQuestionService *WrongQuestionService) loadQuestionInfo(ctx context.Context, wrongQuestion *learning.WrongQuestion) { if wrongQuestion.QuestionId != 0 { var question learning.Question if err := global.GVA_DB.WithContext(ctx).Where("id = ?", wrongQuestion.QuestionId).First(&question).Error; err == nil { wrongQuestion.Question = question } } }