Files

408 lines
12 KiB
Go
Raw Permalink Normal View History

2025-11-17 14:11:46 +08:00
package repository
import (
2025-11-28 15:18:10 +08:00
"context"
2025-11-17 14:11:46 +08:00
"dianshang/internal/model"
"time"
"gorm.io/gorm"
)
// CouponRepository 优惠券仓储
type CouponRepository struct {
db *gorm.DB
}
// NewCouponRepository 创建优惠券仓储
func NewCouponRepository(db *gorm.DB) *CouponRepository {
return &CouponRepository{db: db}
}
// GetAvailableCoupons 获取可用优惠券列表
func (r *CouponRepository) GetAvailableCoupons() ([]model.Coupon, error) {
var coupons []model.Coupon
now := time.Now()
err := r.db.Where("status = ? AND start_time <= ? AND end_time >= ?", 1, now, now).
Where("total_count = 0 OR used_count < total_count").
Order("created_at DESC").
Find(&coupons).Error
return coupons, err
}
// GetUserCoupons 获取用户优惠券
func (r *CouponRepository) GetUserCoupons(userID uint, status int) ([]model.UserCoupon, error) {
var userCoupons []model.UserCoupon
query := r.db.Preload("Coupon").Where("user_id = ?", userID)
if status > 0 {
// API状态值到数据库状态值的映射
// API: 1=未使用,2=已使用,3=已过期
// DB: 0=未使用,1=已使用,2=已过期
dbStatus := status - 1
query = query.Where("status = ?", dbStatus)
}
err := query.Order("created_at DESC").Find(&userCoupons).Error
return userCoupons, err
}
// GetByID 根据ID获取优惠券
func (r *CouponRepository) GetByID(id uint) (*model.Coupon, error) {
var coupon model.Coupon
err := r.db.First(&coupon, id).Error
return &coupon, err
}
// CheckUserCouponExists 检查用户是否已领取优惠券
func (r *CouponRepository) CheckUserCouponExists(userID, couponID uint) (bool, error) {
var count int64
err := r.db.Model(&model.UserCoupon{}).
Where("user_id = ? AND coupon_id = ?", userID, couponID).
Count(&count).Error
return count > 0, err
}
// GetUserCouponCount 获取用户领取某优惠券的数量
func (r *CouponRepository) GetUserCouponCount(userID, couponID uint) (int, error) {
var count int64
err := r.db.Model(&model.UserCoupon{}).
Where("user_id = ? AND coupon_id = ?", userID, couponID).
Count(&count).Error
return int(count), err
}
// CreateUserCoupon 创建用户优惠券记录
func (r *CouponRepository) CreateUserCoupon(userCoupon *model.UserCoupon) error {
return r.db.Transaction(func(tx *gorm.DB) error {
// 创建用户优惠券记录
if err := tx.Create(userCoupon).Error; err != nil {
return err
}
// 更新优惠券使用数量
return tx.Model(&model.Coupon{}).
Where("id = ?", userCoupon.CouponID).
UpdateColumn("used_count", gorm.Expr("used_count + ?", 1)).Error
})
}
// GetUserCouponByID 根据ID获取用户优惠券
func (r *CouponRepository) GetUserCouponByID(id uint) (*model.UserCoupon, error) {
var userCoupon model.UserCoupon
err := r.db.Preload("Coupon").First(&userCoupon, id).Error
return &userCoupon, err
}
// GetUserCouponByOrderID 根据订单ID获取用户优惠券
func (r *CouponRepository) GetUserCouponByOrderID(orderID uint) (*model.UserCoupon, error) {
var userCoupon model.UserCoupon
err := r.db.Preload("Coupon").Where("order_id = ?", orderID).First(&userCoupon).Error
return &userCoupon, err
}
// UseCoupon 使用优惠券
func (r *CouponRepository) UseCoupon(userCouponID, orderID uint) error {
now := time.Now()
return r.db.Model(&model.UserCoupon{}).
Where("id = ?", userCouponID).
Updates(map[string]interface{}{
"status": 1, // 已使用
"order_id": orderID,
"used_time": &now,
}).Error
}
// RestoreCoupon 恢复优惠券(取消订单时使用)
func (r *CouponRepository) RestoreCoupon(userCouponID uint) error {
return r.db.Model(&model.UserCoupon{}).
Where("id = ?", userCouponID).
Updates(map[string]interface{}{
"status": 0, // 恢复为未使用
"order_id": nil, // 清除订单关联
"used_time": nil, // 清除使用时间
}).Error
}
2025-11-28 15:18:10 +08:00
// ==================== 管理端方法 ====================
// GetCouponListForAdmin 获取优惠券列表(管理端)
func (r *CouponRepository) GetCouponListForAdmin(page, pageSize int, status, couponType, keyword string) ([]model.Coupon, int64, error) {
var coupons []model.Coupon
var total int64
query := r.db.Model(&model.Coupon{})
// 状态筛选
if status != "" {
query = query.Where("status = ?", status)
}
// 类型筛选
if couponType != "" {
query = query.Where("type = ?", couponType)
}
// 关键词搜索
if keyword != "" {
query = query.Where("name LIKE ? OR description LIKE ?", "%"+keyword+"%", "%"+keyword+"%")
}
// 获取总数
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
// 分页查询
offset := (page - 1) * pageSize
err := query.Order("created_at DESC").
Limit(pageSize).
Offset(offset).
Find(&coupons).Error
return coupons, total, err
}
// GetCouponUsageStats 获取优惠券使用统计
func (r *CouponRepository) GetCouponUsageStats(couponID uint) (int, int, error) {
// 获取领取数
var receivedCount int64
err := r.db.Model(&model.UserCoupon{}).Where("coupon_id = ?", couponID).Count(&receivedCount).Error
if err != nil {
return 0, 0, err
}
// 获取使用数
var usedCount int64
err = r.db.Model(&model.UserCoupon{}).Where("coupon_id = ? AND status = ?", couponID, 1).Count(&usedCount).Error
if err != nil {
return 0, 0, err
}
return int(receivedCount), int(usedCount), nil
}
// Create 创建优惠券
func (r *CouponRepository) Create(coupon *model.Coupon) error {
return r.db.Create(coupon).Error
}
// Update 更新优惠券
func (r *CouponRepository) Update(couponID uint, updates map[string]interface{}) error {
return r.db.Model(&model.Coupon{}).Where("id = ?", couponID).Updates(updates).Error
}
// Delete 删除优惠券
func (r *CouponRepository) Delete(couponID uint) error {
return r.db.Delete(&model.Coupon{}, couponID).Error
}
// CheckCouponHasUsers 检查优惠券是否有用户领取
func (r *CouponRepository) CheckCouponHasUsers(couponID uint) (bool, error) {
var count int64
err := r.db.Model(&model.UserCoupon{}).Where("coupon_id = ?", couponID).Count(&count).Error
return count > 0, err
}
// BatchDelete 批量删除优惠券
func (r *CouponRepository) BatchDelete(couponIDs []uint) error {
return r.db.Delete(&model.Coupon{}, couponIDs).Error
}
// CountTotalCoupons 统计总优惠券数
func (r *CouponRepository) CountTotalCoupons(ctx context.Context) (int64, error) {
var count int64
err := r.db.WithContext(ctx).Model(&model.Coupon{}).Count(&count).Error
return count, err
}
// CountActiveCoupons 统计启用的优惠券数
func (r *CouponRepository) CountActiveCoupons(ctx context.Context) (int64, error) {
var count int64
now := time.Now()
err := r.db.WithContext(ctx).Model(&model.Coupon{}).
Where("status = ? AND start_time <= ? AND end_time >= ?", 1, now, now).
Count(&count).Error
return count, err
}
// CountTotalReceived 统计总领取数
func (r *CouponRepository) CountTotalReceived(ctx context.Context, startTime, endTime time.Time) (int64, error) {
var count int64
query := r.db.WithContext(ctx).Model(&model.UserCoupon{})
if !startTime.IsZero() && !endTime.IsZero() {
query = query.Where("created_at BETWEEN ? AND ?", startTime, endTime)
}
err := query.Count(&count).Error
return count, err
}
// CountTotalUsed 统计总使用数
func (r *CouponRepository) CountTotalUsed(ctx context.Context, startTime, endTime time.Time) (int64, error) {
var count int64
query := r.db.WithContext(ctx).Model(&model.UserCoupon{}).Where("status = ?", 1)
if !startTime.IsZero() && !endTime.IsZero() {
query = query.Where("used_time BETWEEN ? AND ?", startTime, endTime)
}
err := query.Count(&count).Error
return count, err
}
// GetCouponTypeStats 获取各类型优惠券统计
func (r *CouponRepository) GetCouponTypeStats(ctx context.Context) ([]map[string]interface{}, error) {
var results []map[string]interface{}
rows, err := r.db.WithContext(ctx).Model(&model.Coupon{}).
Select("type, COUNT(*) as count").
Group("type").
Rows()
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var couponType, count int
if err := rows.Scan(&couponType, &count); err != nil {
return nil, err
}
typeName := ""
switch couponType {
case 1:
typeName = "满减券"
case 2:
typeName = "折扣券"
case 3:
typeName = "免邮券"
}
results = append(results, map[string]interface{}{
"type": couponType,
"type_name": typeName,
"count": count,
})
}
return results, nil
}
// GetTopCoupons 获取热门优惠券
func (r *CouponRepository) GetTopCoupons(ctx context.Context, limit int) ([]map[string]interface{}, error) {
var results []map[string]interface{}
err := r.db.WithContext(ctx).Model(&model.Coupon{}).
Select("id, name, type, received_count, used_count").
Order("received_count DESC").
Limit(limit).
Scan(&results).Error
return results, err
}
// GetUserCouponListForAdmin 获取用户优惠券列表(管理端)
func (r *CouponRepository) GetUserCouponListForAdmin(userID uint, page, pageSize int) ([]model.UserCoupon, int64, error) {
var userCoupons []model.UserCoupon
var total int64
query := r.db.Model(&model.UserCoupon{}).Where("user_id = ?", userID)
// 获取总数
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
// 分页查询
offset := (page - 1) * pageSize
err := query.Preload("Coupon").
Order("created_at DESC").
Limit(pageSize).
Offset(offset).
Find(&userCoupons).Error
return userCoupons, total, err
}
// GetDistributeHistory 获取优惠券发放历史
func (r *CouponRepository) GetDistributeHistory(page, pageSize int) ([]map[string]interface{}, int64, error) {
var history []map[string]interface{}
var total int64
// 先获取总数
type CountResult struct {
Count int64
}
var countResult CountResult
err := r.db.Model(&model.UserCoupon{}).
Select("COUNT(DISTINCT DATE(created_at), coupon_id) as count").
Scan(&countResult).Error
if err != nil {
return nil, 0, err
}
total = countResult.Count
// 分页查询分组数据
type DistributeRecord struct {
DistributeDate string `gorm:"column:distribute_date"`
CouponID uint `gorm:"column:coupon_id"`
TotalCount int `gorm:"column:total_count"`
UnusedCount int `gorm:"column:unused_count"`
UsedCount int `gorm:"column:used_count"`
CreatedAt time.Time `gorm:"column:created_at"`
}
var records []DistributeRecord
offset := (page - 1) * pageSize
err = r.db.Model(&model.UserCoupon{}).
Select(`
DATE(created_at) as distribute_date,
coupon_id,
COUNT(*) as total_count,
SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) as unused_count,
SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) as used_count,
MIN(created_at) as created_at
`).
Group("DATE(created_at), coupon_id").
Order("created_at DESC").
Limit(pageSize).
Offset(offset).
Scan(&records).Error
if err != nil {
return nil, 0, err
}
// 处理结果
for i, record := range records {
// 获取优惠券信息
var coupon model.Coupon
r.db.First(&coupon, record.CouponID)
// 判断发放类型
distributeType := "batch"
if record.TotalCount == 1 {
distributeType = "single"
}
history = append(history, map[string]interface{}{
"id": i + 1 + offset,
"coupon_id": record.CouponID,
"coupon_name": coupon.Name,
"distribute_type": distributeType,
"distribute_date": record.DistributeDate,
"total_count": record.TotalCount,
"success_count": record.TotalCount,
"fail_count": 0,
"used_count": record.UsedCount,
"unused_count": record.UnusedCount,
"admin_name": "系统",
"created_at": record.CreatedAt,
})
}
return history, total, nil
}