Initial commit

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 13:57:10 +08:00
co-authored by Claude Opus 5
commit 8679200f41
1897 changed files with 257900 additions and 0 deletions
+55
View File
@@ -0,0 +1,55 @@
package prdcthsomod
import (
"91porn-server/models/commod"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options"
)
// PaymentLogBody 商品交易订单请求参数
type PaymentLogBody struct {
ProductID primitive.ObjectID `bson:"productID" json:"productID" binding:"required" ` //产品id
Name string `bson:"name" json:"name" binding:"required" ` //商品名字
Amount int64 `bson:"amount" json:"amount" binding:"required"` //成交价格
ProductType int `bson:"productType" json:"productType"` //产品类型
}
// ProductHistoryQueryReq 通用查询参数
type ProductHistoryQueryReq struct {
UID *uint64 `form:"uid" json:"uid,omitempty" bson:"uid"` // 用户id
ProductType *commod.ProductType `form:"productType" json:"productType" ` // 产品类型 // 0-会员卡 21-预售卡
AdvanceOrderStatus *int `form:"advanceOrderStatus" json:"advanceOrderStatus"` // 预售订单状态 // 2-预付成功 4-尾款支付成功
Start *time.Time `form:"start" json:"start"` // 开始时间
End *time.Time `form:"end" json:"end"` // 结束时间
commod.Page
}
type ProductHistoryQueryResp struct {
Total int64 `json:"total"`
List []*ProductHistory `json:"list"`
}
func (req *ProductHistoryQueryReq) GetCond() bson.M {
cond := bson.M{}
if req.UID != nil {
cond["uid"] = *req.UID
}
if req.ProductType != nil {
cond["productType"] = *req.ProductType
}
if req.AdvanceOrderStatus != nil {
cond["advanceOrderStatus"] = *req.AdvanceOrderStatus
}
if req.Start != nil && req.End != nil {
cond["createdAt"] = bson.M{"$gte": req.Start, "$lt": req.End}
}
return cond
}
func (req *ProductHistoryQueryReq) GetOpt() *options.FindOptions {
opt := options.Find().SetSkip(req.Skip64()).SetLimit(req.Limit64()).SetSort(bson.D{{Key: "createdAt", Value: -1}})
return opt
}
+53
View File
@@ -0,0 +1,53 @@
package prdcthsomod
import (
"time"
"go.mongodb.org/mongo-driver/bson"
)
type M = bson.M
// PayVipTotalAmountByCreatedTime 购买VIP的总金额
func PayVipTotalAmountByCreatedTime(start time.Time, end time.Time) (int64, error) {
filter := M{
"createdAt": M{
"$gte": start,
"$lt": end,
},
"productType": VIP,
}
list := make([]struct {
Amount int64 `bson:"amount"`
}, 0)
if err := coll(nil).Find(&list, filter); err != nil {
return 0, err
}
var totalAmount int64
for _, v := range list {
totalAmount += v.Amount
}
return totalAmount, nil
}
// PayVipUIDSByCreatedTime 购买VIP的用户UID
func PayVipUIDSByCreatedTime(start time.Time, end time.Time) ([]uint64, error) {
filter := M{
"createdAt": M{
"$gte": start,
"$lt": end,
},
"productType": VIP,
}
list := make([]struct {
UID uint64 `bson:"uid"`
}, 0)
if err := coll(nil).Find(&list, filter); err != nil {
return nil, err
}
uidList := make([]uint64, len(list))
for i, v := range list {
uidList[i] = v.UID
}
return uidList, nil
}
+213
View File
@@ -0,0 +1,213 @@
package prdcthsomod
import (
"fmt"
"time"
"91porn-server/common/db"
"91porn-server/common/log"
"91porn-server/models"
"91porn-server/models/commod"
"91porn-server/models/v/productmod"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
const table = models.ProductHistory
// initIndex 设置index
func initIndex() {
coll := coll(nil)
many := []mongo.IndexModel{
{
Keys: bson.D{{Key: "uid", Value: 1}},
},
{
Keys: bson.D{{Key: "productID", Value: 1}},
},
{
Keys: bson.D{{Key: "name", Value: 1}},
},
{
Keys: bson.D{{Key: "amount", Value: 1}},
},
{
Keys: bson.D{{Key: "productType", Value: 1}},
},
{
Keys: bson.D{{Key: "status", Value: 1}},
},
{
Keys: bson.D{{Key: "createdAt", Value: 1}},
},
{
Keys: bson.D{{Key: "updatedAt", Value: 1}},
},
// 用户运营导出预售状态相关的订单
{
Keys: bson.D{{Key: "advanceOrderStatus", Value: 1}, {Key: "createdAt", Value: -1}},
},
{
Keys: bson.D{{Key: "deductType", Value: 1}, {Key: "createdAt", Value: -1}},
Options: options.Index().SetSparse(true),
},
{
Keys: bson.D{
{Key: "experimentId", Value: 1},
{Key: "experimentVariant", Value: 1},
{Key: "productID", Value: 1},
},
Options: options.Index().
SetName("vip_experiment_gold_order_statistics").
SetPartialFilterExpression(bson.M{"experimentId": bson.M{"$gt": ""}}),
},
}
if _, err := coll.CreateIndex(many); err != nil {
panic(fmt.Sprintf("%s model set index err ==>[%+v]", table, err))
}
}
func coll(t *db.MongoTool) *db.MongoTool {
if t == nil {
return mdb.Coll(table)
}
return t.Coll(table)
}
func IsBoughtVIP(uid uint64) (bool, error) {
p := ProductHistory{}
if err := coll(nil).FindOne(&p, bson.M{"uid": uid, "productType": VIP}); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "IsBoughtVIP", table, "FindOne", err), log.Any("uid", uid))
return false, err
}
return p.UID != 0, nil
}
// GetUserLastVip 获取用户最后充值的VIP
func GetUserLastVip(uid uint64) (productID primitive.ObjectID, productName string, amount int64) {
p := ProductHistory{}
opt := options.FindOne().SetSort(bson.D{{Key: "createdAt", Value: -1}})
if err := coll(nil).FindOne(&p, bson.M{"uid": uid, "productType": bson.M{"$in": []commod.ProductType{productmod.VIP, productmod.NewUser, productmod.AdvanceCard}}}, opt); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "IsBoughtVIP", table, "FindOne", err), log.Any("uid", uid))
return primitive.NilObjectID, "", 0
}
if p.ProductType == productmod.AdvanceCard {
return productID, "", 0
}
if p.IsUpgrade {
// 假设A100 B300 C:500 如果A连续升到B,不这么处理,就会变成B=》C要付款300,实际应该给200差价就好
return p.ProductID, p.Name, p.PurchasePrice
}
return p.ProductID, p.Name, p.Amount
}
// InsertProductHistory 插入一条数据
func InsertProductHistory(t *db.MongoTool, p *ProductHistory) error {
p.CreatedAt = time.Now()
p.UpdatedAt = time.Now()
res, err := coll(t).InsertOne(p)
if err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "InsertProductHistory", table, "InsertOne", err))
return err
}
p.ID = res.InsertedID.(primitive.ObjectID)
return nil
}
func InsertManyProductHistory(t *db.MongoTool, p []ProductHistory) error {
if _, err := coll(t).InsertMany(p); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "InsertProductHistory", table, "InsertOne", err))
return err
}
return nil
}
// FindProductHistorys 查询所有ProductHistory类型
func FindProductHistorys(cond bson.M, opts *options.FindOptions) (total int64, data []*ProductHistory, err error) {
data = make([]*ProductHistory, 0)
if err = coll(nil).Find(&data, cond, opts); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "FindProductHistorys", table, "Find", err), log.Any("cond", cond))
return
}
total, err = coll(nil).Count(cond)
if err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "FindProductHistorys", table, "Count", err), log.Any("cond", cond))
}
return
}
// FindList
func FindList(cond bson.M, opts *options.FindOptions) (data []*ProductHistory, err error) {
data = make([]*ProductHistory, 0)
if err = coll(nil).Find(&data, cond, opts); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "FindList", table, "Find", err), log.Any("cond", cond))
return
}
return
}
func FindUserProductHistory(uid uint64) (list []ProductHistory, err error) {
f := bson.M{"uid": uid, "productType": bson.M{"$in": []commod.ProductType{productmod.VIP, productmod.OTHER,
productmod.MeetingCard, productmod.VideoDiscount,
productmod.VideoFreeCard, productmod.VideoDiscount, productmod.VideoFreeCard,
}}}
opts := options.Find().SetSort(bson.D{{Key: "createdAt", Value: -1}})
if err = coll(nil).Find(&list, f, opts); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "FindProductHistorys", table, "Find", err), log.Any("query", f))
return
}
return
}
func FindUserProductHistoryByType(uid uint64) (list []ProductHistory, err error) {
f := bson.M{"uid": uid, "productType": bson.M{"$in": []commod.ProductType{productmod.GameAdvanceCard}}}
opts := options.Find().SetSort(bson.D{{Key: "createdAt", Value: -1}})
if err = coll(nil).Find(&list, f, opts); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "FindProductHistorys", table, "Find", err), log.Any("query", f))
return
}
return
}
// FindProductHistorysByUID 查询所有ProductHistory类型
func FindProductHistorysByUID(uid, pageNumber, pageSizse uint64) (total int64, data []*ProductHistory, hasNext bool, err error) {
data = make([]*ProductHistory, 0)
f := bson.M{"uid": uid, "productType": bson.M{"$in": []commod.ProductType{productmod.VIP, productmod.OTHER,
productmod.MeetingCard, productmod.VideoDiscount,
productmod.VideoFreeCard, productmod.VideoDiscount, productmod.VideoFreeCard,
}}}
skip := int64(pageSizse * (pageNumber - 1))
limit := int64(pageSizse + 1)
opts := options.FindOptions{
Skip: &skip,
Limit: &limit,
Sort: bson.D{{Key: "createdAt", Value: -1}},
}
total, err = coll(nil).Count(f)
if err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %ss fail error:%+v:", "FindProductHistorys", table, "Count", err), log.Any("query", f))
}
if err = coll(nil).Find(&data, f, &opts); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "FindProductHistorys", table, "Find", err), log.Any("query", f))
return
}
if len(data) > int(pageSizse) {
hasNext = true
data = data[:pageSizse]
}
return
}
// FindMany FindMany
func FindMany(start, end time.Time, opts *options.FindOptions) (data []*ProductStat, err error) {
cond := bson.M{"createdAt": bson.M{"$gte": start, "$lt": end}}
data = make([]*ProductStat, 0)
if err = coll(nil).Find(&data, cond, opts); err != nil {
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "FindProductHistorys", table, "Find", err), log.Any("cond", cond))
return
}
return
}
+93
View File
@@ -0,0 +1,93 @@
package prdcthsomod
import (
"time"
"91porn-server/common/db"
"91porn-server/models/commod"
"91porn-server/models/v/productmod"
"go.mongodb.org/mongo-driver/bson/primitive"
)
const (
VIP = commod.VIP //product 0
VIDEO = commod.VIDEO //VIDEO视频
MODEL = commod.MODEL //MODEL嫩模
GAME = commod.GAME //GAME 游戏币
MeetingCard = commod.MeetingCard //约会卡
OTHER = commod.OTHER //OTHER 1
VideoDiscount = commod.VideoDiscount //视频折扣卡
VideoFreeCard = commod.VideoFreeCard //视频免费卡
CoinMonthCard = commod.CoinMonthCard //金币月卡
Media = commod.Media //动漫整本
AdvanceCard = commod.AdvanceCard // 预售卡
GameAdvanceCard = commod.GameAdvanceCard // 游戏售卡
WhoringCard = commod.WhoringCard // 白嫖卡
ImGroup = commod.WhoringCard // 加入群 24
)
const (
COMPLETE = iota //COMPLETE 交易完成
CANCEL //CANCEL 交易撤销
)
var mdb *db.MongoDB
type DiscDoc = commod.DiscDoc
// ProductHistory 商品交易订单
type ProductHistory struct {
ID primitive.ObjectID `bson:"_id,omitempty" json:"id" ` // 交易订单号
UID uint64 `bson:"uid" json:"uid"` // 用户id
ProductID primitive.ObjectID `bson:"productID" json:"productID" ` // 产品id
Name string `bson:"name" json:"name" ` // 商品名字
Amount int64 `bson:"amount" json:"amount" ` // 花费的余额
Income int64 `bson:"income" json:"income"` // 花费的收益
ProductType commod.ProductType `bson:"productType" json:"productType" ` // 产品类型 // 0-会员卡 21-预售卡
AdvanceOrderStatus int `bson:"advanceOrderStatus" json:"advanceOrderStatus"` // 预售订单状态 // 2-预付成功 4-尾款支付成功
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
SysType string `json:"sysType" bson:"sysType"` // 设备系统类型 ios pc android
GameCode string `json:"gameCode" bson:"gameCode"` // 购买游戏码
ProductSnapShot *productmod.Product `json:"productSnapShot" bson:"productSnapShot"` // 产品购买时快照
IsUpgrade bool `json:"isUpgrade" bson:"isUpgrade"` // 是否VIP升级
CurrentVipName string `json:"currentVipName" bson:"currentVipName"` // 当前VIP名称
CurrentVipPrice int64 `json:"currentVipPrice" bson:"currentVipPrice"` // 当前VIP价格
PurchasePrice int64 `json:"purchasePrice" bson:"purchasePrice"` // 原价购买价格
ExperimentID string `json:"experimentId,omitempty" bson:"experimentId,omitempty"` // VIP卡片A/B实验ID
ExperimentVariant string `json:"experimentVariant,omitempty" bson:"experimentVariant,omitempty"` // VIP卡片A/B实验分组
SessionID string `json:"sessionId,omitempty" bson:"sessionId,omitempty"` // VIP卡片页面会话ID
DiscDoc `bson:",inline"`
}
type ProductHistoryExport struct {
ID primitive.ObjectID `bson:"_id,omitempty" json:"id" xlsx:"交易订单号"` // 交易订单号
UID uint64 `bson:"uid" json:"uid" xlsx:"用户id"` // 用户id
ProductID primitive.ObjectID `bson:"productID" json:"productID" xlsx:"会员卡id"` // 会员卡id
Name string `bson:"name" json:"name" xlsx:"商品名字"` // 商品名字
Duration int `bson:"duration" json:"duration" xlsx:"会员卡持续天数"` // 会员卡持续天数
VipLevel int `bson:"vipLevel" json:"vipLevel" xlsx:"购买时的会员卡等级"` // 购买时的会员卡等级
IsUpgrade bool `json:"isUpgrade" bson:"isUpgrade" xlsx:"是否VIP升级"` // 是否VIP升级
OriginalPrice int64 `bson:"originalPrice" json:"originalPrice" xlsx:"原价(金币)"` // 原价(金币)
DiscountedPriceIos int64 `bson:"discountedPriceIos,omitempty" json:"discountedPriceIos,omitempty" xlsx:"ios现价/升级价(金币)"` // ios现价/升级价(金币)
DiscountedPriceAnd int64 `bson:"discountedPriceAnd,omitempty" json:"discountedPriceAnd,omitempty" xlsx:"安卓现价/升级价(金币)"` // 安卓现价/升级价(金币)
Amount int64 `bson:"amount" json:"amount" xlsx:"花费的金币"` // 花费的余额
Income int64 `bson:"income" json:"income" xlsx:"花费的收益"` // 花费的收益
ProductType string `bson:"productType" json:"productType" xlsx:"产品类型"` // 产品类型 // 0-会员卡 21-预售卡
AdvanceOrderStatus string `bson:"advanceOrderStatus" json:"advanceOrderStatus" xlsx:"预售订单状态"` // 预售订单状态 // 2-预付成功 4-尾款支付成功
SysType string `json:"sysType" bson:"sysType" xlsx:"设备系统类型"` // 设备系统类型 ios pc android
CreatedAt time.Time `json:"createdAt" bson:"createdAt" xlsx:"创建时间"` // 创建时间
}
func Init() {
mdb = db.Init(table)
initIndex()
}
type ProductStat struct {
ID primitive.ObjectID `bson:"_id,omitempty" json:"id" ` //交易订单号
ProductID primitive.ObjectID `bson:"productID" json:"productID" ` //产品id
Amount int64 `bson:"amount" json:"amount" ` //成交价格
Income int64 `bson:"income" json:"income"` //花费的作品收益
CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
}
+53
View File
@@ -0,0 +1,53 @@
package prdcthsomod
import (
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// VIPExperimentGoldOrderStat contains successful VIP card purchases paid with coins.
type VIPExperimentGoldOrderStat struct {
Variant string `json:"variant" bson:"variant"`
ProductID primitive.ObjectID `json:"productId" bson:"productId"`
GoldPaidOrders int `json:"goldPaidOrders" bson:"goldPaidOrders"`
GoldPaidAmount int64 `json:"goldPaidAmount" bson:"goldPaidAmount"`
}
func VIPExperimentGoldOrderStatistics(experimentID string) ([]VIPExperimentGoldOrderStat, error) {
var raw []struct {
ID struct {
Variant string `bson:"variant"`
ProductID primitive.ObjectID `bson:"productId"`
} `bson:"_id"`
GoldPaidOrders int `bson:"goldPaidOrders"`
GoldPaidAmount int64 `bson:"goldPaidAmount"`
}
err := coll(nil).Aggregate(&raw, []bson.M{
{"$match": bson.M{"experimentId": experimentID}},
{"$group": bson.M{
"_id": bson.M{
"variant": "$experimentVariant",
"productId": "$productID",
},
"goldPaidOrders": bson.M{"$sum": 1},
"goldPaidAmount": bson.M{"$sum": bson.M{"$add": bson.A{
bson.M{"$ifNull": bson.A{"$amount", 0}},
bson.M{"$ifNull": bson.A{"$income", 0}},
}}},
}},
{"$sort": bson.D{{Key: "_id.variant", Value: 1}, {Key: "goldPaidOrders", Value: -1}}},
})
if err != nil {
return nil, err
}
result := make([]VIPExperimentGoldOrderStat, 0, len(raw))
for _, item := range raw {
result = append(result, VIPExperimentGoldOrderStat{
Variant: item.ID.Variant,
ProductID: item.ID.ProductID,
GoldPaidOrders: item.GoldPaidOrders,
GoldPaidAmount: item.GoldPaidAmount,
})
}
return result, nil
}