Files
ai_dianshang/server/internal/service/points.go

350 lines
8.5 KiB
Go
Raw Normal View History

2025-11-17 13:32:54 +08:00
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
}