package handler import ( "errors" "net/http" "backend/internal/model" "backend/internal/service" "github.com/gin-gonic/gin" ) type CDKHandler struct { cdks *service.CDKService } func NewCDKHandler(cdks *service.CDKService) *CDKHandler { return &CDKHandler{cdks: cdks} } func (h *CDKHandler) List(c *gin.Context) { items, stats, names, err := h.cdks.List(c.Request.Context()) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"detail": "failed to load cdks"}) return } c.JSON(http.StatusOK, gin.H{"data": cdkPublic(items, names), "stats": stats}) } func (h *CDKHandler) Create(c *gin.Context) { var body struct { Amount int `json:"amount"` Count int `json:"count"` Note string `json:"note"` Type string `json:"type"` } if err := c.ShouldBindJSON(&body); err != nil { c.JSON(http.StatusBadRequest, gin.H{"detail": "invalid request body"}) return } items, err := h.cdks.Generate(c.Request.Context(), body.Amount, body.Count, body.Note, body.Type) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"detail": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"ok": true, "created": cdkPublic(items, nil)}) } func (h *CDKHandler) Delete(c *gin.Context) { if err := h.cdks.Delete(c.Request.Context(), c.Param("code")); err != nil { if errors.Is(err, service.ErrNotFound) { c.JSON(http.StatusNotFound, gin.H{"detail": "cdk not found"}) return } c.JSON(http.StatusInternalServerError, gin.H{"detail": "failed to delete cdk"}) return } c.JSON(http.StatusOK, gin.H{"ok": true}) } // DeleteBulk removes multiple CDK codes in one call (multi-select). func (h *CDKHandler) DeleteBulk(c *gin.Context) { var body struct { Codes []string `json:"codes"` } if err := c.ShouldBindJSON(&body); err != nil { c.JSON(http.StatusBadRequest, gin.H{"detail": "invalid request body"}) return } if len(body.Codes) == 0 { c.JSON(http.StatusBadRequest, gin.H{"detail": "未选择任何兑换码"}) return } n, err := h.cdks.DeleteBulk(c.Request.Context(), body.Codes) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"detail": "failed to delete cdks"}) return } c.JSON(http.StatusOK, gin.H{"ok": true, "deleted": n}) } func cdkPublic(items []model.CDKCode, nameByID map[string]string) []gin.H { out := make([]gin.H, 0, len(items)) for _, item := range items { var redeemedByName any if item.RedeemedBy != nil && *item.RedeemedBy != "" { if name, ok := nameByID[*item.RedeemedBy]; ok { redeemedByName = name } } out = append(out, gin.H{ "code": item.Code, "amount": item.Amount, "status": item.Status, "type": item.Type, "batch_id": item.BatchID, "note": item.Note, "redeemed_by": item.RedeemedBy, "redeemed_by_name": redeemedByName, "redeemed_at": unixSecPtr(item.RedeemedAt), "created_at": unixSec(item.CreatedAt), }) } return out }