Browse Source

增加-数据结构

userxzz 10 months ago
parent
commit
773e592b6a

+ 10 - 8
game/game_cluster/internal/constant/constant.go

@@ -19,18 +19,20 @@ const (
 	PlayerIpRecordKey   = "PlayerIpRecord"
 
 	MoneyRatio = 10000000
+
+	AdminAccess = "admin"
 )
 
 // 游戏表名
 const (
-	CNameAccount               = "account"
-	CNamePlayer                = "player"
-	CNamePlayerReward          = "playerReward"
-	CNamePlayerDailyRecord     = "playerDailyRecord"
-	CNameCashOutRecord         = "cashOutRecord"
-	CNamePlayerLevelStat       = "playerLevelStat"
-	CNameServerLoadStat        = "serverLoadStat"
-	CNamePlayerCountryByIPStat = "playerCountryStat"
+	CNameAccount               = "account"           // 账号
+	CNamePlayer                = "player"            // 玩家
+	CNamePlayerReward          = "playerReward"      // 玩家奖励
+	CNamePlayerDailyRecord     = "playerDailyRecord" // 玩家每日记录
+	CNameCashOutRecord         = "cashOutRecord"     // 提现记录
+	CNamePlayerLevelStat       = "playerLevelStat"   // 玩家等级统计
+	CNameServerLoadStat        = "serverLoadStat"    // 服务器负载统计
+	CNamePlayerCountryByIPStat = "playerCountryStat" //    玩家注册国家统计
 )
 
 // 榜单数据来源类型

+ 19 - 0
game/game_cluster/internal/mdb/models/access.go

@@ -0,0 +1,19 @@
+package models
+
+// Access 权限模型
+type Access struct {
+	ID          string `bson:"_id" json:"id,omitempty"`
+	ModuleName  string `bson:"module_name" json:"module_name,omitempty"` // 模块名称
+	ActionName  string `bson:"action_name" json:"action_name,omitempty"` // 操作名称
+	ParentId    string `bson:"parent_id" json:"parent_id,omitempty"`     // 父级ID
+	Type        int    `bson:"type" json:"type,omitempty"`               // 节点类型 :  1、表示模块    2、表示菜单     3、操作
+	URL         string `bson:"url" json:"url,omitempty"`                 // 路由跳转地址
+	Sort        int    `bson:"sort" json:"sort,omitempty"`               // 排序
+	Description string `bson:"description" json:"description,omitempty"` // 描述
+	Status      int    `bson:"status" json:"status,omitempty"`           // 状态 1、正常  2、禁用
+	AddTime     int    `bson:"add_time" json:"add_time,omitempty"`       // 添加时间
+}
+
+func (Access) TableName() string {
+	return "access"
+}

+ 13 - 0
game/game_cluster/internal/mdb/models/item.go

@@ -35,6 +35,19 @@ func NewSubItem() SubItem {
 	return make(map[int]*data.ItemReward, 10)
 }
 
+func NewItemBasePack() ItemBasePack {
+	var m = make(map[int]*Item)
+	ret := data.ItemConfig.GetMap()
+	for k, v := range ret {
+		m[k] = &Item{
+			ID:       v.ID,
+			ItemType: v.Type,
+			ItemKey:  v.ItemKey,
+		}
+		delete(m, ItemAllRoll)
+	}
+	return m
+}
 func NewItem() ItemBasePack {
 	ret := data.ItemConfig
 	initItem, _ := data.DiscreteRuleConfig.Get(InitRoll)

+ 15 - 0
game/game_cluster/internal/mdb/models/role_access.go

@@ -0,0 +1,15 @@
+package models
+
+type RoleAccess struct {
+	ID       string   `json:"id" gorm:"column:id" bson:"_id"`
+	RoleId   string   `json:"role_id" gorm:"column:role_id" bson:"role_id"`       // 角色ID
+	AccessID []string `json:"access_id" gorm:"column:access_id" bson:"access_id"` // 权限ID MAP
+}
+
+func (t *RoleAccess) TableName() string {
+	return "role_access"
+}
+
+func (t *RoleAccess) GetID() string {
+	return t.ID
+}

+ 17 - 0
game/game_cluster/internal/mdb/models/roles.go

@@ -0,0 +1,17 @@
+package models
+
+type Roles struct {
+	Id            string `gorm:"column:id;primaryKey" json:"id" bson:"_id"`
+	RenterId      uint64 `gorm:"column:renter_id;type:bigint;NOT NULL;comment:租户ID;" json:"renter_id" bson:"renter_id"`
+	Name          string `gorm:"column:name;type:varchar(1024);NOT NULL;comment:角色名称" json:"name" bson:"name"`
+	PresetId      uint64 `gorm:"column:preset_id;comment:预设角色" json:"preset_id" bson:"preset_id"`
+	Desc          string `gorm:"column:desc;comment:描述" json:"desc" bson:"desc"`
+	ImportantInfo uint   `gorm:"column:important_info;type:tinyint;comment:重要信息,1:是,2:否" json:"important_info" bson:"important_info"`
+	Status        uint   `gorm:"column:status;type:tinyint;default:1;comment:状态,1:正常,2:禁用" json:"status" bson:"status"`
+	CreatedAt     uint64 `gorm:"column:created_at;autoCreateTime" json:"created_at" bson:"created_at"`
+	DeletedAt     uint64 `gorm:"column:deleted_at;" json:"deleted_at" bson:"deleted_at"`
+}
+
+func (t *Roles) TableName() string {
+	return "roles"
+}

+ 4 - 3
game/game_cluster/nodes/center/module/account/actor_account.go

@@ -2,6 +2,9 @@ package account
 
 import (
 	"context"
+	"strings"
+	"time"
+
 	mhayaTime "github.com/mhaya/extend/time"
 	cutils "github.com/mhaya/extend/utils"
 	"github.com/mhaya/game/game_cluster/internal/code"
@@ -14,8 +17,6 @@ import (
 	cactor "github.com/mhaya/net/actor"
 	"go.mongodb.org/mongo-driver/bson"
 	"go.mongodb.org/mongo-driver/mongo/options"
-	"strings"
-	"time"
 )
 
 type (
@@ -39,7 +40,7 @@ func (p *ActorAccount) OnInit() {
 	p.Timer().Add(1*time.Minute, p.PlayerIpStat)
 	p.Timer().Add(time.Minute, p.playerLevelStat)
 	p.Timer().AddFixedHour(23, 59, 59, p.Stat)
-	p.Timer().AddOnce(30*time.Second, RunToMongoDB)
+	// p.Timer().AddOnce(30*time.Second, RunToMongoDB)
 }
 
 func (p *ActorAccount) Stat() {

+ 0 - 173
game/game_cluster/nodes/tool/migrate.go

@@ -1,173 +0,0 @@
-package main
-
-import (
-	"context"
-	"database/sql"
-	"encoding/json"
-	"fmt"
-	_ "github.com/go-sql-driver/mysql"
-	"github.com/mhaya/game/game_cluster/internal/mdb/models"
-	"go.mongodb.org/mongo-driver/mongo"
-	"go.mongodb.org/mongo-driver/mongo/options"
-	"log"
-	"time"
-)
-
-// MySQL结构体
-type MySQLUser struct {
-	Username      string  `json:"username"`
-	Nickname      string  `json:"nickname"`
-	Pid           string  `json:"pid"`
-	Level         int     `json:"level"`
-	Money         float64 `json:"money"`
-	Score         int     `json:"score"`
-	Roll          int     `json:"roll"`
-	Invite        int     `json:"invite"`
-	AllRoll       int     `json:"allroll"`
-	RollDay       int     `json:"rollday"`
-	RollNums      int     `json:"rollnums"`
-	RollDays      int     `json:"rolldays"`
-	TonWall       string  `json:"tonwall"`
-	DrawsNumber   int     `json:"drawsnumber"`
-	DayLimit      int     `json:"daylimit"`
-	Jump          int     `json:"jump"`
-	DayRoll       int     `json:"dayroll"`
-	DayInvite     int     `json:"dayinvite"`
-	DatScore      int     `json:"datscore"`
-	WallTon       string  `json:"wallton"`
-	WallU         string  `json:"wallu"`
-	RollOneStatus int     `json:"rollonestatus"`
-	FirstReward   int     `json:"firsteward"`
-}
-
-// MySQL 数据读取
-func readFromMySQL() ([]MySQLUser, error) {
-	db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/dbname")
-	if err != nil {
-		return nil, err
-	}
-	defer db.Close()
-
-	rows, err := db.Query("SELECT * FROM users")
-	if err != nil {
-		return nil, err
-	}
-	defer rows.Close()
-
-	var users []MySQLUser
-	for rows.Next() {
-		var user MySQLUser
-		err := rows.Scan(
-			&user.Username,
-			&user.Nickname,
-			&user.Pid,
-			&user.Level,
-			&user.Money,
-			&user.Score,
-			&user.Roll,
-			&user.Invite,
-			&user.AllRoll,
-			&user.RollDay,
-			&user.RollNums,
-			&user.RollDays,
-			&user.TonWall,
-			&user.DrawsNumber,
-			&user.DayLimit,
-			&user.Jump,
-			&user.DayRoll,
-			&user.DayInvite,
-			&user.DatScore,
-			&user.WallTon,
-			&user.WallU,
-			&user.RollOneStatus,
-			&user.FirstReward,
-		)
-		if err != nil {
-			return nil, err
-		}
-		users = append(users, user)
-	}
-
-	return users, nil
-}
-
-// 数据转换
-func convertToMongo(user MySQLUser) (models.Player, error) {
-	var mongoUser models.Player
-	err := json.Unmarshal([]byte(fmt.Sprintf(`%v`, user)), &mongoUser)
-	if err != nil {
-		return mongoUser, err
-	}
-
-	// 填充其他字段
-	mongoUser.UserName = user.Username
-	mongoUser.NickName = user.Nickname
-	mongoUser.Pid = user.Pid
-	mongoUser.Level = user.Level
-	mongoUser.Exp = user.Score // 假设Exp和Score相同
-	mongoUser.CreateTime = time.Now().Unix()
-	mongoUser.UpdateTime = time.Now().Unix()
-	mongoUser.DailyRefreshTime = time.Now().Unix()
-	mongoUser.WeeklyRefreshTime = time.Now().Unix()
-	//mongoUser.RollDay = user.RollDay
-	mongoUser.Status = 1 // 默认状态
-	mongoUser.Index = 1  // 默认索引
-	mongoUser.TonWall = user.TonWall
-	mongoUser.JoinTime = time.Now().Unix()
-	mongoUser.JoinIP = "127.0.0.1"
-
-	// 初始化其他结构体
-	//mongoUser.Roll = &models.Roll{}
-	//mongoUser.Share = &models.RShare{}
-	//mongoUser.Item = models.RItemBasePack{}
-	//mongoUser.SinIn = models.RSignIn{}
-	//mongoUser.DailyTask = models.RDailyTask{}
-	//mongoUser.AchieveTask = models.RAchieveTask{}
-	//mongoUser.RankReward = models.RRankReward{}
-	//mongoUser.Invite = models.RInvite{}
-	//mongoUser.InviteReward = &models.RInviteReward{}
-	//mongoUser.PlayerReward = make(map[int]*models.RPlayerRewardBase)
-
-	return mongoUser, nil
-}
-
-// 插入MongoDB
-func insertIntoMongo(users []MySQLUser) error {
-	clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
-	client, err := mongo.Connect(context.TODO(), clientOptions)
-	if err != nil {
-		return err
-	}
-	defer client.Disconnect(context.TODO())
-
-	collection := client.Database("game").Collection("players")
-
-	for _, user := range users {
-		mongoUser, err := convertToMongo(user)
-		if err != nil {
-			return err
-		}
-
-		_, err = collection.InsertOne(context.TODO(), mongoUser)
-		if err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
-
-// 主函数
-func main() {
-	users, err := readFromMySQL()
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	err = insertIntoMongo(users)
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	log.Println("Data migration completed successfully.")
-}

+ 202 - 0
game/game_cluster/nodes/toolmigrate/migrate.go

@@ -0,0 +1,202 @@
+package toolmigrate
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/go-redis/redis/v8"
+	_ "github.com/go-sql-driver/mysql"
+	csnowflake "github.com/mhaya/extend/snowflake"
+	"github.com/mhaya/game/game_cluster/internal/constant"
+	"github.com/mhaya/game/game_cluster/internal/data"
+	"github.com/mhaya/game/game_cluster/internal/mdb/models"
+	"go.mongodb.org/mongo-driver/mongo"
+	"go.mongodb.org/mongo-driver/mongo/options"
+	"gorm.io/driver/mysql"
+	"gorm.io/gorm"
+)
+
+var Mdb *mongo.Client
+var RDB redis.UniversalClient
+
+func InsertMongoPlayer(userS []FaUser) error {
+	var playerData []*models.Player
+	var docs []interface{}
+	// 格式化数据存入mongodb
+	for _, user := range userS {
+		result, err := RDB.Get(context.Background(), user.Username).Result()
+		if err != nil {
+			return err
+		}
+		pid, err := RDB.Get(context.Background(), user.Pid).Result()
+		if err != nil || pid == "" {
+			pid = ""
+		}
+		var item = make(map[int]*models.Item)
+		ret := data.ItemConfig.GetMap()
+		for k, v := range ret {
+			item[k] = &models.Item{
+				ID:       v.ID,
+				ItemType: v.Type,
+				ItemKey:  v.ItemKey,
+			}
+			delete(item, models.ItemAllRoll)
+		}
+
+		pl := &models.Player{
+			UserName:      result,
+			OpenId:        user.Username,
+			UserNameMaybe: user.Nickname,
+			XID:           user.XId,
+			JoinIP:        user.Joinip,
+			Pid:           pid,
+			JoinTime:      user.Jointime,
+			CreateTime:    user.Createtime,
+			TonWall:       user.Tonwall,
+			UpdateTime:    user.Updatetime,
+			Level:         int(user.Level),
+			Item:          item,
+		}
+		pl.Item.AddItem([]data.ItemReward{{ItemID: models.ItemScore, ItemBaseType: 1, Amount: int(user.Score)}})
+		pl.Item.AddItem([]data.ItemReward{{ItemID: models.ItemRoll, ItemBaseType: 1, Amount: int(user.Roll)}})
+		pl.Item.AddItem([]data.ItemReward{{ItemID: models.ItemInvite, ItemBaseType: 3, Amount: int(user.Invite)}})
+		pl.Item.AddItem([]data.ItemReward{{ItemID: models.ItemDrawsNumber, ItemBaseType: 1, Amount: int(user.Drawsnumber)}})
+		pl.Item.AddItem([]data.ItemReward{{ItemID: models.ItemTon, ItemBaseType: 1, Amount: MoneyRatioFloat64(user.WallTon)}})
+		pl.Item.AddItem([]data.ItemReward{{ItemID: models.ItemU, ItemBaseType: 1, Amount: MoneyRatioFloat64(user.WallU)}})
+		item[1].MaxNum = int(user.Allroll)
+		playerData = append(playerData, pl)
+
+	}
+	// 将 playerData 转换为 []interface{} 类型
+	docs = make([]interface{}, len(playerData))
+	for i, player := range playerData {
+		docs[i] = player
+	}
+	// 批量插入MongoDB
+	collection := Mdb.Database("db_mhaya").Collection("player")
+	_, err := collection.InsertMany(context.Background(), docs)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func MoneyRatioFloat64(f float64) int {
+	return int(f * constant.MoneyRatio)
+}
+
+func InsertMongoBD() error {
+	var userS []FaUser
+	db, err := connectToDatabase()
+	if err != nil {
+		return err
+	}
+	db.Table("fa_user").Find(&userS)
+
+	err = InsertMongoAccount(userS)
+	if err != nil {
+		return err
+	}
+	err = InsertMongoPlayer(userS)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func GetRedisConnect() {
+	RDB = redis.NewUniversalClient(&redis.UniversalOptions{
+		Addrs:    []string{"127.0.0.1:6379"},
+		Password: "",
+		DB:       0,
+	})
+}
+
+func InsertMongoAccount(userS []FaUser) error {
+	var AccountData []models.Account
+
+	// redis map 映射
+	for _, user := range userS {
+		RDB.Set(context.Background(), user.Username, Next(), 0)
+	}
+
+	for _, user := range userS {
+		result, err := RDB.Get(context.Background(), user.Username).Result()
+		if err != nil {
+			return err
+		}
+		AccountData = append(AccountData, models.Account{
+			Channel:  "on",
+			JoinIp:   user.Joinip,
+			JoinTime: user.Jointime,
+			OpenId:   user.Username,
+			Platform: "tg",
+			UserName: result,
+		})
+	}
+	// 将 playerData 转换为 []interface{} 类型
+	docs := make([]interface{}, len(AccountData))
+	for i, player := range AccountData {
+		docs[i] = player
+	}
+	// 批量插入MongoDB
+	collection := Mdb.Database("db_mhaya").Collection("account")
+	_, err := collection.InsertMany(context.Background(), docs)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func connectToMongoDB() error {
+	// 假设使用标准库或第三方库进行 MongoDB 连接
+	clientOptions := options.Client().ApplyURI("mongodb://192.168.0.185:27017")
+	// 创建一个新的 MongoDB 客户端
+	mdb, err := mongo.Connect(context.Background(), clientOptions)
+	if err != nil {
+		return err
+	}
+	// 检查连接是否成功
+	err = mdb.Ping(context.Background(), nil)
+	if err != nil {
+		return err
+	}
+	Mdb = mdb
+	return nil
+}
+
+func connectToDatabase() (*gorm.DB, error) {
+	dsn := "root:root@tcp(127.0.0.1:3306)/load_db?charset=utf8mb4&parseTime=True&loc=Local"
+	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
+	if err != nil {
+		return nil, fmt.Errorf("failed to connect database: %v", err)
+	}
+	return db, nil
+}
+func Next() string {
+	node, _ := csnowflake.NewNode(1)
+	var sid string
+	for {
+		id := node.Generate()
+		sid = id.Base58()
+		if RDB.HExists(context.Background(), "PlayerID", sid).Val() {
+			continue
+		}
+		RDB.HSet(context.Background(), "PlayerID", sid, 1)
+		return sid
+	}
+}
+
+func RunToMongoDB() {
+	GetRedisConnect()
+
+	err := connectToMongoDB()
+	if err != nil {
+		return
+	}
+	// err = InsertMongoBD()
+	// if err != nil {
+	// 	return
+	// }
+
+}

+ 503 - 0
game/game_cluster/nodes/webadmin/controller/role.go

@@ -0,0 +1,503 @@
+package controller
+
+import (
+	"net/http"
+
+	"github.com/gin-gonic/gin"
+	"github.com/mhaya/game/game_cluster/nodes/webadmin/entity"
+	"github.com/mhaya/game/game_cluster/nodes/webadmin/service"
+)
+
+type Role struct {
+}
+
+func NewRole() *Role {
+	return &Role{}
+}
+
+// Add 新增角色
+// @Summary 新增角色
+// @Description 新增角色
+// @Tags 角色
+// @Accept application/json
+// @Produce application/json
+// @Param data body entity.RoleAddReq true "新增角色"
+// @Success 200 {object} entity.Response
+// @Router /v1/admin/role/add [post]
+func (r *Role) Add(ctx *gin.Context) {
+	req := new(entity.RoleAddReq)
+	if err := ctx.ShouldBindJSON(&req); err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	err := new(service.Role).Add(ctx, *req)
+	if err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	ctx.JSON(http.StatusOK, gin.H{
+		"code": 200,
+		"msg":  "success",
+	})
+}
+
+// List 角色列表
+// @Summary 角色列表
+// @Description 角色列表
+// @Tags 角色
+// @Accept application/json
+// @Produce application/json
+// @Param data query entity.RoleListReq true "角色列表"
+// @Success 200 {object} entity.Response
+// @Router /v1/admin/role/list [get]
+func (r *Role) List(ctx *gin.Context) {
+	req := new(entity.RoleListReq)
+	if err := ctx.ShouldBindQuery(&req); err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	list, err := new(service.Role).List(ctx, *req)
+	if err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	ctx.JSON(http.StatusOK, gin.H{
+		"code": 200,
+		"msg":  "success",
+		"data": list,
+	})
+}
+
+// Update 修改角色
+// @Summary 修改角色
+// @Description 修改角色
+// @Tags 角色
+// @Accept application/json
+// @Produce application/json
+// @Param data body entity.RoleUpdateReq true "修改角色"
+// @Success 200 {object} entity.Response
+// @Router /v1/admin/role/update [post]
+func (r *Role) Update(ctx *gin.Context) {
+	req := new(entity.RoleUpdateReq)
+	if err := ctx.ShouldBindJSON(&req); err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	err := new(service.Role).Update(ctx, *req)
+	if err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	ctx.JSON(http.StatusOK, gin.H{
+		"code": 200,
+		"msg":  "success",
+	})
+}
+
+// Del 删除角色
+// @Summary 删除角色
+// @Description 删除角色
+// @Tags 角色
+// @Accept application/json
+// @Produce application/json
+// @Param data query entity.RoleDelReq true "删除角色"
+// @Success 200 {object} entity.Response
+// @Router /v1/admin/role/del [get]
+func (r *Role) Del(ctx *gin.Context) {
+	req := new(entity.RoleDelReq)
+	if err := ctx.ShouldBindQuery(&req); err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	err := new(service.Role).Del(ctx, *req)
+	if err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	ctx.JSON(http.StatusOK, gin.H{
+		"code": 200,
+		"msg":  "success",
+	})
+}
+
+// AddRoleAccess  添加角色权限
+// @Summary 添加角色权限
+// @Description 添加角色权限
+// @Tags 角色
+// @Accept application/json
+// @Produce application/json
+// @Param data body entity.RoleAccessAddReq true "添加角色权限"
+// @Success 200 {object} entity.Response
+// @Router /v1/admin/role/role_access/add [post]
+func (r *Role) AddRoleAccess(ctx *gin.Context) {
+	req := new(entity.RoleAccessAddReq)
+	if err := ctx.ShouldBindJSON(&req); err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	err := new(service.Role).AddRoleAccess(ctx, *req)
+	if err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	ctx.JSON(http.StatusOK, gin.H{
+		"code": 200,
+		"msg":  "success",
+	})
+}
+
+// UpdateRoleAccess 修改角色权限
+// @Summary 修改角色权限
+// @Description 修改角色权限
+// @Tags 角色
+// @Accept application/json
+// @Produce application/json
+// @Param data body entity.RoleAccessUpdateReq true "修改角色权限"
+// @Success 200 {object} entity.Response
+// @Router /v1/admin/role/role_access/update [post]
+func (r *Role) UpdateRoleAccess(ctx *gin.Context) {
+	req := new(entity.RoleAccessUpdateReq)
+	if err := ctx.ShouldBindJSON(&req); err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	err := new(service.Role).UpdateRoleAccess(ctx, *req)
+	if err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	ctx.JSON(http.StatusOK, gin.H{
+		"code": 200,
+		"msg":  "success",
+	})
+}
+
+// DelRoleAccess 删除角色权限
+// @Summary 删除角色权限
+// @Description 删除角色权限
+// @Tags 角色
+// @Accept application/json
+// @Produce application/json
+// @Param data query entity.RoleAccessDelReq true "删除角色权限"
+// @Success 200 {object} entity.Response
+// @Router /v1/admin/role/role_access/del [get]
+func (r *Role) DelRoleAccess(ctx *gin.Context) {
+	req := new(entity.RoleAccessDelReq)
+	if err := ctx.ShouldBindQuery(&req); err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	err := new(service.Role).DelRoleAccess(ctx, *req)
+	if err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	ctx.JSON(http.StatusOK, gin.H{
+		"code": 200,
+		"msg":  "success",
+	})
+}
+
+// GetRoleAccessList 获取角色权限列表根据角色ID
+// @Summary 获取角色权限列表根据角色ID
+// @Description 获取角色权限列表根据角色ID
+// @Tags 角色
+// @Accept application/json
+// @Produce application/json
+// @Param data query entity.RoleAccessListReq true "获取角色权限列表根据角色ID"
+// @Success 200 {object} []entity.AccessResp
+// @Router /v1/admin/role/role_access/list [get]
+func (r *Role) GetRoleAccessList(ctx *gin.Context) {
+	req := new(entity.RoleAccessListReq)
+	if err := ctx.ShouldBindQuery(&req); err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	list, err := new(service.Role).GetRoleAccessList(ctx, *req)
+	if err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	ctx.JSON(http.StatusOK, gin.H{
+		"code": 200,
+		"msg":  "success",
+		"data": list,
+	})
+}
+
+// AddAccess 添加权限路由
+// @Summary 添加权限路由
+// @Description 添加权限路由
+// @Tags 角色-路由
+// @Accept application/json
+// @Produce application/json
+// @Param data body entity.AccessAddReq true "添加权限路由"
+// @Success 200 {object} entity.Response
+// @Router /v1/admin/role/access/add [post]
+func (r *Role) AddAccess(ctx *gin.Context) {
+	req := new(entity.AccessAddReq)
+	if err := ctx.ShouldBindJSON(&req); err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	err := new(service.Role).AddAccess(ctx, *req)
+	if err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	ctx.JSON(http.StatusOK, gin.H{
+		"code": 200,
+		"msg":  "success",
+	})
+}
+
+// DelAccess
+// @Summary 删除权限路由
+// @Description 删除权限路由
+// @Tags 角色-路由
+// @Accept application/json
+// @Produce application/json
+// @Param data query entity.AccessDelReq true "删除权限路由"
+// @Success 200 {object} entity.Response
+// @Router /v1/admin/role/access/del [post]
+func (r *Role) DelAccess(ctx *gin.Context) {
+	req := new(entity.AccessDelReq)
+	if err := ctx.ShouldBindJSON(&req); err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	err := new(service.Role).DelAccess(ctx, *req)
+	if err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	ctx.JSON(http.StatusOK, gin.H{
+		"code": 200,
+		"msg":  "success",
+	})
+
+}
+
+// UpdateAccess  修改权限路由
+// @Summary 修改权限路由
+// @Description 修改权限路由
+// @Tags 角色-路由
+// @Accept application/json
+// @Produce application/json
+// @Param data body entity.AccessUpdateReq true "修改权限路由"
+// @Success 200 {object} entity.Response
+// @Router /v1/admin/role/access/update [post]
+func (r *Role) UpdateAccess(ctx *gin.Context) {
+	req := new(entity.AccessUpdateReq)
+	if err := ctx.ShouldBindJSON(&req); err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	err := new(service.Role).UpdateAccess(ctx, *req)
+	if err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	ctx.JSON(http.StatusOK, gin.H{
+		"code": 200,
+		"msg":  "success",
+	})
+}
+
+// ListAccess 获取权限路由列表
+// @Summary 获取权限路由列表
+// @Description 获取权限路由列表
+// @Tags 角色-路由
+// @Accept application/json
+// @Produce application/json
+// @Param data query entity.AccessListReq true "获取权限路由列表"
+// @Success 200 {object} []entity.AccessResp
+// @Router /v1/admin/role/access/list [get]
+func (r *Role) ListAccess(ctx *gin.Context) {
+	req := new(entity.AccessListReq)
+	if err := ctx.ShouldBindQuery(&req); err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	list, err := new(service.Role).ListAccess(ctx, *req)
+	if err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	ctx.JSON(http.StatusOK, gin.H{
+		"code": 200,
+		"msg":  "success",
+		"data": list,
+	})
+}
+
+// GetAdminRole
+// @Summary 获取该管理员的权限详情
+// @Description 获取该管理员的权限详情
+// @Tags 角色
+// @Accept application/json
+// @Produce application/json
+// @Param data query entity.AdminBindRoleReq true "获取角色"
+// @Success 200 {object} entity.AdminBindRoleResp
+// @Router /v1/admin/role/admin_role_info [get]
+func (r *Role) GetAdminRole(ctx *gin.Context) {
+	req := new(entity.AdminBindRoleReq)
+	if err := ctx.ShouldBindQuery(&req); err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	list, err := new(service.Role).GetAdminRole(ctx, req)
+	if err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	ctx.JSON(http.StatusOK, gin.H{
+		"code": 200,
+		"msg":  "success",
+		"data": list,
+	})
+	return
+}
+
+// AdminBindRole 绑定角色
+// @Summary 绑定角色
+// @Description 绑定角色
+// @Tags 角色
+// @Accept application/json
+// @Produce application/json
+// @Param data body entity.AdminBindRoleReq true "绑定角色"
+// @Success 200 {object} entity.Response
+// @Router /v1/admin/role/admin_bind_role [post]
+func (r *Role) AdminBindRole(ctx *gin.Context) {
+	req := new(entity.AdminBindRoleReq)
+	if err := ctx.ShouldBindJSON(&req); err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	err := new(service.Role).AdminBindRole(ctx, req)
+	if err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	ctx.JSON(http.StatusOK, gin.H{
+		"code": 200,
+		"msg":  "success",
+	})
+
+}
+
+// AdminUnBindRole 取消绑定角色
+// @Summary 取消绑定角色
+// @Description 取消绑定角色
+// @Tags 角色
+// @Accept application/json
+// @Produce application/json
+// @Param data body entity.AdminBindRoleReq true "取消绑定角色"
+// @Success 200 {object} entity.Response
+// @Router /v1/admin/role/admin_unbind_role [post]
+func (r *Role) AdminUnBindRole(ctx *gin.Context) {
+	req := new(entity.AdminBindRoleReq)
+	if err := ctx.ShouldBindJSON(&req); err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	err := new(service.Role).AdminUnBindRole(ctx, req)
+	if err != nil {
+		ctx.JSON(200, gin.H{
+			"code": 400,
+			"msg":  err.Error(),
+		})
+		return
+	}
+	ctx.JSON(http.StatusOK, gin.H{
+		"code": 200,
+		"msg":  "success",
+	})
+}

+ 131 - 0
game/game_cluster/nodes/webadmin/entity/role.go

@@ -0,0 +1,131 @@
+package entity
+
+type RoleResp struct {
+	Id        string `gorm:"column:id;primaryKey" json:"id" bson:"_id"`
+	RenterId  uint64 `gorm:"column:renter_id;type:bigint;NOT NULL;comment:租户ID;" json:"renter_id" bson:"renter_id"`
+	Name      string `gorm:"column:name;type:varchar(1024);NOT NULL;comment:角色名称" json:"name" bson:"name"`
+	PresetId  uint64 `gorm:"column:preset_id;comment:预设角色" json:"preset_id" bson:"preset_id"`
+	Desc      string `gorm:"column:desc;comment:描述" json:"desc" bson:"desc"`
+	Status    uint   `gorm:"column:status;type:tinyint;default:1;comment:状态,1:正常,2:禁用" json:"status" bson:"status"`
+	CreatedAt uint64 `gorm:"column:created_at;autoCreateTime" json:"created_at" bson:"created_at"`
+	DeletedAt uint64 `gorm:"column:deleted_at;" json:"deleted_at" bson:"deleted_at"`
+}
+
+type AccessResp struct {
+	ID          string        `bson:"id" json:"id,omitempty"`
+	ModuleName  string        `bson:"module_name" json:"module_name,omitempty"` // 模块名称
+	ActionName  string        `bson:"action_name" json:"action_name,omitempty"` // 操作名称
+	ParentId    string        `bson:"parent_id" json:"parent_id,omitempty"`     // 父级ID
+	Type        int           `bson:"type" json:"type,omitempty"`               // 节点类型 :  1、表示模块    2、表示菜单     3、操作
+	URL         string        `bson:"url" json:"url,omitempty"`                 // 路由跳转地址
+	Sort        int           `bson:"sort" json:"sort,omitempty"`               // 排序
+	Description string        `bson:"description" json:"description,omitempty"` // 描述
+	Status      int           `bson:"status" json:"status,omitempty"`           // 状态 1、正常  2、禁用
+	AddTime     int           `bson:"add_time" json:"add_time,omitempty"`       // 添加时间
+	AccessItem  []*AccessResp `bson:"access_item" json:"access_item"`           // 子节点
+}
+
+type RoleListReq struct {
+	Page   int    `json:"page"  binding:"required" form:"page"`
+	Size   int    `json:"size"  binding:"required" form:"size"`
+	Name   string `json:"name" form:"name"`
+	Status uint   `json:"status" form:"status"`
+}
+
+type RoleAddReq struct {
+	Name   string `json:"name"  binding:"required" bson:"name"`
+	Desc   string `json:"desc" bson:"desc"`
+	Status uint   `json:"status" bson:"status"  binding:"required"`
+}
+type RoleDelReq struct {
+	Id string `json:"id" binding:"required" form:"id"`
+}
+
+type RoleUpdateReq struct {
+	Id     string `json:"id" binding:"required"`
+	Name   string `json:"name"`
+	Desc   string `json:"desc" bson:"desc"`
+	Status uint   `json:"status" bson:"status"`
+}
+
+// RoleAccessListReq 角色权限
+type RoleAccessListReq struct {
+	RoleId string `json:"role_id" form:"role_id"`
+}
+
+// RoleAccessAddReq 添加角色权限
+type RoleAccessAddReq struct {
+	RoleId   string   `json:"role_id"`
+	AccessId []string `json:"access"`
+}
+
+// RoleAccessUpdateReq 修改角色权限
+type RoleAccessUpdateReq struct {
+	RoleId   string   `json:"role_id"`
+	AccessId []string `json:"access"`
+}
+
+type RoleAccessDelReq struct {
+	RoleId string `json:"role_id"`
+}
+type Response struct {
+	Code    int    `json:"code"`
+	Message string `json:"message"`
+	Data    interface{}
+}
+type AccessDelReq struct {
+	Id string `json:"id" form:"id"`
+}
+
+// AccessAddReq 添加权限路由
+type AccessAddReq struct {
+	ModuleName  string `bson:"module_name" json:"module_name"` // 模块名称
+	ActionName  string `bson:"action_name" json:"action_name"` // 操作名称
+	ParentId    string `bson:"parent_id" json:"parent_id"`     // 父级ID  0表示顶级
+	Type        int    `bson:"type" json:"type"`               // 节点类型 :  1、表示模块    2、表示菜单     3、操作
+	URL         string `bson:"url" json:"url"`                 // 路由跳转地址
+	Sort        int    `bson:"sort" json:"sort"`               // 排序
+	Description string `bson:"description" json:"description"` // 描述
+	Status      int    `bson:"status" json:"status"`           // 状态 1、正常  2、禁用
+}
+
+// AccessUpdateReq 修改权限路由
+type AccessUpdateReq struct {
+	Id          string `bson:"_id" json:"id"`                  // 权限ID
+	ModuleName  string `bson:"module_name" json:"module_name"` // 模块名称
+	ActionName  string `bson:"action_name" json:"action_name"` // 操作名称
+	ParentId    string `bson:"parent_id" json:"parent_id"`     // 父级ID  0表示顶级
+	Type        int    `bson:"type" json:"type"`               // 节点类型 :  1、表示模块    2、表示菜单     3、操作
+	URL         string `bson:"url" json:"url"`                 // 路由跳转地址
+	Sort        int    `bson:"sort" json:"sort"`               // 排序
+	Description string `bson:"description" json:"description"` // 描述
+	Status      int    `bson:"status" json:"status"`           // 状态 1、正常  2、禁用
+}
+
+type AccessListReq struct {
+	Page       int    `json:"page" form:"page"`
+	Size       int    `json:"size" form:"size"`
+	ModuleName string `json:"module_name" form:"module_name"`
+	ActionName string `json:"action_name" form:"action_name"`
+	ParentId   string `json:"parent_id" form:"parent_id"`
+	Type       int    `json:"type" form:"type"`
+	Status     int    `json:"status" form:"status"`
+	URL        string `bson:"url" json:"url" form:"url"` // 路由跳转地址
+}
+
+type AdminBindRoleReq struct {
+	AdminId string `json:"admin_id" form:"admin_id"`
+	RoleId  string `json:"role_id" form:"role_id"`
+}
+
+type AdminRoleByIDReq struct {
+	AdminId string `json:"admin_id" form:"admin_id"`
+}
+
+type AdminBindRoleResp struct {
+	RoleId     string        `json:"role_id"`    // 角色ID
+	AdminId    string        `json:"admin_id"`   // 管理员ID
+	AdminName  string        `json:"admin_name"` // 管理员名称
+	RoleName   string        `json:"role_name"`  // 角色名称
+	AccessList []*AccessResp `json:"access_list"`
+}

+ 14 - 14
game/game_cluster/nodes/webadmin/model/admin.go

@@ -9,19 +9,19 @@ import (
 )
 
 type Admin struct {
-	Id            int64  `json:"id" bson:"id"`                           // 自增ID
-	Username      string `json:"username" bson:"username"`               // 用户名
-	Password      string `json:"password" bson:"password"`               // 密码
-	RealName      string `json:"real_name" bson:"real_name"`             // 真实姓名
-	Pid           int64  `json:"pid" bson:"pid"`                         // 父级ID
-	RoleId        int64  `json:"role_id" bson:"role_id"`                 // 角色ID
-	Status        int    `json:"status" bson:"status"`                   // 状态 0:禁用 1:启用
-	ManagerAuth   int8   `json:"manager_auth" bson:"manager_auth"`       // 管理员权限
-	LastLoginIp   string `json:"last_login_ip" bson:"last_login_ip"`     // 最后登录IP
-	LastLoginTime int64  `json:"last_login_time" bson:"last_login_time"` // 最后登录时间
-	CreatedAt     int64  `json:"created_at" bson:"created_at"`
-	UpdatedAt     int64  `json:"updated_at" bson:"updated_at"`
-	DeletedAt     int64  `json:"deleted_at" bson:"deleted_at"`
+	Id            interface{} `json:"id" bson:"_id"`                          // 自增ID
+	Username      string      `json:"username" bson:"username"`               // 用户名
+	Password      string      `json:"password" bson:"password"`               // 密码
+	RealName      string      `json:"real_name" bson:"real_name"`             // 真实姓名
+	Pid           int64       `json:"pid" bson:"pid"`                         // 父级ID
+	RoleId        string      `json:"role_id" bson:"role_id"`                 // 角色ID
+	Status        int         `json:"status" bson:"status"`                   // 状态 0:禁用 1:启用
+	ManagerAuth   int8        `json:"manager_auth" bson:"manager_auth"`       // 管理员权限
+	LastLoginIp   string      `json:"last_login_ip" bson:"last_login_ip"`     // 最后登录IP
+	LastLoginTime int64       `json:"last_login_time" bson:"last_login_time"` // 最后登录时间
+	CreatedAt     int64       `json:"created_at" bson:"created_at"`
+	UpdatedAt     int64       `json:"updated_at" bson:"updated_at"`
+	DeletedAt     int64       `json:"deleted_at" bson:"deleted_at"`
 }
 
 func (a *Admin) TableName() string {
@@ -62,6 +62,6 @@ func (a *Admin) GenerateToken() (string, error) {
 	return base64.URLEncoding.EncodeToString(token), nil
 }
 
-func (a *Admin) GetID() int64 {
+func (a *Admin) GetID() interface{} {
 	return a.Id
 }

+ 12 - 0
game/game_cluster/nodes/webadmin/router/middleware.go

@@ -5,6 +5,7 @@ import (
 	"net/http"
 
 	"github.com/gin-gonic/gin"
+	"github.com/mhaya/game/game_cluster/internal/constant"
 	"github.com/mhaya/game/game_cluster/internal/mdb"
 )
 
@@ -27,6 +28,17 @@ func Auth() gin.HandlerFunc {
 			})
 			return
 		}
+		// 获取请求URL
+		url := c.Request.URL.Path
+		s, _ := mdb.RDB.HGet(context.Background(), "admin::token::"+tokenString, url).Result()
+		admin, _ := mdb.RDB.HGet(context.Background(), "admin::token::"+tokenString, constant.AdminAccess).Result()
+		// 检查是否有权限
+		if s == "" && admin == "" {
+			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
+				"msg": "token is no auth",
+			})
+			return
+		}
 		c.Next()
 	}
 }

+ 16 - 1
game/game_cluster/nodes/webadmin/router/router.go

@@ -36,7 +36,7 @@ func (c *Controller) SetRouter() {
 }
 
 func (c *Controller) InitApiRouter(u *gin.RouterGroup) {
-	u.Use(Auth())
+	// u.Use(Auth())
 	u.POST("/user/log/daily", controller.NewSynthesis().FindUserLogDaily)
 	u.POST("/user/retention", controller.NewSynthesis().FindUserRetention)
 	u.POST("/user/country", controller.NewSynthesis().FindUserCountryCount)
@@ -49,6 +49,21 @@ func (c *Controller) InitApiRouter(u *gin.RouterGroup) {
 	u.POST("/user/find", controller.NewAdmin().FindAll)
 	u.POST("/user/update", controller.NewAdmin().UpdateStatus)
 	u.POST("/user/server_status", controller.NewAdmin().GetServerStatus)
+	u.POST("/role/add", controller.NewRole().Add)
+	u.POST("/role/update", controller.NewRole().Update)
+	u.GET("/role/del", controller.NewRole().Del)
+	u.GET("/role/list", controller.NewRole().List)
+	u.POST("/role/access/add", controller.NewRole().AddAccess)
+	u.GET("/role/access/del", controller.NewRole().DelAccess)
+	u.GET("/role/access/list", controller.NewRole().ListAccess)
+	u.POST("/role/access/update", controller.NewRole().UpdateAccess)
+	u.POST("/role/role_access/add", controller.NewRole().AddRoleAccess)
+	u.GET("/role/role_access/del", controller.NewRole().DelRoleAccess)
+	u.GET("/role/role_access/list", controller.NewRole().GetRoleAccessList)
+	u.POST("/role/role_access/update", controller.NewRole().UpdateRoleAccess)
+	u.POST("/role/admin_unbind_role", controller.NewRole().AdminUnBindRole)
+	u.POST("/role/admin_bind_role", controller.NewRole().AdminBindRole)
+	u.POST("/role/admin_role_info", controller.NewRole().GetAdminRole)
 }
 
 // func (c *Controller) InitMdb() {

+ 87 - 30
game/game_cluster/nodes/webadmin/service/admin.go

@@ -6,6 +6,7 @@ import (
 	"fmt"
 	"log"
 	"regexp"
+	"strconv"
 	"strings"
 	"time"
 
@@ -16,6 +17,7 @@ import (
 	"github.com/mhaya/game/game_cluster/nodes/webadmin/entity"
 	"github.com/mhaya/game/game_cluster/nodes/webadmin/model"
 	"go.mongodb.org/mongo-driver/bson"
+	"go.mongodb.org/mongo-driver/bson/primitive"
 	"go.mongodb.org/mongo-driver/mongo"
 	"go.mongodb.org/mongo-driver/mongo/options"
 	"golang.org/x/crypto/bcrypt"
@@ -51,7 +53,6 @@ func HashPassword(password string) (string, error) {
 
 // Login 登录
 func (a *Admin) Login(ctx *gin.Context, username string, password string) (*entity.AdminResp, error) {
-	log.Printf("Attempting login for user: %s", username)
 	user, err := a.QueryUserByUsername(ctx, username)
 	if err != nil {
 		log.Printf("Failed to query user: %s", err)
@@ -77,6 +78,10 @@ func (a *Admin) Login(ctx *gin.Context, username string, password string) (*enti
 	if err != nil {
 		return nil, err
 	}
+	err = a.loginAuthSetRoleRedis(user.RoleId, generateToken)
+	if err != nil {
+		return nil, err
+	}
 	// 更新用户登录时间
 	_, err = mdb.MDB.Collection(a.GetDBName()).UpdateOne(ctx, bson.M{"username": username}, bson.M{"$set": bson.M{"last_login_time": time.Now().Unix()}})
 	log.Printf("Login successful for user: %s", username)
@@ -94,44 +99,96 @@ func (a *Admin) Login(ctx *gin.Context, username string, password string) (*enti
 	}, nil
 }
 
+// LoginAuthSetRoleRedis 登录时写入该用户的权限
+func (a *Admin) loginAuthSetRoleRedis(roleID, generateToken string) error {
+	if roleID == constant.AdminAccess {
+		mdb.RDB.HSet(context.Background(), "admin::token::"+generateToken, constant.AdminAccess, 1)
+		return nil
+	}
+
+	// 写入redis
+	role := models.Roles{}
+	collection := mdb.MDB.Collection(role.TableName())
+	roleIdObj, _ := primitive.ObjectIDFromHex(roleID)
+	filter := bson.M{"_id": roleIdObj, "status": 1}
+	err := collection.FindOne(context.TODO(), filter).Decode(&role)
+	if err != nil {
+		return err
+	}
+	roleAccess := models.RoleAccess{}
+	collection = mdb.MDB.Collection(roleAccess.TableName())
+	roleAccessFilter := bson.M{"role_id": roleID}
+	err = collection.FindOne(context.TODO(), roleAccessFilter).Decode(&roleAccess)
+	if err != nil {
+		return err
+	}
+	// 写入redis
+	var accessIDS []primitive.ObjectID
+	for _, v := range roleAccess.AccessID {
+		accessIdObj, _ := primitive.ObjectIDFromHex(v)
+		accessIDS = append(accessIDS, accessIdObj)
+	}
+
+	access := models.Access{}
+	var accessList []models.Access
+	collection = mdb.MDB.Collection(access.TableName())
+	accessFilter := bson.M{"_id": bson.M{"$in": accessIDS}}
+	cursor, err := collection.Find(context.Background(), accessFilter)
+	if err != nil {
+		return err
+	}
+	if err = cursor.All(context.Background(), &accessList); err != nil {
+		return err
+	}
+	for _, v := range accessList {
+		mdb.RDB.HSet(context.Background(), "admin::token::"+generateToken, v.URL, 1)
+	}
+	return nil
+
+}
+
 // QueryUserByUsername 根据用户名查询用户
 func (a *Admin) QueryUserByUsername(ctx context.Context, username string) (*model.Admin, error) {
-	admin := model.Admin{}
+	admin := &model.Admin{}
 	err := mdb.MDB.Collection(a.GetDBName()).FindOne(ctx, bson.M{"username": username}).Decode(&admin)
 	if errors.Is(err, mongo.ErrNoDocuments) && username == "admin" {
 		// 如果是admin 登录的话 创建一个初始的admin并且存入数据库
-		if username == "admin" {
-			pwd, err := HashPassword("123456")
-			if err != nil {
-				return nil, err
-			}
-			adminn := &model.Admin{
-				Username:      "admin",
-				Password:      pwd,
-				RealName:      "admin",
-				Pid:           0,
-				RoleId:        0,
-				ManagerAuth:   0,
-				Status:        1,
-				CreatedAt:     0,
-				UpdatedAt:     0,
-				DeletedAt:     0,
-				LastLoginIp:   "",
-				LastLoginTime: 0,
-				Id:            0,
-			}
-			_, err = mdb.MDB.Collection(a.GetDBName()).InsertOne(ctx, adminn)
-			if err != nil {
-				return nil, err
-			}
-			return adminn, nil
+		pwd, err := HashPassword("123456")
+		if err != nil {
+			return nil, err
+		}
+		admin = &model.Admin{
+			Username:      constant.AdminAccess,
+			Password:      pwd,
+			RealName:      constant.AdminAccess,
+			Pid:           0,
+			RoleId:        constant.AdminAccess,
+			ManagerAuth:   0,
+			Status:        1,
+			CreatedAt:     0,
+			UpdatedAt:     0,
+			DeletedAt:     0,
+			LastLoginIp:   "",
+			LastLoginTime: 0,
+		}
+		_, err = mdb.MDB.Collection(a.GetDBName()).InsertOne(ctx, bson.M{
+			"username":  constant.AdminAccess,
+			"password":  pwd,
+			"real_name": constant.AdminAccess,
+			"pid":       0,
+			"role_id":   constant.AdminAccess,
+			"status":    1,
+		})
+		if err != nil {
+			return nil, err
 		}
+		return admin, nil
 	}
 	if err != nil {
 		return nil, err
 	}
 
-	return &admin, nil
+	return admin, nil
 
 }
 
@@ -158,7 +215,7 @@ func (a *Admin) Add(ctx context.Context, username string, password string, realN
 			Password:      password,
 			RealName:      realName,
 			Pid:           pid,
-			RoleId:        roleId,
+			RoleId:        strconv.FormatInt(roleId, 10),
 			Status:        status,
 			CreatedAt:     time.Now().Unix(),
 			UpdatedAt:     time.Now().Unix(),
@@ -183,7 +240,7 @@ func (a *Admin) Delete(ctx context.Context, username string) error {
 	return nil
 }
 
-// updateStatus
+// UpdateStatus updateStatus
 func (a *Admin) UpdateStatus(ctx context.Context, username string, status int) error {
 	_, err := mdb.MDB.Collection(a.GetDBName()).UpdateOne(ctx, bson.M{"username": username}, bson.M{"$set": bson.M{"status": status}})
 	if err != nil {

+ 726 - 0
game/game_cluster/nodes/webadmin/service/role.go

@@ -0,0 +1,726 @@
+package service
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"log"
+	"strings"
+	"sync"
+	"time"
+
+	"github.com/mhaya/game/game_cluster/internal/mdb"
+	"github.com/mhaya/game/game_cluster/internal/mdb/models"
+	"github.com/mhaya/game/game_cluster/nodes/webadmin/entity"
+	"github.com/mhaya/game/game_cluster/nodes/webadmin/model"
+	"go.mongodb.org/mongo-driver/bson"
+	"go.mongodb.org/mongo-driver/bson/primitive"
+	"go.mongodb.org/mongo-driver/mongo"
+	"go.mongodb.org/mongo-driver/mongo/options"
+)
+
+type Role struct {
+}
+
+func NewRole() *Role {
+	return &Role{}
+}
+
+// List 角色列表
+func (r *Role) List(ctx context.Context, req entity.RoleListReq) ([]entity.RoleResp, error) {
+	roles := models.Roles{}
+	rolesCollection := mdb.MDB.Collection(roles.TableName())
+
+	// 构建过滤器
+	filter := bson.M{}
+	if req.Name != "" {
+		filter["name"] = req.Name
+	}
+	if req.Status > 0 {
+		filter["status"] = req.Status
+	}
+
+	// 数据验证
+	if req.Page <= 0 || req.Size <= 0 {
+		return nil, fmt.Errorf("invalid page or size")
+	}
+
+	// 设置分页选项
+	findOptions := options.Find().SetSkip(int64((req.Page - 1) * req.Size)).SetLimit(int64(req.Size))
+
+	// 防御性编程
+	tableName := roles.TableName()
+	if tableName == "" {
+		return nil, fmt.Errorf("invalid table name")
+	}
+
+	cursor, err := rolesCollection.Find(ctx, filter, findOptions)
+	if err != nil {
+		log.Printf("Failed to execute query: %v", err)
+		return nil, err
+	}
+	defer func() {
+		if err := cursor.Close(ctx); err != nil {
+			log.Printf("Failed to close cursor: %v", err)
+		}
+	}()
+
+	var result []entity.RoleResp
+	for cursor.Next(ctx) {
+		var role entity.RoleResp
+		if err := cursor.Decode(&role); err != nil {
+			log.Printf("Failed to decode document: %v", err)
+			return nil, err
+		}
+		result = append(result, role)
+	}
+
+	if err := cursor.Err(); err != nil {
+		log.Printf("Cursor error: %v", err)
+		return nil, err
+	}
+
+	return result, nil
+}
+
+// Add 新增角色
+func (r *Role) Add(ctx context.Context, req entity.RoleAddReq) error {
+	// 验证角色名称是否已存在
+	if r.checkRoleNameExist(req.Name) == false {
+		return fmt.Errorf("角色名称已存在")
+	}
+	// 检查上下文是否有效
+	if ctx.Err() != nil {
+		return ctx.Err()
+	}
+	// 插入新角色记录
+	roles := models.Roles{}
+	insertData := bson.M{}
+	insertData["name"] = req.Name
+	insertData["desc"] = req.Desc
+	insertData["status"] = req.Status
+	insertData["created_at"] = time.Now().Unix()
+	// 确保 Collection 方法不会返回错误
+	collection := mdb.MDB.Collection(roles.TableName())
+	_, insertErr := collection.InsertOne(ctx, req)
+	if insertErr != nil {
+		log.Printf("Failed to insert role: %s", insertErr)
+		return insertErr
+	}
+	return nil
+}
+
+// Update 修改角色
+func (r *Role) Update(ctx context.Context, req entity.RoleUpdateReq) error {
+	// 更新条件
+	objID, err := primitive.ObjectIDFromHex(req.Id)
+	if err != nil {
+		return fmt.Errorf("invalid ObjectID: %v", err)
+	}
+	updateCondition := bson.M{"_id": objID}
+	// 更新内容
+	updateContent := bson.M{
+		"$set": bson.M{
+			"name":   req.Name,
+			"desc":   req.Desc,
+			"status": req.Status,
+		},
+	}
+	// 设置更新选项
+	roles := models.Roles{}
+	collection := mdb.MDB.Collection(roles.TableName())
+	updateOptions := options.Update().SetUpsert(true) // 设置 upsert 选项
+	// 执行更新操作
+	_, err = collection.UpdateOne(context.TODO(), updateCondition, updateContent, updateOptions)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// checkRoleNameExist 检查角色名称是否已存在
+func (r *Role) checkRoleNameExist(name string) bool {
+	// 创建带超时的上下文
+	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+	defer cancel()
+	roles := models.Roles{}
+	collection := mdb.MDB.Collection(roles.TableName())
+
+	// 构建过滤器
+	filter := bson.M{"name": name}
+
+	// 执行查询
+	if err := collection.FindOne(ctx, filter).Err(); err != nil {
+		if errors.Is(err, mongo.ErrNoDocuments) {
+			log.Printf("No document found with role name: %s", name)
+			return true
+		}
+		return false
+	}
+	return false
+}
+
+// Del 删除角色
+func (r *Role) Del(ctx context.Context, req entity.RoleDelReq) error {
+	// 创建带超时的上下文
+	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+	defer cancel()
+	roles := models.Roles{}
+	collection := mdb.MDB.Collection(roles.TableName())
+	id, _ := primitive.ObjectIDFromHex(req.Id)
+	_, err := collection.DeleteOne(ctx, bson.M{"id": id})
+	return err
+}
+
+// AddRoleAccess  添加角色权限
+func (r *Role) AddRoleAccess(ctx context.Context, req entity.RoleAccessAddReq) error {
+	// 检查上下文是否有效
+	if ctx.Err() != nil {
+		return ctx.Err()
+	}
+	// 检查角色是否存在
+	roles := models.Roles{}
+	collection := mdb.MDB.Collection(roles.TableName())
+	roleIDobj, _ := primitive.ObjectIDFromHex(req.RoleId)
+	if err := collection.FindOne(ctx, bson.M{"_id": roleIDobj}).Err(); err != nil {
+		if errors.Is(err, mongo.ErrNoDocuments) {
+			return fmt.Errorf("角色不存在")
+		}
+	}
+	// 检查权限是否存在 ->具体的权限规则表-存放路由、菜单等
+	access := models.Access{}
+	collection = mdb.MDB.Collection(access.TableName())
+	var accessIDS []primitive.ObjectID
+	for _, v := range req.AccessId {
+		accessIDobj, _ := primitive.ObjectIDFromHex(v)
+		accessIDS = append(accessIDS, accessIDobj)
+	}
+	filter := bson.M{"_id": bson.M{"$in": accessIDS}} // 数组查询
+	if err := collection.FindOne(ctx, filter).Err(); err != nil {
+		if errors.Is(err, mongo.ErrNoDocuments) {
+			return fmt.Errorf("权限不存在")
+		}
+	}
+	// 插入新角色权限记录
+	roleAccess := models.RoleAccess{}
+	// 确保 Collection 方法不会返回错误
+	collection = mdb.MDB.Collection(roleAccess.TableName())
+	_, insertErr := collection.UpdateOne(ctx, bson.M{"role_id": req.RoleId}, bson.M{"$addToSet": bson.M{"access_id": bson.M{"$each": req.AccessId}}}, options.Update().SetUpsert(true))
+	if insertErr != nil {
+		log.Printf("Failed to insert role: %s", insertErr)
+		return insertErr
+	}
+	return nil
+}
+
+// UpdateRoleAccess 修改角色权限
+func (r *Role) UpdateRoleAccess(ctx context.Context, req entity.RoleAccessUpdateReq) error {
+	// 验证请求数据的有效性
+	if err := validateConcurrently(ctx, req); err != nil {
+		return err
+	}
+	// 更新角色权限
+	if err := r.updateAccessInDatabase(ctx, req); err != nil {
+		return err
+	}
+	// 返回成功
+	return nil
+}
+
+// DelRoleAccess 根据角色ID删除角色权限
+func (r *Role) DelRoleAccess(ctx context.Context, req entity.RoleAccessDelReq) error {
+	roleAccess := models.RoleAccess{}
+	collection := mdb.MDB.Collection(roleAccess.TableName())
+	filter := bson.M{"role_id": req.RoleId}
+	_, err := collection.DeleteOne(ctx, filter)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// GetRoleAccessList 获取角色权限列表根据角色ID
+func (r *Role) GetRoleAccessList(ctx context.Context, req entity.RoleAccessListReq) ([]*entity.AccessResp, error) {
+	// 查询角色权限列表
+	roleAccess := models.RoleAccess{}
+	collection := mdb.MDB.Collection(roleAccess.TableName())
+	filter := bson.M{"role_id": req.RoleId} // 数组查询
+	cursor, err := collection.Find(ctx, filter)
+	defer cursor.Close(ctx)
+	if err != nil {
+		return nil, err
+	}
+	var accessIDS []string
+	for cursor.Next(ctx) {
+		var roleAccess models.RoleAccess
+		if err := cursor.Decode(&roleAccess); err != nil {
+			log.Printf("Failed to decode document: %v", err)
+			return nil, err
+		}
+		accessIDS = append(accessIDS, roleAccess.AccessID...)
+	}
+
+	// 判断accessIDS是否为空
+	if len(accessIDS) == 0 {
+		return nil, nil
+	}
+
+	// 根据accessIDS查询权限列表 并且按照下级关系组合
+	access := models.Access{}
+	collection = mdb.MDB.Collection(access.TableName())
+	accessFilter := bson.M{"id": bson.M{"$in": accessIDS}}
+	cursor, err = collection.Find(ctx, accessFilter)
+	defer cursor.Close(ctx)
+	if err != nil {
+		return nil, err
+	}
+	var accessList []*entity.AccessResp
+	for cursor.Next(ctx) {
+		var accesss *models.Access
+		if err := cursor.Decode(&accesss); err != nil {
+			log.Printf("Failed to decode document: %v", err)
+			return nil, err
+		}
+		accessList = append(accessList, &entity.AccessResp{
+			ID:          accesss.ID,
+			ActionName:  accesss.ActionName,
+			ModuleName:  accesss.ModuleName,
+			Description: accesss.Description,
+			URL:         accesss.URL,
+			ParentId:    accesss.ParentId,
+			Sort:        accesss.Sort,
+			Type:        accesss.Type,
+			Status:      accesss.Status,
+		})
+	}
+	// 格式化数据并且按照下级关系组合
+	return formatAccessData(accessList), nil
+}
+
+// formatAccessData formats and organizes access data into a hierarchical structure
+func formatAccessData(accessData []*entity.AccessResp) []*entity.AccessResp {
+	nodeMap := make(map[interface{}]*entity.AccessResp)
+	var rootNodes []*entity.AccessResp
+	for i := range accessData {
+		node := accessData[i]
+		nodeMap[node.ID] = node
+	}
+	for i := range accessData {
+		node := accessData[i]
+		if node.ParentId == "0" {
+			rootNodes = append(rootNodes, node)
+		} else {
+			if parentNode, exists := nodeMap[node.ParentId]; exists {
+				parentNode.AccessItem = append(parentNode.AccessItem, node)
+			}
+		}
+	}
+	return rootNodes
+}
+
+// AddAccess 添加权限路由
+func (r *Role) AddAccess(ctx context.Context, req entity.AccessAddReq) error {
+	// 检查上下文是否有效
+	if ctx.Err() != nil {
+		return ctx.Err()
+	}
+	access := models.Access{}
+	collection := mdb.MDB.Collection(access.TableName())
+	// 判断是否有相同的数据
+	filter := bson.M{"path": req.URL}
+	if err := collection.FindOne(ctx, filter).Err(); err == nil {
+		return fmt.Errorf("权限已存在")
+	}
+	// 插入新角色权限记录
+	_, err := collection.InsertOne(ctx, req)
+	return err
+}
+
+// DelAccess 删除权限路由
+func (r *Role) DelAccess(ctx context.Context, req entity.AccessDelReq) error {
+	access := models.Access{}
+	collection := mdb.MDB.Collection(access.TableName())
+	// 判断是否有角色使用了该权限路由
+	roleAccess := models.RoleAccess{}
+	collection = mdb.MDB.Collection(roleAccess.TableName())
+	filter := bson.M{"access_id": bson.M{"$in": req.Id}} // 数组查询
+	if err := collection.FindOne(ctx, filter).Err(); err == nil {
+		return fmt.Errorf("权限已被角色使用,无法删除")
+	}
+	_, err := collection.DeleteOne(ctx, bson.M{"id": req.Id})
+	return err
+}
+
+// UpdateAccess  修改权限路由
+func (r *Role) UpdateAccess(ctx context.Context, req entity.AccessUpdateReq) error {
+	access := models.Access{}
+	collection := mdb.MDB.Collection(access.TableName())
+	// update
+	var updateFields = bson.M{
+		"module_name": req.ModuleName,
+		"action_name": req.ActionName,
+		"url":         req.URL,
+		"type":        req.Type,
+		"description": req.Description,
+		"sort":        req.Sort,
+		"status":      req.Status}
+	// 去掉为空的字段
+	for k, v := range updateFields {
+		switch v.(type) {
+		case string:
+			if v == "" {
+				delete(updateFields, k)
+			}
+		case int:
+			if v == 0 {
+				delete(updateFields, k)
+			}
+		default:
+			continue
+		}
+	}
+	// 检查是否有需要更新的字段
+	if len(updateFields) == 0 {
+		return errors.New("no fields to update")
+	}
+	// 确保 req.Id 是一个有效的 ObjectID
+	objID, err := primitive.ObjectIDFromHex(req.Id)
+	if err != nil {
+		return fmt.Errorf("invalid ObjectID: %v", err)
+	}
+
+	_, err = collection.UpdateByID(ctx, objID, bson.M{"$set": updateFields})
+	if err != nil {
+		return fmt.Errorf("update failed: %v", err)
+	}
+	return err
+}
+
+// ListAccess listAccessa
+func (r *Role) ListAccess(ctx context.Context, req entity.AccessListReq) ([]*entity.AccessResp, error) {
+	access := models.Access{}
+	collection := mdb.MDB.Collection(access.TableName())
+	filter := bson.M{}
+	if req.ActionName != "" {
+		filter["action_name"] = req.ActionName
+	}
+	if req.ModuleName != "" {
+		filter["module_name"] = req.ModuleName
+	}
+	if req.Status != 0 {
+		filter["status"] = req.Status
+	}
+	if req.Type != 0 {
+		filter["type"] = req.Type
+	}
+	if req.ParentId != "" {
+		filter["parent_id"] = req.ParentId
+	}
+	if req.URL != "" {
+		filter["url"] = req.URL
+	}
+	// 数据验证
+	if req.Page <= 0 || req.Size <= 0 {
+		return nil, fmt.Errorf("invalid page or size")
+	}
+	// 设置分页选项
+	findOptions := options.Find().SetSkip(int64((req.Page - 1) * req.Size)).SetLimit(int64(req.Size))
+	cursor, err := collection.Find(ctx, filter, findOptions)
+	defer cursor.Close(ctx)
+	if err != nil {
+		return nil, err
+	}
+	var accessList []*entity.AccessResp
+	for cursor.Next(ctx) {
+		var accesss *models.Access
+		if err := cursor.Decode(&accesss); err != nil {
+			log.Printf("Failed to decode document: %v", err)
+			return nil, err
+		}
+		accessList = append(accessList, &entity.AccessResp{
+			ID:          accesss.ID,
+			ActionName:  accesss.ActionName,
+			ModuleName:  accesss.ModuleName,
+			Description: accesss.Description,
+			URL:         accesss.URL,
+			ParentId:    accesss.ParentId,
+			Sort:        accesss.Sort,
+			Type:        accesss.Type,
+			Status:      accesss.Status,
+		})
+	}
+	// 格式化数据并且按照下级关系组合
+	return formatAccessData(accessList), nil
+}
+
+// updateAccessInDatabase 在数据库中更新角色权限
+func (r *Role) updateAccessInDatabase(ctx context.Context, req entity.RoleAccessUpdateReq) error {
+	// 例如更新角色权限表中的记录
+	roleAccess := models.RoleAccess{}
+	collection := mdb.MDB.Collection(roleAccess.TableName())
+	filter := bson.M{"role_id": req.RoleId}
+	update := bson.M{"$set": bson.M{"access_id": req.AccessId}}
+	_, err := collection.UpdateOne(ctx, filter, update)
+	if err != nil {
+		return err
+	}
+	return nil // 假设更新成功,实际应根据业务逻辑处理
+}
+
+// AdminBindRole 绑定角色
+func (r *Role) AdminBindRole(ctx context.Context, req *entity.AdminBindRoleReq) error {
+	// 例如更新角色权限表中的记录
+	role := models.Roles{}
+	collection := mdb.MDB.Collection(role.TableName())
+	roleId, _ := primitive.ObjectIDFromHex(req.RoleId)
+	filter := bson.M{"_id": roleId, "status": 1}
+	// 判断你是否存在
+	if err := collection.FindOne(ctx, filter).Err(); err != nil {
+		return fmt.Errorf("角色不存在,或者已经被禁用")
+	}
+	// 判断管理员是否存在
+	admin := model.Admin{}
+	collection = mdb.MDB.Collection(admin.TableName())
+	objID, _ := primitive.ObjectIDFromHex(req.AdminId)
+	filter = bson.M{"_id": objID, "status": 1}
+	if err := collection.FindOne(ctx, filter).Err(); err != nil {
+		return fmt.Errorf("管理员不存在 或者 已经被禁用")
+	}
+	// 更新管理员数据
+	_, err := collection.UpdateByID(ctx, objID, bson.M{"$set": bson.M{"role_id": req.RoleId}})
+	if err != nil {
+		return fmt.Errorf("更新管理员失败")
+	}
+	return nil // 假设更新成功,实际应根据业务逻辑处理
+}
+
+// AdminUnBindRole 取消绑定角色
+func (r *Role) AdminUnBindRole(ctx context.Context, req *entity.AdminBindRoleReq) error {
+	// 例如更新角色权限表中的记录
+	admin := model.Admin{}
+	collection := mdb.MDB.Collection(admin.TableName())
+	objID, _ := primitive.ObjectIDFromHex(req.AdminId)
+	filter := bson.M{"_id": objID}
+	if err := collection.FindOne(ctx, filter).Err(); err != nil {
+		return fmt.Errorf("管理员不存在")
+	}
+	// 更新管理员数据
+	_, err := collection.UpdateByID(ctx, objID, bson.M{"$set": bson.M{"role_id": ""}})
+	if err != nil {
+		return fmt.Errorf("更新管理员失败")
+	}
+	return nil
+}
+
+// GetAdminRole GetAdminBindRole 根据角色id 获取Access
+func getAdmin(ctx context.Context, id string) (*model.Admin, error) {
+	objID, err := primitive.ObjectIDFromHex(id)
+	if err != nil {
+		return nil, fmt.Errorf("解析管理员ID失败: %v", err)
+	}
+
+	admin := model.Admin{}
+	adminCollection := mdb.MDB.Collection(admin.TableName())
+	adminFilter := bson.M{"_id": objID}
+	err = adminCollection.FindOne(ctx, adminFilter).Decode(&admin)
+	if err != nil {
+		if errors.Is(err, mongo.ErrNoDocuments) {
+			return nil, fmt.Errorf("找不到管理员")
+		}
+		return nil, fmt.Errorf("查询管理员失败: %v", err)
+	}
+	return &admin, nil
+}
+
+func getRole(ctx context.Context, id string) (*models.Roles, error) {
+	objID, err := primitive.ObjectIDFromHex(id)
+	if err != nil {
+		return nil, fmt.Errorf("解析角色ID失败: %v", err)
+	}
+
+	role := models.Roles{}
+	roleCollection := mdb.MDB.Collection(role.TableName())
+	roleFilter := bson.M{"_id": objID}
+	err = roleCollection.FindOne(ctx, roleFilter).Decode(&role)
+	if err != nil {
+		if errors.Is(err, mongo.ErrNoDocuments) {
+			return nil, fmt.Errorf("找不到角色")
+		}
+		return nil, fmt.Errorf("查询角色失败: %v", err)
+	}
+	return &role, nil
+}
+
+func getRoleAccess(ctx context.Context, roleId string) (*models.RoleAccess, error) {
+	roleAccess := models.RoleAccess{}
+	roleAccessCollection := mdb.MDB.Collection(roleAccess.TableName())
+	roleAccessFilter := bson.M{"role_id": roleId}
+	err := roleAccessCollection.FindOne(ctx, roleAccessFilter).Decode(&roleAccess)
+	if err != nil {
+		if errors.Is(err, mongo.ErrNoDocuments) {
+			return nil, fmt.Errorf("找不到角色权限")
+		}
+		return nil, fmt.Errorf("查询角色权限失败: %v", err)
+	}
+	return &roleAccess, nil
+}
+
+func (r *Role) GetAdminRole(ctx context.Context, req *entity.AdminBindRoleReq) (*entity.AdminBindRoleResp, error) {
+	admin, err := getAdmin(ctx, req.AdminId)
+	if err != nil {
+		return nil, err
+	}
+
+	role, err := getRole(ctx, req.RoleId)
+	if err != nil {
+		return nil, err
+	}
+
+	roleAccess, err := getRoleAccess(ctx, req.RoleId)
+	if err != nil {
+		return nil, err
+	}
+
+	var AccessIds []primitive.ObjectID
+	var invalidAccessIds []string
+	for _, v := range roleAccess.AccessID {
+		objId, err := primitive.ObjectIDFromHex(v)
+		if err != nil {
+			invalidAccessIds = append(invalidAccessIds, v)
+			continue
+		}
+		AccessIds = append(AccessIds, objId)
+	}
+
+	if len(AccessIds) == 0 {
+		if len(invalidAccessIds) > 0 {
+			return nil, fmt.Errorf("无效的权限ID: %v", strings.Join(invalidAccessIds, ", "))
+		}
+		return nil, fmt.Errorf("没有权限")
+	}
+
+	access := models.Access{}
+	collection := mdb.MDB.Collection(access.TableName())
+	filter := bson.M{}
+	filter["_id"] = bson.M{"$in": AccessIds}
+	cursor, err := collection.Find(ctx, filter)
+	defer cursor.Close(ctx)
+	if err != nil {
+		return nil, fmt.Errorf("查询权限失败: %v", err)
+	}
+
+	var accessList []*entity.AccessResp
+	for cursor.Next(ctx) {
+		var accesss *models.Access
+		if err := cursor.Decode(&accesss); err != nil {
+			log.Printf("Failed to decode document: %v", err)
+			return nil, fmt.Errorf("解码权限失败: %v", err)
+		}
+		accessList = append(accessList, &entity.AccessResp{
+			ID:          accesss.ID,
+			ActionName:  accesss.ActionName,
+			ModuleName:  accesss.ModuleName,
+			Description: accesss.Description,
+			URL:         accesss.URL,
+			ParentId:    accesss.ParentId,
+			Sort:        accesss.Sort,
+			Type:        accesss.Type,
+			Status:      accesss.Status,
+		})
+	}
+
+	return &entity.AdminBindRoleResp{
+			AdminId:    req.AdminId,
+			AdminName:  admin.Username,
+			RoleName:   role.Name,
+			RoleId:     req.RoleId,
+			AccessList: formatAccessData(accessList)},
+		nil
+}
+
+// 使用协程和通道并发执行验证操作
+func validateConcurrently(ctx context.Context, req entity.RoleAccessUpdateReq) error {
+	// 创建通道
+	ch := make(chan error, 3)
+
+	// 并发执行验证操作
+	var wg sync.WaitGroup
+	wg.Add(3)
+	go func() {
+		defer wg.Done()
+		ch <- validateRoleExistence(ctx, req)
+	}()
+	go func() {
+		defer wg.Done()
+		ch <- validateAccessExistence(ctx, req)
+	}()
+	go func() {
+		defer wg.Done()
+		ch <- validateRoleAccessExistence(ctx, req)
+	}()
+
+	// 收集所有验证结果
+	var e []error
+	go func() {
+		defer wg.Wait()
+		for i := 0; i < 3; i++ {
+			if err := <-ch; err != nil {
+				e = append(e, err)
+			}
+		}
+		if len(e) > 0 {
+			ch <- fmt.Errorf("验证失败: %v", e)
+		} else {
+			ch <- nil
+		}
+	}()
+
+	// 等待所有并发任务完成
+	select {
+	case err := <-ch:
+		return err
+	case <-ctx.Done():
+		return ctx.Err()
+	}
+}
+
+// 验证角色是否存在
+func validateRoleExistence(ctx context.Context, req entity.RoleAccessUpdateReq) error {
+	roles := models.Roles{}
+	collection := mdb.MDB.Collection(roles.TableName())
+	if err := collection.FindOne(ctx, bson.M{"id": req.RoleId}).Err(); err != nil {
+		if errors.Is(err, mongo.ErrNoDocuments) {
+			return fmt.Errorf("角色不存在")
+		}
+		return err
+	}
+	return nil
+}
+
+// 验证权限是否存在
+func validateAccessExistence(ctx context.Context, req entity.RoleAccessUpdateReq) error {
+	access := models.Access{}
+	collection := mdb.MDB.Collection(access.TableName())
+	filter := bson.M{"id": bson.M{"$in": req.AccessId}} // 数组查询
+	if err := collection.FindOne(ctx, filter).Err(); err != nil {
+		if errors.Is(err, mongo.ErrNoDocuments) {
+			return fmt.Errorf("权限不存在")
+		}
+		return err
+	}
+	return nil
+}
+
+// 验证角色权限是否已存在
+func validateRoleAccessExistence(ctx context.Context, req entity.RoleAccessUpdateReq) error {
+	roleAccess := models.RoleAccess{}
+	collection := mdb.MDB.Collection(roleAccess.TableName())
+	filter := bson.M{"role_id": req.RoleId}
+	if err := collection.FindOne(ctx, filter).Err(); err != nil {
+		if errors.Is(err, mongo.ErrNoDocuments) {
+			return fmt.Errorf("角色权限不存在 不能更新")
+		}
+		return err
+	}
+	return nil
+}

+ 3 - 6
game/game_cluster/nodes/webadmin/service/synthesis.go

@@ -2,7 +2,6 @@ package service
 
 import (
 	"context"
-	"fmt"
 	"math"
 	"time"
 
@@ -174,10 +173,8 @@ func (s *Synthesis) WithdrawalStatus(req *entity.UserWithdrawalStatus) error {
 	// 设置更新选项
 	updateOptions := options.Update().SetUpsert(true) // 设置 upsert 选项
 	// 执行更新操作
-	result, err := collection.UpdateOne(context.TODO(), updateCondition, updateContent, updateOptions)
+	_, err := collection.UpdateOne(context.TODO(), updateCondition, updateContent, updateOptions)
 	if err != nil {
-		fmt.Println(result)
-		fmt.Println(err)
 		return err
 	}
 	return nil
@@ -220,14 +217,14 @@ func (s *Synthesis) FindUserCountryCount() ([]*entity.UserCountryResp, error) {
 	// 执行聚合查询
 	cursor, err := collection.Aggregate(context.TODO(), pipeline)
 	if err != nil {
-		panic(err)
+		return nil, err
 	}
 	defer cursor.Close(context.TODO())
 
 	// 遍历查询结果
 	var results []bson.M
 	if err := cursor.All(context.TODO(), &results); err != nil {
-		panic(err)
+		return nil, err
 	}
 	var totalIPCount int64
 	var data []*entity.UserCountryResp

+ 0 - 8
game/game_cluster/nodes/webadmin/web.go

@@ -9,33 +9,25 @@ import (
 	checkCenter "github.com/mhaya/game/game_cluster/internal/component/check_center"
 	"github.com/mhaya/game/game_cluster/internal/data"
 	"github.com/mhaya/game/game_cluster/internal/mdb"
-	mdb2 "github.com/mhaya/game/game_cluster/nodes/webadmin/mdb"
 	"github.com/mhaya/game/game_cluster/nodes/webadmin/router"
 )
 
 func Run(profileFilePath, nodeId string) {
 	// 配置mhaya引擎,加载profile配置文件
 	app := mhaya.Configure(profileFilePath, nodeId, false, mhaya.Cluster)
-
 	// 注册调度组件
 	app.Register(mhayaCron.New())
-
 	// 注册检查中心服是否启动组件
 	app.Register(checkCenter.New())
-
 	// 注册数据配表组件
 	app.Register(data.New())
-
 	// 加载http server组件
 	app.Register(httpServerComponent(app.Address()))
 	// 注册db组件
 	app.Register(mhayaMongo.NewComponent())
-
 	app.AddActors(
 		&mdb.ActorDB{},
 	)
-	mdb2.InitializeMongoDB()
-	// 启动mhaya引擎
 	app.Startup()
 }
 

+ 3 - 0
go.mod

@@ -17,6 +17,9 @@ require (
 )
 
 require (
+	github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect
+	github.com/casbin/casbin/v2 v2.99.0 // indirect
+	github.com/casbin/govaluate v1.2.0 // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/google/go-cmp v0.5.9 // indirect
 	github.com/klauspost/compress v1.17.0 // indirect

+ 13 - 0
go.sum

@@ -1,8 +1,15 @@
 github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU=
 github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
+github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I=
+github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
+github.com/casbin/casbin/v2 v2.99.0 h1:Y993vfRenh8Xtb4XVaK8KeYJTjD4Zn1XVewGszhzk1E=
+github.com/casbin/casbin/v2 v2.99.0/go.mod h1:LO7YPez4dX3LgoTCqSQAleQDo0S0BeZBDxYnPUl95Ng=
+github.com/casbin/govaluate v1.2.0 h1:wXCXFmqyY+1RwiKfYo3jMKyrtZmOL3kHwaqDyCPOYak=
+github.com/casbin/govaluate v1.2.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
 github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
@@ -52,12 +59,18 @@ go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
 go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
 go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
 go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
 golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
 golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=