package models import ( "strings" "time" "github.com/beego/beego/v2/client/orm" ) // Menu 菜单模型 type Menu struct { Id int `orm:"auto"` Name string `orm:"size(100)"` Path string `orm:"size(255)"` ParentId int `orm:"default(0)"` Icon string `orm:"size(100)"` Order int `orm:"default(0)"` Status int8 `orm:"default(1)"` ComponentPath string `orm:"size(500);null"` IsExternal int8 `orm:"default(0)"` ExternalUrl string `orm:"size(1000);null"` MenuType int8 `orm:"default(1)"` Permission string `orm:"size(200);null"` CreateTime time.Time `orm:"auto_now_add;type(datetime)"` UpdateTime time.Time `orm:"auto_now;type(datetime)"` DeleteTime *time.Time `orm:"null;type(datetime)"` } // TableName 设置表名 func (m *Menu) TableName() string { return "yz_menus" } // GetAllMenus 获取所有菜单(未删除的) func GetAllMenus() ([]map[string]interface{}, error) { o := orm.NewOrm() var menus []*Menu _, err := o.QueryTable("yz_menus").Filter("delete_time__isnull", true).All(&menus) if err != nil { return nil, err } result := make([]map[string]interface{}, 0, len(menus)) for _, m := range menus { item := map[string]interface{}{ "id": m.Id, "name": m.Name, "path": m.Path, "parentId": m.ParentId, "icon": m.Icon, "order": m.Order, "status": m.Status, "componentPath": m.ComponentPath, "isExternal": m.IsExternal, "externalUrl": m.ExternalUrl, "menuType": m.MenuType, } result = append(result, item) } return result, nil } // AddMenu 添加新菜单 func AddMenu(menu *Menu) (int64, error) { o := orm.NewOrm() id, err := o.Insert(menu) return id, err } // UpdateMenu 更新菜单 func UpdateMenu(menu *Menu) error { o := orm.NewOrm() _, err := o.Update(menu) return err } // UpdateMenuStatus 更新菜单状态 func UpdateMenuStatus(id int, status int8) error { o := orm.NewOrm() menu := Menu{Id: id} if err := o.Read(&menu); err != nil { return err } menu.Status = status _, err := o.Update(&menu, "Status") return err } // DeleteMenu 删除菜单(软删除) func DeleteMenu(id int) error { o := orm.NewOrm() menu := Menu{Id: id} if err := o.Read(&menu); err != nil { return err } now := time.Now() menu.DeleteTime = &now _, err := o.Update(&menu, "DeleteTime") return err } // GetTenantMenus 根据角色ID获取租户菜单(只返回该角色有权限的菜单,且只返回页面菜单menu_type=1) // 注意:会自动包含所有父菜单,即使父菜单不在权限列表中 func GetTenantMenus(roleId int) ([]map[string]interface{}, error) { o := orm.NewOrm() // 如果角色ID为0或无效,返回空列表 if roleId <= 0 { return []map[string]interface{}{}, nil } // 1. 从yz_roles表的menu_ids JSON字段获取该角色的所有菜单ID menuIds, err := GetRoleMenus(roleId) if err != nil { return nil, err } // 如果没有权限,返回空列表 if len(menuIds) == 0 { return []map[string]interface{}{}, nil } // 2. 构建IN查询的占位符 placeholders := make([]string, len(menuIds)) args := make([]interface{}, len(menuIds)+1) for i, id := range menuIds { placeholders[i] = "?" args[i] = id } args[len(menuIds)] = 1 // menu_type=1 表示页面菜单 // 3. 查询菜单(只返回menu_type=1的页面菜单,且未删除的) query := "SELECT id, name, path, parent_id, icon, `order`, status, component_path, is_external, external_url, menu_type, permission " + "FROM yz_menus " + "WHERE id IN (" + strings.Join(placeholders, ",") + ") " + "AND delete_time IS NULL " + "AND menu_type = ? " + "ORDER BY `order`, id" var menus []*Menu _, err = o.Raw(query, args...).QueryRows(&menus) if err != nil { return nil, err } // 4. 收集所有需要查询的父菜单ID(递归查找所有父菜单) parentIds := make(map[int]bool) var findParents func(pid int) findParents = func(pid int) { if pid == 0 || parentIds[pid] { return } parentIds[pid] = true // 查询父菜单 var parentMenu Menu err := o.Raw("SELECT id, parent_id FROM yz_menus WHERE id = ? AND delete_time IS NULL AND menu_type = 1", pid).QueryRow(&parentMenu.Id, &parentMenu.ParentId) if err == nil && parentMenu.Id > 0 { // 继续查找父菜单的父菜单 if parentMenu.ParentId > 0 { findParents(parentMenu.ParentId) } } } // 为每个菜单查找其父菜单 for _, m := range menus { if m.ParentId > 0 { findParents(m.ParentId) } } // 5. 如果存在父菜单,查询所有父菜单 if len(parentIds) > 0 { parentIdList := make([]int, 0, len(parentIds)) for pid := range parentIds { parentIdList = append(parentIdList, pid) } // 构建父菜单查询 parentPlaceholders := make([]string, len(parentIdList)) parentArgs := make([]interface{}, len(parentIdList)+1) for i, id := range parentIdList { parentPlaceholders[i] = "?" parentArgs[i] = id } parentArgs[len(parentIdList)] = 1 // menu_type=1 parentQuery := "SELECT id, name, path, parent_id, icon, `order`, status, component_path, is_external, external_url, menu_type, permission " + "FROM yz_menus " + "WHERE id IN (" + strings.Join(parentPlaceholders, ",") + ") " + "AND delete_time IS NULL " + "AND menu_type = ? " + "ORDER BY `order`, id" var parentMenus []*Menu _, err = o.Raw(parentQuery, parentArgs...).QueryRows(&parentMenus) if err == nil && len(parentMenus) > 0 { // 将父菜单添加到结果中(去重) menuMap := make(map[int]*Menu) for _, m := range menus { menuMap[m.Id] = m } for _, pm := range parentMenus { if _, exists := menuMap[pm.Id]; !exists { menus = append(menus, pm) menuMap[pm.Id] = pm } } } } // 6. 转换为map格式 result := make([]map[string]interface{}, 0, len(menus)) for _, m := range menus { item := map[string]interface{}{ "id": m.Id, "name": m.Name, "path": m.Path, "parentId": m.ParentId, "icon": m.Icon, "order": m.Order, "status": m.Status, "componentPath": m.ComponentPath, "isExternal": m.IsExternal, "externalUrl": m.ExternalUrl, "menuType": m.MenuType, "permission": m.Permission, } result = append(result, item) } return result, nil }