package services import ( "time" "github.com/inchstep/server/internal/models" "gorm.io/gorm" ) type PointsService struct { db *gorm.DB } func NewPointsService(db *gorm.DB) *PointsService { return &PointsService{db: db} } const ( PointsCheckIn = 1 PointsStreak7 = 5 PointsStreak30 = 20 PointsGoalComplete = 10 PointsPostShare = 2 PointsComment = 1 PointsInviteUser = 15 ) // AddPoints 为用户增加积分 func (s *PointsService) AddPoints(userID string, amount int, reason string) error { return s.db.Model(&models.User{}).Where("id = ?", userID). UpdateColumn("points", gorm.Expr("points + ?", amount)).Error } // CheckAndAwardStreak 检查并发放连续打卡奖励 func (s *PointsService) CheckAndAwardStreak(userID string, streak int) error { switch streak { case 7: return s.AddPoints(userID, PointsStreak7, "连续打卡 7 天") case 30: return s.AddPoints(userID, PointsStreak30, "连续打卡 30 天") } return nil } // AwardCheckIn 打卡奖励 func (s *PointsService) AwardCheckIn(userID string) error { return s.AddPoints(userID, PointsCheckIn, "每日打卡") } func ptr(s string) *string { return &s } // predefinedAchievements 预定义成就列表 var predefinedAchievements = []models.Achievement{ {ID: "first_checkin", Name: "初露锋芒", Rarity: "bronze", Condition: ptr("完成第 1 次打卡")}, {ID: "streak_7", Name: "七日坚持", Rarity: "bronze", Condition: ptr("连续 7 天打卡")}, {ID: "streak_15", Name: "半月之约", Rarity: "bronze", Condition: ptr("连续 15 天打卡")}, {ID: "streak_30", Name: "月满则盈", Rarity: "silver", Condition: ptr("连续 30 天打卡")}, {ID: "streak_100", Name: "百日筑基", Rarity: "gold", Condition: ptr("连续 100 天打卡")}, {ID: "all_round", Name: "全面开花", Rarity: "silver", Condition: ptr("同时有 5 个打卡项保持活跃")}, {ID: "social_star", Name: "社交达人", Rarity: "silver", Condition: ptr("获得 50 个点赞")}, {ID: "group_star", Name: "小组之星", Rarity: "silver", Condition: ptr("在小组内连续打卡满 30 天")}, {ID: "makeup_master", Name: "神补刀", Rarity: "bronze", Condition: ptr("使用补卡功能 10 次")}, {ID: "year_champion", Name: "年度坚持王", Rarity: "gold", Condition: ptr("全年打卡完成率 ≥ 80%")}, } // InitAchievements 初始化成就数据 func (s *PointsService) InitAchievements() error { for _, a := range predefinedAchievements { s.db.Where("id = ?", a.ID).FirstOrCreate(&a) } return nil } // UnlockAchievement 解锁成就 func (s *PointsService) UnlockAchievement(userID, achievementID string) (*models.UserAchievement, error) { ua := &models.UserAchievement{ UserID: userID, AchievementID: achievementID, UnlockedAt: time.Now(), } if err := s.db.Create(ua).Error; err != nil { return nil, err } return ua, nil } // GetUserAchievements 获取用户已解锁的成就 func (s *PointsService) GetUserAchievements(userID string) ([]models.UserAchievement, error) { var list []models.UserAchievement err := s.db.Where("user_id = ?", userID).Preload("Achievement").Find(&list).Error return list, err } // GetAllAchievements 获取所有成就 func (s *PointsService) GetAllAchievements() ([]models.Achievement, error) { var list []models.Achievement err := s.db.Find(&list).Error return list, err } // DeductPoints 扣除积分 func (s *PointsService) DeductPoints(userID string, amount int) error { var user models.User if err := s.db.First(&user, "id = ?", userID).Error; err != nil { return err } if user.Points < amount { return gorm.ErrRecordNotFound // 积分不足 } return s.db.Model(&user).UpdateColumn("points", gorm.Expr("points - ?", amount)).Error }