package app import ( "context" "strings" "git.5iot.com/iotlcm-public/iotlcm-app/internal/consts" "git.5iot.com/iotlcm-public/iotlcm-app/internal/dao" "git.5iot.com/iotlcm-public/iotlcm-app/internal/library/contexts" "git.5iot.com/iotlcm-public/iotlcm-app/internal/model" "git.5iot.com/iotlcm-public/iotlcm-app/internal/model/entity" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/util/gconv" ) type appEnterpriseDataScope struct { Configured bool All bool Restricted bool DeptIds []int64 UserIds []int64 } func appApplyEnterpriseDataScope(ctx context.Context, user *entity.SysUser, mod *gdb.Model, deptField string, userField string, legacy func(*gdb.Model) *gdb.Model) *gdb.Model { scope, err := appResolveEnterpriseDataScope(ctx, user) if err != nil { g.Log().Errorf(ctx, "appApplyEnterpriseDataScope resolve error: %v", err) return mod.Where("1 = 0") } if !scope.Configured { if legacy != nil { return legacy(mod) } return mod } if scope.All { return mod } hasDeptScope := deptField != "" && len(scope.DeptIds) > 0 hasUserScope := userField != "" && len(scope.UserIds) > 0 if hasDeptScope && hasUserScope { return mod.Where("("+deptField+" IN (?) OR "+userField+" IN (?))", scope.DeptIds, scope.UserIds) } if hasDeptScope { return mod.WhereIn(deptField, scope.DeptIds) } if hasUserScope { return mod.WhereIn(userField, scope.UserIds) } if scope.Restricted { return mod.Where("1 = 0") } return mod.Where("1 = 0") } func appResolveEnterpriseDataScope(ctx context.Context, user *entity.SysUser) (*appEnterpriseDataScope, error) { scope := &appEnterpriseDataScope{} if user == nil || user.UserId <= 0 { scope.Restricted = true return scope, nil } configured, err := appAccessConfigured(ctx) if err != nil { return nil, err } scope.Configured = configured if !configured { return scope, nil } if contexts.IsSuperAdmin(ctx) { scope.All = true return scope, nil } currentRoleId, currentRoleDataScope := appCurrentRoleDataScope(ctx) if currentRoleId > 0 && currentRoleDataScope != "" { return appBuildEnterpriseDataScope(ctx, user, currentRoleId, currentRoleDataScope, true) } roles := contexts.GetRoles(ctx) if len(roles) == 0 { roles, err = appLoadUserRoleScopes(ctx, user) if err != nil { return nil, err } } if len(roles) == 0 { scope.Restricted = true return scope, nil } scope.Restricted = true for _, role := range roles { part, err := appBuildEnterpriseDataScope(ctx, user, role.RoleId, role.DataScope, true) if err != nil { return nil, err } if part.All { return part, nil } scope.DeptIds = append(scope.DeptIds, part.DeptIds...) scope.UserIds = append(scope.UserIds, part.UserIds...) } scope.DeptIds = appUniqueInt64(scope.DeptIds) scope.UserIds = appUniqueInt64(scope.UserIds) return scope, nil } func appCurrentRoleDataScope(ctx context.Context) (int64, string) { roleId := int64(0) dataScope := "" if value := contexts.GetDataValue(ctx, "currentRoleId"); value != nil { roleId = gconv.Int64(value) } if value := contexts.GetDataValue(ctx, "currentRoleDataScope"); value != nil { dataScope = strings.TrimSpace(gconv.String(value)) } return roleId, dataScope } func appBuildEnterpriseDataScope(ctx context.Context, user *entity.SysUser, roleId int64, dataScope string, configured bool) (*appEnterpriseDataScope, error) { scope := &appEnterpriseDataScope{ Configured: configured, } dataScope = strings.TrimSpace(dataScope) if dataScope == "" { dataScope = consts.SysRoleDataScopeAll } switch dataScope { case consts.SysRoleDataScopeAll: scope.All = true case consts.SysRoleDataScopeCustom: scope.Restricted = true deptIds, err := appCustomRoleDeptIds(ctx, user.TenantId, roleId) if err != nil { return nil, err } scope.DeptIds = deptIds case consts.SysRoleDataScopeDept: scope.Restricted = true if user.DeptId > 0 { scope.DeptIds = []int64{user.DeptId} } case consts.SysRoleDataScopeDeptAndBelow: scope.Restricted = true deptIds, err := appEnterpriseDeptAndSubIds(ctx, user.TenantId, user.DeptId) if err != nil { return nil, err } scope.DeptIds = deptIds case consts.SysRoleDataScopePersonal: scope.Restricted = true scope.UserIds = []int64{user.UserId} case consts.SysRoleDataScopeDeptAndBelowOrPersonal: scope.Restricted = true deptIds, err := appEnterpriseDeptAndSubIds(ctx, user.TenantId, user.DeptId) if err != nil { return nil, err } scope.DeptIds = deptIds scope.UserIds = []int64{user.UserId} case consts.SysRoleDataScopeOrgAndNextLevel: scope.Restricted = true deptIds, err := appOrgAndNextLevelDeptIds(ctx, user.TenantId, user.DeptId) if err != nil { return nil, err } scope.DeptIds = deptIds case consts.SysRoleDataScopeOrgNextLevel: scope.Restricted = true deptIds, err := appOrgNextLevelDeptIds(ctx, user.TenantId, user.DeptId) if err != nil { return nil, err } scope.DeptIds = deptIds default: scope.Restricted = true } scope.DeptIds = appUniqueInt64(scope.DeptIds) scope.UserIds = appUniqueInt64(scope.UserIds) return scope, nil } func appLoadUserRoleScopes(ctx context.Context, user *entity.SysUser) ([]model.Role, error) { if user == nil || user.UserId <= 0 { return []model.Role{}, nil } var userRoles []*entity.SysUserRole if err := dao.SysUserRole.Ctx(ctx). Where(dao.SysUserRole.Columns().UserId, user.UserId). Scan(&userRoles); err != nil { return nil, err } roleIds := make([]int64, 0, len(userRoles)) for _, userRole := range userRoles { if userRole != nil && userRole.RoleId > 0 { roleIds = append(roleIds, userRole.RoleId) } } roleIds = appUniqueInt64(roleIds) if len(roleIds) == 0 { return []model.Role{}, nil } var rows []*entity.SysRole err := dao.SysRole.Ctx(ctx). Fields(dao.SysRole.Columns().RoleId, dao.SysRole.Columns().DataScope). Where(dao.SysRole.Columns().TenantId, user.TenantId). WhereIn(dao.SysRole.Columns().RoleId, roleIds). Where(dao.SysRole.Columns().Status, consts.SysStatusNormal). Scan(&rows) if err != nil { return nil, err } roles := make([]model.Role, 0, len(rows)) for _, row := range rows { if row == nil || row.RoleId <= 0 { continue } roles = append(roles, model.Role{ RoleId: row.RoleId, DataScope: row.DataScope, }) } return roles, nil } func appCustomRoleDeptIds(ctx context.Context, tenantId string, roleId int64) ([]int64, error) { if roleId <= 0 { return []int64{}, nil } var rows []*entity.SysRoleDept err := dao.SysRoleDept.Ctx(ctx). Where("tenant_id", tenantId). Where(dao.SysRoleDept.Columns().RoleId, roleId). Scan(&rows) if err != nil { return nil, err } deptIds := make([]int64, 0, len(rows)) for _, row := range rows { if row != nil && row.DeptId > 0 { deptIds = append(deptIds, row.DeptId) } } return appUniqueInt64(deptIds), nil } func appLegacyEnterpriseDeptAndSubScope(ctx context.Context, user *entity.SysUser, mod *gdb.Model, deptField string) *gdb.Model { if user == nil || user.DeptId <= 0 || deptField == "" { return mod.Where("1 = 0") } deptIds, err := appEnterpriseDeptAndSubIds(ctx, user.TenantId, user.DeptId) if err != nil || len(deptIds) == 0 { if err != nil { g.Log().Errorf(ctx, "appLegacyEnterpriseDeptAndSubScope error: %v", err) } return mod.Where("1 = 0") } return mod.WhereIn(deptField, deptIds) } func appFilterDeptsByEnterpriseDataScope(ctx context.Context, user *entity.SysUser, depts []*entity.SysDept) ([]*entity.SysDept, error) { scope, err := appResolveEnterpriseDataScope(ctx, user) if err != nil { return nil, err } if !scope.Configured || scope.All { return depts, nil } if len(scope.DeptIds) == 0 { return []*entity.SysDept{}, nil } allowed := make(map[int64]struct{}, len(scope.DeptIds)) for _, deptId := range scope.DeptIds { allowed[deptId] = struct{}{} } result := make([]*entity.SysDept, 0, len(depts)) for _, dept := range depts { if dept == nil || dept.DeptId <= 0 { continue } if _, ok := allowed[dept.DeptId]; ok { result = append(result, dept) } } return result, nil } func appEnterpriseDeptVisibleByDataScope(ctx context.Context, user *entity.SysUser, deptId int64) (bool, error) { if deptId <= 0 { return false, nil } scope, err := appResolveEnterpriseDataScope(ctx, user) if err != nil { return false, err } if !scope.Configured || scope.All { return true, nil } for _, item := range scope.DeptIds { if item == deptId { return true, nil } } return false, nil } func appParentCompanyDeptId(ctx context.Context, tenantId string, deptId int64) (int64, error) { if deptId <= 0 { return deptId, nil } var dept *entity.SysDept if err := dao.SysDept.Ctx(ctx). Where(dao.SysDept.Columns().TenantId, tenantId). Where(dao.SysDept.Columns().DeptId, deptId). WhereNull(dao.SysDept.Columns().DeletedAt). Limit(1). Scan(&dept); err != nil { return 0, gerror.Wrap(err, "查询上级组织失败") } if dept == nil || dept.DeptId == 0 { return deptId, nil } if dept.ParentId == 0 || dept.DeptType == 1 { return dept.DeptId, nil } return appParentCompanyDeptId(ctx, tenantId, dept.ParentId) } func appDeptDirectSubIds(ctx context.Context, tenantId string, deptId int64) ([]int64, error) { if deptId <= 0 { return []int64{}, nil } var rows []*entity.SysDept err := dao.SysDept.Ctx(ctx). Fields(dao.SysDept.Columns().DeptId). Where(dao.SysDept.Columns().TenantId, tenantId). Where(dao.SysDept.Columns().ParentId, deptId). WhereNull(dao.SysDept.Columns().DeletedAt). Scan(&rows) if err != nil { return nil, gerror.Wrap(err, "查询下级组织失败") } deptIds := make([]int64, 0, len(rows)) for _, row := range rows { if row != nil && row.DeptId > 0 { deptIds = append(deptIds, row.DeptId) } } return appUniqueInt64(deptIds), nil } func appOrgAndNextLevelDeptIds(ctx context.Context, tenantId string, deptId int64) ([]int64, error) { orgDeptId, err := appParentCompanyDeptId(ctx, tenantId, deptId) if err != nil { return nil, err } ids := []int64{} if orgDeptId > 0 { ids = append(ids, orgDeptId) } children, err := appDeptDirectSubIds(ctx, tenantId, orgDeptId) if err != nil { return nil, err } ids = append(ids, children...) return appUniqueInt64(ids), nil } func appOrgNextLevelDeptIds(ctx context.Context, tenantId string, deptId int64) ([]int64, error) { orgDeptId, err := appParentCompanyDeptId(ctx, tenantId, deptId) if err != nil { return nil, err } return appDeptDirectSubIds(ctx, tenantId, orgDeptId) } func appUniqueInt64(values []int64) []int64 { result := make([]int64, 0, len(values)) seen := make(map[int64]struct{}, len(values)) for _, value := range values { if value <= 0 { continue } if _, ok := seen[value]; ok { continue } seen[value] = struct{}{} result = append(result, value) } return result }