Initial commit

This commit is contained in:
2026-05-20 16:13:58 +08:00
commit ceffbe382e
500 changed files with 157469 additions and 0 deletions
+588
View File
@@ -0,0 +1,588 @@
package channelSer
import (
"context"
"errors"
"fmt"
"os"
"path"
"stat/api/proto"
"stat/common/log"
"stat/models/adminMod"
"stat/models/appInfoMod"
"stat/models/channelmod"
"stat/models/registermod"
"time"
"github.com/360EntSecGroup-Skylar/excelize"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options"
)
// SearchChannelInfo 查询渠道信息
func SearchChannelInfo(ctx context.Context, req *proto.ChannelInfoSearch) (
*proto.ChannelInfoSearchResp, error) {
filter := bson.M{}
opt := &options.FindOptions{}
opt.SetSort(bson.M{channelmod.FN.ChannelInfo.CreatedAt: -1})
opt.SetSkip((req.PageNum - 1) * req.PageSize)
opt.SetLimit(req.PageSize)
resp := &proto.ChannelInfoSearchResp{}
if req.ID != nil && *req.ID != "" {
id, err := primitive.ObjectIDFromHex(*req.ID)
if err != nil {
return nil, errors.New("ID 格式错误")
}
filter[channelmod.FN.ChannelInfo.ID] = id
}
if req.Channel != nil && *req.Channel != "" {
filter[channelmod.FN.ChannelInfo.Channel] = bson.M{"$regex": *req.Channel}
}
if req.AppId != nil {
filter[channelmod.FN.ChannelInfo.AppIds] = bson.M{"$in": []int32{*req.AppId}}
}
if req.Type != nil {
filter[channelmod.FN.ChannelInfo.Type] = *req.Type
}
if req.ParentChannel != nil && *req.ParentChannel != "" {
filter[channelmod.FN.ChannelInfo.ParentChannel] = bson.M{"$regex": *req.ParentChannel}
}
if req.UserName != nil && *req.UserName != "" {
filter[channelmod.FN.ChannelInfo.UserName] = *req.UserName
}
if req.Status != nil {
filter[channelmod.FN.ChannelInfo.Status] = *req.Status
}
if req.Remark != nil && *req.Remark != "" {
filter[channelmod.FN.ChannelInfo.Remark] = bson.M{"$regex": *req.Remark}
}
if req.Mobile != nil && *req.Mobile != "" {
filter[channelmod.FN.ChannelInfo.Mobile] = bson.M{"$regex": *req.Mobile}
}
total, serr := channelmod.CountChannelInfos(ctx, filter)
if serr != nil {
return nil, serr
}
if total == 0 {
return resp, nil
}
channelInfoList, err := channelmod.FindManyChannelInfo(ctx, filter, opt)
if serr != nil {
return nil, err
}
for i := range channelInfoList {
channelInfoList[i].Token = ""
}
resp.List = channelInfoList
resp.Total = total
return resp, nil
}
// SearchChannelInfoExport 导出渠道信息
func SearchChannelInfoExport(ctx context.Context, req *proto.ChannelInfoSearch) (string, error) {
filter := bson.M{}
opt := &options.FindOptions{}
opt.SetSort(bson.M{channelmod.FN.ChannelInfo.CreatedAt: -1})
opt.SetSkip((req.PageNum - 1) * req.PageSize)
opt.SetLimit(req.PageSize)
if req.ID != nil && *req.ID != "" {
id, err := primitive.ObjectIDFromHex(*req.ID)
if err != nil {
return "", errors.New("ID 格式错误")
}
filter[channelmod.FN.ChannelInfo.ID] = id
}
if req.Channel != nil && *req.Channel != "" {
filter[channelmod.FN.ChannelInfo.Channel] = bson.M{"$regex": *req.Channel}
}
if req.AppId != nil {
filter[channelmod.FN.ChannelInfo.AppIds] = bson.M{"$in": []int32{*req.AppId}}
}
if req.Type != nil {
filter[channelmod.FN.ChannelInfo.Type] = *req.Type
}
if req.ParentChannel != nil && *req.ParentChannel != "" {
filter[channelmod.FN.ChannelInfo.ParentChannel] = bson.M{"$regex": *req.ParentChannel}
}
if req.UserName != nil && *req.UserName != "" {
filter[channelmod.FN.ChannelInfo.UserName] = bson.M{"$regex": *req.UserName}
}
if req.Status != nil {
filter[channelmod.FN.ChannelInfo.Status] = *req.Status
}
if req.Remark != nil && *req.Remark != "" {
filter[channelmod.FN.ChannelInfo.Remark] = bson.M{"$regex": *req.Remark}
}
if req.Remark != nil && *req.Remark != "" {
filter[channelmod.FN.ChannelInfo.Remark] = bson.M{"$regex": *req.Remark}
}
total, serr := channelmod.CountChannelInfos(ctx, filter)
if serr != nil {
return "", serr
}
if total == 0 {
return "", nil
}
appList, err := appInfoMod.GetAllAppInfo(ctx)
if err != nil {
return "", err
}
channelInfoList, err := channelmod.FindManyChannelInfo(ctx, filter, opt)
if serr != nil {
return "", err
}
filePath := fmt.Sprintf("./tmp/兑换记录-%s.xlsx", time.Now().Format("2006-01-02 15:04:05"))
if sErr := channelInfoExport(filePath, channelInfoList, appList); sErr != nil {
return "", sErr
}
return filePath, nil
}
// channelInfoExport 导出
func channelInfoExport(filePath string, list channelmod.ChannelInfoList, appList []appInfoMod.AppInfo) error {
f := excelize.NewFile()
sheetName := "Sheet1"
// 设置列宽
f.SetColWidth("Sheet1", "A", "L", 23)
// 设置表头行高
f.SetRowHeight("Sheet1", 1, 25)
// 设置表头样式
headStyleID, _ := f.NewStyle(`{
"font":{
"color":"#333333",
"bold":true,
"size":16,
"family":"arial"
},
"alignment":{
"vertical":"center",
"horizontal":"center",
"wrap_text":true
}
}`)
f.SetCellStyle("Sheet1", "A1", "L1", headStyleID)
idx := f.NewSheet(sheetName)
var exportTransWaterTitle = map[string]string{
"A1": "名称",
"B1": "应用列表",
"C1": "渠道类型",
"D1": "IP",
"E1": "下级代理数",
"F1": "父渠道",
"G1": "禁止登陆",
"H1": "渠道状态",
"I1": "登陆错误次数",
"J1": "创建者",
"K1": "创建时间",
"L1": "更新时间",
}
for k, v := range exportTransWaterTitle {
f.SetCellValue(sheetName, k, v)
}
var cLock string
var cStatus string
for k, v := range list {
apps := string2app(appList, v.AppIds)
i := 'A' // i 不能超过Z,即列输不能超过26列,超出将出现bug
f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.Channel) //名称
i++
f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), apps) //应用列表
i++
f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.Type.String()) //渠道类型
i++
f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.IP) //IP
i++
f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.ChildCount) //下级代理数
i++
f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.ParentChannel) //父渠道
i++
if v.Lock {
cLock = "封禁"
} else if !v.Lock {
cLock = "未封禁"
}
f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), cLock) //禁止登陆
i++
if v.Status {
cStatus = "开启"
} else if !v.Status {
cStatus = "关闭"
}
f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), cStatus) //渠道状态
i++
f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.ShowMagic) //登陆错误次数
i++
f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.UserName) //创建者
i++
created := v.CreatedAt.Local().Format("2006-01-02 15:04:05")
f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), created) //创建时间
i++
updated := v.UpdatedAt.Local().Format("2006-01-02 15:04:05")
f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), updated) //更新时间
}
f.SetActiveSheet(idx)
p, _ := os.Getwd()
fileName := path.Join(p, filePath)
if err := f.SaveAs(fileName); err != nil {
log.Error("redeemCodeExport:export save file to disk failed",
log.Any("fileName", fileName),
log.E(err))
return err
}
return nil
}
func string2app(appList []appInfoMod.AppInfo, appIds []int32) string {
var result string
for count, id := range appIds {
if count == len(appIds)-1 {
result += GetAppName(appList, id)
} else {
result += (GetAppName(appList, id) + "、")
}
}
return result
}
// AddChannelInfo 添加一个媒体视频
func AddChannelInfo(ctx context.Context, username string, req *proto.ChannelInfoAdd) (*channelmod.ChannelInfo, error) {
if channelmod.IsOfficialChannelName(req.Channel) {
return nil, fmt.Errorf("渠道名字为系统保留字,请换一个渠道名字")
}
checkFilter := bson.M{channelmod.FN.ChannelInfo.Channel: req.Channel}
channelInfo, err := channelmod.FindOneChannelInfo(ctx, checkFilter)
if err != nil {
return nil, err
}
if channelInfo.Channel == req.Channel {
return channelInfo, errors.New("渠道已经存在")
}
now := time.Now()
newChannelInfo := channelmod.ChannelInfo{
Channel: req.Channel,
UserName: username,
ParentChannel: req.ParentChannel,
Password: req.Password,
Status: req.Status,
Mobile: req.Mobile,
Type: req.Type,
Remark: req.Remark,
Lock: req.Lock,
ChildShowDivideRate: req.ChildShowDivideRate,
ShowMagic: 0,
CreatedAt: now,
UpdatedAt: now,
}
if req.Type == channelmod.ChannelTypeParent {
newChannelInfo.ParentChannel = ""
newChannelInfo.ParentAgent = ""
} else if req.Type == channelmod.ChannelTypeSecond {
parentInfo, err := channelmod.FindOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: req.ParentChannel})
if err != nil {
return nil, err
}
if parentInfo.Channel != req.ParentChannel {
return nil, fmt.Errorf("指定的父渠道[%s]不存在", req.ParentChannel)
}
newChannelInfo.ParentChannel = req.ParentChannel
newChannelInfo.ParentAgent = req.ParentChannel
} else {
return nil, errors.New("后台只支持添加一级和二级渠道,其他级别的渠道请登陆渠道后台添加")
}
err = channelmod.InsertOneChannelInfo(ctx, &newChannelInfo)
if err != nil {
log.Error("AddChannelInfo InsertOneChannelInfo", log.Any("channel", newChannelInfo.ParentChannel), log.E(err))
return nil, err
}
if req.Type.IsChild() {
setdoc := bson.M{"$inc": bson.M{channelmod.FN.ChannelInfo.ChildCount: 1}}
err = channelmod.UpdateOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: newChannelInfo.ParentChannel}, setdoc)
if err != nil {
log.Error("AddChannelInfo UpdateOneChannelInfo", log.Any("channel", newChannelInfo.ParentChannel), log.E(err))
return nil, err
}
}
return channelmod.FindOneChannelInfo(ctx, checkFilter)
}
// DelChannelInfo 删除指定渠道信息
func DelChannelInfo(ctx context.Context, channelId string) error {
id, err := primitive.ObjectIDFromHex(channelId)
if err != nil {
return errors.New("ID 格式错误")
}
// 1. 查询渠道信息
channelFilter := bson.M{channelmod.FN.ChannelInfo.ID: id}
channelInfo, err := channelmod.FindOneChannelInfo(ctx, channelFilter)
if err != nil {
log.Error("DelChannelInfo FindOneChannelInfo", log.Any("channelId", channelId), log.E(err))
return err
}
// 3. 查询子代理数
childFilter := bson.M{channelmod.FN.ChannelInfo.ParentAgent: channelInfo.Channel}
childCount, err := channelmod.CountChannelInfos(ctx, childFilter)
if err != nil {
log.Error("DelChannelInfo CountChannelDeductionRules", log.Any("channelId", channelId), log.E(err))
return err
}
if childCount > 0 {
return errors.New("代理下级代理不为空,请先删除下级代理")
}
// 2. 查询渠道绑定应用
ruleFilter := bson.M{channelmod.FN.ChannelDeductionRule.Channel: channelInfo.Channel}
ruleCount, err := channelmod.CountChannelDeductionRules(ctx, ruleFilter)
if err != nil {
log.Error("DelChannelInfo CountChannelDeductionRules", log.Any("channelId", channelId), log.E(err))
return err
}
if ruleCount > 0 {
return errors.New("绑定应用不为空,请先删除绑定应用")
}
// 4. 删除渠道
_, err = channelmod.DelOneChannelInfo(ctx, channelFilter)
if err != nil {
return err
}
// 5 更新父渠道子渠道数量
if channelInfo.Type.IsChild() {
setdoc := bson.M{"$inc": bson.M{channelmod.FN.ChannelInfo.ChildCount: -1}}
err = channelmod.UpdateOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: channelInfo.ParentAgent}, setdoc)
if err != nil {
log.Error("DelChannelInfo UpdateOneChannelInfo", log.Any("channel", channelInfo.ParentAgent), log.E(err))
return err
}
}
return nil
}
// UpdateChannelInfo 更新指定渠道
func UpdateChannelInfo(ctx context.Context, channelId string, req proto.ChannelInfoUpdate) error {
id, err := primitive.ObjectIDFromHex(channelId)
if err != nil {
return errors.New("ID 格式错误")
}
filter := bson.M{channelmod.FN.ChannelInfo.ID: id}
//更新数据库
setDoc := bson.M{"$set": req}
serr := channelmod.UpdateOneChannelInfo(ctx, filter, setDoc)
if serr != nil {
return serr
}
return nil
}
// UpdateOneChannelOwner 更新指定渠道的所有者
func UpdateOneChannelOwner(ctx context.Context, operator, account string, req proto.ChannelOwnerUpdate) error {
filter := bson.M{channelmod.FN.ChannelInfo.Channel: req.Channel}
cInfo, serr := channelmod.FindOneChannelInfo(ctx, filter)
if serr != nil {
log.Error("UpdateOneChannelOwner:FindOneChannelInfo err", log.Any("serr", serr),
log.Any("req", req))
return serr
} else if cInfo != nil && cInfo.Channel == "" {
log.Error("UpdateOneChannelOwner:FindOneChannelInfo err", log.Any("serr", serr),
log.Any("req", req))
return errors.New("渠道不存在")
}
if req.UserName == "" {
return errors.New("变更的所有者不能为空")
} else if req.UserName == cInfo.UserName {
return errors.New("变更的所有者不能与之前的相同")
// } else if cInfo.Type != 1 { // 只能操作1级渠道
// return errors.New("变更所有者,只能操作1级渠道")
}
admin, serr := adminMod.FindOnedmin(ctx, bson.M{"name": req.UserName})
if serr != nil {
log.Error("UpdateOneChannelOwner:FindOnedmin err", log.Any("serr", serr),
log.Any("req", req))
return serr
} else if admin != nil && admin.Name == "" {
log.Error("UpdateOneChannelOwner:FindOnedmin err", log.Any("serr", serr),
log.Any("req", req))
return errors.New("账号不存在")
}
now := time.Now()
// 更新渠道信息
setDoc := bson.M{"$set": bson.M{
channelmod.FN.ChannelInfo.UserName: req.UserName,
channelmod.FN.ChannelInfo.UpdatedAt: now,
}}
serr = channelmod.UpdateOneChannelInfo(ctx, filter, setDoc)
if serr != nil {
log.Error("UpdateOneChannelOwner:UpdateOneChannelInfo err", log.Any("serr", serr),
log.Any("req", req))
return serr
}
// 更新渠道统计信息
csFilter := bson.M{channelmod.FN.ChannelStat.Channel: cInfo.Channel}
csSetDoc := bson.M{"$set": bson.M{channelmod.FN.ChannelStat.UserName: req.UserName}}
serr = channelmod.UpdateManyChannelStat(ctx, csFilter, csSetDoc)
if serr != nil {
log.Error("UpdateOneChannelOwner:UpdateManyChannelStat err", log.Any("serr", serr),
log.Any("req", req))
return serr
}
// 找到一级渠道的所有子渠道
allFlter := bson.M{channelmod.FN.ChannelInfo.ParentChannel: req.Channel}
chanIds := make([]string, 0)
cInfos, _ := channelmod.FindManyChannelInfo(ctx, allFlter)
if len(cInfos) > 0 {
for _, info := range cInfos {
chanIds = append(chanIds, info.Channel)
}
// 更新一级渠道的所有子渠道
serr = channelmod.UpdateManyChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: bson.M{"$in": chanIds}}, setDoc)
if serr != nil {
log.Error("UpdateOneChannelOwner:UpdateManyChannelInfo 2 err", log.Any("serr", serr),
log.Any("req", req))
}
// 更新一级渠道的所有子渠道统计
serr = channelmod.UpdateManyChannelStat(ctx, bson.M{channelmod.FN.ChannelStat.Channel: bson.M{"$in": chanIds}}, csSetDoc)
if serr != nil {
log.Error("UpdateOneChannelOwner:UpdateManyChannelStat 2 err", log.Any("serr", serr),
log.Any("req", req))
}
}
// 添加变更记录
new := &channelmod.ChannelOwnerChange{
ID: primitive.NewObjectID(),
Channel: cInfo.Channel,
OldUser: cInfo.UserName,
NewUser: req.UserName,
Mark: req.Mark,
CreatedAt: now,
UpdatedAt: now,
Operator: operator,
Account: account,
}
serr = channelmod.InsertOneChannelOwnerChange(ctx, new)
if serr != nil {
log.Error("UpdateOneChannelOwner:InsertOneChannelOwnerChange err", log.Any("new", new),
log.Any("err", serr))
return serr
}
return nil
}
// SearchChannelOwnerChangeInfo 查询渠道所有者变更信息
func SearchChannelOwnerChangeInfo(ctx context.Context, req *proto.ChannelOwnerChangeInfoSearch) (
*proto.ChannelOwnerChangeInfoSearchResp, error) {
filter := bson.M{}
opt := &options.FindOptions{}
opt.SetSort(bson.M{channelmod.FN.ChannelInfo.CreatedAt: -1})
opt.SetSkip((req.PageNum - 1) * req.PageSize)
opt.SetLimit(req.PageSize)
resp := &proto.ChannelOwnerChangeInfoSearchResp{}
if req.ID != nil {
filter[channelmod.FN.ChannelOwnerChange.ID] = req.ID
}
if req.Channel != nil {
filter[channelmod.FN.ChannelOwnerChange.Channel] = *req.Channel
}
if req.OldUser != nil {
filter[channelmod.FN.ChannelOwnerChange.OldUser] = *req.OldUser
}
if req.NewUser != nil {
filter[channelmod.FN.ChannelOwnerChange.NewUser] = *req.NewUser
}
total, serr := channelmod.CountChannelOwnerChanges(ctx, filter)
if serr != nil {
return nil, serr
}
if total == 0 {
return resp, nil
}
ownerChangeList, err := channelmod.FindManyChannelOwnerChanges(ctx, filter, opt)
if serr != nil {
return nil, err
}
resp.List = ownerChangeList
resp.Total = total
return resp, nil
}
// SearchUserInfo 查询用户信息
func SearchUserInfo(ctx context.Context, req *proto.UserInfoSearch) (
*proto.UserInfoSearchResp, error) {
resp := &proto.UserInfoSearchResp{}
filter := bson.M{}
if req.UserId != nil {
filter["userId"] = *req.UserId
}
if req.Channel != nil {
filter["districtCode"] = *req.Channel
}
if req.AppId != nil {
filter["appId"] = *req.AppId
}
if req.IP != nil {
filter["ip"] = *req.IP
}
if req.Start != nil && req.End != nil {
filter["createdAt"] = bson.M{"$gt": *req.Start, "$lt": *req.End}
}
total, err := registermod.CountRegister(ctx, filter)
if err != nil {
log.Error("SearchUserInfo CountRegister", log.Any("err", err))
return nil, err
}
opt := &options.FindOptions{}
opt.SetSort(bson.M{"createdAt": -1})
opt.SetSkip((req.PageNum - 1) * req.PageSize)
opt.SetLimit(req.PageSize)
userList, err := registermod.FindManyRegister(ctx, filter, opt)
if err != nil {
log.Error("SearchUserInfo FindManyRegister", log.Any("err", err))
return nil, err
}
resp.Total = total
resp.List = userList
return resp, nil
}
+30
View File
@@ -0,0 +1,30 @@
package channelSer
import "math/rand"
var (
//所有的字符
ALL_CHARS = []string{
"1", "2", "3", "4", "5",
"6", "7", "8", "9", "A",
"B", "C", "D", "E", "F",
"G", "H", "J", "K",
"L", "M", "N", "O", "P",
"Q", "R", "S", "T", "U",
"V", "W", "X", "Y", "Z"}
aLen = len(ALL_CHARS)
)
const (
//默认长度
DEFAULT_LEN = 6
)
// 用户推广码
func InviteShartPasswd() (code string) {
for i := 0; i < DEFAULT_LEN; i++ {
index := rand.Intn(aLen)
code += ALL_CHARS[index]
}
return
}
+184
View File
@@ -0,0 +1,184 @@
package channelSer
import (
"context"
"errors"
"stat/api/proto"
"stat/common/log"
"stat/models/channelmod"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options"
)
// SearchChannelDeductionRule 查询渠道扣量规则信息
func SearchChannelDeductionRule(ctx context.Context, req *proto.ChannelDeductionRuleSearch) (*proto.ChannelDeductionRuleSearchResp, error) {
resp := &proto.ChannelDeductionRuleSearchResp{}
filter := bson.M{}
opt := &options.FindOptions{}
opt.SetSort(bson.M{channelmod.FN.ChannelDeductionRule.BeginTime: -1})
opt.SetSkip((req.PageNum - 1) * req.PageSize)
opt.SetLimit(req.PageSize)
if req.Channel != nil && *req.Channel != "" {
filter[channelmod.FN.ChannelDeductionRule.Channel] = bson.M{"$regex": *req.Channel}
}
if req.AppId != nil {
filter[channelmod.FN.ChannelDeductionRule.AppId] = *req.AppId
}
if req.Channel != nil && *req.Channel != "" {
filter[channelmod.FN.ChannelDeductionRule.Channel] = *req.Channel
}
total, err := channelmod.CountChannelDeductionRules(ctx, filter)
if err != nil {
return nil, err
}
if total == 0 {
return resp, nil
}
ChannelDeductionRuleList, err := channelmod.FindManyChannelDeductionRule(ctx, filter, opt)
if err != nil {
return nil, err
}
for _, rule := range ChannelDeductionRuleList {
if rule.DivideRate == 0 {
rule.DivideRate = 100
}
}
resp.Total = total
resp.List = ChannelDeductionRuleList
return resp, nil
}
// AddChannelDeductionRule 添加一个媒体视频
func AddChannelDeductionRule(ctx context.Context, req *proto.ChannelDeductionRuleAdd) (*channelmod.ChannelDeductionRule, error) {
checkFilter := bson.M{channelmod.FN.ChannelDeductionRule.Channel: req.Channel, channelmod.FN.ChannelDeductionRule.AppId: req.AppId}
ChannelDeductionRule, err := channelmod.FindOneChannelDeductionRule(ctx, checkFilter)
if err != nil {
return nil, err
}
if ChannelDeductionRule.Channel == req.Channel {
return ChannelDeductionRule, errors.New("渠道扣量规则已经存在")
}
channelInfo, err := channelmod.FindOneChannelInfoEx(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: req.Channel})
if err != nil {
return nil, err
}
var one float64
if req.LessIncomeRate == nil {
one = 0.0
} else {
one = *req.LessIncomeRate
}
now := time.Now()
rule := channelmod.ChannelDeductionRule{
AppId: req.AppId,
AppType: req.AppType,
PromoteMode: req.PromoteMode,
Channel: req.Channel,
Settlement: req.Settlement,
First: req.First,
Second: req.Second,
Third: req.Third,
Fourth: req.Fourth,
Fifth: req.Fifth,
CPAPrice: req.CPAPrice,
CPSRate: req.CPSRate,
BeginTime: req.BeginTime,
CPSBegin: req.CPSBegin,
CPSDeductionRate: req.CPSDeductionRate,
DivideRate: req.DivideRate,
LandingPage: req.LandingPage,
ProxyDeduction: req.ProxyDeduction,
AutoDeduction: req.AutoDeduction,
LessIncomeRate: one,
CreatedAt: now,
UpdatedAt: now,
}
err = channelmod.InsertOneChannelDeductionRule(ctx, &rule)
if err != nil {
return nil, err
}
channelInfo.AppIds = append(channelInfo.AppIds, req.AppId)
setdoc := bson.M{"$set": bson.M{channelmod.FN.ChannelInfo.AppIds: channelInfo.AppIds}}
err = channelmod.UpdateOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: req.Channel}, setdoc)
if err != nil {
return nil, err
}
return channelmod.FindOneChannelDeductionRuleEx(ctx, checkFilter)
}
// DelChannelDeductionRule 删除指定渠道扣量规则信息
func DelChannelDeductionRule(ctx context.Context, channelId string) error {
id, err := primitive.ObjectIDFromHex(channelId)
if err != nil {
return errors.New("ID 格式错误")
}
ruleFilter := bson.M{channelmod.FN.ChannelDeductionRule.ID: id}
channelRuleInfo, err := channelmod.FindOneChannelDeductionRuleEx(ctx, ruleFilter)
if err != nil {
return err
}
channelInfo, err := channelmod.FindOneChannelInfoEx(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: channelRuleInfo.Channel})
if err != nil {
return err
}
count, err := channelmod.CountChannelInfos(ctx, bson.M{channelmod.FN.ChannelInfo.ParentAgent: channelInfo.Channel})
if err != nil {
log.Error("DelChannelDeductionRule CountChannelInfos", log.Any("channelId", channelId), log.E(err))
return err
}
if count > 0 {
return errors.New("下级代理不为空,请先删除下级代理, 再删除应用规则")
}
_, err = channelmod.DelOneChannelDeductionRule(ctx, ruleFilter)
if err != nil {
return err
}
appids := make([]int32, 0)
for _, appid := range channelInfo.AppIds {
if appid != channelRuleInfo.AppId {
appids = append(appids, appid)
}
}
setdoc := bson.M{"$set": bson.M{channelmod.FN.ChannelInfo.AppIds: appids}}
err = channelmod.UpdateOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: channelRuleInfo.Channel}, setdoc)
if err != nil {
return err
}
return nil
}
// UpdateChannelDeductionRule 更新指定渠道扣量规则
func UpdateChannelDeductionRule(ctx context.Context, channelId string, info proto.ChannelDeductionRuleUpdate) error {
id, err := primitive.ObjectIDFromHex(channelId)
if err != nil {
return errors.New("ID 格式错误")
}
filter := bson.M{channelmod.FN.ChannelDeductionRule.ID: id}
//更新数据库
setDoc := bson.M{"$set": info}
serr := channelmod.UpdateOneChannelDeductionRule(ctx, filter, setDoc)
if serr != nil {
return serr
}
return nil
}
File diff suppressed because it is too large Load Diff
+150
View File
@@ -0,0 +1,150 @@
package channelSer
import (
"context"
"fmt"
"stat/api/proto"
"stat/common/utils"
"stat/middleware/define"
"stat/models/adminMod"
channelmod "stat/models/channelmod"
"stat/models/channelsettlementrecord"
"time"
"go.mongodb.org/mongo-driver/bson"
)
var (
SystemStartTime = time.Date(2020, time.January, 1, 0, 0, 0, 0, time.UTC)
)
func SettlementInfoToApplyRecord(src *channelsettlementrecord.ChannelSettlementRecord) *proto.ApplyFormRecord {
ret := &proto.ApplyFormRecord{
ID: src.ID,
Channel: src.Channel,
AppId: src.AppId,
BeginTime: src.BeginTime,
EndTime: src.EndTime,
TotalMoney: src.TotalMoney,
SettleMoney: src.SettleMoney,
Settlement: src.Settlement,
Wallet: src.Wallet,
PayMoney: src.PayMoney,
Usdt: src.Usdt,
Status: src.Status,
Remark: "",
Pictures: nil,
UpdatedAt: src.UpdatedAt,
CreatedAt: src.CreatedAt,
}
remark := ""
if len(src.OperateHistory) > 0 {
remark = src.OperateHistory[0].Remark
if len(src.OperateHistory) > 1 {
if remark == "" {
remark = src.OperateHistory[len(src.OperateHistory)-1].Remark
} else {
s := src.OperateHistory[len(src.OperateHistory)-1].Remark
if s != "" {
remark += " / " + s
}
}
}
ret.Pictures = src.OperateHistory[len(src.OperateHistory)-1].Pictures
}
ret.Remark = remark
return ret
}
func SettlementInfoListToApplyForm(lst channelsettlementrecord.ChannelSettlementRecordList) proto.ApplyFormRecordList {
res := make(proto.ApplyFormRecordList, 0)
for _, item := range lst {
a := SettlementInfoToApplyRecord(item)
res = append(res, a)
}
return res
}
func FenToYuanDisplay(fen int64) string {
return fmt.Sprintf("%.2f", float64(fen)/float64(100))
}
func IndentationDisplay(v int64) string {
return fmt.Sprintf("%.2f", float64(v)/float64(10000))
}
func CheckAndFixTime(startTime, endTime *time.Time) (*time.Time, *time.Time, error) {
var start, end *time.Time
// 开始时间和结束时间
if endTime == nil {
e := utils.BeginOfYesterday()
end = &e
} else {
end = endTime
}
if startTime == nil {
start = &SystemStartTime
} else {
start = startTime
}
//
if end.After(utils.BeginOfYesterday()) {
e := utils.BeginOfYesterday()
end = &e
}
if end.Before(*start) {
return nil, nil, fmt.Errorf("开始和结束的时间区间填写不正确")
}
return start, end, nil
}
func GetUpdateSettlementOperateItem(old channelsettlementrecord.ChannelSettlementRecord, update proto.SettlementInfoUpdate2,
accType define.ActType, account string, accountName string, images []string) channelsettlementrecord.SettlementOperateItem {
res := channelsettlementrecord.SettlementOperateItem{}
res.OperateTime = time.Now()
if update.Remark != nil {
res.Remark = *update.Remark
}
res.OperatorAccountType = accType
res.OperatorAccount = account
res.OperatorAccountName = accountName
res.BeforeStatus = old.Status
if update.Status != nil && *update.Status != old.Status {
res.AfterStatus = *update.Status
res.Content += fmt.Sprintf("状态改变:(%s => %s)\n", old.Status.String(), update.Status.String())
} else {
res.AfterStatus = old.Status
}
if update.Usdt != nil && *update.Usdt != old.Usdt {
res.Content += fmt.Sprintf("修改了打款金额(USDT):(%s => %s)\n", FenToYuanDisplay(old.Usdt), FenToYuanDisplay(*update.Usdt))
}
if update.PayMoney != nil && *update.PayMoney != old.PayMoney {
res.Content += fmt.Sprintf("修改了打款金额(CNY): (%s => %s)\n", FenToYuanDisplay(old.PayMoney), FenToYuanDisplay(*update.PayMoney))
}
if update.SettleMoney != nil && *update.SettleMoney != old.SettleMoney {
res.Content += fmt.Sprintf("修改了申请结算金额:(%s => %s)\n", FenToYuanDisplay(old.SettleMoney), FenToYuanDisplay(*update.SettleMoney))
}
for _, img := range images {
res.Pictures = append(res.Pictures, img)
}
return res
}
func GetAccountName(ctx context.Context, accType define.ActType, account string) (string, error) {
if accType == define.Admin {
if acc, err := adminMod.FindOneByAccount(ctx, account); err != nil {
return "", err
} else {
return acc.Name, nil
}
} else if accType == define.Channel {
if acc, err := channelmod.FindOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: account}); err != nil {
return "", err
} else {
return acc.Channel, nil
}
} else {
return "", fmt.Errorf("error account type: %s", accType)
}
}
+321
View File
@@ -0,0 +1,321 @@
package channelSer
import (
"context"
"errors"
"runtime"
"stat/api/proto"
"stat/common/utils"
"stat/models/channelmod"
"time"
"github.com/jinzhu/now"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo/options"
)
// SearchChannelStat 查询渠道扣量规则信息
func SearchChannelStat(ctx context.Context, req *proto.ChannelStatSearch) (*proto.ChannelStatSearchResp, error) {
resp := &proto.ChannelStatSearchResp{
List: make(channelmod.ChannelStatList, 0),
}
filter := bson.M{}
opt := &options.FindOptions{}
opt.SetSkip((req.PageNum - 1) * req.PageSize)
opt.SetLimit(req.PageSize)
if req.Channel != nil && *req.Channel != "" {
if req.WithChild != nil && *req.WithChild {
filter = bson.M{
"$or": bson.A{
bson.M{channelmod.FN.ChannelStat.Channel: *req.Channel},
bson.M{channelmod.FN.ChannelStat.ParentChannel: *req.Channel},
},
}
} else {
filter[channelmod.FN.ChannelStat.Channel] = *req.Channel
}
} else if req.DayType != nil {
timeNow := time.Now()
now.WeekStartDay = time.Monday
Now := now.With(timeNow.In(time.Local))
todayBegin := utils.BeginWithTime(timeNow)
weekBegin := Now.BeginningOfWeek()
monthBegin := Now.BeginningOfMonth()
var timeBegin time.Time
if *req.DayType == 1 { // 今天内
timeBegin = todayBegin
} else if *req.DayType == 2 { // 昨天和今天
timeBegin = todayBegin.AddDate(0, 0, -1)
} else if *req.DayType == 3 { // 三天内
timeBegin = todayBegin.AddDate(0, 0, -2)
} else if *req.DayType == 4 { // 七天内
timeBegin = todayBegin.AddDate(0, 0, -6)
} else if *req.DayType == 5 { // 本周内
timeBegin = weekBegin
} else if *req.DayType == 6 { // 两周内
timeBegin = weekBegin.AddDate(0, 0, -7)
} else if *req.DayType == 7 { // 本月内
timeBegin = monthBegin
} else if *req.DayType == 8 { // 两月内
timeBegin = monthBegin.AddDate(0, -1, 0)
}
channelList, err := channelmod.FindManyChannelInfo(ctx, bson.M{
channelmod.FN.ChannelInfo.CreatedAt: bson.M{
"$gte": timeBegin,
"$lte": timeNow,
},
})
if err != nil {
return resp, err
}
channelIds := make([]string, 0)
for _, channelInfo := range channelList {
channelIds = append(channelIds, channelInfo.Channel)
}
if len(channelIds) > 0 {
if req.WithChild != nil && *req.WithChild {
filter = bson.M{
"$or": bson.A{
bson.M{channelmod.FN.ChannelStat.Channel: bson.M{"$in": channelIds}},
bson.M{channelmod.FN.ChannelStat.ParentChannel: bson.M{"$in": channelIds}},
},
}
} else {
filter[channelmod.FN.ChannelStat.Channel] = bson.M{"$in": channelIds}
}
} else {
return resp, nil
}
}
//
//排序
if req.RankType != nil {
if *req.RankType == 1 {
opt.SetSort(bson.D{{Key: channelmod.FN.ChannelStat.SumDate, Value: -1}, {Key: channelmod.FN.ChannelStat.DirectAmount, Value: -1}})
} else if *req.RankType == 2 {
opt.SetSort(bson.D{{Key: channelmod.FN.ChannelStat.SumDate, Value: -1}, {Key: channelmod.FN.ChannelStat.NewDirectCount, Value: -1}})
} else if *req.RankType == 3 {
opt.SetSort(bson.D{{Key: channelmod.FN.ChannelStat.SumDate, Value: -1}, {Key: channelmod.FN.ChannelStat.NewRechargeAmount, Value: -1}})
} else if *req.RankType == 4 {
opt.SetSort(bson.D{{Key: channelmod.FN.ChannelStat.SumDate, Value: -1}, {Key: channelmod.FN.ChannelStat.IncomeRate, Value: -1}})
}
} else {
opt.SetSort(bson.D{{Key: channelmod.FN.ChannelStat.SumDate, Value: -1}, {Key: channelmod.FN.ChannelStat.NewDirectCount, Value: -1}})
}
if req.UserName != nil && *req.UserName != "" {
filter[channelmod.FN.ChannelStat.UserName] = bson.M{"$regex": *req.UserName}
}
if req.AppId != nil {
filter[channelmod.FN.ChannelStat.AppId] = bson.M{"$in": *req.AppId}
}
if req.Start != nil && req.End != nil {
filter[channelmod.FN.ChannelStat.SumDate] = bson.M{"$gte": *req.Start, "$lte": *req.End}
}
if req.WithChild != nil && !*req.WithChild {
filter[channelmod.FN.ChannelStat.Type] = channelmod.ChannelTypeParent
}
if req.Settlement != nil {
filter[channelmod.FN.ChannelStat.Settlement] = *req.Settlement
}
if req.Detail != nil && *req.Detail {
if req.SumDate == nil {
return resp, errors.New("param error")
}
filter = bson.M{
"$or": bson.A{
bson.M{channelmod.FN.ChannelStat.Channel: *req.Channel},
bson.M{channelmod.FN.ChannelStat.ParentChannel: *req.Channel},
},
channelmod.FN.ChannelStat.SumDate: *req.SumDate,
}
}
ChannelStatList, err := channelmod.FindManyChannelStat(ctx, filter, opt)
if err != nil {
return resp, err
}
for _, v := range ChannelStatList {
v.CorrectValidData()
v.CalcIncomeRate()
}
resp.List = ChannelStatList
// 汇总
canSum := utils.M(filter).HasKey(channelmod.FN.ChannelStat.AppId) && utils.M(filter).HasKey(channelmod.FN.ChannelStat.SumDate)
if canSum {
var total int64
err = channelmod.FindManyChannelStatShard(ctx, filter, 10000, func(item *channelmod.ChannelStat) {
total++
channelmod.ChannelStatSummation(&resp.TotalInfo, item)
if req.WithChild != nil && *req.WithChild {
for _, v := range ChannelStatList {
if item.ParentChannel == v.Channel && v.SumDate.Equal(item.SumDate) {
channelmod.ChannelStatSummation(v, item)
}
}
}
})
if err != nil {
return resp, err
}
if total == 0 {
return resp, nil
}
if total > 10000 {
runtime.GC()
}
resp.Total = total
var ruleInfo *channelmod.ChannelDeductionRule
if req.Channel != nil && *req.Channel != "" {
ruleFilter := bson.M{
channelmod.FN.ChannelDeductionRule.Channel: req.Channel,
// channelmod.FN.ChannelDeductionRule.AppId: req.AppId,
}
ruleInfo, _ = channelmod.FindOneChannelDeductionRule(ctx, ruleFilter)
}
if ruleInfo != nil {
resp.TotalInfo.Channel = ruleInfo.Channel
resp.TotalInfo.Settlement = ruleInfo.Settlement
resp.TotalInfo.AppId = ruleInfo.AppId
resp.TotalInfo.CPAPrice = ruleInfo.CPAPrice
resp.TotalInfo.CPSRate = ruleInfo.CPSRate
resp.TotalInfo.AppType = ruleInfo.AppType
resp.TotalInfo.PromoteMode = ruleInfo.PromoteMode
resp.TotalInfo.CalcIncomeRate()
resp.Income, resp.Desc = channelmod.CalculateChannelIncome(&resp.TotalInfo)
}
} else {
resp.Total = 1000000
}
return resp, nil
}
// SearchChannelSettlement 查询渠道结算信息
func SearchChannelSettlement(ctx context.Context, req *proto.ChannelSettlementSearch) (
*proto.ChannelSettlementSearchResp, error) {
resp := &proto.ChannelSettlementSearchResp{}
filter := bson.M{}
opt := &options.FindOptions{}
opt.SetSort(bson.M{channelmod.FN.ChannelSettlement.CreatedAt: -1})
opt.SetSkip((req.PageNum - 1) * req.PageSize)
opt.SetLimit(req.PageSize)
if req.Channel != nil && *req.Channel != "" {
filter[channelmod.FN.ChannelSettlement.Channel] = *req.Channel
}
if req.AppId != nil {
filter[channelmod.FN.ChannelSettlement.AppId] = *req.AppId
}
if req.Start != nil && req.End != nil {
filter[channelmod.FN.ChannelSettlement.SumDate] = bson.M{"$gt": *req.Start, "$lt": *req.End}
}
if req.WithChild != nil && *req.WithChild {
filter[channelmod.FN.ChannelSettlement.Type] = channelmod.ChannelTypeParent
}
total, serr := channelmod.CountChannelSettlements(ctx, filter)
if serr != nil {
return nil, serr
}
if total == 0 {
return resp, nil
}
ChannelSettlementList, err := channelmod.FindManyChannelSettlement(ctx, filter, opt)
if serr != nil {
return nil, err
}
if req.WithChild != nil && *req.WithChild {
channels := make([]string, 0)
for _, v := range ChannelSettlementList {
channels = append(channels, v.Channel)
}
childTypes := channelmod.GetChildChannelTypes()
filter[channelmod.FN.ChannelSettlement.Type] = bson.M{"$in": childTypes}
filter[channelmod.FN.ChannelSettlement.ParentChannel] = bson.M{"$in": channels}
channelsettlementList, err := channelmod.FindManyChannelStat(ctx, filter)
if err != nil {
return nil, err
}
for _, channnelSettlementInfo := range channelsettlementList {
for _, v := range ChannelSettlementList {
if channnelSettlementInfo.ParentChannel == v.Channel {
channnelSettlementInfo.AccumulateTo(v)
}
}
}
}
resp.Total = total
resp.List = ChannelSettlementList
return resp, nil
}
// SearchChannelStatCompared 渠道同时段对比
func SearchChannelStatCompared(ctx context.Context, req *proto.SearchChannelStatComparedReq) (*proto.SearchChannelStatComparedResp, error) {
resp := &proto.SearchChannelStatComparedResp{}
filter := bson.M{}
opt := &options.FindOptions{}
opt.SetSkip((req.PageNum - 1) * req.PageSize)
opt.SetLimit(req.PageSize)
opt.SetSort(
bson.D{
{Key: channelmod.FN.ChannelStatYestoday.SumDate, Value: -1},
{Key: channelmod.FN.ChannelStatYestoday.NewCount, Value: -1},
},
)
if req.Channel != nil && *req.Channel != "" {
if req.WithChild != nil && *req.WithChild {
filter = bson.M{
"$or": bson.A{
bson.M{channelmod.FN.ChannelStatYestoday.Channel: *req.Channel},
bson.M{channelmod.FN.ChannelStatYestoday.ParentChannel: *req.Channel},
},
}
} else {
filter[channelmod.FN.ChannelStatYestoday.Channel] = *req.Channel
}
}
if req.AppId != nil {
filter[channelmod.FN.ChannelStatYestoday.AppId] = *req.AppId
}
if req.Start != nil && req.End != nil {
filter[channelmod.FN.ChannelStatYestoday.SumDate] = bson.M{"$gte": *req.Start, "$lte": *req.End}
}
if req.Settlement != nil {
filter[channelmod.FN.ChannelStatYestoday.Settlement] = *req.Settlement
}
total, err := channelmod.CountChannelStatYestoday(ctx, filter)
if err != nil {
return nil, err
}
channelStatList, err := channelmod.FindManyChannelStatYestoday(ctx, filter, opt)
if err != nil {
return nil, err
}
resp.Total = total
resp.List = channelStatList
return resp, nil
}