menu 模型:
type Menu struct {
Id int `gorm:"primary_key;AUTO_INCREMENT" json:"id"`
Pid int `json:"pid"` // 父级menu
Label string `gorm:"type:varchar(50);not null" json:"label"` // menu名称
Sort int `json:"sort"` // 排序值
Path string `gorm:"type:varchar(30);not null" json:"path"` // 跳转路由
Icon string `gorm:"type:varchar(20);" json:"icon"` // 图标
Component string `gorm:"type:varchar(50);" json:"component"` // 组件路径
}
插入几条记录(下面的icon、component为随意虚构,根据自己的环境对应设置即可):
# 有子菜单的一级菜单
INSERT INTO `menus` VALUES ('1', '0', '用户管理', '1', '/user', 'icon-users', '');
INSERT INTO `menus` VALUES ('2', '0', '实例管理', '1', '/instance', 'icon-instances', '');
# 二级菜单
INSERT INTO `menus` VALUES ('3', '1', '用户列表', '2', 'user', 'icon-user', 'views/user/user/index');
INSERT INTO `menus` VALUES ('4', '1', '角色列表', '2', 'role', 'icon-role', 'views/user/role/index');
INSERT INTO `menus` VALUES ('5', '1', '权限列表', '2', 'permission', 'icon-perm', 'views/user/permission/index');
INSERT INTO `menus` VALUES ('6', '2', '实例列表', '3', 'instance', 'icon-instance', 'views/instance/instance/index');
INSERT INTO `menus` VALUES ('7', '2', '集群列表', '3', 'cluster', 'icon-cluster', 'views/instance/cluster/index');
# 没有子菜单的一级菜单
INSERT INTO `menus` VALUES ('8', '0', '文档', '1', '/opsdoc', 'icon-doc', 'views/doc/index');
注意:如果没有父级菜单,则pid为0.
定义一个序列化数据的结构体:
type TreeList struct {
Id int `json:"id"`
Label string `json:"label"`
Pid int `json:"pid"`
Sort int `json:"sort"`
Path string `json:"path"`
Component string `json:"component"`
Icon string `json:"icon"`
Children []*TreeList `json:"children"`
}
定义一个response结构体,用于构造返回数据:
type DataRes struct {
Data []*TreeList `json:"data"`
}
使用递归的方式构造树形菜单:
/*
递归获取树形菜单
*/
func getMenu(pid int) []*TreeList {
var menu []model.Menu
model.DB().Where("pid = ?", pid).Order("sort").Find(&menu)
treeList := []*TreeList{}
for _, v := range menu {
child := getMenu(v.Id)
node := &TreeList{
Id: v.Id,
Name: v.Name,
Sort: v.Sort,
Route: v.Route,
Pid: v.Pid,
}
node.Children = child
treeList = append(treeList, node)
}
return treeList
}
api方法:
func HandlerMenuListGet(c echo.Context) (err error) {
treeList := getMenu(0)
return c.JSON(200, DataRes{
Data: treeList,
})
}
最后调用接口返回的数据json格式:
{
"data": [
{
"id": 1,
"label": "用户管理",
"pid": 0,
"sort": 1,
"path": "/user",
"component": "",
"icon": "icon-users",
"children": [
{
"id": 3,
"label": "用户列表",
"pid": 1,
"sort": 2,
"path": "user/user",
"component": "views/user/user/index",
"icon": "icon-user",
"children": []
},
{
"id": 4,
"label": "角色列表",
"pid": 1,
"sort": 2,
"path": "user/role",
"component": "views/user/role/index",
"icon": "icon-role",
"children": []
},
{
"id": 5,
"label": "权限列表",
"pid": 1,
"sort": 2,
"path": "user/permission",
"component": "views/user/permission/index",
"icon": "icon-perm",
"children": []
}
]
},
{
"id": 2,
"label": "实例管理",
"pid": 0,
"sort": 1,
"path": "/instance",
"component": "",
"icon": "icon-instances",
"children": [
{
"id": 6,
"label": "实例列表",
"pid": 2,
"sort": 3,
"path": "instance/instance",
"component": "views/instance/instance/index",
"icon": "icon-instance",
"children": []
},
{
"id": 7,
"label": "集群列表",
"pid": 2,
"sort": 3,
"path": "instance/cluster",
"component": "views/instance/cluster/index",
"icon": "icon-cluster",
"children": []
}
]
},
{
"id": 8,
"label": "文档",
"pid": 0,
"sort": 1,
"path": "/opsdoc",
"component": "views/doc/index",
"icon": "icon-doc",
"children": []
}
]
}