package service import ( dto2 "Medical_OAuth/common/dto" "Medical_OAuth/common/global" cModel "Medical_OAuth/common/model" "encoding/json" "fmt" "gogs.baozhida.cn/zoie/OAuth-core/service" "strings" "github.com/pkg/errors" "gorm.io/gorm" "Medical_OAuth/app/admin/model" "Medical_OAuth/app/admin/service/dto" "gogs.baozhida.cn/zoie/OAuth-core/pkg" ) type ServMenu struct { service.Service } // GetPage 获取ServMenu列表 func (e *ServMenu) GetPage(c *dto.ServMenuGetPageReq, menus *[]model.ServMenu) *ServMenu { var menu = make([]model.ServMenu, 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 := servMenuCall(&menu, menu[i]) *menus = append(*menus, menusInfo) } if len(*menus) == 0 { parentMap, flag := getServMenuParent(&menu) if flag { for i := 0; i < len(menu); i++ { if parentMap[menu[i].ParentId] { continue } menusInfo := servMenuCall(&menu, menu[i]) *menus = append(*menus, menusInfo) } } else { for i := 0; i < len(menu); i++ { menusInfo := servMenuCall(&menu, menu[i]) *menus = append(*menus, menusInfo) } } } return e } // 获取搜索出来的菜单的父菜单 func getServMenuParent(menuList *[]model.ServMenu) (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 *ServMenu) getPage(c *dto.ServMenuGetPageReq, list *[]model.ServMenu) *ServMenu { var err error var data model.ServMenu var tempList []model.ServMenu err = e.Orm.Model(&data). Scopes(dto2.MakeCondition(c.GetNeedSearch())). Find(&tempList).Error if err != nil { e.Log.Errorf("getServMenuPage error: %s", err) _ = e.AddError(err) return e } // 获取菜单及其子菜单下ID for _, menu := range tempList { var menuList = make([]model.ServMenu, 0) err = e.Orm.Where("menu_path like ?", menu.MenuPath+"%").Order(fmt.Sprintf("sort %s", c.SortOrder)).Find(&menuList).Error *list = append(*list, menuList...) } *list = DeduplicateServMenu(*list) return e } // Get 获取ServMenu对象 func (e *ServMenu) Get(d *dto.ServMenuGetReq, menuModel *model.ServMenu) *ServMenu { 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 创建ServMenu对象 func (e *ServMenu) Insert(c *dto.ServMenuInsertReq) *ServMenu { var err error var data model.ServMenu 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 } return e } func (e *ServMenu) initPaths(menu *model.ServMenu) (menuPath string, err error) { var data model.ServMenu parentMenu := new(model.ServMenu) if menu.ParentId != 0 { e.Orm.Model(&data).Where("service_id = ?", menu.ServiceId).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 修改ServMenu对象 func (e *ServMenu) Update(c *dto.ServMenuUpdateReq) *ServMenu { var err error tx := e.Orm.Debug().Begin() defer func() { if err != nil { tx.Rollback() } else { tx.Commit() } }() var menuModel = model.ServMenu{} 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.ServMenu 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 删除ServMenu func (e *ServMenu) Remove(d *dto.ServMenuDeleteReq) *ServMenu { var err error tx := e.Orm.Begin() defer func() { if err != nil { tx.Rollback() } else { tx.Commit() } }() var menuList = make([]model.ServMenu, 0) tx.Where("id in (?)", d.GetId(), d.GetId()).Find(&menuList) if len(menuList) == 0 { return e } for _, menu := range menuList { err = e.Orm.Where("menu_path like ?", menu.MenuPath+"%").Delete(&model.ServMenu{}).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 *ServMenu) GetList(c *dto.ServMenuGetPageReq, list *[]model.ServMenu) error { var err error var data model.ServMenu 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 } // servMenuCall 构建菜单树 func servMenuCall(menuList *[]model.ServMenu, menu model.ServMenu) model.ServMenu { list := *menuList min := make([]model.ServMenu, 0) for j := 0; j < len(list); j++ { if menu.Id != list[j].ParentId { continue } mi := model.ServMenu{} mi.Id = list[j].Id mi.Name = list[j].Name mi.Icon = list[j].Icon mi.Path = list[j].Path mi.MenuType = list[j].MenuType mi.Permission = list[j].Permission 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.ServMenu{} if mi.MenuType != cModel.Button { ms := servMenuCall(menuList, mi) min = append(min, ms) } else { min = append(min, mi) } } menu.Children = min return menu } // DeduplicateServMenu 菜单列表去重 func DeduplicateServMenu(list []model.ServMenu) []model.ServMenu { seen := make(map[string]bool) deduplicated := []model.ServMenu{} 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 }