feat: update smoke profile area handling
This commit is contained in:
@@ -18,6 +18,7 @@ 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"`
|
||||
@@ -71,6 +72,13 @@ func (h *SmokeHandler) UpsertProfile(c *gin.Context) {
|
||||
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
|
||||
@@ -91,6 +99,7 @@ func (h *SmokeHandler) UpsertProfile(c *gin.Context) {
|
||||
BaselineCigsPerDay: req.BaselineCigsPerDay,
|
||||
SmokingYears: req.SmokingYears,
|
||||
PackPriceCent: req.PackPriceCent,
|
||||
Mode: req.Mode,
|
||||
SmokeMotivations: req.SmokeMotivations,
|
||||
QuitMotivations: req.QuitMotivations,
|
||||
WakeUpTime: req.WakeUpTime,
|
||||
|
||||
@@ -67,6 +67,7 @@ type SmokeUserProfile struct {
|
||||
|
||||
SmokeMotivations StringSlice `gorm:"column:smoke_motivations;type:json;comment:抽烟动机(JSON数组)" json:"smoke_motivations"`
|
||||
QuitMotivations StringSlice `gorm:"column:quit_motivations;type:json;comment:戒烟动力(JSON数组)" json:"quit_motivations"`
|
||||
Mode string `gorm:"column:mode;size:16;default:record;comment:使用模式(quit=戒烟打卡,record=记录抽烟)" json:"mode,omitempty"`
|
||||
|
||||
WakeUpTime string `gorm:"column:wake_up_time;size:5;comment:起床时间(HH:MM)" json:"wake_up_time"`
|
||||
SleepTime string `gorm:"column:sleep_time;size:5;comment:入睡时间(HH:MM)" json:"sleep_time"`
|
||||
|
||||
@@ -16,6 +16,11 @@ var (
|
||||
ErrSmokeProfileInvalidTime = errors.New("invalid time format, expected HH:MM")
|
||||
)
|
||||
|
||||
const (
|
||||
SmokeModeQuit = "quit"
|
||||
SmokeModeRecord = "record"
|
||||
)
|
||||
|
||||
type SmokeProfileService struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
@@ -47,6 +52,7 @@ func (s *SmokeProfileService) GetView(ctx context.Context, uid int) (SmokeProfil
|
||||
BaselineIntervalMinute: 0,
|
||||
}, nil
|
||||
}
|
||||
profile.Mode = normalizedSmokeMode(profile.Mode)
|
||||
|
||||
awakeMinutes, err := awakeMinutesWithFallback(profile.WakeUpTime, profile.SleepTime)
|
||||
if err != nil {
|
||||
@@ -83,6 +89,7 @@ type UpsertSmokeProfileRequest struct {
|
||||
BaselineCigsPerDay *int
|
||||
SmokingYears *float64
|
||||
PackPriceCent *int
|
||||
Mode *string
|
||||
|
||||
SmokeMotivations *[]string
|
||||
QuitMotivations *[]string
|
||||
@@ -116,6 +123,12 @@ func (s *SmokeProfileService) Upsert(ctx context.Context, uid int, req UpsertSmo
|
||||
*dst = *v
|
||||
}
|
||||
}
|
||||
applyMode := func(dst *string, v *string) {
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
*dst = normalizedSmokeMode(*v)
|
||||
}
|
||||
applyTimeStr := func(dst *string, v *string) error {
|
||||
if v == nil {
|
||||
return nil
|
||||
@@ -135,6 +148,7 @@ func (s *SmokeProfileService) Upsert(ctx context.Context, uid int, req UpsertSmo
|
||||
applyInt(&profile.BaselineCigsPerDay, req.BaselineCigsPerDay)
|
||||
applyFloat(&profile.SmokingYears, req.SmokingYears)
|
||||
applyInt(&profile.PackPriceCent, req.PackPriceCent)
|
||||
applyMode(&profile.Mode, req.Mode)
|
||||
|
||||
if req.SmokeMotivations != nil {
|
||||
profile.SmokeMotivations = smokemodel.StringSlice(*req.SmokeMotivations)
|
||||
@@ -154,6 +168,7 @@ func (s *SmokeProfileService) Upsert(ctx context.Context, uid int, req UpsertSmo
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
profile.Mode = normalizedSmokeMode(profile.Mode)
|
||||
if profile.OnboardingCompletedAt == nil && isSmokeProfileCompleted(profile) {
|
||||
profile.OnboardingCompletedAt = &now
|
||||
}
|
||||
@@ -215,6 +230,17 @@ func baselineIntervalMinutes(awakeMinutes int, baselineCigsPerDay int) int {
|
||||
return interval
|
||||
}
|
||||
|
||||
func normalizedSmokeMode(mode string) string {
|
||||
switch strings.TrimSpace(mode) {
|
||||
case SmokeModeQuit:
|
||||
return SmokeModeQuit
|
||||
case SmokeModeRecord:
|
||||
return SmokeModeRecord
|
||||
default:
|
||||
return SmokeModeRecord
|
||||
}
|
||||
}
|
||||
|
||||
func parseHHMMToMinutes(s string) (int, error) {
|
||||
s = strings.TrimSpace(s)
|
||||
if len(s) != 5 || s[2] != ':' {
|
||||
|
||||
@@ -106,3 +106,23 @@ func TestIsSmokeProfileCompleted(t *testing.T) {
|
||||
t.Fatalf("isSmokeProfileCompleted: expected false when quit_motivations missing")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizedSmokeMode(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cases := []struct {
|
||||
in string
|
||||
want string
|
||||
}{
|
||||
{in: SmokeModeQuit, want: SmokeModeQuit},
|
||||
{in: SmokeModeRecord, want: SmokeModeRecord},
|
||||
{in: "", want: SmokeModeRecord},
|
||||
{in: "unknown", want: SmokeModeRecord},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
if got := normalizedSmokeMode(c.in); got != c.want {
|
||||
t.Fatalf("normalizedSmokeMode(%q): got %q, want %q", c.in, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user