parent
d3047448bc
commit
203a4e9d49
63 changed files with 4730 additions and 2 deletions
@ -0,0 +1,96 @@ |
|||||||
|
package call |
||||||
|
|
||||||
|
import ( |
||||||
|
"server/common" |
||||||
|
"server/db" |
||||||
|
|
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
) |
||||||
|
|
||||||
|
// LoadConfigCustomerRobot 客服机器人配置
|
||||||
|
func LoadConfigCustomerRobot() (err error) { |
||||||
|
var one []*common.ConfigCustomerRobot |
||||||
|
if _, err = db.Mysql().QueryAll("", "", &common.ConfigCustomerRobot{}, &one); err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
return err |
||||||
|
} |
||||||
|
configCustomerRobot = one |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// GetCustomerRobot 获取机器人配置
|
||||||
|
func GetCustomerRobot(parentId int) []*common.ConfigCustomerRobot { |
||||||
|
if configCustomerRobot == nil { |
||||||
|
if LoadConfigCustomerRobot() != nil { |
||||||
|
return nil |
||||||
|
} |
||||||
|
} |
||||||
|
var res []*common.ConfigCustomerRobot |
||||||
|
for i := 0; i < len(configCustomerRobot); i++ { |
||||||
|
if configCustomerRobot[i].ParentId == parentId { |
||||||
|
res = append(res, configCustomerRobot[i]) |
||||||
|
} |
||||||
|
} |
||||||
|
return res |
||||||
|
} |
||||||
|
|
||||||
|
// GetCustomerRobotById 获取机器人配置
|
||||||
|
func GetCustomerRobotById(parentId int) *common.ConfigCustomerRobot { |
||||||
|
if configCustomerRobot == nil { |
||||||
|
if LoadConfigCustomerRobot() != nil { |
||||||
|
return nil |
||||||
|
} |
||||||
|
} |
||||||
|
for i := 0; i < len(configCustomerRobot); i++ { |
||||||
|
if configCustomerRobot[i].ID == parentId { |
||||||
|
return configCustomerRobot[i] |
||||||
|
} |
||||||
|
} |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// GetCustomerRobotMsg 机器人人工服务
|
||||||
|
func GetCustomerRobotMsg(Id int) *common.ConfigCustomerRobot { |
||||||
|
if configCustomerRobot == nil { |
||||||
|
if LoadConfigCustomerRobot() != nil { |
||||||
|
return nil |
||||||
|
} |
||||||
|
} |
||||||
|
for i := 0; i < len(configCustomerRobot); i++ { |
||||||
|
if configCustomerRobot[i].ParentId == Id { |
||||||
|
return configCustomerRobot[i] |
||||||
|
} |
||||||
|
} |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// LoadConfigCustomerLabel 客服机器人配置
|
||||||
|
func LoadConfigCustomerLabel() (err error) { |
||||||
|
var one []*common.CustomerOrderLabel |
||||||
|
if _, err = db.Mysql().QueryAll("", "", &common.CustomerOrderLabel{}, &one); err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
return err |
||||||
|
} |
||||||
|
customerOrderLabel = one |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// LoadConfigCustomer 客服字段配置
|
||||||
|
func LoadConfigCustomer() (err error) { |
||||||
|
one := new(common.ConfigCustomer) |
||||||
|
if err = db.Mysql().Get(one); err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
configCustomer = one |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// GetConfigCustomer 获取客服字段配置
|
||||||
|
func GetConfigCustomer() *common.ConfigCustomer { |
||||||
|
if configCustomer == nil { |
||||||
|
if LoadConfigCustomer() != nil { |
||||||
|
return nil |
||||||
|
} |
||||||
|
} |
||||||
|
return configCustomer |
||||||
|
} |
||||||
@ -0,0 +1,92 @@ |
|||||||
|
package common |
||||||
|
|
||||||
|
// 客服工单状态
|
||||||
|
const ( |
||||||
|
CustomerOrderCreate = iota + 1 // 创建工单
|
||||||
|
CustomerOrderAllocate // 工单已分配
|
||||||
|
CustomerOrderProcessing // 工单处理中
|
||||||
|
CustomerOrderDelayed // 工单延期
|
||||||
|
CustomerOrderComplete // 工单已完成 工单到此结束
|
||||||
|
) |
||||||
|
|
||||||
|
// 客服系统机器人配置
|
||||||
|
type ConfigCustomerRobot struct { |
||||||
|
ID int `gorm:"primarykey"` |
||||||
|
ParentId int `gorm:"column:parent_id;default:0;type:int(11);comment:父类id 0表示一级标题" json:"ParentId" web:"ParentId"` |
||||||
|
Label string `gorm:"column:label;type:varchar(128);comment:工单标签描述" json:"Label" web:"Label"` |
||||||
|
Title string `gorm:"column:title;type:varchar(128);comment:标题" json:"Title" web:"Title"` |
||||||
|
Content string `gorm:"column:content;type:varchar(1280);comment:内容" json:"Content" web:"Content"` |
||||||
|
Image string `gorm:"column:image;type:varchar(1280);comment:图片用英文逗号分隔地址" json:"Image" web:"Image"` |
||||||
|
IsEnd bool `gorm:"column:is_end;not null;type:bool;comment:是否截止" json:"IsEnd" web:"IsEnd"` |
||||||
|
} |
||||||
|
|
||||||
|
func (c *ConfigCustomerRobot) TableName() string { |
||||||
|
return "config_customer_robot" |
||||||
|
} |
||||||
|
|
||||||
|
// 客服系统聊天配置
|
||||||
|
type CustomerChatData struct { |
||||||
|
ID int `gorm:"primarykey"` |
||||||
|
Title int `gorm:"column:title;not null;type:int(11);comment:用玩家uid做聊天的title" json:"Title" web:"Title"` |
||||||
|
Uid int `gorm:"column:uid;not null;type:int(11);comment:玩家uid或者客服人员uid" json:"Uid" web:"Uid"` |
||||||
|
Time int64 `gorm:"column:time;type:int(11);default:0;comment:当前时间" json:"Time" web:"Time"` |
||||||
|
Type int `gorm:"column:type;type:int(11);default:0;comment:消息类型 1表示文字消息,2表示图片消息" json:"Type" web:"Type"` |
||||||
|
Content string `gorm:"column:content;type:varchar(1280);comment:消息内容 文字消息直接显示 图片消息用英文逗号分隔地址" json:"Content" web:"Content"` |
||||||
|
IsRead bool `gorm:"column:is_read;type:bool;comment:消息是否已读" json:"IsRead" web:"IsRead"` |
||||||
|
} |
||||||
|
|
||||||
|
func (c *CustomerChatData) TableName() string { |
||||||
|
return "customer_chat_data" |
||||||
|
} |
||||||
|
|
||||||
|
// 人工服务工单
|
||||||
|
type CustomerOrder struct { |
||||||
|
ID int `gorm:"primarykey"` |
||||||
|
Uid int `gorm:"column:uid;not null;type:int(11);comment:玩家uid" json:"Uid" web:"Uid"` |
||||||
|
Status int `gorm:"column:status;not null;type:int(11);comment:工单状态 1创建工单(未分配工单),2已分配工单,3工单处理中,4延期,5完成" json:"Status" web:"Status"` |
||||||
|
Start int64 `gorm:"column:start;type:int(11);default:0;comment:工单开始时间" json:"Start" web:"Start"` |
||||||
|
End int64 `gorm:"column:end;type:int(11);default:0;comment:工单结束时间" json:"End" web:"End"` |
||||||
|
CustomerUid int `gorm:"column:customer_uid;type:int(11);default:0;comment:客服人员uid,0表示未分配工单, -1表示机器人处理的订单" json:"CustomerUid" web:"CustomerUid"` |
||||||
|
Vip int `gorm:"column:vip;type:int(11);default:0;comment:玩家vip等级" json:"Vip" web:"Vip"` |
||||||
|
Label1 int `gorm:"column:Label1;type:int(11);default:0;comment:处理人员标记该工单类型" json:"Label1" web:"Label1"` |
||||||
|
Label2 int `gorm:"column:label2;type:int(11);default:0;comment:处理人员标记该工单类型" json:"Label2" web:"Label2"` |
||||||
|
Label3 int `gorm:"column:label3;type:int(11);default:0;comment:处理人员标记该工单类型" json:"Label3" web:"Label3"` |
||||||
|
Label4 int `gorm:"column:label4;type:int(11);default:0;comment:处理人员标记该工单类型" json:"Label4" web:"Label4"` |
||||||
|
Label5 int `gorm:"column:label5;type:int(11);default:0;comment:处理人员标记该工单类型" json:"Label5" web:"Label5"` |
||||||
|
UnRead int `gorm:"column:un_read;type:int(11);default:0;comment:未读消息条数" json:"UnRead" web:"UnRead"` |
||||||
|
} |
||||||
|
|
||||||
|
func (c *CustomerOrder) TableName() string { |
||||||
|
return "customer_order" |
||||||
|
} |
||||||
|
|
||||||
|
// 客服标签分组
|
||||||
|
type CustomerOrderLabel struct { |
||||||
|
ID int `gorm:"primarykey"` |
||||||
|
Label string `gorm:"column:label;type:varchar(20);comment:工单标签描述" json:"Label" web:"Label"` |
||||||
|
} |
||||||
|
|
||||||
|
func (c *CustomerOrderLabel) TableName() string { |
||||||
|
return "customer_order_label" |
||||||
|
} |
||||||
|
|
||||||
|
// 客服配置
|
||||||
|
type ConfigCustomer struct { |
||||||
|
ID int `gorm:"primarykey"` |
||||||
|
Vip int `gorm:"column:vip;type:int(11);default:3;comment:默认走人工服务vip等级" json:"Vip" web:"Vip"` |
||||||
|
} |
||||||
|
|
||||||
|
func (c *ConfigCustomer) TableName() string { |
||||||
|
return "config_customer" |
||||||
|
} |
||||||
|
|
||||||
|
// 客服黑名单
|
||||||
|
type CustomerBlackUser struct { |
||||||
|
ID int `gorm:"primarykey"` |
||||||
|
Time int64 `gorm:"column:time;type:int(20);default:0;comment:当前时间" json:"Time" web:"time"` |
||||||
|
Uid int `gorm:"column:uid;not null;type:int(11);uniqueIndex:uid;comment:玩家uid" json:"Uid" web:"uid"` |
||||||
|
} |
||||||
|
|
||||||
|
func (c *CustomerBlackUser) TableName() string { |
||||||
|
return "customer_black_user" |
||||||
|
} |
||||||
@ -0,0 +1,114 @@ |
|||||||
|
package app |
||||||
|
|
||||||
|
import ( |
||||||
|
"encoding/json" |
||||||
|
"fmt" |
||||||
|
"net/http" |
||||||
|
"reflect" |
||||||
|
"server/modules/customer/bdb" |
||||||
|
"server/modules/customer/values" |
||||||
|
"time" |
||||||
|
|
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
"gorm.io/gorm" |
||||||
|
) |
||||||
|
|
||||||
|
type Gin struct { |
||||||
|
C *gin.Context |
||||||
|
R |
||||||
|
User *values.User |
||||||
|
} |
||||||
|
|
||||||
|
type R struct { |
||||||
|
Data interface{} `json:"data"` |
||||||
|
Msg string `json:"msg"` |
||||||
|
Code int `json:"code"` |
||||||
|
} |
||||||
|
|
||||||
|
func NewApp(c *gin.Context) *Gin { |
||||||
|
g := &Gin{C: c, R: R{Code: values.CodeOK, Msg: "ok"}} |
||||||
|
user, ex := c.Get("user") |
||||||
|
if ex { |
||||||
|
g.User = user.(*values.User) |
||||||
|
if len(g.User.Channels) > 0 { |
||||||
|
json.Unmarshal([]byte(g.User.Channels), &g.User.SChannels) |
||||||
|
} |
||||||
|
} |
||||||
|
return g |
||||||
|
} |
||||||
|
|
||||||
|
// Response setting gin.JSON
|
||||||
|
func (g *Gin) Response() { |
||||||
|
if g.Code == values.CodeRetry { |
||||||
|
g.Msg = "内部错误" |
||||||
|
} else if g.Code == values.CodePower { |
||||||
|
g.Msg = "您无权操作此项" |
||||||
|
} |
||||||
|
g.C.JSON(http.StatusOK, g.R) |
||||||
|
} |
||||||
|
|
||||||
|
func (g *Gin) RecordEdit(t int, detail string) { |
||||||
|
u, _ := g.C.Get("user") |
||||||
|
user := u.(*values.User) |
||||||
|
one := &values.EditHistory{Model: t, Detail: detail, Time: time.Now().Unix(), Operator: user.Name, UID: int(user.ID)} |
||||||
|
bdb.BackDB.Create(one) |
||||||
|
} |
||||||
|
|
||||||
|
func (g *Gin) S(one interface{}) (pass bool) { |
||||||
|
err := g.C.ShouldBind(one) |
||||||
|
if err != nil { |
||||||
|
g.R.Code = values.CodeParam |
||||||
|
g.R.Msg = err.Error() |
||||||
|
log.Error("bind %v err:%v", reflect.TypeOf(one), err) |
||||||
|
return |
||||||
|
} |
||||||
|
pass = true |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// U 统一json解析方法
|
||||||
|
func (g *Gin) U(src []byte, tar interface{}) (pass bool) { |
||||||
|
err := json.Unmarshal(src, tar) |
||||||
|
if err != nil { |
||||||
|
log.Error("%v err:%v", reflect.TypeOf(tar), err) |
||||||
|
g.R.Code = values.CodeRetry |
||||||
|
g.R.Msg = err.Error() |
||||||
|
return |
||||||
|
} |
||||||
|
pass = true |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// MCommit 提交事务
|
||||||
|
func (g *Gin) MCommit(tx *gorm.DB) { |
||||||
|
if g.Code == values.CodeOK { |
||||||
|
if err := tx.Commit().Error; err != nil { |
||||||
|
tx.Rollback() |
||||||
|
return |
||||||
|
} |
||||||
|
} else { |
||||||
|
tx.Rollback() |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// CheckPower 检查权限是否合法
|
||||||
|
func (g *Gin) CheckPower(power string) bool { |
||||||
|
newMap := map[int][]int{} |
||||||
|
if err := json.Unmarshal([]byte(power), &newMap); err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
g.Code = values.CodeParam |
||||||
|
g.Msg = err.Error() |
||||||
|
return false |
||||||
|
} |
||||||
|
for i := range newMap { |
||||||
|
if !values.IsValidPower(i) { |
||||||
|
log.Error("invalid power:%v", i) |
||||||
|
g.Code = values.CodeParam |
||||||
|
g.Msg = fmt.Sprintf("未知权限参数%v", i) |
||||||
|
return false |
||||||
|
} |
||||||
|
} |
||||||
|
return true |
||||||
|
} |
||||||
@ -0,0 +1,21 @@ |
|||||||
|
package bdb |
||||||
|
|
||||||
|
import ( |
||||||
|
"encoding/json" |
||||||
|
"server/modules/customer/values" |
||||||
|
|
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
) |
||||||
|
|
||||||
|
func GetPowerByRole(role int) map[int][]int { |
||||||
|
one := &values.Role{Role: role} |
||||||
|
BackDB.Get(one) |
||||||
|
ret := map[int][]int{} |
||||||
|
if len(one.Power) > 0 { |
||||||
|
err := json.Unmarshal([]byte(one.Power), &ret) |
||||||
|
if err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
} |
||||||
|
} |
||||||
|
return ret |
||||||
|
} |
||||||
@ -0,0 +1,35 @@ |
|||||||
|
package bdb |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"server/config" |
||||||
|
mdb "server/db/mysql" |
||||||
|
"server/modules/customer/values" |
||||||
|
) |
||||||
|
|
||||||
|
var BackDB *mdb.MysqlClient |
||||||
|
|
||||||
|
func InitMysql() { |
||||||
|
var err error |
||||||
|
fmt.Println(config.GetConfig().Customer.DB) |
||||||
|
BackDB, err = mdb.InitMysqlClient(config.GetConfig().Customer.DB, false) |
||||||
|
if err != nil { |
||||||
|
panic(err) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// MigrateDB 自动数据库迁移
|
||||||
|
func MigrateDB() { |
||||||
|
err := BackDB.C().AutoMigrate(new(values.User)) |
||||||
|
if err != nil { |
||||||
|
panic(err) |
||||||
|
} |
||||||
|
err = BackDB.C().AutoMigrate(new(values.EditHistory)) |
||||||
|
if err != nil { |
||||||
|
panic(err) |
||||||
|
} |
||||||
|
err = BackDB.C().AutoMigrate(new(values.Role)) |
||||||
|
if err != nil { |
||||||
|
panic(err) |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,35 @@ |
|||||||
|
package customer |
||||||
|
|
||||||
|
import ( |
||||||
|
"server/call" |
||||||
|
"server/pb" |
||||||
|
) |
||||||
|
|
||||||
|
func loadConfig() error { |
||||||
|
c := map[int][]func(*pb.ReloadGameConfig) error{} |
||||||
|
// c[common.ReloadTypeExcel] = []func(*pb.ReloadGameConfig) error{ReloadExcel}
|
||||||
|
// c[common.ReloadTypeNewControlConfig] = []func(*pb.ReloadGameConfig) error{func(rgc *pb.ReloadGameConfig) error {
|
||||||
|
// if err := call.LoadNewControlConfig(); err != nil {
|
||||||
|
// log.Error("err:%v", err)
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// return nil
|
||||||
|
// }}
|
||||||
|
// c[common.ReloadTypeSingleControlConfig] = []func(*pb.ReloadGameConfig) error{func(rgc *pb.ReloadGameConfig) error {
|
||||||
|
// if err := call.LoadSingleControlConfig(); err != nil {
|
||||||
|
// log.Error("err:%v", err)
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// return nil
|
||||||
|
// }}
|
||||||
|
call.LoadConfigs(c) |
||||||
|
// game.LoadConfigs(c)
|
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// func ReloadExcel(c *pb.ReloadGameConfig) error {
|
||||||
|
// if err := call.LoadGoodsConfig(); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
@ -0,0 +1,38 @@ |
|||||||
|
// 账号相关的接口实现
|
||||||
|
package handler |
||||||
|
|
||||||
|
import ( |
||||||
|
"server/common" |
||||||
|
"server/db" |
||||||
|
"server/modules/customer/app" |
||||||
|
"server/modules/customer/bdb" |
||||||
|
"server/modules/customer/values" |
||||||
|
"server/util" |
||||||
|
|
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
|
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
) |
||||||
|
|
||||||
|
func Login(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.LoginReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
one := &values.User{Account: req.Account, Password: req.Pass} |
||||||
|
if err := bdb.BackDB.Get(one); err != nil { |
||||||
|
a.Code = values.CodeParam |
||||||
|
a.Msg = "账号不存在" |
||||||
|
return |
||||||
|
} |
||||||
|
token := util.GetSimpleRandomString(6) |
||||||
|
err := db.Redis().SetJsonData(common.GetBackendTokenKey(token), one, values.RedisTokenEx) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
a.Data = values.LoginResp{Role: one.Role, Token: token, Power: one.Power, Id: int(one.ID)} |
||||||
|
} |
||||||
@ -0,0 +1,357 @@ |
|||||||
|
package chat |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
"gorm.io/gorm" |
||||||
|
"server/call" |
||||||
|
"server/common" |
||||||
|
"server/db" |
||||||
|
"server/modules/customer/app" |
||||||
|
"server/modules/customer/values" |
||||||
|
"server/pb" |
||||||
|
"time" |
||||||
|
) |
||||||
|
|
||||||
|
// 获取聊天历史
|
||||||
|
func GetCustomerHistory(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.GetCustomerHistoryReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
var resp values.GetCustomerHistoryResp |
||||||
|
Count, err := db.Mysql().QueryList(req.Page-1, req.Num, fmt.Sprintf("title = %v", req.Title), "time DESC", &common.CustomerChatData{}, &resp.List) |
||||||
|
if err != nil { |
||||||
|
if err != gorm.ErrRecordNotFound { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
resp.Count = Count |
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
// 消息已读
|
||||||
|
func ReadMessage(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := &values.ReadMessageReq{} |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
for i := 0; i < len(req.List); i++ { |
||||||
|
err := db.Mysql().Update(&common.CustomerChatData{ID: req.List[i], Title: req.Title}, map[string]interface{}{"is_read": true}) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if req.OrderId != 0 { |
||||||
|
db.Mysql().Update(&common.CustomerOrder{ID: req.OrderId}, map[string]interface{}{ |
||||||
|
"un_read": 0, |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// 需要通知在线玩家刷新客服消息
|
||||||
|
// session := call.GetUserSession(req.Title)
|
||||||
|
// if session == nil {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// call.SendSS(session, int(pb.ServerCommonCmd_CMD_BS_CustomerMsgResp), nil, "common")
|
||||||
|
} |
||||||
|
|
||||||
|
// 玩家发送消息
|
||||||
|
func SendMessage(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := &values.SendMessageReq{} |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
req.Time = time.Now().Unix() |
||||||
|
err := db.Mysql().Create(&req) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// 需要通知在线玩家刷新客服消息
|
||||||
|
session := call.GetUserSession(req.Title) |
||||||
|
if session == nil { |
||||||
|
return |
||||||
|
} |
||||||
|
call.SendSS(session, int(pb.ServerCommonCmd_CMD_BS_CustomerMsgResp), nil, "common") |
||||||
|
} |
||||||
|
|
||||||
|
// 根据订单状态获取订单列表
|
||||||
|
func GetCustomerOrder(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := &values.GetCustomerOrderReq{} |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
var resp values.GetCustomerOrderResp |
||||||
|
|
||||||
|
var flag bool |
||||||
|
var query string |
||||||
|
|
||||||
|
if req.Label != 0 { |
||||||
|
query += fmt.Sprintf(" (label1 = %v OR label2 = %v OR label3 = %v OR label4 = %v OR label5 = %v) ", req.Label, req.Label, req.Label, req.Label, req.Label) |
||||||
|
flag = true |
||||||
|
} |
||||||
|
|
||||||
|
if req.Uid != 0 { |
||||||
|
if flag { |
||||||
|
query += " AND " |
||||||
|
} |
||||||
|
query += fmt.Sprintf(" uid = %v ", req.Uid) |
||||||
|
flag = true |
||||||
|
} |
||||||
|
if req.CustomerUid != 0 { |
||||||
|
if flag { |
||||||
|
query += " AND " |
||||||
|
} |
||||||
|
query += fmt.Sprintf(" customer_uid = %v ", req.CustomerUid) |
||||||
|
flag = true |
||||||
|
} |
||||||
|
|
||||||
|
if req.Status != 0 { |
||||||
|
if flag { |
||||||
|
query += " AND " |
||||||
|
} |
||||||
|
query = fmt.Sprintf(" status = %v", req.Status) |
||||||
|
flag = true |
||||||
|
} else { |
||||||
|
if req.Status2 != 0 { |
||||||
|
if flag { |
||||||
|
query += " AND " |
||||||
|
} |
||||||
|
query = fmt.Sprintf(" status <= %v", req.Status2) |
||||||
|
flag = true |
||||||
|
} |
||||||
|
} |
||||||
|
if req.Vip != 0 { |
||||||
|
if flag { |
||||||
|
query += " AND " |
||||||
|
} |
||||||
|
query += fmt.Sprintf(" vip >= %v ", req.Vip) |
||||||
|
flag = true |
||||||
|
} |
||||||
|
|
||||||
|
var order = "start DESC" |
||||||
|
if req.Order == 2 { |
||||||
|
order = "start ASC" |
||||||
|
} |
||||||
|
if req.Order == 3 { |
||||||
|
order = "un_read DESC" |
||||||
|
} |
||||||
|
|
||||||
|
count, err := db.Mysql().QueryList(req.Page-1, req.Num, query, order, &common.CustomerOrder{}, &resp.List) |
||||||
|
if err != nil && err != gorm.ErrRecordNotFound { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
resp.Count = count |
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
// 工单处理状态改变
|
||||||
|
func ChangeCustomerOrderStatus(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := &values.ChangeCustomerOrderReq{} |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
for i := 0; i < len(req.List); i++ { |
||||||
|
update := make(map[string]interface{}) |
||||||
|
/*if req.List[i].Status != 0 { |
||||||
|
update["status"] = req.List[i].Status |
||||||
|
} |
||||||
|
if req.List[i].Label1 != 0 { |
||||||
|
update["label1"] = req.List[i].Label1 |
||||||
|
} |
||||||
|
if req.List[i].Label2 != 0 { |
||||||
|
update["label2"] = req.List[i].Label2 |
||||||
|
} |
||||||
|
if req.List[i].Label3 != 0 { |
||||||
|
update["label3"] = req.List[i].Label3 |
||||||
|
} |
||||||
|
if req.List[i].Label4 != 0 { |
||||||
|
update["label4"] = req.List[i].Label4 |
||||||
|
} |
||||||
|
if req.List[i].Label5 != 0 { |
||||||
|
update["label5"] = req.List[i].Label5 |
||||||
|
} |
||||||
|
if len(update) < 1 { |
||||||
|
continue |
||||||
|
}*/ |
||||||
|
update["status"] = req.List[i].Status |
||||||
|
update["label1"] = req.List[i].Label1 |
||||||
|
update["label2"] = req.List[i].Label2 |
||||||
|
update["label3"] = req.List[i].Label3 |
||||||
|
update["label4"] = req.List[i].Label4 |
||||||
|
update["label5"] = req.List[i].Label5 |
||||||
|
|
||||||
|
// 完成工单
|
||||||
|
update["end"] = time.Now().Unix() |
||||||
|
update["un_read"] = 0 |
||||||
|
err := db.Mysql().Update(&common.CustomerOrder{ID: req.List[i].Id}, update) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 分配工单到客服人员
|
||||||
|
func CustomerOrderAllocate(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := &values.CustomerOrderAllocateReq{} |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
tx := db.Mysql().Begin() |
||||||
|
defer a.MCommit(tx) |
||||||
|
|
||||||
|
for i := 0; i < len(req.List); i++ { |
||||||
|
err := tx.Exec("UPDATE customer_order SET customer_uid = ?, status = ? WHERE id = ? AND status != ?", req.List[i].Uid, common.CustomerOrderAllocate, req.List[i].OrderId, common.CustomerOrderComplete).Error |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 编辑标签
|
||||||
|
func EditCustomerOrderLabel(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := &values.EditCustomerOrderLabelReq{} |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
update := make(map[string]interface{}) |
||||||
|
update["label1"] = req.LabelId1 |
||||||
|
update["label2"] = req.LabelId2 |
||||||
|
update["label3"] = req.LabelId3 |
||||||
|
update["label4"] = req.LabelId4 |
||||||
|
update["label5"] = req.LabelId5 |
||||||
|
err := db.Mysql().Update(&common.CustomerOrder{ID: req.OrderId}, update) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 获取玩家信息
|
||||||
|
func GetPlayerInfo(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
|
||||||
|
req := &values.GetPlayerInfoReq{} |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
var resp values.GetPlayerInfoResp |
||||||
|
|
||||||
|
// 玩家信息
|
||||||
|
player, err := call.GetUserXInfo(req.Uid, "channel_id", "nick", "avatar", "birth", "mobile") |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
resp.Uid = req.Uid |
||||||
|
resp.Nick = player.Nick |
||||||
|
resp.Avatar = player.Avatar |
||||||
|
resp.Birth = player.Birth |
||||||
|
resp.Phone = player.Mobile |
||||||
|
resp.Channel = player.ChannelID |
||||||
|
|
||||||
|
// 渠道信息
|
||||||
|
channel := &common.Channel{ChannelID: player.ChannelID} |
||||||
|
err = db.Mysql().Get(channel) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
resp.Package = channel.PackName |
||||||
|
|
||||||
|
// vip
|
||||||
|
resp.Vip = call.GetVIP(req.Uid).Level |
||||||
|
|
||||||
|
order := &common.RechargeInfo{UID: req.Uid} |
||||||
|
err = db.Mysql().Get(order) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
|
||||||
|
resp.Withdraw = order.TotalWithdraw |
||||||
|
resp.Recharge = order.TotalRecharge |
||||||
|
|
||||||
|
if db.Mysql().Exist(&common.CustomerBlackUser{Uid: req.Uid}) { |
||||||
|
resp.CustomerBlack = true |
||||||
|
} |
||||||
|
|
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
// 玩家历史客诉记录
|
||||||
|
func ComplaintHistory(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
|
||||||
|
req := &values.ComplaintHistoryReq{} |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
var resp values.ComplaintHistoryResp |
||||||
|
|
||||||
|
count, err := db.Mysql().QueryList(req.Page-1, req.Num, fmt.Sprintf("uid = %v", req.Uid), "", &common.CustomerOrder{}, &resp.List) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
resp.Count = count |
||||||
|
a.Data = resp |
||||||
|
} |
||||||
@ -0,0 +1,261 @@ |
|||||||
|
package common |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"io" |
||||||
|
"mime" |
||||||
|
"net/http" |
||||||
|
"os" |
||||||
|
"server/call" |
||||||
|
"server/common" |
||||||
|
"server/config" |
||||||
|
"server/db" |
||||||
|
utils "server/modules/backend/util" |
||||||
|
"server/modules/customer/app" |
||||||
|
"server/modules/customer/bdb" |
||||||
|
"server/modules/customer/values" |
||||||
|
"server/util" |
||||||
|
"strings" |
||||||
|
"time" |
||||||
|
|
||||||
|
"github.com/olivere/elastic/v7" |
||||||
|
|
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
) |
||||||
|
|
||||||
|
// 上传图片 并返回图片地址
|
||||||
|
func UploadImage(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
|
||||||
|
// 解析请求中的 multipart/form-data
|
||||||
|
err := c.Request.ParseMultipartForm(10 << 20) // 限制上传文件的大小为 10MB
|
||||||
|
if err != nil { |
||||||
|
log.Error("图片超过10Mb, err:%v", err.Error()) |
||||||
|
a.Code = values.CodeParam |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// 打开上传的文件
|
||||||
|
file, header, err := c.Request.FormFile("file") |
||||||
|
if err != nil { |
||||||
|
log.Error("打开上传图片失败, err:%v", err.Error()) |
||||||
|
a.Code = values.CodeParam |
||||||
|
return |
||||||
|
} |
||||||
|
defer file.Close() |
||||||
|
|
||||||
|
// 获取上传文件的 MIME 类型
|
||||||
|
contentType := header.Header.Get("Content-Type") |
||||||
|
|
||||||
|
// 根据 MIME 类型获取文件扩展名
|
||||||
|
ext, err := mime.ExtensionsByType(contentType) |
||||||
|
if err != nil || len(ext) == 0 { |
||||||
|
log.Error("获取上传图片格式失败, err:%v", err.Error()) |
||||||
|
a.Code = values.CodeParam |
||||||
|
return |
||||||
|
} |
||||||
|
imageName := call.SnowNode().Generate().String() + ext[0] |
||||||
|
|
||||||
|
// 读取上传的文件内容
|
||||||
|
data, err := io.ReadAll(file) |
||||||
|
if err != nil { |
||||||
|
log.Error("读取图片内容失败, err:%v", err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// 获取当前本地时间
|
||||||
|
now := time.Now() |
||||||
|
zeroTime := now.Format("20060102") |
||||||
|
rounded := now.Hour() |
||||||
|
dir := fmt.Sprintf("%v/%v/%v", values.ImagePath, zeroTime, rounded) |
||||||
|
|
||||||
|
// 创建保存文件的目标文件
|
||||||
|
err = createDirIfNotExist(dir) |
||||||
|
if err != nil { |
||||||
|
log.Error("创建图片保存目录, err:%v", err.Error()) |
||||||
|
a.Code = values.CodeParam |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// 将上传的文件复制到目标文件
|
||||||
|
err = os.WriteFile(dir+"/"+imageName, data, 0644) // 写入文件
|
||||||
|
if err != nil { |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
name := strings.Replace(dir+"/"+imageName, "/", ",", -1) |
||||||
|
a.Data = config.GetConfig().Customer.ImageURL + name |
||||||
|
} |
||||||
|
|
||||||
|
// 检测文件目录是否存在
|
||||||
|
func createDirIfNotExist(path string) error { |
||||||
|
// 检查目录是否存在
|
||||||
|
_, err := os.Stat(path) |
||||||
|
if err == nil { |
||||||
|
// 目录已存在,直接返回
|
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// 目录不存在,创建目录
|
||||||
|
if os.IsNotExist(err) { |
||||||
|
err = os.MkdirAll(path, 0755) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// 返回图片
|
||||||
|
func DownImage(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
// req := &values.DownLoadImageReq{}
|
||||||
|
// if !a.S(req) {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
name := c.Query("path") |
||||||
|
path := strings.Replace(name, ",", "/", -1) |
||||||
|
|
||||||
|
// 打开要返回的图片文件
|
||||||
|
file, err := os.Open(path) |
||||||
|
if err != nil { |
||||||
|
c.AbortWithError(http.StatusInternalServerError, err) |
||||||
|
return |
||||||
|
} |
||||||
|
defer file.Close() |
||||||
|
|
||||||
|
// 读取图片文件的内容
|
||||||
|
data, err := io.ReadAll(file) |
||||||
|
if err != nil { |
||||||
|
c.AbortWithError(http.StatusInternalServerError, err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
arr := strings.Split(path, ".") |
||||||
|
|
||||||
|
// 返回图片
|
||||||
|
c.Data(http.StatusOK, "image/"+arr[len(arr)-1], data) |
||||||
|
} |
||||||
|
|
||||||
|
// OptList 操作日志
|
||||||
|
func OptList(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.EditHistoryListReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
resp := values.EditHistoryListResp{} |
||||||
|
if err := bdb.BackDB.C().Order("time Desc").Limit(int(req.Num)).Offset(int((req.Page - 1) * req.Num)).Find(&resp.List).Error; err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
} |
||||||
|
resp.Count = bdb.BackDB.Count(&values.EditHistory{}, "") |
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
func GoodList(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
} |
||||||
|
|
||||||
|
func ProductList(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
products := call.GetConfigPayProduct() |
||||||
|
resp := &values.ProductListResp{List: products} |
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
func GamesList(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
a.Data = values.GamesListResp{} |
||||||
|
} |
||||||
|
|
||||||
|
func ChannelList(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
ret := call.GetChannelListReal() |
||||||
|
if ret == nil { |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
resp := values.ChannelListResp{} |
||||||
|
for _, v := range ret { |
||||||
|
if v.Show != 2 { |
||||||
|
continue |
||||||
|
} |
||||||
|
if len(a.User.SChannels) > 0 { |
||||||
|
if !util.SliceContain(a.User.SChannels, v.ChannelID) { |
||||||
|
continue |
||||||
|
} |
||||||
|
} |
||||||
|
resp.List = append(resp.List, v) |
||||||
|
} |
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
func UserInfo(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
resp := values.UserInfoResp{Name: a.User.Name, Role: a.User.Role, Power: a.User.Power} |
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
func GameInfo(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
|
||||||
|
var resp values.GameInfoResp |
||||||
|
|
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
func FeedbackList(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.FeedbackListReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
var resp values.FeedbackListResp |
||||||
|
su, eu := utils.GetQueryUnix(req.Start, req.End) |
||||||
|
q := elastic.NewBoolQuery() |
||||||
|
q.Must(elastic.NewRangeQuery("time").Gt(su)) |
||||||
|
q.Must(elastic.NewRangeQuery("time").Lt(eu)) |
||||||
|
var list []*common.ESFeedback |
||||||
|
count, err := db.ES().QueryList(common.ESIndexBackFeedback, req.Page-1, req.Num, q, &list, "time", false) |
||||||
|
if err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
} |
||||||
|
resp.List = list |
||||||
|
resp.Count = count |
||||||
|
a.Data = resp |
||||||
|
} |
||||||
@ -0,0 +1,146 @@ |
|||||||
|
package gm |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"server/call" |
||||||
|
"server/common" |
||||||
|
"server/db" |
||||||
|
"server/modules/backend/models" |
||||||
|
"server/modules/backend/values" |
||||||
|
"server/modules/customer/app" |
||||||
|
uutil "server/util" |
||||||
|
"strconv" |
||||||
|
|
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
"github.com/olivere/elastic/v7" |
||||||
|
) |
||||||
|
|
||||||
|
func GetGameUserInfo(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.GetGameUserInfoReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
user := &common.PlayerDBInfo{} |
||||||
|
switch req.Data.(type) { |
||||||
|
case int, int64, float32, float64: |
||||||
|
id := uutil.GetInt(req.Data) |
||||||
|
if id <= 999999999 { |
||||||
|
user.Id = id |
||||||
|
} else { |
||||||
|
user.Mobile = strconv.Itoa(id) |
||||||
|
} |
||||||
|
case string: |
||||||
|
str := req.Data.(string) |
||||||
|
if len(str) == 10 { |
||||||
|
user.Mobile = str |
||||||
|
} else { |
||||||
|
id, err := strconv.Atoi(str) |
||||||
|
if err != nil { |
||||||
|
a.Code = values.CodeParam |
||||||
|
a.Msg = "玩家不存在" |
||||||
|
return |
||||||
|
} |
||||||
|
user.Id = id |
||||||
|
} |
||||||
|
} |
||||||
|
err := db.Mysql().Get(user) |
||||||
|
if err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeParam |
||||||
|
a.Msg = "玩家不存在" |
||||||
|
return |
||||||
|
} |
||||||
|
uid := user.Id |
||||||
|
ur, _ := call.GetUserXInfo(uid, "online") |
||||||
|
info := &common.RechargeInfo{UID: uid} |
||||||
|
db.Mysql().Get(info) |
||||||
|
lg := &common.LoginRecord{UID: uid} |
||||||
|
db.Mysql().GetLast(lg) |
||||||
|
resp := values.GetGameUserInfoResp{ |
||||||
|
UID: user.Id, |
||||||
|
Nick: user.Nick, |
||||||
|
Channel: user.ChannelID, |
||||||
|
Phone: user.Mobile, |
||||||
|
OpenID: *user.Openid, |
||||||
|
Online: ur.Online == common.PlayerOnline, |
||||||
|
Status: user.Status, |
||||||
|
Birth: user.Birth, |
||||||
|
// PlayCount: util.GetGUserPlayCount(uid),
|
||||||
|
IP: user.IP, |
||||||
|
LastLogin: lg.Time, |
||||||
|
Tag: user.Tag, |
||||||
|
UserGameData: GetUserGameInfo(user.Id), |
||||||
|
OutputData: models.GetOutputData(0, 0, 0, uid), |
||||||
|
Gpsadid: user.DeviceId, |
||||||
|
} |
||||||
|
|
||||||
|
// re := call.GetRechargeInfo(uid)
|
||||||
|
// resp.Recharge = re.TotalRecharge
|
||||||
|
// resp.Withdraw = re.TotalWithdraw
|
||||||
|
// resp.NeedBet = call.GetUserNeedBet(uid)
|
||||||
|
// resp.Cash = call.GetUserCurrency(uid, common.CurrencyINR)
|
||||||
|
db.Mysql().C().Table("users").Select("id").Where("deviceid = ?", user.DeviceId).Scan(&resp.SubAccount) |
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
// 获取用户游戏信息
|
||||||
|
func GetUserGameInfo(uid int) map[string][]values.UserGameInfo { |
||||||
|
q := elastic.NewBoolQuery() |
||||||
|
q.Filter(elastic.NewTermQuery("uid", uid)) |
||||||
|
q.Filter(elastic.NewTermsQuery("event", common.GetGameEvents()...)) |
||||||
|
buk, err := db.ES().Group2SumBy(common.ESIndexBalance, "exi1", "exi2", "value", q, "", false, 0) |
||||||
|
if err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
} |
||||||
|
ret := map[string][]values.UserGameInfo{} |
||||||
|
var totalCount, totalProfit int64 |
||||||
|
for _, v := range buk.Buckets { |
||||||
|
provider := call.GetConfigGameProvider(uutil.GetInt(v.Key)) |
||||||
|
if provider == nil { |
||||||
|
continue |
||||||
|
} |
||||||
|
games := []values.UserGameInfo{} |
||||||
|
for _, k := range v.Sub1.Buckets { |
||||||
|
thisGame := call.GetConfigGameListByGameID(provider.ProviderID, uutil.GetInt(k.Key)) |
||||||
|
if thisGame == nil { |
||||||
|
continue |
||||||
|
} |
||||||
|
count := uutil.GetInt64(k.Doc_count) |
||||||
|
profit := uutil.GetInt64(k.Sub2.Value) |
||||||
|
totalCount += count |
||||||
|
totalProfit += profit |
||||||
|
games = append(games, values.UserGameInfo{ |
||||||
|
GameName: thisGame.Name + fmt.Sprintf("(%d)", thisGame.GameID), |
||||||
|
GameCount: count, |
||||||
|
Profit: profit, |
||||||
|
}) |
||||||
|
} |
||||||
|
ret[provider.ProviderName] = games |
||||||
|
} |
||||||
|
ret["总计"] = []values.UserGameInfo{{GameCount: totalCount, Profit: totalProfit}} |
||||||
|
return ret |
||||||
|
} |
||||||
|
|
||||||
|
// func getUserGameData(uid int, gameId *int, win, lost *bool) values.UserGameInfo {
|
||||||
|
// var userGameInfo values.UserGameInfo
|
||||||
|
// if gameId == nil {
|
||||||
|
// userGameInfo.GameId = 0
|
||||||
|
// } else {
|
||||||
|
// userGameInfo.GameId = *gameId
|
||||||
|
// }
|
||||||
|
// userGameInfo.GameCount = models.GetWinGameCountByBalance(nil, nil, &uid, nil, gameId, nil, nil)
|
||||||
|
// userGameInfo.WinCount = models.GetWinGameCountByBalance(nil, nil, &uid, nil, gameId, nil, win)
|
||||||
|
// userGameInfo.LoseCount = models.GetWinGameCountByBalance(nil, nil, &uid, nil, gameId, nil, lost)
|
||||||
|
|
||||||
|
// userGameInfo.Profit = models.GetGameProfitByUid(nil, nil, &uid, nil, gameId, nil, nil)
|
||||||
|
// userGameInfo.WinProfit = models.GetGameProfitByUid(nil, nil, &uid, nil, gameId, nil, win)
|
||||||
|
// userGameInfo.LoseProfit = models.GetGameProfitByUid(nil, nil, &uid, nil, gameId, nil, lost)
|
||||||
|
// userGameInfo.WinPer = util.GetPer(userGameInfo.WinCount, userGameInfo.GameCount)
|
||||||
|
|
||||||
|
// return userGameInfo
|
||||||
|
// }
|
||||||
@ -0,0 +1,401 @@ |
|||||||
|
package gm |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
"server/call" |
||||||
|
"server/common" |
||||||
|
"server/db" |
||||||
|
"server/modules/customer/app" |
||||||
|
"server/modules/customer/values" |
||||||
|
"server/natsClient" |
||||||
|
"server/pb" |
||||||
|
"server/util" |
||||||
|
) |
||||||
|
|
||||||
|
// 获取客服机器人消息
|
||||||
|
func GetCustomerRobot(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
|
||||||
|
req := &values.GetCustomerRobotReq{} |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
resp := values.GetCustomerRobotResp{} |
||||||
|
if _, err := db.Mysql().QueryAll(fmt.Sprintf("parent_id = %v", req.ParentId), "", &common.ConfigCustomerRobot{}, &resp.List); err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
// 编辑客服机器人消息
|
||||||
|
func EditCustomerRobot(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := &values.EditCustomerRobotReq{} |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
var resp values.EditCustomerRobotResp |
||||||
|
|
||||||
|
for i := 0; i < len(req.List); i++ { |
||||||
|
if req.List[i] != nil { |
||||||
|
// 新增
|
||||||
|
if req.List[i].ID == 0 { |
||||||
|
log.Debug("req:%+v", req.List[i]) |
||||||
|
err := db.Mysql().Create(req.List[i]) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
log.Debug("req:%+v", req.List[i]) |
||||||
|
resp.List = append(resp.List, req.List[i]) |
||||||
|
} else { |
||||||
|
// 修改
|
||||||
|
log.Debug("req:%+v", req.List[i]) |
||||||
|
u := &common.ConfigCustomerRobot{} |
||||||
|
u.ID = req.List[i].ID |
||||||
|
update := util.StructToMap(req.List[i], "json") |
||||||
|
if err := db.Mysql().Update(u, update); err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
err := call.Publish(natsClient.TopicReloadConfig, &pb.ReloadGameConfig{Type: common.ReloadConfigCustomerRobot}) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// 写入日志
|
||||||
|
for i := 0; i < len(req.List); i++ { |
||||||
|
if req.List[i] != nil { |
||||||
|
a.RecordEdit(values.PowerGM, fmt.Sprintf("编辑客服机器人配置:%v", *req.List[i])) |
||||||
|
} |
||||||
|
} |
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
// 删除客服机器人消息
|
||||||
|
func DelCustomerRobot(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := &values.DelCustomerRobotReq{} |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
for i := 0; i < len(req.List); i++ { |
||||||
|
if req.List[i] != nil { |
||||||
|
log.Debug("req:%+v", *req.List[i]) |
||||||
|
err := db.Mysql().Del(&common.ConfigCustomerRobot{}, " id = ?", *req.List[i]) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
err := call.Publish(natsClient.TopicReloadConfig, &pb.ReloadGameConfig{Type: common.ReloadConfigCustomerRobot}) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
} |
||||||
|
|
||||||
|
// 写入日志
|
||||||
|
for i := 0; i < len(req.List); i++ { |
||||||
|
if req.List[i] != nil { |
||||||
|
a.RecordEdit(values.PowerGM, fmt.Sprintf("删除客服机器人配置:%v", *req.List[i])) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 获取标签
|
||||||
|
func GetCustomerLabel(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
|
||||||
|
resp := values.GetCustomerLabelResp{} |
||||||
|
if _, err := db.Mysql().QueryAll("", "", &common.CustomerOrderLabel{}, &resp.List); err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
// 编辑标签
|
||||||
|
func EditCustomerLabel(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := &values.EditCustomerLabelReq{} |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
for i := 0; i < len(req.List); i++ { |
||||||
|
if req.List[i] != nil { |
||||||
|
// 新增
|
||||||
|
if req.List[i].ID == 0 { |
||||||
|
log.Debug("req:%+v", req.List[i]) |
||||||
|
err := db.Mysql().Create(req.List[i]) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
} else { |
||||||
|
// 修改
|
||||||
|
log.Debug("req:%+v", req.List[i]) |
||||||
|
u := &common.CustomerOrderLabel{} |
||||||
|
u.ID = req.List[i].ID |
||||||
|
update := util.StructToMap(req.List[i], "json") |
||||||
|
if err := db.Mysql().Update(u, update); err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
err := call.Publish(natsClient.TopicReloadConfig, &pb.ReloadGameConfig{Type: common.ReloadConfigCustomerLabel}) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
} |
||||||
|
|
||||||
|
// 写入日志
|
||||||
|
for i := 0; i < len(req.List); i++ { |
||||||
|
if req.List[i] != nil { |
||||||
|
a.RecordEdit(values.PowerGM, fmt.Sprintf("编辑工单标签配置:%v", *req.List[i])) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 删除标签
|
||||||
|
func DelCustomerLabel(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := &values.DelCustomerLabelReq{} |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
for i := 0; i < len(req.List); i++ { |
||||||
|
if req.List[i] != nil { |
||||||
|
log.Debug("req:%+v", req.List[i]) |
||||||
|
err := db.Mysql().Del(&common.ConfigCustomerRobot{}, " id = ?", *req.List[i]) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
err := call.Publish(natsClient.TopicReloadConfig, &pb.ReloadGameConfig{Type: common.ReloadConfigCustomerLabel}) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
} |
||||||
|
|
||||||
|
// 写入日志
|
||||||
|
for i := 0; i < len(req.List); i++ { |
||||||
|
if req.List[i] != nil { |
||||||
|
a.RecordEdit(values.PowerGM, fmt.Sprintf("删除工单标签配置:%v", *req.List[i])) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 客服系统配置
|
||||||
|
func GetConfigCustomer(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
|
||||||
|
resp := values.GetConfigCustomerResp{} |
||||||
|
if _, err := db.Mysql().QueryAll("", "", &common.ConfigCustomer{}, &resp.List); err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
// 客服系统配置
|
||||||
|
func EditConfigCustomer(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := &values.EditConfigCustomerReq{} |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
for i := 0; i < len(req.List); i++ { |
||||||
|
if req.List[i] != nil { |
||||||
|
// 新增
|
||||||
|
if req.List[i].ID == 0 { |
||||||
|
log.Debug("req:%+v", req.List[i]) |
||||||
|
err := db.Mysql().Create(req.List[i]) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
} else { |
||||||
|
// 修改
|
||||||
|
log.Debug("req:%+v", req.List[i]) |
||||||
|
u := &common.ConfigCustomer{} |
||||||
|
u.ID = req.List[i].ID |
||||||
|
update := util.StructToMap(req.List[i], "json") |
||||||
|
if err := db.Mysql().Update(u, update); err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
err := call.Publish(natsClient.TopicReloadConfig, &pb.ReloadGameConfig{Type: common.ReloadConfigCustomer}) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
} |
||||||
|
|
||||||
|
// 写入日志
|
||||||
|
for i := 0; i < len(req.List); i++ { |
||||||
|
if req.List[i] != nil { |
||||||
|
a.RecordEdit(values.PowerGM, fmt.Sprintf("编辑客服系统配置:%v", *req.List[i])) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 客服系统配置
|
||||||
|
func DelConfigCustomer(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := &values.DelConfigCustomerReq{} |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
for i := 0; i < len(req.List); i++ { |
||||||
|
if req.List[i] != nil { |
||||||
|
log.Debug("req:%+v", req.List[i]) |
||||||
|
err := db.Mysql().Del(&common.ConfigCustomer{}, " id = ?", *req.List[i]) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
err := call.Publish(natsClient.TopicReloadConfig, &pb.ReloadGameConfig{Type: common.ReloadConfigCustomer}) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
} |
||||||
|
|
||||||
|
// 写入日志
|
||||||
|
for i := 0; i < len(req.List); i++ { |
||||||
|
if req.List[i] != nil { |
||||||
|
a.RecordEdit(values.PowerGM, fmt.Sprintf("删除客服系统配置:%v", *req.List[i])) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 客服黑名单
|
||||||
|
func GetCustomerBlackUser(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
|
||||||
|
req := &values.CustomerBlackUserReq{} |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
var resp values.CustomerBlackUserResp |
||||||
|
count, err := db.Mysql().QueryList(req.Page-1, req.Num, "", "", &common.CustomerBlackUser{}, &resp.List) |
||||||
|
if err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
resp.Count = count |
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
// 客服黑名单
|
||||||
|
func EditCustomerBlackUser(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := &values.EditCustomerBlackUserReq{} |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
for i := 0; i < len(req.List); i++ { |
||||||
|
if req.List[i] != nil { |
||||||
|
log.Debug("opt:%v, req:%+v", req.Opt, *req.List[i]) |
||||||
|
if req.Opt == 1 { |
||||||
|
err := db.Mysql().Create(&common.CustomerBlackUser{Uid: *req.List[i]}) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
} else { |
||||||
|
data := &common.CustomerBlackUser{Uid: *req.List[i]} |
||||||
|
err := db.Mysql().Get(data) |
||||||
|
if err == nil { |
||||||
|
db.Mysql().Del(data) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
var str string |
||||||
|
if req.Opt == 1 { |
||||||
|
str = "添加" |
||||||
|
} else { |
||||||
|
str = "删除" |
||||||
|
} |
||||||
|
// 写入日志
|
||||||
|
for i := 0; i < len(req.List); i++ { |
||||||
|
if req.List[i] != nil { |
||||||
|
a.RecordEdit(values.PowerGM, fmt.Sprintf("%v客服系统黑名单 uid:%v", str, *req.List[i])) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,121 @@ |
|||||||
|
package guser |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
"github.com/olivere/elastic/v7" |
||||||
|
"server/common" |
||||||
|
"server/db" |
||||||
|
utils "server/modules/backend/util" |
||||||
|
"server/modules/backend/values" |
||||||
|
"server/modules/customer/app" |
||||||
|
"server/util" |
||||||
|
) |
||||||
|
|
||||||
|
func ActiveUserList(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.ActiveUserListReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
var resp values.ActiveUserListResp |
||||||
|
|
||||||
|
su, eu := utils.GetQueryUnix(req.Start, req.End) |
||||||
|
|
||||||
|
queryCount := " SELECT COUNT(*) FROM login_record WHERE " |
||||||
|
|
||||||
|
str := fmt.Sprintf(" time >= %d AND time < %d ", su, eu) |
||||||
|
|
||||||
|
if req.Channel != nil { |
||||||
|
str += fmt.Sprintf(" AND channel_id = %d ", *req.Channel) |
||||||
|
} |
||||||
|
|
||||||
|
if req.Status != nil { |
||||||
|
str += fmt.Sprintf(" AND status = %v ", req.Status) |
||||||
|
} |
||||||
|
|
||||||
|
var count int64 |
||||||
|
err := db.Mysql().QueryBySql(queryCount+str, &count) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
|
||||||
|
sql := fmt.Sprintf( |
||||||
|
`SELECT d.id,d.nick,d.status,d.birth,d.cash,d.bind_cash,d.online,d.time,IFNULL(c.total_charge,0) as total_charge,IFNULL(c.total_withdraw,0) as total_withdraw from |
||||||
|
(SELECT id,nick,status,birth,cash,bind_cash,online,b.time from users as a |
||||||
|
INNER JOIN |
||||||
|
(SELECT uid,max(time) as time from login_record WHERE time >= %d and time < %d GROUP BY uid) as b |
||||||
|
on a.id = b.uid
|
||||||
|
LIMIT %d,%d |
||||||
|
) as d |
||||||
|
LEFT JOIN |
||||||
|
(SELECT uid,total_charge,total_withdraw from recharge_info) as c |
||||||
|
on d.id = c.uid`, su, eu, (req.Page-1)*req.Num, req.Num) |
||||||
|
|
||||||
|
list := []values.ActiveUserOne{} |
||||||
|
|
||||||
|
if err := db.Mysql().C().Raw(sql).Scan(&list).Error; err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
} |
||||||
|
|
||||||
|
uids := []interface{}{} |
||||||
|
for _, v := range list { |
||||||
|
uids = append(uids, v.ID) |
||||||
|
resp.List = append(resp.List, values.ActiveUserInfo{ |
||||||
|
UID: int64(v.ID), |
||||||
|
Nick: v.Nick, |
||||||
|
Status: v.Status, |
||||||
|
Birth: v.Birth, |
||||||
|
LastLogin: v.Time, |
||||||
|
Recharge: v.TotalCharge, |
||||||
|
Withdraw: v.TotalWithdraw, |
||||||
|
Cash: v.Cash, |
||||||
|
TotalCash: v.Cash + v.BindCash, |
||||||
|
Online: v.Online, |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
q := elastic.NewBoolQuery() |
||||||
|
q.Filter(elastic.NewRangeQuery("time").Gte(list[0].Birth)) |
||||||
|
q.Filter(elastic.NewRangeQuery("event").Gte(common.CurrencyEventGameSettle)) |
||||||
|
q.Filter(elastic.NewRangeQuery("event").Lt(common.CurrencyEventGameBet)) |
||||||
|
q.Must(elastic.NewTermsQuery("uid", uids...)) |
||||||
|
totalGameCount, _ := db.ES().GroupBy(common.ESIndexBalance, "uid", q, len(list)) |
||||||
|
q.Filter(elastic.NewRangeQuery("value").Gt(0)) |
||||||
|
winGameCount, _ := db.ES().GroupBy(common.ESIndexBalance, "uid", q, len(list)) |
||||||
|
q = elastic.NewBoolQuery() |
||||||
|
q.Filter(elastic.NewRangeQuery("time").Gte(su)) |
||||||
|
q.Filter(elastic.NewRangeQuery("time").Lt(eu)) |
||||||
|
q.Filter(elastic.NewRangeQuery("event").Gte(common.CurrencyEventGameSettle)) |
||||||
|
q.Filter(elastic.NewRangeQuery("event").Lt(common.CurrencyEventGameBet)) |
||||||
|
q.Must(elastic.NewTermsQuery("uid", uids...)) |
||||||
|
todayGameCount, _ := db.ES().GroupBy(common.ESIndexBalance, "uid", q, len(list)) |
||||||
|
for i, v := range resp.List { |
||||||
|
for _, u := range totalGameCount.Buckets { |
||||||
|
if util.GetInt64(u.Key) == v.UID { |
||||||
|
resp.List[i].GameCount = int64(u.Doc_count) |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
var winCount int64 |
||||||
|
for _, u := range winGameCount.Buckets { |
||||||
|
if util.GetInt64(u.Key) == v.UID { |
||||||
|
winCount = int64(u.Doc_count) |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
resp.List[i].WinPer = utils.GetPer(winCount, resp.List[i].GameCount) |
||||||
|
for _, u := range todayGameCount.Buckets { |
||||||
|
if util.GetInt64(u.Key) == v.UID { |
||||||
|
resp.List[i].TodayCount = int64(u.Doc_count) |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
resp.Count = count |
||||||
|
a.Data = resp |
||||||
|
} |
||||||
@ -0,0 +1,86 @@ |
|||||||
|
package guser |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"server/call" |
||||||
|
"server/common" |
||||||
|
"server/db" |
||||||
|
"server/modules/backend/values" |
||||||
|
"server/modules/customer/app" |
||||||
|
|
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
) |
||||||
|
|
||||||
|
// 将用户相关信息拉入黑名单
|
||||||
|
func AddUserBlackList(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.AddUserBlackListReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
user, err := call.GetUserInfo(req.UID) |
||||||
|
if err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
list := []common.RechargeOrder{} |
||||||
|
db.Mysql().QueryList(0, 20, fmt.Sprintf("uid = %v and event = %v", user.Id, common.CurrencyEventWithDraw), "", common.RechargeOrder{}, &list) |
||||||
|
banAccounts := map[string]struct{}{} |
||||||
|
for _, v := range list { |
||||||
|
info := common.WithdrawCommon{} |
||||||
|
json.Unmarshal([]byte(v.PayAccount), &info) |
||||||
|
acc := "" |
||||||
|
if info.PayType == common.PayTypeBank { |
||||||
|
if info.BankCardNo != "" { |
||||||
|
acc = info.BankCardNo |
||||||
|
} |
||||||
|
} else if info.PayType == common.PayTypeUPI { |
||||||
|
if info.BankCode != "" { |
||||||
|
acc = info.BankCode |
||||||
|
} |
||||||
|
} |
||||||
|
if acc == "" { |
||||||
|
continue |
||||||
|
} |
||||||
|
if _, ok := banAccounts[acc]; !ok { |
||||||
|
banAccounts[acc] = struct{}{} |
||||||
|
} |
||||||
|
} |
||||||
|
if len(banAccounts) == 0 { |
||||||
|
black := &common.BlackList{ |
||||||
|
Phone: user.Mobile, |
||||||
|
IP: user.IP, |
||||||
|
} |
||||||
|
if user.DeviceId != "00000000-0000-0000-0000-000000000000" { |
||||||
|
black.DeviceID = user.DeviceId |
||||||
|
} |
||||||
|
err := db.Mysql().Create(black) |
||||||
|
if err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeParam |
||||||
|
a.Msg = "该用户信息已在黑名单里" |
||||||
|
} |
||||||
|
} else { |
||||||
|
for k := range banAccounts { |
||||||
|
black := &common.BlackList{ |
||||||
|
Phone: user.Mobile, |
||||||
|
IP: user.IP, |
||||||
|
PayAccount: k, |
||||||
|
} |
||||||
|
if user.DeviceId != "00000000-0000-0000-0000-000000000000" { |
||||||
|
black.DeviceID = user.DeviceId |
||||||
|
} |
||||||
|
err := db.Mysql().Create(black) |
||||||
|
if err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeParam |
||||||
|
a.Msg = "该用户信息已在黑名单里" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,31 @@ |
|||||||
|
package guser |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
"server/common" |
||||||
|
"server/db" |
||||||
|
"server/modules/backend/values" |
||||||
|
"server/modules/customer/app" |
||||||
|
) |
||||||
|
|
||||||
|
func AddUserTag(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.UserTagReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
err := db.Mysql().C().Model(&common.PlayerDBInfo{}).Where("id = ?", req.Uid).Updates(map[string]interface{}{ |
||||||
|
"tag": req.Tag, |
||||||
|
}).Error |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,57 @@ |
|||||||
|
package guser |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
"github.com/olivere/elastic/v7" |
||||||
|
"server/call" |
||||||
|
"server/common" |
||||||
|
"server/db" |
||||||
|
"server/modules/backend/models" |
||||||
|
utils "server/modules/backend/util" |
||||||
|
"server/modules/backend/values" |
||||||
|
"server/modules/customer/app" |
||||||
|
) |
||||||
|
|
||||||
|
func BanUserList(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.BanUserListReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
var resp values.BanUserListResp |
||||||
|
su, eu := utils.GetQueryUnix(req.Start, req.End) |
||||||
|
|
||||||
|
q := elastic.NewBoolQuery() |
||||||
|
q.Must(elastic.NewRangeQuery("Time").Gt(su)) |
||||||
|
q.Must(elastic.NewRangeQuery("Time").Lt(eu)) |
||||||
|
|
||||||
|
var list []*common.ESBlackList |
||||||
|
|
||||||
|
count, err := db.ES().QueryList(common.ESIndexBackBlackList, req.Page-1, req.Num, q, &list, "Time", false) |
||||||
|
if err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
for i := 0; i < len(list); i++ { |
||||||
|
user, err := call.GetUserInfo(list[i].UID) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
continue |
||||||
|
} |
||||||
|
resp.List = append(resp.List, &values.BanUserInfo{ |
||||||
|
ESBlackList: *list[i], |
||||||
|
Birth: user.Birth, |
||||||
|
Recharge: models.GetRechargeTotalByUid(&user.Id), |
||||||
|
Withdraw: models.GetWithdrawTotalByUid(&user.Id), |
||||||
|
Channel: user.ChannelID, |
||||||
|
}) |
||||||
|
} |
||||||
|
resp.Count = count |
||||||
|
a.Data = resp |
||||||
|
} |
||||||
@ -0,0 +1 @@ |
|||||||
|
package guser |
||||||
@ -0,0 +1 @@ |
|||||||
|
package guser |
||||||
@ -0,0 +1 @@ |
|||||||
|
package guser |
||||||
@ -0,0 +1,56 @@ |
|||||||
|
package guser |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"server/call" |
||||||
|
"server/common" |
||||||
|
"server/db" |
||||||
|
"server/modules/backend/values" |
||||||
|
"server/modules/customer/app" |
||||||
|
"server/natsClient" |
||||||
|
"server/pb" |
||||||
|
|
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
) |
||||||
|
|
||||||
|
func EditGameUserStatus(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.EditGameUserStatusReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
if req.Status <= common.AccountStatus || req.Status >= common.AccountStatusAll { |
||||||
|
a.Code = values.CodeParam |
||||||
|
a.Msg = "请求状态不合法" |
||||||
|
return |
||||||
|
} |
||||||
|
user, err := call.GetUserInfo(req.UID) |
||||||
|
if err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
if user.Status == req.Status { |
||||||
|
a.Code = values.CodeParam |
||||||
|
a.Msg = "无内容修改" |
||||||
|
return |
||||||
|
} |
||||||
|
if err = call.UpdateUserXInfo(&common.PlayerDBInfo{Id: req.UID}, map[string]interface{}{"status": req.Status}); err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
if req.Status == common.AccountStatusLimit { // 封禁账号要通知全服,踢出玩家
|
||||||
|
db.Redis().Delkey(common.GetRedisKeyToken(db.Redis().GetUserToken(req.UID))) |
||||||
|
db.Redis().Delkey(common.GetRedisKeyUser(req.UID)) |
||||||
|
err = call.Publish(natsClient.TopicInnerOptPlayer, &pb.InnerOptPlayer{UID: uint32(req.UID), Opt: common.OptPlayerTypeKick}) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
} |
||||||
|
a.RecordEdit(values.PowerGUser, fmt.Sprintf("修改玩家%v状态:%v", req.UID, req.Status)) |
||||||
|
} |
||||||
@ -0,0 +1,34 @@ |
|||||||
|
package guser |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
"server/common" |
||||||
|
"server/db" |
||||||
|
"server/modules/backend/values" |
||||||
|
"server/modules/customer/app" |
||||||
|
) |
||||||
|
|
||||||
|
func GetGameUserAllBalance(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.GetGameUserAllBalanceReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
resp := values.GetGameUserAllBalanceResp{ |
||||||
|
List: []common.CurrencyBalance{}, |
||||||
|
} |
||||||
|
var count int64 |
||||||
|
var err error |
||||||
|
count, err = db.ES().QueryPlayerAllBalance(&req.UID, req.Page-1, req.Num, req.Start, req.End, &resp.List) |
||||||
|
if err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
resp.Count = count |
||||||
|
a.Data = resp |
||||||
|
} |
||||||
@ -0,0 +1,47 @@ |
|||||||
|
package guser |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
"server/common" |
||||||
|
"server/db" |
||||||
|
"server/modules/backend/models" |
||||||
|
utils "server/modules/backend/util" |
||||||
|
"server/modules/backend/values" |
||||||
|
"server/modules/customer/app" |
||||||
|
) |
||||||
|
|
||||||
|
func GetGameUserControlBalance(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.GetGameUserControlBalanceReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
resp := values.GetGameUserControlBalanceResp{ |
||||||
|
List: []common.CurrencyBalance{}, |
||||||
|
} |
||||||
|
s, e := utils.GetQueryUnix(req.Start, req.End) |
||||||
|
count, err := db.ES().QueryPlayerControlBalance(req.UID, req.Page-1, req.Num, &s, &e, &resp.List, req.ControlType) |
||||||
|
if err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
resp.Count = count |
||||||
|
|
||||||
|
event := int(common.CurrencyEventGameSettle) |
||||||
|
// 查询控杀次数
|
||||||
|
resp.ControlCount = models.GetControlCount(&s, &e, &req.UID, &event, false) |
||||||
|
loseCount := models.GetControlCount(&s, &e, &req.UID, &event, true) |
||||||
|
resp.ControlPer = utils.GetPer(loseCount, resp.ControlCount) |
||||||
|
|
||||||
|
// 幸运次数
|
||||||
|
resp.LuckCount = models.GetLuckCount(&s, &e, &req.UID, nil, &event, false, false) |
||||||
|
winCount := models.GetLuckCount(&s, &e, &req.UID, nil, &event, true, false) |
||||||
|
resp.LuckPer = utils.GetPer(winCount, resp.LuckCount) |
||||||
|
|
||||||
|
a.Data = resp |
||||||
|
} |
||||||
@ -0,0 +1,245 @@ |
|||||||
|
package guser |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"reflect" |
||||||
|
"server/call" |
||||||
|
"server/common" |
||||||
|
"server/db" |
||||||
|
"server/modules/backend/models" |
||||||
|
"server/modules/backend/util" |
||||||
|
"server/modules/backend/values" |
||||||
|
"server/modules/customer/app" |
||||||
|
uutil "server/util" |
||||||
|
"sort" |
||||||
|
"strconv" |
||||||
|
|
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
"github.com/olivere/elastic/v7" |
||||||
|
) |
||||||
|
|
||||||
|
func GetGameUserInfo(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.GetGameUserInfoReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
user := &common.PlayerDBInfo{} |
||||||
|
switch req.Data.(type) { |
||||||
|
case int, int64, float32, float64: |
||||||
|
id := uutil.GetInt(req.Data) |
||||||
|
if id <= 999999999 { |
||||||
|
user.Id = id |
||||||
|
} else { |
||||||
|
user.Mobile = strconv.Itoa(id) |
||||||
|
} |
||||||
|
case string: |
||||||
|
str := req.Data.(string) |
||||||
|
if len(str) == 10 { |
||||||
|
user.Mobile = str |
||||||
|
} else { |
||||||
|
id, err := strconv.Atoi(str) |
||||||
|
if err != nil { |
||||||
|
a.Code = values.CodeParam |
||||||
|
a.Msg = "玩家不存在" |
||||||
|
return |
||||||
|
} |
||||||
|
user.Id = id |
||||||
|
} |
||||||
|
} |
||||||
|
err := db.Mysql().Get(user) |
||||||
|
if err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeParam |
||||||
|
a.Msg = "玩家不存在" |
||||||
|
return |
||||||
|
} |
||||||
|
uid := user.Id |
||||||
|
ur, _ := call.GetUserXInfo(uid, "online") |
||||||
|
info := &common.RechargeInfo{UID: uid} |
||||||
|
err = db.Mysql().Get(info) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
control := &common.PlayerControl{UID: uid} |
||||||
|
err = db.Mysql().Get(control) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
lg := &common.LoginRecord{UID: uid} |
||||||
|
err = db.Mysql().GetLast(lg) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
|
||||||
|
pointControl := &common.ConfigPointControl{UID: uid} |
||||||
|
db.Mysql().Get(pointControl) |
||||||
|
per := 0 |
||||||
|
tar := "" |
||||||
|
if control.NewControlFin == 1 { |
||||||
|
if control.NewControlLevel == 0 { |
||||||
|
control.NewControlLevel = 1 |
||||||
|
} |
||||||
|
con := call.GetNewControlConfigByID(control.NewControlLevel) |
||||||
|
if con != nil { |
||||||
|
control.TargetValue = con.ControlNum |
||||||
|
per = con.ControlPer |
||||||
|
tar = fmt.Sprintf("%v", control.TargetValue) |
||||||
|
} |
||||||
|
} else { |
||||||
|
if control.ControlSection > 0 { |
||||||
|
re := &common.RechargeInfo{UID: uid} |
||||||
|
db.Mysql().Get(re) |
||||||
|
con := call.GetSignleControlConfigByRecharge(re.TotalCharge) |
||||||
|
if con != nil { |
||||||
|
rcon := reflect.ValueOf(con).Elem() |
||||||
|
per = int(rcon.FieldByName(fmt.Sprintf("ControlPer%v", control.ControlSection)).Int()) |
||||||
|
} |
||||||
|
} |
||||||
|
tar = uutil.FormatFloat(float64(control.TargetValue)/100, 2) |
||||||
|
} |
||||||
|
black := &common.ConfigMillionBlack{UID: uid} |
||||||
|
db.Mysql().Get(black) |
||||||
|
resp := values.GetGameUserInfoResp{ |
||||||
|
UID: user.Id, |
||||||
|
Nick: user.Nick, |
||||||
|
Recharge: info.TotalCharge, |
||||||
|
Withdraw: info.TotoalWithdraw, |
||||||
|
Channel: user.ChannelID, |
||||||
|
Phone: user.Mobile, |
||||||
|
OpenID: *user.Openid, |
||||||
|
Cash: user.Cash, |
||||||
|
Total: user.BindCash + user.Cash, |
||||||
|
Online: ur.Online == common.PlayerOnline, |
||||||
|
Status: user.Status, |
||||||
|
Birth: user.Birth, |
||||||
|
// PlayCount: util.GetGUserPlayCount(uid),
|
||||||
|
IP: user.IP, |
||||||
|
LastLogin: lg.Time, |
||||||
|
Tag: user.Tag, |
||||||
|
IsFinishNewControl: control.NewControlFin == 2, |
||||||
|
NewControlLevel: control.NewControlLevel, |
||||||
|
ControlLevel: control.ControlLevel, |
||||||
|
ControlSection: control.ControlSection, |
||||||
|
ControlValue: uutil.FormatFloat(float64(control.ControlValue)/100, 2), |
||||||
|
ControlPer: per, |
||||||
|
TargetValue: tar, |
||||||
|
FreeAmount: uutil.FormatFloat(float64(control.FreeAmount)/100, 2), |
||||||
|
PointControlValue: uutil.FormatFloat(float64(pointControl.CurControlNum)/100, 2), |
||||||
|
PointControlTargetValue: uutil.FormatFloat(float64(pointControl.ControlNum), 2), |
||||||
|
PointControlPer: pointControl.ControlPer, |
||||||
|
UserGameData: GetUserGameInfo(user.Id), |
||||||
|
Gpsadid: user.DeviceId, |
||||||
|
Black: black, |
||||||
|
} |
||||||
|
|
||||||
|
_, err = db.Mysql().QueryAll(fmt.Sprintf("deviceid = '%s'", user.DeviceId), "", &common.PlayerDBInfo{}, &resp.SubAccount) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
// 获取用户游戏信息
|
||||||
|
func GetUserGameInfo(uid int) []values.UserGameInfo { |
||||||
|
q := elastic.NewBoolQuery() |
||||||
|
q.Filter(elastic.NewRangeQuery("uid").Gte(uid)) |
||||||
|
q.Filter(elastic.NewRangeQuery("uid").Lt(uid + 1)) |
||||||
|
q.Filter(elastic.NewRangeQuery("event").Gte(common.CurrencyEventGameSettle)) |
||||||
|
q.Filter(elastic.NewRangeQuery("event").Lt(common.CurrencyEventGameBet)) |
||||||
|
totalGameCount, _ := db.ES().GroupBy(common.ESIndexBalance, "desc.keyword", q, len(common.Games)) |
||||||
|
q.Filter(elastic.NewRangeQuery("value").Gt(0)) |
||||||
|
winGameCount, _ := db.ES().GroupBy(common.ESIndexBalance, "desc.keyword", q, len(common.Games)) |
||||||
|
|
||||||
|
q = elastic.NewBoolQuery() |
||||||
|
q.Filter(elastic.NewRangeQuery("uid").Gte(uid)) |
||||||
|
q.Filter(elastic.NewRangeQuery("uid").Lt(uid + 1)) |
||||||
|
q.Filter(elastic.NewRangeQuery("event").Gte(common.CurrencyEventGameSettle)) |
||||||
|
q.Filter(elastic.NewRangeQuery("event").Lt(common.CurrencyEventGameBet)) |
||||||
|
totalBulk := new(common.GroupSumBuckets) |
||||||
|
db.ES().GroupSumBy(common.ESIndexBalance, "desc.keyword", q, &totalBulk, "", false, 5000, "value") |
||||||
|
|
||||||
|
q.Filter(elastic.NewRangeQuery("value").Gt(0)) |
||||||
|
winBulk := new(common.GroupSumBuckets) |
||||||
|
db.ES().GroupSumBy(common.ESIndexBalance, "desc.keyword", q, &winBulk, "", false, 5000, "value") |
||||||
|
|
||||||
|
tmp := map[int]values.UserGameInfo{} |
||||||
|
for _, v := range common.RoomGameIDs { |
||||||
|
tmp[v] = values.UserGameInfo{GameId: v, WinPer: "0%"} |
||||||
|
} |
||||||
|
for _, v := range common.MillionGameIDs { |
||||||
|
tmp[uutil.GetInt(v)] = values.UserGameInfo{GameId: uutil.GetInt(v), WinPer: "0%"} |
||||||
|
} |
||||||
|
for _, v := range totalGameCount.Buckets { |
||||||
|
id := uutil.GetInt(v.Key) |
||||||
|
m := tmp[id] |
||||||
|
m.GameCount += int64(v.Doc_count) |
||||||
|
tmp[id] = m |
||||||
|
} |
||||||
|
for _, v := range winGameCount.Buckets { |
||||||
|
id := uutil.GetInt(v.Key) |
||||||
|
m := tmp[id] |
||||||
|
m.WinCount += int64(v.Doc_count) |
||||||
|
m.LoseCount = m.GameCount - m.WinCount |
||||||
|
tmp[id] = m |
||||||
|
} |
||||||
|
for _, v := range totalBulk.Buckets { |
||||||
|
id := uutil.GetInt(v.Key) |
||||||
|
m := tmp[id] |
||||||
|
m.Profit += int64(v.Value.Value) |
||||||
|
m.WinPer = util.GetPer(m.WinCount, m.GameCount) |
||||||
|
tmp[id] = m |
||||||
|
} |
||||||
|
for _, v := range winBulk.Buckets { |
||||||
|
id := uutil.GetInt(v.Key) |
||||||
|
m := tmp[id] |
||||||
|
m.WinProfit += int64(v.Value.Value) |
||||||
|
m.LoseProfit = m.Profit - m.WinProfit |
||||||
|
m.WinPer = util.GetPer(m.WinCount, m.GameCount) |
||||||
|
tmp[id] = m |
||||||
|
} |
||||||
|
|
||||||
|
var res []values.UserGameInfo |
||||||
|
total := values.UserGameInfo{} |
||||||
|
for _, v := range tmp { |
||||||
|
res = append(res, v) |
||||||
|
total.GameCount += v.GameCount |
||||||
|
total.WinCount += v.WinCount |
||||||
|
total.LoseCount += v.LoseCount |
||||||
|
total.Profit += v.Profit |
||||||
|
total.WinProfit += v.WinProfit |
||||||
|
total.LoseProfit += v.LoseProfit |
||||||
|
} |
||||||
|
total.WinPer = util.GetPer(total.WinCount, total.GameCount) |
||||||
|
|
||||||
|
sort.Slice(res, func(i, j int) bool { |
||||||
|
return res[i].GameCount > res[j].GameCount |
||||||
|
}) |
||||||
|
|
||||||
|
// 汇总
|
||||||
|
res = append([]values.UserGameInfo{total}, res...) |
||||||
|
return res |
||||||
|
} |
||||||
|
|
||||||
|
func getUserGameData(uid int, gameId *int, win, lost *bool) values.UserGameInfo { |
||||||
|
var userGameInfo values.UserGameInfo |
||||||
|
if gameId == nil { |
||||||
|
userGameInfo.GameId = 0 |
||||||
|
} else { |
||||||
|
userGameInfo.GameId = *gameId |
||||||
|
} |
||||||
|
userGameInfo.GameCount = models.GetWinGameCountByBalance(nil, nil, &uid, nil, gameId, nil, nil) |
||||||
|
userGameInfo.WinCount = models.GetWinGameCountByBalance(nil, nil, &uid, nil, gameId, nil, win) |
||||||
|
userGameInfo.LoseCount = models.GetWinGameCountByBalance(nil, nil, &uid, nil, gameId, nil, lost) |
||||||
|
|
||||||
|
userGameInfo.Profit = models.GetGameProfitByUid(nil, nil, &uid, nil, gameId, nil, nil) |
||||||
|
userGameInfo.WinProfit = models.GetGameProfitByUid(nil, nil, &uid, nil, gameId, nil, win) |
||||||
|
userGameInfo.LoseProfit = models.GetGameProfitByUid(nil, nil, &uid, nil, gameId, nil, lost) |
||||||
|
userGameInfo.WinPer = util.GetPer(userGameInfo.WinCount, userGameInfo.GameCount) |
||||||
|
|
||||||
|
return userGameInfo |
||||||
|
} |
||||||
@ -0,0 +1,231 @@ |
|||||||
|
package guser |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"server/call" |
||||||
|
"server/common" |
||||||
|
"server/db" |
||||||
|
"server/modules/backend/models" |
||||||
|
utils "server/modules/backend/util" |
||||||
|
"server/modules/backend/values" |
||||||
|
"server/modules/customer/app" |
||||||
|
"server/util" |
||||||
|
"time" |
||||||
|
|
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
"github.com/olivere/elastic/v7" |
||||||
|
) |
||||||
|
|
||||||
|
func GetGameUserList(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.GetGameUserListReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
su, eu := utils.GetQueryUnix(req.Start, req.End) |
||||||
|
|
||||||
|
var sqlList, sqlTotal, sqlCount string |
||||||
|
if req.ExcWithdraw { |
||||||
|
// list
|
||||||
|
sqlList = fmt.Sprintf("SELECT a.id AS UID,"+ // 用户uid
|
||||||
|
"a.nick AS Nick,"+ // 用户昵称
|
||||||
|
"a.status AS Status,"+ // 用户状态
|
||||||
|
"a.mobile AS Phone,"+ // 用户手机号
|
||||||
|
"a.birth AS Birth,"+ // 用户生日
|
||||||
|
"(a.cash+a.bind_cash) AS TotalCash,"+ // 用户总金额
|
||||||
|
"a.cash AS Cash,"+ // 用户可提现现金
|
||||||
|
"IFNULL(b.total_charge,0) AS Recharge,"+ // 用户充值金额
|
||||||
|
"IFNULL(b.total_withdraw,0) AS Withdraw,"+ // 用户提现金额
|
||||||
|
"a.online AS Online "+ // 用户是否在线
|
||||||
|
"FROM users AS a LEFT JOIN recharge_info AS b ON a.id = b.uid WHERE b.total_withdraw >= b.total_charge AND a.role <> 100 AND a.birth >= %d AND a.birth < %d", su, eu) |
||||||
|
|
||||||
|
// total
|
||||||
|
sqlTotal = fmt.Sprintf("SELECT SUM(a.cash+a.bind_cash) AS CashTotal,"+ // 总金额
|
||||||
|
"SUM(a.cash) AS WithdrawableTotal,"+ // 总可提现现金
|
||||||
|
"SUM(b.total_charge) AS RechargeTotal,"+ // 总充值
|
||||||
|
"SUM(b.total_withdraw) AS WithdrawHistoryTotal, "+ // 历史提现
|
||||||
|
"COUNT((IF(a.cash>=10000,TRUE,NULL))) AS WithdrawPlayerCount "+ // 提现玩家数量
|
||||||
|
"FROM users AS a LEFT JOIN recharge_info AS b ON a.id = b.uid WHERE b.total_withdraw >= b.total_charge AND a.role <> 100 AND a.birth >= %d AND a.birth < %d", su, eu) |
||||||
|
|
||||||
|
// count
|
||||||
|
sqlCount = fmt.Sprintf("SELECT count(*) FROM users AS a LEFT JOIN recharge_info AS b ON a.id = b.uid WHERE b.total_withdraw >= b.total_charge AND a.role<>100 AND a.birth >= %d AND a.birth < %d", su, eu) |
||||||
|
} else { |
||||||
|
// list
|
||||||
|
sqlList = fmt.Sprintf("SELECT a.id AS UID,"+ // 用户uid
|
||||||
|
"a.nick AS Nick,"+ // 用户昵称
|
||||||
|
"a.status AS Status,"+ // 用户状态
|
||||||
|
"a.mobile AS Phone,"+ // 用户手机号
|
||||||
|
"a.birth AS Birth,"+ // 用户生日
|
||||||
|
"(a.cash+a.bind_cash) AS TotalCash,"+ // 用户总金额
|
||||||
|
"a.cash AS Cash,"+ // 用户可提现现金
|
||||||
|
"IFNULL(b.total_charge,0) AS Recharge,"+ // 用户充值金额
|
||||||
|
"IFNULL(b.total_withdraw,0) AS Withdraw,"+ // 用户提现金额
|
||||||
|
"a.online AS Online "+ // 用户是否在线
|
||||||
|
"FROM users AS a LEFT JOIN recharge_info AS b ON a.id = b.uid WHERE a.role <> 100 AND a.birth >= %d AND a.birth < %d", su, eu) |
||||||
|
|
||||||
|
// total
|
||||||
|
sqlTotal = fmt.Sprintf("SELECT SUM(a.cash+a.bind_cash) AS CashTotal,"+ // 总金额
|
||||||
|
"SUM(a.cash) AS WithdrawableTotal,"+ // 总可提现现金
|
||||||
|
"SUM(b.total_charge) AS RechargeTotal,"+ // 总充值
|
||||||
|
"SUM(b.total_withdraw) AS WithdrawHistoryTotal, "+ // 历史提现
|
||||||
|
"COUNT((IF(a.cash>=10000,TRUE,NULL))) AS WithdrawPlayerCount "+ // 提现玩家数量
|
||||||
|
"FROM users AS a LEFT JOIN recharge_info AS b ON a.id = b.uid WHERE a.role <> 100 AND a.birth >= %d AND a.birth < %d", su, eu) |
||||||
|
|
||||||
|
// count
|
||||||
|
sqlCount = fmt.Sprintf("SELECT count(*) FROM users WHERE role<>100 AND birth >= %d AND birth < %d", su, eu) |
||||||
|
} |
||||||
|
|
||||||
|
order := "a.birth" |
||||||
|
sort := "" |
||||||
|
if req.Order != nil { |
||||||
|
if *req.Order < 0 { |
||||||
|
sort = " desc" |
||||||
|
*req.Order = -*req.Order |
||||||
|
} |
||||||
|
switch *req.Order { |
||||||
|
case 1: // 1是按玩家充值金额排序
|
||||||
|
order = "b.total_charge" |
||||||
|
case 2: // 2是按金币数量排序
|
||||||
|
order = "a.cash+a.bind_cash" |
||||||
|
case 3: // 3是按可提现总额排序
|
||||||
|
order = "a.cash" |
||||||
|
case 4: // 4是按历史提现金额排序
|
||||||
|
order = "b.total_withdraw" |
||||||
|
case 5: // 5是按注册时间排序
|
||||||
|
order = "a.birth" |
||||||
|
default: |
||||||
|
a.Code = values.CodeParam |
||||||
|
a.Msg = "排序参数不合法" |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if req.Channel != nil { |
||||||
|
sqlList += fmt.Sprintf(" and a.channel_id = %d ", *req.Channel) |
||||||
|
sqlTotal += fmt.Sprintf(" and a.channel_id = %d ", *req.Channel) |
||||||
|
sqlCount += fmt.Sprintf(" and channel_id = %d ", *req.Channel) |
||||||
|
} |
||||||
|
|
||||||
|
if req.Status != nil { |
||||||
|
sqlList += fmt.Sprintf(" and a.status = %v", *req.Status) |
||||||
|
sqlCount += fmt.Sprintf(" and status = %v", *req.Status) |
||||||
|
sqlTotal += fmt.Sprintf(" and status = %v", *req.Status) |
||||||
|
} |
||||||
|
if req.Online != nil { |
||||||
|
sqlList += fmt.Sprintf(" and a.online = %v", *req.Online) |
||||||
|
sqlCount += fmt.Sprintf(" and online = %v", *req.Online) |
||||||
|
sqlTotal += fmt.Sprintf(" and online = %v", *req.Online) |
||||||
|
} |
||||||
|
|
||||||
|
if req.CoinLimit != nil { |
||||||
|
CoinLimit := *req.CoinLimit |
||||||
|
if len(CoinLimit) < 2 { |
||||||
|
sqlList += fmt.Sprintf(" and %d <= (a.cash + a.bind_cash) and (a.cash + a.bind_cash) <= %d", 0, 3000) |
||||||
|
sqlCount += fmt.Sprintf(" and %d <= (cash + bind_cash) and (cash + bind_cash) <= %d", 0, 3000) |
||||||
|
sqlTotal += fmt.Sprintf(" and %d <= (cash + bind_cash) and (cash + bind_cash) <= %d", 0, 3000) |
||||||
|
} else { |
||||||
|
if CoinLimit[1] == 0 { |
||||||
|
sqlList += fmt.Sprintf(" and %d <= (a.cash + a.bind_cash) ", CoinLimit[0]) |
||||||
|
sqlCount += fmt.Sprintf(" and %d <= (cash + bind_cash) ", CoinLimit[0]) |
||||||
|
sqlTotal += fmt.Sprintf(" and %d <= (cash + bind_cash) ", CoinLimit[0]) |
||||||
|
} else { |
||||||
|
sqlList += fmt.Sprintf(" and %d <= (a.cash + a.bind_cash) and (a.cash + a.bind_cash) <= %d", CoinLimit[0], CoinLimit[1]) |
||||||
|
sqlCount += fmt.Sprintf(" and %d <= (cash + bind_cash) and (cash + bind_cash) <= %d", CoinLimit[0], CoinLimit[1]) |
||||||
|
sqlTotal += fmt.Sprintf(" and %d <= (cash + bind_cash) and (cash + bind_cash) <= %d", CoinLimit[0], CoinLimit[1]) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
sqlList += fmt.Sprintf(" ORDER BY %v %v LIMIT %v OFFSET %v", order, sort, req.Num, (req.Page-1)*req.Num) |
||||||
|
resp := values.GetGameUserListResp{} |
||||||
|
if err := db.Mysql().C().Raw(sqlList).Scan(&resp.List).Error; err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// isWin := true
|
||||||
|
uids := []interface{}{} |
||||||
|
for i, v := range resp.List { |
||||||
|
lg := &common.LoginRecord{UID: v.UID} |
||||||
|
err := db.Mysql().GetLast(lg) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
resp.List[i].LastLogin = lg.Time |
||||||
|
|
||||||
|
uids = append(uids, v.UID) |
||||||
|
// winCount := models.GetWinGameCountByBalance(nil, nil, &resp.List[i].UID, req.Channel, nil, nil, &isWin)
|
||||||
|
// resp.List[i].GameCount = models.GetGameCountByBalance(nil, nil, &resp.List[i].UID, req.Channel, nil, nil)
|
||||||
|
// resp.List[i].WinPer = utils.GetPer(winCount, resp.List[i].GameCount)
|
||||||
|
|
||||||
|
controlInfo := &common.PlayerControl{UID: v.UID} |
||||||
|
err = db.Mysql().GetLast(controlInfo) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
resp.List[i].ControlInfo = *controlInfo |
||||||
|
|
||||||
|
data := common.CurrencyBalance{} |
||||||
|
q := elastic.NewBoolQuery() |
||||||
|
q.Filter(elastic.NewRangeQuery("uid").Gte(resp.List[i].UID)) |
||||||
|
q.Filter(elastic.NewRangeQuery("uid").Lt(resp.List[i].UID + 1)) |
||||||
|
q.Filter(elastic.NewRangeQuery("event").Gte(common.CurrencyEventGameSettle)) |
||||||
|
q.Filter(elastic.NewRangeQuery("event").Lt(common.CurrencyEventGameBet)) |
||||||
|
err = db.ES().QueryOne(common.ESIndexBalance, q, &data, "id", false) |
||||||
|
if err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
resp.List[i].PlayerStatus = nil |
||||||
|
} else { |
||||||
|
if data.Time >= (time.Now().Unix() - 60) { |
||||||
|
resp.List[i].PlayerStatus = map[string]string{ |
||||||
|
"gameId": data.Desc, |
||||||
|
"roomId": data.RoomName, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
user, _ := call.GetUserInfo(v.UID) |
||||||
|
resp.List[i].AccountCount = int(db.Mysql().Count(&common.PlayerDBInfo{}, fmt.Sprintf("deviceid = '%v'", user.DeviceId))) |
||||||
|
} |
||||||
|
|
||||||
|
total := models.GetGameCountByUIDs(uids, false) |
||||||
|
win := models.GetGameCountByUIDs(uids, true) |
||||||
|
for i, v := range resp.List { |
||||||
|
for _, u := range total.Buckets { |
||||||
|
if util.GetInt(u.Key) == v.UID { |
||||||
|
resp.List[i].GameCount = int64(u.Doc_count) |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
var winCount int64 |
||||||
|
for _, u := range win.Buckets { |
||||||
|
if util.GetInt(u.Key) == v.UID { |
||||||
|
winCount = int64(u.Doc_count) |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
resp.List[i].WinPer = utils.GetPer(winCount, resp.List[i].GameCount) |
||||||
|
} |
||||||
|
|
||||||
|
if err := db.Mysql().C().Raw(sqlCount).Scan(&resp.Count).Error; err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
if err := db.Mysql().C().Raw(sqlTotal).Scan(&resp.Total).Error; err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
resp.Total.WithdrawPlayerPer = utils.GetPer(resp.Total.WithdrawPlayerCount, resp.Count) |
||||||
|
|
||||||
|
resp.Total.UnRechargePlayerCash, resp.Total.UnRechargePlayerAmount = models.GetUnRechargePlayerAmount(req.Channel, su, eu) |
||||||
|
|
||||||
|
a.Data = resp |
||||||
|
} |
||||||
@ -0,0 +1,53 @@ |
|||||||
|
package guser |
||||||
|
|
||||||
|
import ( |
||||||
|
"server/common" |
||||||
|
"server/db" |
||||||
|
"server/modules/backend/values" |
||||||
|
"server/modules/customer/app" |
||||||
|
|
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
) |
||||||
|
|
||||||
|
func GetGameUserPlayData(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.GetGameUserPlayDataReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
var ret []common.CurrencyBalance |
||||||
|
|
||||||
|
var count int64 |
||||||
|
var err error |
||||||
|
if req.Games != nil { |
||||||
|
count, err = db.ES().QueryPlayerBalance(req.UID, req.Page-1, req.Num, int(common.CurrencyEventGameSettle), req.Start, req.End, &ret, *req.Games) |
||||||
|
} else { |
||||||
|
count, err = db.ES().QueryPlayerBalance(req.UID, req.Page-1, req.Num, int(common.CurrencyEventGameSettle), req.Start, req.End, &ret) |
||||||
|
} |
||||||
|
if err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
resp := values.GetGameUserPlayDataResp{ |
||||||
|
List: []values.OneGameUserPlayData{}, |
||||||
|
Count: count, |
||||||
|
} |
||||||
|
for _, v := range ret { |
||||||
|
resp.List = append(resp.List, values.OneGameUserPlayData{ |
||||||
|
Time: v.Time, |
||||||
|
GameID: v.Desc, |
||||||
|
RoomName: v.RoomName, |
||||||
|
Value: v.Value, |
||||||
|
Balance: v.Balance, |
||||||
|
UUID: v.Extern, |
||||||
|
ControlType: v.ControlType, |
||||||
|
DramaID: v.CardsLevel, |
||||||
|
}) |
||||||
|
} |
||||||
|
a.Data = resp |
||||||
|
} |
||||||
@ -0,0 +1 @@ |
|||||||
|
package guser |
||||||
@ -0,0 +1,62 @@ |
|||||||
|
package guser |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"server/common" |
||||||
|
"server/db" |
||||||
|
utils "server/modules/backend/util" |
||||||
|
"server/modules/backend/values" |
||||||
|
"server/modules/customer/app" |
||||||
|
|
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
) |
||||||
|
|
||||||
|
func GetGameUserRechargeHistory(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.GetGameUserRechargeHistoryReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
resp := values.GetGameUserRechargeHistoryResp{} |
||||||
|
var ret []common.RechargeOrder |
||||||
|
if req.UID > 0 { |
||||||
|
count, err := db.Mysql().QueryPlayerRWHistory(&req.UID, nil, req.Page-1, req.Num, []int{int(common.CurrencyEventReCharge), common.CurrencyEventGMRecharge}, req.Start, req.End, &ret, req.Status) |
||||||
|
if err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
resp.Count = count |
||||||
|
for _, v := range ret { |
||||||
|
resp.List = append(resp.List, values.OneRechargeList{UID: v.UID, Time: v.CreatedAt.Unix(), CallbackTime: v.CallbackTime, |
||||||
|
Amount: v.Amount, Status: int(v.Status), MyOrderID: v.OrderID, OrderID: v.APIPayID, PayChannel: v.PayChannel, PaySource: v.PaySource}) |
||||||
|
} |
||||||
|
|
||||||
|
resp.RechargeCount = db.Mysql().Count(&common.RechargeOrder{}, fmt.Sprintf("uid = %v and (event = %v or event = %v)", req.UID, common.CurrencyEventReCharge, common.CurrencyEventGMRecharge)) |
||||||
|
re := &common.RechargeInfo{UID: req.UID} |
||||||
|
err = db.Mysql().Get(re) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
resp.RechargeTotal = re.TotalCharge |
||||||
|
successCount := db.Mysql().Count(&common.RechargeOrder{}, fmt.Sprintf("uid = %v and (event = %v or event = %v) and status = %v", req.UID, common.CurrencyEventReCharge, common.CurrencyEventGMRecharge, common.StatusROrderPay)) |
||||||
|
resp.RechargeSuccessPer = utils.GetPer(successCount, resp.RechargeCount) |
||||||
|
} else if req.OrderID != "" { |
||||||
|
resp.Count, _ = db.Mysql().QueryList(req.Page-1, req.Num, fmt.Sprintf(`event = %v and (apipayid = "%v" or orderid = "%v")`, common.CurrencyEventReCharge, req.OrderID, req.OrderID), "created_at desc", &common.RechargeOrder{}, &ret) |
||||||
|
// log.Debug("ret:%v", ret)
|
||||||
|
for _, v := range ret { |
||||||
|
resp.List = append(resp.List, values.OneRechargeList{UID: v.UID, Time: v.CreatedAt.Unix(), CallbackTime: v.CallbackTime, |
||||||
|
MyOrderID: v.OrderID, OrderID: v.APIPayID, Amount: v.Amount, Status: int(v.Status), PayChannel: v.PayChannel, PaySource: v.PaySource}) |
||||||
|
} |
||||||
|
} else { |
||||||
|
a.Code = values.CodeParam |
||||||
|
a.Msg = "查询条件有误" |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
a.Data = resp |
||||||
|
} |
||||||
@ -0,0 +1 @@ |
|||||||
|
package guser |
||||||
@ -0,0 +1,243 @@ |
|||||||
|
package guser |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"server/common" |
||||||
|
"server/db" |
||||||
|
"server/modules/backend/models" |
||||||
|
utils "server/modules/backend/util" |
||||||
|
"server/modules/backend/values" |
||||||
|
"server/modules/customer/app" |
||||||
|
"time" |
||||||
|
|
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
) |
||||||
|
|
||||||
|
// 流失玩家数据
|
||||||
|
func LostUserData(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.LostUserDataReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
resp := values.LostUserDataResp{} |
||||||
|
|
||||||
|
su, eu := utils.GetQueryUnix(req.Start, req.End) |
||||||
|
|
||||||
|
switch req.Sort { |
||||||
|
case 1: |
||||||
|
resp.Count, resp.List = getAllLostUser(su, eu, req.Page, req.Num, req.Channel) |
||||||
|
case 2: |
||||||
|
resp.Count, resp.List = getPayLostUser(su, eu, req.Page, req.Num, req.Channel) |
||||||
|
case 3: |
||||||
|
resp.Count, resp.List = getActiveLostUser(su, eu, req.Page, req.Num, req.Channel) |
||||||
|
case 4: |
||||||
|
resp.Count, resp.List = getNewLostUser(su, eu, req.Page, req.Num, req.Channel) |
||||||
|
default: |
||||||
|
resp.Count, resp.List = getAllLostUser(su, eu, req.Page, req.Num, req.Channel) |
||||||
|
} |
||||||
|
|
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
// 获取所有流失用户
|
||||||
|
func getAllLostUser(su, eu int64, page, num int, channel *int) (int64, []values.LostUserData) { |
||||||
|
var oneDay = 24 * 60 * 60 |
||||||
|
now := time.Now().Unix() |
||||||
|
|
||||||
|
queryUser := " SELECT u.id, u.nick, u.bind_cash, u.cash, u.birth FROM users u LEFT JOIN (SELECT a.* FROM login_record a INNER JOIN ( SELECT uid, MAX( created_at ) created_at FROM login_record WHERE UNIX_TIMESTAMP(date) >= %d GROUP BY uid ) b ON a.uid = b.uid AND a.created_at = b.created_at WHERE a.uid = b.uid AND a.created_at = b.created_at AND UNIX_TIMESTAMP(a.date) >= %d) r ON u.id = r.uid WHERE " |
||||||
|
queryCount := " SELECT COUNT(DISTINCT(u.id)) FROM users u LEFT JOIN (SELECT a.* FROM login_record a INNER JOIN ( SELECT uid, MAX( created_at ) created_at FROM login_record WHERE UNIX_TIMESTAMP(date) >= %d GROUP BY uid ) b ON a.uid = b.uid AND a.created_at = b.created_at WHERE a.uid = b.uid AND a.created_at = b.created_at AND UNIX_TIMESTAMP(a.date) >= %d) r ON u.id = r.uid WHERE " |
||||||
|
|
||||||
|
str := fmt.Sprintf(" u.birth >= %d AND u.birth < %d ", su, eu) |
||||||
|
|
||||||
|
if channel != nil { |
||||||
|
str += fmt.Sprintf(" AND u.channel_id = %d AND r.channel_id = %d", *channel, *channel) |
||||||
|
} |
||||||
|
|
||||||
|
// 七天未登录的用户 UNIX_TIMESTAMP('20210816')
|
||||||
|
str += fmt.Sprintf(" AND (%d - UNIX_TIMESTAMP(r.date) > %d ) ", now, 7*oneDay) |
||||||
|
|
||||||
|
var count int64 |
||||||
|
err := db.Mysql().QueryBySql(fmt.Sprintf(queryCount+str, su, su), &count) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
return 0, nil |
||||||
|
} |
||||||
|
|
||||||
|
str += " GROUP BY u.id " |
||||||
|
|
||||||
|
str += fmt.Sprintf(" LIMIT %d, %d ", (page-1)*num, num) |
||||||
|
|
||||||
|
var users []common.PlayerDBInfo |
||||||
|
err = db.Mysql().QueryBySql(fmt.Sprintf(queryUser+str, su, su), &users) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
return 0, nil |
||||||
|
} |
||||||
|
|
||||||
|
return count, getLostUserInfo(users) |
||||||
|
} |
||||||
|
|
||||||
|
// 获取付费流失用户
|
||||||
|
func getPayLostUser(su, eu int64, page, num int, channel *int) (int64, []values.LostUserData) { |
||||||
|
var oneDay = 24 * 60 * 60 |
||||||
|
now := time.Now().Unix() |
||||||
|
|
||||||
|
queryUser := " SELECT u.id, u.nick, u.bind_cash, u.cash, u.birth FROM users u LEFT JOIN (SELECT a.* FROM login_record a INNER JOIN ( SELECT uid, MAX( created_at ) created_at FROM login_record WHERE UNIX_TIMESTAMP(date) >= %d GROUP BY uid ) b ON a.uid = b.uid AND a.created_at = b.created_at WHERE a.uid = b.uid AND a.created_at = b.created_at AND UNIX_TIMESTAMP(a.date) >= %d) r ON u.id = r.uid LEFT JOIN (SELECT * FROM recharge_order WHERE `event` = %d AND `status` = %d AND callback_time > %d) re ON u.id = re.uid WHERE u.id = re.uid AND " |
||||||
|
queryCount := " SELECT COUNT(DISTINCT(u.id)) FROM users u LEFT JOIN (SELECT a.* FROM login_record a INNER JOIN ( SELECT uid, MAX( created_at ) created_at FROM login_record WHERE UNIX_TIMESTAMP(date) >= %d GROUP BY uid ) b ON a.uid = b.uid AND a.created_at = b.created_at WHERE a.uid = b.uid AND a.created_at = b.created_at AND UNIX_TIMESTAMP(a.date) >= %d) r ON u.id = r.uid LEFT JOIN (SELECT * FROM recharge_order WHERE `event` = %d AND `status` = %d AND callback_time > %d) re ON u.id = re.uid WHERE u.id = re.uid AND " |
||||||
|
|
||||||
|
str := fmt.Sprintf(" u.birth >= %d AND u.birth < %d ", su, eu) |
||||||
|
|
||||||
|
if channel != nil { |
||||||
|
str += fmt.Sprintf(" AND u.channel_id = %d AND r.channel_id = %d", *channel, *channel) |
||||||
|
} |
||||||
|
|
||||||
|
// 三天未登录的用户 UNIX_TIMESTAMP('20210816')
|
||||||
|
str += fmt.Sprintf(" AND (%d - UNIX_TIMESTAMP(r.date) > %d ) ", now, 7*oneDay) |
||||||
|
|
||||||
|
var count int64 |
||||||
|
err := db.Mysql().QueryBySql(fmt.Sprintf(queryCount+str, su, su, common.CurrencyEventReCharge, common.StatusROrderPay, su), &count) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
return 0, nil |
||||||
|
} |
||||||
|
|
||||||
|
str += " GROUP BY u.id " |
||||||
|
|
||||||
|
str += fmt.Sprintf(" LIMIT %d, %d ", (page-1)*num, num) |
||||||
|
|
||||||
|
var users []common.PlayerDBInfo |
||||||
|
err = db.Mysql().QueryBySql(fmt.Sprintf(queryUser+str, su, su, common.CurrencyEventReCharge, common.StatusROrderPay, su), &users) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
return 0, nil |
||||||
|
} |
||||||
|
|
||||||
|
return count, getLostUserInfo(users) |
||||||
|
} |
||||||
|
|
||||||
|
// 获取活跃流失用户
|
||||||
|
func getActiveLostUser(su, eu int64, page, num int, channel *int) (int64, []values.LostUserData) { |
||||||
|
var oneDay = 24 * 60 * 60 |
||||||
|
now := time.Now().Unix() |
||||||
|
|
||||||
|
queryUser := fmt.Sprintf(" SELECT u.id, u.nick, u.bind_cash, u.cash, u.birth FROM users u LEFT JOIN ( SELECT uid, MAX(date) date, MAX( created_at ) created_at FROM login_record WHERE UNIX_TIMESTAMP(date) >= %d GROUP BY uid ) b ON u.id = b.uid WHERE u.id = b.uid AND ", su) + |
||||||
|
" FROM_UNIXTIME(u.birth,'%Y%m%d') != b.date AND " |
||||||
|
queryCount := fmt.Sprintf(" SELECT COUNT(DISTINCT(u.id)) FROM users u LEFT JOIN ( SELECT uid, MAX(date) date, MAX( created_at ) created_at FROM login_record WHERE UNIX_TIMESTAMP(date) >= %d GROUP BY uid ) b ON u.id = b.uid WHERE u.id = b.uid AND ", su) + |
||||||
|
" FROM_UNIXTIME(u.birth,'%Y%m%d') != b.date AND " |
||||||
|
|
||||||
|
str := fmt.Sprintf(" u.birth >= %d AND u.birth < %d ", su, eu) |
||||||
|
|
||||||
|
if channel != nil { |
||||||
|
str += fmt.Sprintf(" AND u.channel_id = %d AND b.channel_id = %d", *channel, *channel) |
||||||
|
} |
||||||
|
|
||||||
|
// 七天未登录的用户 UNIX_TIMESTAMP('20210816')
|
||||||
|
str += fmt.Sprintf(" AND (%d - UNIX_TIMESTAMP(b.date) > %d ) ", now, 7*oneDay) |
||||||
|
|
||||||
|
var count int64 |
||||||
|
err := db.Mysql().QueryBySql(queryCount+str, &count) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
return 0, nil |
||||||
|
} |
||||||
|
|
||||||
|
str += " GROUP BY u.id " |
||||||
|
|
||||||
|
str += fmt.Sprintf(" LIMIT %d, %d ", (page-1)*num, num) |
||||||
|
|
||||||
|
var users []common.PlayerDBInfo |
||||||
|
err = db.Mysql().QueryBySql(queryUser+str, &users) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
return 0, nil |
||||||
|
} |
||||||
|
|
||||||
|
return count, getLostUserInfo(users) |
||||||
|
} |
||||||
|
|
||||||
|
// 获取新用户流失
|
||||||
|
func getNewLostUser(su, eu int64, page, num int, channel *int) (int64, []values.LostUserData) { |
||||||
|
|
||||||
|
queryUser := fmt.Sprintf(" SELECT u.id, u.nick, u.bind_cash, u.cash, u.birth FROM users u LEFT JOIN ( SELECT uid, MAX( created_at ) created_at, MAX(date) date FROM login_record WHERE UNIX_TIMESTAMP(date) >= %d GROUP BY uid ) b ON u.id = b.uid WHERE u.id = b.uid ", su) + |
||||||
|
"AND FROM_UNIXTIME(u.birth,'%Y%m%d') = b.date AND" |
||||||
|
queryCount := fmt.Sprintf(" SELECT COUNT(DISTINCT(u.id)) FROM users u LEFT JOIN ( SELECT uid, MAX( created_at )created_at, MAX(date) date FROM login_record WHERE UNIX_TIMESTAMP(date) >= %d GROUP BY uid ) b ON u.id = b.uid WHERE u.id = b.uid ", su) + |
||||||
|
"AND FROM_UNIXTIME(u.birth,'%Y%m%d') = b.date AND" |
||||||
|
|
||||||
|
str := fmt.Sprintf(" u.birth >= %d AND u.birth < %d ", su, eu) |
||||||
|
if channel != nil { |
||||||
|
str += fmt.Sprintf(" AND u.channel_id = %d ", *channel) |
||||||
|
str += fmt.Sprintf(" AND u.channel_id = %d ", *channel) |
||||||
|
} |
||||||
|
|
||||||
|
// 7天未登录的用户 UNIX_TIMESTAMP('20210816')
|
||||||
|
str += fmt.Sprintf(" AND (%d - UNIX_TIMESTAMP(b.date) > %d ) ", time.Now().Unix(), 7*24*60*60) |
||||||
|
|
||||||
|
var count int64 |
||||||
|
err := db.Mysql().QueryBySql(queryCount+str, &count) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
return 0, nil |
||||||
|
} |
||||||
|
|
||||||
|
str += fmt.Sprintf(" LIMIT %d, %d ", (page-1)*num, num) |
||||||
|
|
||||||
|
var users []common.PlayerDBInfo |
||||||
|
err = db.Mysql().QueryBySql(queryUser+str, &users) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
return 0, nil |
||||||
|
} |
||||||
|
|
||||||
|
return count, getLostUserInfo(users) |
||||||
|
} |
||||||
|
|
||||||
|
func getLostUserInfo(users []common.PlayerDBInfo) []values.LostUserData { |
||||||
|
var res []values.LostUserData |
||||||
|
for i := 0; i < len(users); i++ { |
||||||
|
var data values.LostUserData |
||||||
|
|
||||||
|
// 用户昵称
|
||||||
|
data.Nick = users[i].Nick |
||||||
|
// 用户uid
|
||||||
|
data.Uid = users[i].Id |
||||||
|
// 用户生日
|
||||||
|
data.Birth = users[i].Birth |
||||||
|
|
||||||
|
var record common.LoginRecord |
||||||
|
err := db.Mysql().C().Model(&common.LoginRecord{}).Where(" uid = ?", users[i].Id).Last(&record).Error |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
// 最后登录时间
|
||||||
|
data.LastLogin = record.Time |
||||||
|
// 玩家游戏局数
|
||||||
|
data.GameCount = models.GetGameCountByBalance(nil, nil, &users[i].Id, nil, nil, nil) |
||||||
|
// 玩家剩余账户金额
|
||||||
|
data.Amount = users[i].BindCash + users[i].Cash |
||||||
|
// 玩家账户可提现金额
|
||||||
|
data.Cash = users[i].Cash |
||||||
|
// 玩家总提现金额
|
||||||
|
data.WithDrawAmount = getPlayerAmountBySql(users[i].Id, int(common.CurrencyEventWithDraw), common.StatusROrderFinish) |
||||||
|
// 玩家总充值金额
|
||||||
|
data.RechargeAmount = getPlayerAmountBySql(users[i].Id, int(common.CurrencyEventReCharge), common.StatusROrderPay) |
||||||
|
|
||||||
|
res = append(res, data) |
||||||
|
} |
||||||
|
return res |
||||||
|
} |
||||||
|
|
||||||
|
// 获取玩家充值金额
|
||||||
|
func getPlayerAmountBySql(uid, event, status int) int64 { |
||||||
|
var amount int64 |
||||||
|
amountTotal := "SELECT IFNULL(SUM(amount),0) as Amount FROM recharge_order WHERE uid = %d AND event = %v AND status = %v " |
||||||
|
err := db.Mysql().QueryBySql(fmt.Sprintf(amountTotal, uid, event, status), &amount) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
return amount |
||||||
|
} |
||||||
@ -0,0 +1,48 @@ |
|||||||
|
package guser |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"server/common" |
||||||
|
"server/modules/backend/models" |
||||||
|
utils "server/modules/backend/util" |
||||||
|
"server/modules/backend/values" |
||||||
|
"server/modules/customer/app" |
||||||
|
) |
||||||
|
|
||||||
|
func LostUserDetail(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.LostUserDetailReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
resp := values.LostUserDetailResp{} |
||||||
|
|
||||||
|
for i := 0; i < len(common.RoomGameIDs); i++ { |
||||||
|
resp.List = append(resp.List, getLostUserDetail(req.Uid, common.RoomGameIDs[i])) |
||||||
|
} |
||||||
|
|
||||||
|
for i := 0; i < len(common.MillionGameIDs); i++ { |
||||||
|
resp.List = append(resp.List, getLostUserDetail(req.Uid, common.MillionGameIDs[i].(int))) |
||||||
|
} |
||||||
|
|
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
func getLostUserDetail(uid int, gameId int) values.LostUserDetail { |
||||||
|
var lostUserDetail values.LostUserDetail |
||||||
|
|
||||||
|
lostUserDetail.GameId = gameId |
||||||
|
|
||||||
|
isWin := true |
||||||
|
winCount := models.GetWinGameCountByBalance(nil, nil, &uid, nil, &gameId, nil, &isWin) |
||||||
|
lostUserDetail.GameCount = models.GetGameCountByBalance(nil, nil, &uid, nil, &gameId, nil) |
||||||
|
|
||||||
|
lostUserDetail.WinPer = utils.GetPer(winCount, lostUserDetail.GameCount) |
||||||
|
|
||||||
|
lostUserDetail.BreakPer = utils.GetPer(models.GetPlayerBreakCount(nil, nil, &uid, &gameId, nil, nil), lostUserDetail.GameCount) |
||||||
|
|
||||||
|
return lostUserDetail |
||||||
|
} |
||||||
@ -0,0 +1,96 @@ |
|||||||
|
package guser |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
"server/call" |
||||||
|
"server/common" |
||||||
|
"server/db" |
||||||
|
utils "server/modules/backend/util" |
||||||
|
"server/modules/backend/values" |
||||||
|
"server/modules/customer/app" |
||||||
|
) |
||||||
|
|
||||||
|
// 充值排行榜
|
||||||
|
func RechargeRank(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.RechargeRankReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
su, eu := utils.GetQueryUnix(req.Start, req.End) |
||||||
|
resp := values.RechargeRankResp{} |
||||||
|
|
||||||
|
var num int64 = 100 |
||||||
|
if req.Num != nil { |
||||||
|
num = *req.Num |
||||||
|
} |
||||||
|
|
||||||
|
var str string |
||||||
|
|
||||||
|
if req.Status == 1 { |
||||||
|
str = fmt.Sprintf("SELECT uid, SUM(amount) AS amount, COUNT(amount) as event FROM recharge_order WHERE event = %d AND status = %d AND callback_time >= %d AND callback_time < %d GROUP BY uid ORDER BY amount DESC LIMIT 0, %d", |
||||||
|
common.CurrencyEventReCharge, |
||||||
|
common.StatusROrderPay, |
||||||
|
su, |
||||||
|
eu, |
||||||
|
num) |
||||||
|
} else { |
||||||
|
str = fmt.Sprintf("SELECT uid, SUM(amount) AS amount, COUNT(amount) as event FROM recharge_order WHERE event = %d AND status = %d AND callback_time >= %d AND callback_time < %d GROUP BY uid ORDER BY amount DESC LIMIT 0, %d", |
||||||
|
common.CurrencyEventWithDraw, |
||||||
|
common.StatusROrderFinish, |
||||||
|
su, |
||||||
|
eu, |
||||||
|
num) |
||||||
|
} |
||||||
|
|
||||||
|
var users []common.RechargeOrder |
||||||
|
|
||||||
|
err := db.Mysql().QueryBySql(str, &users) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
for i := 0; i < len(users); i++ { |
||||||
|
var temp values.RechargeRank |
||||||
|
temp.Date = su |
||||||
|
temp.Uid = users[i].UID |
||||||
|
if req.Status == 1 { |
||||||
|
temp.TodayRechargeAmount = users[i].Amount |
||||||
|
temp.TodayRechargeOrderCount = int64(users[i].Event) |
||||||
|
|
||||||
|
sql := fmt.Sprintf("event = %v and status = %v and callback_time >= '%v' and callback_time < '%v' and uid = %v", common.CurrencyEventWithDraw, common.StatusROrderFinish, su, eu, users[i].UID) |
||||||
|
temp.TodayWithDrawAmount = db.Mysql().Sum(&common.RechargeOrder{}, sql, "amount") |
||||||
|
temp.TodayWithDrawOrderCount = db.Mysql().Count(&common.RechargeOrder{}, sql) |
||||||
|
} else { |
||||||
|
temp.TodayWithDrawAmount = users[i].Amount |
||||||
|
temp.TodayWithDrawOrderCount = int64(users[i].Event) |
||||||
|
|
||||||
|
sql := fmt.Sprintf("event = %v and status = %v and callback_time >= '%v' and callback_time < '%v' and uid = %v", common.CurrencyEventReCharge, common.StatusROrderPay, su, eu, users[i].UID) |
||||||
|
temp.TodayRechargeAmount = db.Mysql().Sum(&common.RechargeOrder{}, sql, "amount") |
||||||
|
temp.TodayRechargeOrderCount = db.Mysql().Count(&common.RechargeOrder{}, sql) |
||||||
|
} |
||||||
|
|
||||||
|
// 玩家总提现金额
|
||||||
|
temp.WithDrawAmount = getPlayerAmountBySql(users[i].UID, int(common.CurrencyEventWithDraw), common.StatusROrderFinish) |
||||||
|
// 玩家总充值金额
|
||||||
|
temp.RechargeAmount = getPlayerAmountBySql(users[i].UID, int(common.CurrencyEventReCharge), common.StatusROrderPay) |
||||||
|
// 玩家生日
|
||||||
|
res, _ := call.GetUserInfo(users[i].UID) |
||||||
|
temp.Birth = res.Birth |
||||||
|
|
||||||
|
// 用户渠道
|
||||||
|
temp.Channel = users[i].ChannelID |
||||||
|
|
||||||
|
resp.List = append(resp.List, &temp) |
||||||
|
} |
||||||
|
resp.Count = int64(len(users)) |
||||||
|
|
||||||
|
a.Data = resp |
||||||
|
} |
||||||
@ -0,0 +1,208 @@ |
|||||||
|
package handler |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"server/modules/customer/app" |
||||||
|
"server/modules/customer/bdb" |
||||||
|
"server/modules/customer/values" |
||||||
|
|
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
) |
||||||
|
|
||||||
|
func UserList(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
resp := values.UserListResp{} |
||||||
|
if err := bdb.BackDB.C().Find(&resp.List).Error; err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
func AddUser(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.AddUserReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
log.Debug("adduser:%+v", req) |
||||||
|
if req.Role == values.UserRoleAdmin { |
||||||
|
a.Code = values.CodeParam |
||||||
|
a.Msg = "不可添加超级管理员" |
||||||
|
return |
||||||
|
} |
||||||
|
var roles []*values.Role |
||||||
|
bdb.BackDB.C().Find(&roles) |
||||||
|
var r *values.Role |
||||||
|
for _, v := range roles { |
||||||
|
if req.Role == v.Role { |
||||||
|
r = v |
||||||
|
} |
||||||
|
} |
||||||
|
if r == nil { |
||||||
|
log.Error("invalid role:%v", req.Role) |
||||||
|
a.Code = values.CodeParam |
||||||
|
a.Msg = "请求角色不存在" |
||||||
|
return |
||||||
|
} |
||||||
|
one := &values.User{Name: req.Name, Account: req.Account, Password: req.Password, Role: req.Role, Power: r.Power, Phone: req.Phone, Channels: req.Channels} |
||||||
|
if err := bdb.BackDB.Create(one); err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeParam |
||||||
|
a.Msg = err.Error() |
||||||
|
return |
||||||
|
} |
||||||
|
a.RecordEdit(values.PowerManageUser, fmt.Sprintf("新增用户:%v", req.Name)) |
||||||
|
} |
||||||
|
|
||||||
|
func EditUserPower(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.EditPowerReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
log.Debug("edit power:%+v", req) |
||||||
|
user := new(values.User) |
||||||
|
user.ID = uint(req.ID) |
||||||
|
if err := bdb.BackDB.Get(user); err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeParam |
||||||
|
a.Msg = "账户不存在" |
||||||
|
return |
||||||
|
} |
||||||
|
if user.Role == values.UserRoleAdmin { |
||||||
|
a.Code = values.CodeParam |
||||||
|
a.Msg = "不可修改超级管理员" |
||||||
|
return |
||||||
|
} |
||||||
|
update := map[string]interface{}{} |
||||||
|
if req.Power != nil { |
||||||
|
if !a.CheckPower(*req.Power) { |
||||||
|
return |
||||||
|
} |
||||||
|
update["power"] = *req.Power |
||||||
|
} |
||||||
|
if req.Name != nil { |
||||||
|
update["name"] = *req.Name |
||||||
|
} |
||||||
|
if req.Account != nil { |
||||||
|
update["account"] = *req.Account |
||||||
|
} |
||||||
|
if req.Password != nil { |
||||||
|
update["password"] = *req.Password |
||||||
|
} |
||||||
|
if req.Role != nil { |
||||||
|
if *req.Role == values.UserRoleAdmin { |
||||||
|
a.Code = values.CodeParam |
||||||
|
a.Msg = "不可修改为超级管理员" |
||||||
|
return |
||||||
|
} |
||||||
|
update["role"] = *req.Role |
||||||
|
} |
||||||
|
if req.Phone != nil { |
||||||
|
update["phone"] = *req.Phone |
||||||
|
} |
||||||
|
if req.Channels != nil { |
||||||
|
update["channels"] = *req.Channels |
||||||
|
} |
||||||
|
if len(update) == 0 { |
||||||
|
a.Code = values.CodeParam |
||||||
|
a.Msg = "无内容修改" |
||||||
|
return |
||||||
|
} |
||||||
|
if err := bdb.BackDB.Update(&values.User{ID: uint(req.ID)}, update); err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
a.RecordEdit(values.PowerManageUser, fmt.Sprintf("修改用户权限:%v", req.ID)) |
||||||
|
} |
||||||
|
|
||||||
|
func DelUser(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.DelUserReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
user := new(values.User) |
||||||
|
user.ID = uint(req.ID) |
||||||
|
if err := bdb.BackDB.C().Delete(user).Where("id = ?", req.ID).Error; err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func RoleList(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
resp := values.RoleListResp{} |
||||||
|
if err := bdb.BackDB.C().Find(&resp.List).Error; err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
func AddRole(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.AddRoleReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
if !a.CheckPower(req.Power) { |
||||||
|
return |
||||||
|
} |
||||||
|
one := &values.Role{Role: req.Role, Name: req.Name, Power: req.Power} |
||||||
|
if err := bdb.BackDB.Create(one); err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
a.RecordEdit(values.PowerManageRole, fmt.Sprintf("新增角色:%v", req.Name)) |
||||||
|
} |
||||||
|
|
||||||
|
func EditRole(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.Response() |
||||||
|
}() |
||||||
|
req := new(values.EditRoleReq) |
||||||
|
if !a.S(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
if !a.CheckPower(req.Power) { |
||||||
|
return |
||||||
|
} |
||||||
|
one := &values.Role{Role: req.Role, Name: req.Name, Power: req.Power} |
||||||
|
if err := bdb.BackDB.Update(&values.Role{ID: uint(req.ID)}, one); err != nil { |
||||||
|
log.Error("err:%v", err) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
err := bdb.BackDB.Update(&values.User{Role: req.Role}, map[string]interface{}{"power": req.Power}) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
a.RecordEdit(values.PowerManageRole, fmt.Sprintf("修改角色:%v", req.ID)) |
||||||
|
} |
||||||
@ -0,0 +1,48 @@ |
|||||||
|
package middleware |
||||||
|
|
||||||
|
import ( |
||||||
|
"net/http" |
||||||
|
"server/modules/customer/app" |
||||||
|
|
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
) |
||||||
|
|
||||||
|
// 跨域访问:cross origin resource share
|
||||||
|
func CrosHandler() gin.HandlerFunc { |
||||||
|
return func(context *gin.Context) { |
||||||
|
method := context.Request.Method |
||||||
|
origin := context.Request.Header.Get("Origin") // 请求头部
|
||||||
|
if origin != "" { |
||||||
|
// 接收客户端发送的origin (重要!)
|
||||||
|
context.Writer.Header().Set("Access-Control-Allow-Origin", "*") |
||||||
|
|
||||||
|
// 设置允许访问所有域
|
||||||
|
context.Header("Access-Control-Allow-Origin", "*") |
||||||
|
|
||||||
|
// 服务器支持的所有跨域请求的方法
|
||||||
|
context.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE") |
||||||
|
|
||||||
|
// 允许跨域设置可以返回其他子段,可以自定义字段
|
||||||
|
context.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma,token,openid,opentoken,istoken") |
||||||
|
|
||||||
|
// 允许浏览器(客户端)可以解析的头部 (重要)
|
||||||
|
context.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar") |
||||||
|
|
||||||
|
// 设置缓存时间
|
||||||
|
context.Header("Access-Control-Max-Age", "172800") |
||||||
|
|
||||||
|
// 允许客户端传递校验信息比如 cookie (重要)
|
||||||
|
context.Header("Access-Control-Allow-Credentials", "true") |
||||||
|
|
||||||
|
// 设置返回格式是json
|
||||||
|
context.Set("content-type", "application/json") |
||||||
|
} |
||||||
|
|
||||||
|
if method == "OPTIONS" { |
||||||
|
context.JSON(http.StatusOK, app.R{Code: http.StatusOK, Data: "Options Request!"}) |
||||||
|
} |
||||||
|
|
||||||
|
// 处理请求
|
||||||
|
context.Next() |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,68 @@ |
|||||||
|
package middleware |
||||||
|
|
||||||
|
import ( |
||||||
|
"server/modules/customer/app" |
||||||
|
"server/modules/customer/bdb" |
||||||
|
"server/modules/customer/values" |
||||||
|
"strings" |
||||||
|
|
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
) |
||||||
|
|
||||||
|
// 进行权限校验
|
||||||
|
func PowerMiddleWare() gin.HandlerFunc { |
||||||
|
return func(c *gin.Context) { |
||||||
|
path := c.Request.RequestURI |
||||||
|
if PassURL(path) { |
||||||
|
c.Next() |
||||||
|
return |
||||||
|
} |
||||||
|
a := app.NewApp(c) |
||||||
|
if !powerPass(a.User, path) { |
||||||
|
a.Code = values.CodePower |
||||||
|
a.Response() |
||||||
|
c.Abort() |
||||||
|
return |
||||||
|
} |
||||||
|
c.Next() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func powerPass(u *values.User, path string) bool { |
||||||
|
if u == nil { |
||||||
|
return false |
||||||
|
} |
||||||
|
if u.Role == values.UserRoleAdmin { |
||||||
|
return true |
||||||
|
} |
||||||
|
// 第一步找到主页签
|
||||||
|
p := 0 |
||||||
|
for s, v := range values.PowerMap { |
||||||
|
if strings.Contains(path, s) { |
||||||
|
p = v |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
// 不在权限控制范围
|
||||||
|
if p == 0 { |
||||||
|
return true |
||||||
|
} |
||||||
|
buttons, ok := bdb.GetPowerByRole(u.Role)[p] |
||||||
|
if !ok { |
||||||
|
return false |
||||||
|
} |
||||||
|
pbutton, ok2 := values.PowerButtonMap[p] |
||||||
|
// 该页签没有子按钮
|
||||||
|
if !ok2 { |
||||||
|
return true |
||||||
|
} |
||||||
|
for i, v := range pbutton { |
||||||
|
if v == path { |
||||||
|
if i > len(pbutton)-1 { |
||||||
|
return true |
||||||
|
} |
||||||
|
return buttons[i] == 1 |
||||||
|
} |
||||||
|
} |
||||||
|
return true |
||||||
|
} |
||||||
@ -0,0 +1,21 @@ |
|||||||
|
package middleware |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
"runtime" |
||||||
|
) |
||||||
|
|
||||||
|
func Recovery() gin.HandlerFunc { |
||||||
|
return func(c *gin.Context) { |
||||||
|
defer func() { |
||||||
|
if err := recover(); err != nil { |
||||||
|
buf := make([]byte, 1024) |
||||||
|
runtime.Stack(buf, false) |
||||||
|
log.Error("panic(%+v), stack:\n%s", err, string(buf)) |
||||||
|
return |
||||||
|
} |
||||||
|
}() |
||||||
|
c.Next() |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,93 @@ |
|||||||
|
package middleware |
||||||
|
|
||||||
|
import ( |
||||||
|
"server/common" |
||||||
|
"server/db" |
||||||
|
"server/modules/customer/app" |
||||||
|
"server/modules/customer/values" |
||||||
|
"strings" |
||||||
|
|
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
|
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
) |
||||||
|
|
||||||
|
var ( |
||||||
|
passURLs = map[string]struct{}{ |
||||||
|
"/account/login": {}, |
||||||
|
"/image/download": {}, |
||||||
|
"/gm/customer/config/info": {}, |
||||||
|
} |
||||||
|
) |
||||||
|
|
||||||
|
// 进行token校验
|
||||||
|
func TokenMiddleWare() gin.HandlerFunc { |
||||||
|
return func(c *gin.Context) { |
||||||
|
|
||||||
|
// 检查是否排除当前url
|
||||||
|
|
||||||
|
// exclude := regexp.MustCompile("/static/*")
|
||||||
|
|
||||||
|
path := c.Request.RequestURI |
||||||
|
|
||||||
|
if PassURL(path) { |
||||||
|
c.Next() |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// 对用户的token进行校验 并对token续期
|
||||||
|
token := c.GetHeader("token") |
||||||
|
one := new(values.User) |
||||||
|
if err := db.Redis().GetJsonData(common.GetBackendTokenKey(token), one); err != nil || one.Account == "" { |
||||||
|
app := app.NewApp(c) |
||||||
|
app.Code = values.CodeToken |
||||||
|
app.Msg = "登录已过期,请重新登录" |
||||||
|
app.Response() |
||||||
|
c.Abort() |
||||||
|
return |
||||||
|
} |
||||||
|
// if len(one.Power) > 0 {
|
||||||
|
// err := json.Unmarshal([]byte(one.Power), &one.PowerMap)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Error("err:%v", err)
|
||||||
|
// app := app.NewApp(c)
|
||||||
|
// app.Code = values.CodePower
|
||||||
|
// app.Response()
|
||||||
|
// c.Abort()
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
c.Set("user", one) |
||||||
|
c.Next() |
||||||
|
// 刷新token过期时间
|
||||||
|
defer func() { |
||||||
|
if token == values.AdminToken { |
||||||
|
return |
||||||
|
} |
||||||
|
err := db.Redis().Expire(common.GetBackendTokenKey(token), values.RedisTokenEx) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
}() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// PassURL 过滤url
|
||||||
|
func PassURL(path string) bool { |
||||||
|
index := strings.Index(path, "?") |
||||||
|
if index > 0 { |
||||||
|
path = path[:index] |
||||||
|
} |
||||||
|
_, ok := passURLs[path] |
||||||
|
if !ok { |
||||||
|
// index := strings.LastIndex(path, "/")
|
||||||
|
// url := path[:index+1] + "*"
|
||||||
|
// _, ok = passURLs[url]
|
||||||
|
for k := range passURLs { |
||||||
|
if strings.Contains(path, k) { |
||||||
|
return true |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return ok |
||||||
|
} |
||||||
@ -0,0 +1,113 @@ |
|||||||
|
package customer |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"net/http" |
||||||
|
"server/call" |
||||||
|
"server/config" |
||||||
|
"server/db" |
||||||
|
edb "server/db/es" |
||||||
|
mdb "server/db/mysql" |
||||||
|
rdb "server/db/redis" |
||||||
|
"server/modules/customer/bdb" |
||||||
|
"server/modules/customer/routers" |
||||||
|
"server/util" |
||||||
|
"time" |
||||||
|
|
||||||
|
"github.com/liangdas/mqant/conf" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
"github.com/liangdas/mqant/module" |
||||||
|
basemodule "github.com/liangdas/mqant/module/base" |
||||||
|
) |
||||||
|
|
||||||
|
var ( |
||||||
|
Module = func() module.Module { |
||||||
|
this := new(Customer) |
||||||
|
return this |
||||||
|
} |
||||||
|
BackDB = new(mdb.MysqlClient) |
||||||
|
) |
||||||
|
|
||||||
|
type Customer struct { |
||||||
|
basemodule.BaseModule |
||||||
|
httpSvr *http.Server |
||||||
|
addr string |
||||||
|
} |
||||||
|
|
||||||
|
func (b *Customer) GetType() string { |
||||||
|
// 很关键,需要与配置文件中的Module配置对应
|
||||||
|
return "customer" |
||||||
|
} |
||||||
|
func (b *Customer) Version() string { |
||||||
|
// 可以在监控时了解代码版本
|
||||||
|
return "1.0.0" |
||||||
|
} |
||||||
|
func (b *Customer) OnInit(app module.App, settings *conf.ModuleSettings) { |
||||||
|
b.BaseModule.OnInit(b, app, settings) |
||||||
|
|
||||||
|
call.NewCaller(b) |
||||||
|
|
||||||
|
db.InitDB(&mdb.MysqlClient{}, &rdb.RedisClient{}, &edb.EsClient{}) |
||||||
|
|
||||||
|
bdb.InitMysql() |
||||||
|
|
||||||
|
// 自动初始化后台数据库
|
||||||
|
bdb.MigrateDB() |
||||||
|
|
||||||
|
// 加载配置
|
||||||
|
util.Go(func() { |
||||||
|
loadConfig() |
||||||
|
}) |
||||||
|
|
||||||
|
b.addr = config.GetConfig().Customer.Addr |
||||||
|
|
||||||
|
call.NewSnowflake(int64(config.GetConfig().WorkID)) |
||||||
|
|
||||||
|
call.InitReload(b.App.Transport()) |
||||||
|
} |
||||||
|
|
||||||
|
func (b *Customer) startHttpServer() { |
||||||
|
router := routers.SetUpRouter() |
||||||
|
srv := &http.Server{ |
||||||
|
Addr: b.addr, |
||||||
|
Handler: router, |
||||||
|
} |
||||||
|
|
||||||
|
go func() { |
||||||
|
if err := srv.ListenAndServe(); err != nil { |
||||||
|
panic(err) |
||||||
|
} |
||||||
|
}() |
||||||
|
// returning reference so caller can call Shutdown()
|
||||||
|
b.httpSvr = srv |
||||||
|
} |
||||||
|
|
||||||
|
func (b *Customer) Run(closeSig chan bool) { |
||||||
|
log.Info("customer: starting HTTP server :%s", b.addr) |
||||||
|
call.InitTimeWheel(closeSig) |
||||||
|
call.InitWarn(b.App.Transport()) |
||||||
|
b.startHttpServer() |
||||||
|
<-closeSig |
||||||
|
log.Info("customer: stopping HTTP server") |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
func (b *Customer) OnDestroy() { |
||||||
|
// The context is used to inform the server it has 5 seconds to finish
|
||||||
|
// the request it is currently handling
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) |
||||||
|
defer cancel() |
||||||
|
|
||||||
|
// now close the server gracefully ("shutdown")
|
||||||
|
// timeout could be given instead of nil as a https://golang.org/pkg/context/
|
||||||
|
if err := b.httpSvr.Shutdown(ctx); err != nil { |
||||||
|
log.Error("OnDestroy Customer Shutdown error:%v", err) |
||||||
|
} |
||||||
|
|
||||||
|
log.Info("Customer: done. exiting") |
||||||
|
|
||||||
|
// 一定别忘了继承
|
||||||
|
b.BaseModule.OnDestroy() |
||||||
|
|
||||||
|
log.Info("Customer 模块已销毁") |
||||||
|
} |
||||||
@ -0,0 +1,35 @@ |
|||||||
|
package routers |
||||||
|
|
||||||
|
import ( |
||||||
|
"server/config" |
||||||
|
"server/modules/customer/middleware" |
||||||
|
|
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
) |
||||||
|
|
||||||
|
func SetUpRouter() *gin.Engine { |
||||||
|
release := config.GetBase().Release |
||||||
|
if release { |
||||||
|
gin.SetMode(gin.ReleaseMode) |
||||||
|
// 禁用控制台颜色
|
||||||
|
gin.DisableConsoleColor() |
||||||
|
} else { |
||||||
|
gin.SetMode(gin.DebugMode) |
||||||
|
} |
||||||
|
r := gin.New() |
||||||
|
// 跨域处理
|
||||||
|
r.Use(middleware.CrosHandler()) |
||||||
|
r.Use(middleware.TokenMiddleWare()) |
||||||
|
r.Use(middleware.PowerMiddleWare()) |
||||||
|
r.Use(middleware.Recovery()) |
||||||
|
|
||||||
|
gmHandle(r) |
||||||
|
account(r) |
||||||
|
power(r) |
||||||
|
common(r) |
||||||
|
chat(r) |
||||||
|
mail(r) |
||||||
|
guser(r) |
||||||
|
|
||||||
|
return r |
||||||
|
} |
||||||
@ -0,0 +1,11 @@ |
|||||||
|
// 账号相关的接口
|
||||||
|
package routers |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
handler "server/modules/customer/handler/account" |
||||||
|
) |
||||||
|
|
||||||
|
func account(e *gin.Engine) { |
||||||
|
e.POST("/account/login", handler.Login) |
||||||
|
} |
||||||
@ -0,0 +1,42 @@ |
|||||||
|
package routers |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
handler2 "server/modules/backend/handler/guser" |
||||||
|
handler "server/modules/customer/handler/chat" |
||||||
|
) |
||||||
|
|
||||||
|
func chat(e *gin.Engine) { |
||||||
|
// 工单分配
|
||||||
|
e.POST("/order/allocate", handler.CustomerOrderAllocate) |
||||||
|
|
||||||
|
// 聊天历史
|
||||||
|
e.POST("/customer/history", handler.GetCustomerHistory) |
||||||
|
|
||||||
|
// 消息已读
|
||||||
|
e.POST("/customer/read/message", handler.ReadMessage) |
||||||
|
|
||||||
|
// 发送消息
|
||||||
|
e.POST("/customer/send/message", handler.SendMessage) |
||||||
|
|
||||||
|
// 工单列表
|
||||||
|
e.POST("/customer/order/list", handler.GetCustomerOrder) |
||||||
|
|
||||||
|
// 改变工单状态
|
||||||
|
e.POST("/customer/order/change", handler.ChangeCustomerOrderStatus) |
||||||
|
|
||||||
|
// 编辑工单标签
|
||||||
|
e.POST("/customer/label/edit", handler.EditCustomerOrderLabel) |
||||||
|
|
||||||
|
// 玩家信息
|
||||||
|
e.POST("/customer/player/info", handler.GetPlayerInfo) |
||||||
|
|
||||||
|
// 玩家充值历史
|
||||||
|
e.POST("/customer/rechargeHistory", handler2.GetGameUserRechargeHistory) |
||||||
|
|
||||||
|
// 玩家提现历史
|
||||||
|
e.POST("/customer/withdrawHistory", handler2.GetGameUserWithdrawHistory) |
||||||
|
|
||||||
|
// 玩家客诉历史
|
||||||
|
e.POST("/customer/complaint/history", handler.ComplaintHistory) |
||||||
|
} |
||||||
@ -0,0 +1,28 @@ |
|||||||
|
// 账号相关的接口
|
||||||
|
package routers |
||||||
|
|
||||||
|
import ( |
||||||
|
handler "server/modules/customer/handler/common" |
||||||
|
|
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
) |
||||||
|
|
||||||
|
func common(e *gin.Engine) { |
||||||
|
// 上传图片
|
||||||
|
e.POST("/image/upload", handler.UploadImage) |
||||||
|
|
||||||
|
// 获取图片
|
||||||
|
e.GET("/image/download", handler.DownImage) |
||||||
|
|
||||||
|
// 操作日志查看
|
||||||
|
e.POST("/option/log/list", handler.OptList) |
||||||
|
|
||||||
|
e.GET("/common/goodsList", handler.GoodList) |
||||||
|
e.GET("/common/productList", handler.ProductList) |
||||||
|
e.GET("/common/gameList", handler.GamesList) |
||||||
|
e.GET("/common/channelList", handler.ChannelList) |
||||||
|
e.GET("/common/userInfo", handler.UserInfo) |
||||||
|
e.GET("/common/getGameInfo", handler.GameInfo) |
||||||
|
|
||||||
|
e.POST("/common/feedbackList", handler.FeedbackList) |
||||||
|
} |
||||||
@ -0,0 +1,27 @@ |
|||||||
|
package routers |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
handler "server/modules/customer/handler/gm" |
||||||
|
) |
||||||
|
|
||||||
|
func gmHandle(e *gin.Engine) { |
||||||
|
// 客服机器人配置
|
||||||
|
e.POST("/gm/customer/robot/info", handler.GetCustomerRobot) |
||||||
|
e.POST("/gm/customer/robot/edit", handler.EditCustomerRobot) |
||||||
|
e.POST("/gm/customer/robot/del", handler.DelCustomerRobot) |
||||||
|
|
||||||
|
// 客服订单标签
|
||||||
|
e.GET("/gm/order/label/info", handler.GetCustomerLabel) |
||||||
|
e.POST("/gm/order/label/edit", handler.EditCustomerLabel) |
||||||
|
e.POST("/gm/order/label/del", handler.DelCustomerLabel) |
||||||
|
|
||||||
|
// 客服系统配置
|
||||||
|
e.GET("/gm/customer/config/info", handler.GetConfigCustomer) |
||||||
|
e.POST("/gm/customer/config/edit", handler.EditConfigCustomer) |
||||||
|
e.POST("/gm/customer/config/del", handler.DelConfigCustomer) |
||||||
|
|
||||||
|
// 客服系统黑名单
|
||||||
|
e.POST("/gm/customer/black/list", handler.GetCustomerBlackUser) |
||||||
|
e.POST("/gm/customer/black/edit", handler.EditCustomerBlackUser) |
||||||
|
} |
||||||
@ -0,0 +1,10 @@ |
|||||||
|
package routers |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
handler "server/modules/customer/handler/gm" |
||||||
|
) |
||||||
|
|
||||||
|
func guser(e *gin.Engine) { |
||||||
|
e.POST("/guser/info", handler.GetGameUserInfo) |
||||||
|
} |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
package routers |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
handler "server/modules/backend/handler/mail" |
||||||
|
) |
||||||
|
|
||||||
|
func mail(e *gin.Engine) { |
||||||
|
e.POST("/mail/draftList", handler.DraftList) |
||||||
|
e.POST("/mail/draftCreate", handler.DraftCreate) |
||||||
|
e.POST("/mail/draftEdit", handler.DraftEdit) |
||||||
|
e.POST("/mail/draftOpt", handler.DraftOpt) |
||||||
|
} |
||||||
@ -0,0 +1,16 @@ |
|||||||
|
package routers |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
handler "server/modules/customer/handler/power" |
||||||
|
) |
||||||
|
|
||||||
|
func power(e *gin.Engine) { |
||||||
|
e.GET("/power/user/list", handler.UserList) |
||||||
|
e.POST("/power/user/add", handler.AddUser) |
||||||
|
e.POST("/power/user/edit", handler.EditUserPower) |
||||||
|
e.POST("/power/user/del", handler.DelUser) |
||||||
|
e.GET("/power/role/list", handler.RoleList) |
||||||
|
e.POST("/power/role/add", handler.AddRole) |
||||||
|
e.POST("/power/role/edit", handler.EditRole) |
||||||
|
} |
||||||
@ -0,0 +1,36 @@ |
|||||||
|
package values |
||||||
|
|
||||||
|
import ( |
||||||
|
"time" |
||||||
|
) |
||||||
|
|
||||||
|
// 用户身份
|
||||||
|
const ( |
||||||
|
UserRoleAdmin = iota + 1 // 管理员
|
||||||
|
UserRole1 // 1级
|
||||||
|
UserRole2 // 2级
|
||||||
|
UserRole3 // 3级
|
||||||
|
) |
||||||
|
|
||||||
|
const ( |
||||||
|
RedisTokenEx = 60 * time.Minute |
||||||
|
AdminToken = "lrmfe2hFQOSqvv4Z" // 常驻调用token
|
||||||
|
) |
||||||
|
|
||||||
|
// LoginReq 登录请求
|
||||||
|
type LoginReq struct { |
||||||
|
Account string `json:"Account" binding:"required"` |
||||||
|
Pass string `json:"Pass" binding:"required"` |
||||||
|
} |
||||||
|
|
||||||
|
// LoginResp 登录返回
|
||||||
|
// Power:权限
|
||||||
|
// Role:账户等级,1管理员
|
||||||
|
// Token:身份码,登录成功后的所有请求需在header里加入token字段以进行后续请求
|
||||||
|
// 账户id
|
||||||
|
type LoginResp struct { |
||||||
|
Power interface{} |
||||||
|
Token string |
||||||
|
Role int |
||||||
|
Id int |
||||||
|
} |
||||||
@ -0,0 +1,119 @@ |
|||||||
|
package values |
||||||
|
|
||||||
|
import "server/common" |
||||||
|
|
||||||
|
// GetCustomerHistoryReq 获取聊天信息
|
||||||
|
type GetCustomerHistoryReq struct { |
||||||
|
Title int `json:"Title" binding:"required"` // 玩家uid
|
||||||
|
Page int `json:"Page" binding:"required"` |
||||||
|
Num int `json:"Num" binding:"required"` |
||||||
|
} |
||||||
|
|
||||||
|
// GetCustomerHistoryResp 获取聊天信息
|
||||||
|
type GetCustomerHistoryResp struct { |
||||||
|
List []*common.CustomerChatData |
||||||
|
Count int64 |
||||||
|
} |
||||||
|
|
||||||
|
// ReadMessageReq 消息已读接口
|
||||||
|
type ReadMessageReq struct { |
||||||
|
OrderId int // 订单id
|
||||||
|
Title int `json:"Title" binding:"required"` // 玩家uid
|
||||||
|
List []int `json:"List" binding:"required"` // 传入需要标记已读消息的id
|
||||||
|
} |
||||||
|
|
||||||
|
// 发送消息请求
|
||||||
|
type SendMessageReq struct { |
||||||
|
common.CustomerChatData |
||||||
|
} |
||||||
|
|
||||||
|
// 查询订单请求
|
||||||
|
type GetCustomerOrderReq struct { |
||||||
|
Page int `json:"Page" binding:"required"` |
||||||
|
Num int `json:"Num" binding:"required"` |
||||||
|
CustomerUid int `json:"CustomerUid"` // uid
|
||||||
|
Uid int `json:"Uid"` // 玩家uid
|
||||||
|
Status int `json:"Status"` // 工单状态码 等于 匹配
|
||||||
|
Vip int `json:"Vip"` // vip等级限制
|
||||||
|
Label int `json:"Label"` // 标签
|
||||||
|
Order int `json:"Order"` // 默认按创建时间逆序, 1表示按创建时间逆序, 2表示按创建时间正序 3表示按消息未读数排序
|
||||||
|
Status2 int `json:"Status2"` // 工单状态码 小于等于 匹配
|
||||||
|
} |
||||||
|
|
||||||
|
type GetCustomerOrderResp struct { |
||||||
|
List []*common.CustomerOrder |
||||||
|
Count int64 |
||||||
|
} |
||||||
|
|
||||||
|
// 改变工单状态
|
||||||
|
type ChangeCustomerOrderReq struct { |
||||||
|
List []*CustomerOrderStatus |
||||||
|
} |
||||||
|
|
||||||
|
type CustomerOrderStatus struct { |
||||||
|
Id int `json:"Id"` // 改订单id
|
||||||
|
Status int `json:"Status"` // 工单状态码
|
||||||
|
Label1 int `json:"Label1"` // 工单标签
|
||||||
|
Label2 int `json:"Label2"` // 工单标签
|
||||||
|
Label3 int `json:"Label3"` // 工单标签
|
||||||
|
Label4 int `json:"Label4"` // 工单标签
|
||||||
|
Label5 int `json:"Label5"` // 工单标签
|
||||||
|
} |
||||||
|
|
||||||
|
// 分配工单到客服人员
|
||||||
|
type CustomerOrderAllocateReq struct { |
||||||
|
List []*OrderAllocate |
||||||
|
} |
||||||
|
|
||||||
|
type OrderAllocate struct { |
||||||
|
Uid int // 客服人员uid
|
||||||
|
OrderId int // 分配工单Id
|
||||||
|
} |
||||||
|
|
||||||
|
// 分配工单到客服人员
|
||||||
|
type CustomerOrderAllocateResp struct { |
||||||
|
List []*OrderAllocate |
||||||
|
} |
||||||
|
|
||||||
|
// 编辑订单标签
|
||||||
|
type EditCustomerOrderLabelReq struct { |
||||||
|
OrderId int `json:"OrderId" binding:"required"` // 编辑的订单id
|
||||||
|
LabelId1 int `json:"LabelId1" binding:"required"` // 编辑的标签id
|
||||||
|
LabelId2 int `json:"LabelId2" binding:"required"` // 编辑的标签id
|
||||||
|
LabelId3 int `json:"LabelId3" binding:"required"` // 编辑的标签id
|
||||||
|
LabelId4 int `json:"LabelId4" binding:"required"` // 编辑的标签id
|
||||||
|
LabelId5 int `json:"LabelId5" binding:"required"` // 编辑的标签id
|
||||||
|
} |
||||||
|
|
||||||
|
// 玩家信息
|
||||||
|
type GetPlayerInfoReq struct { |
||||||
|
Uid int `json:"Uid" binding:"required"` // 客诉玩家uid
|
||||||
|
} |
||||||
|
|
||||||
|
// 玩家信息响应
|
||||||
|
type GetPlayerInfoResp struct { |
||||||
|
Uid int // 客诉玩家uid
|
||||||
|
Nick string // 昵称
|
||||||
|
Avatar string // 头像
|
||||||
|
Birth int64 // 注册日期
|
||||||
|
Phone string // 玩家电话号码
|
||||||
|
Channel int // 渠道
|
||||||
|
Package string // 游戏包名
|
||||||
|
Vip int // 玩家vip等级
|
||||||
|
Recharge int64 // 玩家充值总金额
|
||||||
|
Withdraw int64 // 玩家提现总金额
|
||||||
|
CustomerBlack bool // 是否被拉黑
|
||||||
|
} |
||||||
|
|
||||||
|
// 玩家客诉历史请求
|
||||||
|
type ComplaintHistoryReq struct { |
||||||
|
Uid int `json:"Uid" binding:"required"` // 玩家uid
|
||||||
|
Page int `json:"Page" binding:"required"` |
||||||
|
Num int `json:"Num" binding:"required"` |
||||||
|
} |
||||||
|
|
||||||
|
// 玩家客诉历史响应
|
||||||
|
type ComplaintHistoryResp struct { |
||||||
|
List []*common.CustomerOrder |
||||||
|
Count int64 |
||||||
|
} |
||||||
@ -0,0 +1,76 @@ |
|||||||
|
package values |
||||||
|
|
||||||
|
import "server/common" |
||||||
|
|
||||||
|
// 图片存放地址
|
||||||
|
var ( |
||||||
|
ImagePath = "images" |
||||||
|
) |
||||||
|
|
||||||
|
// DownLoadImageReq 图片请求
|
||||||
|
type DownLoadImageReq struct { |
||||||
|
ImagePath string `json:"ImagePath" binding:"required"` // 图片地址
|
||||||
|
} |
||||||
|
|
||||||
|
// EditHistoryListReq 操作日志请求
|
||||||
|
type EditHistoryListReq struct { |
||||||
|
Page uint `json:"Page" binding:"required"` |
||||||
|
Num uint `json:"Num" binding:"required"` |
||||||
|
} |
||||||
|
|
||||||
|
// EditHistoryListResp 操作日志
|
||||||
|
type EditHistoryListResp struct { |
||||||
|
List []EditHistory |
||||||
|
Count int64 |
||||||
|
} |
||||||
|
|
||||||
|
// // GoodListResp 请求物品列表返回
|
||||||
|
// type GoodListResp struct {
|
||||||
|
// List []*common.SheetGoods_config
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ProductListResp 请求充值列表返回
|
||||||
|
type ProductListResp struct { |
||||||
|
List []*common.ConfigPayProduct |
||||||
|
} |
||||||
|
|
||||||
|
// GamesListResp 游戏列表
|
||||||
|
type GamesListResp struct { |
||||||
|
List []string |
||||||
|
} |
||||||
|
|
||||||
|
// ChannelListResp 渠道列表
|
||||||
|
type ChannelListResp struct { |
||||||
|
List []*common.Channel |
||||||
|
} |
||||||
|
|
||||||
|
// UserInfoResp 获取用户信息
|
||||||
|
type UserInfoResp struct { |
||||||
|
Name string |
||||||
|
Role int |
||||||
|
Power string |
||||||
|
} |
||||||
|
|
||||||
|
// GameInfoResp 游戏信息,游戏名称跟游戏id
|
||||||
|
type GameInfoResp struct { |
||||||
|
List []GameInfo |
||||||
|
RoomId []int |
||||||
|
} |
||||||
|
|
||||||
|
type GameInfo struct { |
||||||
|
GameId int |
||||||
|
Name string |
||||||
|
} |
||||||
|
|
||||||
|
// FeedbackListReq 玩家反馈
|
||||||
|
type FeedbackListReq struct { |
||||||
|
Start string `json:"Start" binding:"required"` |
||||||
|
End string `json:"End" binding:"required"` |
||||||
|
Page int `json:"Page" binding:"required"` |
||||||
|
Num int `json:"Num" binding:"required"` |
||||||
|
} |
||||||
|
|
||||||
|
type FeedbackListResp struct { |
||||||
|
List []*common.ESFeedback |
||||||
|
Count int64 |
||||||
|
} |
||||||
@ -0,0 +1,10 @@ |
|||||||
|
package values |
||||||
|
|
||||||
|
// 错误码
|
||||||
|
const ( |
||||||
|
CodeOK = iota |
||||||
|
CodeRetry |
||||||
|
CodeToken |
||||||
|
CodeParam |
||||||
|
CodePower // 权限不足
|
||||||
|
) |
||||||
@ -0,0 +1,76 @@ |
|||||||
|
package values |
||||||
|
|
||||||
|
import "server/common" |
||||||
|
|
||||||
|
// GetCustomerRobotReq 客服机器人请求
|
||||||
|
type GetCustomerRobotReq struct { |
||||||
|
ParentId int // 该消息父类id
|
||||||
|
} |
||||||
|
|
||||||
|
// GetCustomerRobotResp 客服机器人响应
|
||||||
|
type GetCustomerRobotResp struct { |
||||||
|
List []*common.ConfigCustomerRobot |
||||||
|
} |
||||||
|
|
||||||
|
// EditCustomerRobotReq 编辑客服机器人消息
|
||||||
|
type EditCustomerRobotReq struct { |
||||||
|
List []*common.ConfigCustomerRobot |
||||||
|
} |
||||||
|
|
||||||
|
// EditCustomerRobotResp 编辑客服机器人消息
|
||||||
|
type EditCustomerRobotResp struct { |
||||||
|
List []*common.ConfigCustomerRobot |
||||||
|
} |
||||||
|
|
||||||
|
// DelCustomerRobotReq 删除客服机器人消息
|
||||||
|
type DelCustomerRobotReq struct { |
||||||
|
List []*int // id
|
||||||
|
} |
||||||
|
|
||||||
|
// GetCustomerLabelResp 订单标签响应
|
||||||
|
type GetCustomerLabelResp struct { |
||||||
|
List []*common.CustomerOrderLabel |
||||||
|
} |
||||||
|
|
||||||
|
// EditCustomerLabelReq 编辑订单标签响应
|
||||||
|
type EditCustomerLabelReq struct { |
||||||
|
List []*common.CustomerOrderLabel |
||||||
|
} |
||||||
|
|
||||||
|
// DelCustomerLabelReq 删除订单标签响应
|
||||||
|
type DelCustomerLabelReq struct { |
||||||
|
List []*int // id
|
||||||
|
} |
||||||
|
|
||||||
|
// GetConfigCustomerResp 客服系统配置
|
||||||
|
type GetConfigCustomerResp struct { |
||||||
|
List []*common.ConfigCustomer |
||||||
|
} |
||||||
|
|
||||||
|
// EditConfigCustomerReq 客服系统配置
|
||||||
|
type EditConfigCustomerReq struct { |
||||||
|
List []*common.ConfigCustomer |
||||||
|
} |
||||||
|
|
||||||
|
// DelConfigCustomerReq 客服系统配置
|
||||||
|
type DelConfigCustomerReq struct { |
||||||
|
List []*int // id
|
||||||
|
} |
||||||
|
|
||||||
|
// 客服黑名单请求
|
||||||
|
type CustomerBlackUserReq struct { |
||||||
|
Page int `json:"Page" binding:"required"` |
||||||
|
Num int `json:"Num" binding:"required"` |
||||||
|
} |
||||||
|
|
||||||
|
// 客服黑名单请求
|
||||||
|
type CustomerBlackUserResp struct { |
||||||
|
List []*common.CustomerBlackUser |
||||||
|
Count int64 |
||||||
|
} |
||||||
|
|
||||||
|
// DelConfigCustomerReq 客服系统配置
|
||||||
|
type EditCustomerBlackUserReq struct { |
||||||
|
Opt int // 1是添加黑名单 2是删除黑名单
|
||||||
|
List []*int // uid 传玩家uid
|
||||||
|
} |
||||||
@ -0,0 +1,109 @@ |
|||||||
|
package values |
||||||
|
|
||||||
|
// 权限对应页签
|
||||||
|
const ( |
||||||
|
PowerAll = iota |
||||||
|
// 系统管理从1开始
|
||||||
|
PowerGM // 系统配置
|
||||||
|
PowerManageRole // 角色管理账户权限
|
||||||
|
PowerManageUser // 用户管理账户权限
|
||||||
|
PowerMail // 邮件权限
|
||||||
|
PowerOrderAllocate // 工单分配权限
|
||||||
|
PowerOrderProcessing // 工单处理权限
|
||||||
|
PowerOptionLog // 操作日志权限
|
||||||
|
PowerMax1 |
||||||
|
) |
||||||
|
|
||||||
|
// 数据管理从100开始
|
||||||
|
const ( |
||||||
|
PowerRealData = iota + 100 // 实时数据 100
|
||||||
|
PowerGameData // 游戏概况 101
|
||||||
|
PowerNewPlayData // 新增用户分析 102
|
||||||
|
PowerActivePlayData // 用户活跃分析 103
|
||||||
|
PowerFinancialData // 系统货币 104
|
||||||
|
PowerRechargeData // 收入概要 105
|
||||||
|
PowerPlayData // 用户牌局 106
|
||||||
|
PowerRechargeOrder // 订单明细 107
|
||||||
|
PowerShareData // 分享数据 108
|
||||||
|
PowerWithdrawOrder // 提现明细 109
|
||||||
|
PowerGame // 游戏牌局 110
|
||||||
|
PowerRealProfit // 实时盈亏 111
|
||||||
|
PowerRedActivity // 红包雨活动 112
|
||||||
|
PowerPlayerProfit // 玩家收益 113
|
||||||
|
PowerEventTrack // 打点数据 114
|
||||||
|
PowerMax2 |
||||||
|
) |
||||||
|
|
||||||
|
func IsValidPower(p int) bool { |
||||||
|
if p > PowerAll && p < PowerMax1 || p >= PowerRealData && p < PowerMax2 { |
||||||
|
return true |
||||||
|
} |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
var ( |
||||||
|
// 权限映射表
|
||||||
|
PowerMap = map[string]int{ |
||||||
|
"/gm": PowerGM, |
||||||
|
"/power/role": PowerManageRole, |
||||||
|
"/power/user": PowerManageUser, |
||||||
|
"/mail": PowerMail, |
||||||
|
"/order/allocate": PowerOrderAllocate, |
||||||
|
"/customer": PowerOrderProcessing, |
||||||
|
"/option/log": PowerOptionLog, |
||||||
|
} |
||||||
|
// 页面按钮权限
|
||||||
|
PowerButtonMap = map[int][]string{} |
||||||
|
) |
||||||
|
|
||||||
|
type UserListResp struct { |
||||||
|
List []User |
||||||
|
} |
||||||
|
|
||||||
|
// AddUserReq 新增角色
|
||||||
|
type AddUserReq struct { |
||||||
|
Role int `json:"Role" binding:"required"` |
||||||
|
Name string `json:"Name" binding:"required"` |
||||||
|
Account string `json:"Account" binding:"required"` |
||||||
|
Password string `json:"Password" binding:"required"` |
||||||
|
Phone string `json:"Phone" binding:"required"` |
||||||
|
Channels string `json:"Channels"` |
||||||
|
} |
||||||
|
|
||||||
|
// DelUserReq 删除角色
|
||||||
|
type DelUserReq struct { |
||||||
|
ID int `json:"ID" binding:"required"` |
||||||
|
} |
||||||
|
|
||||||
|
type RoleListResp struct { |
||||||
|
List []Role |
||||||
|
} |
||||||
|
|
||||||
|
// AddRoleReq 新增角色
|
||||||
|
type AddRoleReq struct { |
||||||
|
Role int `json:"Role" binding:"required"` |
||||||
|
Name string `json:"Name" binding:"required"` |
||||||
|
Power string `json:"Power" binding:"required"` |
||||||
|
} |
||||||
|
|
||||||
|
// EditRoleReq 编辑角色
|
||||||
|
type EditRoleReq struct { |
||||||
|
ID int `json:"ID" binding:"required"` |
||||||
|
Role int `json:"Role" binding:"required"` |
||||||
|
Name string `json:"Name" binding:"required"` |
||||||
|
Power string `json:"Power" binding:"required"` |
||||||
|
} |
||||||
|
|
||||||
|
// EditPowerReq 编辑权限
|
||||||
|
// ID 账户id
|
||||||
|
// Power 用户编辑后的权限
|
||||||
|
type EditPowerReq struct { |
||||||
|
ID int `json:"ID" binding:"required"` |
||||||
|
Power *string `json:"Power"` |
||||||
|
Role *int `json:"Role"` |
||||||
|
Name *string `json:"Name"` |
||||||
|
Account *string `json:"Account"` |
||||||
|
Password *string `json:"Password"` |
||||||
|
Phone *string `json:"Phone"` |
||||||
|
Channels *string `json:"Channels"` |
||||||
|
} |
||||||
@ -0,0 +1,52 @@ |
|||||||
|
package values |
||||||
|
|
||||||
|
// User 后台用户
|
||||||
|
type User struct { |
||||||
|
Name string `gorm:"column:name;type:varchar(32);uniqueIndex:name;not null;comment:名字" json:"Name"` |
||||||
|
Account string `gorm:"column:account;type:varchar(32);uniqueIndex:account;not null;comment:账号" json:"Account"` |
||||||
|
Password string `gorm:"column:password;type:varchar(32);not null;comment:密码" json:"Password"` |
||||||
|
ID uint `gorm:"primarykey"` |
||||||
|
Role int `gorm:"column:role;type:tinyint(4);not null;comment:角色" json:"Role"` |
||||||
|
Power string `gorm:"column:power;type:varchar(512);not null;comment:权限" json:"Power"` |
||||||
|
PowerMap map[int][]int `gorm:"-" json:"PowerMap"` |
||||||
|
Phone string `gorm:"column:phone;type:varchar(32);uniqueIndex:phone;comment:手机号" json:"Phone"` |
||||||
|
Channels string `gorm:"column:channels;type:varchar(512);not null;comment:拥有权限的包,为空时代表所有包都有权限" json:"Channels"` |
||||||
|
SChannels []int `gorm:"-"` |
||||||
|
} |
||||||
|
|
||||||
|
func (u *User) TableName() string { |
||||||
|
return "users" |
||||||
|
} |
||||||
|
|
||||||
|
// EditHistory 后台修改操作历史
|
||||||
|
// Operator 操作人
|
||||||
|
// Detail 修改内容
|
||||||
|
// Time 时间
|
||||||
|
// Model 操作模块,与权限列表对应
|
||||||
|
type EditHistory struct { |
||||||
|
Operator string `gorm:"column:operator;type:varchar(32);not null;comment:操作人" json:"Operator"` |
||||||
|
Detail string `gorm:"column:detail;type:varchar(256);not null;comment:修改明细" json:"Detail"` |
||||||
|
ID uint `gorm:"primarykey" json:"-"` |
||||||
|
Time int64 `gorm:"column:time;type:bigint(20);default:0;comment:操作时间" json:"Time"` |
||||||
|
UID int `gorm:"column:uid;type:int(11);comment:操作人id" json:"UID"` |
||||||
|
Model int `gorm:"column:model;type:int(11);comment:操作功能模块" json:"Model"` |
||||||
|
} |
||||||
|
|
||||||
|
func (e *EditHistory) TableName() string { |
||||||
|
return "edit_history" |
||||||
|
} |
||||||
|
|
||||||
|
// Role 后台角色
|
||||||
|
// Role 角色等级 1是超管
|
||||||
|
// Power 权限
|
||||||
|
// Name 角色名
|
||||||
|
type Role struct { |
||||||
|
ID uint `gorm:"primarykey"` |
||||||
|
Role int `gorm:"column:role;type:tinyint(4);uniqueIndex:role;not null;comment:角色等级" json:"Role"` |
||||||
|
Power string `gorm:"column:power;type:varchar(512);not null;comment:权限" json:"Power"` |
||||||
|
Name string `gorm:"column:name;type:varchar(32);uniqueIndex:name;not null;comment:角色名" json:"Name"` |
||||||
|
} |
||||||
|
|
||||||
|
func (u *Role) TableName() string { |
||||||
|
return "role" |
||||||
|
} |
||||||
@ -0,0 +1,334 @@ |
|||||||
|
package handler |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"io" |
||||||
|
"mime" |
||||||
|
"net/http" |
||||||
|
"os" |
||||||
|
"server/call" |
||||||
|
"server/common" |
||||||
|
"server/config" |
||||||
|
"server/db" |
||||||
|
"server/modules/web/app" |
||||||
|
"server/modules/web/values" |
||||||
|
"strings" |
||||||
|
"time" |
||||||
|
|
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"github.com/liangdas/mqant/log" |
||||||
|
"gorm.io/gorm" |
||||||
|
) |
||||||
|
|
||||||
|
// 加载客服系统配置
|
||||||
|
func GetCustomerConfig(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.ResponseB() |
||||||
|
}() |
||||||
|
var resp values.GetCustomerConfigResp |
||||||
|
resp.Config = call.GetConfigCustomer() |
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
// 获取客服机器人消息
|
||||||
|
func GetCustomerRobotList(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.ResponseB() |
||||||
|
}() |
||||||
|
req := new(values.GetCustomerRobotReq) |
||||||
|
if !a.SB(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
var resp values.GetCustomerRobotResp |
||||||
|
|
||||||
|
if req.ParentId == 0 { |
||||||
|
resp.List = call.GetCustomerRobot(req.ParentId) |
||||||
|
if len(resp.List) > 0 { |
||||||
|
resp.Parent = resp.List[0] |
||||||
|
} |
||||||
|
resp.List = call.GetCustomerRobot(resp.List[0].ID) |
||||||
|
} else { |
||||||
|
resp.List = call.GetCustomerRobot(req.ParentId) |
||||||
|
resp.Parent = call.GetCustomerRobotById(req.ParentId) |
||||||
|
} |
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
// 机器人客服消息
|
||||||
|
func GetCustomerRobotMsg(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.ResponseB() |
||||||
|
}() |
||||||
|
req := new(values.GetCustomerRobotMsgReq) |
||||||
|
if !a.SB(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
var resp values.GetCustomerRobotMsgResp |
||||||
|
resp.Content = call.GetCustomerRobotMsg(req.Id) |
||||||
|
|
||||||
|
// 获取玩家vip等级
|
||||||
|
vip := call.GetVIP(a.UID) |
||||||
|
|
||||||
|
data := &common.CustomerOrder{Uid: a.UID, Start: time.Now().Unix(), Vip: vip.Level, Status: common.CustomerOrderCreate} |
||||||
|
|
||||||
|
// 创建机器人订单
|
||||||
|
err := db.Mysql().Create(data) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
|
||||||
|
// 10秒内玩家没有选择满意是否就默认完成工单
|
||||||
|
time.AfterFunc(10*time.Second, func() { |
||||||
|
err = db.Mysql().Update(data, map[string]interface{}{ |
||||||
|
"status": common.CustomerOrderComplete, |
||||||
|
}) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
// 获取聊天历史
|
||||||
|
func GetCustomerHistory(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.ResponseB() |
||||||
|
}() |
||||||
|
req := new(values.GetCustomerHistoryReq) |
||||||
|
if !a.SB(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
var resp values.GetCustomerHistoryResp |
||||||
|
Count, err := db.Mysql().QueryList(req.Page-1, req.Num, fmt.Sprintf("title = %v", a.UID), "id DESC", &common.CustomerChatData{}, &resp.List) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
resp.Count = Count |
||||||
|
|
||||||
|
// 查询玩家上一次客服处理是否结束
|
||||||
|
data := &common.CustomerOrder{Uid: a.UID} |
||||||
|
err = db.Mysql().GetLast(data) |
||||||
|
if err != nil { |
||||||
|
if err != gorm.ErrRecordNotFound { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 是否客服黑名单
|
||||||
|
if db.Mysql().Exist(&common.CustomerBlackUser{Uid: a.UID}) { |
||||||
|
resp.IsBlack = true |
||||||
|
} |
||||||
|
|
||||||
|
resp.Status = data.Status |
||||||
|
|
||||||
|
// 是否客服黑名单
|
||||||
|
if db.Mysql().Exist(&common.CustomerBlackUser{Uid: a.UID}) { |
||||||
|
resp.IsBlack = true |
||||||
|
} |
||||||
|
|
||||||
|
a.Data = resp |
||||||
|
} |
||||||
|
|
||||||
|
// 上传图片
|
||||||
|
func UploadImage(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.ResponseB() |
||||||
|
}() |
||||||
|
|
||||||
|
// 解析请求中的 multipart/form-data
|
||||||
|
err := c.Request.ParseMultipartForm(10 << 20) // 限制上传文件的大小为 10MB
|
||||||
|
if err != nil { |
||||||
|
log.Error("图片超过10Mb, err:%v", err.Error()) |
||||||
|
a.Code = values.CodeParam |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// 打开上传的文件
|
||||||
|
file, header, err := c.Request.FormFile("file") |
||||||
|
if err != nil { |
||||||
|
log.Error("打开上传图片失败, err:%v", err.Error()) |
||||||
|
a.Code = values.CodeParam |
||||||
|
return |
||||||
|
} |
||||||
|
defer file.Close() |
||||||
|
|
||||||
|
// 获取上传文件的 MIME 类型
|
||||||
|
contentType := header.Header.Get("Content-Type") |
||||||
|
// 根据 MIME 类型获取文件扩展名
|
||||||
|
ext, err := mime.ExtensionsByType(contentType) |
||||||
|
if err != nil || len(ext) == 0 { |
||||||
|
log.Error("获取上传图片格式失败, err:%v", err.Error()) |
||||||
|
a.Code = values.CodeParam |
||||||
|
return |
||||||
|
} |
||||||
|
imageName := call.SnowNode().Generate().String() + ext[0] |
||||||
|
// 读取上传的文件内容
|
||||||
|
data, err := io.ReadAll(file) |
||||||
|
if err != nil { |
||||||
|
log.Error("读取图片内容失败, err:%v", err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// 获取当前日期
|
||||||
|
now := time.Now() |
||||||
|
zeroTime := now.Format("20060102") |
||||||
|
rounded := now.Hour() |
||||||
|
dir := fmt.Sprintf("%v/%v/%v", "images", zeroTime, rounded) |
||||||
|
|
||||||
|
// 创建保存文件的目标文件
|
||||||
|
err = createDirIfNotExist(dir) |
||||||
|
if err != nil { |
||||||
|
log.Error("创建图片保存目录, err:%v", err.Error()) |
||||||
|
a.Code = values.CodeParam |
||||||
|
return |
||||||
|
} |
||||||
|
// 将上传的文件复制到目标文件
|
||||||
|
err = os.WriteFile(dir+"/"+imageName, data, 0644) // 写入文件
|
||||||
|
if err != nil { |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
name := strings.Replace(dir+"/"+imageName, "/", ",", -1) |
||||||
|
a.Data = config.GetConfig().Web.ImageURL + name |
||||||
|
} |
||||||
|
|
||||||
|
// 检测文件目录是否存在
|
||||||
|
func createDirIfNotExist(path string) error { |
||||||
|
// 检查目录是否存在
|
||||||
|
_, err := os.Stat(path) |
||||||
|
if err == nil { |
||||||
|
// 目录已存在,直接返回
|
||||||
|
return nil |
||||||
|
} |
||||||
|
// 目录不存在,创建目录
|
||||||
|
if os.IsNotExist(err) { |
||||||
|
err = os.MkdirAll(path, 0755) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
} |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// 获取图片
|
||||||
|
func DownloadImage(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.ResponseB() |
||||||
|
}() |
||||||
|
|
||||||
|
name := c.Query("path") |
||||||
|
path := strings.Replace(name, ",", "/", -1) |
||||||
|
|
||||||
|
// 打开要返回的图片文件
|
||||||
|
file, err := os.Open(path) |
||||||
|
if err != nil { |
||||||
|
c.AbortWithError(http.StatusInternalServerError, err) |
||||||
|
return |
||||||
|
} |
||||||
|
defer file.Close() |
||||||
|
|
||||||
|
// 读取图片文件的内容
|
||||||
|
data, err := io.ReadAll(file) |
||||||
|
if err != nil { |
||||||
|
c.AbortWithError(http.StatusInternalServerError, err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
arr := strings.Split(path, ".") |
||||||
|
|
||||||
|
// 返回图片
|
||||||
|
c.Data(http.StatusOK, "image/"+arr[len(arr)-1], data) |
||||||
|
} |
||||||
|
|
||||||
|
// 消息已读
|
||||||
|
func ReadMessage(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.ResponseB() |
||||||
|
}() |
||||||
|
req := &values.ReadMessageReq{} |
||||||
|
if !a.SB(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
for i := 0; i < len(req.List); i++ { |
||||||
|
err := db.Mysql().Update(&common.CustomerChatData{ID: req.List[i], Title: a.UID}, map[string]interface{}{"is_read": true}) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 玩家发送消息
|
||||||
|
func SendMessage(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.ResponseB() |
||||||
|
}() |
||||||
|
req := &values.SendMessageReq{} |
||||||
|
if !a.SB(req) { |
||||||
|
return |
||||||
|
} |
||||||
|
req.Title = a.UID |
||||||
|
req.Uid = a.UID |
||||||
|
req.Time = time.Now().Unix() |
||||||
|
err := db.Mysql().Create(&req) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
err = db.Mysql().UpdateW(&common.CustomerOrder{}, map[string]interface{}{ |
||||||
|
"un_read": gorm.Expr("un_read + 1"), |
||||||
|
}, fmt.Sprintf("uid = %v AND status < %v", a.UID, common.CustomerOrderComplete)) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
} |
||||||
|
a.Data = req.ID |
||||||
|
} |
||||||
|
|
||||||
|
// 转接人工服务
|
||||||
|
func CreateCustomerOrder(c *gin.Context) { |
||||||
|
a := app.NewApp(c) |
||||||
|
defer func() { |
||||||
|
a.ResponseB() |
||||||
|
}() |
||||||
|
|
||||||
|
if db.Mysql().Exist(&common.CustomerBlackUser{Uid: a.UID}) { |
||||||
|
// 该用户在黑名单
|
||||||
|
log.Info("uid:%v 客服黑名单用户,不创建人工服务", a.UID) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// 查询玩家上一次客服是否结束
|
||||||
|
var order []*common.CustomerOrder |
||||||
|
|
||||||
|
count, err := db.Mysql().QueryList(0, 1, fmt.Sprintf("uid = %v AND status != %v", a.UID, common.CustomerOrderComplete), "", &common.CustomerOrder{}, &order) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} else { |
||||||
|
if count == 0 { |
||||||
|
vip := call.GetVIP(a.UID) |
||||||
|
err = db.Mysql().Create(&common.CustomerOrder{Uid: a.UID, Start: time.Now().Unix(), Vip: vip.Level, Status: common.CustomerOrderCreate}) |
||||||
|
if err != nil { |
||||||
|
log.Error(err.Error()) |
||||||
|
a.Code = values.CodeRetry |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,35 @@ |
|||||||
|
package routers |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"server/modules/web/handler" |
||||||
|
) |
||||||
|
|
||||||
|
func customer(e *gin.RouterGroup) { |
||||||
|
// 获取客服系统配置
|
||||||
|
e.GET("/customer/config", handler.GetCustomerConfig) |
||||||
|
|
||||||
|
// 获取机器人信息
|
||||||
|
e.POST("/customer/robot/list", handler.GetCustomerRobotList) |
||||||
|
|
||||||
|
// 获取机器人消息
|
||||||
|
e.POST("/customer/robot/msg/list", handler.GetCustomerRobotMsg) |
||||||
|
|
||||||
|
// 获取客服聊天历史
|
||||||
|
e.POST("/customer/history", handler.GetCustomerHistory) |
||||||
|
|
||||||
|
// 上传图片
|
||||||
|
e.POST("/customer/upload/image", handler.UploadImage) |
||||||
|
|
||||||
|
// 加载图片
|
||||||
|
e.GET("/customer/image/download", handler.DownloadImage) |
||||||
|
|
||||||
|
// 读消息
|
||||||
|
e.POST("/customer/read/message", handler.ReadMessage) |
||||||
|
|
||||||
|
// 发送消息
|
||||||
|
e.POST("/customer/send/message", handler.SendMessage) |
||||||
|
|
||||||
|
// 创建客服工单
|
||||||
|
e.GET("/customer/create/order", handler.CreateCustomerOrder) |
||||||
|
} |
||||||
@ -0,0 +1,63 @@ |
|||||||
|
package values |
||||||
|
|
||||||
|
import "server/common" |
||||||
|
|
||||||
|
// GetCustomerConfigResp 客服系统配置返回
|
||||||
|
type GetCustomerConfigResp struct { |
||||||
|
Config *common.ConfigCustomer |
||||||
|
} |
||||||
|
|
||||||
|
// GetCustomerHistoryReq 获取聊天信息
|
||||||
|
type GetCustomerHistoryReq struct { |
||||||
|
Page int `json:"Page" binding:"required"` |
||||||
|
Num int `json:"Num" binding:"required"` |
||||||
|
} |
||||||
|
|
||||||
|
// GetCustomerHistoryResp 获取聊天信息
|
||||||
|
type GetCustomerHistoryResp struct { |
||||||
|
List []*common.CustomerChatData |
||||||
|
Count int64 |
||||||
|
Status int // 上一次工单状态
|
||||||
|
IsBlack bool // 是否客服黑名单
|
||||||
|
} |
||||||
|
|
||||||
|
// GetCustomerRobotReq 客服机器人请求
|
||||||
|
type GetCustomerRobotReq struct { |
||||||
|
ParentId int // 该消息父类id
|
||||||
|
} |
||||||
|
|
||||||
|
// GetCustomerRobotResp 客服机器人请求
|
||||||
|
type GetCustomerRobotResp struct { |
||||||
|
List []*common.ConfigCustomerRobot |
||||||
|
Parent *common.ConfigCustomerRobot |
||||||
|
} |
||||||
|
|
||||||
|
// GetCustomerRobotMsgReq 客服机器人请求
|
||||||
|
type GetCustomerRobotMsgReq struct { |
||||||
|
Id int // 该消息父类id
|
||||||
|
} |
||||||
|
|
||||||
|
// GetCustomerRobotMsgResp 客服机器人请求
|
||||||
|
type GetCustomerRobotMsgResp struct { |
||||||
|
Content *common.ConfigCustomerRobot |
||||||
|
} |
||||||
|
|
||||||
|
// UploadImageResp 图片上传返回
|
||||||
|
type UploadImageResp struct { |
||||||
|
Path string // 返回图片地址
|
||||||
|
} |
||||||
|
|
||||||
|
// DownloadImageReq 加载图片地址
|
||||||
|
type DownloadImageReq struct { |
||||||
|
Path string `json:"Path" binding:"required"` // 返回图片地址
|
||||||
|
} |
||||||
|
|
||||||
|
// ReadMessageReq 消息已读接口
|
||||||
|
type ReadMessageReq struct { |
||||||
|
List []int `json:"List" binding:"required"` // 传入需要标记已读消息的id
|
||||||
|
} |
||||||
|
|
||||||
|
// 发送消息请求
|
||||||
|
type SendMessageReq struct { |
||||||
|
common.CustomerChatData |
||||||
|
} |
||||||
Loading…
Reference in new issue