420 lines
12 KiB
Go
420 lines
12 KiB
Go
|
|
package handlers
|
||
|
|
|
||
|
|
import (
|
||
|
|
"net/http"
|
||
|
|
"strconv"
|
||
|
|
|
||
|
|
"github.com/gin-gonic/gin"
|
||
|
|
|
||
|
|
"github.com/Nanqipro/YunQue-Tech-Projects/ai_english_learning/serve/internal/common"
|
||
|
|
"github.com/Nanqipro/YunQue-Tech-Projects/ai_english_learning/serve/internal/models"
|
||
|
|
"github.com/Nanqipro/YunQue-Tech-Projects/ai_english_learning/serve/internal/services"
|
||
|
|
"github.com/Nanqipro/YunQue-Tech-Projects/ai_english_learning/serve/internal/utils"
|
||
|
|
)
|
||
|
|
|
||
|
|
// TestHandler 测试处理器
|
||
|
|
type TestHandler struct {
|
||
|
|
testService *services.TestService
|
||
|
|
}
|
||
|
|
|
||
|
|
// NewTestHandler 创建测试处理器实例
|
||
|
|
func NewTestHandler(testService *services.TestService) *TestHandler {
|
||
|
|
return &TestHandler{
|
||
|
|
testService: testService,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetTestTemplates 获取测试模板列表
|
||
|
|
// @Summary 获取测试模板列表
|
||
|
|
// @Tags Test
|
||
|
|
// @Param type query string false "测试类型"
|
||
|
|
// @Param difficulty query string false "难度"
|
||
|
|
// @Param page query int false "页码"
|
||
|
|
// @Param page_size query int false "每页数量"
|
||
|
|
// @Success 200 {object} common.Response
|
||
|
|
// @Router /api/v1/tests/templates [get]
|
||
|
|
func (h *TestHandler) GetTestTemplates(c *gin.Context) {
|
||
|
|
typeStr := c.Query("type")
|
||
|
|
difficultyStr := c.Query("difficulty")
|
||
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||
|
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
||
|
|
|
||
|
|
var testType *models.TestType
|
||
|
|
if typeStr != "" {
|
||
|
|
t := models.TestType(typeStr)
|
||
|
|
testType = &t
|
||
|
|
}
|
||
|
|
|
||
|
|
var difficulty *models.TestDifficulty
|
||
|
|
if difficultyStr != "" {
|
||
|
|
d := models.TestDifficulty(difficultyStr)
|
||
|
|
difficulty = &d
|
||
|
|
}
|
||
|
|
|
||
|
|
templates, total, err := h.testService.GetTestTemplates(testType, difficulty, page, pageSize)
|
||
|
|
if err != nil {
|
||
|
|
common.ErrorResponse(c, http.StatusInternalServerError, "获取测试模板失败")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
common.SuccessResponse(c, gin.H{
|
||
|
|
"templates": templates,
|
||
|
|
"pagination": gin.H{
|
||
|
|
"page": page,
|
||
|
|
"page_size": pageSize,
|
||
|
|
"total": total,
|
||
|
|
"total_page": (total + int64(pageSize) - 1) / int64(pageSize),
|
||
|
|
},
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetTestTemplateByID 获取测试模板详情
|
||
|
|
// @Summary 获取测试模板详情
|
||
|
|
// @Tags Test
|
||
|
|
// @Param id path string true "模板ID"
|
||
|
|
// @Success 200 {object} common.Response
|
||
|
|
// @Router /api/v1/tests/templates/{id} [get]
|
||
|
|
func (h *TestHandler) GetTestTemplateByID(c *gin.Context) {
|
||
|
|
id := c.Param("id")
|
||
|
|
|
||
|
|
template, err := h.testService.GetTestTemplateByID(id)
|
||
|
|
if err != nil {
|
||
|
|
common.ErrorResponse(c, http.StatusNotFound, "测试模板不存在")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
common.SuccessResponse(c, gin.H{"data": template})
|
||
|
|
}
|
||
|
|
|
||
|
|
// CreateTestSession 创建测试会话
|
||
|
|
// @Summary 创建测试会话
|
||
|
|
// @Tags Test
|
||
|
|
// @Param body body object true "请求体"
|
||
|
|
// @Success 201 {object} common.Response
|
||
|
|
// @Router /api/v1/tests/sessions [post]
|
||
|
|
func (h *TestHandler) CreateTestSession(c *gin.Context) {
|
||
|
|
userID, exists := utils.GetUserIDFromContext(c)
|
||
|
|
if !exists {
|
||
|
|
common.BadRequestResponse(c, "请先登录")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
var req struct {
|
||
|
|
TemplateID string `json:"template_id" binding:"required"`
|
||
|
|
}
|
||
|
|
|
||
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||
|
|
common.BadRequestResponse(c, "请求参数错误")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
session, err := h.testService.CreateTestSession(req.TemplateID, utils.Int64ToString(userID))
|
||
|
|
if err != nil {
|
||
|
|
common.ErrorResponse(c, http.StatusInternalServerError, "创建测试会话失败: "+err.Error())
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
common.SuccessResponseWithStatus(c, http.StatusCreated, gin.H{"data": session})
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetTestSession 获取测试会话
|
||
|
|
// @Summary 获取测试会话
|
||
|
|
// @Tags Test
|
||
|
|
// @Param id path string true "会话ID"
|
||
|
|
// @Success 200 {object} common.Response
|
||
|
|
// @Router /api/v1/tests/sessions/{id} [get]
|
||
|
|
func (h *TestHandler) GetTestSession(c *gin.Context) {
|
||
|
|
sessionID := c.Param("id")
|
||
|
|
|
||
|
|
session, err := h.testService.GetTestSession(sessionID)
|
||
|
|
if err != nil {
|
||
|
|
common.ErrorResponse(c, http.StatusNotFound, "测试会话不存在")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
// 验证用户权限
|
||
|
|
userID, _ := utils.GetUserIDFromContext(c)
|
||
|
|
if session.UserID != utils.Int64ToString(userID) {
|
||
|
|
common.ErrorResponse(c, http.StatusForbidden, "无权访问此测试会话")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
common.SuccessResponse(c, gin.H{"data": session})
|
||
|
|
}
|
||
|
|
|
||
|
|
// StartTest 开始测试
|
||
|
|
// @Summary 开始测试
|
||
|
|
// @Tags Test
|
||
|
|
// @Param id path string true "会话ID"
|
||
|
|
// @Success 200 {object} common.Response
|
||
|
|
// @Router /api/v1/tests/sessions/{id}/start [put]
|
||
|
|
func (h *TestHandler) StartTest(c *gin.Context) {
|
||
|
|
sessionID := c.Param("id")
|
||
|
|
|
||
|
|
// 验证用户权限
|
||
|
|
session, err := h.testService.GetTestSession(sessionID)
|
||
|
|
if err != nil {
|
||
|
|
common.ErrorResponse(c, http.StatusNotFound, "测试会话不存在")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
userID, _ := utils.GetUserIDFromContext(c)
|
||
|
|
if session.UserID != utils.Int64ToString(userID) {
|
||
|
|
common.ErrorResponse(c, http.StatusForbidden, "无权操作此测试会话")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
updatedSession, err := h.testService.StartTest(sessionID)
|
||
|
|
if err != nil {
|
||
|
|
common.ErrorResponse(c, http.StatusBadRequest, err.Error())
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
common.SuccessResponse(c, gin.H{"data": updatedSession})
|
||
|
|
}
|
||
|
|
|
||
|
|
// SubmitAnswer 提交答案
|
||
|
|
// @Summary 提交答案
|
||
|
|
// @Tags Test
|
||
|
|
// @Param id path string true "会话ID"
|
||
|
|
// @Param body body object true "请求体"
|
||
|
|
// @Success 200 {object} common.Response
|
||
|
|
// @Router /api/v1/tests/sessions/{id}/answers [post]
|
||
|
|
func (h *TestHandler) SubmitAnswer(c *gin.Context) {
|
||
|
|
sessionID := c.Param("id")
|
||
|
|
|
||
|
|
var req struct {
|
||
|
|
QuestionID string `json:"question_id" binding:"required"`
|
||
|
|
Answer string `json:"answer" binding:"required"`
|
||
|
|
}
|
||
|
|
|
||
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||
|
|
common.BadRequestResponse(c, "请求参数错误")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
// 验证用户权限
|
||
|
|
session, err := h.testService.GetTestSession(sessionID)
|
||
|
|
if err != nil {
|
||
|
|
common.ErrorResponse(c, http.StatusNotFound, "测试会话不存在")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
userID, _ := utils.GetUserIDFromContext(c)
|
||
|
|
if session.UserID != utils.Int64ToString(userID) {
|
||
|
|
common.ErrorResponse(c, http.StatusForbidden, "无权操作此测试会话")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
updatedSession, err := h.testService.SubmitAnswer(sessionID, req.QuestionID, req.Answer)
|
||
|
|
if err != nil {
|
||
|
|
common.ErrorResponse(c, http.StatusBadRequest, err.Error())
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
common.SuccessResponse(c, gin.H{"data": updatedSession})
|
||
|
|
}
|
||
|
|
|
||
|
|
// PauseTest 暂停测试
|
||
|
|
// @Summary 暂停测试
|
||
|
|
// @Tags Test
|
||
|
|
// @Param id path string true "会话ID"
|
||
|
|
// @Success 200 {object} common.Response
|
||
|
|
// @Router /api/v1/tests/sessions/{id}/pause [put]
|
||
|
|
func (h *TestHandler) PauseTest(c *gin.Context) {
|
||
|
|
sessionID := c.Param("id")
|
||
|
|
|
||
|
|
// 验证用户权限
|
||
|
|
session, err := h.testService.GetTestSession(sessionID)
|
||
|
|
if err != nil {
|
||
|
|
common.ErrorResponse(c, http.StatusNotFound, "测试会话不存在")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
userID, _ := utils.GetUserIDFromContext(c)
|
||
|
|
if session.UserID != utils.Int64ToString(userID) {
|
||
|
|
common.ErrorResponse(c, http.StatusForbidden, "无权操作此测试会话")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
updatedSession, err := h.testService.PauseTest(sessionID)
|
||
|
|
if err != nil {
|
||
|
|
common.ErrorResponse(c, http.StatusBadRequest, err.Error())
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
common.SuccessResponse(c, gin.H{"data": updatedSession})
|
||
|
|
}
|
||
|
|
|
||
|
|
// ResumeTest 恢复测试
|
||
|
|
// @Summary 恢复测试
|
||
|
|
// @Tags Test
|
||
|
|
// @Param id path string true "会话ID"
|
||
|
|
// @Success 200 {object} common.Response
|
||
|
|
// @Router /api/v1/tests/sessions/{id}/resume [put]
|
||
|
|
func (h *TestHandler) ResumeTest(c *gin.Context) {
|
||
|
|
sessionID := c.Param("id")
|
||
|
|
|
||
|
|
// 验证用户权限
|
||
|
|
session, err := h.testService.GetTestSession(sessionID)
|
||
|
|
if err != nil {
|
||
|
|
common.ErrorResponse(c, http.StatusNotFound, "测试会话不存在")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
userID, _ := utils.GetUserIDFromContext(c)
|
||
|
|
if session.UserID != utils.Int64ToString(userID) {
|
||
|
|
common.ErrorResponse(c, http.StatusForbidden, "无权操作此测试会话")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
updatedSession, err := h.testService.ResumeTest(sessionID)
|
||
|
|
if err != nil {
|
||
|
|
common.ErrorResponse(c, http.StatusBadRequest, err.Error())
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
common.SuccessResponse(c, gin.H{"data": updatedSession})
|
||
|
|
}
|
||
|
|
|
||
|
|
// CompleteTest 完成测试
|
||
|
|
// @Summary 完成测试
|
||
|
|
// @Tags Test
|
||
|
|
// @Param id path string true "会话ID"
|
||
|
|
// @Success 200 {object} common.Response
|
||
|
|
// @Router /api/v1/tests/sessions/{id}/complete [put]
|
||
|
|
func (h *TestHandler) CompleteTest(c *gin.Context) {
|
||
|
|
sessionID := c.Param("id")
|
||
|
|
|
||
|
|
// 验证用户权限
|
||
|
|
session, err := h.testService.GetTestSession(sessionID)
|
||
|
|
if err != nil {
|
||
|
|
common.ErrorResponse(c, http.StatusNotFound, "测试会话不存在")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
userID, _ := utils.GetUserIDFromContext(c)
|
||
|
|
if session.UserID != utils.Int64ToString(userID) {
|
||
|
|
common.ErrorResponse(c, http.StatusForbidden, "无权操作此测试会话")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
result, err := h.testService.CompleteTest(sessionID)
|
||
|
|
if err != nil {
|
||
|
|
common.ErrorResponse(c, http.StatusBadRequest, err.Error())
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
common.SuccessResponse(c, gin.H{"data": result})
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetUserTestHistory 获取用户测试历史
|
||
|
|
// @Summary 获取用户测试历史
|
||
|
|
// @Tags Test
|
||
|
|
// @Param page query int false "页码"
|
||
|
|
// @Param page_size query int false "每页数量"
|
||
|
|
// @Success 200 {object} common.Response
|
||
|
|
// @Router /api/v1/tests/sessions [get]
|
||
|
|
func (h *TestHandler) GetUserTestHistory(c *gin.Context) {
|
||
|
|
userID, exists := utils.GetUserIDFromContext(c)
|
||
|
|
if !exists {
|
||
|
|
common.BadRequestResponse(c, "请先登录")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||
|
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10"))
|
||
|
|
|
||
|
|
results, total, err := h.testService.GetUserTestHistory(utils.Int64ToString(userID), page, pageSize)
|
||
|
|
if err != nil {
|
||
|
|
common.ErrorResponse(c, http.StatusInternalServerError, "获取测试历史失败")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
common.SuccessResponse(c, gin.H{
|
||
|
|
"sessions": results,
|
||
|
|
"pagination": gin.H{
|
||
|
|
"page": page,
|
||
|
|
"page_size": pageSize,
|
||
|
|
"total": total,
|
||
|
|
"total_page": (total + int64(pageSize) - 1) / int64(pageSize),
|
||
|
|
},
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetTestResultByID 获取测试结果详情
|
||
|
|
// @Summary 获取测试结果详情
|
||
|
|
// @Tags Test
|
||
|
|
// @Param id path string true "结果ID"
|
||
|
|
// @Success 200 {object} common.Response
|
||
|
|
// @Router /api/v1/tests/results/{id} [get]
|
||
|
|
func (h *TestHandler) GetTestResultByID(c *gin.Context) {
|
||
|
|
resultID := c.Param("id")
|
||
|
|
|
||
|
|
result, err := h.testService.GetTestResultByID(resultID)
|
||
|
|
if err != nil {
|
||
|
|
common.ErrorResponse(c, http.StatusNotFound, "测试结果不存在")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
// 验证用户权限
|
||
|
|
userID, _ := utils.GetUserIDFromContext(c)
|
||
|
|
if result.UserID != utils.Int64ToString(userID) {
|
||
|
|
common.ErrorResponse(c, http.StatusForbidden, "无权访问此测试结果")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
common.SuccessResponse(c, gin.H{"data": result})
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetUserTestStats 获取用户测试统计
|
||
|
|
// @Summary 获取用户测试统计
|
||
|
|
// @Tags Test
|
||
|
|
// @Success 200 {object} common.Response
|
||
|
|
// @Router /api/v1/tests/stats [get]
|
||
|
|
func (h *TestHandler) GetUserTestStats(c *gin.Context) {
|
||
|
|
userID, exists := utils.GetUserIDFromContext(c)
|
||
|
|
if !exists {
|
||
|
|
common.BadRequestResponse(c, "请先登录")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
stats, err := h.testService.GetUserTestStats(utils.Int64ToString(userID))
|
||
|
|
if err != nil {
|
||
|
|
common.ErrorResponse(c, http.StatusInternalServerError, "获取测试统计失败")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
common.SuccessResponse(c, stats)
|
||
|
|
}
|
||
|
|
|
||
|
|
// DeleteTestResult 删除测试结果
|
||
|
|
// @Summary 删除测试结果
|
||
|
|
// @Tags Test
|
||
|
|
// @Param id path string true "结果ID"
|
||
|
|
// @Success 200 {object} common.Response
|
||
|
|
// @Router /api/v1/tests/results/{id} [delete]
|
||
|
|
func (h *TestHandler) DeleteTestResult(c *gin.Context) {
|
||
|
|
resultID := c.Param("id")
|
||
|
|
|
||
|
|
// 验证用户权限
|
||
|
|
result, err := h.testService.GetTestResultByID(resultID)
|
||
|
|
if err != nil {
|
||
|
|
common.ErrorResponse(c, http.StatusNotFound, "测试结果不存在")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
userID, _ := utils.GetUserIDFromContext(c)
|
||
|
|
if result.UserID != utils.Int64ToString(userID) {
|
||
|
|
common.ErrorResponse(c, http.StatusForbidden, "无权删除此测试结果")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
if err := h.testService.DeleteTestResult(resultID); err != nil {
|
||
|
|
common.ErrorResponse(c, http.StatusInternalServerError, "删除测试结果失败")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
common.SuccessResponse(c, gin.H{"message": "删除成功"})
|
||
|
|
}
|