408 lines
12 KiB
Go
408 lines
12 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"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
|
|
}
|
|
|
|
// ==================== 管理端方法 ====================
|
|
|
|
// 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
|
|
}
|