package service import ( "cold-delivery/common/actions" dto2 "cold-delivery/common/dto" "cold-delivery/common/global" cModel "cold-delivery/common/model" "encoding/json" "fmt" "gogs.baozhida.cn/zoie/OAuth-core/service" "strings" "github.com/pkg/errors" "gorm.io/gorm" "cold-delivery/app/admin/model" "cold-delivery/app/admin/service/dto" "gogs.baozhida.cn/zoie/OAuth-core/pkg" ) type SysMenu struct { service.Service } // GetPage 获取SysMenu列表 func (e *SysMenu) GetPage(c *dto.SysMenuGetPageReq, menus *[]model.SysMenu) *SysMenu { var menu = make([]model.SysMenu, 0) err := e.getPage(c, &menu).Error if err != nil { _ = e.AddError(global.GetFailedErr) return e } for i := 0; i < len(menu); i++ { if menu[i].ParentId != 0 { continue } menusInfo := SysMenuCall(&menu, menu[i]) *menus = append(*menus, menusInfo) } if len(*menus) == 0 { parentMap, flag := getSysMenuParent(&menu) if flag { for i := 0; i < len(menu); i++ { if parentMap[menu[i].ParentId] { continue } menusInfo := SysMenuCall(&menu, menu[i]) *menus = append(*menus, menusInfo) } } else { for i := 0; i < len(menu); i++ { menusInfo := SysMenuCall(&menu, menu[i]) *menus = append(*menus, menusInfo) } } } return e } // 获取搜索出来的菜单的父菜单 func getSysMenuParent(menuList *[]model.SysMenu) (map[int]bool, bool) { list := *menuList var flag = false var parentMap = map[int]bool{} for j := 0; j < len(list); j++ { parentMap[list[j].ParentId] = false } for j := 0; j < len(list); j++ { if _, ok := parentMap[list[j].Id]; !ok { continue } parentMap[list[j].Id] = true flag = true } return parentMap, flag } // getPage 菜单分页列表 func (e *SysMenu) getPage(c *dto.SysMenuGetPageReq, list *[]model.SysMenu) *SysMenu { var err error var data model.SysMenu var tempList []model.SysMenu err = e.Orm.Model(&data). Scopes(dto2.MakeCondition(c.GetNeedSearch())). Order("id"). Find(&tempList).Error if err != nil { e.Log.Errorf("getSysMenuPage error: %s", err) _ = e.AddError(err) return e } // 获取菜单及其子菜单下ID for _, menu := range tempList { var menuList = make([]model.SysMenu, 0) err = e.Orm.Where("menu_path like ?", menu.MenuPath+"%").Order(fmt.Sprintf("sort %s", c.SortOrder)).Order("id").Find(&menuList).Error *list = append(*list, menuList...) } *list = DeduplicateSysMenu(*list) return e } // Get 获取SysMenu对象 func (e *SysMenu) Get(d *dto.SysMenuGetReq, menuModel *model.SysMenu) *SysMenu { err := e.Orm.First(menuModel, d.GetId()).Error if err != nil { e.Log.Errorf("db error: %s", err) if errors.Is(err, gorm.ErrRecordNotFound) { err = global.GetNotFoundOrNoPermissionErr } else { err = global.GetFailedErr } _ = e.AddError(err) return e } return e } // Insert 创建SysMenu对象 func (e *SysMenu) Insert(c *dto.SysMenuInsertReq) *SysMenu { var err error var data model.SysMenu tx := e.Orm.Begin() defer func() { if err != nil { tx.Rollback() } else { tx.Commit() } }() c.Generate(&data) err = tx.Create(&data).Error if err != nil { e.Log.Errorf("db error: %s", err) _ = e.AddError(global.CreateFailedErr) return e } c.Id = data.Id menuPath, err := e.initPaths(&data) if err != nil { e.Log.Errorf("db error: %s", err) _ = e.AddError(err) return e } err = tx.Model(&data).Where("id = ?", data.Id).Update("menu_path", menuPath).Error if err != nil { e.Log.Errorf("db error: %s", err) _ = e.AddError(global.CreateFailedErr) return e } // 添加菜单后删除角色菜单缓存,防止系统菜单与服务菜单不同步 err = model.DeleteAllRoleMenuCache() if err != nil { e.Log.Errorf("删除角色菜单缓存失败 %s", err) _ = e.AddError(err) return e } return e } func (e *SysMenu) initPaths(menu *model.SysMenu) (menuPath string, err error) { var data model.SysMenu parentMenu := new(model.SysMenu) if menu.ParentId != 0 { e.Orm.Model(&data).First(parentMenu, menu.ParentId) if parentMenu.MenuPath == "" { err = errors.New("父级menu_path异常,请尝试对当前节点父级菜单进行更新操作!") return menuPath, err } menuPath = parentMenu.MenuPath + "/" + pkg.IntToString(menu.Id) } else { menuPath = "/0/" + pkg.IntToString(menu.Id) } return menuPath, nil } // Update 修改SysMenu对象 func (e *SysMenu) Update(c *dto.SysMenuUpdateReq) *SysMenu { var err error tx := e.Orm.Debug().Begin() defer func() { if err != nil { tx.Rollback() } else { tx.Commit() } }() var menuModel = model.SysMenu{} err = tx.First(&menuModel, c.GetId()).Error if err != nil { e.Log.Errorf("db error: %s", err) if errors.Is(err, gorm.ErrRecordNotFound) { err = global.UpdateNotFoundOrNoPermissionErr } else { err = global.UpdateFailedErr } _ = e.AddError(err) return e } oldPath := menuModel.MenuPath oldParentId := menuModel.ParentId c.Generate(&menuModel) // 替换旧的path if c.ParentId != oldParentId { menuPath, err := e.initPaths(&menuModel) if err != nil { e.Log.Errorf("db error: %s", err) _ = e.AddError(err) return e } menuModel.MenuPath = menuPath } // 更新菜单信息 err = tx.Model(&menuModel).Save(&menuModel).Error if err != nil { e.Log.Errorf("db error: %s", err) _ = e.AddError(global.UpdateFailedErr) return e } // 替换旧的path if oldPath != menuModel.MenuPath { var menuList []model.SysMenu tx.Where("menu_path like ?", oldPath+"%").Find(&menuList) for _, v := range menuList { v.MenuPath = strings.Replace(v.MenuPath, oldPath, menuModel.MenuPath, 1) err := tx.Model(&v).Update("menu_path", v.MenuPath).Error if err != nil { e.Log.Errorf("db error: %s", err) _ = e.AddError(global.CreateFailedErr) return e } } } // 修改服务菜单后删除角色菜单缓存,防止系统菜单与服务菜单不同步 err = model.DeleteAllRoleMenuCache() if err != nil { _ = e.AddError(err) return e } return e } // Remove 删除SysMenu func (e *SysMenu) Remove(d *dto.SysMenuDeleteReq) *SysMenu { var err error tx := e.Orm.Begin() defer func() { if err != nil { tx.Rollback() } else { tx.Commit() } }() var menuModel model.SysMenu err = tx.First(&menuModel, d.GetId()).Error if err != nil { e.Log.Errorf("db error: %s", err) if errors.Is(err, gorm.ErrRecordNotFound) { err = global.DeleteNotFoundOrNoPermissionErr } else { err = global.DeleteFailedErr } _ = e.AddError(err) return e } err = e.Orm.Where("menu_path like ?", menuModel.MenuPath+"%").Delete(&model.SysMenu{}).Error if err != nil { e.Log.Errorf("Delete error: %s", err) _ = e.AddError(global.DeleteFailedErr) return e } // 删除服务菜单后删除角色菜单缓存,防止系统菜单与服务菜单不同步 err = model.DeleteAllRoleMenuCache() if err != nil { e.Log.Errorf("删除角色菜单缓存失败 %s", err) _ = e.AddError(err) return e } return e } // GetList 获取菜单数据 func (e *SysMenu) GetList(c *dto.SysMenuGetPageReq, list *[]model.SysMenu) error { var err error var data model.SysMenu err = e.Orm.Model(&data). Scopes( dto2.MakeCondition(c.GetNeedSearch()), ). Find(list).Error if err != nil { e.Log.Errorf("db error: %s", err) return global.GetFailedErr } return nil } // SysMenuCall 构建菜单树 func SysMenuCall(menuList *[]model.SysMenu, menu model.SysMenu) model.SysMenu { list := *menuList min := make([]model.SysMenu, 0) for j := 0; j < len(list); j++ { if menu.Id != list[j].ParentId { continue } mi := model.SysMenu{} mi.Id = list[j].Id mi.Title = list[j].Title mi.Icon = list[j].Icon mi.Path = list[j].Path mi.MenuType = list[j].MenuType mi.Name = list[j].Name mi.ParentId = list[j].ParentId mi.Component = list[j].Component mi.Sort = list[j].Sort mi.Visible = list[j].Visible mi.Redirect = list[j].Redirect mi.CreatedAt = list[j].CreatedAt mi.Children = []model.SysMenu{} if mi.MenuType != cModel.Button { ms := SysMenuCall(menuList, mi) min = append(min, ms) } else { min = append(min, mi) } } menu.Children = min return menu } // DeduplicateSysMenu 菜单列表去重 func DeduplicateSysMenu(list []model.SysMenu) []model.SysMenu { seen := make(map[string]bool) deduplicated := []model.SysMenu{} for _, v := range list { // 将结构体编码为 JSON 字符串 key, err := json.Marshal(v) if err != nil { // 处理错误 continue } // 将 JSON 字符串作为键插入到 map 中 if _, ok := seen[string(key)]; !ok { seen[string(key)] = true deduplicated = append(deduplicated, v) } } return deduplicated } // menuLabelCall 递归构造组织数据 func menuLabelCall(eList *[]model.SysMenu, organ dto.MenuLabel) dto.MenuLabel { list := *eList min := make([]dto.MenuLabel, 0) for j := 0; j < len(list); j++ { if organ.Id != list[j].ParentId { continue } mi := dto.MenuLabel{} mi.Id = list[j].Id mi.Label = list[j].Title mi.Children = []dto.MenuLabel{} if list[j].MenuType != "F" { ms := menuLabelCall(eList, mi) min = append(min, ms) } else { min = append(min, mi) } } if len(min) > 0 { organ.Children = min } else { organ.Children = nil } return organ } // SetLabel 修改角色中 设置菜单基础数据 func (e *SysMenu) SetLabel() (m []dto.MenuLabel, err error) { var list []model.SysMenu err = e.GetList(&dto.SysMenuGetPageReq{}, &list) if err != nil { return } m = make([]dto.MenuLabel, 0) for i := 0; i < len(list); i++ { if list[i].ParentId != 0 { continue } e := dto.MenuLabel{} e.Id = list[i].Id e.Label = list[i].Title menuInfo := menuLabelCall(&list, e) m = append(m, menuInfo) } return } // menuCall 构建菜单树 func menuCall(menuList *[]model.SysMenu, menu model.SysMenu) model.SysMenu { list := *menuList min := make([]model.SysMenu, 0) for j := 0; j < len(list); j++ { if menu.Id != list[j].ParentId { continue } mi := model.SysMenu{} mi.Id = list[j].Id mi.Title = list[j].Title mi.Icon = list[j].Icon mi.Path = list[j].Path mi.MenuType = list[j].MenuType mi.Name = list[j].Name mi.ParentId = list[j].ParentId mi.Component = list[j].Component mi.Sort = list[j].Sort mi.Visible = list[j].Visible mi.CreatedAt = list[j].CreatedAt mi.Children = []model.SysMenu{} ms := menuCall(menuList, mi) min = append(min, ms) } menu.Children = min return menu } // 通过roleName获取菜单列表 func (e *SysMenu) getByRoleName(roleName string) ([]model.SysMenu, error) { var err error data := make([]model.SysMenu, 0) if roleName == "admin" { err = e.Orm.Find(&data).Error } else { roleMenuIds := make([]int, 0) err = e.Orm.Model(&model.SysRoleMenu{}).Select("menu_id").Where("role_key = ? ", roleName).Scan(&roleMenuIds).Error if len(roleMenuIds) > 0 { if err = recursiveSetMenu(e.Orm, roleMenuIds, &data); err != nil { return nil, err } // 菜单id及父id 去重 data = menuDistinct(data) } } return data, err } func recursiveSetMenu(orm *gorm.DB, mIds []int, menus *[]model.SysMenu) error { if len(mIds) == 0 || menus == nil { return nil } var subMenus []model.SysMenu err := orm.Where("id in ?", mIds).Find(&subMenus).Error if err != nil { return err } subIds := make([]int, 0) for _, menu := range subMenus { if menu.ParentId != 0 { subIds = append(subIds, menu.ParentId) } //if menu.MenuType != cModel.Button { // *menus = append(*menus, menu) //} *menus = append(*menus, menu) } return recursiveSetMenu(orm, subIds, menus) } // 去掉重复菜单 func menuDistinct(menuList []model.SysMenu) (result []model.SysMenu) { distinctMap := make(map[int]struct{}, len(menuList)) for _, menu := range menuList { if _, ok := distinctMap[menu.Id]; !ok { distinctMap[menu.Id] = struct{}{} result = append(result, menu) } } return result } // SetMenuRole 获取左侧菜单树使用 func (e *SysMenu) SetMenuRole(roleKey string, userId int, p *actions.DataPermission) (m []model.SysMenu, err error) { // 从缓存获取角色关联的菜单 var cacheKey string if p.DeptId > 0 { //cacheKey = fmt.Sprintf("%s-1-%d", roleKey, userId) cacheKey = fmt.Sprintf("%s-1", roleKey) } else { //cacheKey = fmt.Sprintf("%s-0-%d", roleKey, userId) cacheKey = fmt.Sprintf("%s-0", roleKey) } if err := model.GetRoleMenuCache(cacheKey, &m); err == nil { return m, nil } menus, err := e.getByRoleName(roleKey) if err != nil { return m, global.GetFailedErr } m = make([]model.SysMenu, 0) var menuList []model.SysMenu if p.DeptId == 0 { if roleKey == "admin" { err = e.Orm.Table("sys_menu"). Where("sys_menu.visible = 1 and sys_menu.deleted_at is null and is_dept = 0"). Order("sys_menu.sort"). Order("id"). Scan(&menuList).Error if err != nil { return m, global.GetFailedErr } } else { menuIds := make([]int, 0) for _, menu := range menus { menuIds = append(menuIds, menu.Id) } err = e.Orm.Table("sys_menu"). Where("sys_menu.id in (?) and sys_menu.visible = 1 and sys_menu.deleted_at is null and is_dept = 0", menuIds). Order("sys_menu.sort"). Order("id"). Scan(&menuList).Error if err != nil { return m, global.GetFailedErr } } } else { if roleKey == "admin" { err = e.Orm.Table("sys_menu"). Where("sys_menu.visible = 1 and sys_menu.deleted_at is null"). Order("sys_menu.sort"). Order("id"). Scan(&menuList).Error if err != nil { return m, global.GetFailedErr } } else { menuIds := make([]int, 0) for _, menu := range menus { menuIds = append(menuIds, menu.Id) } err = e.Orm.Table("sys_menu"). Where("sys_menu.id in (?) and sys_menu.visible = 1 and sys_menu.deleted_at is null", menuIds). Order("sys_menu.sort"). Order("id"). Scan(&menuList).Error if err != nil { return m, global.GetFailedErr } } } //sort.Sort(model.SysMenuSlice(menuList)) for i := 0; i < len(menuList); i++ { if menuList[i].ParentId != 0 { continue } menusInfo := menuCall(&menuList, menuList[i]) m = append(m, menusInfo) } // 保存角色菜单到缓存 _ = model.SetRoleMenuCache(cacheKey, m) return } func (e *SysMenu) MenuSelect(roleKey string, userId int, p *actions.DataPermission) (m []model.SysMenu, err error) { menus, err := e.getByRoleName(roleKey) if err != nil { return m, global.GetFailedErr } m = make([]model.SysMenu, 0) var menuList []model.SysMenu if p.DeptId == 0 { if roleKey == "admin" { err = e.Orm.Table("sys_menu"). Where("sys_menu.visible = 1 and sys_menu.deleted_at is null"). Order("sys_menu.sort"). Order("id"). Scan(&menuList).Error if err != nil { return m, global.GetFailedErr } } else { menuIds := make([]int, 0) for _, menu := range menus { menuIds = append(menuIds, menu.Id) } err = e.Orm.Table("sys_menu"). Where("sys_menu.id in (?) and sys_menu.visible = 1 and sys_menu.deleted_at is null", menuIds). Order("sys_menu.sort"). Order("id"). Scan(&menuList).Error if err != nil { return m, global.GetFailedErr } } } else { if roleKey == "admin" { err = e.Orm.Table("sys_menu"). Where("sys_menu.visible = 1 and sys_menu.deleted_at is null"). Order("sys_menu.sort"). Order("id"). Scan(&menuList).Error if err != nil { return m, global.GetFailedErr } } else { menuIds := make([]int, 0) for _, menu := range menus { menuIds = append(menuIds, menu.Id) } err = e.Orm.Table("sys_menu"). Where("sys_menu.id in (?) and sys_menu.visible = 1 and sys_menu.deleted_at is null", menuIds). Order("sys_menu.sort"). Order("id"). Scan(&menuList).Error if err != nil { return m, global.GetFailedErr } } } //sort.Sort(model.SysMenuSlice(menuList)) for i := 0; i < len(menuList); i++ { if menuList[i].ParentId != 0 { continue } menusInfo := menuCall(&menuList, menuList[i]) m = append(m, menusInfo) } return }