duidui_fiber/internal/question/service/paper_service.go
2026-03-27 10:34:03 +08:00

229 lines
6.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"fmt"
"dd_fiber_api/internal/question"
"dd_fiber_api/internal/question/dao"
)
// PaperService 试卷服务
type PaperService struct {
paperDAO dao.PaperDAOInterface
materialService *MaterialService
}
// NewPaperService 创建试卷服务
func NewPaperService(paperDAO dao.PaperDAOInterface, materialService *MaterialService) *PaperService {
return &PaperService{
paperDAO: paperDAO,
materialService: materialService,
}
}
// CreatePaper 创建试卷
func (s *PaperService) CreatePaper(req *CreatePaperRequest) (*question.Paper, error) {
// 验证:题目数量不能为空
if req.QuestionIds == nil || len(req.QuestionIds) == 0 {
return nil, fmt.Errorf("题目数量不能为空,请至少选择一个题目")
}
paperID := question.GenerateID()
// 确保 MaterialIds 不为 nil
materialIds := req.MaterialIds
if materialIds == nil {
materialIds = []string{}
}
// 确保 QuestionIDs 不为 nil已验证不为空但确保不为 nil
questionIds := req.QuestionIds
if questionIds == nil {
questionIds = []string{}
}
paper := &question.Paper{
ID: paperID,
Title: req.Title,
Description: req.Description,
Source: req.Source,
QuestionIDs: questionIds,
MaterialIDs: materialIds,
CreatedAt: question.GetCurrentTimestamp(),
UpdatedAt: question.GetCurrentTimestamp(),
}
err := s.paperDAO.Create(paper)
if err != nil {
return nil, fmt.Errorf("创建试卷失败: %v", err)
}
return paper, nil
}
// GetPaper 获取试卷
func (s *PaperService) GetPaper(id string) (*question.Paper, error) {
paper, err := s.paperDAO.GetWithQuestions(id)
if err != nil {
return nil, fmt.Errorf("试卷不存在: %v", err)
}
// 收集材料 ID试卷级 + 题目级(按题目中首次出现顺序去重),并拉取材料详情
if s.materialService != nil {
seen := make(map[string]bool)
var orderedIDs []string
for _, mid := range paper.MaterialIDs {
if mid != "" && !seen[mid] {
seen[mid] = true
orderedIDs = append(orderedIDs, mid)
}
}
if paper.Questions != nil {
for _, q := range paper.Questions {
if q.MaterialID != "" && !seen[q.MaterialID] {
seen[q.MaterialID] = true
orderedIDs = append(orderedIDs, q.MaterialID)
}
}
}
for _, mid := range orderedIDs {
mat, err := s.materialService.GetMaterial(mid)
if err != nil {
continue
}
paper.Materials = append(paper.Materials, mat)
}
}
return paper, nil
}
// SearchPapers 搜索试卷
func (s *PaperService) SearchPapers(query string, page, pageSize int32) ([]*question.Paper, int32, error) {
papers, total, err := s.paperDAO.Search(query, page, pageSize)
if err != nil {
return nil, 0, fmt.Errorf("搜索试卷失败: %v", err)
}
return papers, total, nil
}
// UpdatePaper 更新试卷
func (s *PaperService) UpdatePaper(req *UpdatePaperRequest) error {
// 验证:题目数量不能为空
if req.QuestionIds == nil || len(req.QuestionIds) == 0 {
return fmt.Errorf("题目数量不能为空,请至少选择一个题目")
}
paper, err := s.paperDAO.GetByID(req.Id)
if err != nil {
return fmt.Errorf("试卷不存在: %v", err)
}
paper.Title = req.Title
paper.Description = req.Description
paper.Source = req.Source
// 确保 QuestionIDs 不为 nil已验证不为空但确保不为 nil
questionIds := req.QuestionIds
if questionIds == nil {
questionIds = []string{}
}
paper.QuestionIDs = questionIds
// 确保 MaterialIds 不为 nil
materialIds := req.MaterialIds
if materialIds == nil {
materialIds = []string{}
}
paper.MaterialIDs = materialIds
paper.UpdatedAt = question.GetCurrentTimestamp()
err = s.paperDAO.Update(paper)
if err != nil {
return fmt.Errorf("更新试卷失败: %v", err)
}
return nil
}
// DeletePaper 删除试卷
func (s *PaperService) DeletePaper(id string) error {
err := s.paperDAO.Delete(id)
if err != nil {
return fmt.Errorf("删除试卷失败: %v", err)
}
return nil
}
// BatchDeletePapers 批量删除试卷
func (s *PaperService) BatchDeletePapers(ids []string) (int, []string, error) {
deletedCount, failedIDs, err := s.paperDAO.BatchDelete(ids)
if err != nil {
return 0, nil, fmt.Errorf("批量删除失败: %v", err)
}
return deletedCount, failedIDs, nil
}
// AddQuestionToPaper 添加题目到试卷
func (s *PaperService) AddQuestionToPaper(paperID string, questionIDs []string) (int, []string, error) {
addedCount, failedIDs, err := s.paperDAO.AddQuestions(paperID, questionIDs)
if err != nil {
return 0, nil, fmt.Errorf("添加题目失败: %v", err)
}
return addedCount, failedIDs, nil
}
// RemoveQuestionFromPaper 从试卷移除题目
func (s *PaperService) RemoveQuestionFromPaper(paperID string, questionIDs []string) (int, []string, error) {
removedCount, failedIDs, err := s.paperDAO.RemoveQuestions(paperID, questionIDs)
if err != nil {
return 0, nil, fmt.Errorf("移除题目失败: %v", err)
}
return removedCount, failedIDs, nil
}
// GetPaperWithAnswers 获取试卷及题目详情(包含答案和解析,用于答题结果页面)
// 这个方法确保返回的题目包含答案和解析字段
func (s *PaperService) GetPaperWithAnswers(id string) (*question.Paper, error) {
paper, err := s.GetPaper(id)
if err != nil {
return nil, err
}
// 确保每个题目都有答案和解析字段(即使为空字符串)
if paper.Questions != nil {
for _, q := range paper.Questions {
if q.Answer == "" {
q.Answer = ""
}
if q.Explanation == "" {
q.Explanation = ""
}
}
}
return paper, nil
}
// CreatePaperRequest 创建试卷请求
type CreatePaperRequest struct {
Title string `json:"title"`
Description string `json:"description"`
Source string `json:"source,omitempty"` // 题目出处(可选)
QuestionIds []string `json:"question_ids"` // 题目ID列表
MaterialIds []string `json:"material_ids,omitempty"` // 关联的材料ID列表可选用于主观题组卷
}
// UpdatePaperRequest 更新试卷请求
type UpdatePaperRequest struct {
Id string `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Source string `json:"source,omitempty"` // 题目出处(可选)
QuestionIds []string `json:"question_ids"` // 题目ID列表
MaterialIds []string `json:"material_ids,omitempty"` // 关联的材料ID列表可选用于主观题组卷
}