github.com/SupenBysz/gf-admin-community@v0.7.4/internal/logic/sys_menu/sys_menu.go (about) 1 package sys_menu 2 3 import ( 4 "context" 5 "github.com/SupenBysz/gf-admin-community/sys_model" 6 "github.com/SupenBysz/gf-admin-community/sys_model/sys_dao" 7 "github.com/SupenBysz/gf-admin-community/sys_model/sys_do" 8 "github.com/SupenBysz/gf-admin-community/sys_model/sys_entity" 9 "github.com/SupenBysz/gf-admin-community/sys_service" 10 "github.com/gogf/gf/v2/database/gdb" 11 "github.com/gogf/gf/v2/errors/gcode" 12 "github.com/gogf/gf/v2/errors/gerror" 13 "github.com/gogf/gf/v2/os/gtime" 14 "github.com/gogf/gf/v2/util/gconv" 15 "github.com/kysion/base-library/utility/daoctl" 16 "github.com/kysion/base-library/utility/kconv" 17 "sort" 18 ) 19 20 // 设计修改菜单的操作只有超级管理员-1有权限,其他用户只能看看 21 22 type sSysMenu struct { 23 } 24 25 func init() { 26 sys_service.RegisterSysMenu(New()) 27 } 28 29 // New sSysMenu 菜单逻辑实现 30 func New() *sSysMenu { 31 return &sSysMenu{} 32 } 33 34 // GetMenuById 根据ID获取菜单信息 35 func (s *sSysMenu) GetMenuById(ctx context.Context, menuId int64) (*sys_entity.SysMenu, error) { 36 result := sys_entity.SysMenu{} 37 err := sys_dao.SysMenu.Ctx(ctx).Where(sys_do.SysMenu{Id: menuId}).Scan(&result) 38 if err != nil { 39 return nil, sys_service.SysLogs().ErrorSimple(ctx, err, "菜单信息查询失败", sys_dao.SysMenu.Table()) 40 } 41 return &result, err 42 } 43 44 // CreateMenu 创建菜单 45 func (s *sSysMenu) CreateMenu(ctx context.Context, info *sys_model.SysMenu) (*sys_entity.SysMenu, error) { 46 return s.SaveMenu(ctx, info) 47 } 48 49 // UpdateMenu 更新菜单 50 func (s *sSysMenu) UpdateMenu(ctx context.Context, info *sys_model.UpdateSysMenu) (*sys_entity.SysMenu, error) { 51 if info.Id <= 0 { 52 return nil, sys_service.SysLogs().ErrorSimple(ctx, gerror.NewCode(gcode.CodeNil, "ID参数错误"), "", sys_dao.SysMenu.Table()) 53 } 54 data := kconv.Struct(info, &sys_model.SysMenu{}) 55 56 return s.SaveMenu(ctx, data) 57 } 58 59 // SaveMenu 新增或保存菜单信息,并自动更新对应的权限信息 60 func (s *sSysMenu) SaveMenu(ctx context.Context, info *sys_model.SysMenu) (*sys_entity.SysMenu, error) { 61 data := sys_do.SysMenu{} 62 gconv.Struct(info, &data) 63 64 // 如果父级ID大于0,则校验父级菜单信息是否存在 65 if info.ParentId != nil && *info.ParentId > 0 { 66 permissionInfo, err := s.GetMenuById(ctx, gconv.Int64(data.ParentId)) 67 if err != nil || permissionInfo.Id <= 0 { 68 return nil, sys_service.SysLogs().ErrorSimple(ctx, err, "父级菜单信息不存在", sys_dao.SysMenu.Table()) 69 } 70 } 71 72 err := sys_dao.SysMenu.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { 73 if info.Id <= 0 { // 插入 74 if data.ParentId == nil { 75 *info.ParentId = 0 76 data.ParentId = 0 77 } 78 // 保存菜单权限信息,更新操作不重新插入权限 79 sysPermission, err := sys_service.SysPermission().CreatePermission(ctx, sys_model.SysPermission{ 80 Id: info.Id, 81 ParentId: *info.ParentId, 82 Name: *info.Title, 83 Type: 2, 84 Description: gconv.String(data.Description), 85 Identifier: "Menu::" + *info.Name, 86 }) 87 88 if err != nil { 89 return sys_service.SysLogs().ErrorSimple(ctx, err, "保存菜单信息失败", sys_dao.SysMenu.Table()) 90 } 91 92 // 菜单id = 权限id 93 data.Id = sysPermission.Id 94 info.Id = sysPermission.Id 95 data.CreatedAt = gtime.Now() 96 97 _, err = sys_dao.SysMenu.Ctx(ctx).Insert(&data) 98 99 if err != nil { 100 return sys_service.SysLogs().ErrorSimple(ctx, err, "新增菜单信息失败", sys_dao.SysMenu.Table()) 101 } 102 103 } else { // 更新 104 data.UpdatedAt = gtime.Now() 105 data.Id = nil 106 _, err := sys_dao.SysMenu.Ctx(ctx). 107 OmitNilData().Where(sys_dao.SysMenu.Columns().Id, info.Id).Update(&data) 108 if err != nil { 109 return sys_service.SysLogs().ErrorSimple(ctx, err, "菜单信息保存失败", sys_dao.SysMenu.Table()) 110 } 111 112 permisionInfo := sys_model.UpdateSysPermission{ 113 Id: info.Id, 114 Name: info.Title, 115 Type: nil, 116 Description: info.Description, 117 Identifier: nil, 118 } 119 120 if data.Name != nil { 121 identifier := "Menu::" + *info.Name 122 permisionInfo.Identifier = &identifier 123 } 124 125 // 更新菜单权限信息 126 _, err = sys_service.SysPermission().UpdatePermission(ctx, &permisionInfo) 127 128 if err != nil { 129 return sys_service.SysLogs().ErrorSimple(ctx, err, "菜单权限更新失败", sys_dao.SysMenu.Table()) 130 } 131 132 } 133 return nil 134 }) 135 136 if err != nil { 137 return nil, err 138 } 139 140 //go s.makeMenuTeee(ctx, 0) 141 return s.GetMenuById(ctx, info.Id) 142 } 143 144 // DeleteMenu 删除菜单,删除的时候要关联删除sys_permission,有子菜单时禁止删除。 145 func (s *sSysMenu) DeleteMenu(ctx context.Context, id int64) (bool, error) { 146 _, err := s.GetMenuById(ctx, id) 147 148 if err != nil { 149 return false, err 150 } 151 152 // 判断是否具备子菜单 153 count, _ := sys_dao.SysMenu.Ctx(ctx).Where(sys_dao.SysMenu.Columns().ParentId, id).Count() 154 if count > 0 { 155 return false, sys_service.SysLogs().ErrorSimple(ctx, nil, "该菜单具备子菜单,请先移除子菜单再进行操作", sys_dao.SysMenu.Table()) 156 } 157 158 err = sys_dao.SysMenu.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { 159 // 删除关联sys_permission权限记录 菜单id = 权限id 160 ret, err := sys_service.SysPermission().DeletePermission(ctx, id) 161 if err != nil || ret == false { 162 return err 163 } 164 165 // 删除菜单记录 166 _, err = daoctl.DeleteWithError(sys_dao.SysMenu.Ctx(ctx).Where(sys_dao.SysMenu.Columns().Id, id)) 167 if err != nil { 168 return err 169 } 170 171 return nil 172 }) 173 174 if err != nil { 175 return false, err 176 } 177 178 //g.DB().GetCache().Remove(ctx, "getMenuTreeCacheById_"+gconv.String(id)) 179 180 //daoctl.RemoveQueryCache(sys_dao.SysMenu.DB(), sys_dao.SysMenu.Table()) 181 182 //go s.MakeMenuTree(ctx, 0) 183 184 // 有更新的时候,把所有菜单树缓存清除,然后重构 185 186 return true, nil 187 } 188 189 // MakeMenuTree 构建菜单树 190 func (s *sSysMenu) MakeMenuTree(ctx context.Context, parentId int64, isMakeNodeFun func(ctx context.Context, cruuentMenu *sys_entity.SysMenu) bool) ([]*sys_model.SysMenuTreeRes, error) { 191 // 当前级菜单树没加入 192 193 // 获取下级菜单列表 194 result, err := s.GetMenuList(ctx, parentId, false) 195 if err != nil { 196 return nil, sys_service.SysLogs().ErrorSimple(ctx, err, "查询菜单失败", sys_dao.SysPermission.Table()) 197 } 198 199 response := make([]*sys_model.SysMenuTreeRes, 0) 200 201 // 有数据,则递归加载 202 if len(result) > 0 { 203 // 我第一次进来的样子 204 205 // 我进来是否具备上级 206 for _, sysMenuItem := range result { 207 item := &sys_model.SysMenuTreeRes{} 208 gconv.Struct(sysMenuItem, &item) 209 210 tree, err := s.MakeMenuTree(ctx, sysMenuItem.Id, isMakeNodeFun) 211 212 for _, childItem := range tree { 213 if isMakeNodeFun(ctx, childItem.SysMenu) || len(childItem.Children) > 0 { 214 item.Children = append(item.Children, childItem) 215 } 216 } 217 218 if len(tree) == 0 && !isMakeNodeFun(ctx, sysMenuItem) && len(item.Children) == 0 { 219 continue 220 } 221 222 if err != nil { 223 return nil, sys_service.SysLogs().ErrorSimple(ctx, err, "查询菜单失败", sys_dao.SysMenu.Table()) 224 } 225 226 response = append(response, item) 227 228 } 229 } 230 231 if err != nil { 232 return nil, sys_service.SysLogs().ErrorSimple(ctx, err, "查询菜单失败", sys_dao.SysMenu.Table()) 233 } 234 235 return response, nil 236 } 237 238 // GetMenuTree 根据ID获取下级菜单信息,返回菜单树,并缓存 239 func (s *sSysMenu) GetMenuTree(ctx context.Context, parentId int64) (sys_model.SysMenuTreeListRes, error) { 240 // 先判断缓存中是否存在菜单树,存在直接返回 241 //res, _ := g.DB().GetCache().Get(ctx, "MenuTreeCache_"+gconv.String(parentId)) 242 243 //if res.Val() != nil { 244 // data := make([]*sys_model.SysMenuTreeRes, 0) 245 // gconv.Struct(res, &data) 246 // return data, nil 247 //} 248 249 // 将权限树缓存起来, 250 // 注意:这种自定义缓存方式,Ctx内部的缓存机制不会自动帮我们删除该缓存,所以,需要每次有更新操作,手动删除缓存getMenuTreeCacheById_的缓存 251 tree, err := s.MakeMenuTree(ctx, parentId, func(ctx context.Context, cruuentMenu *sys_entity.SysMenu) bool { 252 return true 253 }) 254 if err != nil { 255 return nil, err 256 } 257 258 //g.DB().GetCache().Set(ctx, "MenuTreeCache_"+gconv.String(parentId), tree, 0) 259 260 return tree, nil 261 } 262 263 // GetMenuList 根据ID获取下级菜单列表,IsRecursive代表是否需要返回下级 264 func (s *sSysMenu) GetMenuList(ctx context.Context, parentId int64, IsRecursive bool, limitChildrenIds ...int64) ([]*sys_entity.SysMenu, error) { 265 dataArr := make([]*sys_entity.SysMenu, 0) 266 267 response := make([]*sys_entity.SysMenu, 0) 268 model := sys_dao.SysMenu.Ctx(ctx).Where(sys_dao.SysMenu.Columns().ParentId, parentId) 269 270 if len(limitChildrenIds) > 0 { 271 model = model.WhereIn(sys_dao.SysMenu.Columns().Id, limitChildrenIds) 272 } 273 274 model.Scan(&dataArr) 275 gconv.Struct(dataArr, &response) 276 277 // 如果需要返回下级,则递归加载 278 if IsRecursive == true && len(dataArr) > 0 { 279 for _, sysMenu := range dataArr { 280 var children []*sys_entity.SysMenu 281 children, err := s.GetMenuList(ctx, sysMenu.Id, IsRecursive, limitChildrenIds...) 282 283 if err != nil { 284 return nil, sys_service.SysLogs().ErrorSimple(ctx, err, "查询失败", sys_dao.SysMenu.Table()) 285 } 286 287 if children == nil || len(children) <= 0 { 288 continue 289 } 290 291 for _, menu := range children { 292 response = append(response, menu) 293 } 294 } 295 } 296 297 sort.Slice(response, func(i, j int) bool { 298 return response[i].Sort < response[j].Sort 299 }) 300 301 return response, nil 302 } 303 304 // QueryMenuList 获取菜单列表