gm后台修改玩家资源

This commit is contained in:
liuxiaobo 2025-06-23 01:23:27 +08:00
parent 2e55da8c02
commit 9363e3e05f
12 changed files with 181 additions and 46 deletions

View File

@ -17,7 +17,7 @@ type GameUserApi struct{}
func (e *GameUserApi) GetUserById(c *gin.Context) { func (e *GameUserApi) GetUserById(c *gin.Context) {
var gameUser = &user.GameUser{} var gameUser = &user.GameUser{}
err := c.ShouldBindJSON(&gameUser) err := c.ShouldBindJSON(gameUser)
if err != nil { if err != nil {
response.FailWithMessage(err.Error(), c) response.FailWithMessage(err.Error(), c)
return return
@ -39,7 +39,7 @@ func (e *GameUserApi) GetUserById(c *gin.Context) {
func (e *GameUserApi) GetAccountByUid(c *gin.Context) { func (e *GameUserApi) GetAccountByUid(c *gin.Context) {
var account = &user.UserAccount{} var account = &user.UserAccount{}
err := c.ShouldBindJSON(&account) err := c.ShouldBindJSON(account)
if err != nil { if err != nil {
response.FailWithMessage(err.Error(), c) response.FailWithMessage(err.Error(), c)
return return
@ -58,3 +58,44 @@ func (e *GameUserApi) GetAccountByUid(c *gin.Context) {
} }
response.OkWithData(gin.H{"account": account}, c) response.OkWithData(gin.H{"account": account}, c)
} }
type AddUserResReq struct {
UId int64 `json:"uid"`
ResType string `json:"res_type"`
ResValue int64 `json:"res_value"`
Reason string `json:"reason"`
}
func (e *GameUserApi) AddUserRes(c *gin.Context) {
var req = &AddUserResReq{}
err := c.ShouldBindJSON(req)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
}
if req.UId < 1 {
response.FailWithMessage(fmt.Sprintf("玩家id不能为0"), c)
return
}
if req.ResType == "" {
response.FailWithMessage(fmt.Sprintf("资源类型不能为空"), c)
return
}
if req.ResValue == 0 {
response.FailWithMessage(fmt.Sprintf("添加资源不能为0"), c)
return
}
values, code := rpc.RpcAddUserRes(servicex.GetService(), req.UId, &user.AddUserRes{
Reason: req.Reason,
AddRes: map[string]int64{
req.ResType: req.ResValue,
},
})
if code != pb.ErrCode_OK {
global.GVA_LOG.Error("查询失败!", zap.Error(fmt.Errorf(code.String())))
response.FailWithMessage("查询失败", c)
return
}
response.OkWithData(gin.H{"res": values}, c)
}

View File

@ -14,6 +14,7 @@ func (s *GameUserRouter) InitGameUserRouter(Router *gin.RouterGroup, RouterPub *
{ {
router.PUT("getUserById", gameUserApi.GetUserById) // 获取玩家信息 router.PUT("getUserById", gameUserApi.GetUserById) // 获取玩家信息
router.PUT("getAccountByUid", gameUserApi.GetAccountByUid) // 获取玩家帐号信息 router.PUT("getAccountByUid", gameUserApi.GetAccountByUid) // 获取玩家帐号信息
router.PUT("addUserRes", gameUserApi.AddUserRes) // 添加玩家资源
} }
} }

View File

@ -16,4 +16,12 @@ export function getAccountByUid(params) {
method: 'put', method: 'put',
data: params data: params
}) })
} }
export function AddUserRes(params) {
return request({
url: '/gameUser/addUserRes',
method: 'put',
data: params
})
}

View File

@ -2,10 +2,10 @@
<el-dialog title="添加资源" v-model="dialogVisible" width="500px" @close="onClose"> <el-dialog title="添加资源" v-model="dialogVisible" width="500px" @close="onClose">
<el-form :model="form" label-width="100px" ref="resourceForm" :rules="rules"> <el-form :model="form" label-width="100px" ref="resourceForm" :rules="rules">
<el-form-item label="玩家ID"> <el-form-item label="玩家ID">
<el-input v-model="localUserId" disabled></el-input> <el-input :value="userId" disabled></el-input>
</el-form-item> </el-form-item>
<el-form-item label="玩家昵称"> <el-form-item label="玩家昵称">
<el-input v-model="localNickname" disabled></el-input> <el-input :value="nickname" disabled></el-input>
</el-form-item> </el-form-item>
<el-form-item label="资源类型:" prop="resourceType"> <el-form-item label="资源类型:" prop="resourceType">
@ -29,6 +29,8 @@
</template> </template>
<script> <script>
import {AddUserRes} from "@/api/gameUser";
export default { export default {
props: { props: {
value: { // v-model 使 value prop value: { // v-model 使 value prop
@ -48,8 +50,13 @@ export default {
data(){ data(){
return { return {
dialogVisible:this.value, dialogVisible:this.value,
localUserId:this.userId, user :{
localNickname:this.nickname, id: 0,
nickname: '',
resType:'',
resValue:'',
},
form:{ form:{
resourceType:'gold', resourceType:'gold',
amount:'', amount:'',
@ -88,7 +95,6 @@ export default {
onClose(){ onClose(){
this.dialogVisible = false this.dialogVisible = false
// console.log("dialogVisible:", this.dialogVisible) // console.log("dialogVisible:", this.dialogVisible)
// console.log("userid:", this.localUserId+' nickname:'+this.localNickname)
// this.$emit('input', false) // v-model 使 input // this.$emit('input', false) // v-model 使 input
}, },
validateAmount(rule, value, callback){ validateAmount(rule, value, callback){
@ -105,18 +111,39 @@ export default {
validateNumber(value){ validateNumber(value){
this.form.amount = value.replace(/[^\d]/g, '') this.form.amount = value.replace(/[^\d]/g, '')
}, },
onClick(){ async onClick(){
this.$refs.resourceForm.validate((valid)=>{ // console.log('form:',this.form)
if(valid){ this.user.id = this.userId
const resourceData = { this.user.resType = this.form.resourceType
userId: this.userId, this.user.resValue = this.form.amount
...this.form, //
amount: parseInt(this.form.amount) // const loading = this.$loading({
} lock: true,
this.$emit('confirm', resourceData) text: '处理中...',
this.dialogVisible = false spinner: 'el-icon-loading',
} background: 'rgba(0, 0, 0, 0.7)'
}) })
try {
const response = await AddUserRes({
uid:+this.user.id,
reason:'gm',
res_type:this.user.resType,
res_value:+this.user.resValue,
})
if (response.code !== 0) {
console.error('添加资源失败:', response.msg || `请求失败,错误码: ${response.code}`)
this.$message.error('添加资源失败:'+(response.msg || `请求失败,错误码: ${response.code}`))
return
}
this.$message.info('添加资源成功')
}catch (error){
console.error('获取玩家数据失败:', error)
this.$message.error('获取用户数据失败:'+error)
}finally {
//
loading.close()
}
this.dialogVisible = false
} }
} }
} }

View File

@ -31,6 +31,10 @@ func (u GameRecordLog) GetId() int64 {
return 0 return 0
} }
func (u GameRecordLog) GetIdName() string {
return "game_no"
}
func (u GameRecordLog) TableName() string { func (u GameRecordLog) TableName() string {
return "game_record_log" return "game_record_log"
} }

View File

@ -23,6 +23,10 @@ func (u UserRecordLog) GetId() int64 {
return 0 return 0
} }
func (u UserRecordLog) GetIdName() string {
return "game_no"
}
func (u UserRecordLog) TableName() string { func (u UserRecordLog) TableName() string {
return "user_record_log" return "user_record_log"
} }

View File

@ -14,6 +14,10 @@ func (u User) GetId() int64 {
return u.ID return u.ID
} }
func (u User) GetIdName() string {
return "id"
}
func (u User) TableName() string { func (u User) TableName() string {
return "user" return "user"
} }

View File

@ -29,6 +29,10 @@ func (u UserAccount) GetId() int64 {
return u.ID return u.ID
} }
func (u UserAccount) GetIdName() string {
return "id"
}
func (u UserAccount) TableName() string { func (u UserAccount) TableName() string {
return "user_account" return "user_account"
} }
@ -48,6 +52,10 @@ func (u UserLoginLog) GetId() int64 {
return 0 return 0
} }
func (u UserLoginLog) GetIdName() string {
return "account_id"
}
func (u UserLoginLog) TableName() string { func (u UserLoginLog) TableName() string {
return "user_login_log" return "user_login_log"
} }

View File

@ -1,8 +1,10 @@
package user package user
import "time"
// 玩家账户表 // 玩家账户表
type UserResources struct { type UserResources struct {
UID int64 `gorm:"uniqueIndex" json:"uid"` UID int64 `gorm:"primaryKey" json:"uid"`
Gold int64 `gorm:"default:0" json:"gold"` // 金币 Gold int64 `gorm:"default:0" json:"gold"` // 金币
Diamond int64 `gorm:"default:0" json:"diamond"` // 钻石 Diamond int64 `gorm:"default:0" json:"diamond"` // 钻石
} }
@ -11,28 +13,47 @@ func (u UserResources) GetId() int64 {
return u.UID return u.UID
} }
func (u UserResources) GetIdName() string {
return "uid"
}
func (u UserResources) TableName() string { func (u UserResources) TableName() string {
return "user_resources" return "user_resources"
} }
type UserResourcesLog struct { type UserResourcesLog struct {
UID int64 `gorm:"uniqueIndex" json:"uid"` UID int64 `gorm:"type:Int64;index" json:"uid"` // 玩家id
ResName string `gorm:"default:0" json:"res_name"` // 资源名 Time time.Time `gorm:"type:DateTime;default:now()" json:"time"` // 修改时间
ResAddValue int64 `gorm:"default:0" json:"res_value"` // 资源增加值 ResName string `gorm:"type:String;not null" json:"res_name"` // 资源名
ResAfterValue int64 `gorm:"default:0" json:"res_after_value"` // 资源增加后的值 ResAddValue int64 `gorm:"type:Int64;" json:"res_value"` // 资源增加值
GameId int `gorm:"default:0" json:"game_id"` // 添加资源的玩法id充值等非玩法操作资源则为0 ResAfterValue int64 `gorm:"type:Int64;" json:"res_after_value"` // 资源增加后的值
GameNo string `json:"game_no"` // 游戏局id同上 GameId int `gorm:"type:Int32;" json:"game_id"` // 添加资源的玩法id充值等非玩法操作资源则为0
Reason string `json:"reason"` // 原因 GameNo string `gorm:"type:String" json:"game_no"` // 游戏局id同上
Reason string `gorm:"type:String" json:"reason"` // 原因
OperatorId int64 `gorm:"type:Int64;" json:"operator_id"` // 操作者id
} }
func (u UserResourcesLog) GetId() int64 { func (u UserResourcesLog) GetId() int64 {
return 0 return 0
} }
func (u UserResourcesLog) GetIdName() string {
return "uid"
}
func (u UserResourcesLog) TableName() string { func (u UserResourcesLog) TableName() string {
return "user_resources_log" return "user_resources_log"
} }
func (u UserResourcesLog) TableOptions() string {
// "ENGINE=MergeTree() ORDER BY tuple()"
return `ENGINE=MergeTree()
ORDER BY (uid, time)
PARTITION BY toYYYYMM(time)
TTL time + INTERVAL 6 MONTH
`
}
type AddUserRes struct { type AddUserRes struct {
GameId int `json:"game_id"` // 添加资源的玩法id充值等非玩法操作资源则为0 GameId int `json:"game_id"` // 添加资源的玩法id充值等非玩法操作资源则为0
GameNo string `json:"game_no"` // 游戏局id同上 GameNo string `json:"game_no"` // 游戏局id同上

View File

@ -20,6 +20,7 @@ const (
type iTable interface { type iTable interface {
GetId() int64 GetId() int64
GetIdName() string
TableName() string TableName() string
} }
@ -32,7 +33,7 @@ type TableOp[T iTable] struct {
} }
func NewTableOp[T iTable](db *gorm.DB, rds *redis.Client) *TableOp[T] { func NewTableOp[T iTable](db *gorm.DB, rds *redis.Client) *TableOp[T] {
return &TableOp[T]{db: db, rds: rds} return &TableOp[T]{db: db.Debug(), rds: rds}
} }
func (s *TableOp[T]) tableName() string { func (s *TableOp[T]) tableName() string {
@ -128,7 +129,7 @@ func (s *TableOp[T]) Find(id int64) (*T, pb.ErrCode) {
return table, pb.ErrCode_OK return table, pb.ErrCode_OK
} }
var result utils.TValue[T] var result utils.TValue[T]
err := s.db.Where("id = ?", id).First(&result.V).Error err := s.db.Where(result.V.GetIdName()+" = ?", id).First(&result.V).Error
if err != nil { if err != nil {
log.DebugF("find table:%v id:%v err:%v", s.tableName(), id, err) log.DebugF("find table:%v id:%v err:%v", s.tableName(), id, err)
return nil, pb.ErrCode_SystemErr return nil, pb.ErrCode_SystemErr
@ -153,7 +154,7 @@ func (s *TableOp[T]) FindCondition(condition map[string]any) (*T, pb.ErrCode) {
func (s *TableOp[T]) Update(id int64, updates map[string]any) (*T, pb.ErrCode) { func (s *TableOp[T]) Update(id int64, updates map[string]any) (*T, pb.ErrCode) {
var result utils.TValue[T] var result utils.TValue[T]
err := s.db.Model(&result.V).Where("id = ?", id).Updates(updates).Error err := s.db.Model(&result.V).Where(result.V.GetIdName()+" = ?", id).Updates(updates).Error
if err != nil { if err != nil {
log.ErrorF("update table:%v id:%v err:%v", s.tableName(), id, err) log.ErrorF("update table:%v id:%v err:%v", s.tableName(), id, err)
return nil, pb.ErrCode_SystemErr return nil, pb.ErrCode_SystemErr
@ -184,10 +185,11 @@ func (s *TableOp[T]) GetInt(id int64, resName []string) (map[string]int64, pb.Er
return updatedValues, pb.ErrCode_OK return updatedValues, pb.ErrCode_OK
} }
var result utils.TValue[T]
// redis中没有值从表中加载并写入redis // redis中没有值从表中加载并写入redis
mapAny := make(map[string]any) mapAny := make(map[string]any)
err := s.db.Model(new(T)). err := s.db.Model(new(T)).
Where("id = ?", id). Where(result.V.GetIdName()+" = ?", id).
Take(&mapAny). // 扫描到map Take(&mapAny). // 扫描到map
Error Error
@ -225,24 +227,42 @@ func (s *TableOp[T]) AddInt(id int64, res map[string]int64) (map[string]int64, p
addRes[k] = gorm.Expr(fmt.Sprintf("%v + ?", k), v) addRes[k] = gorm.Expr(fmt.Sprintf("%v + ?", k), v)
} }
var result utils.TValue[T] var result utils.TValue[T]
err := s.db.Model(&result.V).Where("id = ?", id).Updates(addRes).Error err := s.db.Model(&result.V).Where(result.V.GetIdName()+" = ?", id).Updates(addRes).Error
if err != nil { if err != nil {
log.ErrorF("add table:%v id:%v err:%v", s.tableName(), id, err) log.ErrorF("add table:%v id:%v err:%v", s.tableName(), id, err)
return nil, pb.ErrCode_SystemErr return nil, pb.ErrCode_SystemErr
} }
// 查询更新后的值到map rows, err := s.db.Model(&result.V).
updatedValues := make(map[string]int64)
err = s.db.Model(new(T)).
Select(keysToStringSlice(res)). // 只选择需要返回的字段 Select(keysToStringSlice(res)). // 只选择需要返回的字段
Where("id = ?", id). Where(result.V.GetIdName()+" = ?", id).
Take(&updatedValues). // 扫描到map Rows()
Error
if err != nil { if err != nil {
log.ErrorF("query updated values table:%v id:%v err:%v", s.tableName(), id, err) log.ErrorF("query updated values table:%v id:%v err:%v", s.tableName(), id, err)
return nil, pb.ErrCode_SystemErr return nil, pb.ErrCode_SystemErr
} }
defer func() { _ = rows.Close() }() // 确保关闭
// 查询更新后的值到map
updatedValues := make(map[string]int64)
// 手动扫描到 map
if rows.Next() {
columns, _ := rows.Columns()
values := make([]interface{}, len(columns))
for i := range values {
values[i] = new(int64) // 假设所有字段都是 int64
}
err = rows.Scan(values...)
if err != nil {
log.ErrorF("scan updated values err:%v", err)
return nil, pb.ErrCode_SystemErr
}
for i, col := range columns {
updatedValues[col] = *(values[i].(*int64))
}
} else {
return nil, pb.ErrCode_SystemErr // 无记录
}
mapAny := make(map[string]any) mapAny := make(map[string]any)
for k, v := range updatedValues { for k, v := range updatedValues {

View File

@ -4,21 +4,15 @@ import (
"encoding/json" "encoding/json"
"game/common/model/user" "game/common/model/user"
"game/common/proto/pb" "game/common/proto/pb"
"game/common/userBindService"
"github.com/fox/fox/ipb" "github.com/fox/fox/ipb"
"github.com/fox/fox/log" "github.com/fox/fox/log"
"github.com/fox/fox/service" "github.com/fox/fox/service"
) )
// 添加玩家资源,负数为减少 // 添加玩家资源,负数为减少
func RpcAddUserRes(bindService *userBindService.UserBindService, s service.IService, uid int64, addUserRes *user.AddUserRes) (map[string]int64, pb.ErrCode) { func RpcAddUserRes(s service.IService, uid int64, addUserRes *user.AddUserRes) (map[string]int64, pb.ErrCode) {
node, err := bindService.HashServiceNode(pb.ServiceTypeId_STI_DB, uid)
if err != nil {
log.ErrorF("db service node error:%v", err)
return nil, pb.ErrCode_SystemErr
}
rpcMsg := ipb.MakeRpcMsg(AddUserResources, uid, addUserRes) rpcMsg := ipb.MakeRpcMsg(AddUserResources, uid, addUserRes)
rspMsg, err := s.CallByTopic(service.RpcTopicEx(node.Name), timeout, rpcMsg) rspMsg, err := s.CallByServiceId(int(pb.ServiceTypeId_STI_DB), timeout, rpcMsg)
if err != nil { if err != nil {
log.ErrorF("call rpc:%v err:%s ", rpcMsg.RpcMsgId, err.Error()) log.ErrorF("call rpc:%v err:%s ", rpcMsg.RpcMsgId, err.Error())
return nil, pb.ErrCode_SystemErr return nil, pb.ErrCode_SystemErr

View File

@ -72,6 +72,9 @@ func InitDb() {
if err1 := db.AutoMigrateClickHouse(LogDB, user.UserRecordLog{}.TableOptions(), user.UserRecordLog{}); err == nil && err1 != nil { if err1 := db.AutoMigrateClickHouse(LogDB, user.UserRecordLog{}.TableOptions(), user.UserRecordLog{}); err == nil && err1 != nil {
err = err1 err = err1
} }
if err1 := db.AutoMigrateClickHouse(LogDB, user.UserResourcesLog{}.TableOptions(), user.UserResourcesLog{}); err == nil && err1 != nil {
err = err1
}
if err != nil { if err != nil {
log.Fatal(err.Error()) log.Fatal(err.Error())