package handler import ( "fmt" "net/http" "strconv" "strings" "memora-api/internal/request" "memora-api/internal/service" "github.com/gin-gonic/gin" ) type WordHandler struct { wordService *service.WordService } func NewWordHandler(wordService *service.WordService) *WordHandler { return &WordHandler{wordService: wordService} } // 添加单词(记忆模式) func (h *WordHandler) AddWord(c *gin.Context) { var req request.AddWordRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 调用有道API查询 youdaoResp, err := h.wordService.QueryWord(req.Word) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "查询失败: " + err.Error()}) return } if youdaoResp.ErrorCode != "0" && youdaoResp.ErrorCode != "" { c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("有道API错误: %s", youdaoResp.ErrorCode)}) return } // 保存到数据库 word, err := h.wordService.SaveWord(req.Word, youdaoResp) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "保存失败: " + err.Error()}) return } c.JSON(http.StatusOK, gin.H{ "message": "单词添加成功", "data": word, }) } // 获取复习单词列表 func (h *WordHandler) GetReviewWords(c *gin.Context) { mode := c.DefaultQuery("mode", "spelling") limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10")) words, err := h.wordService.GetReviewWords(mode, limit) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"data": words}) } // 提交复习答案 func (h *WordHandler) SubmitReview(c *gin.Context) { var req request.ReviewAnswerRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } result, err := h.wordService.SubmitReviewAnswer(req) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"data": result}) } // 获取所有单词 func (h *WordHandler) GetWords(c *gin.Context) { limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20")) offset, _ := strconv.Atoi(c.DefaultQuery("offset", "0")) words, total, err := h.wordService.GetAllWords(limit, offset) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{ "data": words, "total": total, }) } // 获取统计信息 func (h *WordHandler) GetStatistics(c *gin.Context) { stats, err := h.wordService.GetStatistics() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"data": stats}) } // 获取音频文件 func (h *WordHandler) GetAudio(c *gin.Context) { word := c.Query("word") audioType := c.DefaultQuery("type", "uk") if word == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "缺少word参数"}) return } // very small sanitization word = strings.TrimSpace(word) if word == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "word为空"}) return } for _, r := range word { if !(r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z') { c.JSON(http.StatusBadRequest, gin.H{"error": "word包含非法字符"}) return } } filename := word + "_" + audioType + ".mp3" path := "./audio/" + filename c.File(path) }