239 lines
6.5 KiB
Go
239 lines
6.5 KiB
Go
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"`
|
||
IsShow int8 `orm:"default(1)"`
|
||
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,
|
||
"permission": m.Permission,
|
||
"isShow": m.IsShow,
|
||
}
|
||
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, is_show " +
|
||
"FROM yz_menus " +
|
||
"WHERE id IN (" + strings.Join(placeholders, ",") + ") " +
|
||
"AND delete_time IS NULL " +
|
||
"AND menu_type = ? " +
|
||
"AND is_show = 1 " +
|
||
"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, is_show " +
|
||
"FROM yz_menus " +
|
||
"WHERE id IN (" + strings.Join(parentPlaceholders, ",") + ") " +
|
||
"AND delete_time IS NULL " +
|
||
"AND menu_type = ? " +
|
||
"AND is_show = 1 " +
|
||
"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,
|
||
"isShow": m.IsShow,
|
||
}
|
||
result = append(result, item)
|
||
}
|
||
|
||
return result, nil
|
||
}
|