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 }