diff --git a/call/config.go b/call/config.go index 96cc25e..3a38299 100644 --- a/call/config.go +++ b/call/config.go @@ -448,6 +448,165 @@ func GetConfigWithdrawChannels() []*common.ConfigWithdrawChannels { return ret } +func GetWithdrawChannelName(channelId int) string { + var name string + switch channelId { + case 0: + name = "FunzonePay" + case 1: + name = "WellPay" + case 2: + name = "OctroPay" + case 3: + name = "IGeekPay" + case 4: + name = "CloudPay" + case 5: + name = "VSPay" + case 6: + name = "JoyPay" + case 7: + name = "FFPay" + case 8: + name = "BestPay" + case 9: + name = "HXPay" + case 10: + name = "MGPay" + case 11: + name = "OOPay" + case 12: + name = "ZWPay" + case 13: + name = "FastPay" + case 14: + name = "HaoPay" + case 15: + name = "QPPay" + case 16: + name = "OwlPay" + case 17: + name = "SkyPay" + case 18: + name = "GrePay" + case 19: + name = "MoonPay" + case 20: + name = "Acepay" + case 21: + name = "MccPay" + case 22: + name = "YoduPay" + case 23: + name = "WordPay" + case 24: + name = "HWPay" + case 25: + name = "JJPay" + case 26: + name = "AntPay" + case 27: + name = "MlPay" + case 28: + name = "RojPay" + case 29: + name = "QuantaPay" + case 30: + name = "InnoPay" + case 31: + name = "PePay" + case 32: + name = "FF8Pay" + case 33: + name = "flapay" + case 34: + name = "DidaPay" + case 35: + name = "CYGGPay" + case 36: + name = "ZPay" + case 37: + name = "HappyPay" + case 38: + name = "FastPlusPay" + case 39: + name = "GoPay" + case 40: + name = "LemonPay" + case 41: + name = "CamelPay" + case 42: + name = "MoonPay2" + case 43: + name = "Spay" + case 44: + name = "VendooPay" + case 45: + name = "EaniPay" + case 46: + name = "AgroPay" + case 47: + name = "H4pay" + case 48: + name = "NativePay" + case 49: + name = "FeiPay" + case 50: + name = "VTPay" + case 51: + name = "NewbePay" + case 52: + name = "RoosPay" + case 53: + name = "ProPay" + case 54: + name = "FoxPay" + case 55: + name = "SuperPay" + case 56: + name = "STGoPay" + case 57: + name = "QeelinPay" + case 58: + name = "airpay" + case 59: + name = "NSpay" + case 60: + name = "RupeePay" + case 61: + name = "Fpay" + case 62: + name = "kingpay" + case 63: + name = "tkpay" + case 64: + name = "GalloPay" + case 65: + name = "MLPay2" + case 66: + name = "GlobalPay" + case 67: + name = "DDayPay" + case 68: + name = "HongxinPay" + case 69: + name = "Richpay" + case 70: + name = "MoneydealerPay" + case 71: + name = "MtxxPay" + case 72: + name = "robus" + case 73: + name = "MoneydealerNatviePay" + case 74: + name = "Virgopay" + default: + name = "unknown name" + } + return name +} + // GetConfigWithdrawLimits 获取赠送上下限配置 func GetConfigWithdrawLimits() (down, up int64) { for _, v := range configWithdrawChannels { @@ -2307,6 +2466,7 @@ func GetShareWithdrawInfo(uid int) *common.ShareWithdrawInfo { } if !util.IsSameDayTimeStamp(now, info.DayTime) { info.DayCount = 0 + info.TodayWithdraw = 0 } if info.DayCount < 0 { info.DayCount = 0 diff --git a/call/share.go b/call/share.go index 1c25475..3da9e76 100644 --- a/call/share.go +++ b/call/share.go @@ -113,14 +113,26 @@ func ShareBind(share string, isOld bool, uid, cid int) { } } // 更新上级的下级数 - ref := reflect.ValueOf(upInfo).Elem() - for i := 1; i <= 4; i++ { - upUid := int(ref.FieldByName(fmt.Sprintf("UP%d", i)).Int()) + ref := reflect.ValueOf(upInfo).Elem() // 上级的1-5级 + for i := 0; i <= 4; i++ { + var upUid int + if i == 0 { + upUid = upInfo.UID + } else { + upUid = int(ref.FieldByName(fmt.Sprintf("UP%d", i)).Int()) + } if uid == 0 { - break + continue } field := fmt.Sprintf("down%d", i+1) - db.Mysql().Update(&common.ShareInfo{UID: upUid}, map[string]interface{}{field: gorm.Expr(fmt.Sprintf("%s + 1", field))}) + log.Debug("uid:%d, field:%s", upUid, field) + updateErr := db.Mysql().C().Model(&common.ShareInfo{}).Where("uid = ?", upUid).Updates(map[string]interface{}{ + field: gorm.Expr(fmt.Sprintf("`%s` + 1", field)), + }).Error + if updateErr != nil { + log.Error("update share info err, %s", updateErr.Error()) + } + //db.Mysql().Update(&common.ShareInfo{UID: upUid}, map[string]interface{}{field:}) } // todo diff --git a/call/user.go b/call/user.go index c45cbef..4f99710 100644 --- a/call/user.go +++ b/call/user.go @@ -164,28 +164,30 @@ func NewUser(info *common.PlayerDBInfo, ip, share, fbc, fbp, agent string) error // balance := &common.CurrencyBalance{UID: uid, Type: common.CurrencyTypeBindCash, // Event: common.CurrencyEventNewPlayer, Value: initCoin, ChannelID: info.ChannelID, // Balance: initCoin, Time: time.Now().Unix(), Exs1: "NewPlayer"} + //util.Go(func() { + initPlayer(uid, cid) + ShareBind(share, isOld, uid, cid) + // 新手赠送 + first := GetConfigPlatform().NewPlayerGift + if first > 0 { + UpdateCurrencyPro(&common.UpdateCurrency{ + CurrencyBalance: &common.CurrencyBalance{ + UID: uid, + Value: first, + ChannelID: info.ChannelID, + Type: common.CurrencyINR, + Event: common.CurrencyEventNewPlayer, + NeedBet: GetConfigCurrencyResourceNeedBet(common.CurrencyResourceBonus, first), + }, + }) + } util.Go(func() { - initPlayer(uid, cid) UploadAdjust(common.AdjustEventNewPlayer, info, nil) - ShareBind(share, isOld, uid, cid) - // 新手赠送 - first := GetConfigPlatform().NewPlayerGift - if first > 0 { - UpdateCurrencyPro(&common.UpdateCurrency{ - CurrencyBalance: &common.CurrencyBalance{ - UID: uid, - Value: first, - ChannelID: info.ChannelID, - Type: common.CurrencyINR, - Event: common.CurrencyEventNewPlayer, - NeedBet: GetConfigCurrencyResourceNeedBet(common.CurrencyResourceBonus, first), - }, - }) - } FBBind(ip, uid, cid, fbc, fbp, agent) UploadFB(uid, FBEventRegist, 0) UploadKwai(uid, KwaiEventRegist, 0) }) + //}) return nil } diff --git a/common/share.go b/common/share.go index 2c902a9..5b3dc5d 100644 --- a/common/share.go +++ b/common/share.go @@ -385,6 +385,7 @@ type ShareWithdrawInfo struct { DayCount int `gorm:"column:day_count;type:int(11);default:0;comment:日退出次数"` DayTime int64 `gorm:"column:day_time;type:bigint(20);default:0;comment:日退出时间标记"` Record string `gorm:"column:record;type:varchar(256);default:'';comment:已退出金额标记"` + TodayWithdraw int64 `gorm:"column:today_withdraw;type:int(11);default:0;comment:已退出总数(今天)"` TotalWithdraw int64 `gorm:"column:total_withdraw;type:int(11);default:0;comment:已退出总数"` SubRecord map[int64]int `gorm:"-"` } diff --git a/db/mysql/mysql_exec.go b/db/mysql/mysql_exec.go index 63ccc8a..ea666e9 100644 --- a/db/mysql/mysql_exec.go +++ b/db/mysql/mysql_exec.go @@ -304,7 +304,7 @@ func (u *MysqlClient) QueryPlayerRWHistory(uid *int, channel *int, page, num int } } if status != nil && status[0] != nil { - query += fmt.Sprintf(" and status = %v", *status[0]) + query += fmt.Sprintf(" and `status` = %v", *status[0]) } if uid != nil { query += fmt.Sprintf(" and uid = %v", *uid) diff --git a/modules/backend/handler/examine/examine.go b/modules/backend/handler/examine/examine.go index fc1697e..c4be89b 100644 --- a/modules/backend/handler/examine/examine.go +++ b/modules/backend/handler/examine/examine.go @@ -106,15 +106,11 @@ func WithdrawList(c *gin.Context) { a.Code = values.CodeRetry return } - payList := map[int]string{ - 18: "GrePay", - 27: "MLPay", - 39: "GoPay", - 42: "MoonPay", - 43: "PayPlus", - 44: "LuckinPay", - 45: "EaniPay", - 46: "AgroPay", + payList := make(map[int]string) + withdrawChannels := call.GetConfigWithdrawChannels() + + for _, v := range withdrawChannels { + payList[v.ChannelID] = call.GetWithdrawChannelName(v.ChannelID) } a.Data = values.WithdrawListResp{List: WithdrawOrderArr, Count: count, PayList: payList} } diff --git a/modules/backend/values/gameuser.go b/modules/backend/values/gameuser.go index 58f5320..21d1a1e 100644 --- a/modules/backend/values/gameuser.go +++ b/modules/backend/values/gameuser.go @@ -207,12 +207,13 @@ type GetGameUserPlayDataResp struct { // ProviderID type OneGameUserPlayData struct { Time int64 - GameID int RoomName int Value int64 Balance int64 UUID string ProviderID int + GameID int + GameName string } // GetGameUserControlBalanceReq 获取游戏玩家控杀流水 diff --git a/modules/customer/app/response.go b/modules/customer/app/response.go new file mode 100644 index 0000000..3dcb7b5 --- /dev/null +++ b/modules/customer/app/response.go @@ -0,0 +1,226 @@ +package app + +import ( + "encoding/json" + "fmt" + "net/http" + "reflect" + "server/db" + "server/modules/customer/bdb" + "server/modules/customer/values" + "server/util" + "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 +} + +// 从数据库中读取数据 +func (g *Gin) MGetSqlAll(model, tar interface{}, condition map[string]interface{}) (pass bool) { + sql := "" + mod := reflect.TypeOf(model).Elem() + for k, v := range condition { + tmp, ok := mod.FieldByName(k) + if !ok { + log.Error("invalid model:%v,condition:%v", model, condition) + continue + } + tag := tmp.Tag.Get("web") + if tag == "" || tag == "-" { + log.Error("invalid model:%v,condition:%v", model, condition) + continue + } + reft := reflect.TypeOf(v) + ref := reflect.ValueOf(v) + if reft.Kind() == reflect.Slice { + if ref.Len() != 2 { + log.Error("invalid model:%v,condition:%v", model, condition) + continue + } + if len(sql) > 0 { + sql += " and " + } + sql += fmt.Sprintf("%s >= %v and %s <= %v", tag, ref.Index(0).Interface(), tag, ref.Index(1).Interface()) + } else { + if len(sql) > 0 { + sql += " and " + } + sql += fmt.Sprintf("%s = %v", tag, ref.Interface()) + } + } + if _, err := db.Mysql().QueryAll(sql, "", model, tar); err != nil { + log.Error("err:%v", err) + g.Code = values.CodeRetry + g.R.Msg = err.Error() + return + } + pass = true + return +} + +func (g *Gin) MUpdateAll(updates []map[string]interface{}, element interface{}) (pass bool) { + for _, v := range updates { + tmp := reflect.New(reflect.TypeOf(element).Elem()).Interface() + // log.Debug("%v", v) + tmpbyte, _ := json.Marshal(v) + err := json.Unmarshal(tmpbyte, &tmp) + if err != nil { + log.Error("err%v", err) + return + } + ref := reflect.ValueOf(tmp).Elem() + reft := reflect.TypeOf(tmp).Elem() + id := ref.FieldByName("ID").Int() + if id == 0 { + if err := db.Mysql().Create(tmp); err != nil { + g.Code = values.CodeRetry + return + } + } else { + update := map[string]interface{}{} + for k := range v { + field, ok := reft.FieldByName(k) + if !ok { + field, ok = util.GetStructFieldByJsonTag(tmp, k) + if !ok { + continue + } + k = field.Name + } + tag := field.Tag.Get("web") + if tag == "" || tag == "-" { + continue + } + update[tag] = ref.FieldByName(k).Interface() + } + // update := util.StructToMap(tmp, "web") + model := reflect.New(reflect.TypeOf(element).Elem()) + model.Elem().FieldByName("ID").SetInt(id) + // log.Debug("element:%v", element) + log.Debug("update:%v", update) + log.Debug("model:%v", model) + if err := db.Mysql().Update(model.Interface(), update); err != nil { + g.Code = values.CodeRetry + return + } + } + } + pass = true + return +} + +func (g *Gin) MDel(id int, element interface{}) (pass bool) { + tmp := reflect.New(reflect.TypeOf(element).Elem()) + tmp.Elem().FieldByName("ID").SetInt(int64(id)) + if !db.Mysql().Exist(tmp.Interface()) { + g.Code = values.CodeParam + g.Msg = "该id不存在" + return + } + if err := db.Mysql().Del(tmp.Interface()); err != nil { + g.Code = values.CodeRetry + return + } + pass = true + return +} diff --git a/modules/customer/bdb/exec.go b/modules/customer/bdb/exec.go new file mode 100644 index 0000000..57d1627 --- /dev/null +++ b/modules/customer/bdb/exec.go @@ -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 +} diff --git a/modules/customer/bdb/mysql.go b/modules/customer/bdb/mysql.go new file mode 100644 index 0000000..339fad3 --- /dev/null +++ b/modules/customer/bdb/mysql.go @@ -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) + } +} diff --git a/modules/customer/config.go b/modules/customer/config.go new file mode 100644 index 0000000..b7e2998 --- /dev/null +++ b/modules/customer/config.go @@ -0,0 +1,21 @@ +package customer + +import ( + "server/call" + "server/common" + "server/pb" +) + +func loadConfig() error { + c := map[int][]func(*pb.ReloadGameConfig) error{} + c[common.ReloadTypeExcel] = []func(*pb.ReloadGameConfig) error{ReloadExcel} + call.LoadConfigs(c) + return nil +} + +func ReloadExcel(c *pb.ReloadGameConfig) error { + if err := call.LoadGoodsConfig(); err != nil { + return err + } + return nil +} diff --git a/modules/customer/handler/account/account.go b/modules/customer/handler/account/account.go new file mode 100644 index 0000000..51efe3e --- /dev/null +++ b/modules/customer/handler/account/account.go @@ -0,0 +1,81 @@ +// 账号相关的接口实现 +package handler + +import ( + "fmt" + "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)} +} + +// 操作 1上线 2下线 +type OnlineReq struct { + Opt int +} + +func Online(c *gin.Context) { + a := app.NewApp(c) + defer func() { + a.Response() + }() + // if a.User.Role != values.UserRole2 { + // return + // } + req := new(OnlineReq) + if !a.S(req) { + return + } + str := "上线" + opt := 1 + if req.Opt == 2 { + str = "下线" + opt = 0 + } + bdb.BackDB.Update(&values.User{ID: a.User.ID}, map[string]interface{}{"online": opt}) + a.RecordEdit(values.PowerGM, fmt.Sprintf("客服%s", str)) +} + +type OnlineResp struct { + Status int +} + +func OnlineStatus(c *gin.Context) { + a := app.NewApp(c) + defer func() { + a.Response() + }() + user := &values.User{ID: a.User.ID} + bdb.BackDB.Get(user) + resp := OnlineResp{Status: user.Online} + a.Data = resp +} diff --git a/modules/customer/handler/chat/chat.go b/modules/customer/handler/chat/chat.go new file mode 100644 index 0000000..8cf0d48 --- /dev/null +++ b/modules/customer/handler/chat/chat.go @@ -0,0 +1,414 @@ +package chat + +import ( + "fmt" + "server/call" + "server/common" + "server/db" + "server/modules/customer/app" + "server/modules/customer/values" + "server/pb" + "time" + + "github.com/gin-gonic/gin" + "github.com/liangdas/mqant/log" + "gorm.io/gorm" +) + +// 获取聊天历史 +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 + } + + list := []common.CustomerOrder{} + db.Mysql().QueryList(0, 100, fmt.Sprintf("uid = %d and reply = 0", req.Title), "", &common.CustomerOrder{}, &list) + + for _, v := range list { + u := map[string]interface{}{"is_read": false, "reply": true} + if v.FirstReplyTime == 0 { + u["first_reply_time"] = req.Time + } + db.Mysql().Update(&common.CustomerOrder{ID: v.ID}, u) + } + + // 客服回复后,标记玩家读取状态为未读 + // db.Mysql().Update(&common.CustomerOrder{Uid: req.Title}, map[string]interface{}{"is_read": false, "reply": true}) + + // 需要通知在线玩家刷新客服消息 + 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 + } else { + if req.CustomerUid != 0 { + if flag { + query += " AND " + } + query += fmt.Sprintf(" customer_uid = %v ", req.CustomerUid) + flag = true + } else if a.User.Role == values.UserRole2 { + if flag { + query += " AND " + } + query += fmt.Sprintf(" customer_uid = %v ", a.User.ID) + 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 + } + + if req.Reply > 0 { + if flag { + query += " AND " + } + if req.Reply == 1 { + query += fmt.Sprintf(" reply = %d ", 1) + } else { + query += fmt.Sprintf(" reply = %d ", 0) + } + flag = true + } + + if req.Recharge { + if flag { + query += " AND " + } + query += " order_id != ''" + 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 + }*/ + if req.List[i].Status == common.CustomerOrderComplete { + order := &common.CustomerOrder{ID: req.List[i].Id} + db.Mysql().Get(order) + if !order.Reply { + a.Code = values.CodeParam + a.Msg = fmt.Sprintf("玩家%d的订单还未回复,不能修改为完成状态", order.Uid) + return + } + } + + 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 + + // if req.List[i].Remark != "" { + update["remark"] = req.List[i].Remark + // } + + // 完成工单 + 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 +} diff --git a/modules/customer/handler/common/common.go b/modules/customer/handler/common/common.go new file mode 100644 index 0000000..2506adb --- /dev/null +++ b/modules/customer/handler/common/common.go @@ -0,0 +1,216 @@ +package common + +import ( + "fmt" + "io" + "mime" + "net/http" + "os" + "server/call" + "server/config" + "server/modules/customer/app" + "server/modules/customer/bdb" + "server/modules/customer/values" + "server/util" + "strings" + "time" + + "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() + }() + goods := call.GetGoodsConfig() + resp := &values.GoodListResp{List: goods} + a.Data = resp +} + +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 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 +} diff --git a/modules/customer/handler/gm/gm.go b/modules/customer/handler/gm/gm.go new file mode 100644 index 0000000..eb4d71b --- /dev/null +++ b/modules/customer/handler/gm/gm.go @@ -0,0 +1,451 @@ +package gm + +import ( + "fmt" + "server/call" + "server/common" + "server/db" + "server/modules/customer/app" + "server/modules/customer/values" + "server/natsClient" + "server/pb" + "server/util" + "strings" + + "github.com/gin-gonic/gin" + "github.com/liangdas/mqant/log" +) + +// 获取客服机器人消息 +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])) + } + } +} + +// ConfigControlCommon 所有调控配置通用逻辑 +func ConfigControlCommon(c *gin.Context) { + a := app.NewApp(c) + defer func() { + a.Response() + }() + path := c.Request.URL.Path + path = strings.ReplaceAll(path, "/gm/control/", "") + all := strings.Split(path, "/") + if len(all) > 2 { + a.Code = values.CodeRetry + return + } + t := all[0] + opt := all[1] + element, list := GetElementByPath(t) + var resp interface{} + if opt == "list" { + req := &values.GMConfigCommonListReq{ + Condition: map[string]interface{}{}, + } + a.S(req) + if !a.MGetSqlAll(element, list, req.Condition) { + return + } + resp = values.GMConfigCommonListResp{Config: list} + } else if opt == "edit" { + req := new(values.GMConfigCommonEditReq) + if !a.S(req) { + return + } + if !a.MUpdateAll(req.Config, element) { + return + } + // call.Publish(natsClient.TopicReloadConfig, &pb.ReloadGameConfig{Type: int32(reloadType)}) + } else if opt == "del" { + req := new(values.GMConfigCommonDelReq) + if !a.S(req) { + return + } + if !a.MDel(req.ID, element) { + return + } + // call.Publish(natsClient.TopicReloadConfig, &pb.ReloadGameConfig{Type: int32(reloadType)}) + } + a.Data = resp +} diff --git a/modules/customer/handler/gm/values.go b/modules/customer/handler/gm/values.go new file mode 100644 index 0000000..cd39d63 --- /dev/null +++ b/modules/customer/handler/gm/values.go @@ -0,0 +1,12 @@ +package gm + +import "server/common" + +func GetElementByPath(path string) (interface{}, interface{}) { + switch path { + case "customerPhrases": + return &common.ConfigCustomerPhrases{}, &[]common.ConfigCustomerPhrases{} + default: + return nil, nil + } +} diff --git a/modules/customer/handler/guser/activeUserList.go b/modules/customer/handler/guser/activeUserList.go new file mode 100644 index 0000000..ee87834 --- /dev/null +++ b/modules/customer/handler/guser/activeUserList.go @@ -0,0 +1,122 @@ +package guser + +import ( + "fmt" + "server/common" + "server/db" + utils "server/modules/backend/util" + "server/modules/backend/values" + "server/modules/customer/app" + "server/util" + + "github.com/gin-gonic/gin" + "github.com/liangdas/mqant/log" + "github.com/olivere/elastic/v7" +) + +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.Filter(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.Filter(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 +} diff --git a/modules/customer/handler/guser/addUserBlackList.go b/modules/customer/handler/guser/addUserBlackList.go new file mode 100644 index 0000000..9ddbafe --- /dev/null +++ b/modules/customer/handler/guser/addUserBlackList.go @@ -0,0 +1,87 @@ +package guser + +import ( + "encoding/json" + "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 := info.BankCardNo + //if info.DrawType == common.WithdrawTypeBank { + // if info.BankCardNo != "" { + // acc = info.BankCardNo + // } + //} else if info.DrawType == common.WithdrawTypeUPI { + // 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 = "该用户信息已在黑名单里" + } + } + } +} diff --git a/modules/customer/handler/guser/addUserTag.go b/modules/customer/handler/guser/addUserTag.go new file mode 100644 index 0000000..4bc279b --- /dev/null +++ b/modules/customer/handler/guser/addUserTag.go @@ -0,0 +1,31 @@ +package guser + +import ( + "github.com/gin-gonic/gin" + "github.com/liangdas/mqant/log" + "server/common" + "server/db" + "server/modules/customer/app" + "server/modules/backend/values" +) + +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 + } + +} diff --git a/modules/customer/handler/guser/banUserList.go b/modules/customer/handler/guser/banUserList.go new file mode 100644 index 0000000..6a92d24 --- /dev/null +++ b/modules/customer/handler/guser/banUserList.go @@ -0,0 +1,58 @@ +package guser + +import ( + "server/call" + "server/common" + "server/db" + "server/modules/backend/models" + utils "server/modules/backend/util" + "server/modules/backend/values" + "server/modules/customer/app" + + "github.com/gin-gonic/gin" + "github.com/liangdas/mqant/log" + "github.com/olivere/elastic/v7" +) + +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.Filter(elastic.NewRangeQuery("Time").Gt(su)) + q.Filter(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 +} diff --git a/modules/customer/handler/guser/bigRUserData.go b/modules/customer/handler/guser/bigRUserData.go new file mode 100644 index 0000000..a27bd0a --- /dev/null +++ b/modules/customer/handler/guser/bigRUserData.go @@ -0,0 +1 @@ +package guser diff --git a/modules/customer/handler/guser/controlCardData.go b/modules/customer/handler/guser/controlCardData.go new file mode 100644 index 0000000..6f367b7 --- /dev/null +++ b/modules/customer/handler/guser/controlCardData.go @@ -0,0 +1,81 @@ +package guser + +import ( + "github.com/gin-gonic/gin" + "github.com/liangdas/mqant/log" + "server/common" + "server/modules/backend/models" + utils "server/modules/backend/util" + "server/modules/backend/values" + "server/modules/customer/app" +) + +func ControlCardData(c *gin.Context) { + a := app.NewApp(c) + defer func() { + a.Response() + }() + req := new(values.ControlCardDataReq) + if !a.S(req) { + return + } + var resp values.ControlCardDataResp + event := int(common.CurrencyEventGameSettle) + + s, e := utils.GetQueryUnix(req.Start, req.End) + + var balance []common.CurrencyBalance + count, err := models.QueryPlayerAllBalance(req.Uid, req.Page-1, req.Num, &s, &e, req.GameId, req.RoomId, req.ControlType, req.Channel, &event, &balance) + if err != nil { + log.Error("err:%v", err) + a.Code = values.CodeRetry + return + } + + //MillionGameIdMap := make(map[string]bool) + //for i := 0; i < len(common.MillionGameIDs); i++ { + // MillionGameIdMap[strconv.Itoa(common.MillionGameIDs[i].(int))] = true + //} + // + //for i := 0; i < len(balance); i++ { + // var playerBalance values.PlayerBalance + // playerBalance.CurrencyBalance = balance[i] + // + // if _, ok := MillionGameIdMap[balance[i].Desc]; ok { + // playerBalance.MillionBetArea, playerBalance.Result = getMillionBetArea(balance[i].Extern, balance[i].Uid) + // } + // + // resp.List = append(resp.List, playerBalance) + //} + + resp.Total = count + a.Data = resp +} + +func getAndarBaharArea(res int) string { + if 1 <= res && res <= 5 { + return "2" + } + if 6 <= res && res <= 10 { + return "3" + } + if 11 <= res && res <= 15 { + return "4" + } + if 16 <= res && res <= 25 { + return "5" + } + if 26 <= res && res <= 30 { + return "6" + } + if 31 <= res && res <= 35 { + return "7" + } + if 36 <= res && res <= 40 { + return "8" + } + if 41 <= res && res <= 100 { + return "9" + } + return "-1" +} diff --git a/modules/customer/handler/guser/editGameUserGold.go b/modules/customer/handler/guser/editGameUserGold.go new file mode 100644 index 0000000..f2021dd --- /dev/null +++ b/modules/customer/handler/guser/editGameUserGold.go @@ -0,0 +1,53 @@ +package guser + +import ( + "fmt" + "server/call" + "server/common" + "server/modules/backend/values" + "server/modules/customer/app" + + "github.com/gin-gonic/gin" + "github.com/liangdas/mqant/log" +) + +// 修改玩家金币 +func EditGameUserGold(c *gin.Context) { + a := app.NewApp(c) + defer func() { + a.Response() + }() + req := new(values.EditGameUserGoldReq) + if !a.S(req) { + return + } + //var ct common.CurrencyType + //switch req.Type { + //case 1: + // ct = common.CurrencyTypeBindCash + //case 2: + // ct = common.CurrencyTypeCash + //default: + // a.Code = values.CodeParam + // a.Msg = "非法请求类型" + // return + //} + user, _ := call.GetUserXInfo(req.UID, "channel_id") + _ = user + _, err := call.UpdateCurrencyPro(&common.UpdateCurrency{ + CurrencyBalance: &common.CurrencyBalance{ + UID: req.UID, + Event: common.CurrencyEventGM, + Type: common.CurrencyINR, + Value: req.Amount, + ChannelID: user.ChannelID, + //NeedBet: GetConfigCurrencyResourceNeedBet(common.CurrencyResourceBonus, conf.Reward), + }, + }) + if err != nil { + log.Error("err:%v", err) + a.Code = values.CodeRetry + return + } + a.RecordEdit(values.PowerGUser, fmt.Sprintf("修改玩家%v金币:%v", req.UID, req.Amount)) +} diff --git a/modules/customer/handler/guser/editGameUserStatus.go b/modules/customer/handler/guser/editGameUserStatus.go new file mode 100644 index 0000000..04d9ba0 --- /dev/null +++ b/modules/customer/handler/guser/editGameUserStatus.go @@ -0,0 +1,56 @@ +package guser + +import ( + "fmt" + "server/call" + "server/common" + "server/db" + "server/modules/customer/app" + "server/modules/backend/values" + "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)) +} diff --git a/modules/customer/handler/guser/getGameUserAllBalance.go b/modules/customer/handler/guser/getGameUserAllBalance.go new file mode 100644 index 0000000..12c51c3 --- /dev/null +++ b/modules/customer/handler/guser/getGameUserAllBalance.go @@ -0,0 +1,34 @@ +package guser + +import ( + "github.com/gin-gonic/gin" + "github.com/liangdas/mqant/log" + "server/common" + "server/db" + "server/modules/customer/app" + "server/modules/backend/values" +) + +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 +} diff --git a/modules/customer/handler/guser/getGameUserControlBalance.go b/modules/customer/handler/guser/getGameUserControlBalance.go new file mode 100644 index 0000000..208c128 --- /dev/null +++ b/modules/customer/handler/guser/getGameUserControlBalance.go @@ -0,0 +1,47 @@ +package guser + +import ( + "github.com/gin-gonic/gin" + "github.com/liangdas/mqant/log" + "server/common" + "server/db" + "server/modules/customer/app" + "server/modules/backend/models" + utils "server/modules/backend/util" + "server/modules/backend/values" +) + +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 +} diff --git a/modules/customer/handler/guser/getGameUserInfo.go b/modules/customer/handler/guser/getGameUserInfo.go new file mode 100644 index 0000000..5164b30 --- /dev/null +++ b/modules/customer/handler/guser/getGameUserInfo.go @@ -0,0 +1,183 @@ +package guser + +import ( + "fmt" + "github.com/olivere/elastic/v7" + "server/call" + "server/common" + "server/db" + "server/modules/backend/values" + "server/modules/customer/app" + "strconv" + + "github.com/gin-gonic/gin" + "github.com/liangdas/mqant/log" + uutil "server/util" +) + +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: user.LastLogin, + 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, + } + + var tmpUser []common.PlayerDBInfo + _, err = db.Mysql().QueryAll(fmt.Sprintf("deviceid = '%s'", user.DeviceId), "", &common.PlayerDBInfo{}, &tmpUser) + if err != nil { + log.Error(err.Error()) + } + for _, v := range tmpUser { + resp.SubAccount = append(resp.SubAccount, v.Id) + } + 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.GetConfigGameListByID(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 +} diff --git a/modules/customer/handler/guser/getGameUserList.go b/modules/customer/handler/guser/getGameUserList.go new file mode 100644 index 0000000..46f55eb --- /dev/null +++ b/modules/customer/handler/guser/getGameUserList.go @@ -0,0 +1,206 @@ +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" + "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 + + // 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 != 0 { + 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 != 0 { + 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 != 0 { + 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 != 0 { + 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 { + _ = i + 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 +} diff --git a/modules/customer/handler/guser/getGameUserPlayData.go b/modules/customer/handler/guser/getGameUserPlayData.go new file mode 100644 index 0000000..67c5d68 --- /dev/null +++ b/modules/customer/handler/guser/getGameUserPlayData.go @@ -0,0 +1,52 @@ +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, + Value: v.Value, + Balance: v.Balance, + UUID: v.Exs1, + ProviderID: v.Exi1, + GameID: v.Exi2, + GameName: v.Exs4, + }) + } + a.Data = resp +} diff --git a/modules/customer/handler/guser/getGameUserPlayDetail.go b/modules/customer/handler/guser/getGameUserPlayDetail.go new file mode 100644 index 0000000..6f79bfa --- /dev/null +++ b/modules/customer/handler/guser/getGameUserPlayDetail.go @@ -0,0 +1,67 @@ +package guser + +import ( + "github.com/gin-gonic/gin" + "github.com/liangdas/mqant/log" + "github.com/olivere/elastic/v7" + "server/common" + "server/db" + "server/modules/backend/values" + "server/modules/customer/app" +) + +func GetGameUserPlayDetail(c *gin.Context) { + a := app.NewApp(c) + defer func() { + a.Response() + }() + req := new(values.GetGameUserPlayDetailReq) + if !a.S(req) { + return + } + + data := common.CurrencyBalance{} + q := elastic.NewBoolQuery() + q.Filter(elastic.NewTermQuery("extern.keyword", req.UUID)) + q.Filter(elastic.NewTermQuery("event", common.CurrencyEventGameSettle)) + err := db.ES().QueryOne(common.ESIndexBalance, q, &data) + if err != nil { + log.Error("err:%v", err) + a.Code = values.CodeRetry + return + } + //gameId, err := strconv.Atoi(data.Desc) + //if err != nil { + // log.Error("err:%v", err) + // a.Code = values.CodeRetry + // return + //} + resp := values.GetGameUserPlayDetailResp{} + //resp.GameId = gameId + a.Data = resp + //if data.Desc == fmt.Sprintf("%d", common.GameIDDragon) || data.Desc == fmt.Sprintf("%d", common.GameIDSeven) { + // res, err := getDVTGameUserPlayDetail(req.UUID, req.UID) + // if err != nil { + // log.Error("查询百人模式游戏数据统计失败, error : [%s]", err.Error()) + // a.Code = values.CodeRetry + // return + // } + // resp.Result = res + // a.Data = resp + //} else { + // + // if 2001 <= gameId && gameId < 3000 { + // Result, History := getESTeenpattiOperateLog(req.UUID) + // resp.Result = Result + // resp.History = History + // } + // + // if 3001 <= gameId && gameId < 4000 { + // Result, History := getESRummyOperateLog(req.UUID) + // resp.Result = Result + // resp.History = History + // } + // + // a.Data = resp + //} +} diff --git a/modules/customer/handler/guser/getGameUserRechargeHistory.go b/modules/customer/handler/guser/getGameUserRechargeHistory.go new file mode 100644 index 0000000..122555b --- /dev/null +++ b/modules/customer/handler/guser/getGameUserRechargeHistory.go @@ -0,0 +1,63 @@ +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 + } + log.Debug("req:") + 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, &common.RechargeOrder{}, &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.TotalRecharge + 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 +} diff --git a/modules/customer/handler/guser/getGameUserWithdrawHistory.go b/modules/customer/handler/guser/getGameUserWithdrawHistory.go new file mode 100644 index 0000000..538a5e8 --- /dev/null +++ b/modules/customer/handler/guser/getGameUserWithdrawHistory.go @@ -0,0 +1,67 @@ +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" + + "github.com/gin-gonic/gin" + "github.com/liangdas/mqant/log" +) + +func GetGameUserWithdrawHistory(c *gin.Context) { + a := app.NewApp(c) + defer func() { + a.Response() + }() + req := new(values.GetGameUserWithdrawHistoryReq) + if !a.S(req) { + return + } + resp := values.GetGameUserWithdrawHistoryResp{} + var ret []common.WithdrawOrder + if req.UID > 0 { + count, err := db.Mysql().QueryPlayerRWHistory(&req.UID, nil, req.Page-1, req.Num, []int{int(common.CurrencyEventWithDraw)}, req.Start, req.End, &common.WithdrawOrder{}, &ret) + 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.OneWithdrawList{UID: v.UID, Time: v.CreateTime, PayAccount: v.PayAccount, + Amount: v.Amount, Status: int(v.Status), OrderID: v.APIPayID, MyOrderID: v.OrderID, FailReason: v.FailReason, OrderCreateAt: v.CreateTime, + AuditTime: 0, CallbackTime: v.CallbackTime, Channel: v.PayChannel}) + } + resp.WithdrawCount = db.Mysql().Count(&common.WithdrawOrder{}, fmt.Sprintf("uid = %v and event = %v", req.UID, common.CurrencyEventWithDraw)) + re := &common.RechargeInfo{UID: req.UID} + err = db.Mysql().Get(re) + if err != nil { + log.Error(err.Error()) + } + resp.WithdrawTotal = re.TotalWithdraw + successCount := db.Mysql().Count(&common.WithdrawOrder{}, fmt.Sprintf("uid = %v and event = %v and status = %v", req.UID, common.CurrencyEventWithDraw, common.StatusROrderFinish)) + resp.WithdrawSuccessPer = utils.GetPer(successCount, resp.WithdrawCount) + resp.WithdrawCash = db.Mysql().Sum(&common.WithdrawOrder{}, fmt.Sprintf("uid = %v and event = %v and status = %v", req.UID, common.CurrencyEventWithDraw, common.StatusROrderFinish), "withdraw_cash") + resp.WithdrawTax = resp.WithdrawCash - resp.WithdrawTotal*100 + resp.RechargeTotal = models.GetRechargeTotalByUid(&req.UID) + resp.WithDrawPer = utils.GetPer(resp.WithdrawTotal, resp.RechargeTotal) + } else if req.Data != "" { + resp.Count, _ = db.Mysql().QueryList(req.Page-1, req.Num, fmt.Sprintf(`event = %v and (apipayid = "%v" or orderid = '%v')`, common.CurrencyEventWithDraw, req.Data, req.Data), "created_at desc", &common.WithdrawOrder{}, &ret) + for _, v := range ret { + resp.List = append(resp.List, values.OneWithdrawList{UID: v.UID, Time: v.CreateTime, PayAccount: v.PayAccount, + Amount: v.Amount, Status: int(v.Status), OrderID: v.APIPayID, MyOrderID: v.OrderID, FailReason: v.FailReason, OrderCreateAt: v.CreateTime, + AuditTime: 0, CallbackTime: v.CallbackTime, Channel: v.PayChannel}) + } + } else { + a.Code = values.CodeParam + a.Msg = "查询条件有误" + return + } + + a.Data = resp +} diff --git a/modules/customer/handler/guser/lostPlayerData.go b/modules/customer/handler/guser/lostPlayerData.go new file mode 100644 index 0000000..57bbf85 --- /dev/null +++ b/modules/customer/handler/guser/lostPlayerData.go @@ -0,0 +1,113 @@ +package guser + +import ( + "fmt" + "github.com/gin-gonic/gin" + "github.com/liangdas/mqant/log" + "server/call" + "server/common" + "server/db" + "server/modules/backend/models" + utils "server/modules/backend/util" + "server/modules/backend/values" + "server/modules/customer/app" + "strconv" + "time" +) + +func LostPlayerData(c *gin.Context) { + a := app.NewApp(c) + defer func() { + a.Response() + }() + req := new(values.LostPlayerDataReq) + if !a.S(req) { + return + } + resp := values.LostPlayerDataResp{} + + su, eu := utils.GetQueryUnix(req.Start, req.End) + var oneDay int64 = 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 req.Channel != nil { + str += fmt.Sprintf(" AND u.channel_id = %d AND r.channel_id = %d", *req.Channel, *req.Channel) + } + + // 三天未登录的用户 UNIX_TIMESTAMP('20210816') + str += fmt.Sprintf(" AND (%d - UNIX_TIMESTAMP(r.date) > %d ) ", now, 3*oneDay) + + var count int64 + err := db.Mysql().QueryBySql(fmt.Sprintf(queryCount+str, eu, eu), &count) + if err != nil { + log.Error(err.Error()) + } + + str += " GROUP BY u.id " + + str += fmt.Sprintf(" LIMIT %d, %d ", (req.Page-1)*req.Num, req.Num) + + var users []common.PlayerDBInfo + err = db.Mysql().QueryBySql(fmt.Sprintf(queryUser+str, eu, eu), &users) + if err != nil { + log.Error(err.Error()) + } + + for i := 0; i < len(users); i++ { + var lostPlayerData values.LostPlayerData + lostPlayerData.Date = su + lostPlayerData.Nick = users[i].Nick + lostPlayerData.Uid = users[i].Id + lostPlayerData.Birth = users[i].Birth + lostPlayerData.Amount = call.GetUserCurrencyTotal(users[i].Id, 0) + + 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()) + } + lostPlayerData.LastLogin = record.Time + + // 玩家提现金额 + lostPlayerData.WithDrawAmount = models.GetWithdrawTotalByUid(&users[i].Id) + + // 玩家游戏局数 + //gameCount := make(map[string]int64) + // 房间游戏数据 + //for j := 0; j < len(common.RoomGameIDs); j++ { + // gameCount[strconv.Itoa(common.RoomGameIDs[j])] = models.GetUserGameCount(nil, nil, &users[i].Id, &common.RoomGameIDs[j], nil, req.Channel) + // lostPlayerData.GameCount += gameCount[strconv.Itoa(common.RoomGameIDs[j])] + //} + // + //// 百人游戏数据 + //for j := 0; j < len(common.MillionGameIDs); j++ { + // millionGameID := common.MillionGameIDs[j].(int) + // gameCount[strconv.Itoa(millionGameID)] = models.GetUserGameCount(nil, nil, &users[i].Id, &millionGameID, nil, req.Channel) + // lostPlayerData.GameCount += gameCount[strconv.Itoa(millionGameID)] + //} + //lostPlayerData.MostGameCount = gameCount + + // 最后三局游戏记录 + event := int(common.CurrencyEventGameSettle) + var balance []common.CurrencyBalance + uid := strconv.Itoa(users[i].Id) + _, err = models.QueryUserBalance(&uid, 0, 3, nil, nil, nil, nil, nil, req.Channel, &event, &balance) + if err != nil { + log.Error(err.Error()) + return + } + for j := 0; j < len(balance); j++ { + lostPlayerData.GameRecord = append(lostPlayerData.GameRecord, balance[j].Value) + } + + resp.List = append(resp.List, lostPlayerData) + } + + resp.Count = count + a.Data = resp +} diff --git a/modules/customer/handler/guser/lostUserData.go b/modules/customer/handler/guser/lostUserData.go new file mode 100644 index 0000000..1ef0de3 --- /dev/null +++ b/modules/customer/handler/guser/lostUserData.go @@ -0,0 +1,242 @@ +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" + "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 = call.GetUserCurrencyTotal(users[i].Id, 0) + // 玩家总提现金额 + 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 +} diff --git a/modules/customer/handler/guser/lostUserDetail.go b/modules/customer/handler/guser/lostUserDetail.go new file mode 100644 index 0000000..3cf6791 --- /dev/null +++ b/modules/customer/handler/guser/lostUserDetail.go @@ -0,0 +1,39 @@ +package guser + +//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 +//} diff --git a/modules/customer/handler/guser/rechargeRank.go b/modules/customer/handler/guser/rechargeRank.go new file mode 100644 index 0000000..99851f3 --- /dev/null +++ b/modules/customer/handler/guser/rechargeRank.go @@ -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 +} diff --git a/modules/customer/handler/power/power.go b/modules/customer/handler/power/power.go new file mode 100644 index 0000000..057ecc2 --- /dev/null +++ b/modules/customer/handler/power/power.go @@ -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)) +} diff --git a/modules/customer/middleware/cross.go b/modules/customer/middleware/cross.go new file mode 100644 index 0000000..6050e31 --- /dev/null +++ b/modules/customer/middleware/cross.go @@ -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() + } +} diff --git a/modules/customer/middleware/power.go b/modules/customer/middleware/power.go new file mode 100644 index 0000000..aca8f0c --- /dev/null +++ b/modules/customer/middleware/power.go @@ -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 +} diff --git a/modules/customer/middleware/token.go b/modules/customer/middleware/token.go new file mode 100644 index 0000000..6706d9b --- /dev/null +++ b/modules/customer/middleware/token.go @@ -0,0 +1,90 @@ +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() { + 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 +} diff --git a/modules/customer/module.go b/modules/customer/module.go new file mode 100644 index 0000000..12932f8 --- /dev/null +++ b/modules/customer/module.go @@ -0,0 +1,114 @@ +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" + "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() + + // 加载配置 + call.Go(func() { + loadConfig() + }) + + b.addr = config.GetConfig().Customer.Addr + + call.NewSnowflake(int64(config.GetConfig().WorkID)) + + call.InitReload(b.App.Transport()) + + StartTimer() +} + +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 模块已销毁") +} diff --git a/modules/customer/routers/routers.go b/modules/customer/routers/routers.go new file mode 100644 index 0000000..ac5b9fe --- /dev/null +++ b/modules/customer/routers/routers.go @@ -0,0 +1,41 @@ +package routers + +import ( + "runtime" + "server/config" + "server/modules/customer/middleware" + + "github.com/gin-gonic/gin" + "github.com/liangdas/mqant/log" +) + +func SetUpRouter() *gin.Engine { + release := config.GetConfig().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(gin.RecoveryWithWriter(log.LogBeego(), func(c *gin.Context, err interface{}) { + buf := make([]byte, 1024) + runtime.Stack(buf, false) + log.Error("panic(%+v), stack:\n%s", err, string(buf)) + })) + + gmHandle(r) + account(r) + power(r) + common(r) + chat(r) + mail(r) + guser(r) + + return r +} diff --git a/modules/customer/routers/routers_account.go b/modules/customer/routers/routers_account.go new file mode 100644 index 0000000..fe2b2f8 --- /dev/null +++ b/modules/customer/routers/routers_account.go @@ -0,0 +1,14 @@ +// 账号相关的接口 +package routers + +import ( + handler "server/modules/customer/handler/account" + + "github.com/gin-gonic/gin" +) + +func account(e *gin.Engine) { + e.POST("/account/login", handler.Login) + e.POST("/account/online", handler.Online) + e.POST("/account/onlineStatus", handler.OnlineStatus) +} diff --git a/modules/customer/routers/routers_chat.go b/modules/customer/routers/routers_chat.go new file mode 100644 index 0000000..b2193ad --- /dev/null +++ b/modules/customer/routers/routers_chat.go @@ -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) +} diff --git a/modules/customer/routers/routers_common.go b/modules/customer/routers/routers_common.go new file mode 100644 index 0000000..4f44b6e --- /dev/null +++ b/modules/customer/routers/routers_common.go @@ -0,0 +1,23 @@ +// 账号相关的接口 +package routers + +import ( + "github.com/gin-gonic/gin" + handler "server/modules/customer/handler/common" +) + +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/channelList", handler.ChannelList) + e.GET("/common/userInfo", handler.UserInfo) +} diff --git a/modules/customer/routers/routers_gm.go b/modules/customer/routers/routers_gm.go new file mode 100644 index 0000000..ac31b08 --- /dev/null +++ b/modules/customer/routers/routers_gm.go @@ -0,0 +1,31 @@ +package routers + +import ( + handler "server/modules/customer/handler/gm" + + "github.com/gin-gonic/gin" +) + +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) + + e.GET("/gm/control/*action", handler.ConfigControlCommon) + e.POST("/gm/control/*action", handler.ConfigControlCommon) +} diff --git a/modules/customer/routers/routers_guser.go b/modules/customer/routers/routers_guser.go new file mode 100644 index 0000000..fe883ca --- /dev/null +++ b/modules/customer/routers/routers_guser.go @@ -0,0 +1,26 @@ +package routers + +import ( + handler "server/modules/customer/handler/guser" + + "github.com/gin-gonic/gin" +) + +func guser(e *gin.Engine) { + e.POST("/guser/list", handler.GetGameUserList) + e.POST("/guser/activeUserList", handler.ActiveUserList) + + e.POST("/guser/info", handler.GetGameUserInfo) + e.POST("/guser/allBalance", handler.GetGameUserAllBalance) + e.POST("/guser/playData", handler.GetGameUserPlayData) + e.POST("/guser/playDetail", handler.GetGameUserPlayDetail) + e.POST("/guser/rechargeHistory", handler.GetGameUserRechargeHistory) + e.POST("/guser/withdrawHistory", handler.GetGameUserWithdrawHistory) + e.POST("/guser/controlBalance", handler.GetGameUserControlBalance) + e.POST("/guser/controlCardData", handler.ControlCardData) + e.POST("/guser/editGold", handler.EditGameUserGold) + e.POST("/guser/editStatus", handler.EditGameUserStatus) + e.POST("/guser/addUserTag", handler.AddUserTag) + e.POST("/guser/deleteUserTag", handler.AddUserTag) + e.POST("/guser/addUserBlackList", handler.AddUserBlackList) +} diff --git a/modules/customer/routers/routers_mail.go b/modules/customer/routers/routers_mail.go new file mode 100644 index 0000000..b8f1573 --- /dev/null +++ b/modules/customer/routers/routers_mail.go @@ -0,0 +1,12 @@ +package routers + +import ( + "github.com/gin-gonic/gin" +) + +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) +} diff --git a/modules/customer/routers/routers_power.go b/modules/customer/routers/routers_power.go new file mode 100644 index 0000000..9a37e8e --- /dev/null +++ b/modules/customer/routers/routers_power.go @@ -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) +} diff --git a/modules/customer/timer.go b/modules/customer/timer.go new file mode 100644 index 0000000..b3ec52f --- /dev/null +++ b/modules/customer/timer.go @@ -0,0 +1,113 @@ +package customer + +import ( + "fmt" + "math/rand" + "server/common" + "server/config" + "server/db" + "server/modules/customer/bdb" + "server/modules/customer/values" + "server/util" + "time" + + "github.com/liangdas/mqant/log" +) + +func StartTimer() { + count := config.GetConfig().Customer.MaxOrderCount + if count > 0 { + MaxOrderCount = count + } + CustomerOrderAssignTimer() +} + +const ( +// MaxOrderCount = 10 // 暂定客诉最大同时分配支付订单数 +) + +var ( + MaxOrderCount int64 = 10 +) + +func CustomerOrderAssignTimer() { + time.AfterFunc(2*time.Second, func() { + defer func() { + CustomerOrderAssignTimer() + }() + users := []*values.User{} + bdb.BackDB.QueryAll(fmt.Sprintf("role = %d and online = 1", values.UserRole2), "", &values.User{}, &users) + if len(users) == 0 { + return + } + orderCount := map[int]int64{} + uids := []int{} + for _, v := range users { + list := []common.CustomerOrder{} + count, _ := db.Mysql().QueryList(0, 100, fmt.Sprintf(`customer_uid = %d and status = %d and order_id <> ""`, v.ID, common.CustomerOrderCreate), + "", &common.CustomerOrder{}, &list) + orderCount[int(v.ID)] = count + uids = append(uids, int(v.ID)) + } + rechargeList := []common.CustomerOrder{} + db.Mysql().QueryList(0, 100, fmt.Sprintf(`status = %d and order_id <> ""`, common.CustomerOrderCreate), "", &common.CustomerOrder{}, &rechargeList) + + normalList := []common.CustomerOrder{} + db.Mysql().QueryList(0, 100, fmt.Sprintf(`status = %d`, common.CustomerOrderCreate), "", &common.CustomerOrder{}, &normalList) + + if len(rechargeList) == 0 && len(normalList) == 0 { + return + } + begin := time.Now() + // log.Debug("start CustomerOrderAssignTimer......") + count := 0 + now := time.Now().Unix() + // 先分配充值订单 + for _, v := range rechargeList { + if util.SliceContain(uids, v.CustomerUid) { + continue + } + indexs := rand.Perm(len(users)) + var u *values.User + for _, l := range indexs { + diff := MaxOrderCount - orderCount[int(users[l].ID)] + if diff <= 0 { + continue + } + u = users[l] + break + } + if u == nil { + break + } + orderCount[int(u.ID)]++ + db.Mysql().Update(&common.CustomerOrder{ID: v.ID}, map[string]interface{}{"customer_uid": u.ID, "assign_time": now}) + count++ + } + + for _, v := range normalList { + if util.SliceContain(uids, v.CustomerUid) { + continue + } + indexs := rand.Perm(len(users)) + var u *values.User + for _, l := range indexs { + diff := MaxOrderCount - orderCount[int(users[l].ID)] + if diff <= 0 { + continue + } + u = users[l] + break + } + if u == nil { + break + } + orderCount[int(u.ID)]++ + db.Mysql().Update(&common.CustomerOrder{ID: v.ID}, map[string]interface{}{"customer_uid": u.ID, "assign_time": now}) + count++ + } + if count > 0 { + log.Debug("finish CustomerOrderAssignTimer since:%v,rechargeList:%d,normalList:%d,count:%d", time.Since(begin), len(rechargeList), len(normalList), count) + } + }) +} diff --git a/modules/customer/values/account.go b/modules/customer/values/account.go new file mode 100644 index 0000000..9e132d0 --- /dev/null +++ b/modules/customer/values/account.go @@ -0,0 +1,34 @@ +package values + +import ( + "time" +) + +// 用户身份 +const ( + UserRoleAdmin = iota + 1 // 管理员 + UserRole1 // 主管 + UserRole2 // 普通客服 +) + +const ( + RedisTokenEx = 60 * time.Minute +) + +// 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 +} diff --git a/modules/customer/values/chat.go b/modules/customer/values/chat.go new file mode 100644 index 0000000..694392b --- /dev/null +++ b/modules/customer/values/chat.go @@ -0,0 +1,122 @@ +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"` // 工单状态码 小于等于 匹配 + Reply int // 是否已回复 0 不筛选 1已回复 2未回复 + Recharge bool `json:"Recharge"` // 是否查询充值订单 +} + +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"` // 工单标签 + Remark string +} + +// 分配工单到客服人员 +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 +} diff --git a/modules/customer/values/common.go b/modules/customer/values/common.go new file mode 100644 index 0000000..7b41c47 --- /dev/null +++ b/modules/customer/values/common.go @@ -0,0 +1,63 @@ +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 +} diff --git a/modules/customer/values/errorCode.go b/modules/customer/values/errorCode.go new file mode 100644 index 0000000..92c426f --- /dev/null +++ b/modules/customer/values/errorCode.go @@ -0,0 +1,10 @@ +package values + +// 错误码 +const ( + CodeOK = iota + CodeRetry + CodeToken + CodeParam + CodePower // 权限不足 +) diff --git a/modules/customer/values/gm.go b/modules/customer/values/gm.go new file mode 100644 index 0000000..1f68afa --- /dev/null +++ b/modules/customer/values/gm.go @@ -0,0 +1,96 @@ +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 +} + +// GMConfigCommonListReq 后台获取调控配置通用接口 +type GMConfigCommonListReq struct { + Condition map[string]interface{} +} + +// GMConfigCommonListResp 后台获取调控配置通用接口 +type GMConfigCommonListResp struct { + Config interface{} +} + +// GMConfigCommonEditReq 后台修改调控配置通用接口 +type GMConfigCommonEditReq struct { + Config []map[string]interface{} +} + +// GMConfigCommonDelReq 后台删除调控配置通用接口 +type GMConfigCommonDelReq struct { + ID int +} diff --git a/modules/customer/values/powers.go b/modules/customer/values/powers.go new file mode 100644 index 0000000..05008a4 --- /dev/null +++ b/modules/customer/values/powers.go @@ -0,0 +1,111 @@ +package values + +// 权限对应页签 +const ( + PowerAll = iota + // 系统管理从1开始 + PowerGM // 系统配置 + PowerManageRole // 角色管理账户权限 + PowerManageUser // 用户管理账户权限 + PowerMail // 邮件权限 + PowerOrderAllocate // 工单分配权限 + PowerOrderProcessing // 工单处理权限 + PowerOptionLog // 操作日志权限 + PowerOptionBlack // 操作黑名单权限 + 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, + "/black": PowerOptionBlack, + } + // 页面按钮权限 + 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"` +} diff --git a/modules/customer/values/tables.go b/modules/customer/values/tables.go new file mode 100644 index 0000000..64c5ac2 --- /dev/null +++ b/modules/customer/values/tables.go @@ -0,0 +1,53 @@ +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:"-"` + Online int `gorm:"column:online;type:tinyint(4);default:0;comment:是否在线" json:"Online"` +} + +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" +} diff --git a/modules/pay/allpay/all.go b/modules/pay/allpay/all.go index c281376..9a05bff 100644 --- a/modules/pay/allpay/all.go +++ b/modules/pay/allpay/all.go @@ -145,6 +145,9 @@ func NewSub(b *base.Base, index int) { if index < 0 { return } + if b != nil { + b.Channel = values.PayWay(index) + } if index >= int(values.PayAll) { log.Error("get newSub err, %d %d", index, values.PayAll) return diff --git a/modules/pay/antpay/base.go b/modules/pay/antpay/base.go index 6aeeef0..f1a20ff 100644 --- a/modules/pay/antpay/base.go +++ b/modules/pay/antpay/base.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "net/http" - "server/common" "server/config" "server/modules/pay/base" "server/modules/pay/values" @@ -161,13 +160,13 @@ func (s *Sub) PackWithdrawReq() interface{} { AccountName: r.Name, NotifyURL: s.Base.GetWithdrawCallbackURL(), } - if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { - send.BankNo = r.PayCode - send.AccountType = "BANK" - send.AccountNo = r.CardNo - } else { - return nil - } + //if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { + send.BankNo = r.PayCode + send.AccountType = "BANK" + send.AccountNo = r.CardNo + //} else { + // return nil + //} // signStr := GetSignStr(send, s.Base.SignPassStr...) // signStr = signStr + "&key=" + key // send.Sign = util.CalculateMD5(util.CalculateMD5(signStr)) diff --git a/modules/pay/ddaypay/base.go b/modules/pay/ddaypay/base.go index eb2ee62..d2b5bad 100644 --- a/modules/pay/ddaypay/base.go +++ b/modules/pay/ddaypay/base.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "net/http" - "server/common" "server/modules/pay/base" "server/modules/pay/values" "server/pb" @@ -147,12 +146,12 @@ func (s *Sub) PackWithdrawReq() interface{} { NotifyUrl: s.Base.GetWithdrawCallbackURL(), } - if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { - send.IfscCode = r.PayCode - send.BankCardNumber = r.CardNo - } else { - return nil - } + //if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { + send.IfscCode = r.PayCode + send.BankCardNumber = r.CardNo + //} else { + // return nil + //} send.Sign = s.Base.SignMD5(send) return send diff --git a/modules/pay/feipay/base.go b/modules/pay/feipay/base.go index dfa675d..07f18c3 100644 --- a/modules/pay/feipay/base.go +++ b/modules/pay/feipay/base.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "net/http" - "server/common" "server/modules/pay/base" "server/modules/pay/values" "server/pb" @@ -158,16 +157,16 @@ func (s *Sub) PackWithdrawReq() interface{} { NotifyUrl: s.Base.GetWithdrawCallbackURL(), CreateOrderTime: fmt.Sprintf("%d", time.Now().Unix()), } - if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { - send.PayType = "IMPS" - send.UserBankAccount = r.CardNo - send.IfscCode = r.PayCode - } else if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeUPI { - send.PayType = "UPI" - send.UserBankAccount = r.PayCode - } else { - return nil - } + //if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { + send.PayType = "IMPS" + send.UserBankAccount = r.CardNo + send.IfscCode = r.PayCode + //} else if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeUPI { + // send.PayType = "UPI" + // send.UserBankAccount = r.PayCode + //} else { + // return nil + //} send.Sign = s.Base.SignMD5(send) return send diff --git a/modules/pay/foxpay/base.go b/modules/pay/foxpay/base.go index 8ca06c7..0a7cd4c 100644 --- a/modules/pay/foxpay/base.go +++ b/modules/pay/foxpay/base.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "net/http" - "server/common" "server/modules/pay/base" "server/modules/pay/values" "server/pb" @@ -158,16 +157,16 @@ func (s *Sub) PackWithdrawReq() interface{} { NotifyUrl: s.Base.GetWithdrawCallbackURL(), ReqTime: time.Now().Unix(), } - if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { - send.PayType = "IMPS" - send.UbAccount = r.CardNo - send.IfscCode = r.PayCode - } else if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeUPI { - send.PayType = "UPI" - send.UbAccount = r.PayCode - } else { - return nil - } + //if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { + send.PayType = "IMPS" + send.UbAccount = r.CardNo + send.IfscCode = r.PayCode + //} else if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeUPI { + // send.PayType = "UPI" + // send.UbAccount = r.PayCode + //} else { + // return nil + //} send.Sign = s.Base.SignMD5(send) return send diff --git a/modules/pay/fpay/base.go b/modules/pay/fpay/base.go index 727d294..2dfd1c6 100644 --- a/modules/pay/fpay/base.go +++ b/modules/pay/fpay/base.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "net/http" - "server/common" "server/modules/pay/base" "server/modules/pay/values" "server/pb" @@ -154,14 +153,14 @@ func (s *Sub) PackWithdrawReq() interface{} { ClientIp: r.IP, NotifyUrl: s.Base.GetWithdrawCallbackURL(), } - if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { - send.PayType = 4 - send.Account = r.CardNo - send.AccountOwner = r.Name - send.BankCode = r.PayCode - } else { - return nil - } + //if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { + send.PayType = 4 + send.Account = r.CardNo + send.AccountOwner = r.Name + send.BankCode = r.PayCode + //} else { + // return nil + //} str := base.GetSignStr(send) var err error send.Sign, err = base.SignWithSHA512([]byte(str), string(privateKey)) diff --git a/modules/pay/gallopay/base.go b/modules/pay/gallopay/base.go index 5bcf06f..ff68230 100644 --- a/modules/pay/gallopay/base.go +++ b/modules/pay/gallopay/base.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "net/http" - "server/common" "server/config" "server/modules/pay/base" "server/modules/pay/values" @@ -155,15 +154,15 @@ func (s *Sub) PackWithdrawReq() interface{} { Timestamp: fmt.Sprintf("%d", time.Now().Unix()), } - if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { - send.PayMethod = "imps" - send.IFSC = r.PayCode - send.Account = r.CardNo - } else if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeUPI { - send.PayMethod = "upi" - send.Account = r.PayCode - return nil - } + //if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { + send.PayMethod = "imps" + send.IFSC = r.PayCode + send.Account = r.CardNo + //} else if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeUPI { + // send.PayMethod = "upi" + // send.Account = r.PayCode + // return nil + //} s.Base.Sign = s.Base.SignMD5(send) return send diff --git a/modules/pay/hongxinpay/base.go b/modules/pay/hongxinpay/base.go index f438143..1e299d1 100644 --- a/modules/pay/hongxinpay/base.go +++ b/modules/pay/hongxinpay/base.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "net/http" - "server/common" "server/modules/pay/base" "server/modules/pay/values" "server/pb" @@ -154,13 +153,13 @@ func (s *Sub) PackWithdrawReq() interface{} { Phone: r.Phone, SignType: "RSA", } - if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { - send.BankName = r.BankName - send.AccountNumber = r.CardNo - send.IfscCode = r.PayCode - } else { - return nil - } + //if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { + send.BankName = r.BankName + send.AccountNumber = r.CardNo + send.IfscCode = r.PayCode + //} else { + // return nil + //} str := base.GetSignStr(send) var err error send.Sign, err = base.SignWithSHA512([]byte(str), string(privateKey)) diff --git a/modules/pay/jjpay/base.go b/modules/pay/jjpay/base.go index c0eb639..274e1a7 100644 --- a/modules/pay/jjpay/base.go +++ b/modules/pay/jjpay/base.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "net/http" - "server/common" "server/modules/pay/base" "server/modules/pay/values" "server/pb" @@ -156,14 +155,14 @@ func (s *Sub) PackWithdrawReq() interface{} { Time: fmt.Sprintf("%d", time.Now().Unix()), } - if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { - send.AccountType = "Bank" - send.AccountCode = r.PayCode - send.IFSC = r.PayCode - send.Account = r.CardNo - } else { - return nil - } + //if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { + send.AccountType = "Bank" + send.AccountCode = r.PayCode + send.IFSC = r.PayCode + send.Account = r.CardNo + //} else { + // return nil + //} send.Sign = s.Base.SignMD5(send) return send diff --git a/modules/pay/kingpay/base.go b/modules/pay/kingpay/base.go index 6e36c34..aee2b1b 100644 --- a/modules/pay/kingpay/base.go +++ b/modules/pay/kingpay/base.go @@ -140,6 +140,7 @@ func (s *Sub) PackWithdrawReq() interface{} { KeyId: KeyID, NotifyUrl: s.Base.GetWithdrawCallbackURL(), } + // todo if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { } else { return nil diff --git a/modules/pay/luckyinpay/base.go b/modules/pay/luckyinpay/base.go index 5a9504c..4097676 100644 --- a/modules/pay/luckyinpay/base.go +++ b/modules/pay/luckyinpay/base.go @@ -113,7 +113,7 @@ func (s *Sub) PackWithdrawReq() interface{} { MchNo: mchId, MchOrderNo: r.OrderID, Currency: "INR", - PayAmount: fmt.Sprintf("%."+strconv.Itoa(2)+"f", float64(r.Amount)/common.DecimalDigits), + PayAmount: fmt.Sprintf("%."+strconv.Itoa(2)+"f", float64(r.Amount)), AccountType: accountType, AccountCode: r.PayCode, AccountNo: r.CardNo, diff --git a/modules/pay/mlpay2/base.go b/modules/pay/mlpay2/base.go index c4619e8..635f55b 100644 --- a/modules/pay/mlpay2/base.go +++ b/modules/pay/mlpay2/base.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "net/http" - "server/common" "server/modules/pay/base" "server/modules/pay/values" "server/pb" @@ -190,17 +189,17 @@ func (s *Sub) PackWithdrawReq() interface{} { AccountEmail: r.Email, Version: "1.0", } - if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { - send.ReceiptMode = 1 - send.AccountNumber = r.CardNo - send.AccountExtra1 = r.PayCode - send.AccountExtra2 = r.PayCode[:4] - } else if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeUPI { - send.ReceiptMode = 0 - send.AccountNumber = r.PayCode - } else { - return nil - } + //if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { + send.ReceiptMode = 1 + send.AccountNumber = r.CardNo + send.AccountExtra1 = r.PayCode + send.AccountExtra2 = r.PayCode[:4] + //} else if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeUPI { + // send.ReceiptMode = 0 + // send.AccountNumber = r.PayCode + //} else { + // return nil + //} send.Sign = Sign(util.StructToMapJson(send), 1) return send } diff --git a/modules/pay/payplus/base.go b/modules/pay/payplus/base.go index 587a8e2..580e6ab 100644 --- a/modules/pay/payplus/base.go +++ b/modules/pay/payplus/base.go @@ -102,7 +102,7 @@ func (s *Sub) PackWithdrawReq() interface{} { Type: "api", MchId: mchId, MchTransNo: r.OrderID, - Amount: util.Decimal(float64(r.Amount)/common.DecimalDigits, 2), + Amount: float64(r.Amount), NotifyUrl: values.GetWithdrawCallback(values.PayPlus), AccountName: r.Name, AccountNo: r.CardNo, diff --git a/modules/pay/propay/base.go b/modules/pay/propay/base.go index 40cae05..4cd37b4 100644 --- a/modules/pay/propay/base.go +++ b/modules/pay/propay/base.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "net/http" - "server/common" "server/modules/pay/base" "server/modules/pay/values" "server/pb" @@ -155,13 +154,13 @@ func (s *Sub) PackWithdrawReq() interface{} { MchOrderNo: r.OrderID, NotifyURL: s.Base.GetWithdrawCallbackURL(), } - if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { - send.EntryType = "IMPS" - send.AccountNo = r.CardNo - send.AccountCode = r.PayCode - } else { - return nil - } + //if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { + send.EntryType = "IMPS" + send.AccountNo = r.CardNo + send.AccountCode = r.PayCode + //} else { + // return nil + //} send.Sign = s.Base.SignMD5(send) return send diff --git a/modules/pay/richpay/base.go b/modules/pay/richpay/base.go index 5aecd48..dba0c0e 100644 --- a/modules/pay/richpay/base.go +++ b/modules/pay/richpay/base.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "net/http" - "server/common" "server/config" "server/modules/pay/base" "server/modules/pay/values" @@ -196,16 +195,16 @@ func (s *Sub) PackWithdrawReq() interface{} { // Account: , // IFSC: , } - if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { - send.Type = "BANK" - send.Account = r.CardNo - send.IFSC = r.PayCode - } else if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeUPI { - send.Type = "UPI" - send.VPA = r.PayCode - } else { - return nil - } + //if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { + send.Type = "BANK" + send.Account = r.CardNo + send.IFSC = r.PayCode + //} else if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeUPI { + // send.Type = "UPI" + // send.VPA = r.PayCode + //} else { + // return nil + //} str := fmt.Sprintf("%s%s%d%s%s%s", mid, send.MerchantOrderNo, send.OrderAmount, send.NonceStr, send.Timestamp, send.Action) sign, err := base.SignDsa(str, privateKey) if err != nil { diff --git a/modules/pay/superpay/base.go b/modules/pay/superpay/base.go index 815d613..cfc9c9b 100644 --- a/modules/pay/superpay/base.go +++ b/modules/pay/superpay/base.go @@ -6,7 +6,6 @@ import ( "fmt" "math/rand" "net/http" - "server/common" "server/config" "server/modules/pay/base" "server/modules/pay/values" @@ -185,17 +184,17 @@ func (s *Sub) PackWithdrawReq() interface{} { return nil } send.IfCode = code[rand.Intn(len(code))] - if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { - send.EntryType = BankCard - send.AccountNo = r.CardNo - send.ChannelExtra.Ifsc = r.PayCode - } else if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeUPI { - send.EntryType = IndiaUpiUtr - send.AccountNo = r.PayCode - send.ChannelExtra.Upi = r.PayCode - } else { - return nil - } + //if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { + send.EntryType = BankCard + send.AccountNo = r.CardNo + send.ChannelExtra.Ifsc = r.PayCode + //} else if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeUPI { + // send.EntryType = IndiaUpiUtr + // send.AccountNo = r.PayCode + // send.ChannelExtra.Upi = r.PayCode + //} else { + // return nil + //} // send.Sign = s.Base.SignMD5(send) return send diff --git a/modules/pay/timer.go b/modules/pay/timer.go index 54e966c..268ed43 100644 --- a/modules/pay/timer.go +++ b/modules/pay/timer.go @@ -276,6 +276,7 @@ func TryWithdraw(or *common.WithdrawOrder) { if channel == nil || channel.WithdrawPer <= 0 { con := call.GetConfigWithdrawChannelsBest(common.CurrencyINR) if con == nil { + log.Debug("get withdraw channel is nil") return } req.Channel = int64(con.ChannelID) @@ -292,7 +293,7 @@ func TryWithdraw(or *common.WithdrawOrder) { } log.Debug("order:%v,err:%v", req.OrderID, err) if err != nil { - log.Debug("order:%+v,err:%v", or, err) + log.Error("order:%+v,err:%v", or, err) call.ReturnBackWithdraw(or, common.StatusROrderPay, common.StatusROrderFail, int(req.Channel)) return } diff --git a/modules/pay/tkpay/base.go b/modules/pay/tkpay/base.go index ac9790f..54f5d47 100644 --- a/modules/pay/tkpay/base.go +++ b/modules/pay/tkpay/base.go @@ -157,15 +157,15 @@ func (s *Sub) PackWithdrawReq() interface{} { // Account: , } - if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { - send.WithdrawType = "1" - send.BankCode = r.PayCode - send.Account = r.CardNo - } else if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeUPI { - send.WithdrawType = "2" - send.Account = r.PayCode - return nil - } + //if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { + send.WithdrawType = "1" + send.BankCode = r.PayCode + send.Account = r.CardNo + //} else if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeUPI { + // send.WithdrawType = "2" + // send.Account = r.PayCode + // return nil + //} str := base.GetSignStr(send, s.Base.SignPassStr...) + "&key=" + key var err error diff --git a/modules/pay/values/values.go b/modules/pay/values/values.go index 35c6b7e..0db201d 100644 --- a/modules/pay/values/values.go +++ b/modules/pay/values/values.go @@ -283,43 +283,44 @@ func WithdrawSuccess(w PayWay) { } func PayFail(w PayWay) { - // failWeight := config.GetConfig().Pay.PayFailWeight - // if failWeight <= 0 { - // return - // } - // PayWeightLock.Lock() - // for _, v := range call.ConfigPayChannels { - // if v.ChannelID == int(w) { - // v.PayPer -= failWeight - // break - // } - // } - // sort.Slice(call.ConfigPayChannels, func(i, j int) bool { - // return call.ConfigPayChannels[i].PayPer > call.ConfigPayChannels[j].PayPer - // }) - // PayWeightLock.Unlock() - // AddPayChannel(int(w), -failWeight) - // call.AddChannel(int(w), false) + if w == MoneydealerPay { + return + } + failWeight := config.GetConfig().Pay.PayFailWeight + if failWeight <= 0 { + return + } + PayWeightLock.Lock() + for _, v := range call.ConfigPayChannels { + if v.ChannelID == int(w) { + v.PayPer -= failWeight + break + } + } + sort.Slice(call.ConfigPayChannels, func(i, j int) bool { + return call.ConfigPayChannels[i].PayPer > call.ConfigPayChannels[j].PayPer + }) + PayWeightLock.Unlock() + AddPayChannel(int(w), -failWeight) } func PaySuccess(w PayWay) { - // successWeight := config.GetConfig().Pay.PaySuccessWeight - // if successWeight <= 0 { - // return - // } - // PayWeightLock.Lock() - // for _, v := range call.ConfigPayChannels { - // if v.ChannelID == int(w) { - // v.PayPer += successWeight - // break - // } - // } - // sort.Slice(call.ConfigPayChannels, func(i, j int) bool { - // return call.ConfigPayChannels[i].PayPer > call.ConfigPayChannels[j].PayPer - // }) - // PayWeightLock.Unlock() - // AddPayChannel(int(w), successWeight) - call.AddChannel(int(w), true) + successWeight := config.GetConfig().Pay.PaySuccessWeight + if successWeight <= 0 { + return + } + PayWeightLock.Lock() + for _, v := range call.ConfigPayChannels { + if v.ChannelID == int(w) { + v.PayPer += successWeight + break + } + } + sort.Slice(call.ConfigPayChannels, func(i, j int) bool { + return call.ConfigPayChannels[i].PayPer > call.ConfigPayChannels[j].PayPer + }) + PayWeightLock.Unlock() + AddPayChannel(int(w), successWeight) } // 获取支付回调路径 @@ -542,14 +543,10 @@ func AddWithdrawChannel(p int, amount int) { } func AddPayChannel(p int, amount int) { - channel := &common.ConfigPayChannels{ - ChannelID: p, - } - db.Mysql().Get(&channel) - if channel.PayPer+amount > 100 { - if err := db.Mysql().C().Model(&common.ConfigPayChannels{}).Where("channel_id = ?", p).Updates(map[string]interface{}{"pay_per": gorm.Expr("pay_per + ?", amount)}).Error; err != nil { - log.Error("err:%v", err) - } + log.Debug("update pay per, %d:%d", p, amount) + if err := db.Mysql().C().Model(&common.ConfigPayChannels{}).Where("channel_id = ? and pay_per > 0 ", p). + Updates(map[string]interface{}{"pay_per": gorm.Expr("pay_per + ?", amount)}).Error; err != nil { + log.Error("err:%v", err) } } diff --git a/modules/pay/virgopay/base.go b/modules/pay/virgopay/base.go index 5782b82..5966fd3 100644 --- a/modules/pay/virgopay/base.go +++ b/modules/pay/virgopay/base.go @@ -162,16 +162,16 @@ func (s *Sub) PackWithdrawReq() interface{} { NotifyURL: s.Base.GetWithdrawCallbackURL(), } - if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { - send.PayType = 1 - send.IFSC = r.PayCode - send.Account = r.CardNo - send.BankName = r.BankName - } else if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeUPI { - send.PayType = 2 - send.Account = r.PayCode - return nil - } + //if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeBank { + send.PayType = 1 + send.IFSC = r.PayCode + send.Account = r.CardNo + send.BankName = r.BankName + //} else if fmt.Sprintf("%d", r.PayType) == common.WithdrawTypeUPI { + // send.PayType = 2 + // send.Account = r.PayCode + // return nil + //} send.Sign = s.Base.SignMD5(send) return send } diff --git a/modules/web/app/account.go b/modules/web/app/account.go index 1acfc38..aea59e8 100644 --- a/modules/web/app/account.go +++ b/modules/web/app/account.go @@ -1,17 +1,20 @@ package app import ( + "fmt" + "github.com/go-redis/redis/v8" + "github.com/liangdas/mqant/log" + iptool "github.com/liangdas/mqant/utils/ip" + "github.com/olivere/elastic/v7" + "gorm.io/gorm" "net" "server/call" "server/common" "server/db" "server/modules/web/values" + "server/util" "strings" - - "github.com/go-redis/redis/v8" - "github.com/liangdas/mqant/log" - iptool "github.com/liangdas/mqant/utils/ip" - "gorm.io/gorm" + "time" ) // VerifyCode 验证短信验证码 @@ -88,6 +91,20 @@ func (g *Gin) QueryUser(req values.CommonLogin) (user *common.PlayerDBInfo, isNe return } isNew = true + if len(req.DeviceID) > 0 { + uuid := req.DeviceID + // 处理一下新增安装 + util.Go(func() { + q := elastic.NewBoolQuery() + q.Filter(elastic.NewTermsQuery("UUID.keyword", uuid)) + q.Filter(elastic.NewTermQuery("Channel", g.Channel)) + if db.ES().Count(common.ESIndexBackOpenRecord, q) > 0 { + return + } + id := fmt.Sprintf("%v_%v", g.Channel, uuid) + db.ES().InsertToESByIDGO(common.ESIndexBackOpenRecord, id, &common.ESOpenRecord{Time: time.Now().Unix(), UUID: uuid, Channel: g.Channel}) + }) + } } else { user.ADID = req.Adid user.GPSADID = req.Gpsadid diff --git a/modules/web/app/response.go b/modules/web/app/response.go index 85d8b90..182c93e 100644 --- a/modules/web/app/response.go +++ b/modules/web/app/response.go @@ -100,6 +100,8 @@ func (g *Gin) Response() { if g.R.Code == values.CodeRetry { } else if g.R.Code == values.CodeToken { g.R.Msg = "login expired" + } else if g.R.Code == values.CodeCodeError { + g.R.Msg = "Code is wrong" } jsonData, _ := json.Marshal(g.R) g.Context.Data(http.StatusOK, "text", util.AesEncrypt(jsonData)) diff --git a/modules/web/handler/share.go b/modules/web/handler/share.go index 0f1ecab..2577407 100644 --- a/modules/web/handler/share.go +++ b/modules/web/handler/share.go @@ -573,8 +573,8 @@ func ShareCfg(c *gin.Context) { resp.TotalAward = shareInfo.Reward err := db.Mysql().C().Model(&common.ShareReward{}). Select("COALESCE(SUM(reward_count), 0) as todayAmount"). - Where("uid = ? and reward_at > ?", a.UID, util.GetZeroTime(time.Now()).Unix()). - Scan(&resp.TotalAward).Error + Where("uid = ? and reward_at > ? and reward_count > 0 ", a.UID, util.GetZeroTime(time.Now()).Unix()). + Scan(&resp.TodayAward).Error if err != nil { log.Error("get todayAmount err, %s", err.Error()) } @@ -850,6 +850,11 @@ func ShareWithdraw(c *gin.Context) { db.Redis().UnLock(common.GetRedisKeyShare(uid)) }() + if req.Amount < 0 { + a.Code = values.CodeParam + a.Msg = "Insufficient Amount." + return + } shareInfo := call.GetShareInfo(uid) if shareInfo.Reward < req.Amount { a.Code = values.CodeParam @@ -866,7 +871,12 @@ func ShareWithdraw(c *gin.Context) { shareWithdrawInfo := call.GetShareWithdrawInfo(uid) if shareWithdrawInfo.DayCount >= con.DayWithdrawCount { a.Code = values.CodeParam - a.Msg = "Withdrawal limit." + a.Msg = fmt.Sprintf("Your current agent level is %d, with a maximum of %d withdrawals per day.", shareInfo.Level, con.DayWithdrawCount) + return + } + if shareWithdrawInfo.TodayWithdraw+req.Amount >= con.WithdrawAudit { + a.Code = values.CodeParam + a.Msg = fmt.Sprintf("Your current agent level is %d, with a max amount of %d withdrawals per day.", shareInfo.Level, con.WithdrawAudit/common.DecimalDigits) return } err := call.UpdateShare(uid, 5, req.Amount, fmt.Sprintf("%d", req.Amount)) @@ -894,10 +904,12 @@ func ShareWithdraw(c *gin.Context) { updateValues := map[string]interface{}{ "day_count": 1, "day_time": now.Unix(), + "today_withdraw": req.Amount, "total_withdraw": gorm.Expr("total_withdraw + ?", req.Amount), } if shareWithdrawInfo.DayTime != 0 && util.IsSameDayTimeStamp(shareWithdrawInfo.DayTime, now.Unix()) { updateValues["day_count"] = gorm.Expr("day_count + ?", 1) + updateValues["today_withdraw"] = gorm.Expr("today_withdraw + ?", req.Amount) delete(updateValues, "day_time") } err = db.Mysql().C().Model(&common.ShareWithdrawInfo{}).Where("id = ?", shareWithdrawInfo.ID).Updates(updateValues).Error diff --git a/modules/web/handler/user.go b/modules/web/handler/user.go index b16cdcd..438f4ac 100644 --- a/modules/web/handler/user.go +++ b/modules/web/handler/user.go @@ -79,8 +79,11 @@ func getUserInfo(uid int, isNew bool) (resp values.UserInfoResp, err error) { resp.Currencys[i] = ref.Field(int(i) + 1).Int() } if isNew { - if resp.Currencys[common.CurrencyINR] == 0 { - resp.Currencys[common.CurrencyINR] = call.GetConfigPlatform().NewPlayerGift + if resp.Currencys[common.CurrencyINR] == 0 && call.GetConfigPlatform().NewPlayerGift > 0 { + resp.Currencys[common.CurrencyINR] += call.GetConfigPlatform().NewPlayerGift + } + if resp.Currencys[common.CurrencyINR] == 0 && call.GetConfigPlatform().NewPlayerGift > 0 { + resp.Currencys[common.CurrencyINR] += call.GetConfigPlatform().NewPlayerGift } } re := &common.RechargeInfo{UID: uid} diff --git a/modules/web/middleware/token.go b/modules/web/middleware/token.go index d5213b0..e06fe19 100644 --- a/modules/web/middleware/token.go +++ b/modules/web/middleware/token.go @@ -88,6 +88,7 @@ func TokenMiddleWare() gin.HandlerFunc { c.Set("uid", uid) c.Set("token", token) c.Set("referrer", c.GetHeader("referrer")) + c.Set("channel", c.GetHeader("channel")) util.Go(func() { db.Redis().AddUserExpire(uid, token) }) diff --git a/modules/web/providers/jin/base.go b/modules/web/providers/jin/base.go index 46293e0..64ba163 100644 --- a/modules/web/providers/jin/base.go +++ b/modules/web/providers/jin/base.go @@ -29,7 +29,7 @@ func (s *Sub) EnterGame() string { token := s.Base.EnterGameReq.Token providerID := s.Base.EnterGameReq.ProviderID gameID := s.Base.EnterGameReq.GameID - game := call.GetConfigProviderGameListByID(providerID, gameID) + game := call.GetGameListByByID(providerID, gameID) if game == nil { return "" } diff --git a/modules/web/providers/jin/handler.go b/modules/web/providers/jin/handler.go index b3aa951..496bc7e 100644 --- a/modules/web/providers/jin/handler.go +++ b/modules/web/providers/jin/handler.go @@ -36,7 +36,7 @@ func Auth(c *gin.Context) { req := &AuthReq{} resp := &AuthResp{} a.RetData = resp - if !a.S(req) { + if !a.SB(req) { resp.Code = CodeRequestInvalidParams return } @@ -67,7 +67,7 @@ func GameBet(c *gin.Context) { req := &GameBetReq{} resp := &GameBetResp{} a.RetData = resp - if !a.S(req) { + if !a.SB(req) { resp.Code = CodeRequestInvalidParams return } @@ -125,7 +125,7 @@ func Jackpot(c *gin.Context) { req := &JackpotReq{} resp := &JackpotResp{} a.RetData = resp - if !a.S(req) { + if !a.SB(req) { resp.Code = CodeRequestInvalidParams return }