Jelajahi Sumber

后台管理用户角色支持导航菜单权限分配&各环境管理后台切换&服务部署修改

huwei 5 bulan lalu
induk
melakukan
2fd9ffdf21

TEMPAT SAMPAH
server/cadmin


+ 33 - 0
server/config/database.go

@@ -19,12 +19,14 @@ var (
 	LDB      *gorm.DB
 	GDB1     *gorm.DB
 	GDBGroup map[int]*gorm.DB
+	AdminDB  *gorm.DB
 )
 
 func InitDatabase() {
 	initDefaultDB()
 	initGraveDB()
 	initLoginDB()
+	initAdminDB()
 }
 
 func initDefaultDB() {
@@ -58,6 +60,37 @@ func initDefaultDB() {
 	DB = db
 }
 
+func initAdminDB() {
+	connString := os.Getenv("ADMIN_MYSQL_DSN")
+	newLogger := logger.New(
+		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
+		logger.Config{
+			SlowThreshold:             time.Second, // Slow SQL threshold
+			LogLevel:                  logger.Info, // Log level(这里记得根据需求改一下)
+			IgnoreRecordNotFoundError: true,        // Ignore ErrRecordNotFound error for logger
+			Colorful:                  false,       // Disable color
+		},
+	)
+
+	db, err := gorm.Open(mysql.Open(connString), &gorm.Config{
+		Logger:                 newLogger,
+		SkipDefaultTransaction: true,
+	})
+
+	if connString == "" || err != nil {
+		logrus.Fatalf("mysql lost: %v", err)
+	}
+	sqlDB, err := db.DB()
+	if err != nil {
+		logrus.Fatalf("mysql lost: %v", err)
+	}
+
+	sqlDB.SetMaxIdleConns(10)
+	sqlDB.SetMaxOpenConns(20)
+	sqlDB.SetConnMaxLifetime(2 * time.Hour)
+	AdminDB = db
+}
+
 func initGraveDB() {
 	GDBGroup = make(map[int]*gorm.DB)
 

+ 1 - 1
server/config/permissions.go

@@ -180,7 +180,7 @@ func ValidityAuth(roleId int64, method, path string) (err error) {
 		return errors.New("当前登录用户角色信息异常,请退出重新登录")
 	}
 
-	rdb := query.Use(DB).AdminRole
+	rdb := query.Use(AdminDB).AdminRole
 	result, err := rdb.Where(rdb.ID.Eq(roleId)).First()
 	if err != nil {
 		logrus.Warnf("AdminRole... err:%+v", err)

+ 30 - 1
server/internal/admin/api/admin_role.go

@@ -48,10 +48,39 @@ func AdminRoleAuthOption(c *gin.Context) {
 	c.JSON(200, serializer.Suc(lists))
 }
 
+func AdminRolePageOption(c *gin.Context) {
+	var (
+		lists []*forms.TreeOption
+	)
+	menuList, err := GetRoleMenuList(c)
+	if err != nil {
+		c.JSON(200, ErrorResponse(err))
+		return
+	}
+	for _, item := range menuList {
+		menu := &forms.TreeOption{
+			Key:      item.Id,
+			Label:    item.Meta.Title,
+			Children: []*forms.TreeOption{},
+		}
+		if len(item.Children) > 0 {
+			for _, children := range item.Children {
+				menu.Children = append(menu.Children, &forms.TreeOption{
+					Key:   children.Id,
+					Label: children.Meta.Title,
+				})
+			}
+		}
+		lists = append(lists, menu)
+	}
+
+	c.JSON(200, serializer.Suc(lists))
+}
+
 // AdminRoleOption 角色选项
 func AdminRoleOption(c *gin.Context) {
 	var (
-		q     = query.Use(config.DB).AdminRole
+		q     = query.Use(config.AdminDB).AdminRole
 		m     = q.WithContext(c)
 		lists []*model.AdminRole
 		list  []forms.Option

+ 227 - 14
server/internal/admin/api/menu.go

@@ -1,19 +1,125 @@
 package api
 
 import (
+	"context"
 	"gadmin/config"
+	"gadmin/internal/admin/forms"
 	"gadmin/internal/admin/service"
+	"gadmin/internal/gorm/query"
+	"gadmin/utility/character"
 	"gadmin/utility/serializer"
 	"github.com/gin-gonic/gin"
+	"github.com/sirupsen/logrus"
 	"os"
+	"sort"
+	"strings"
+)
+
+type (
+	Map = map[string]interface{}
 )
 
 func MenuDynamic(c *gin.Context) {
 
-	type (
-		Map = map[string]interface{}
-	)
+	list, err := GetRoleMenuList(c)
+	if err != nil {
+		c.JSON(200, ErrorResponse(err))
+		return
+	}
+	c.JSON(200, serializer.Suc(list, "获取成功"))
+	return
+}
+
+func GetRoleMenuList(c *gin.Context) ([]*forms.Menu, error) {
+	//lists := GetMenuList(c)
+	lists, err := service.Menu.GetMenuList()
+	if err != nil {
+		return nil, err
+	}
+	t := c.GetHeader("authorization")
+	for _, item := range lists {
+		if strings.Contains(item.Name, "{access-token}") {
+			item.Name = strings.ReplaceAll(item.Name, "{access-token}", t)
+		}
+		if len(item.Children) > 0 {
+			for _, children := range item.Children {
+				if strings.Contains(children.Name, "{access-token}") {
+					children.Name = strings.ReplaceAll(children.Name, "{access-token}", t)
+				}
+			}
+		}
+	}
+	// 获取角色可查看的页面
+	roleId, _ := c.Get("admin_role_id")
+
+	// 超管查看所有页面
+	if config.IsSuperRole(roleId.(int64)) {
+		return lists, nil
+	}
+	var rolePages []int32
+	rdb := query.Use(config.DB).AdminRoleMenu
+	m := rdb.WithContext(context.Background())
+	err = m.Where(rdb.RoleID.Eq(int32(roleId.(int64)))).Pluck(rdb.PageID, &rolePages)
+	if err != nil {
+		logrus.Error("AdminRole... err:%+v", err)
+		return nil, err
+	}
+	newList := make([]*forms.Menu, 0)
+	if len(rolePages) == 0 { // 没有配置权限默认全部
+		newList = lists
+	} else {
+		tmpPages := make(map[int32]*forms.Menu)
 
+		for _, item := range lists {
+			if character.InSlice(rolePages, item.Id) {
+				tmpPages[item.Id] = &forms.Menu{
+					Id:        item.Id,
+					Component: item.Component,
+					Meta:      item.Meta,
+					Name:      item.Name,
+					Path:      item.Name,
+					Redirect:  item.Redirect,
+					Children:  []*forms.Menu{},
+				}
+			}
+			if len(item.Children) > 0 {
+				for _, children := range item.Children {
+					if !character.InSlice(rolePages, children.Id) {
+						continue
+					}
+					if _, ok2 := tmpPages[item.Id]; ok2 {
+						tmpPages[item.Id].Children = append(tmpPages[item.Id].Children, children)
+					} else {
+						tmpPages[item.Id] = &forms.Menu{
+							Id:        item.Id,
+							Component: item.Component,
+							Meta:      item.Meta,
+							Name:      item.Name,
+							Path:      item.Name,
+							Redirect:  item.Redirect,
+							Children:  []*forms.Menu{children},
+						}
+					}
+				}
+			}
+		}
+
+		for _, item := range tmpPages {
+			sort.Slice(item.Children, func(i, j int) bool {
+				return item.Children[i].Meta.Sort < item.Children[j].Meta.Sort
+			})
+			newList = append(newList, item)
+		}
+	}
+
+	// 排序
+	sort.Slice(newList, func(i, j int) bool {
+		return newList[i].Meta.Sort < newList[j].Meta.Sort
+	})
+	return newList, nil
+}
+
+func GetMenuList(c *gin.Context) []Map {
 	var (
 		lists       []Map
 		localHidden = true // 本地显示的菜单
@@ -25,6 +131,7 @@ func MenuDynamic(c *gin.Context) {
 
 	// 控制台
 	lists = append(lists, Map{
+		"id":        1,
 		"path":      "/dashboard",
 		"name":      "Dashboard",
 		"component": "LAYOUT",
@@ -35,6 +142,7 @@ func MenuDynamic(c *gin.Context) {
 		},
 		"children": []Map{
 			{
+				"id":        1001,
 				"path":      "console",
 				"name":      "dashboard_console",
 				"component": "/dashboard/console/console",
@@ -47,6 +155,7 @@ func MenuDynamic(c *gin.Context) {
 
 	// 玩家管理
 	lists = append(lists, Map{
+		"id":        2,
 		"path":      "/account",
 		"name":      "Account",
 		"component": "LAYOUT",
@@ -58,6 +167,7 @@ func MenuDynamic(c *gin.Context) {
 		},
 		"children": []Map{
 			{
+				"id":        2001,
 				"path":      "account-list",
 				"name":      "account-list",
 				"component": "/account/accountList/index",
@@ -66,6 +176,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        2002,
 				"path":      "account-info/:id?",
 				"name":      "account-info",
 				"component": "/account/accountList/info",
@@ -76,6 +187,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        2003,
 				"path":      "account-search",
 				"name":      "account-search",
 				"component": "/account/accountList/search",
@@ -153,6 +265,7 @@ func MenuDynamic(c *gin.Context) {
 	if config.IsSuperRole(service.User.GetUserRoleId(c)) {
 		// 权限管理
 		lists = append(lists, Map{
+			"id":        3,
 			"path":      "/permission",
 			"name":      "Permission",
 			"component": "LAYOUT",
@@ -163,15 +276,17 @@ func MenuDynamic(c *gin.Context) {
 				"sort":  1,
 			},
 			"children": []Map{
-				//{
-				//	"path":      "menu",
-				//	"name":      "permission_menu",
-				//	"component": "/permission/menu/menu",
-				//	"meta": Map{
-				//		"title": "菜单权限",
-				//	},
-				//},
 				{
+					"id":        3003,
+					"path":      "menu",
+					"name":      "permission_menu",
+					"component": "/permission/menu/menu",
+					"meta": Map{
+						"title": "菜单权限",
+					},
+				},
+				{
+					"id":        3001,
 					"path":      "user",
 					"name":      "permission_user",
 					"component": "/permission/user/user",
@@ -180,6 +295,7 @@ func MenuDynamic(c *gin.Context) {
 					},
 				},
 				{
+					"id":        3002,
 					"path":      "role",
 					"name":      "permission_role",
 					"component": "/permission/role/role",
@@ -193,6 +309,7 @@ func MenuDynamic(c *gin.Context) {
 
 	// 充值管理
 	/*lists = append(lists, Map{
+		"id":        4,
 		"path":      "/recharge",
 		"name":      "Recharge",
 		"component": "LAYOUT",
@@ -204,6 +321,7 @@ func MenuDynamic(c *gin.Context) {
 		},
 		"children": []Map{
 			{
+				"id":        4001,
 				"path":      "recharge-list",
 				"name":      "recharge-list",
 				"component": "/recharge/rechargeList/index",
@@ -212,6 +330,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        4002,
 				"path":      "recharge-dailyStatistics",
 				"name":      "recharge-dailyStatistics",
 				"component": "/recharge/dailyStatistics/index",
@@ -220,6 +339,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        4003,
 				"path":      "recharge-ordersSettle",
 				"name":      "recharge-ordersSettle",
 				"component": "/recharge/ordersSettle/index",
@@ -229,6 +349,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        4004,
 				"path":      "recharge-abnormalOrder",
 				"name":      "recharge-abnormalOrder",
 				"component": "/recharge/abnormalOrder/index",
@@ -242,6 +363,7 @@ func MenuDynamic(c *gin.Context) {
 
 	// 排行榜
 	/*lists = append(lists, Map{
+		"id":        5,
 		"path":      "/ranking",
 		"name":      "Ranking",
 		"component": "LAYOUT",
@@ -253,6 +375,7 @@ func MenuDynamic(c *gin.Context) {
 		},
 		"children": []Map{
 			{
+				"id":        5001,
 				"path":      "recharge-ranking",
 				"name":      "recharge-ranking",
 				"component": "/ranking/recharge/index",
@@ -261,6 +384,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        5002,
 				"path":      "diamond-ranking",
 				"name":      "diamond-ranking",
 				"component": "/ranking/diamond/index",
@@ -269,6 +393,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        5003,
 				"path":      "level-ranking",
 				"name":      "level-ranking",
 				"component": "/ranking/level/index",
@@ -277,6 +402,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        5004,
 				"path":      "elrank-ranking",
 				"name":      "elrank-ranking",
 				"component": "/ranking/elrank/index",
@@ -285,6 +411,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        5005,
 				"path":      "duel-ranking",
 				"name":      "duel-ranking",
 				"component": "/ranking/duel/index",
@@ -293,6 +420,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        5006,
 				"path":      "gudong-ranking",
 				"name":      "gudong-ranking",
 				"component": "/ranking/gudong/index",
@@ -301,6 +429,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        5007,
 				"path":      "idiom-ranking",
 				"name":      "idiom-ranking",
 				"component": "/ranking/idiom/index",
@@ -309,6 +438,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        5008,
 				"path":      "boss-ranking",
 				"name":      "boss-ranking",
 				"component": "/ranking/boss/index",
@@ -317,6 +447,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        5009,
 				"path":      "adv-ranking",
 				"name":      "adv-ranking",
 				"component": "/ranking/adv/index",
@@ -325,6 +456,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        5010,
 				"path":      "login-ranking",
 				"name":      "login-ranking",
 				"component": "/ranking/login/index",
@@ -337,6 +469,7 @@ func MenuDynamic(c *gin.Context) {
 
 	// 数据统计
 	/*lists = append(lists, Map{
+		"id":        6,
 		"path":      "/echarts",
 		"name":      "Echarts",
 		"component": "LAYOUT",
@@ -348,6 +481,7 @@ func MenuDynamic(c *gin.Context) {
 		},
 		"children": []Map{
 			{
+				"id":        6001,
 				"path":      "login-echarts",
 				"name":      "login-echarts",
 				"component": "/echarts/login/index",
@@ -356,6 +490,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        6002,
 				"path":      "chapter-echarts",
 				"name":      "chapter-echarts",
 				"component": "/echarts/chapter/index",
@@ -364,6 +499,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        6003,
 				"path":      "basic-echarts",
 				"name":      "basic-echarts",
 				"component": "/echarts/basic/index",
@@ -372,6 +508,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        6004,
 				"path":      "adv-echarts",
 				"name":      "adv-echarts",
 				"component": "/echarts/adv/index",
@@ -380,6 +517,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        6005,
 				"path":      "echarts-tests",
 				"name":      "echarts-tests",
 				"component": "/echarts/adv/index2",
@@ -389,6 +527,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        6006,
 				"path":      "goods-echarts",
 				"name":      "goods-echarts",
 				"component": "/echarts/goods/index",
@@ -397,6 +536,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        6007,
 				"path":      "gudong-echarts",
 				"name":      "gudong-echarts",
 				"component": "/echarts/gudong/index",
@@ -405,6 +545,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        6008,
 				"path":      "duel-echarts",
 				"name":      "duel-echarts",
 				"component": "/echarts/duel/index",
@@ -413,6 +554,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        6009,
 				"path":      "expedition-echarts",
 				"name":      "expedition-echarts",
 				"component": "/echarts/expedition/index",
@@ -421,6 +563,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        6010,
 				"path":      "idiom-echarts",
 				"name":      "idiom-echarts",
 				"component": "/echarts/idiom/index",
@@ -429,6 +572,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        6011,
 				"path":      "boss-echarts",
 				"name":      "boss-echarts",
 				"component": "/echarts/boss/index",
@@ -437,6 +581,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        6012,
 				"path":      "seven-echarts",
 				"name":      "seven-echarts",
 				"component": "/echarts/seven/index",
@@ -445,6 +590,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        6013,
 				"path":      "disconnect-echarts",
 				"name":      "disconnect-echarts",
 				"component": "/echarts/disconnect/index",
@@ -453,6 +599,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        6014,
 				"path":      "gem-echarts",
 				"name":      "gem-echarts",
 				"component": "/echarts/gem/index",
@@ -461,6 +608,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        6015,
 				"path":      "limitgift-echarts",
 				"name":      "limitgift-echarts",
 				"component": "/echarts/limitgift/index",
@@ -469,6 +617,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        6016,
 				"path":      "treasure-echarts",
 				"name":      "treasure-echarts",
 				"component": "/echarts/treasure/index",
@@ -477,6 +626,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        6017,
 				"path":      "grandmaster-echarts",
 				"name":      "grandmaster-echarts",
 				"component": "/echarts/grandmaster/index",
@@ -485,6 +635,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        6018,
 				"path":      "gradeDistribution-echarts",
 				"name":      "gradeDistribution-echarts",
 				"component": "/echarts/gradeDistribution/index",
@@ -493,6 +644,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        6019,
 				"path":      "roles-echarts",
 				"name":      "roles-echarts",
 				"component": "/echarts/roles/index",
@@ -501,6 +653,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        6020,
 				"path":      "heroLevelDistribution-echarts",
 				"name":      "heroLevelDistribution-echarts",
 				"component": "/echarts/heroLevelDistribution/index",
@@ -509,6 +662,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        6021,
 				"path":      "levelOutput-echarts",
 				"name":      "levelOutput-echarts",
 				"component": "/echarts/levelOutput/index",
@@ -521,6 +675,7 @@ func MenuDynamic(c *gin.Context) {
 
 	gameToolMap := make([]Map, 0)
 	gameToolMap = append(gameToolMap, Map{
+		"id":        7001,
 		"path":      "config",
 		"name":      "system_config",
 		"component": "/system/config/config",
@@ -528,6 +683,7 @@ func MenuDynamic(c *gin.Context) {
 			"title": "服务配置",
 		},
 	}, Map{
+		"id":        7002,
 		"path":      "deploy",
 		"name":      "system_deploy",
 		"component": "/deploy/index",
@@ -558,6 +714,7 @@ func MenuDynamic(c *gin.Context) {
 
 	// 游戏工具
 	lists = append(lists, Map{
+		"id":        7,
 		"path":      "/tool",
 		"name":      "Tool",
 		"component": "LAYOUT",
@@ -572,6 +729,7 @@ func MenuDynamic(c *gin.Context) {
 
 	// 邮件通知
 	/*lists = append(lists, Map{
+		"id":        8,
 		"path":      "/email",
 		"name":      "email",
 		"component": "LAYOUT",
@@ -584,6 +742,7 @@ func MenuDynamic(c *gin.Context) {
 		},
 		"children": []Map{
 			{
+				"id":        8001,
 				"path":      "index",
 				"name":      "email_index",
 				"component": "/email/index",
@@ -596,6 +755,7 @@ func MenuDynamic(c *gin.Context) {
 
 	// 邮件通知
 	/*lists = append(lists, Map{
+		"id":        9,
 		"path":      "/Mail",
 		"name":      "mail",
 		"component": "LAYOUT",
@@ -608,6 +768,7 @@ func MenuDynamic(c *gin.Context) {
 		},
 		"children": []Map{
 			{
+				"id":        9001,
 				"path":      "index",
 				"name":      "mail_index",
 				"component": "/mail/index",
@@ -620,6 +781,7 @@ func MenuDynamic(c *gin.Context) {
 
 	// 广播通知
 	/*lists = append(lists, Map{
+		"id":        10,
 		"path":      "/notice",
 		"name":      "notice",
 		"component": "LAYOUT",
@@ -633,6 +795,7 @@ func MenuDynamic(c *gin.Context) {
 		},
 		"children": []Map{
 			{
+				"id":        10001,
 				"path":      "noticev2_index", // ?
 				"name":      "noticev2_index",
 				"component": "/noticev2/index",
@@ -654,6 +817,7 @@ func MenuDynamic(c *gin.Context) {
 	})*/
 	// 客服记录
 	/*lists = append(lists, Map{
+		"id":        11,
 		"path":      "/chatLog",
 		"name":      "ChatLog",
 		"component": "LAYOUT",
@@ -665,6 +829,7 @@ func MenuDynamic(c *gin.Context) {
 		},
 		"children": []Map{
 			{
+				"id":        11001,
 				"path":      "chatLog-index",
 				"name":      "chatLog-index",
 				"component": "/chatLog/index",
@@ -676,6 +841,7 @@ func MenuDynamic(c *gin.Context) {
 	})*/
 	// 兑换码
 	/*lists = append(lists, Map{
+		"id":        12,
 		"path":      "/cdk",
 		"name":      "cdk",
 		"component": "LAYOUT",
@@ -689,6 +855,7 @@ func MenuDynamic(c *gin.Context) {
 		},
 		"children": []Map{
 			{
+				"id":        12001,
 				"path":      "index",
 				"name":      "cdk_index",
 				"component": "/cdk/index",
@@ -698,6 +865,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        12002,
 				"path":      "cdk-redeemCodeList/:sn?",
 				"name":      "cdk-redeemCodeList",
 				"component": "/cdk/redeemCodeList",
@@ -712,6 +880,7 @@ func MenuDynamic(c *gin.Context) {
 
 	// 设置页面
 	lists = append(lists, Map{
+		"id":        13,
 		"path":      "/setting",
 		"name":      "Setting",
 		"component": "LAYOUT",
@@ -724,6 +893,7 @@ func MenuDynamic(c *gin.Context) {
 		"hidden": false,
 		"children": []Map{
 			{
+				"id":        13001,
 				"path":      "account",
 				"name":      "setting-account",
 				"component": "/setting/account/account",
@@ -740,6 +910,7 @@ func MenuDynamic(c *gin.Context) {
 			//	},
 			//},
 			{
+				"id":        13002,
 				"path":      "log",
 				"name":      "log-index",
 				"component": "/log/index",
@@ -748,6 +919,7 @@ func MenuDynamic(c *gin.Context) {
 				},
 			},
 			{
+				"id":        13003,
 				"path":      "log-view/:id?",
 				"name":      "log-view",
 				"component": "/log/view",
@@ -759,10 +931,53 @@ func MenuDynamic(c *gin.Context) {
 			},
 		},
 	})
+	t := c.GetHeader("authorization")
+	// 管理后台切换
+	lists = append(lists, Map{
+		"id":        14,
+		"path":      "/server_select",
+		"name":      "ServerSelect",
+		"component": "LAYOUT",
+		"meta": Map{
+			"icon":  "ServerOutline",
+			"title": "管理后台切换",
+			"sort":  5,
+		},
+		"children": []Map{
+			{
+				"id":        14001,
+				"path":      "/redirect",
+				"name":      "http://101.43.249.6:7004/gadmin/?access-token=%s" + t,
+				"component": "LAYOUT",
+				"meta": Map{
+					"title": "魔君测试服",
+				},
+			},
+			{
+				"id":        14002,
+				"path":      "/redirect",
+				"name":      "http://101.43.249.6:7006/cadmin/?access-token=" + t,
+				"component": "LAYOUT",
+				"meta": Map{
+					"title": "空之契约测试服",
+				},
+			},
+			{
+				"id":        14003,
+				"path":      "/redirect",
+				"name":      "http://192.168.0.186:8253/gadmin/?access-token=" + t,
+				"component": "LAYOUT",
+				"meta": Map{
+					"title": "魔君本地",
+				},
+			},
+		},
+	})
 
 	// 文档
 	if localHidden == false {
 		lists = append(lists, Map{
+			"id":        15,
 			"path":      "/external",
 			"name":      "https://www.naiveui.com",
 			"component": "LAYOUT",
@@ -773,8 +988,6 @@ func MenuDynamic(c *gin.Context) {
 			},
 			"children": []Map{},
 		})
-
 	}
-
-	c.JSON(200, serializer.Suc(lists, "获取成功"))
+	return lists
 }

+ 22 - 1
server/internal/admin/forms/admin_role.go

@@ -35,6 +35,7 @@ type AdminRoleListModel struct {
 	Name        string      `gorm:"column:name;not null" json:"name"`                  // 角色名称
 	Key         string      `gorm:"column:key;not null" json:"key"`                    // 角色权限字符串
 	Permissions interface{} `gorm:"column:permissions" json:"permissions"`             // 权限分配
+	Pages       interface{} `gorm:"column:pages" json:"pages"`                         // 页面分配
 	Remark      string      `gorm:"column:remark" json:"remark"`                       // 备注
 	Sort        int32       `gorm:"column:sort;not null" json:"sort"`                  // 排序
 	Status      int32       `gorm:"column:status;not null;default:1" json:"status"`    // 角色状态
@@ -50,9 +51,29 @@ type AdminRoleEditReq struct {
 	Remark      string `gorm:"column:remark" json:"remark"`                    // 备注
 	Sort        int32  `gorm:"column:sort;not null" json:"sort"`               // 排序
 	Status      int32  `gorm:"column:status;not null;default:1" json:"status"` // 角色状态
-	Permissions []int  ` json:"permissions"`                                   // 权限分配
+	Permissions []int  `json:"permissions"`                                    // 权限分配
+	Pages       []int  `json:"pages"`                                          // 页面分配
 }
 
 type AdminRoleReq struct {
 	ID int64 `json:"id" form:"id"`
 }
+
+type Menu struct {
+	Id        int32     `json:"id"`
+	Component string    `json:"component"`
+	Meta      *MenuMeta `json:"meta"`
+	Name      string    `json:"name"`
+	Path      string    `json:"path"`
+	Redirect  string    `json:"redirect"`
+	Children  []*Menu   `json:"children"`
+}
+
+type MenuMeta struct {
+	Icon       string `json:"icon"`
+	Sort       int32  `json:"sort"`
+	Title      string `json:"title"`
+	Hidden     bool   `json:"hidden,omitempty"`
+	ActiveMenu string `json:"activeMenu,omitempty"`
+	IsRoot     bool   `json:"isRoot,omitempty"`
+}

+ 2 - 0
server/internal/admin/forms/deploy.go

@@ -62,6 +62,8 @@ type DeployListReq struct {
 	ContainerName string   `json:"container_name" form:"container_name"`
 	Name          string   `json:"name" form:"name"`
 	ServerType    []string `json:"server_type[]" form:"server_type[]"`
+	RunStatus     []string `json:"run_status[]" form:"run_status[]"`
+	DeployStatus  []string `json:"deploy_status[]" form:"deploy_status[]"`
 }
 
 func (req *DeployListReq) Check() error {

+ 5 - 2
server/internal/admin/middleware/permission.go

@@ -13,7 +13,7 @@ import (
 func Permission() gin.HandlerFunc {
 	return func(c *gin.Context) {
 
-		q := query.Use(config.DB).AdminUser
+		q := query.Use(config.AdminDB).AdminUser
 
 		userId := token.GetUID(c)
 		if userId <= 0 {
@@ -27,18 +27,21 @@ func Permission() gin.HandlerFunc {
 		if err != nil {
 			c.JSON(200, serializer.Err(consts.CodeNoPermission, err.Error(), err))
 			c.Abort()
+			return
 		}
 
 		if models == nil {
 			c.JSON(200, serializer.Err(consts.CodeNoPermission, "用户不存在", nil))
 			c.Abort()
+			return
 		}
 
 		if models.Status != 1 {
 			c.JSON(200, serializer.Err(consts.CodeCheckLogin, "账号已被禁用", nil))
 			c.Abort()
+			return
 		}
-
+		c.Set("admin_role_id", int64(models.RoleID))
 		if models.UserName != "mojun" {
 			if err := config.ValidityAuth(int64(models.RoleID), c.Request.Method, c.Request.URL.Path); err != nil {
 				c.JSON(200, serializer.Err(consts.CodeNoPermission, err.Error(), err))

+ 1 - 0
server/internal/admin/server/router.go

@@ -175,6 +175,7 @@ func NewEngine() *gin.Engine {
 			admin := auth.Group("admin")
 			admin.GET("roleList", api.AdminRoleList)             // 角色列表
 			admin.GET("roleAuthOption", api.AdminRoleAuthOption) // 角色权限选项
+			admin.GET("rolePageOption", api.AdminRolePageOption) // 角色可查看页面选项
 			admin.POST("roleEdit", api.AdminRoleEdit)            // 角色修改/创建
 			admin.GET("roleOption", api.AdminRoleOption)         // 角色选项
 			admin.GET("userList", api.AdminUserList)             // 用户列表

+ 91 - 0
server/internal/admin/service/admin_menu.go

@@ -0,0 +1,91 @@
+package service
+
+import (
+	"context"
+	"gadmin/config"
+	"gadmin/internal/admin/forms"
+	"gadmin/internal/gorm/model"
+	"gadmin/internal/gorm/query"
+	"github.com/sirupsen/logrus"
+	"os"
+	"sort"
+)
+
+var Menu = NewAMenu()
+
+type aMenu struct{}
+
+func NewAMenu() *aMenu {
+	return &aMenu{}
+}
+
+func (s *aMenu) GetMenuList() ([]*forms.Menu, error) {
+	q := query.Use(config.DB).AdminMenu
+	m := q.WithContext(context.Background())
+	m = m.Where(q.Disable.Eq(0)).Order(q.Sort)
+	if os.Getenv("ADMIN_IS_LOCAL") != "1" {
+		m = m.Where(q.LocalShow.Eq(0))
+	}
+	menus, err := m.Find()
+	if err != nil {
+		logrus.Error(err)
+		return nil, err
+	}
+	retMenus := handleMenus(menus)
+	return retMenus, nil
+}
+
+func handleMenus(menus []*model.AdminMenu) []*forms.Menu {
+	menuMap := make(map[int32]*forms.Menu, 0)
+	for _, menu := range menus {
+		item := &forms.Menu{
+			Id:        menu.ID,
+			Component: menu.Component,
+			Meta: &forms.MenuMeta{
+				Icon:       menu.Icon,
+				Sort:       menu.Sort,
+				Title:      menu.Title,
+				Hidden:     menu.Hidden == 1,
+				ActiveMenu: menu.ActiveMenu,
+				IsRoot:     menu.IsRoot == 1,
+			},
+			Name:     menu.Name,
+			Path:     menu.Path,
+			Redirect: menu.Redirect,
+			Children: []*forms.Menu{},
+		}
+
+		if menu.ParentID == 0 {
+			if _, ok := menuMap[menu.ID]; ok {
+				menuMap[menu.ID].Id = menu.ID
+				menuMap[menu.ID].Component = menu.Component
+				menuMap[menu.ID].Meta = item.Meta
+				menuMap[menu.ID].Name = menu.Name
+				menuMap[menu.ID].Path = menu.Path
+				menuMap[menu.ID].Redirect = menu.Redirect
+			} else {
+				menuMap[menu.ID] = item
+			}
+		} else {
+			if _, ok := menuMap[menu.ParentID]; ok {
+				menuMap[menu.ParentID].Children = append(menuMap[menu.ParentID].Children, item)
+			} else {
+				menuMap[menu.ParentID] = &forms.Menu{
+					Id:   menu.ParentID,
+					Meta: &forms.MenuMeta{},
+					Children: []*forms.Menu{
+						item,
+					},
+				}
+			}
+		}
+	}
+	retMenus := make([]*forms.Menu, 0, len(menuMap))
+	for _, menu := range menuMap {
+		retMenus = append(retMenus, menu)
+	}
+	sort.Slice(retMenus, func(i, j int) bool {
+		return retMenus[i].Meta.Sort < retMenus[j].Meta.Sort
+	})
+	return retMenus
+}

+ 38 - 5
server/internal/admin/service/admin_role.go

@@ -1,6 +1,7 @@
 package service
 
 import (
+	"context"
 	"encoding/json"
 	"errors"
 	"gadmin/config"
@@ -23,8 +24,10 @@ type sAdminRole struct{}
 
 func (s *sAdminRole) List(ctx *gin.Context, req forms.AdminRoleListReq) serializer.Response {
 	var (
-		q            = query.Use(config.DB).AdminRole
+		q            = query.Use(config.AdminDB).AdminRole
 		m            = q.WithContext(ctx)
+		mq           = query.Use(config.DB).AdminRoleMenu
+		mm           = mq.WithContext(context.Background())
 		offset int64 = 0
 		models forms.UserAccountListRes
 		lists  []*forms.AdminRoleListModel
@@ -47,6 +50,11 @@ func (s *sAdminRole) List(ctx *gin.Context, req forms.AdminRoleListReq) serializ
 
 	for _, v := range lists {
 		err = json.Unmarshal([]byte(cast.ToString(v.Permissions)), &v.Permissions)
+		pages := make([]int64, 0)
+		if err := mm.Where(mq.RoleID.Eq(int32(v.ID))).Pluck(mq.PageID, &pages); err != nil {
+			return serializer.Err(consts.CodeParamErr, "查询出错 pages", err)
+		}
+		v.Pages = pages
 	}
 
 	models.List = lists
@@ -58,7 +66,9 @@ func (s *sAdminRole) List(ctx *gin.Context, req forms.AdminRoleListReq) serializ
 }
 
 func (s *sAdminRole) Edit(ctx *gin.Context, req forms.AdminRoleEditReq) serializer.Response {
-	q := query.Use(config.DB).AdminRole
+	q := query.Use(config.AdminDB).AdminRole
+	mq := query.Use(config.DB).AdminRoleMenu
+	m := mq.WithContext(context.Background())
 
 	logrus.Warnf("req:%+v", req)
 
@@ -66,6 +76,13 @@ func (s *sAdminRole) Edit(ctx *gin.Context, req forms.AdminRoleEditReq) serializ
 	if err != nil {
 		return serializer.Err(consts.CodeParamErr, "Marshal err", err)
 	}
+	menusModel := make([]*model.AdminRoleMenu, 0)
+	for _, menu := range req.Pages {
+		menusModel = append(menusModel, &model.AdminRoleMenu{
+			RoleID: int32(req.ID),
+			PageID: int32(menu),
+		})
+	}
 
 	// 修改
 	if req.ID > 0 {
@@ -82,6 +99,14 @@ func (s *sAdminRole) Edit(ctx *gin.Context, req forms.AdminRoleEditReq) serializ
 		if err != nil {
 			return serializer.Err(consts.CodeParamErr, "更新出错", err)
 		}
+		// 删除旧的菜单权限
+		if _, err := m.Where(mq.RoleID.Eq(int32(req.ID))).Delete(); err != nil {
+			return serializer.Response{}
+		}
+		// 插入新的菜单权限
+		if err := m.Create(menusModel...); err != nil {
+			return serializer.Response{}
+		}
 		return serializer.Suc(nil)
 	}
 
@@ -96,8 +121,16 @@ func (s *sAdminRole) Edit(ctx *gin.Context, req forms.AdminRoleEditReq) serializ
 		UpdatedAt:   time.Now(),
 		CreatedAt:   time.Now(),
 	}
-
-	if err := query.Use(config.DB).AdminRole.WithContext(ctx).Create(create); err != nil {
+	if err := query.Use(config.AdminDB).AdminRole.WithContext(ctx).Create(create); err != nil {
+		logrus.Error(err)
+		return serializer.DBErr(err.Error(), err)
+	}
+	// 插入新的菜单权限
+	for _, item := range menusModel {
+		item.RoleID = int32(create.ID)
+	}
+	if err := m.Create(menusModel...); err != nil {
+		logrus.Error(err)
 		return serializer.DBErr(err.Error(), err)
 	}
 
@@ -106,7 +139,7 @@ func (s *sAdminRole) Edit(ctx *gin.Context, req forms.AdminRoleEditReq) serializ
 
 func (s *sAdminRole) GetRole(ctx *gin.Context, req forms.AdminRoleReq) (*model.AdminRole, error) {
 	var (
-		q = query.Use(config.DB).AdminRole
+		q = query.Use(config.AdminDB).AdminRole
 		m = q.WithContext(ctx)
 	)
 	result, err := m.Where(q.ID.Eq(req.ID)).First()

+ 8 - 8
server/internal/admin/service/admin_user.go

@@ -108,7 +108,7 @@ func (s *sUser) Login(req forms.UserLoginReq, ip string) serializer.Response {
 		return serializer.ParamErr("账号已被禁止登录", nil)
 	}
 
-	if err := config.DB.Where("user_name = ?", req.UserName).First(&u).Error; err != nil {
+	if err := config.AdminDB.Where("user_name = ?", req.UserName).First(&u).Error; err != nil {
 		s.AddFailNum(ip)
 		logrus.Warnf("sUser %v Login req error %v.", req.UserName, ip)
 		return serializer.ParamErr("账号错误或不存在,请检查", nil)
@@ -198,8 +198,8 @@ func (s *sUser) Register(req forms.UserRegisterReq) serializer.Response {
 
 func (s *sUser) List(ctx *gin.Context, req forms.AdminUserListReq) serializer.Response {
 	var (
-		q            = query.Use(config.DB).AdminUser
-		r            = query.Use(config.DB).AdminRole
+		q            = query.Use(config.AdminDB).AdminUser
+		r            = query.Use(config.AdminDB).AdminRole
 		m            = q.WithContext(ctx)
 		offset int64 = 0
 		models forms.UserAccountListRes
@@ -242,7 +242,7 @@ func (s *sUser) List(ctx *gin.Context, req forms.AdminUserListReq) serializer.Re
 }
 
 func (s *sUser) Edit(ctx *gin.Context, req forms.AdminUserEditReq) serializer.Response {
-	q := query.Use(config.DB).AdminUser
+	q := query.Use(config.AdminDB).AdminUser
 
 	logrus.Warnf("sUser Edit req:%+v", req)
 
@@ -295,7 +295,7 @@ func (s *sUser) Edit(ctx *gin.Context, req forms.AdminUserEditReq) serializer.Re
 		CreatedAt:      time.Now(),
 	}
 
-	if err = query.Use(config.DB).AdminUser.WithContext(ctx).Create(create); err != nil {
+	if err = query.Use(config.AdminDB).AdminUser.WithContext(ctx).Create(create); err != nil {
 		return serializer.DBErr(err.Error(), err)
 	}
 
@@ -303,7 +303,7 @@ func (s *sUser) Edit(ctx *gin.Context, req forms.AdminUserEditReq) serializer.Re
 }
 
 func (s *sUser) ResetPassword(ctx *gin.Context, req forms.AdminUserResetPasswordReq) serializer.Response {
-	q := query.Use(config.DB).AdminUser
+	q := query.Use(config.AdminDB).AdminUser
 
 	logrus.Warnf("sUser ResetPassword req:%+v", req)
 
@@ -337,7 +337,7 @@ func (s *sUser) ResetPassword(ctx *gin.Context, req forms.AdminUserResetPassword
 }
 
 func (s *sUser) UpdatePassword(ctx *gin.Context, req forms.AdminUserUpdatePasswordReq) serializer.Response {
-	q := query.Use(config.DB).AdminUser
+	q := query.Use(config.AdminDB).AdminUser
 
 	logrus.Warnf("sUser UpdatePassword req:%+v", req)
 
@@ -381,7 +381,7 @@ func (s *sUser) UpdatePassword(ctx *gin.Context, req forms.AdminUserUpdatePasswo
 }
 
 func (s *sUser) GetUserInfo(c *gin.Context) (*model.AdminUser, error) {
-	q := query.Use(config.DB).AdminUser
+	q := query.Use(config.AdminDB).AdminUser
 
 	userId := token.GetUID(c)
 	if userId <= 0 {

+ 36 - 3
server/internal/admin/service/deploy.go

@@ -17,6 +17,7 @@ import (
 	"gadmin/utility/serializer"
 	"gadmin/utility/token"
 	"os"
+	"strconv"
 	"strings"
 	"time"
 
@@ -484,7 +485,8 @@ func (s *sDeploy) List(ctx *gin.Context, req forms.DeployListReq) serializer.Res
 	}
 
 	if count > 0 {
-		if err = m.Limit(int(req.PerPage)).Offset(int(offset)).Scan(&lists); err != nil {
+		//if err = m.Limit(int(req.PerPage)).Offset(int(offset)).Scan(&lists); err != nil {
+		if err = m.Scan(&lists); err != nil {
 			return serializer.Err(consts.CodeParamErr, "查询出错 lists", err)
 		}
 	}
@@ -593,10 +595,41 @@ func (s *sDeploy) List(ctx *gin.Context, req forms.DeployListReq) serializer.Res
 	//
 	//	lists[k].DeployStatus = s.getLastDeployStatus(ctx, v.ID)
 	//}
-	models.List = lists
+	newList1 := make([]forms.DeployListData, 0)
+	if len(req.RunStatus) > 0 {
+		for _, item := range lists {
+			if character.InSlice(req.RunStatus, strconv.Itoa(int(item.RunStatus))) {
+				newList1 = append(newList1, item)
+			}
+		}
+	} else {
+		newList1 = lists
+	}
+
+	newList2 := make([]forms.DeployListData, 0)
+	if len(req.DeployStatus) > 0 {
+		for _, item := range newList1 {
+			if character.InSlice(req.DeployStatus, strconv.Itoa(int(item.DeployStatus))) {
+				newList2 = append(newList2, item)
+			}
+		}
+	} else {
+		newList2 = newList1
+	}
+	pageCount := int64(len(newList2))
+	pageList := make([]forms.DeployListData, 0)
+	if offset+req.PerPage <= pageCount-1 {
+		pageList = newList2[offset : req.PerPage+offset]
+	} else if offset+req.PerPage > pageCount-1 && offset <= pageCount-1 {
+		pageList = newList2[offset:]
+	}
+
+	models.List = pageList
+	//models.List = lists
 	models.Page = req.Page
 	models.PerPage = req.PerPage
-	models.PageCount = (count + req.PerPage - 1) / req.PerPage
+	// todo 分页逻辑处理
+	models.PageCount = (pageCount + req.PerPage - 1) / req.PerPage
 	return serializer.Suc(models)
 }
 

+ 33 - 0
server/internal/gorm/model/admin_menu.gen.go

@@ -0,0 +1,33 @@
+// Code generated by gorm.io/gen. DO NOT EDIT.
+// Code generated by gorm.io/gen. DO NOT EDIT.
+// Code generated by gorm.io/gen. DO NOT EDIT.
+
+package model
+
+const TableNameAdminMenu = "admin_menu"
+
+// AdminMenu mapped from table <admin_menu>
+type AdminMenu struct {
+	ID        int32  `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
+	Path      string `gorm:"column:path" json:"path"`
+	Name      string `gorm:"column:name" json:"name"`
+	Component string `gorm:"column:component" json:"component"`
+	Redirect  string `gorm:"column:redirect" json:"redirect"`
+	Icon      string `gorm:"column:icon" json:"icon"`
+	Title     string `gorm:"column:title" json:"title"`
+	Sort      int32  `gorm:"column:sort" json:"sort"`
+	ActiveMenu      string  `gorm:"column:active_menu" json:"active_menu"`
+	IsRoot    int32   `gorm:"column:is_root" json:"is_root"`
+	ParentID  int32  `gorm:"column:parent_id" json:"parent_id"`
+	Hidden    int32  `gorm:"column:hidden" json:"hidden"`
+	Disable   int32  `gorm:"column:disable;not null" json:"disable"`
+	IsSuper   int32  `gorm:"column:is_super;not null;comment:1只有管理员有查看权限" json:"is_super"` // 1只有管理员有查看权限
+	LocalShow int32  `gorm:"column:local_show;not null;comment:1只在本地展示" json:"local_show"` // 1只在本地展示
+	CreateAt  int32  `gorm:"column:create_at" json:"create_at"`
+	UpdateAt  int32  `gorm:"column:update_at" json:"update_at"`
+}
+
+// TableName AdminMenu's table name
+func (*AdminMenu) TableName() string {
+	return TableNameAdminMenu
+}

+ 19 - 0
server/internal/gorm/model/admin_role_menu.gen.go

@@ -0,0 +1,19 @@
+// Code generated by gorm.io/gen. DO NOT EDIT.
+// Code generated by gorm.io/gen. DO NOT EDIT.
+// Code generated by gorm.io/gen. DO NOT EDIT.
+
+package model
+
+const TableNameAdminRoleMenu = "admin_role_menu"
+
+// AdminRoleMenu mapped from table <admin_role_menu>
+type AdminRoleMenu struct {
+	ID     int32 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
+	RoleID int32 `gorm:"column:role_id" json:"role_id"`
+	PageID int32 `gorm:"column:page_id" json:"page_id"`
+}
+
+// TableName AdminRoleMenu's table name
+func (*AdminRoleMenu) TableName() string {
+	return TableNameAdminRoleMenu
+}

+ 381 - 0
server/internal/gorm/query/admin_menu.gen.go

@@ -0,0 +1,381 @@
+// Code generated by gorm.io/gen. DO NOT EDIT.
+// Code generated by gorm.io/gen. DO NOT EDIT.
+// Code generated by gorm.io/gen. DO NOT EDIT.
+
+package query
+
+import (
+	"context"
+
+	"gorm.io/gorm"
+	"gorm.io/gorm/clause"
+	"gorm.io/gorm/schema"
+
+	"gorm.io/gen"
+	"gorm.io/gen/field"
+
+	"gorm.io/plugin/dbresolver"
+
+	"gadmin/internal/gorm/model"
+)
+
+func newAdminMenu(db *gorm.DB, opts ...gen.DOOption) adminMenu {
+	_adminMenu := adminMenu{}
+
+	_adminMenu.adminMenuDo.UseDB(db, opts...)
+	_adminMenu.adminMenuDo.UseModel(&model.AdminMenu{})
+
+	tableName := _adminMenu.adminMenuDo.TableName()
+	_adminMenu.ALL = field.NewAsterisk(tableName)
+	_adminMenu.ID = field.NewInt32(tableName, "id")
+	_adminMenu.Path = field.NewString(tableName, "path")
+	_adminMenu.Name = field.NewString(tableName, "name")
+	_adminMenu.Component = field.NewString(tableName, "component")
+	_adminMenu.Redirect = field.NewString(tableName, "redirect")
+	_adminMenu.Icon = field.NewString(tableName, "icon")
+	_adminMenu.Title = field.NewString(tableName, "title")
+	_adminMenu.Sort = field.NewInt32(tableName, "sort")
+	_adminMenu.ParentID = field.NewInt32(tableName, "parent_id")
+	_adminMenu.Disable = field.NewInt32(tableName, "disable")
+	_adminMenu.IsSuper = field.NewInt32(tableName, "is_super")
+	_adminMenu.LocalShow = field.NewInt32(tableName, "local_show")
+	_adminMenu.CreateAt = field.NewInt32(tableName, "create_at")
+	_adminMenu.UpdateAt = field.NewInt32(tableName, "update_at")
+
+	_adminMenu.fillFieldMap()
+
+	return _adminMenu
+}
+
+type adminMenu struct {
+	adminMenuDo adminMenuDo
+
+	ALL       field.Asterisk
+	ID        field.Int32
+	Path      field.String
+	Name      field.String
+	Component field.String
+	Redirect  field.String
+	Icon      field.String
+	Title     field.String
+	Sort      field.Int32
+	ParentID  field.Int32
+	Disable   field.Int32
+	IsSuper   field.Int32 // 1只有管理员有查看权限
+	LocalShow field.Int32 // 1只在本地展示
+	CreateAt  field.Int32
+	UpdateAt  field.Int32
+
+	fieldMap map[string]field.Expr
+}
+
+func (a adminMenu) Table(newTableName string) *adminMenu {
+	a.adminMenuDo.UseTable(newTableName)
+	return a.updateTableName(newTableName)
+}
+
+func (a adminMenu) As(alias string) *adminMenu {
+	a.adminMenuDo.DO = *(a.adminMenuDo.As(alias).(*gen.DO))
+	return a.updateTableName(alias)
+}
+
+func (a *adminMenu) updateTableName(table string) *adminMenu {
+	a.ALL = field.NewAsterisk(table)
+	a.ID = field.NewInt32(table, "id")
+	a.Path = field.NewString(table, "path")
+	a.Name = field.NewString(table, "name")
+	a.Component = field.NewString(table, "component")
+	a.Redirect = field.NewString(table, "redirect")
+	a.Icon = field.NewString(table, "icon")
+	a.Title = field.NewString(table, "title")
+	a.Sort = field.NewInt32(table, "sort")
+	a.ParentID = field.NewInt32(table, "parent_id")
+	a.Disable = field.NewInt32(table, "disable")
+	a.IsSuper = field.NewInt32(table, "is_super")
+	a.LocalShow = field.NewInt32(table, "local_show")
+	a.CreateAt = field.NewInt32(table, "create_at")
+	a.UpdateAt = field.NewInt32(table, "update_at")
+
+	a.fillFieldMap()
+
+	return a
+}
+
+func (a *adminMenu) WithContext(ctx context.Context) *adminMenuDo {
+	return a.adminMenuDo.WithContext(ctx)
+}
+
+func (a adminMenu) TableName() string { return a.adminMenuDo.TableName() }
+
+func (a adminMenu) Alias() string { return a.adminMenuDo.Alias() }
+
+func (a adminMenu) Columns(cols ...field.Expr) gen.Columns { return a.adminMenuDo.Columns(cols...) }
+
+func (a *adminMenu) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
+	_f, ok := a.fieldMap[fieldName]
+	if !ok || _f == nil {
+		return nil, false
+	}
+	_oe, ok := _f.(field.OrderExpr)
+	return _oe, ok
+}
+
+func (a *adminMenu) fillFieldMap() {
+	a.fieldMap = make(map[string]field.Expr, 14)
+	a.fieldMap["id"] = a.ID
+	a.fieldMap["path"] = a.Path
+	a.fieldMap["name"] = a.Name
+	a.fieldMap["component"] = a.Component
+	a.fieldMap["redirect"] = a.Redirect
+	a.fieldMap["icon"] = a.Icon
+	a.fieldMap["title"] = a.Title
+	a.fieldMap["sort"] = a.Sort
+	a.fieldMap["parent_id"] = a.ParentID
+	a.fieldMap["disable"] = a.Disable
+	a.fieldMap["is_super"] = a.IsSuper
+	a.fieldMap["local_show"] = a.LocalShow
+	a.fieldMap["create_at"] = a.CreateAt
+	a.fieldMap["update_at"] = a.UpdateAt
+}
+
+func (a adminMenu) clone(db *gorm.DB) adminMenu {
+	a.adminMenuDo.ReplaceConnPool(db.Statement.ConnPool)
+	return a
+}
+
+func (a adminMenu) replaceDB(db *gorm.DB) adminMenu {
+	a.adminMenuDo.ReplaceDB(db)
+	return a
+}
+
+type adminMenuDo struct{ gen.DO }
+
+func (a adminMenuDo) Debug() *adminMenuDo {
+	return a.withDO(a.DO.Debug())
+}
+
+func (a adminMenuDo) WithContext(ctx context.Context) *adminMenuDo {
+	return a.withDO(a.DO.WithContext(ctx))
+}
+
+func (a adminMenuDo) ReadDB() *adminMenuDo {
+	return a.Clauses(dbresolver.Read)
+}
+
+func (a adminMenuDo) WriteDB() *adminMenuDo {
+	return a.Clauses(dbresolver.Write)
+}
+
+func (a adminMenuDo) Session(config *gorm.Session) *adminMenuDo {
+	return a.withDO(a.DO.Session(config))
+}
+
+func (a adminMenuDo) Clauses(conds ...clause.Expression) *adminMenuDo {
+	return a.withDO(a.DO.Clauses(conds...))
+}
+
+func (a adminMenuDo) Returning(value interface{}, columns ...string) *adminMenuDo {
+	return a.withDO(a.DO.Returning(value, columns...))
+}
+
+func (a adminMenuDo) Not(conds ...gen.Condition) *adminMenuDo {
+	return a.withDO(a.DO.Not(conds...))
+}
+
+func (a adminMenuDo) Or(conds ...gen.Condition) *adminMenuDo {
+	return a.withDO(a.DO.Or(conds...))
+}
+
+func (a adminMenuDo) Select(conds ...field.Expr) *adminMenuDo {
+	return a.withDO(a.DO.Select(conds...))
+}
+
+func (a adminMenuDo) Where(conds ...gen.Condition) *adminMenuDo {
+	return a.withDO(a.DO.Where(conds...))
+}
+
+func (a adminMenuDo) Order(conds ...field.Expr) *adminMenuDo {
+	return a.withDO(a.DO.Order(conds...))
+}
+
+func (a adminMenuDo) Distinct(cols ...field.Expr) *adminMenuDo {
+	return a.withDO(a.DO.Distinct(cols...))
+}
+
+func (a adminMenuDo) Omit(cols ...field.Expr) *adminMenuDo {
+	return a.withDO(a.DO.Omit(cols...))
+}
+
+func (a adminMenuDo) Join(table schema.Tabler, on ...field.Expr) *adminMenuDo {
+	return a.withDO(a.DO.Join(table, on...))
+}
+
+func (a adminMenuDo) LeftJoin(table schema.Tabler, on ...field.Expr) *adminMenuDo {
+	return a.withDO(a.DO.LeftJoin(table, on...))
+}
+
+func (a adminMenuDo) RightJoin(table schema.Tabler, on ...field.Expr) *adminMenuDo {
+	return a.withDO(a.DO.RightJoin(table, on...))
+}
+
+func (a adminMenuDo) Group(cols ...field.Expr) *adminMenuDo {
+	return a.withDO(a.DO.Group(cols...))
+}
+
+func (a adminMenuDo) Having(conds ...gen.Condition) *adminMenuDo {
+	return a.withDO(a.DO.Having(conds...))
+}
+
+func (a adminMenuDo) Limit(limit int) *adminMenuDo {
+	return a.withDO(a.DO.Limit(limit))
+}
+
+func (a adminMenuDo) Offset(offset int) *adminMenuDo {
+	return a.withDO(a.DO.Offset(offset))
+}
+
+func (a adminMenuDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *adminMenuDo {
+	return a.withDO(a.DO.Scopes(funcs...))
+}
+
+func (a adminMenuDo) Unscoped() *adminMenuDo {
+	return a.withDO(a.DO.Unscoped())
+}
+
+func (a adminMenuDo) Create(values ...*model.AdminMenu) error {
+	if len(values) == 0 {
+		return nil
+	}
+	return a.DO.Create(values)
+}
+
+func (a adminMenuDo) CreateInBatches(values []*model.AdminMenu, batchSize int) error {
+	return a.DO.CreateInBatches(values, batchSize)
+}
+
+// Save : !!! underlying implementation is different with GORM
+// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
+func (a adminMenuDo) Save(values ...*model.AdminMenu) error {
+	if len(values) == 0 {
+		return nil
+	}
+	return a.DO.Save(values)
+}
+
+func (a adminMenuDo) First() (*model.AdminMenu, error) {
+	if result, err := a.DO.First(); err != nil {
+		return nil, err
+	} else {
+		return result.(*model.AdminMenu), nil
+	}
+}
+
+func (a adminMenuDo) Take() (*model.AdminMenu, error) {
+	if result, err := a.DO.Take(); err != nil {
+		return nil, err
+	} else {
+		return result.(*model.AdminMenu), nil
+	}
+}
+
+func (a adminMenuDo) Last() (*model.AdminMenu, error) {
+	if result, err := a.DO.Last(); err != nil {
+		return nil, err
+	} else {
+		return result.(*model.AdminMenu), nil
+	}
+}
+
+func (a adminMenuDo) Find() ([]*model.AdminMenu, error) {
+	result, err := a.DO.Find()
+	return result.([]*model.AdminMenu), err
+}
+
+func (a adminMenuDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AdminMenu, err error) {
+	buf := make([]*model.AdminMenu, 0, batchSize)
+	err = a.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
+		defer func() { results = append(results, buf...) }()
+		return fc(tx, batch)
+	})
+	return results, err
+}
+
+func (a adminMenuDo) FindInBatches(result *[]*model.AdminMenu, batchSize int, fc func(tx gen.Dao, batch int) error) error {
+	return a.DO.FindInBatches(result, batchSize, fc)
+}
+
+func (a adminMenuDo) Attrs(attrs ...field.AssignExpr) *adminMenuDo {
+	return a.withDO(a.DO.Attrs(attrs...))
+}
+
+func (a adminMenuDo) Assign(attrs ...field.AssignExpr) *adminMenuDo {
+	return a.withDO(a.DO.Assign(attrs...))
+}
+
+func (a adminMenuDo) Joins(fields ...field.RelationField) *adminMenuDo {
+	for _, _f := range fields {
+		a = *a.withDO(a.DO.Joins(_f))
+	}
+	return &a
+}
+
+func (a adminMenuDo) Preload(fields ...field.RelationField) *adminMenuDo {
+	for _, _f := range fields {
+		a = *a.withDO(a.DO.Preload(_f))
+	}
+	return &a
+}
+
+func (a adminMenuDo) FirstOrInit() (*model.AdminMenu, error) {
+	if result, err := a.DO.FirstOrInit(); err != nil {
+		return nil, err
+	} else {
+		return result.(*model.AdminMenu), nil
+	}
+}
+
+func (a adminMenuDo) FirstOrCreate() (*model.AdminMenu, error) {
+	if result, err := a.DO.FirstOrCreate(); err != nil {
+		return nil, err
+	} else {
+		return result.(*model.AdminMenu), nil
+	}
+}
+
+func (a adminMenuDo) FindByPage(offset int, limit int) (result []*model.AdminMenu, count int64, err error) {
+	result, err = a.Offset(offset).Limit(limit).Find()
+	if err != nil {
+		return
+	}
+
+	if size := len(result); 0 < limit && 0 < size && size < limit {
+		count = int64(size + offset)
+		return
+	}
+
+	count, err = a.Offset(-1).Limit(-1).Count()
+	return
+}
+
+func (a adminMenuDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
+	count, err = a.Count()
+	if err != nil {
+		return
+	}
+
+	err = a.Offset(offset).Limit(limit).Scan(result)
+	return
+}
+
+func (a adminMenuDo) Scan(result interface{}) (err error) {
+	return a.DO.Scan(result)
+}
+
+func (a adminMenuDo) Delete(models ...*model.AdminMenu) (result gen.ResultInfo, err error) {
+	return a.DO.Delete(models)
+}
+
+func (a *adminMenuDo) withDO(do gen.Dao) *adminMenuDo {
+	a.DO = *do.(*gen.DO)
+	return a
+}

+ 339 - 0
server/internal/gorm/query/admin_role_menu.gen.go

@@ -0,0 +1,339 @@
+// Code generated by gorm.io/gen. DO NOT EDIT.
+// Code generated by gorm.io/gen. DO NOT EDIT.
+// Code generated by gorm.io/gen. DO NOT EDIT.
+
+package query
+
+import (
+	"context"
+
+	"gorm.io/gorm"
+	"gorm.io/gorm/clause"
+	"gorm.io/gorm/schema"
+
+	"gorm.io/gen"
+	"gorm.io/gen/field"
+
+	"gorm.io/plugin/dbresolver"
+
+	"gadmin/internal/gorm/model"
+)
+
+func newAdminRoleMenu(db *gorm.DB, opts ...gen.DOOption) adminRoleMenu {
+	_adminRoleMenu := adminRoleMenu{}
+
+	_adminRoleMenu.adminRoleMenuDo.UseDB(db, opts...)
+	_adminRoleMenu.adminRoleMenuDo.UseModel(&model.AdminRoleMenu{})
+
+	tableName := _adminRoleMenu.adminRoleMenuDo.TableName()
+	_adminRoleMenu.ALL = field.NewAsterisk(tableName)
+	_adminRoleMenu.ID = field.NewInt32(tableName, "id")
+	_adminRoleMenu.RoleID = field.NewInt32(tableName, "role_id")
+	_adminRoleMenu.PageID = field.NewInt32(tableName, "page_id")
+
+	_adminRoleMenu.fillFieldMap()
+
+	return _adminRoleMenu
+}
+
+type adminRoleMenu struct {
+	adminRoleMenuDo adminRoleMenuDo
+
+	ALL    field.Asterisk
+	ID     field.Int32
+	RoleID field.Int32
+	PageID field.Int32
+
+	fieldMap map[string]field.Expr
+}
+
+func (a adminRoleMenu) Table(newTableName string) *adminRoleMenu {
+	a.adminRoleMenuDo.UseTable(newTableName)
+	return a.updateTableName(newTableName)
+}
+
+func (a adminRoleMenu) As(alias string) *adminRoleMenu {
+	a.adminRoleMenuDo.DO = *(a.adminRoleMenuDo.As(alias).(*gen.DO))
+	return a.updateTableName(alias)
+}
+
+func (a *adminRoleMenu) updateTableName(table string) *adminRoleMenu {
+	a.ALL = field.NewAsterisk(table)
+	a.ID = field.NewInt32(table, "id")
+	a.RoleID = field.NewInt32(table, "role_id")
+	a.PageID = field.NewInt32(table, "page_id")
+
+	a.fillFieldMap()
+
+	return a
+}
+
+func (a *adminRoleMenu) WithContext(ctx context.Context) *adminRoleMenuDo {
+	return a.adminRoleMenuDo.WithContext(ctx)
+}
+
+func (a adminRoleMenu) TableName() string { return a.adminRoleMenuDo.TableName() }
+
+func (a adminRoleMenu) Alias() string { return a.adminRoleMenuDo.Alias() }
+
+func (a adminRoleMenu) Columns(cols ...field.Expr) gen.Columns {
+	return a.adminRoleMenuDo.Columns(cols...)
+}
+
+func (a *adminRoleMenu) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
+	_f, ok := a.fieldMap[fieldName]
+	if !ok || _f == nil {
+		return nil, false
+	}
+	_oe, ok := _f.(field.OrderExpr)
+	return _oe, ok
+}
+
+func (a *adminRoleMenu) fillFieldMap() {
+	a.fieldMap = make(map[string]field.Expr, 3)
+	a.fieldMap["id"] = a.ID
+	a.fieldMap["role_id"] = a.RoleID
+	a.fieldMap["page_id"] = a.PageID
+}
+
+func (a adminRoleMenu) clone(db *gorm.DB) adminRoleMenu {
+	a.adminRoleMenuDo.ReplaceConnPool(db.Statement.ConnPool)
+	return a
+}
+
+func (a adminRoleMenu) replaceDB(db *gorm.DB) adminRoleMenu {
+	a.adminRoleMenuDo.ReplaceDB(db)
+	return a
+}
+
+type adminRoleMenuDo struct{ gen.DO }
+
+func (a adminRoleMenuDo) Debug() *adminRoleMenuDo {
+	return a.withDO(a.DO.Debug())
+}
+
+func (a adminRoleMenuDo) WithContext(ctx context.Context) *adminRoleMenuDo {
+	return a.withDO(a.DO.WithContext(ctx))
+}
+
+func (a adminRoleMenuDo) ReadDB() *adminRoleMenuDo {
+	return a.Clauses(dbresolver.Read)
+}
+
+func (a adminRoleMenuDo) WriteDB() *adminRoleMenuDo {
+	return a.Clauses(dbresolver.Write)
+}
+
+func (a adminRoleMenuDo) Session(config *gorm.Session) *adminRoleMenuDo {
+	return a.withDO(a.DO.Session(config))
+}
+
+func (a adminRoleMenuDo) Clauses(conds ...clause.Expression) *adminRoleMenuDo {
+	return a.withDO(a.DO.Clauses(conds...))
+}
+
+func (a adminRoleMenuDo) Returning(value interface{}, columns ...string) *adminRoleMenuDo {
+	return a.withDO(a.DO.Returning(value, columns...))
+}
+
+func (a adminRoleMenuDo) Not(conds ...gen.Condition) *adminRoleMenuDo {
+	return a.withDO(a.DO.Not(conds...))
+}
+
+func (a adminRoleMenuDo) Or(conds ...gen.Condition) *adminRoleMenuDo {
+	return a.withDO(a.DO.Or(conds...))
+}
+
+func (a adminRoleMenuDo) Select(conds ...field.Expr) *adminRoleMenuDo {
+	return a.withDO(a.DO.Select(conds...))
+}
+
+func (a adminRoleMenuDo) Where(conds ...gen.Condition) *adminRoleMenuDo {
+	return a.withDO(a.DO.Where(conds...))
+}
+
+func (a adminRoleMenuDo) Order(conds ...field.Expr) *adminRoleMenuDo {
+	return a.withDO(a.DO.Order(conds...))
+}
+
+func (a adminRoleMenuDo) Distinct(cols ...field.Expr) *adminRoleMenuDo {
+	return a.withDO(a.DO.Distinct(cols...))
+}
+
+func (a adminRoleMenuDo) Omit(cols ...field.Expr) *adminRoleMenuDo {
+	return a.withDO(a.DO.Omit(cols...))
+}
+
+func (a adminRoleMenuDo) Join(table schema.Tabler, on ...field.Expr) *adminRoleMenuDo {
+	return a.withDO(a.DO.Join(table, on...))
+}
+
+func (a adminRoleMenuDo) LeftJoin(table schema.Tabler, on ...field.Expr) *adminRoleMenuDo {
+	return a.withDO(a.DO.LeftJoin(table, on...))
+}
+
+func (a adminRoleMenuDo) RightJoin(table schema.Tabler, on ...field.Expr) *adminRoleMenuDo {
+	return a.withDO(a.DO.RightJoin(table, on...))
+}
+
+func (a adminRoleMenuDo) Group(cols ...field.Expr) *adminRoleMenuDo {
+	return a.withDO(a.DO.Group(cols...))
+}
+
+func (a adminRoleMenuDo) Having(conds ...gen.Condition) *adminRoleMenuDo {
+	return a.withDO(a.DO.Having(conds...))
+}
+
+func (a adminRoleMenuDo) Limit(limit int) *adminRoleMenuDo {
+	return a.withDO(a.DO.Limit(limit))
+}
+
+func (a adminRoleMenuDo) Offset(offset int) *adminRoleMenuDo {
+	return a.withDO(a.DO.Offset(offset))
+}
+
+func (a adminRoleMenuDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *adminRoleMenuDo {
+	return a.withDO(a.DO.Scopes(funcs...))
+}
+
+func (a adminRoleMenuDo) Unscoped() *adminRoleMenuDo {
+	return a.withDO(a.DO.Unscoped())
+}
+
+func (a adminRoleMenuDo) Create(values ...*model.AdminRoleMenu) error {
+	if len(values) == 0 {
+		return nil
+	}
+	return a.DO.Create(values)
+}
+
+func (a adminRoleMenuDo) CreateInBatches(values []*model.AdminRoleMenu, batchSize int) error {
+	return a.DO.CreateInBatches(values, batchSize)
+}
+
+// Save : !!! underlying implementation is different with GORM
+// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
+func (a adminRoleMenuDo) Save(values ...*model.AdminRoleMenu) error {
+	if len(values) == 0 {
+		return nil
+	}
+	return a.DO.Save(values)
+}
+
+func (a adminRoleMenuDo) First() (*model.AdminRoleMenu, error) {
+	if result, err := a.DO.First(); err != nil {
+		return nil, err
+	} else {
+		return result.(*model.AdminRoleMenu), nil
+	}
+}
+
+func (a adminRoleMenuDo) Take() (*model.AdminRoleMenu, error) {
+	if result, err := a.DO.Take(); err != nil {
+		return nil, err
+	} else {
+		return result.(*model.AdminRoleMenu), nil
+	}
+}
+
+func (a adminRoleMenuDo) Last() (*model.AdminRoleMenu, error) {
+	if result, err := a.DO.Last(); err != nil {
+		return nil, err
+	} else {
+		return result.(*model.AdminRoleMenu), nil
+	}
+}
+
+func (a adminRoleMenuDo) Find() ([]*model.AdminRoleMenu, error) {
+	result, err := a.DO.Find()
+	return result.([]*model.AdminRoleMenu), err
+}
+
+func (a adminRoleMenuDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AdminRoleMenu, err error) {
+	buf := make([]*model.AdminRoleMenu, 0, batchSize)
+	err = a.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
+		defer func() { results = append(results, buf...) }()
+		return fc(tx, batch)
+	})
+	return results, err
+}
+
+func (a adminRoleMenuDo) FindInBatches(result *[]*model.AdminRoleMenu, batchSize int, fc func(tx gen.Dao, batch int) error) error {
+	return a.DO.FindInBatches(result, batchSize, fc)
+}
+
+func (a adminRoleMenuDo) Attrs(attrs ...field.AssignExpr) *adminRoleMenuDo {
+	return a.withDO(a.DO.Attrs(attrs...))
+}
+
+func (a adminRoleMenuDo) Assign(attrs ...field.AssignExpr) *adminRoleMenuDo {
+	return a.withDO(a.DO.Assign(attrs...))
+}
+
+func (a adminRoleMenuDo) Joins(fields ...field.RelationField) *adminRoleMenuDo {
+	for _, _f := range fields {
+		a = *a.withDO(a.DO.Joins(_f))
+	}
+	return &a
+}
+
+func (a adminRoleMenuDo) Preload(fields ...field.RelationField) *adminRoleMenuDo {
+	for _, _f := range fields {
+		a = *a.withDO(a.DO.Preload(_f))
+	}
+	return &a
+}
+
+func (a adminRoleMenuDo) FirstOrInit() (*model.AdminRoleMenu, error) {
+	if result, err := a.DO.FirstOrInit(); err != nil {
+		return nil, err
+	} else {
+		return result.(*model.AdminRoleMenu), nil
+	}
+}
+
+func (a adminRoleMenuDo) FirstOrCreate() (*model.AdminRoleMenu, error) {
+	if result, err := a.DO.FirstOrCreate(); err != nil {
+		return nil, err
+	} else {
+		return result.(*model.AdminRoleMenu), nil
+	}
+}
+
+func (a adminRoleMenuDo) FindByPage(offset int, limit int) (result []*model.AdminRoleMenu, count int64, err error) {
+	result, err = a.Offset(offset).Limit(limit).Find()
+	if err != nil {
+		return
+	}
+
+	if size := len(result); 0 < limit && 0 < size && size < limit {
+		count = int64(size + offset)
+		return
+	}
+
+	count, err = a.Offset(-1).Limit(-1).Count()
+	return
+}
+
+func (a adminRoleMenuDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
+	count, err = a.Count()
+	if err != nil {
+		return
+	}
+
+	err = a.Offset(offset).Limit(limit).Scan(result)
+	return
+}
+
+func (a adminRoleMenuDo) Scan(result interface{}) (err error) {
+	return a.DO.Scan(result)
+}
+
+func (a adminRoleMenuDo) Delete(models ...*model.AdminRoleMenu) (result gen.ResultInfo, err error) {
+	return a.DO.Delete(models)
+}
+
+func (a *adminRoleMenuDo) withDO(do gen.Dao) *adminRoleMenuDo {
+	a.DO = *do.(*gen.DO)
+	return a
+}

+ 12 - 0
server/internal/gorm/query/gen.go

@@ -18,6 +18,8 @@ import (
 func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
 	return &Query{
 		db:                        db,
+		AdminMenu:     newAdminMenu(db, opts...),
+		AdminRoleMenu: newAdminRoleMenu(db, opts...),
 		AdminEmail:                newAdminEmail(db, opts...),
 		AdminLog:                  newAdminLog(db, opts...),
 		AdminNotice:               newAdminNotice(db, opts...),
@@ -145,6 +147,8 @@ func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
 type Query struct {
 	db *gorm.DB
 
+	AdminMenu     adminMenu
+	AdminRoleMenu adminRoleMenu
 	AdminEmail                adminEmail
 	AdminLog                  adminLog
 	AdminNotice               adminNotice
@@ -273,6 +277,8 @@ func (q *Query) Available() bool { return q.db != nil }
 func (q *Query) clone(db *gorm.DB) *Query {
 	return &Query{
 		db:                        db,
+		AdminMenu:     q.AdminMenu.clone(db),
+		AdminRoleMenu: q.AdminRoleMenu.clone(db),
 		AdminEmail:                q.AdminEmail.clone(db),
 		AdminLog:                  q.AdminLog.clone(db),
 		AdminNotice:               q.AdminNotice.clone(db),
@@ -408,6 +414,8 @@ func (q *Query) WriteDB() *Query {
 func (q *Query) ReplaceDB(db *gorm.DB) *Query {
 	return &Query{
 		db:                        db,
+		AdminMenu:     q.AdminMenu.replaceDB(db),
+		AdminRoleMenu: q.AdminRoleMenu.replaceDB(db),
 		AdminEmail:                q.AdminEmail.replaceDB(db),
 		AdminLog:                  q.AdminLog.replaceDB(db),
 		AdminNotice:               q.AdminNotice.replaceDB(db),
@@ -533,6 +541,8 @@ func (q *Query) ReplaceDB(db *gorm.DB) *Query {
 }
 
 type queryCtx struct {
+	AdminMenu     *adminMenuDo
+	AdminRoleMenu *adminRoleMenuDo
 	AdminEmail                *adminEmailDo
 	AdminLog                  *adminLogDo
 	AdminNotice               *adminNoticeDo
@@ -658,6 +668,8 @@ type queryCtx struct {
 
 func (q *Query) WithContext(ctx context.Context) *queryCtx {
 	return &queryCtx{
+		AdminMenu:     q.AdminMenu.WithContext(ctx),
+		AdminRoleMenu: q.AdminRoleMenu.WithContext(ctx),
 		AdminEmail:                q.AdminEmail.WithContext(ctx),
 		AdminLog:                  q.AdminLog.WithContext(ctx),
 		AdminNotice:               q.AdminNotice.WithContext(ctx),

+ 3 - 0
server/local.env

@@ -1,5 +1,8 @@
 # 配置改动都需要在这里进行说明
 
+# 日志服务器的数据库
+ADMIN_MYSQL_DSN="root:123456@(127.0.0.1:3306)/grave_dashboard?charset=utf8mb4&parseTime=True&loc=Local"
+
 # 日志服务器的数据库
 MYSQL_DSN="root:123456@(127.0.0.1:3306)/covenant_dashboard?charset=utf8mb4&parseTime=True&loc=Local"
 

+ 1 - 1
server/utility/character/character.go

@@ -39,7 +39,7 @@ func IsLetterNumber(str string) bool {
 }
 
 // InSlice 元素是否存在于切片中
-func InSlice(slice []string, key string) bool {
+func InSlice[T int | int32 | int64 | string](slice []T, key T) bool {
 	if len(slice) == 0 {
 		return false
 	}

+ 1 - 1
web/.env.development

@@ -1,7 +1,7 @@
 # 只在开发模式中被载入
 VITE_PORT = 8252
 
-VITE_PUBLIC_PATH = /gadmin
+VITE_PUBLIC_PATH = /cadmin
 
 VITE_USE_MOCK = false
 

+ 7 - 0
web/src/api/system/role.ts

@@ -14,6 +14,13 @@ export function RoleAuthOption() {
   });
 }
 
+export function RolePageOption() {
+  return http.request({
+    url: '/admin/rolePageOption',
+    method: 'GET',
+  });
+}
+
 export function RoleEdit(params) {
   return http.request({
     url: '/admin/roleEdit',

+ 17 - 1
web/src/main.ts

@@ -3,9 +3,17 @@ import { createApp } from 'vue';
 import App from './App.vue';
 import router, { setupRouter } from './router';
 import { setupStore } from '@/store';
-import { setupNaive, setupDirectives } from '@/plugins';
+import { setupDirectives, setupNaive } from '@/plugins';
 import { AppProvider } from '@/components/Application';
 import Websocket from '@/utils/websocket';
+import { storage } from '@/utils/Storage';
+import { ACCESS_TOKEN } from '@/store/mutation-types';
+
+function getQueryParams() {
+  const params = new URLSearchParams(window.location.search);
+  // 获取 access-token 的值
+  return params.get('access-token');
+}
 
 async function bootstrap() {
   const appProvider = createApp(AppProvider);
@@ -15,6 +23,14 @@ async function bootstrap() {
   setupDirectives(app);
   setupStore(app);
   appProvider.mount('#appProvider', true);
+
+  // 调用函数获取查询参数
+  const accessToken = getQueryParams();
+  console.log('====accessToken:', accessToken);
+  if (accessToken !== '' && accessToken !== null) {
+    storage.set(ACCESS_TOKEN, accessToken);
+  }
+
   await setupRouter(app);
   await router.isReady();
   const onMessageList: Array<Function> = [];

+ 2 - 0
web/src/router/router-icons.ts

@@ -28,6 +28,7 @@ import {
   HelpCircleOutline,
   TicketOutline,
   ChatboxEllipsesOutline,
+  ServerOutline,
 } from '@vicons/ionicons5';
 
 export const constantRouterIcon = {
@@ -57,4 +58,5 @@ export const constantRouterIcon = {
   ToolOutlined: renderIcon(ToolOutlined),
   HelpCircleOutline: renderIcon(HelpCircleOutline),
   ChatboxEllipsesOutline: renderIcon(ChatboxEllipsesOutline),
+  ServerOutline: renderIcon(ServerOutline),
 };

+ 1 - 1
web/src/views/deploy/columns.ts

@@ -2,7 +2,7 @@ import { h } from 'vue';
 import { NTag } from 'naive-ui';
 import { getStatusName, getStatusTag } from '@/utils/deploy';
 
-const runStatus = {
+export const runStatus = {
   1: '运行中',
   2: '已退出',
   3: '拉取超时',

+ 59 - 3
web/src/views/deploy/index.vue

@@ -219,7 +219,7 @@
     DeployTask,
     DeployStop,
   } from '@/api/deploy/deploy';
-  import { columns } from './columns';
+  import { columns, runStatus } from './columns';
   import { cloneDeep } from 'lodash-es';
   import { PlusOutlined, CodeSandboxOutlined, StopOutlined } from '@vicons/antd';
   import RetrofitModal from './modal/modal.vue';
@@ -335,6 +335,36 @@
     },
   ]);
 
+  const runStatusOptions = ref(
+    Object.entries(runStatus).map(([key, value]) => ({
+      label: value,
+      value: key,
+    }))
+  );
+
+  const deployStatusOptions = ref([
+    {
+      value: 1,
+      label: '等待部署',
+    },
+    {
+      value: 2,
+      label: '部署中',
+    },
+    {
+      value: 3,
+      label: '部署成功',
+    },
+    {
+      value: 4,
+      label: '部署失败',
+    },
+    {
+      value: 5,
+      label: '部署超时',
+    },
+  ]);
+
   const schemas: FormSchema[] = [
     {
       field: 'server_type',
@@ -371,10 +401,36 @@
         },
       },
     },
+    {
+      field: 'run_status',
+      component: 'NSelect',
+      label: '运行状态',
+      componentProps: {
+        multiple: true,
+        placeholder: '请选择',
+        options: runStatusOptions.value,
+        onUpdateValue: (e: any) => {
+          console.log(e);
+        },
+      },
+    },
+    {
+      field: 'deploy_status',
+      component: 'NSelect',
+      label: '部署状态',
+      componentProps: {
+        multiple: true,
+        placeholder: '请选择',
+        options: deployStatusOptions.value,
+        onUpdateValue: (e: any) => {
+          console.log(e);
+        },
+      },
+    },
   ];
 
   const [register, {}] = useForm({
-    gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' },
+    gridProps: { cols: '6' },
     labelWidth: 80,
     schemas,
   });
@@ -662,7 +718,7 @@
     // }
 
     if (value.includes('all') && value.length > 1) {
-      value = value.filter(item => item !== 'all');
+      value = value.filter((item) => item !== 'all');
     }
     formDeployParams.value.deployServ = value;
   }

+ 9 - 2
web/src/views/permission/role/role.vue

@@ -57,6 +57,10 @@
           <n-select multiple v-model:value="formParams.permissions" :options="optionsPermissions" />
         </n-form-item>
 
+        <n-form-item label="页面分配" path="pages">
+          <n-tree-select multiple v-model:value="formParams.pages" :options="optionsPages" />
+        </n-form-item>
+
         <n-form-item label="备注" path="remark">
           <n-input type="textarea" placeholder="请输入备注内容" v-model:value="formParams.remark" />
         </n-form-item>
@@ -91,7 +95,7 @@
   import { reactive, ref, h, onMounted } from 'vue';
   import { useMessage } from 'naive-ui';
   import { BasicTable, TableAction } from '@/components/Table';
-  import { getRoleList, RoleAuthOption, RoleEdit } from '@/api/system/role';
+  import { getRoleList, RoleAuthOption, RoleEdit, RolePageOption } from '@/api/system/role';
   import { columns } from './columns';
   import { PlusOutlined } from '@vicons/antd';
   import { cloneDeep } from 'lodash-es';
@@ -104,12 +108,14 @@
   const formBtnLoading = ref(false);
   const formParams = ref<any>();
   const optionsPermissions = ref<any>();
+  const optionsPages = ref<any>();
 
   const defaultState = {
     id: 0,
     key: '',
     name: '',
-    permissions: '',
+    permissions: [],
+    pages: [],
     remark: '',
     sort: 0,
     status: 1,
@@ -192,6 +198,7 @@
 
   onMounted(async () => {
     optionsPermissions.value = await RoleAuthOption();
+    optionsPages.value = await RolePageOption();
   });
 </script>