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
+156
View File
@@ -0,0 +1,156 @@
package commod
import (
"reflect"
"91porn-server/common/stderr"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options"
)
// Page 客户端传低过来的分页信息 对外暴露
type Page struct {
PageNumber uint64 `form:"pageNumber" json:"pageNumber" binding:"required,min=1"` // 当前页
PageSize uint64 `form:"pageSize" json:"pageSize" binding:"required,min=1,max=100"` // 每页条数
Sort []Sorts `form:"sort" json:"sort"`
}
type Sorts struct {
SortKey string `json:"sortKey"`
SortVal int `json:"sortVal"`
}
func (p Page) Skip() uint64 {
return (p.PageNumber - 1) * p.PageSize
}
func (p Page) Skip64() int64 {
return int64((p.PageNumber - 1) * p.PageSize)
}
func (p Page) Limit64() int64 {
return int64(p.PageSize)
}
func (p Page) Limit() uint64 {
return p.PageSize
}
// 注意:Page.Sort内元素顺序决定排序顺序
func (p Page) GetSort() bson.D {
sorts := make(bson.D, len(p.Sort))
for i, v := range p.Sort {
sorts[i] = bson.E{Key: v.SortKey, Value: v.SortVal}
}
return sorts
}
// Sig 签名结构体
type Sig struct {
AccessKey string `form:"accessKey" json:"accessKey" binding:"required"`
BucketName string `form:"bucketName" json:"bucketName" binding:"required"`
}
// Resp 返回结构体
type Resp struct {
Code stderr.Code `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data"`
}
// ListResp 分页列表 公共返回结构体
type ListResp struct {
Total int64 `json:"total"`
HasNext bool `json:"hasNext"`
List interface{} `json:"list"`
}
// Page 客户端传低过来的分页信息 内部使用
type PageBy struct {
CheckNext bool
Num uint64
Size uint64
}
// OrderBy 排序
type OrderBy struct {
Key string // 排序的字段
Desc bool // 排序方式 是否倒序
}
// StdQuery 客户端传过来的时间条件信息
type StdQuery struct {
Page *PageBy
Order *[]OrderBy
}
// ConvertToListQuery 分页列表 通用条件查询条件组装
func ConvertToListQuery(s StdQuery) (opts *options.FindOptions) {
opts = &options.FindOptions{}
if s.Page != nil {
skip := int64((s.Page.Num - 1) * s.Page.Size)
limit := int64(s.Page.Size)
if s.Page.CheckNext {
limit++
}
opts.Skip = &skip
opts.Limit = &limit
}
if s.Order != nil && len(*s.Order) > 0 {
sort := bson.D{}
for _, v := range *s.Order {
e := bson.E{}
if v.Desc {
e.Key = v.Key
e.Value = -1
} else {
e.Key = v.Key
e.Value = 1
}
sort = append(sort, e)
}
opts.Sort = sort
}
return
}
// StructToMap2 对象转map,去掉无效值
func StructToMap3(u interface{}) map[string]interface{} {
t := reflect.TypeOf(u)
v := reflect.ValueOf(u)
m := make(map[string]interface{})
for i := 0; i < t.NumField(); i++ {
fv := v.Field(i).Type()
vv := v.Field(i)
k, _ := t.Field(i).Tag.Lookup("bson")
switch fv.Kind() {
case reflect.String:
if vv.String() != "" {
if k == "_id" {
idv, _ := primitive.ObjectIDFromHex(vv.String())
m["_id"] = idv
} else {
m[k] = vv.String()
}
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if vv.Int() != 0 {
m[k] = vv.Interface()
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
if vv.Uint() != 0 {
m[k] = vv.Interface()
}
case reflect.Interface, reflect.Ptr:
if vv.Interface() != nil {
m[k] = vv.Interface()
}
}
}
return m
}
+44
View File
@@ -0,0 +1,44 @@
package commod
const (
LouFengCostNotify = "LouFengCostNotify:%d" //用户楼凤消费通知
GameRechargePoliteNotify = "GameRechargePoliteNotify:%d" //用户游戏充值有礼通知
)
// SystemConfigType 系统配置类型
type SystemConfigType int
const (
NudeChatSpecialArea SystemConfigType = iota // 裸聊专区
)
// SystemLocationCode 系统位置编号
type SystemLocationCode int
const (
OfficialBulletin SystemLocationCode = iota // 官方公告
)
// BuyType 充值购买类型
type BuyType int
const (
BuyGold BuyType = iota + 1 // 购买金币
BuyGameCoin // 购买游戏币
BuyFruitCoin // 购买果币
BuyProduct // 购买商品
//BuyNudeChatService // 购买裸聊服务
)
type AdGroup string
const (
AdGroupNone AdGroup = "" // 无组
AdGroupA AdGroup = "A" // A组
AdGroupB AdGroup = "B" // B组
AdGroupC AdGroup = "C" // C组
)
func (ag AdGroup) InABC() bool {
return ag == AdGroupA || ag == AdGroupB || ag == AdGroupC
}
+52
View File
@@ -0,0 +1,52 @@
package commod
import (
"errors"
"math"
)
// 扣量类型
type DeductType int
const (
NotDed DeductType = iota
)
const (
DedConsume DeductType = 1 << iota
DedNewUser
DedBooker
DedRecharge
)
func (d DeductType) Has(t DeductType) bool {
return int(t)&int(d) == int(t)
}
// BitSet 位集合
func (d DeductType) BitSet() []int {
return []int{int(math.Log2(float64(d)))}
}
func (d DeductType) String() string {
switch d {
case DedConsume:
return "dedConsume"
case DedNewUser:
return "dedNewUser"
case DedBooker:
return "dedBooker"
case DedConsume | DedNewUser:
return "dedConsumeAndNewUser"
default:
return "unknow"
}
}
func ToDeductType(v int) (DeductType, error) {
all := DedConsume | DedNewUser | DedBooker
if all.Has(DeductType(v)) {
return DeductType(v), nil
}
return NotDed, errors.New(NotDed.String())
}
+93
View File
@@ -0,0 +1,93 @@
package commod
import (
"strings"
"time"
"91porn-server/common/pageopt"
)
type DiscSeqe struct {
DistrictCode string `json:"districtCode" bson:"districtCode"` //商区码
PromSeqe string `json:"promSeqe" bson:"promSeqe"` //推广序列
}
func (d *DiscSeqe) String() string {
if d.PromSeqe == "" {
return d.DistrictCode
}
return strings.ToUpper(strings.Join([]string{d.DistrictCode, d.PromSeqe}, "-"))
}
func (p *DiscSeqe) From(s string) *DiscSeqe {
p.Clean()
list := strings.Split(s, "-")
if len(list) > 0 {
p.DistrictCode = list[0]
}
if len(list) > 1 {
p.PromSeqe = list[1]
}
return p
}
func (p *DiscSeqe) Clean() {
p.DistrictCode = ""
p.PromSeqe = ""
}
type DiscDoc struct {
//商区码和推广序列
DiscSeqe `bson:",inline"`
//true:是直推用户
IsDirect bool `json:"isDirect" bson:"isDirect"`
//商区绑定时间
DiscBindAt time.Time `bson:"discBindAt"`
}
func NewDiscDoc(discSeqe DiscSeqe, isDirect bool, discBindAt time.Time) DiscDoc {
return DiscDoc{
discSeqe,
isDirect, //直推:推广链接没有推广码, 否则是分裂,
discBindAt,
}
}
type Matcher = pageopt.Matcher
// IsDirectMatch
type IsDirectMatch struct {
IsDirect *bool
}
func (b *IsDirectMatch) New() Matcher {
return pageopt.NewAssignMatch("isDirect", b.IsDirect)
}
// DistrictCodeMatch
type DistrictCodeMatch struct {
DistrictCode *string
}
func (s *DistrictCodeMatch) New() Matcher {
return pageopt.NewAssignMatch("districtCode", s.DistrictCode)
}
// DistrictCodeInMatch
type DistrictCodeInMatch struct {
Codes []string
}
func (s *DistrictCodeInMatch) New() Matcher {
return pageopt.NewInMatch("districtCode", s.Codes)
}
// DiscBindAtGTEAndLTMatch
type DiscBindAtGTEAndLTMatch struct {
GTE *time.Time
LT *time.Time
}
func (c *DiscBindAtGTEAndLTMatch) New() Matcher {
return pageopt.NewGTEAndLTMatch("discBindAt", c.GTE, c.LT)
}
+14
View File
@@ -0,0 +1,14 @@
package commod
import "91porn-server/common/constant"
type ButtonProp struct {
Style constant.SwitchStyle `form:"style" json:"style" bson:"style"` //开关样式
Enable bool `form:"enable" json:"enable" bson:"enable"` //true:显示按钮
}
type LdyButton struct {
Name string `form:"name" json:"name" bson:"name"` //开关名
Type constant.SwitchAct `form:"type" json:"type" bson:"type"` //开关类型
ButtonProp `bson:",inline"`
}
+34
View File
@@ -0,0 +1,34 @@
package commod
type ProductType int
const (
VIP ProductType = 0 // product 0
VIDEO ProductType = 1 // VIDEO视频1
MODEL ProductType = 2 // MODEL嫩模2
MeetingCard ProductType = 3 // 约会卡 3
GAME ProductType = 4 // 游戏币 4
NEWUSERCard ProductType = 5 // 新手卡 5
PhysicalGoods ProductType = 6 // 实体商品 6
AudioBook ProductType = 8 // 语音小说 8
VideoDiscount ProductType = 13 // 视频折扣卡 13
VideoFreeCard ProductType = 14 // 视频免费卡 14
CoinMonthCard ProductType = 18 // 金币月卡 18
Media ProductType = 19 // 动漫整本 19
AdvanceCard ProductType = 21 // 预售卡 21
GameAdvanceCard ProductType = 22 // 游戏预售卡 22
WhoringCard ProductType = 24 // 白嫖卡 24
ImGroup ProductType = 101 // 加入群 101
NakedChat ProductType = 102 // 裸聊 102
)
const OTHER = 20 //OTHER 20
// CurrencyType 货币类型
type CurrencyType int
const (
Gold CurrencyType = iota + 1 // 金币
GameCoin // 游戏币
FruitCoin // 果币
AiMateCoin // AI伴侣币
)
+65
View File
@@ -0,0 +1,65 @@
package commod
type SortType int
// 1、最新,2、最热/推荐,3、最多播放,4、十分钟以上视频, 5、精华/精选,6、视频 7-最多收藏 8、解锁次数 9、最新热评
const (
New SortType = 1 // 最新上架
MostHot SortType = 2 // 热门推荐
MostWatch SortType = 3 // 最多观看
MostCollect SortType = 7 // 最多收藏
HotComment SortType = 9 // 最新热评
)
var nameMap = map[SortType]string{
New: "最新上架",
MostHot: "热门推荐",
MostWatch: "最多观看",
HotComment: "最新热评",
MostCollect: "最多收藏",
}
func (s SortType) Name() string {
name, ok := nameMap[s]
if !ok {
return "未知排序"
}
return name
}
func (s SortType) Item() SortItemData {
item := SortItemData{
Value: s,
Name: "未知排序",
}
name, ok := nameMap[s]
if !ok {
return item
}
item.Name = name
return item
}
type SortItemData struct {
Value SortType `json:"value"`
Name string `json:"name"`
}
// WebSortRules 后台支持修改的排序规则
var WebSortRules = map[string][]SortItemData{
"acgSort": {
New.Item(),
MostHot.Item(),
MostWatch.Item(),
MostCollect.Item(),
HotComment.Item(),
},
"videoSort": {
New.Item(),
MostHot.Item(),
MostWatch.Item(),
MostCollect.Item(),
HotComment.Item(),
},
}
+165
View File
@@ -0,0 +1,165 @@
package commod
import (
"time"
"github.com/shopspring/decimal"
"go.mongodb.org/mongo-driver/bson/primitive"
)
//统计中心Model
type KFKTopic string
const (
KFK_APPID int32 = 204 // 20591PORN
KFK_APP_NAME = "91PORN" // app名字
USER_REG KFKTopic = "user_register" // 用户注册
USER_RECH KFKTopic = "user_recharge" // 用户充值
USER_RECH_ALL KFKTopic = "user_recharge_all" // 全部订单
USER_ACCE KFKTopic = "user_access" // 用户访问
USER_WOTHDRAW KFKTopic = "user_withdraw" // 用户提现
USER_BINDING KFKTopic = "user_binding" // 用户绑定
USER_INVITE KFKTopic = "user_invite" // 用户邀请
ConsumeRecordJob = "consume_record" // 产品消费流水
CardSellJob KFKTopic = "card_sell" // 会员卡特权卡销售流水
AiSellJob = "ai_sell" // AI销售流水
AdsTimeLongVideo = 15 // 长视频广告时间(单位: 秒)
)
type AiSellMsg struct {
AppID int32 `json:"appID" bson:"appID"` // AppID
UID uint64 `json:"uid" bson:"uid"` // UID
UniqID string `json:"uniqID" bson:"uniqID"` // 唯一ID,各个app内部交易ID
Amount int64 `json:"amount" bson:"amount"` // 金币数
TranType string `json:"tranType" bson:"tranType"` // 交易类型
SysType string `json:"sysType" bson:"sysType"` // 系统类型
CurrencyType string `json:"currencyType" bson:"currencyType"` // 交易类型,pay、free
TranCreatedAt time.Time `json:"tranCreatedAt" bson:"tranCreatedAt"` // 交易完成时间
IsRepurchase string `json:"isRepurchase" bson:"isRepurchase"` // 是否复购,yes、no
}
// UserRegisterMsg 用户注册
type UserRegisterMsg struct {
UserId uint64 `json:"userId"`
AppId int32 `json:"appId"`
PlatformId string `json:"platformId"` // 原始平台流水Id
SysType string `json:"sysType"`
DevType string `json:"devType"`
Mobile string `json:"mobile"`
Name string `json:"name"`
IP string `json:"ip"`
IsDirect bool `json:"isDirect"`
DistrictCode string `json:"districtCode"` // 渠道推广 dc
PromSeqe string `json:"promSeqe"` // 代理推广 pc
PUC string `json:"puc" bson:"puc"` //
PromCode string `json:"promCode"` // 用户推广序列(全名代理)
RegisterTime time.Time `json:"registerTime"`
}
// UserAccessMsg 用户访问 用户每天第一访问
type UserAccessMsg struct {
UserId uint64 `json:"userId"`
PlatformId string `json:"platformId"` // 原始平台流水Id
AppId int32 `json:"appId"`
SysType string `json:"sysType"`
DevType string `json:"devType"`
IP string `json:"ip"`
Version string `json:"version"`
DevID string `json:"devID"`
VisitAt time.Time `json:"visitAt"`
IsDirect bool `json:"isDirect,omitempty"` // true:是直推用户
DistrictCode string `json:"districtCode,omitempty"` // 渠道码
RegisterTime time.Time `json:"registerTime,omitempty"` //用户注册时间
IsDeduction bool `json:"isDeduction,omitempty"` // true:CPA扣量用户
}
// UserBindingMsg 用户绑定
type UserBindingMsg struct {
UserId uint64 `json:"userId"` // 用户ID
AppId int32 `json:"appId"` // appID
PlatformId string `json:"platformId"` // 原始平台流水Id
SysType string `json:"sysType"` // 操作系统类型 安卓 IOS
DevType string `json:"devType"` // 设备类型
Mobile string `json:"mobile"` // 手机号
BindingTime *time.Time `json:"bindingTime"` // 绑定时间
}
type UserInviteBindMsg struct {
UserId uint64 `json:"userId" bson:"userId" binding:"required"` // 用户ID
AppId int32 `json:"appId" bson:"appId" binding:"required"` // appID
ParentPromCode string `json:"parentPromCode,omitempty" bson:"promSeqe"` // 邀请人推广码
InviteTime time.Time `json:"inviteTime,omitempty" bson:"inviteTime" binding:"required"` // 邀请码绑定时间
}
const (
StatVipCard = iota //会员卡
StatLouFeng //楼凤
StatValueAddSer //增值服务
)
const (
CurrencyTypeGold = iota //金币
CurrencyTypeCash //现金
)
type ConsumeRecordMsg struct {
AppID int32 `json:"appID" bson:"appID"`
UID uint64 `json:"uid" bson:"uid"` //
Type int `json:"type" bson:"type"` //消费类型
CurrencyType int `json:"currencyType" bson:"currencyType"` //货币类型 0金币 1人民币
Money decimal.Decimal `json:"money" bson:"money"` //人民币 元
Amount decimal.Decimal `json:"amount" bson:"amount"` //金币(角)
Uniq string `json:"uniq" bson:"uniq"` //唯一号码
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` //记录创建时间
}
// 用户充值消息
type UserRechargeMsg struct {
UserId uint64 `json:"userId" bson:"userId" binding:"required"` // 用户ID
AppId int32 `json:"appId" bson:"appId" binding:"required"` // appID
PlatformId string `json:"platformId" bson:"platformId"` // 原始平台流水Id
SysType string `json:"sysType" bson:"sysType" binding:"required"` // 操作系统类型 安卓 IOS
DevType string `json:"devType" bson:"devType"` // 设备类型
ChannelName string `json:"channelName" bson:"channelName"` // 支付渠道名字
CID string `json:"cid" bson:"cid"` // 渠道id
Type string `bson:"type" json:"type"` // 充值方式
OrderId string `json:"orderId" bson:"orderId" binding:"required"` // 流水id
OID string `json:"oid" bson:"oid"` //第三方支付流水id
Money int64 `json:"money" bson:"money" binding:"required"` // 充值金额 订单金额
PayMoney int64 `json:"payMoney" bson:"payMoney" binding:"required"` // 实际到账金额 用户实际支付金额
Status int `json:"status" bson:"status"` // 2付款失败 3付款成功(目前只有成功才发送)
Rate string `json:"rate"` //渠道费率
SuccessAt time.Time `json:"successAt,omitempty" bson:"successAt"` // 成功时间
ProductType int `json:"productType" bson:"productType"`
ChanShareMod int `json:"chanShareMod" bson:"chanShareMod"` //渠道分成 0消费分成 1金币分成 2不分成
/*......*/
}
type CardSellMsg struct {
AppID int32 `json:"appID" bson:"appID"` // AppID
UID uint64 `json:"uid" bson:"uid"` // UID
UniqID string `json:"uniqID" bson:"uniqID"` // 唯一ID,各个app内部交易ID
Amount int64 `json:"amount" bson:"amount"` // 金币数
TranTypeInt int64 `json:"tranTypeInt" bson:"tranTypeInt"` // 交易类型码
TranType string `json:"tranType" bson:"tranType"` // 交易类型文字描述
SysType string `json:"sysType" bson:"sysType"` // 系统类型
CurrencyType int `json:"currencyType" bson:"currencyType"` // 交易类型(0 金币 1 现金)
TranCreatedAt time.Time `json:"tranCreatedAt" bson:"tranCreatedAt"` // 交易完成时间
Product Product `json:"product" bson:"product"` // 产品信息
}
type Position struct {
ID primitive.ObjectID `json:"id" bson:"id"` // 位置ID
Name string `json:"name" bson:"name"` // 位置名称
}
type Product struct {
ID string `json:"id"` // ID
Name string `json:"name"` // 产品名称
DiscountedPrice int64 `bson:"discountedPrice" json:"discountedPrice"` // 现价 单位角(金币)
ProductType ProductType `bson:"productType" json:"productType"` // 产品类型
Position Position `json:"position"` // 产品位置
}