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 获取菜单列表