deptTreeLogic.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. package dept
  2. import (
  3. "context"
  4. "strings"
  5. "perms-system-server/internal/consts"
  6. "perms-system-server/internal/middleware"
  7. deptModel "perms-system-server/internal/model/dept"
  8. "perms-system-server/internal/response"
  9. "perms-system-server/internal/svc"
  10. "perms-system-server/internal/types"
  11. "github.com/zeromicro/go-zero/core/logx"
  12. )
  13. type DeptTreeLogic struct {
  14. logx.Logger
  15. ctx context.Context
  16. svcCtx *svc.ServiceContext
  17. }
  18. func NewDeptTreeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeptTreeLogic {
  19. return &DeptTreeLogic{
  20. Logger: logx.WithContext(ctx),
  21. ctx: ctx,
  22. svcCtx: svcCtx,
  23. }
  24. }
  25. // DeptTree 部门树。超管 / 产品 ADMIN 返回完整组织架构树;其他成员仅返回以其 DeptPath
  26. // 为根的子树,避免 MEMBER 级账号枚举全公司组织结构、定位 DEV 部门用于针对性特权获取
  27. // (见审计 M-2)。未归属部门或 DeptPath 为空的成员返回空树。
  28. func (l *DeptTreeLogic) DeptTree() (resp []*types.DeptItem, err error) {
  29. caller := middleware.GetUserDetails(l.ctx)
  30. if caller == nil {
  31. return nil, response.ErrUnauthorized("未登录")
  32. }
  33. list, err := l.svcCtx.SysDeptModel.FindAll(l.ctx)
  34. if err != nil {
  35. return nil, err
  36. }
  37. fullAccess := caller.IsSuperAdmin || caller.MemberType == consts.MemberTypeAdmin
  38. if !fullAccess {
  39. if caller.DeptPath == "" {
  40. return make([]*types.DeptItem, 0), nil
  41. }
  42. filtered := make([]*deptModel.SysDept, 0, len(list))
  43. for _, d := range list {
  44. if strings.HasPrefix(d.Path, caller.DeptPath) {
  45. filtered = append(filtered, d)
  46. }
  47. }
  48. list = filtered
  49. }
  50. items := make([]*types.DeptItem, 0, len(list))
  51. for _, d := range list {
  52. items = append(items, &types.DeptItem{
  53. Id: d.Id,
  54. ParentId: d.ParentId,
  55. Name: d.Name,
  56. Path: d.Path,
  57. Sort: d.Sort,
  58. DeptType: d.DeptType,
  59. Remark: d.Remark,
  60. Status: d.Status,
  61. CreateTime: d.CreateTime,
  62. Children: make([]*types.DeptItem, 0),
  63. })
  64. }
  65. itemMap := make(map[int64]*types.DeptItem)
  66. for _, item := range items {
  67. itemMap[item.Id] = item
  68. }
  69. roots := make([]*types.DeptItem, 0)
  70. for _, item := range items {
  71. // 非特权成员下只保留 caller 子树:原树的上级部门不出现在 items 中,item.ParentId
  72. // 找不到父节点时应当把当前节点当成局部根展示,而不是报错丢弃。
  73. if _, hasParent := itemMap[item.ParentId]; item.ParentId == 0 || !hasParent {
  74. if fullAccess && item.ParentId != 0 {
  75. l.Errorf("DeptTree: dept id=%d has parentId=%d which does not exist, treated as root", item.Id, item.ParentId)
  76. }
  77. roots = append(roots, item)
  78. } else {
  79. itemMap[item.ParentId].Children = append(itemMap[item.ParentId].Children, item)
  80. }
  81. }
  82. return roots, nil
  83. }