yunzer_go/server/models/menu.go
2025-11-13 17:24:59 +08:00

239 lines
6.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}