新增语言学习后台服务
- 分类管理:支持分类的增删改查 - 单词管理:支持单词的增删改查,包含音标、释义、例句等字段 - 更新 README 项目说明 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/fish/language/backend/internal/models"
|
||||
"github.com/fish/language/backend/internal/services"
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
// WordHandler handles HTTP requests for words.
|
||||
type WordHandler struct {
|
||||
svc *services.WordService
|
||||
}
|
||||
|
||||
// NewWordHandler creates a new WordHandler.
|
||||
func NewWordHandler(svc *services.WordService) *WordHandler {
|
||||
return &WordHandler{svc: svc}
|
||||
}
|
||||
|
||||
// Register mounts word routes.
|
||||
func (h *WordHandler) Register(r chi.Router) {
|
||||
r.Get("/words", h.List)
|
||||
r.Post("/words", h.Create)
|
||||
r.Get("/words/{id}", h.Get)
|
||||
r.Put("/words/{id}", h.Update)
|
||||
r.Delete("/words/{id}", h.Delete)
|
||||
}
|
||||
|
||||
// List returns a paginated list of words.
|
||||
func (h *WordHandler) List(w http.ResponseWriter, r *http.Request) {
|
||||
req := models.ListWordsRequest{}
|
||||
if v := r.URL.Query().Get("category_id"); v != "" {
|
||||
if id64, err := strconv.ParseInt(v, 10, 32); err == nil {
|
||||
id := int32(id64)
|
||||
req.CategoryID = &id
|
||||
}
|
||||
}
|
||||
req.Keyword = r.URL.Query().Get("keyword")
|
||||
if v := r.URL.Query().Get("page"); v != "" {
|
||||
if page, err := strconv.ParseInt(v, 10, 32); err == nil {
|
||||
req.Page = int32(page)
|
||||
}
|
||||
}
|
||||
if v := r.URL.Query().Get("page_size"); v != "" {
|
||||
if ps, err := strconv.ParseInt(v, 10, 32); err == nil {
|
||||
req.PageSize = int32(ps)
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := h.svc.List(r.Context(), req)
|
||||
if err != nil {
|
||||
status, code, msg := MapError(err)
|
||||
RespondError(w, status, code, msg)
|
||||
return
|
||||
}
|
||||
RespondSuccess(w, resp)
|
||||
}
|
||||
|
||||
// Get returns a word by id.
|
||||
func (h *WordHandler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
id, err := parseID(r)
|
||||
if err != nil {
|
||||
RespondError(w, http.StatusBadRequest, 10002, "invalid id")
|
||||
return
|
||||
}
|
||||
item, err := h.svc.Get(r.Context(), id)
|
||||
if err != nil {
|
||||
status, code, msg := MapError(err)
|
||||
RespondError(w, status, code, msg)
|
||||
return
|
||||
}
|
||||
RespondSuccess(w, item)
|
||||
}
|
||||
|
||||
// Create creates a new word.
|
||||
func (h *WordHandler) Create(w http.ResponseWriter, r *http.Request) {
|
||||
var req models.CreateWordRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
RespondError(w, http.StatusBadRequest, 10003, "invalid request body")
|
||||
return
|
||||
}
|
||||
if req.Word == "" || req.Translation == "" || req.CategoryID == 0 {
|
||||
RespondError(w, http.StatusBadRequest, 10004, "word, translation and category_id are required")
|
||||
return
|
||||
}
|
||||
item, err := h.svc.Create(r.Context(), req)
|
||||
if err != nil {
|
||||
status, code, msg := MapError(err)
|
||||
RespondError(w, status, code, msg)
|
||||
return
|
||||
}
|
||||
RespondJSON(w, http.StatusCreated, modelsAPIResponse{Code: 0, Message: "created", Data: item})
|
||||
}
|
||||
|
||||
// Update updates a word.
|
||||
func (h *WordHandler) Update(w http.ResponseWriter, r *http.Request) {
|
||||
id, err := parseID(r)
|
||||
if err != nil {
|
||||
RespondError(w, http.StatusBadRequest, 10002, "invalid id")
|
||||
return
|
||||
}
|
||||
var req models.UpdateWordRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
RespondError(w, http.StatusBadRequest, 10003, "invalid request body")
|
||||
return
|
||||
}
|
||||
if req.Word == "" || req.Translation == "" || req.CategoryID == 0 {
|
||||
RespondError(w, http.StatusBadRequest, 10004, "word, translation and category_id are required")
|
||||
return
|
||||
}
|
||||
item, err := h.svc.Update(r.Context(), id, req)
|
||||
if err != nil {
|
||||
status, code, msg := MapError(err)
|
||||
RespondError(w, status, code, msg)
|
||||
return
|
||||
}
|
||||
RespondSuccess(w, item)
|
||||
}
|
||||
|
||||
// Delete removes a word.
|
||||
func (h *WordHandler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||
id, err := parseID(r)
|
||||
if err != nil {
|
||||
RespondError(w, http.StatusBadRequest, 10002, "invalid id")
|
||||
return
|
||||
}
|
||||
if err := h.svc.Delete(r.Context(), id); err != nil {
|
||||
status, code, msg := MapError(err)
|
||||
RespondError(w, status, code, msg)
|
||||
return
|
||||
}
|
||||
RespondSuccess(w, nil)
|
||||
}
|
||||
Reference in New Issue
Block a user