diff --git a/internal/handlers/exam_handler.go b/internal/handlers/exam_handler.go index bdc3aac..16982df 100644 --- a/internal/handlers/exam_handler.go +++ b/internal/handlers/exam_handler.go @@ -169,10 +169,11 @@ func GetExamList(c *gin.Context) { type ExamWithStats struct { models.Exam QuestionCount int `json:"question_count"` - AttemptCount int `json:"attempt_count"` // 考试次数 - BestScore float64 `json:"best_score"` // 最高分 + AttemptCount int `json:"attempt_count"` // 考试次数(当前用户) + BestScore float64 `json:"best_score"` // 最高分(当前用户) HasInProgressExam bool `json:"has_in_progress_exam"` // 是否有进行中的考试 InProgressRecordID uint `json:"in_progress_record_id,omitempty"` // 进行中的考试记录ID + ParticipantCount int `json:"participant_count"` // 共享试卷的参与人数(所有用户) } result := make([]ExamWithStats, 0, len(exams)) @@ -184,12 +185,12 @@ func GetExamList(c *gin.Context) { QuestionCount: len(questionIDs), } - // 查询该试卷的考试记录统计 + // 查询该试卷的考试记录统计(当前用户) var count int64 db.Model(&models.ExamRecord{}).Where("exam_id = ? AND user_id = ?", exam.ID, userID).Count(&count) stats.AttemptCount = int(count) - // 查询最高分 + // 查询最高分(当前用户) var record models.ExamRecord if err := db.Where("exam_id = ? AND user_id = ?", exam.ID, userID). Order("score DESC"). @@ -206,6 +207,41 @@ func GetExamList(c *gin.Context) { stats.InProgressRecordID = inProgressRecord.ID } + // 计算共享试卷的参与人数 + // 获取所有相关试卷ID(包括原始试卷和所有分享副本) + var relatedExamIDs []uint + relatedExamIDs = append(relatedExamIDs, exam.ID) + + // 如果这是被分享的试卷,找到原始试卷 + if exam.IsShared && exam.SharedByID != nil { + var originalExam models.Exam + if err := db.Where("user_id = ? AND question_ids = ? AND deleted_at IS NULL", + *exam.SharedByID, exam.QuestionIDs).First(&originalExam).Error; err == nil { + relatedExamIDs = append(relatedExamIDs, originalExam.ID) + } + } + + // 查找所有基于该试卷的分享副本 + var sharedExams []models.Exam + sharedByID := exam.UserID + if exam.IsShared && exam.SharedByID != nil { + sharedByID = *exam.SharedByID + } + if err := db.Where("shared_by_id = ? AND question_ids = ? AND deleted_at IS NULL", + sharedByID, exam.QuestionIDs).Find(&sharedExams).Error; err == nil { + for _, se := range sharedExams { + relatedExamIDs = append(relatedExamIDs, se.ID) + } + } + + // 统计所有相关试卷的已完成考试的不同用户数 + var participantCount int64 + db.Model(&models.ExamRecord{}). + Where("exam_id IN ? AND status = ?", relatedExamIDs, "graded"). + Distinct("user_id"). + Count(&participantCount) + stats.ParticipantCount = int(participantCount) + result = append(result, stats) } } diff --git a/web/src/pages/ExamManagement.tsx b/web/src/pages/ExamManagement.tsx index eacd6ea..a0313f9 100644 --- a/web/src/pages/ExamManagement.tsx +++ b/web/src/pages/ExamManagement.tsx @@ -30,7 +30,8 @@ import { PrinterOutlined, ArrowLeftOutlined, ShareAltOutlined, - UserOutlined + UserOutlined, + TeamOutlined } from '@ant-design/icons' import * as examApi from '../api/exam' import styles from './ExamManagement.module.less' @@ -46,6 +47,7 @@ interface ExamListItem { best_score: number has_in_progress_exam: boolean in_progress_record_id?: number + participant_count: number // 共享试卷的参与人数 created_at: string is_shared?: boolean shared_by?: { @@ -396,6 +398,14 @@ const ExamManagement: React.FC = () => { 考试次数 {exam.attempt_count} + {exam.participant_count > 0 && ( +