package handlers import ( "net/http" "strconv" "time" "github.com/gin-gonic/gin" "github.com/inchstep/server/internal/middleware" "github.com/inchstep/server/internal/models" "github.com/inchstep/server/internal/services" ) type CheckInHandler struct { checkinSvc *services.CheckInService pointsSvc *services.PointsService } func NewCheckInHandler(cs *services.CheckInService, ps *services.PointsService) *CheckInHandler { return &CheckInHandler{checkinSvc: cs, pointsSvc: ps} } // ---------- 打卡项 ---------- func (h *CheckInHandler) CreateItem(c *gin.Context) { userID := middleware.GetUserID(c) var item models.CheckInItem if err := c.ShouldBindJSON(&item); err != nil { middleware.Error(c, http.StatusBadRequest, 400, "参数格式错误") return } if item.Name == "" { middleware.Error(c, http.StatusBadRequest, 400, "打卡项名称不能为空") return } if err := h.checkinSvc.CreateItem(userID, &item); err != nil { middleware.Error(c, http.StatusInternalServerError, 500, err.Error()) return } middleware.Success(c, item) } func (h *CheckInHandler) ListItems(c *gin.Context) { userID := middleware.GetUserID(c) items, err := h.checkinSvc.GetUserItems(userID) if err != nil { middleware.Error(c, http.StatusInternalServerError, 500, err.Error()) return } middleware.Success(c, items) } func (h *CheckInHandler) GetItem(c *gin.Context) { userID := middleware.GetUserID(c) id := c.Param("id") item, err := h.checkinSvc.GetItemByID(id, userID) if err != nil { middleware.Error(c, http.StatusNotFound, 404, "打卡项不存在") return } middleware.Success(c, item) } func (h *CheckInHandler) UpdateItem(c *gin.Context) { userID := middleware.GetUserID(c) id := c.Param("id") var updates map[string]interface{} if err := c.ShouldBindJSON(&updates); err != nil { middleware.Error(c, http.StatusBadRequest, 400, "参数格式错误") return } item, err := h.checkinSvc.UpdateItem(id, userID, updates) if err != nil { middleware.Error(c, http.StatusInternalServerError, 500, err.Error()) return } middleware.Success(c, item) } func (h *CheckInHandler) DeleteItem(c *gin.Context) { userID := middleware.GetUserID(c) id := c.Param("id") if err := h.checkinSvc.DeleteItem(id, userID); err != nil { middleware.Error(c, http.StatusInternalServerError, 500, err.Error()) return } middleware.Success(c, nil) } func (h *CheckInHandler) PauseItem(c *gin.Context) { userID := middleware.GetUserID(c) id := c.Param("id") if err := h.checkinSvc.PauseItem(id, userID); err != nil { middleware.Error(c, http.StatusInternalServerError, 500, err.Error()) return } middleware.Success(c, nil) } func (h *CheckInHandler) ResumeItem(c *gin.Context) { userID := middleware.GetUserID(c) id := c.Param("id") if err := h.checkinSvc.ResumeItem(id, userID); err != nil { middleware.Error(c, http.StatusInternalServerError, 500, err.Error()) return } middleware.Success(c, nil) } // ---------- 打卡记录 ---------- type createRecordReq struct { ItemID string `json:"itemId" binding:"required"` CheckDate string `json:"checkDate"` Note *string `json:"note,omitempty"` Images *string `json:"images,omitempty"` } func (h *CheckInHandler) CreateRecord(c *gin.Context) { userID := middleware.GetUserID(c) var req createRecordReq if err := c.ShouldBindJSON(&req); err != nil { middleware.Error(c, http.StatusBadRequest, 400, "参数格式错误") return } checkDate := time.Now() if req.CheckDate != "" { if parsed, err := time.Parse("2006-01-02", req.CheckDate); err == nil { checkDate = parsed } } record, err := h.checkinSvc.CreateRecord(userID, req.ItemID, checkDate, req.Note, req.Images) if err != nil { middleware.Error(c, http.StatusBadRequest, 400, err.Error()) return } // 发放打卡积分 h.pointsSvc.AwardCheckIn(userID) middleware.Success(c, record) } type makeupRecordReq struct { ItemID string `json:"itemId" binding:"required"` CheckDate string `json:"checkDate" binding:"required"` } func (h *CheckInHandler) MakeupRecord(c *gin.Context) { userID := middleware.GetUserID(c) var req makeupRecordReq if err := c.ShouldBindJSON(&req); err != nil { middleware.Error(c, http.StatusBadRequest, 400, "参数格式错误") return } checkDate, err := time.Parse("2006-01-02", req.CheckDate) if err != nil { middleware.Error(c, http.StatusBadRequest, 400, "日期格式错误,请使用 YYYY-MM-DD") return } record, err := h.checkinSvc.MakeupRecord(userID, req.ItemID, checkDate, 5) if err != nil { middleware.Error(c, http.StatusBadRequest, 400, err.Error()) return } middleware.Success(c, record) } func (h *CheckInHandler) GetRecords(c *gin.Context) { userID := middleware.GetUserID(c) itemID := c.Query("itemId") startStr := c.DefaultQuery("start", time.Now().AddDate(0, -1, 0).Format("2006-01-02")) endStr := c.DefaultQuery("end", time.Now().Format("2006-01-02")) start, _ := time.Parse("2006-01-02", startStr) end, _ := time.Parse("2006-01-02", endStr) end = end.Add(24 * time.Hour) records, err := h.checkinSvc.GetRecords(userID, itemID, start, end) if err != nil { middleware.Error(c, http.StatusInternalServerError, 500, err.Error()) return } middleware.Success(c, records) } func (h *CheckInHandler) GetStreak(c *gin.Context) { userID := middleware.GetUserID(c) itemID := c.Param("id") streak, err := h.checkinSvc.GetStreak(itemID, userID) if err != nil { middleware.Error(c, http.StatusInternalServerError, 500, err.Error()) return } middleware.Success(c, gin.H{"itemId": itemID, "streak": streak}) } func (h *CheckInHandler) GetMonthlyStats(c *gin.Context) { userID := middleware.GetUserID(c) yearStr := c.DefaultQuery("year", strconv.Itoa(time.Now().Year())) monthStr := c.DefaultQuery("month", strconv.Itoa(int(time.Now().Month()))) year, _ := strconv.Atoi(yearStr) month, _ := strconv.Atoi(monthStr) stats, err := h.checkinSvc.GetMonthlyStats(userID, year, month) if err != nil { middleware.Error(c, http.StatusInternalServerError, 500, err.Error()) return } middleware.Success(c, stats) } func (h *CheckInHandler) GetTodayStatus(c *gin.Context) { userID := middleware.GetUserID(c) status, err := h.checkinSvc.GetTodayStatus(userID) if err != nil { middleware.Error(c, http.StatusInternalServerError, 500, err.Error()) return } middleware.Success(c, status) }