package service import ( "dianshang/internal/model" "dianshang/internal/repository" "errors" "fmt" "time" "gorm.io/gorm" ) // PointsService 积分服务 type PointsService struct { pointsRepo *repository.PointsRepository db *gorm.DB } // NewPointsService 创建积分服务 func NewPointsService(pointsRepo *repository.PointsRepository, db *gorm.DB) *PointsService { return &PointsService{ pointsRepo: pointsRepo, db: db, } } // GetUserPoints 获取用户积分 func (s *PointsService) GetUserPoints(userID uint) (int, error) { return s.pointsRepo.GetUserPoints(userID) } // AddPoints 增加用户积分 func (s *PointsService) AddPoints(userID uint, amount int, description string, orderID *uint, orderNo, productName string) error { if amount <= 0 { return errors.New("积分数量必须大于0") } // 开启事务 tx := s.db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() // 获取当前积分 currentPoints, err := s.pointsRepo.GetUserPoints(userID) if err != nil { tx.Rollback() return err } // 更新用户积分 newPoints := currentPoints + amount err = s.pointsRepo.UpdateUserPoints(userID, newPoints) if err != nil { tx.Rollback() return err } // 创建积分历史记录 history := &model.PointsHistory{ UserID: userID, Type: 1, // 获得 Points: amount, Description: description, OrderID: orderID, OrderNo: orderNo, ProductName: productName, } err = s.pointsRepo.CreatePointsHistory(history) if err != nil { tx.Rollback() return err } return tx.Commit().Error } // DeductPoints 扣减用户积分 func (s *PointsService) DeductPoints(userID uint, amount int, description string, orderID *uint, orderNo, productName string) error { if amount <= 0 { return errors.New("积分数量必须大于0") } // 开启事务 tx := s.db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() // 获取当前积分 currentPoints, err := s.pointsRepo.GetUserPoints(userID) if err != nil { tx.Rollback() return err } // 检查积分是否足够 if currentPoints < amount { tx.Rollback() return errors.New("积分不足") } // 更新用户积分 newPoints := currentPoints - amount err = s.pointsRepo.UpdateUserPoints(userID, newPoints) if err != nil { tx.Rollback() return err } // 创建积分历史记录 history := &model.PointsHistory{ UserID: userID, Type: 2, // 消费 Points: amount, Description: description, OrderID: orderID, OrderNo: orderNo, ProductName: productName, } err = s.pointsRepo.CreatePointsHistory(history) if err != nil { tx.Rollback() return err } return tx.Commit().Error } // GetPointsHistory 获取积分历史记录 func (s *PointsService) GetPointsHistory(userID uint, page, pageSize int) ([]model.PointsHistory, map[string]interface{}, error) { if page <= 0 { page = 1 } if pageSize <= 0 || pageSize > 100 { pageSize = 20 } histories, total, err := s.pointsRepo.GetPointsHistory(userID, page, pageSize) if err != nil { return nil, nil, err } // 构建分页信息 totalPages := (int(total) + pageSize - 1) / pageSize pagination := map[string]interface{}{ "total": total, "page": page, "page_size": pageSize, "total_pages": totalPages, } return histories, pagination, nil } // GetPointsRules 获取积分规则列表 func (s *PointsService) GetPointsRules() ([]model.PointsRule, error) { return s.pointsRepo.GetPointsRules() } // GetPointsExchangeList 获取积分兑换商品列表 func (s *PointsService) GetPointsExchangeList() ([]model.PointsExchange, error) { return s.pointsRepo.GetPointsExchangeList() } // ExchangePoints 积分兑换 func (s *PointsService) ExchangePoints(userID, exchangeID uint) error { // 开启事务 tx := s.db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() // 获取兑换商品信息 exchange, err := s.pointsRepo.GetPointsExchangeByID(exchangeID) if err != nil { tx.Rollback() return errors.New("兑换商品不存在") } // 检查库存 if exchange.Stock > 0 && exchange.ExchangeCount >= exchange.Stock { tx.Rollback() return errors.New("商品库存不足") } // 获取用户当前积分 currentPoints, err := s.pointsRepo.GetUserPoints(userID) if err != nil { tx.Rollback() return err } // 检查积分是否足够 if currentPoints < exchange.Points { tx.Rollback() return errors.New("积分不足") } // 扣减积分 description := fmt.Sprintf("兑换商品:%s", exchange.Name) err = s.DeductPoints(userID, exchange.Points, description, nil, "", exchange.Name) if err != nil { tx.Rollback() return err } // 创建兑换记录 record := &model.PointsExchangeRecord{ UserID: userID, PointsExchangeID: exchangeID, Points: exchange.Points, Status: 1, // 已兑换 } err = s.pointsRepo.CreatePointsExchangeRecord(record) if err != nil { tx.Rollback() return err } // 更新兑换次数 err = s.pointsRepo.UpdatePointsExchangeCount(exchangeID) if err != nil { tx.Rollback() return err } return tx.Commit().Error } // GetUserExchangeRecords 获取用户兑换记录 func (s *PointsService) GetUserExchangeRecords(userID uint, page, pageSize int) ([]model.PointsExchangeRecord, map[string]interface{}, error) { if page <= 0 { page = 1 } if pageSize <= 0 || pageSize > 100 { pageSize = 20 } records, total, err := s.pointsRepo.GetUserExchangeRecords(userID, page, pageSize) if err != nil { return nil, nil, err } // 构建分页信息 totalPages := (int(total) + pageSize - 1) / pageSize pagination := map[string]interface{}{ "total": total, "page": page, "page_size": pageSize, "total_pages": totalPages, } return records, pagination, nil } // GetPointsOverview 获取积分概览 func (s *PointsService) GetPointsOverview(userID uint) (map[string]interface{}, error) { // 获取用户当前积分 currentPoints, err := s.pointsRepo.GetUserPoints(userID) if err != nil { return nil, err } // 获取积分历史统计 var totalEarned, totalSpent, thisMonthEarned, thisMonthSpent int64 // 统计总获得积分 s.db.Model(&model.PointsHistory{}). Where("user_id = ? AND type = ?", userID, 1). Select("COALESCE(SUM(points), 0)"). Scan(&totalEarned) // 统计总消费积分 s.db.Model(&model.PointsHistory{}). Where("user_id = ? AND type = ?", userID, 2). Select("COALESCE(SUM(points), 0)"). Scan(&totalSpent) // 获取本月的开始时间和结束时间 now := time.Now() firstDayOfMonth := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) firstDayOfNextMonth := firstDayOfMonth.AddDate(0, 1, 0) // 统计本月获得积分 s.db.Model(&model.PointsHistory{}). Where("user_id = ? AND type = ? AND created_at >= ? AND created_at < ?", userID, 1, firstDayOfMonth, firstDayOfNextMonth). Select("COALESCE(SUM(points), 0)"). Scan(&thisMonthEarned) // 统计本月消费积分 s.db.Model(&model.PointsHistory{}). Where("user_id = ? AND type = ? AND created_at >= ? AND created_at < ?", userID, 2, firstDayOfMonth, firstDayOfNextMonth). Select("COALESCE(SUM(points), 0)"). Scan(&thisMonthSpent) overview := map[string]interface{}{ "total_points": currentPoints, "available_points": currentPoints, "frozen_points": 0, "total_earned": totalEarned, "total_spent": totalSpent, "this_month_earned": thisMonthEarned, "this_month_spent": thisMonthSpent, } return overview, nil } // CheckAndGiveDailyLoginPoints 检查并给予每日首次登录积分 func (s *PointsService) CheckAndGiveDailyLoginPoints(userID uint) (bool, error) { // 获取今天的开始时间(00:00:00) now := time.Now() today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) tomorrow := today.Add(24 * time.Hour) // 检查今天是否已经有登录积分记录 var count int64 err := s.db.Model(&model.PointsHistory{}). Where("user_id = ? AND description = ? AND created_at >= ? AND created_at < ?", userID, "每日首次登录", today, tomorrow). Count(&count).Error if err != nil { return false, fmt.Errorf("检查每日登录记录失败: %v", err) } // 如果今天已经有登录积分记录,则不再给予 if count > 0 { return false, nil } // 给予每日登录积分(1积分) err = s.AddPoints(userID, 1, "每日首次登录", nil, "", "") if err != nil { return false, fmt.Errorf("给予每日登录积分失败: %v", err) } return true, nil }