package radio import ( "context" "errors" "sundynix-go/global" common "sundynix-go/model/commom/request" "sundynix-go/model/radio" "sundynix-go/model/radio/request" "sundynix-go/utils/uniqueid" "sundynix-go/utils/wechat" "github.com/wechatpay-apiv3/wechatpay-go/core" "github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi" "gorm.io/gorm" ) type SubscriptionService struct{} // GetUserSubscription 获取用户订阅列表 func (s *SubscriptionService) GetUserSubscription(userId string, info common.PageInfo) ([]radio.RadioSubscription, int64, error) { var subscriptions []radio.RadioSubscription var total int64 db := global.DB // 替换为你实际的 GORM 变量 // 2. 统计该用户订阅的总数 (Status=1 表示订阅中) err := db.Model(&radio.RadioSubscription{}). Where("user_id = ? AND status = 1", userId). Count(&total).Error if err != nil { return nil, 0, err } // 3. 执行分页关联查询 err = db.Model(&radio.RadioSubscription{}). Where("user_id = ? AND status = 1", userId). Limit(info.PageSize). Offset((info.Current-1)*info.PageSize). Order("created_at DESC"). // 级联加载频道及其封面 Preload("Channel"). // 关键:子查询过滤——只预加载每个频道 ID 最大的那一条节目 Preload("Channel.Programs", func(db *gorm.DB) *gorm.DB { // 子查询:找到每个频道下 ID 最大的节目(通常 ID 越大代表越新,也可以用 CreatedAt) subQuery := db.Table("sundynix_radio_program"). Select("id"). Where("status = 1"). // 只找上架的 Where("created_at = (SELECT MAX(created_at) FROM sundynix_radio_program AS rp WHERE rp.channel_id = sundynix_radio_program.channel_id AND rp.status = 1)") // 嵌套预加载:节目里的音频和封面也一并带出来 return db.Where("id IN (?)", subQuery).Preload("Audio") }). Find(&subscriptions).Error if err != nil { return nil, total, err } return subscriptions, total, err } // UnlockChannel 解锁频道 func (s *SubscriptionService) UnlockChannel(userId string, req request.UnlockChannel) (resp *jsapi.PrepayWithRequestPaymentResponse, no string, err error) { //1.查询频道 var channel radio.RadioChannel err = global.DB.Where("id = ?", req.ChannelId).First(&channel).Error if err != nil { return nil, "", err } //2.创建一个订单 根据eventType 创建不同的订单 var price int var orderName string switch req.EventType { case "1": price = channel.MonthlyPrice //包月 orderName = channel.Name + " - 月度订阅" case "2": price = channel.QuarterlyPrice //包季 orderName = channel.Name + " - 季度订阅" case "3": price = channel.AnnualPrice //包年 orderName = channel.Name + " - 年度订阅" default: return nil, "", errors.New("无效的订阅类型") } order := radio.Order{ UserId: userId, OutTradeNo: uniqueid.GenOrderNo(), ChannelId: req.ChannelId, SubscriptionType: req.EventType, Amount: price, Name: orderName, } err = global.DB.Create(&order).Error if err != nil { return nil, "", err } //4.调用微信api 拉起支付 var user radio.RadioUser err = global.DB.Where("user_id = ?", userId).First(&user).Error if err != nil { return nil, "", err } payClient, err := wechat.GetWxPayClient() if err != nil { return nil, "", err } svc := jsapi.JsapiApiService{Client: payClient} result, _, err := svc.PrepayWithRequestPayment(context.Background(), jsapi.PrepayRequest{ Appid: core.String(global.Config.MiniProgram.AppId), Mchid: core.String(global.Config.WechatPay.MchId), Description: core.String(order.Name), OutTradeNo: core.String(order.OutTradeNo), //TimeExpire: core.Time(time.Now()), //选填 //Attach: core.String("自定义数据说明"), //选填 NotifyUrl: core.String(global.Config.WechatPay.NotifyUrl), //GoodsTag: core.String("WXG"), //选填 //SupportFapiao: core.Bool(false), //选填 Amount: &jsapi.Amount{ Currency: core.String("CNY"), Total: core.Int64(int64(price)), }, Payer: &jsapi.Payer{ Openid: core.String(user.OpenId), }, }) if err != nil { return nil, "", err } return result, order.OutTradeNo, nil }