package models import ( "encoding/json" "errors" "log" "os" "strings" "git.apinb.com/bsm-sdk/core/types" "git.apinb.com/bsm-sdk/core/utils" "gorm.io/gorm" ) // DefaultFilePath 相对进程工作目录,与服务启动时读取配置方式一致 const DefaultFilePath = "etc/menu.json" // File 与 etc/menu_structure.json 根结构一致 type File struct { Menus []Node `json:"menus"` TotalLevel1 int `json:"total_level1"` TotalLevel2 int `json:"total_level2"` } // Node 菜单节点(可嵌套 children) type Node struct { Title string `json:"title"` TitleEn string `json:"title_en"` Code string `json:"code"` Description string `json:"description"` MenuPath string `json:"menu_path"` Type int8 `json:"type"` SortKey int8 `json:"sort_key"` IsWebPage bool `json:"is_web_page"` IsNewTab bool `json:"is_new_tab"` IsFull bool `json:"is_full"` HideMenu bool `json:"hide_menu"` WebURL string `json:"web_url"` Component string `json:"component"` Children []Node `json:"children"` } // Load 读取并解析 path func Load(path string) (*File, error) { raw, err := os.ReadFile(path) if err != nil { return nil, err } var f File if err := json.Unmarshal(raw, &f); err != nil { return nil, err } return &f, nil } func buildPermissions(tx *gorm.DB, appID uint) ([]MgtPermission, error) { mf, err := Load(DefaultFilePath) if err != nil { return nil, err } if len(mf.Menus) == 0 { return nil, errors.New("menu is empty") } var out []MgtPermission if err := walkMenuTree(tx, appID, 0, mf.Menus, &out); err != nil { return nil, err } log.Printf("已从 %s 载入 %d 条权限(含子级)", DefaultFilePath, len(out)) return out, nil } func walkMenuTree(tx *gorm.DB, appID uint, parentID uint, nodes []Node, out *[]MgtPermission) error { for i := range nodes { p, err := upsertMenuPermissionFromJSON(tx, appID, parentID, nodes[i]) if err != nil { return err } *out = append(*out, p) if len(nodes[i].Children) > 0 { if err := walkMenuTree(tx, appID, p.ID, nodes[i].Children, out); err != nil { return err } } } return nil } func upsertMenuPermissionFromJSON(tx *gorm.DB, appID, parentID uint, n Node) (MgtPermission, error) { code := strings.TrimSpace(n.Code) if code == "" { code = "menu_" + strings.ReplaceAll(utils.UUID(), "-", "") } typ := n.Type if typ == 0 { typ = 1 } p := MgtPermission{ Std_IICUDS: types.Std_IICUDS{Identity: utils.UUID(), Status: 1}, Title: n.Title, TitleEn: n.TitleEn, Code: code, Description: n.Description, Appid: appID, ParentID: parentID, MenuPath: n.MenuPath, MenuIcon: "", SortKey: n.SortKey, Type: typ, Component: n.Component, IsWebPage: n.IsWebPage, IsNewTab: n.IsNewTab, IsFull: n.IsFull, HideMenu: n.HideMenu, WebUrl: n.WebURL, } var existingPmn MgtPermission err := tx.Model(&MgtPermission{}).Where("code = ? AND app_id = ?", p.Code, appID).First(&existingPmn).Error if err == gorm.ErrRecordNotFound { if err := tx.Create(&p).Error; err != nil { return p, err } return p, nil } if err != nil { return p, err } p.ID = existingPmn.ID return p, nil } func builtinManagementMenuTemplates() []MgtPermission { return []MgtPermission{ {Title: "系统管理", TitleEn: "System Management", Code: "system:management", Description: "系统管理菜单", MenuPath: "/system", MenuIcon: "setting", SortKey: 1, Type: 1}, {Title: "用户管理", TitleEn: "User Management", Code: "user:management", Description: "用户管理菜单", MenuPath: "/system/user", MenuIcon: "user", SortKey: 2, Type: 1}, {Title: "角色管理", TitleEn: "Role Management", Code: "role:management", Description: "角色管理菜单", MenuPath: "/system/role", MenuIcon: "team", SortKey: 3, Type: 1}, {Title: "权限管理", TitleEn: "Permission Management", Code: "permission:management", Description: "权限管理菜单", MenuPath: "/system/permission", MenuIcon: "safety", SortKey: 4, Type: 1}, {Title: "应用管理", TitleEn: "Application Management", Code: "application:management", Description: "应用管理菜单", MenuPath: "/system/application", MenuIcon: "appstore", SortKey: 5, Type: 1}, {Title: "部门管理", TitleEn: "Department Management", Code: "department:management", Description: "部门管理菜单", MenuPath: "/system/department", MenuIcon: "apartment", SortKey: 6, Type: 1}, } }