package handler import ( "errors" "io" "net/http" "strings" "time" "github.com/gin-gonic/gin" "wx_service/internal/middleware" "wx_service/internal/model" smokeservice "wx_service/internal/smoke/service" ) type upsertSmokeProfileRequest struct { BaselineCigsPerDay *int `json:"baseline_cigs_per_day"` SmokingYears *float64 `json:"smoking_years"` PackPriceCent *int `json:"pack_price_cent"` Mode *string `json:"mode"` SmokeMotivations *[]string `json:"smoke_motivations"` QuitMotivations *[]string `json:"quit_motivations"` WakeUpTime *string `json:"wake_up_time"` SleepTime *string `json:"sleep_time"` QuitDate *string `json:"quit_date"` AchievementThemeID *uint `json:"achievement_theme_id"` } func (h *SmokeHandler) GetProfile(c *gin.Context) { user := middleware.MustCurrentUser(c) view, err := h.smokeProfileService.GetView(c.Request.Context(), int(user.ID)) if err != nil { if errors.Is(err, smokeservice.ErrSmokeProfileInvalidTime) { c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "作息时间格式错误,应为 HH:MM")) return } c.JSON(http.StatusInternalServerError, model.Error(http.StatusInternalServerError, "获取基础信息失败,请稍后重试")) return } c.JSON(http.StatusOK, model.Success(view)) } func (h *SmokeHandler) UpsertProfile(c *gin.Context) { user := middleware.MustCurrentUser(c) var req upsertSmokeProfileRequest if err := c.ShouldBindJSON(&req); err != nil && !errors.Is(err, io.EOF) { c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "请求参数错误")) return } if req.BaselineCigsPerDay != nil { if *req.BaselineCigsPerDay < 0 || *req.BaselineCigsPerDay > 300 { c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "baseline_cigs_per_day 应在 0~300")) return } } if req.SmokingYears != nil { if *req.SmokingYears < 0 || *req.SmokingYears > 80 { c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "smoking_years 应在 0~80")) return } } if req.PackPriceCent != nil { if *req.PackPriceCent < 0 || *req.PackPriceCent > 1000000 { c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "pack_price_cent 应在 0~1000000")) return } } if req.Mode != nil { mode := strings.TrimSpace(*req.Mode) if mode != "" && mode != smokeservice.SmokeModeQuit && mode != smokeservice.SmokeModeRecord { c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "mode 仅支持 quit 或 record")) return } } quitDateProvided := false var quitDate *time.Time if req.QuitDate != nil { quitDateProvided = true value := strings.TrimSpace(*req.QuitDate) if value != "" { parsed, err := time.ParseInLocation(dateLayout, value, time.Local) if err != nil { c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "quit_date 格式错误,应为 YYYY-MM-DD")) return } quitDate = &parsed } } achievementThemeIDProvided := req.AchievementThemeID != nil view, err := h.smokeProfileService.Upsert(c.Request.Context(), int(user.ID), smokeservice.UpsertSmokeProfileRequest{ BaselineCigsPerDay: req.BaselineCigsPerDay, SmokingYears: req.SmokingYears, PackPriceCent: req.PackPriceCent, Mode: req.Mode, SmokeMotivations: req.SmokeMotivations, QuitMotivations: req.QuitMotivations, WakeUpTime: req.WakeUpTime, SleepTime: req.SleepTime, QuitDateProvided: quitDateProvided, QuitDate: quitDate, AchievementThemeIDProvided: achievementThemeIDProvided, AchievementThemeID: req.AchievementThemeID, }) if err != nil { if errors.Is(err, smokeservice.ErrSmokeProfileInvalidTime) { c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "作息时间格式错误,应为 HH:MM")) return } c.JSON(http.StatusInternalServerError, model.Error(http.StatusInternalServerError, "保存基础信息失败,请稍后重试")) return } c.JSON(http.StatusOK, model.Success(view)) }