package rechargeser import ( "context" "strings" "time" "videoweb/app/service/rechargeser/jiahua" "videoweb/pub/common/log" "videoweb/pub/common/srvdef" "videoweb/pub/models/rechargepackagemod" "videoweb/pub/models/usermod" "videoweb/pub/models/vipordermod" "videoweb/pub/mongos" "videoweb/pub/pubdef" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo/options" ) // SubmitOrderResp 创建第三方支付订单的响应 type SubmitOrderResp struct { TradeNo string `json:"tradeNo"` // 本地订单号(可用于查询) PayUrl string `json:"payUrl"` // 支付链接 PayUrlMode string `json:"payUrlMode"` // 链接打开方式 IsOpenNewBrowser bool `json:"isOpenNewBrowser"` // 是否需要外部浏览器打开 } // CreateOrder 创建第三方支付 VIP 订单。 // 防重复:15 秒内同一用户+同一套餐的 pending 订单直接返回原支付链接。 func CreateOrder(ctx context.Context, userId int64, userName string, packageId int64, payMode string, sysType string, devType string, ip string, districtCode string, ) (*SubmitOrderResp, *srvdef.SrvErr) { pkg, serr := rechargepackagemod.FindOneRechargePackage(ctx, bson.M{ rechargepackagemod.FN.RechargePackage.Id: packageId, rechargepackagemod.FN.RechargePackage.PackageType: rechargepackagemod.PackageTypeVip, rechargepackagemod.FN.RechargePackage.Status: rechargepackagemod.StatusEnabled, }) if serr != nil || pkg == nil { return nil, srvdef.New(srvdef.ErrNoData, "会员套餐不存在或已下架", "") } now := time.Now() dupFilter := bson.M{ vipordermod.FN.VipOrder.UserId: userId, vipordermod.FN.VipOrder.CardId: packageId, vipordermod.FN.VipOrder.PayMode: payMode, vipordermod.FN.VipOrder.Status: pubdef.VipOrderPending, vipordermod.FN.VipOrder.CreatedAt: bson.M{"$gte": now.Add(-15 * time.Second)}, } existing, _ := vipordermod.FindOneVipOrder(ctx, dupFilter) if existing != nil && existing.PayUrl != "" { return &SubmitOrderResp{ TradeNo: existing.TradeNo, PayUrl: existing.PayUrl, PayUrlMode: existing.PayUrlMode, IsOpenNewBrowser: true, }, nil } tradeNo := pubdef.GetTrandNoWithUUID() amount := pkg.Price payInfo, serr := jiahua.SubmitOrder(ctx, userId, userName, tradeNo, amount, payMode, sysType, devType, ip) if serr != nil { return nil, serr } order := &vipordermod.VipOrder{ Id: mongos.Lid.VipOrder.Get(), OrderType: vipordermod.OrderTypeVip, UserId: userId, CardId: packageId, // 兼容历史字段,存购买套餐ID CardName: pkg.Name, Amount: amount, PayMode: payMode, TradeNo: tradeNo, Oid: payInfo.Oid, Status: pubdef.VipOrderPending, PayUrl: payInfo.PayUrl, PayUrlMode: payInfo.PayUrlMode, PayChannel: payInfo.PayChannel, PayRate: payInfo.PayRate, IPAddr: ip, SysType: sysType, DistrictCode: strings.TrimSpace(districtCode), CreatedAt: now, UpdatedAt: now, } if serr = vipordermod.InsertOneVipOrder(ctx, order); serr != nil { log.Error("rechargeser:CreateOrder InsertOneVipOrder failed", log.Any("tradeNo", tradeNo), log.E(serr)) return nil, serr } return &SubmitOrderResp{ TradeNo: tradeNo, PayUrl: payInfo.PayUrl, PayUrlMode: payInfo.PayUrlMode, IsOpenNewBrowser: true, }, nil } // GetOrderHistory 查询用户的 VIP 订单历史 func GetOrderHistory(ctx context.Context, userId int64, page, pageSize int64) (vipordermod.VipOrderList, int64, *srvdef.SrvErr) { filter := bson.M{ vipordermod.FN.VipOrder.UserId: userId, vipordermod.FN.VipOrder.OrderType: vipordermod.OrderTypeVip, } total, serr := vipordermod.CountVipOrder(ctx, filter) if serr != nil { return nil, 0, serr } skip := (page - 1) * pageSize opts := options.Find(). SetSort(bson.M{vipordermod.FN.VipOrder.CreatedAt: -1}). SetSkip(skip). SetLimit(pageSize) list, serr := vipordermod.FindManyVipOrder(ctx, filter, opts) return list, total, serr } // GetUserInfo 获取用户信息(供 app 层展示当前 VIP 状态) func GetUserInfo(ctx context.Context, userId int64) (*usermod.User, *srvdef.SrvErr) { return usermod.FindOneUser(ctx, bson.M{usermod.FN.User.Id: userId}) }