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) {
var gameUser = &user.GameUser{}
err := c.ShouldBindJSON(&gameUser)
err := c.ShouldBindJSON(gameUser)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
@ -39,7 +39,7 @@ func (e *GameUserApi) GetUserById(c *gin.Context) {
func (e *GameUserApi) GetAccountByUid(c *gin.Context) {
var account = &user.UserAccount{}
err := c.ShouldBindJSON(&account)
err := c.ShouldBindJSON(account)
if err != nil {
response.FailWithMessage(err.Error(), c)
return
@ -58,3 +58,44 @@ func (e *GameUserApi) GetAccountByUid(c *gin.Context) {
}
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("getAccountByUid", gameUserApi.GetAccountByUid) // 获取玩家帐号信息
router.PUT("addUserRes", gameUserApi.AddUserRes) // 添加玩家资源
}
}

View File

@ -17,3 +17,11 @@ export function getAccountByUid(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-form :model="form" label-width="100px" ref="resourceForm" :rules="rules">
<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 label="玩家昵称">
<el-input v-model="localNickname" disabled></el-input>
<el-input :value="nickname" disabled></el-input>
</el-form-item>
<el-form-item label="资源类型:" prop="resourceType">
@ -29,6 +29,8 @@
</template>
<script>
import {AddUserRes} from "@/api/gameUser";
export default {
props: {
value: { // v-model 使 value prop
@ -48,8 +50,13 @@ export default {
data(){
return {
dialogVisible:this.value,
localUserId:this.userId,
localNickname:this.nickname,
user :{
id: 0,
nickname: '',
resType:'',
resValue:'',
},
form:{
resourceType:'gold',
amount:'',
@ -88,7 +95,6 @@ export default {
onClose(){
this.dialogVisible = false
// console.log("dialogVisible:", this.dialogVisible)
// console.log("userid:", this.localUserId+' nickname:'+this.localNickname)
// this.$emit('input', false) // v-model 使 input
},
validateAmount(rule, value, callback){
@ -105,18 +111,39 @@ export default {
validateNumber(value){
this.form.amount = value.replace(/[^\d]/g, '')
},
onClick(){
this.$refs.resourceForm.validate((valid)=>{
if(valid){
const resourceData = {
userId: this.userId,
...this.form,
amount: parseInt(this.form.amount) //
}
this.$emit('confirm', resourceData)
this.dialogVisible = false
}
async onClick(){
// console.log('form:',this.form)
this.user.id = this.userId
this.user.resType = this.form.resourceType
this.user.resValue = this.form.amount
//
const loading = this.$loading({
lock: true,
text: '处理中...',
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
}
func (u GameRecordLog) GetIdName() string {
return "game_no"
}
func (u GameRecordLog) TableName() string {
return "game_record_log"
}

View File

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

View File

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

View File

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

View File

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

View File

@ -20,6 +20,7 @@ const (
type iTable interface {
GetId() int64
GetIdName() string
TableName() string
}
@ -32,7 +33,7 @@ type TableOp[T iTable] struct {
}
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 {
@ -128,7 +129,7 @@ func (s *TableOp[T]) Find(id int64) (*T, pb.ErrCode) {
return table, pb.ErrCode_OK
}
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 {
log.DebugF("find table:%v id:%v err:%v", s.tableName(), id, err)
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) {
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 {
log.ErrorF("update table:%v id:%v err:%v", s.tableName(), id, err)
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
}
var result utils.TValue[T]
// redis中没有值从表中加载并写入redis
mapAny := make(map[string]any)
err := s.db.Model(new(T)).
Where("id = ?", id).
Where(result.V.GetIdName()+" = ?", id).
Take(&mapAny). // 扫描到map
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)
}
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 {
log.ErrorF("add table:%v id:%v err:%v", s.tableName(), id, err)
return nil, pb.ErrCode_SystemErr
}
// 查询更新后的值到map
updatedValues := make(map[string]int64)
err = s.db.Model(new(T)).
rows, err := s.db.Model(&result.V).
Select(keysToStringSlice(res)). // 只选择需要返回的字段
Where("id = ?", id).
Take(&updatedValues). // 扫描到map
Error
Where(result.V.GetIdName()+" = ?", id).
Rows()
if err != nil {
log.ErrorF("query updated values table:%v id:%v err:%v", s.tableName(), id, err)
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)
for k, v := range updatedValues {

View File

@ -4,21 +4,15 @@ import (
"encoding/json"
"game/common/model/user"
"game/common/proto/pb"
"game/common/userBindService"
"github.com/fox/fox/ipb"
"github.com/fox/fox/log"
"github.com/fox/fox/service"
)
// 添加玩家资源,负数为减少
func RpcAddUserRes(bindService *userBindService.UserBindService, 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
}
func RpcAddUserRes(s service.IService, uid int64, addUserRes *user.AddUserRes) (map[string]int64, pb.ErrCode) {
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 {
log.ErrorF("call rpc:%v err:%s ", rpcMsg.RpcMsgId, err.Error())
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 {
err = err1
}
if err1 := db.AutoMigrateClickHouse(LogDB, user.UserResourcesLog{}.TableOptions(), user.UserResourcesLog{}); err == nil && err1 != nil {
err = err1
}
if err != nil {
log.Fatal(err.Error())