Files
rootandClaude Opus 5 8679200f41 Initial commit
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 13:57:10 +08:00

1117 lines
44 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package userctrl
import (
"91porn-server/common/db"
"91porn-server/models/v/productmod"
"91porn-server/models/v/txnmod"
"91porn-server/models/v/walletmod"
"91porn-server/web/webg"
"encoding/json"
"fmt"
"strings"
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
"91porn-server/common"
"91porn-server/common/constant"
"91porn-server/common/log"
"91porn-server/common/pageopt"
"91porn-server/common/stderr"
v10 "91porn-server/common/v10"
"91porn-server/common/ysphone"
"91porn-server/models/commod"
"91porn-server/models/l/operatorlgmod"
"91porn-server/models/v/operationlogmod"
"91porn-server/models/v/usermod"
"91porn-server/web/middleware/authweb"
"91porn-server/web/service/userser"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"go.mongodb.org/mongo-driver/bson"
)
// List doc
// @Summary 获取用户列表
// @Description 获取用户列表
// @Tags web-用户管理
// @Accept mpfd,json
// @Produce json,html
// @Param pageNumber query integer true "当前页"
// @Param pageSize query integer true "每页条数"
// @Param uid query integer false "过滤条件-uid"
// @Param devID query string false "过滤条件-设备ID"
// @Param vipLevel query integer false "过滤条件-VIP等级"
// @Param hasPromotionCode query bool false "过滤条件-有邀请码"
// @Param name query string false "过滤条件-用户昵称"
// @Param mobile query string false "过滤条件-手机号"
// @Param promotionCode query string false "过滤条件-邀请码"
// @Param hasLocked query bool false "过滤条件-已禁止登陆"
// @Param hasBanned query bool false "过滤条件-已禁言"
// @Param forbidUpload query bool false "过滤条件-禁止上传文件"
// @Param districtCode query bool false "过滤条件-商区码"
// @Param startTime query integer false "过滤条件-开始时间"
// @Param endTime query integer false "过滤条件-结束时间"
// @Param isPretendAcc query string false "过滤条件-是否马甲账号"
// @Param autoFollow query string false "过滤条件-是否配置被自动关注"
// @Param registerIP query string false "过滤条件-指定某IP地址注册的用户"
// @Success 200 {string} json "{"msg": "操作成功", "date": { "total":10, "list":[] }}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/user/list [get]
func List(c *gin.Context) {
type Filter struct {
UID *uint64 `form:"uid" json:"uid" binding:""` //uid
DevID *string `form:"devID" json:"devID" binding:""` //设备ID
VipLevel *int `form:"vipLevel" json:"vipLevel" binding:""` //vip等级
Name *string `form:"name" json:"name" binding:""` //用户名
Mobile *string `form:"mobile" json:"mobile" binding:""` //手机号
PromotionCode *string `form:"promotionCode" json:"promotionCode" binding:""` //推广码
HasPromotionCode *bool `form:"hasPromotionCode" json:"hasPromotionCode" binding:""` //有推广码
HasLocked *bool `form:"hasLocked" json:"hasLocked" binding:""` //已禁止登陆
HasBanned *bool `form:"hasBanned" json:"hasBanned" binding:""` //已禁言
ForbidUpload *bool `form:"forbidUpload" json:"forbidUpload" binding:""` //是否禁止上传文件
StartTime *time.Time `form:"startTime" json:"startTime" binding:""` //开始时间
EndTime *time.Time `form:"endTime" json:"endTime" binding:""` //结束时间
DistrictCode *string `form:"districtCode" json:"districtCode" binding:""` //商区码
IsPretendAcc *int `form:"isPretendAcc" json:"isPretendAcc"` //是否马甲账号
AutoFollow *bool `form:"autoFollow" json:"autoFollow" binding:""` //是否配置被自动关注
RegisterIP *string `form:"registerIP" json:"registerIP" binding:"-"` // IP过滤
}
var arg struct {
commod.Page
Filter
}
if err := c.ShouldBind(&arg); err != nil {
common.ServeJSON(c, stderr.ErrParamError, "user List arg error "+err.Error())
return
}
//马甲账户
if arg.IsPretendAcc != nil && *arg.IsPretendAcc == 1 {
devID := "^" + usermod.SystemDevIDPrex
arg.DevID = &devID
}
if arg.Name != nil {
name := "^" + *arg.Name
arg.Name = &name
}
sort := bson.D{{Key: "createdAt", Value: -1}}
skip := int64((arg.PageNumber - 1) * arg.PageSize)
limit := int64(arg.PageSize)
page, err := userser.UserPages(sort, skip, limit,
pageopt.UIDMatch{UID: arg.UID},
usermod.DevIDRegexMatch{DevID: arg.DevID},
usermod.VipLevelMatch{VipLevel: arg.VipLevel},
usermod.NameRegexMatch{Name: arg.Name},
usermod.MobileMatch{Mobile: arg.Mobile},
usermod.PromotionCodeMatch{PromotionCode: arg.PromotionCode},
usermod.HasPromotionCodeMatch{IsExisted: arg.HasPromotionCode},
usermod.LockedMatch{Locked: arg.HasLocked},
usermod.BannedMatch{Banned: arg.HasBanned},
usermod.ForbidUploadMatch{ForbidUpload: arg.ForbidUpload},
usermod.CreatedAtGTEAndLTMatch{GTE: arg.StartTime, LT: arg.EndTime},
usermod.DistrictCodeMatch{DistrictCode: arg.DistrictCode},
usermod.AutoFollowMatch{AutoFollow: arg.AutoFollow},
usermod.RegisterIpMatch{RegisterIp: arg.RegisterIP},
)
if err != nil {
common.ServeJSON(c, stderr.Failure, "user List error: "+err.Error())
return
}
common.ServeJSON(c, stderr.Success, page)
}
// Update doc
// @Summary 用户编辑
// @Description 用户编辑
// @Tags web-用户管理
// @Accept mpfd,json
// @Produce json,html
// @Param uid formData string false "uid"
// @Param vipLevel formData integer false "vip等级"
// @Param mobile formData integer false "手机号"
// @Param vipExpireDate formData string false "vip到期时间 format:2001-09-07T03:14:54.072Z"
// @Param dramaExpire formData string false "短剧权益有效期 format:2001-09-07T03:14:54.072Z"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/user/update [post]
func Update(c *gin.Context) {
manager, err := common.GetAdminAct(c)
if err != nil {
common.ServeJSON(c, stderr.AdminIDErr, err.Error())
return
}
type Update struct {
VipExpireDate *string `form:"vipExpireDate" json:"vipExpireDate" binding:""` //vip到期时间
VipExpireDateModifyReason *string `form:"vipExpireDateModifyReason" json:"vipExpireDateModifyReason"` // 修改VIP到期时间原因
VipLevel *int `form:"vipLevel" json:"vipLevel" binding:""` //vip等级
Amount *int64 `form:"amount" json:"amount"`
Background *[]string `form:"background" json:"background"` //背景图
//web端零值不传,导致无法将电话改为空
//web端正确情况应是 空值不传(web后台无修改时), 零值应传(web后台修改为""后)
Mobile *string `form:"mobile" json:"mobile" binding:""` //手机号
Portrait *string `form:"portrait" json:"portrait"`
Region *string `form:"region" json:"region"` //地区
Summary *string `form:"summary" json:"summary"`
Name *string `form:"name" json:"name"`
SuperUser *bool `form:"superUser" json:"superUser"` //大v
OfficialCert *bool `form:"officialCert" json:"officialCert"` //是否官方认证
IsMadou *bool `form:"isMadou" json:"isMadou"` //是否麻豆账号
TaxLevel *int64 `form:"taxLevel" json:"taxLevel"` //扣税等级,默认03.7
AutoFollow *bool `form:"autoFollow" json:"autoFollow"` //是否配置被自动关注
BankActName *string `json:"bankActName,omitempty" bson:"bankActName,omitempty"` //银行卡绑定名字
OriginalSort *int `json:"originalSort" bson:"originalSort"` // 新版原创排序
VideoDeduction *float64 `json:"videoDeduction" bson:"videoDeduction"` //视频扣量,1:博主10单扣1单, 以此类推
VideoDeductionPayCount *int `json:"videoDeductionPayCount" bson:"videoDeductionPayCount"` //视频扣量购买次数
VideoDeductionCount *int `json:"videoDeductionCount" bson:"videoDeductionCount"` //视频扣量次数
MerchantAccount *string `json:"merchantAccount,omitempty" bson:"merchantAccount,omitempty"` //商家账号
VipID *string `form:"vipID" json:"vipID" bson:"vipID,omitempty"` // 会员卡ID
AllGoldVideoFree *bool `json:"allGoldVideoFree" bson:"allGoldVideoFree"` // 是否所有金币视频免费
GoldVideoFreeExpire *time.Time `json:"goldVideoFreeExpire" bson:"goldVideoFreeExpire,omitempty"` // 金币视频免费日期
GoldVideoFreeLimit *int64 `json:"goldVideoFreeLimit" bson:"goldVideoFreeLimit"` // 金币视频免费限制门槛(包含acg)
ChatPrice *int64 `form:"chatPrice" json:"chatPrice"` // 私信价格
BroadcastExpire *time.Time `json:"broadcastExpire" bson:"broadcastExpire,omitempty"` //直播有效期
DramaExpire *time.Time `json:"dramaExpire" bson:"dramaExpire,omitempty"` //短剧权益有效期
}
var arg struct {
UID uint64 `form:"uid" json:"uid" binding:"required"`
Update
}
if err = c.ShouldBind(&arg); err != nil {
common.ServeJSON(c, stderr.ErrParamError, "web user Update arg error "+err.Error())
return
}
if arg.VipExpireDate != nil && (arg.VipExpireDateModifyReason == nil || *arg.VipExpireDateModifyReason == "") {
common.ServeJSON(c, stderr.ErrParamError, "web user Update arg error: "+"请填写更新用户VIP到期时间的原因")
return
}
//获取更新用户信息
u, err := usermod.FindUserByUIDForNoCache(arg.UID)
if err != nil || u == nil {
common.ServeJSON(c, stderr.UserIsNotExists, "web user Update arg error: 更新用户不存在 ")
return
}
//视频扣量更新, 则充值扣量次数
if arg.Update.VideoDeduction != nil && *arg.Update.VideoDeduction != 0 && *arg.Update.VideoDeduction != u.VideoDeduction {
var n int = 0
arg.Update.VideoDeductionPayCount = &n
arg.Update.VideoDeductionCount = &n
}
//修改账号金币
opLogs := []operationlogmod.OperationLog{}
if arg.Amount != nil && *arg.Amount != 0 {
opLog, err := userser.ModifyUserAmount(arg.UID, *arg.Amount, manager, "")
if err != nil {
common.ServeJSON(c, stderr.Failure, err)
return
}
opLogs = []operationlogmod.OperationLog{opLog}
}
if arg.VipID != nil {
oid, err := primitive.ObjectIDFromHex(*arg.VipID)
if err != nil {
log.Error(fmt.Sprintf("admin add vip param VipID err:%v, VipID:%v", err, *arg.VipID))
common.ServeJSON(c, stderr.ErrParamError, nil)
return
}
code := AddVIP(arg.UID, oid, u.DevType)
if code != stderr.Success {
log.Error(fmt.Sprintf("admin add vip err:%v,code:%v", code.Error(), code))
common.ServeJSON(c, code, nil)
return
}
}
//修改用户手机
if arg.Mobile != nil && u.Mobile != *arg.Mobile { //注意会有空字符串的情况
mobile := *arg.Mobile
if *arg.Mobile != "" && (len(mobile) > 6 && mobile[:len(constant.FakeMobilePrefix)] != constant.FakeMobilePrefix) {
if !v10.IsGlobalizationPhoneNumber(mobile) {
common.ServeJSON(c, stderr.ErrParamError, "web user Update arg.Mobile error")
return
}
}
if err = userser.ModifyUserMobile(arg.UID, ysphone.FormatPhoneNumber(*arg.Mobile)); err != nil {
switch err.(type) {
case usermod.MobileHasBindError:
common.ServeJSON(c, stderr.ErrMobileHasBind, err)
return
}
if strings.Contains(err.Error(), "mobile_1") {
common.ServeJSON(c, stderr.ErrMobileHasBindByOther, err)
return
}
common.ServeJSON(c, stderr.Failure, err)
return
}
}
doc := usermod.UserSelector{
VipLevel: arg.VipLevel,
Portrait: arg.Portrait,
Summary: arg.Summary,
Name: arg.Name,
Region: arg.Region,
Background: arg.Background,
SuperUser: arg.SuperUser,
OfficialCert: arg.OfficialCert,
TaxLevel: arg.TaxLevel,
AutoFollow: arg.AutoFollow,
BankActName: arg.BankActName,
OriginalSort: arg.OriginalSort,
VideoDeduction: arg.VideoDeduction,
VideoDeductionCount: arg.VideoDeductionCount,
VideoDeductionPayCount: arg.VideoDeductionPayCount,
ChatPrice: arg.ChatPrice,
BroadcastExpire: arg.BroadcastExpire,
DramaExpire: arg.DramaExpire,
}
if arg.AllGoldVideoFree != nil {
doc.AllGoldVideoFree = arg.AllGoldVideoFree
}
if arg.GoldVideoFreeExpire != nil {
doc.GoldVideoFreeExpire = arg.GoldVideoFreeExpire
}
if arg.GoldVideoFreeLimit != nil {
doc.GoldVideoFreeLimit = arg.GoldVideoFreeLimit
}
if arg.MerchantAccount != nil {
doc.MerchantAccount = arg.MerchantAccount
}
//修改vip到期时间
if arg.VipExpireDate != nil {
vipExpireDate, err := time.Parse(time.RFC3339, *arg.VipExpireDate)
if err != nil {
common.ServeJSON(c, stderr.ErrParamError, "web user Update arg.VipExpireDate error "+err.Error())
return
}
doc.VipExpireDate = &vipExpireDate
opLog := operationlogmod.OperationLog{
UserID: int64(arg.UID),
OperationAPI: c.Request.URL.Path,
OperationType: constant.User_Edit_VIP_Expire,
BeforeContent: u.VipExpireDate.Local().String(),
AfterContent: vipExpireDate.Local().String(),
Reason: *arg.VipExpireDateModifyReason,
CreatedUser: manager,
CreatedID: 0,
CreatedAt: time.Now(),
}
opLogs = append(opLogs, opLog)
}
user, err := usermod.Update(arg.UID, doc)
if err != nil {
common.ServeJSON(c, stderr.ErrServerUnavailable, err)
return
}
if user.UID <= 0 {
common.ServeJSON(c, stderr.UserIsNotExists, nil)
return
}
common.Go(func() {
if err := operationlogmod.InsertMany(opLogs); err != nil {
log.ErrorX(c, "insert operation log failed", log.Any("logs", opLogs), log.Any("req", arg),
log.Any("operator", manager), log.E(err))
}
log, _ := json.Marshal(arg)
_ = operatorlgmod.RecordOperation(manager, constant.UserManageList, constant.Modify, string(log),
c.Request.URL.RequestURI())
})
common.ServeJSON(c, stderr.Success, "")
}
// Banned doc
// @Summary 批量使能用户禁言
// @Description 批量使能用户禁言
// @Tags web-用户管理
// @Accept mpfd,json
// @Produce json,html
// @Param uidList formData array true "uid数组"
// @Param enable formData bool true "ture:开始禁言,false:关闭禁言"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/user/banned [post]
func Banned(c *gin.Context) {
manager, err := common.GetAdminAct(c)
if err != nil {
common.ServeJSON(c, stderr.AdminIDErr, err.Error())
return
}
var arg userser.UserCommentBanned
if err = c.ShouldBind(&arg); err != nil {
common.ServeJSON(c, stderr.ErrParamError, "web user Banned arg error "+err.Error())
return
}
code := arg.Banned()
log, _ := json.Marshal(arg)
_ = operatorlgmod.RecordOperation(manager, constant.UserManageList, constant.Modify, string(log), c.Request.URL.RequestURI())
common.ServeJSON(c, code, "")
}
// SetAdvertiser doc
// @Summary 批设置用户为打广告用户
// @Description 批设置用户为打广告用户
// @Tags web-用户管理
// @Accept mpfd,json
// @Produce json,html
// @Param uid formData array true "uid数组"
// @Param enable formData bool true "ture:开启,false:关闭"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/user/advertiser [post]
func SetAdvertiser(c *gin.Context) {
manager, err := common.GetAdminAct(c)
if err != nil {
common.ServeJSON(c, stderr.AdminIDErr, err.Error())
return
}
var arg usermod.SetAdvertiseCond
if err = c.ShouldBind(&arg); err != nil {
common.ServeJSON(c, stderr.ErrParamError, "web user SetAdvertiser arg error "+err.Error())
return
}
err = userser.SetAdvertiser(&arg)
if err != nil {
common.ServeJSON(c, stderr.Failure, err)
return
}
log, _ := json.Marshal(arg)
_ = operatorlgmod.RecordOperation(manager, constant.UserManageList, constant.Modify, string(log), c.Request.URL.RequestURI())
common.ServeJSON(c, stderr.Success, "")
}
// Lock doc
// @Summary 批量使能禁止用户登陆
// @Description 批量使能禁止用户登陆
// @Tags web-用户管理
// @Accept mpfd,json
// @Produce json,html
// @Param uidList formData array true "uid数组"
// @Param enable formData bool true "ture:禁止用户登陆,false:允许用户登陆"
// @Param reason formData string false "封禁原因"
// @Param lockAt formData string false "封禁开始时间,format:2006-01-02T15:04:05Z07:00"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/user/lock [post]
func Lock(c *gin.Context) {
manager, err := common.GetAdminAct(c)
if err != nil {
common.ServeJSON(c, stderr.AdminIDErr, err.Error())
return
}
var arg userser.LockUserReq
if err = c.ShouldBind(&arg); err != nil {
common.ServeJSON(c, stderr.ErrParamError, "web user Banned arg error "+err.Error())
return
}
code := arg.Lock()
if code != stderr.Success {
common.ServeJSON(c, code, "")
return
}
authweb.RevokeTokenCache(arg.UID)
log, _ := json.Marshal(arg)
_ = operatorlgmod.RecordOperation(manager, constant.UserManageList, constant.Modify, string(log), c.Request.URL.RequestURI())
common.ServeJSON(c, stderr.Success, "")
}
// ForbidUpload doc
// @Summary 批量使用户禁止上传文件
// @Description 批量使用户禁止上传文件
// @Tags web-用户管理
// @Accept mpfd,json
// @Produce json,html
// @Param uidList formData array true "uid数组"
// @Param enable formData bool true "true:开始禁止上传文件,false:取消禁止上传文件"
// @Param reason formData string false "true:开始禁止上传文件,false:取消禁止上传文件"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/user/forbid [post]
func Forbid(c *gin.Context) {
manager, err := common.GetAdminAct(c)
if err != nil {
common.ServeJSON(c, stderr.AdminIDErr, err.Error())
return
}
var arg struct {
UIDList []uint64 `form:"uidList" json:"uidList" binding:"required"`
Enable *bool `form:"enable" json:"enable" binding:"required"`
Reason *string `form:"reason" json:"reason"`
}
if err = c.ShouldBind(&arg); err != nil {
common.ServeJSON(c, stderr.ErrParamError, "web user Forbid arg error "+err.Error())
return
}
doc := usermod.UserSelector{ForbidUpload: arg.Enable}
if _, err = usermod.UpdateMany(arg.UIDList, doc); err != nil {
common.ServeJSON(c, stderr.ErrServerUnavailable, err)
return
}
log, _ := json.Marshal(arg)
_ = operatorlgmod.RecordOperation(manager, constant.UserManageList, constant.Modify, string(log), c.Request.URL.RequestURI())
common.ServeJSON(c, stderr.Success, "")
}
// PlayRecord doc
// @Summary 用户播放记录表
// @Description 用户播放记录表
// @Tags web-用户管理
// @Accept mpfd,json
// @Produce json,html
// @Param uid formData integer true "用户id"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/user/devID/reset [get]
func DevIDReset(ctx *gin.Context) {
adminID, err := common.GetAdminAct(ctx)
if err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminAct error "+err.Error())
return
}
role, err := common.GetAdminRole(ctx)
if err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminRole error "+err.Error())
return
}
if role != "superAdmin" {
common.ServeJSON(ctx, stderr.ErrAccessForbid, "")
return
}
type Info struct {
UID uint64 `form:"uid" json:"uid"`
}
param := Info{}
if err = ctx.ShouldBind(&param); err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset param error "+err.Error())
return
}
_uuid, err := uuid.NewRandom()
if err != nil {
common.ServeJSON(ctx, stderr.Failure, "web user DevIDReset uuid NewRandom error "+err.Error())
return
}
if err = usermod.ResetDevID(param.UID, _uuid.String()); err != nil {
common.ServeJSON(ctx, stderr.Failure, "web user DevIDReset ResetDevID error "+err.Error())
return
}
log, _ := json.Marshal(param)
_ = operatorlgmod.RecordOperation(adminID, constant.UserManageList, constant.Modify, string(log), ctx.Request.URL.RequestURI())
common.ServeJSON(ctx, stderr.Success, nil)
}
// CreditAmount doc
// @Summary 修改用户金币
// @Description 修改用户金币
// @Tags web-用户管理
// @Accept mpfd,json
// @Produce json,html
// @Param uid formData integer true "用户id"
// @Param amount formData integer true "增减金额"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/user/devID/reset [get]
func CreditAmount(ctx *gin.Context) {
adminID, err := common.GetAdminAct(ctx)
if err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminAct error "+err.Error())
return
}
var p struct {
UID uint64 `json:"uid"`
Amount int64 `json:"amount"`
Reason string `json:"reason"`
}
if err = ctx.ShouldBind(&p); err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset param error "+err.Error())
return
}
if err = userser.CreditAmount(p.UID, p.Amount, adminID, p.Reason); err != nil {
if err.Error() == "Insufficient balance" {
common.ServeJSON(ctx, stderr.InsufficientBalance, "web user DevIDReset ResetDevID error "+err.Error())
return
}
common.ServeJSON(ctx, stderr.Failure, "web user DevIDReset ResetDevID error "+err.Error())
return
}
log, _ := json.Marshal(p)
_ = operatorlgmod.RecordOperation(adminID, constant.UserManageList, constant.Modify, string(log), ctx.Request.URL.RequestURI())
common.ServeJSON(ctx, stderr.Success, nil)
}
func FruitCoinChange(ctx *gin.Context) {
adminID, err := common.GetAdminAct(ctx)
if err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminAct error "+err.Error())
return
}
var p struct {
UID uint64 `json:"uid"`
FruitCoin int64 `json:"fruitCoin"`
Reason string `json:"reason"`
}
if err = ctx.ShouldBind(&p); err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset param error "+err.Error())
return
}
if err = userser.FruitCoinChange(p.UID, p.FruitCoin, adminID, p.Reason); err != nil {
if err.Error() == "Insufficient balance" {
common.ServeJSON(ctx, stderr.InsufficientBalance, "web user DevIDReset ResetDevID error "+err.Error())
return
}
common.ServeJSON(ctx, stderr.Failure, "web user DevIDReset ResetDevID error "+err.Error())
return
}
log, _ := json.Marshal(p)
_ = operatorlgmod.RecordOperation(adminID, constant.UserManageList, constant.Modify, string(log), ctx.Request.URL.RequestURI())
common.ServeJSON(ctx, stderr.Success, nil)
}
// PlayRecord doc
// @Summary 用户VIP权益
// @Description 用户VIP权益
// @Tags web-用户管理
// @Accept mpfd,json
// @Produce json,html
// @Param uid formData integer true "用户id"
// @Param pageNumber query integer true "当前页"
// @Param pageSize query integer true "每页条数"
// @Success 200 {object} usermod.UserVipInfoRes "success"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/user/vipInfo [get]
func VipInfo(c *gin.Context) {
var arg struct {
UID uint64 `form:"uid" json:"uid" binding:"required"`
}
if err := c.ShouldBind(&arg); err != nil {
common.ServeJSON(c, stderr.ErrParamError, "web user VipInfo arg error "+err.Error())
return
}
//查询
userInfo, err := userser.Info(arg.UID)
if err != nil {
common.ServeJSON(c, stderr.ErrServerUnavailable, "web user VipInfo userser.Info error "+err.Error())
return
}
common.ServeJSON(c, stderr.Success, userInfo)
}
// CreditGold doc
// @Summary 用户金币回收
// @Description 用户金币回收
// @Tags web-用户管理
// @Accept mpfd,json
// @Produce json,html
// @Param uid formData integer true "用户id"
// @Param amount formData integer true "增减金额"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/user/credit/gold [post]
func CreditGold(ctx *gin.Context) {
adminID, err := common.GetAdminAct(ctx)
if err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminAct error "+err.Error())
return
}
var p struct {
UID uint64 `json:"uid"`
Amount int64 `json:"amount"`
Income int64 `json:"income"`
Mark string `json:"mark"`
}
if err = ctx.ShouldBind(&p); err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset param error "+err.Error())
return
}
if err = userser.CreditGold(p.UID, p.Amount, p.Income, adminID, p.Mark); err != nil {
common.ServeJSON(ctx, stderr.Failure, err.Error())
return
}
log, _ := json.Marshal(p)
_ = operatorlgmod.RecordOperation(adminID, constant.UserManageList, constant.Modify, string(log), ctx.Request.URL.RequestURI())
common.ServeJSON(ctx, stderr.Success, nil)
}
// GenerateQRCode doc
// @Summary 生成用户登录用二维码
// @Description 生成用户登录用二维码
// @Tags vid
// @Accept mpfd,json
// @Produce json,html
// @Param uid formData integer true "用户ID"
// @Success 200 {string} string "qr content"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /api/web/admin/user/qr_code [post]
func GenerateQRCode(ctx *gin.Context) {
manager, err := common.GetAdminAct(ctx)
if err != nil {
common.ServeJSON(ctx, stderr.AdminIDErr, err.Error())
return
}
var p struct {
UID uint64 `json:"uid" binding:"required"`
}
if err = ctx.ShouldBind(&p); err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, nil)
return
}
content, err := userser.GenerateQRCode(p.UID)
if err != nil {
common.ServeJSON(ctx, stderr.ErrInterServerError, err)
return
}
log, _ := json.Marshal(p)
_ = operatorlgmod.RecordOperation(manager, constant.VideoManageList, constant.Modify, string(log), ctx.Request.URL.RequestURI())
common.ServeJSON(ctx, stderr.Success, content)
}
// UpdateFreeTimes doc
// @Summary 修改用户AI脱衣免费次数
// @Description 修改用户AI脱衣免费次数
// @Tags web-用户管理
// @Accept mpfd,json
// @Produce json,html
// @Param uid formData integer true "用户id"
// @Param freeTimes formData integer true "增减免费次数"
// @Param mark formData string true "备注"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/user/update/freeTimes [post]
func UpdateFreeTimes(ctx *gin.Context) {
adminAct, err := common.GetAdminAct(ctx)
if err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminAct error "+err.Error())
return
}
var in usermod.UpdateFreeTimesCond
err = ctx.ShouldBind(&in)
if err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset param error "+err.Error())
return
}
err = userser.UpdateFreeTimes(&in, adminAct)
if err != nil {
common.ServeJSON(ctx, stderr.Failure, err.Error())
return
}
log, _ := json.Marshal(in)
_ = operatorlgmod.RecordOperation(adminAct, constant.UserManageList, constant.Modify, string(log), ctx.Request.URL.RequestURI())
common.ServeJSON(ctx, stderr.Success, nil)
}
// UpdateDownload doc
// @Summary 修改用户下载次数
// @Description 修改用户下载次数
// @Tags web-用户管理
// @Accept mpfd,json
// @Produce json,html
// @Param uid formData integer true "用户id"
// @Param download formData integer true "增减下载次数"
// @Param mark formData string true "备注"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/user/update/download [post]
func UpdateDownload(ctx *gin.Context) {
adminAct, err := common.GetAdminAct(ctx)
if err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminAct error "+err.Error())
return
}
var in usermod.UpdateDownloadCond
err = ctx.ShouldBind(&in)
if err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset param error "+err.Error())
return
}
err = userser.UpdateDownloadCounts(&in, adminAct)
if err != nil {
common.ServeJSON(ctx, stderr.Failure, err.Error())
return
}
log, _ := json.Marshal(in)
_ = operatorlgmod.RecordOperation(adminAct, constant.UserManageList, constant.Modify, string(log), ctx.Request.URL.RequestURI())
common.ServeJSON(ctx, stderr.Success, nil)
}
// DeleteComment doc
// @Summary 删除用户评论
// @Description 删除用户评论
// @Tags web-用户管理
// @Accept mpfd,json
// @Produce json,html
// @Param uid formData integer true "用户id"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/user/deleteComment [post]
func DeleteComment(ctx *gin.Context) {
adminAct, err := common.GetAdminAct(ctx)
if err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminAct error "+err.Error())
return
}
var in usermod.DeleteCommentCond
err = ctx.ShouldBind(&in)
if err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset param error "+err.Error())
return
}
err = userser.DeleteComment(&in, adminAct)
if err != nil {
common.ServeJSON(ctx, stderr.Failure, err.Error())
return
}
log, _ := json.Marshal(in)
_ = operatorlgmod.RecordOperation(adminAct, constant.UserManageList, constant.Delete, string(log), ctx.Request.URL.RequestURI())
common.ServeJSON(ctx, stderr.Success, nil)
}
// QueryGameCode doc
// @Summary 查询用户游戏码
// @Description 查询用户游戏码
// @Tags web-用户管理
// @Accept mpfd,json
// @Produce json,html
// @Param q query usermod.QueryGameCodeCond false "请求参数"
// @Success 200 object game.QueryData "成功"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/user/queryGameCode [get]
func QueryGameCode(ctx *gin.Context) {
var in usermod.QueryGameCodeCond
err := ctx.ShouldBind(&in)
if err != nil {
log.Error(fmt.Sprintf("web user QueryGameCode param error:%v", err))
common.ServeJSON(ctx, stderr.ErrParamError, "web user QueryGameCode param error "+err.Error())
return
}
data, err := userser.QueryGameCode(&in)
if err != nil {
log.Error(fmt.Sprintf("web user QueryGameCode error:%v", err))
common.ServeJSON(ctx, stderr.Failure, err.Error())
return
}
common.ServeJSON(ctx, stderr.Success, data)
}
// UpdateLotteryTimes doc
// @Summary 修改用户抽奖次数
// @Description 修改用户抽奖次数
// @Tags web-用户管理
// @Accept mpfd,json
// @Produce json,html
// @Param uid formData integer true "用户id"
// @Param lotteryTimes formData integer true "增减抽奖次数"
// @Param mark formData string true "备注"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/user/update/lotteryTimes [post]
func UpdateLotteryTimes(ctx *gin.Context) {
adminAct, err := common.GetAdminAct(ctx)
if err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminAct error "+err.Error())
return
}
var in usermod.UpdateLotteryTimesCond
err = ctx.ShouldBind(&in)
if err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset param error "+err.Error())
return
}
err = userser.UpdateLotteryTimes(&in, adminAct)
if err != nil {
common.ServeJSON(ctx, stderr.Failure, err.Error())
return
}
log, _ := json.Marshal(in)
_ = operatorlgmod.RecordOperation(adminAct, constant.UserManageList, constant.Modify, string(log), ctx.Request.URL.RequestURI())
common.ServeJSON(ctx, stderr.Success, nil)
}
// AddVIP 新增产品产生的行为
func AddVIP(uid uint64, productID primitive.ObjectID, sys string) stderr.Code {
p, err := productmod.FindProduct(productID, sys)
if err != nil || p == nil {
return stderr.ErrParamError
}
u, err := usermod.FindUserByUID(uid)
if err != nil || u == nil {
return stderr.ErrNetWorkBusy
}
w, err := walletmod.GetWallet(uid)
if err != nil || w == nil {
return stderr.ErrNetWorkBusy
}
vipExpire, vipLevel, payVidDiscount, vName := checkVipRenew(u, p)
sel := usermod.UserSelector{VipExpireDate: &vipExpire, VipLevel: &vipLevel, PayVidDiscount: &payVidDiscount, VipName: &vName}
if p.GoldVideoFreeDay > 0 {
expire := time.Time{}
if u.GoldVideoFreeExpire.IsZero() || u.GoldVideoFreeExpire.Before(time.Now()) {
expire = time.Now().AddDate(0, 0, p.GoldVideoFreeDay)
} else {
expire = u.GoldVideoFreeExpire.AddDate(0, 0, p.GoldVideoFreeDay)
}
sel.GoldVideoFreeExpire = &expire
}
var plan walletmod.CreditPlan
if p.DownloadCount > 0 {
plan.DownloadCount = &p.DownloadCount
}
if p.AiUndressCount > 0 {
aiUndressFreeTimes := int64(p.AiUndressCount)
plan.AiUndressFreeTimes = &aiUndressFreeTimes
}
if p.LuckyDrawCount > 0 {
plan.LotteryTimes = &p.LuckyDrawCount
}
if p.ChatPrice > 0 {
sel.ChatPrice = &p.ChatPrice
}
if p.GiveCoin > 0 {
plan.Amount = &p.GiveCoin
}
if p.BroadcastDays > 0 {
expire := time.Time{}
if u.BroadcastExpire.IsZero() || u.BroadcastExpire.Before(time.Now()) {
expire = time.Now().AddDate(0, 0, p.BroadcastDays)
} else {
expire = u.BroadcastExpire.AddDate(0, 0, p.BroadcastDays)
}
sel.BroadcastExpire = &expire
}
if p.DramaDays > 0 {
expire := usermod.RenewDramaExpire(u.DramaExpire, time.Now(), p.DramaDays)
sel.DramaExpire = &expire
}
if err = webg.VideoDB.Trans(func(t *db.MongoTool) error {
var err error
if err = usermod.UpdateVIP(t, uid, u.VipExpireDate, sel); err != nil {
return err
}
txnLogs := []txnmod.TransactionLog{
{
UID: uid,
TranType: txnmod.AdminAddVIP.Key(),
TranTypeInt: int64(txnmod.AdminAddVIP),
Desc: "官方添加VIP-" + p.Name,
SysType: u.SysType,
RealAmount: w.RealAmount(),
},
}
if p.AiUndressCount > 0 || p.GiveCoin > 0 || p.DownloadCount > 0 || p.LuckyDrawCount > 0 {
wallet, err := walletmod.Credit(t, plan, uid)
if err != nil {
return err
}
// 插入购买会员卡赠送金币流水
if p.GiveCoin > 0 {
giveLog := txnmod.TransactionLog{
UID: uid,
Amount: p.GiveCoin,
ActualAmount: float64(p.GiveCoin),
TranType: txnmod.VipCardGive.Key(),
TranTypeInt: int64(txnmod.VipCardGive),
Desc: "官方添加VIP-" + p.Name + "-赠送金币",
SysType: u.SysType,
RealAmount: walletmod.GetRealAmount(wallet),
}
txnLogs = append(txnLogs, giveLog)
}
if p.AiUndressCount > 0 {
aiLog := txnmod.TransactionLog{
UID: uid,
Amount: int64(p.AiUndressCount),
ActualAmount: float64(p.AiUndressCount),
TranType: txnmod.VipCardGiveAiUndressFreeCount.Key(),
TranTypeInt: int64(txnmod.VipCardGiveAiUndressFreeCount),
Desc: fmt.Sprintf("官方添加VIP%s-赠送AI脱衣免费次数[%v次]", p.Name, p.AiUndressCount),
DiscDoc: u.DiscDoc,
SysType: u.SysType,
RealAmount: walletmod.GetRealAmount(wallet),
}
txnLogs = append(txnLogs, aiLog)
}
if p.DownloadCount > 0 {
txnLogs = append(txnLogs, txnmod.TransactionLog{
UID: uid,
DownloadCount: p.DownloadCount,
TranType: txnmod.GiveDownload.Key(),
TranTypeInt: int64(txnmod.GiveDownload),
Desc: fmt.Sprintf("官方添加VIP-%v", p.Name) + fmt.Sprintf("-赠送视频下载[%d]次", p.DownloadCount),
DiscDoc: u.DiscDoc,
SysType: u.SysType,
RealAmount: walletmod.GetRealAmount(wallet),
})
}
if p.LuckyDrawCount > 0 {
txnLogs = append(txnLogs, txnmod.TransactionLog{
UID: uid,
DownloadCount: p.LuckyDrawCount,
TranType: txnmod.GiveLotteryTimesCount.Key(),
TranTypeInt: int64(txnmod.GiveLotteryTimesCount),
Desc: fmt.Sprintf("官方添加VIP-%v", p.Name) + fmt.Sprintf("-赠送[%d]次数", p.LuckyDrawCount),
DiscDoc: u.DiscDoc,
SysType: u.SysType,
})
}
}
if len(txnLogs) > 0 {
if err = txnmod.InsertManyTransactionLog(t, txnLogs); err != nil {
log.Warn(fmt.Sprintf("productser addVIP Transaction err %s", err.Error()))
return err
}
}
return nil
}); err != nil {
log.Warn(fmt.Sprintf("productser addVIP Transaction err %s", err.Error()))
return stderr.BuyFailed //通知消息
}
return stderr.Success
}
func checkVipRenew(u *usermod.User, p *productmod.Product) (time.Time, int, int, string) {
var (
end time.Time
now = time.Now()
level = p.VipLevel
payVidDiscount = p.PayVidDiscount
d = time.Hour * 24 * time.Duration(p.Duration)
vipName = p.Name
)
if u.VipExpireDate.After(now) { //renew
// 判断用户VIP等级
if p.VipLevel > u.VipLevel {
end = now.Add(d)
} else if p.VipLevel == u.VipLevel {
end = u.VipExpireDate.Add(d)
} else if p.VipLevel < u.VipLevel {
end = u.VipExpireDate
}
if u.VipLevel > p.VipLevel { //当前用户的vip等级比这次购买的大,使用用户的
level = u.VipLevel
vipName = u.VipName
}
//当前用户的折扣比这次购买的大,使用用户的
if u.PayVidDiscount < payVidDiscount && u.PayVidDiscount > 0 {
payVidDiscount = u.PayVidDiscount
}
} else {
end = now.Add(time.Duration(d))
}
return end, level, payVidDiscount, vipName
}
// SetaiMateBalance doc
// @Summary 设置用户AI伴侣积分
// @Description 设置用户AI伴侣积分
// @Tags web-用户管理
// @Accept mpfd,json
// @Produce json,html
// @Param uid formData integer true "用户id"
// @Param amount formData integer true "增减金额"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/user/credit/aiMateBalance [post]
func SetAiMateBalance(ctx *gin.Context) {
adminID, err := common.GetAdminAct(ctx)
if err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminAct error "+err.Error())
return
}
var p struct {
UID uint64 `json:"uid"`
AiMateBalance float64 `json:"aiMateBalance"` //ai伴侣余额
Reason string `json:"reason"`
}
if err = ctx.ShouldBind(&p); err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset param error "+err.Error())
return
}
if p.AiMateBalance < 0 {
common.ServeJSON(ctx, stderr.ErrParamError, nil)
return
}
if err = userser.SetAiMateBalance(p.UID, p.AiMateBalance, p.Reason); err != nil {
common.ServeJSON(ctx, stderr.Failure, err.Error())
return
}
log, _ := json.Marshal(p)
_ = operatorlgmod.RecordOperation(adminID, constant.UserManageList, constant.Modify, string(log), ctx.Request.URL.RequestURI())
common.ServeJSON(ctx, stderr.Success, nil)
}
// PrivateZone doc
// @Summary 批量使用户开启私密圈权限
// @Description 批量使用户开启私密圈权限
// @Tags web-用户管理
// @Accept mpfd,json
// @Produce json,html
// @Param uidList formData array true "uid数组"
// @Param enable formData bool true "ture:开启私密圈权限,false:关闭私密圈权限"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/user/privateZone [post]
func PrivateZone(c *gin.Context) {
manager, err := common.GetAdminAct(c)
if err != nil {
common.ServeJSON(c, stderr.AdminIDErr, err.Error())
return
}
var arg struct {
UIDList []uint64 `form:"uidList" json:"uidList" binding:"required"`
Enable *bool `form:"enable" json:"enable" binding:"required"`
}
if err = c.ShouldBind(&arg); err != nil {
common.ServeJSON(c, stderr.ErrParamError, "web user Banned arg error "+err.Error())
return
}
doc := usermod.UserSelector{HasPrivateZone: arg.Enable}
if _, err = usermod.UpdateMany(arg.UIDList, doc); err != nil {
common.ServeJSON(c, stderr.ErrServerUnavailable, err)
return
}
log, _ := json.Marshal(arg)
_ = operatorlgmod.RecordOperation(manager, constant.UserManageList, constant.Modify, string(log), c.Request.URL.RequestURI())
common.ServeJSON(c, stderr.Success, "")
}
// CreditIntegral doc
// @Summary 修改用户积分
// @Description 修改用户积分
// @Tags web-用户管理
// @Accept mpfd,json
// @Produce json,html
// @Param uid formData integer true "用户id"
// @Param integral formData integer true "增减积分"
// @Success 200 {string} json "{"msg": "操作成功"}"
// @Failure 400 {string} json "{"msg": "操作失败"}"
// @Router /web/admin/user/integral [post]
func CreditIntegral(ctx *gin.Context) {
adminID, err := common.GetAdminAct(ctx)
if err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset GetAdminAct error "+err.Error())
return
}
var p struct {
UID uint64 `json:"uid"`
Integral int64 `json:"integral"`
Reason string `json:"reason"`
}
if err = ctx.ShouldBind(&p); err != nil {
common.ServeJSON(ctx, stderr.ErrParamError, "web user DevIDReset param error "+err.Error())
return
}
if err = userser.CreditIntegral(p.UID, p.Integral, adminID, p.Reason); err != nil {
if err.Error() == "Insufficient balance" {
common.ServeJSON(ctx, stderr.InsufficientBalance, "web user DevIDReset ResetDevID error "+err.Error())
return
}
common.ServeJSON(ctx, stderr.Failure, "web user DevIDReset ResetDevID error "+err.Error())
return
}
log, _ := json.Marshal(p)
_ = operatorlgmod.RecordOperation(adminID, constant.UserManageList, constant.Modify, string(log), ctx.Request.URL.RequestURI())
common.ServeJSON(ctx, stderr.Success, nil)
}