首次提交
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user