feat: 互动处理

This commit is contained in:
Blizzard
2026-03-05 16:54:25 +08:00
parent 74b252550b
commit 2583b5f302
30 changed files with 412 additions and 119 deletions
+1 -1
View File
@@ -91,7 +91,7 @@ func (s *ChannelService) GetChannelById(userId, id string) (radio.RadioChannel,
return channel, nil
}
channel.HasSubscribed = 0
if userId != "" {
if userId != "" && userId != "0" {
var sub radio.RadioSubscription
err = global.DB.Model(&radio.RadioSubscription{}).
Where("user_id = ?", userId).
+1
View File
@@ -8,6 +8,7 @@ type ServiceGroup struct {
InteractionService
PayService
OrderService
VipService
}
var GroupApp = new(ServiceGroup)
+43 -34
View File
@@ -3,6 +3,7 @@ package radio
import (
"errors"
"sundynix-go/model/radio"
"sundynix-go/model/system"
"time"
"gorm.io/gorm"
@@ -12,7 +13,7 @@ type OrderService struct{}
var OrderServiceApp = new(OrderService)
// ExecuteOrderUnlock 核心原子操作:解锁权限
// ExecuteOrderUnlock 订阅/开通vip 核心原子操作:解锁权限
func (s *OrderService) ExecuteOrderUnlock(tx *gorm.DB, outTradeNo string) error {
var order radio.Order
// 1. 锁住订单行,防止回调和主动查询并发导致时长翻倍
@@ -33,40 +34,48 @@ func (s *OrderService) ExecuteOrderUnlock(tx *gorm.DB, outTradeNo string) error
}).Error; err != nil {
return err
}
// 4. 根据订单中的 sub_type 决定增加几个月
var months int
switch order.SubscriptionType {
case "1":
months = 1 // 月
case "2":
months = 3 // 季
case "3":
months = 12 // 年
}
// 5. 更新或创建订阅权限
var sub radio.RadioSubscription
now := time.Now()
err := tx.Where("user_id = ? AND channel_id = ?", order.UserId, order.ChannelId).First(&sub).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
// 首次订阅
return tx.Create(&radio.RadioSubscription{
UserId: order.UserId,
ChannelId: order.ChannelId,
ExpiredAt: now.AddDate(0, months, 0),
Status: 1,
if order.Type == 2 {
//4.开通vip 过期时间为2099 年
return tx.Model(&system.User{}).Where("id = ?", order.UserId).Updates(map[string]interface{}{
"is_vip": 1,
"vip_expire_at": time.Date(2099, 12, 31, 23, 59, 59, 999, time.Local),
}).Error
} else {
// 续费逻辑
newExpiredAt := sub.ExpiredAt
if sub.ExpiredAt.Before(now) {
newExpiredAt = now // 已过期,从现在开始往后加
} else if order.Type == 1 {
// 4. 订阅 根据订单中的 sub_type 决定增加几个月
var months int
switch order.SubscriptionType {
case "1":
months = 1 // 月
case "2":
months = 3 // 季
case "3":
months = 12 // 年
}
// 5. 更新或创建订阅权限
var sub radio.RadioSubscription
now := time.Now()
err := tx.Where("user_id = ? AND channel_id = ?", order.UserId, order.ChannelId).First(&sub).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
// 首次订阅
return tx.Create(&radio.RadioSubscription{
UserId: order.UserId,
ChannelId: order.ChannelId,
ExpiredAt: now.AddDate(0, months, 0),
Status: 1,
}).Error
} else {
// 续费逻辑
newExpiredAt := sub.ExpiredAt
if sub.ExpiredAt.Before(now) {
newExpiredAt = now // 已过期,从现在开始往后加
}
return tx.Model(&sub).Updates(map[string]interface{}{
"expired_at": newExpiredAt.AddDate(0, months, 0),
"status": 1,
}).Error
}
return tx.Model(&sub).Updates(map[string]interface{}{
"expired_at": newExpiredAt.AddDate(0, months, 0),
"status": 1,
}).Error
}
return nil
}
+1 -1
View File
@@ -58,7 +58,7 @@ func (s *PayService) PrePay(orderId, userId string) (resp *jsapi.PrepayWithReque
Total: core.Int64(int64(order.Amount)),
},
Payer: &jsapi.Payer{
Openid: core.String(user.MiniOpenId),
Openid: core.String(user.OpenId),
},
//Detail: &jsapi.Detail{
// CostPrice: core.Int64(608800),
+7 -5
View File
@@ -7,6 +7,7 @@ import (
common "sundynix-go/model/commom/request"
"sundynix-go/model/radio"
"sundynix-go/model/radio/request"
"sundynix-go/model/system"
"sundynix-go/utils/uniqueid"
"sundynix-go/utils/wechat"
@@ -64,6 +65,11 @@ func (s *SubscriptionService) UnlockChannel(userId string, req request.UnlockCha
if err != nil {
return nil, "", err
}
var user system.User
err = global.DB.Where("id = ?", userId).First(&user).Error
if err != nil || user.OpenId == "" {
return nil, "", err
}
//2.创建一个订单 根据eventType 创建不同的订单
var price int
var orderName string
@@ -81,6 +87,7 @@ func (s *SubscriptionService) UnlockChannel(userId string, req request.UnlockCha
return nil, "", errors.New("无效的订阅类型")
}
order := radio.Order{
Type: 1, //很重要 1订阅 2开通vip
UserId: userId,
OutTradeNo: uniqueid.GenOrderNo(),
ChannelId: req.ChannelId,
@@ -93,11 +100,6 @@ func (s *SubscriptionService) UnlockChannel(userId string, req request.UnlockCha
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
+90
View File
@@ -0,0 +1,90 @@
package radio
import (
"context"
"sundynix-go/global"
"sundynix-go/model/radio"
"sundynix-go/model/radio/request"
"sundynix-go/model/system"
"sundynix-go/utils/uniqueid"
"sundynix-go/utils/wechat"
"github.com/wechatpay-apiv3/wechatpay-go/core"
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi"
)
type VipService struct{}
func (s *VipService) UpdateVipConfig(req request.UpdateVipConfig) error {
updateData := map[string]interface{}{
"price": req.Price,
"discountedPrice": req.DiscountedPrice,
"remark": req.Remark,
}
err := global.DB.Model(&radio.Vip{}).Where("id = ?", req.Id).Updates(updateData).Error
return err
}
func (s *VipService) VipConfigDetail() (radio.Vip, error) {
var vip radio.Vip
err := global.DB.Model(&radio.Vip{}).First(&vip).Error
return vip, err
}
// VipVip 开通vip
func (s *VipService) VipVip(userId string) (*jsapi.PrepayWithRequestPaymentResponse, string, error) {
//1.查询vip配置
var config radio.Vip
err := global.DB.Model(&radio.Vip{}).First(&config).Error
if err != nil {
return nil, "", err
}
//2.创建订单
order := radio.Order{
Type: 2, //很重要 1订阅 2开通vip
UserId: userId,
OutTradeNo: uniqueid.GenOrderNo(),
SubscriptionType: "vip sub",
Amount: config.DiscountedPrice,
Name: "vip sub",
}
err = global.DB.Create(&order).Error
if err != nil {
return nil, "", err
}
//3.调用微信api 拉起支付
var user system.User
err = global.DB.Where("id = ?", userId).First(&user).Error
if err != nil || user.OpenId == "" {
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(config.DiscountedPrice)),
},
Payer: &jsapi.Payer{
Openid: core.String(user.OpenId),
},
})
if err != nil {
return nil, "", err
}
return result, order.OutTradeNo, nil
}
+3 -14
View File
@@ -12,7 +12,6 @@ import (
"strconv"
"sundynix-go/global"
common "sundynix-go/model/commom/request"
"sundynix-go/model/radio"
"sundynix-go/model/system"
systemReq "sundynix-go/model/system/request"
systemResp "sundynix-go/model/system/response"
@@ -145,29 +144,19 @@ func (userService *UserService) MiniLogin(code string) (result *system.User, err
// 7. 根据openid查询用户 存在--> 更新session_key 返回数据
var user system.User
err = global.DB.Where("mini_open_id = ?", wxResp.Openid).Preload("Avatar").First(&user).Error
err = global.DB.Where("open_id = ?", wxResp.Openid).Preload("Avatar").First(&user).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
// 8. 使用 Transaction 闭包管理事务
err = global.DB.Transaction(func(tx *gorm.DB) error {
// 创建新用户
newUser := system.User{
Name: uniqueid.GenerateName(),
MiniOpenId: wxResp.Openid,
Name: uniqueid.GenerateRadioUsername(),
OpenId: wxResp.Openid,
SessionKey: wxResp.SessionKey,
}
if err := tx.Create(&newUser).Error; err != nil {
return err
}
// 创建小程序用户
mpUser := radio.RadioUser{
UserId: newUser.Id,
OpenId: wxResp.Openid,
UnionId: wxResp.Unionid,
SessionKey: wxResp.SessionKey,
}
if err := tx.Create(&mpUser).Error; err != nil {
return err
}
// 赋值给外部变量以便返回
user = newUser