Skip to content

接口名称

角色成员管理 -(IFeishuTenantV3RoleMember)

功能描述

角色成员管理API用于管理角色内的成员及其权限范围。通过该接口可以实现角色成员的添加、删除、权限范围设置等操作。角色成员功能特别适用于企业内部的审批流程管理,可以将角色设置为审批流程的审批人,并为每个角色成员设置不同的管理范围,实现精细化的权限控制。当前接口使用租户令牌访问,适用于租户应用场景。

参考文档

https://open.feishu.cn/document/server-docs/contact-v3/functional_role-member/resource-introduction

函数列表

函数名称功能描述认证方式HTTP 方法
BatchAddMemberAsync批量添加角色成员租户令牌POST
BatchAddMembersSopesAsync批量设置成员管理范围租户令牌POST
GetMembersSopesAsync查询指定成员的管理范围租户令牌GET
GetMembersAsync查询角色内所有成员信息租户令牌GET
DeleteMembersByRoleIdAsync批量删除角色成员租户令牌DELETE

函数详细内容


函数名称:批量添加角色成员

函数签名

csharp
Task<FeishuApiResult<RoleAssignmentResult>?> BatchAddMemberAsync(
             [Path] string role_id,
             [Body] RoleMembersRequest roleMembersRequest,
             [Query("user_id_type")] string? user_id_type = Consts.User_Id_Type,
             CancellationToken cancellationToken = default);

认证:租户令牌

参数

参数名类型必填说明示例值
role_idstring✅ 必填角色ID"6982451736382267393"
roleMembersRequestRoleMembersRequest✅ 必填角色成员的用户ID列表请求体见下方结构
roleMembersRequest.MembersList<string>✅ 必填待添加为角色成员的用户ID列表["ou_7d8a6e9d3c2c1b882487c7398e9d8f7", "ou_8f9c7a6d4d3e2f1a987d6387c2a1b3e"]
user_id_typestring⚪ 可选用户ID类型,默认值:open_id"open_id"
cancellationTokenCancellationToken⚪ 可选取消操作令牌-

响应

成功响应示例:

json
{
  "code": 0,
  "msg": "success",
  "data": {
    "results": [
      {
        "user_id": "ou_7d8a6e9d3c2c1b882487c7398e9d8f7",
        "reason": 0
      },
      {
        "user_id": "ou_8f9c7a6d4d3e2f1a987d6387c2a1b3e",
        "reason": 0
      }
    ]
  }
}

常见错误响应示例:

json
{
  "code": 403,
  "msg": "无权限访问该角色",
  "data": null
}
json
{
  "code": 404,
  "msg": "角色不存在",
  "data": null
}

说明

  • 批量添加用户到指定角色中
  • 每个用户ID的类型需要和user_id_type参数保持一致
  • reason字段:0表示成功,1表示用户已在角色中,2表示失败
  • 支持一次添加多个成员,提高操作效率

代码示例

javascript
// 批量添加财务审批人员到财务角色
async function addFinanceApprovalMembers() {
  const roleId = "6982451736382267393"; // 财务角色ID
  const newMembers = [
    "ou_7d8a6e9d3c2c1b882487c7398e9d8f7", // 张三
    "ou_8f9c7a6d4d3e2f1a987d6387c2a1b3e", // 李四
    "ou_5a4b3c2d1e9f8a7b6c5d4e3f2a1b9c"  // 王五
  ];

  try {
    const response = await feishuClient.tenantV3RoleMember.batchAddMemberAsync(
      roleId,
      {
        members: newMembers
      },
      "open_id"
    );

    if (response.code === 0) {
      console.log("财务审批人员添加成功");
      
      // 分析添加结果
      const successUsers = response.data.results.filter(r => r.reason === 0);
      const existingUsers = response.data.results.filter(r => r.reason === 1);
      const failedUsers = response.data.results.filter(r => r.reason === 2);
      
      console.log(`成功添加: ${successUsers.length} 人`);
      if (existingUsers.length > 0) {
        console.log(`已在角色中: ${existingUsers.length} 人`);
      }
      if (failedUsers.length > 0) {
        console.log(`添加失败: ${failedUsers.length} 人`);
      }
      
      // 发送通知给新添加的成员
      if (successUsers.length > 0) {
        await notifyNewApprovalMembers(successUsers.map(r => r.user_id), roleId);
      }
      
      return successUsers;
    } else {
      console.error(`添加失败: ${response.msg}`);
      throw new Error(`角色成员添加失败: ${response.msg}`);
    }
  } catch (error) {
    console.error("添加财务审批人员时发生错误:", error.message);
    throw error;
  }
}

// 通知新添加的审批人员
async function notifyNewApprovalMembers(userIds, roleId) {
  const roleInfo = await getRoleInfo(roleId);
  const message = `您已被添加到"${roleInfo.name}"角色,现在可以处理相关审批流程。`;
  
  for (const userId of userIds) {
    await sendSystemMessage(userId, {
      title: "角色权限更新通知",
      content: message,
      type: "role_assignment"
    });
  }
}

// 获取角色信息
async function getRoleInfo(roleId) {
  const response = await feishuClient.tenantV3Role.getRoleAsync(roleId);
  return response.data.role;
}

函数名称:批量设置成员管理范围

函数签名

csharp
Task<FeishuApiResult<RoleAssignmentResult>?> BatchAddMembersSopesAsync(
           [Path] string role_id,
           [Body] RoleMembersScopeRequest membersScopeRequest,
           [Query("user_id_type")] string? user_id_type = Consts.User_Id_Type,
           [Query("department_id_type")] string? department_id_type = Consts.Department_Id_Type,
           CancellationToken cancellationToken = default);

认证:租户令牌

参数

参数名类型必填说明示例值
role_idstring✅ 必填角色ID"6982451736382267393"
membersScopeRequestRoleMembersScopeRequest✅ 必填角色成员管理范围请求体见下方结构
membersScopeRequest.MembersList<string>✅ 必填角色成员的用户ID列表["ou_7d8a6e9d3c2c1b882487c7398e9d8f7", "ou_8f9c7a6d4d3e2f1a987d6387c2a1b3e"]
membersScopeRequest.DepartmentsList<string>✅ 必填设置角色成员可管理的部门范围["od-4e6789c92a3c8e02dbe89d3f9b87c", "od-8f9a2b1c4d3e9f7c3d8e7a0b9f6c"]
user_id_typestring⚪ 可选用户ID类型,默认值:open_id"open_id"
department_id_typestring⚪ 可选部门ID类型,默认值:open_department_id"open_department_id"
cancellationTokenCancellationToken⚪ 可选取消操作令牌-

响应

成功响应示例:

json
{
  "code": 0,
  "msg": "success",
  "data": {
    "results": [
      {
        "user_id": "ou_7d8a6e9d3c2c1b882487c7398e9d8f7",
        "reason": 0
      }
    ]
  }
}

常见错误响应示例:

json
{
  "code": 400,
  "msg": "部门ID无效",
  "data": null
}

说明

  • 为角色成员设置可管理的部门范围,实现精细化的权限控制
  • 每个成员只能管理指定范围内的审批流程
  • 部门ID类型需要与department_id_type参数保持一致
  • 适用于需要区域化管理的场景

代码示例

javascript
// 为不同地区的财务人员设置相应的管理范围
async function setRegionalFinanceManagerScope() {
  const roleId = "6982451736382267393"; // 财务经理角色ID
  
  // 地区财务人员对应的管理部门
  const regionalManagers = [
    {
      userId: "ou_7d8a6e9d3c2c1b882487c7398e9d8f7", // 华北财务经理
      departmentIds: ["od-4e6789c92a3c8e02dbe89d3f9b87c", "od-5f7a8b9c3d4e9f2a1b8c7d6e5f4a"] // 华北地区部门
    },
    {
      userId: "ou_8f9c7a6d4d3e2f1a987d6387c2a1b3e", // 华南财务经理
      departmentIds: ["od-6a8b9c2d4e3f9a7b1c8d7e6f5a4b", "od-7b9c2d5f4e8a9b3c1d7e6f5a4b8c"] // 华南地区部门
    },
    {
      userId: "ou_5a4b3c2d1e9f8a7b6c5d4e3f2a1b9c", // 华东财务经理
      departmentIds: ["od-8c9d2e6f5a4b9c3d2e8f7a6b5c4d", "od-9d2e7f6a5b4c9d3e2f8a7b6c5d4e"] // 华东地区部门
    }
  ];

  try {
    for (const manager of regionalManagers) {
      const response = await feishuClient.tenantV3RoleMember.batchAddMembersSopesAsync(
        roleId,
        {
          members: [manager.userId],
          departments: manager.departmentIds
        },
        "open_id",
        "open_department_id"
      );

      if (response.code === 0) {
        console.log(`为用户 ${manager.userId} 设置管理范围成功`);
        
        // 验证设置结果
        await validateMemberScope(roleId, manager.userId, manager.departmentIds);
      } else {
        console.error(`设置管理范围失败: ${response.msg}`);
      }
    }
    
    console.log("地区财务经理管理范围设置完成");
  } catch (error) {
    console.error("设置管理范围时发生错误:", error.message);
    throw error;
  }
}

// 验证成员管理范围设置是否正确
async function validateMemberScope(roleId, userId, expectedDepartments) {
  try {
    const response = await feishuClient.tenantV3RoleMember.getMembersSopesAsync(
      roleId,
      userId,
      "open_id",
      "open_department_id"
    );

    if (response.code === 0) {
      const scopeInfo = response.data.member;
      const actualDepartments = scopeInfo.department_ids.sort();
      const expectedSorted = expectedDepartments.sort();
      
      if (JSON.stringify(actualDepartments) === JSON.stringify(expectedSorted)) {
        console.log(`用户 ${userId} 的管理范围验证通过`);
      } else {
        console.warn(`用户 ${userId} 的管理范围验证失败,期望: ${expectedDepartments.join(',')}, 实际: ${actualDepartments.join(',')}`);
      }
    }
  } catch (error) {
    console.error(`验证用户 ${userId} 管理范围时发生错误:`, error.message);
  }
}

函数名称:查询指定成员的管理范围

函数签名

csharp
Task<FeishuApiResult<RoleMemberScopeResult>?> GetMembersSopesAsync(
          [Path] string role_id,
          [Path] string member_id,
          [Query("user_id_type")] string? user_id_type = Consts.User_Id_Type,
          [Query("department_id_type")] string? department_id_type = Consts.Department_Id_Type,
          CancellationToken cancellationToken = default);

认证:租户令牌

参数

参数名类型必填说明示例值
role_idstring✅ 必填角色ID"6982451736382267393"
member_idstring✅ 必填角色成员的用户ID"ou_7d8a6e9d3c2c1b882487c7398e9d8f7"
user_id_typestring⚪ 可选用户ID类型,默认值:open_id"open_id"
department_id_typestring⚪ 可选部门ID类型,默认值:open_department_id"open_department_id"
cancellationTokenCancellationToken⚪ 可选取消操作令牌-

响应

成功响应示例:

json
{
  "code": 0,
  "msg": "success",
  "data": {
    "member": {
      "user_id": "ou_7d8a6e9d3c2c1b882487c7398e9d8f7",
      "scope_type": "department",
      "department_ids": [
        "od-4e6789c92a3c8e02dbe89d3f9b87c",
        "od-5f7a8b9c3d4e9f2a1b8c7d6e5f4a"
      ]
    }
  }
}

常见错误响应示例:

json
{
  "code": 404,
  "msg": "成员不存在",
  "data": null
}

说明

  • 查询指定角色成员的管理范围信息
  • scope_type为"department"表示有部门范围限制,为"all"表示全部范围
  • 返回具体的部门ID列表,便于权限控制和审批流程判断

代码示例

javascript
// 检查用户是否有权限处理特定部门的审批
async function checkApprovalPermission(userId, roleId, departmentId) {
  try {
    const response = await feishuClient.tenantV3RoleMember.getMembersSopesAsync(
      roleId,
      userId,
      "open_id",
      "open_department_id"
    );

    if (response.code === 0) {
      const memberScope = response.data.member;
      
      // 检查权限范围
      if (memberScope.scope_type === "all") {
        return { hasPermission: true, scopeType: "all", reason: "拥有全部管理权限" };
      }
      
      if (memberScope.scope_type === "department") {
        if (memberScope.department_ids.includes(departmentId)) {
          return { 
            hasPermission: true, 
            scopeType: "department", 
            reason: "拥有该部门管理权限",
            managedDepartments: memberScope.department_ids
          };
        } else {
          return { 
            hasPermission: false, 
            scopeType: "department", 
            reason: "无权管理该部门",
            managedDepartments: memberScope.department_ids
          };
        }
      }
      
      return { hasPermission: false, scopeType: "unknown", reason: "未知的权限范围类型" };
    } else {
      console.error(`查询用户权限失败: ${response.msg}`);
      return { hasPermission: false, reason: `查询失败: ${response.msg}` };
    }
  } catch (error) {
    console.error("检查审批权限时发生错误:", error.message);
    return { hasPermission: false, reason: "权限检查异常" };
  }
}

// 获取用户的权限范围摘要
async function getUserPermissionSummary(userId, roleId) {
  try {
    const response = await feishuClient.tenantV3RoleMember.getMembersSopesAsync(
      roleId,
      userId,
      "open_id",
      "open_department_id"
    );

    if (response.code === 0) {
      const memberScope = response.data.member;
      
      let summary = {
        userId,
        scopeType: memberScope.scope_type,
        departmentCount: memberScope.department_ids.length,
        managedDepartments: memberScope.department_ids
      };

      // 获取部门名称
      if (memberScope.scope_type === "department" && memberScope.department_ids.length > 0) {
        summary.departmentNames = await getDepartmentNames(memberScope.department_ids);
      }

      return summary;
    }
  } catch (error) {
    console.error("获取权限摘要时发生错误:", error.message);
    return null;
  }
}

// 批量获取多个用户的权限信息
async function batchGetUserPermissions(userIds, roleId) {
  const permissions = [];
  
  for (const userId of userIds) {
    const permission = await getUserPermissionSummary(userId, roleId);
    if (permission) {
      permissions.push(permission);
    }
  }
  
  return permissions;
}

函数名称:查询角色内所有成员信息

函数签名

csharp
Task<FeishuApiResult<RoleMemberScopeResult>?> GetMembersAsync(
          [Path] string role_id,
          [Query("page_size")] int? page_size = 10,
          [Query("page_token")] string? page_token = null,
          [Query("user_id_type")] string? user_id_type = Consts.User_Id_Type,
          [Query("department_id_type")] string? department_id_type = Consts.Department_Id_Type,
          CancellationToken cancellationToken = default);

认证:租户令牌

参数

参数名类型必填说明示例值
role_idstring✅ 必填角色ID"6982451736382267393"
page_sizeint⚪ 可选分页大小,默认值:1050
page_tokenstring⚪ 可选分页标记,第一次请求不填"page_token_abc123"
user_id_typestring⚪ 可选用户ID类型,默认值:open_id"open_id"
department_id_typestring⚪ 可选部门ID类型,默认值:open_department_id"open_department_id"
cancellationTokenCancellationToken⚪ 可选取消操作令牌-

响应

成功响应示例:

json
{
  "code": 0,
  "msg": "success",
  "data": {
    "member": {
      "user_id": "ou_7d8a6e9d3c2c1b882487c7398e9d8f7",
      "scope_type": "department",
      "department_ids": ["od-4e6789c92a3c8e02dbe89d3f9b87c"]
    },
    "page_token": "page_token_def456",
    "has_more": true
  }
}

常见错误响应示例:

json
{
  "code": 404,
  "msg": "角色不存在",
  "data": null
}

说明

  • 分页查询指定角色内的所有成员信息
  • 包含每个成员的用户ID和管理范围
  • 支持自定义分页大小,提高大数据量场景的性能
  • 返回分页标记用于获取下一页数据

代码示例

javascript
// 获取角色所有成员的完整列表
async function getAllRoleMembers(roleId) {
  let allMembers = [];
  let pageToken = null;
  const pageSize = 50;

  try {
    do {
      const response = await feishuClient.tenantV3RoleMember.getMembersAsync(
        roleId,
        pageSize,
        pageToken,
        "open_id",
        "open_department_id"
      );

      if (response.code === 0) {
        // 注意:根据实际API响应结构调整,这里假设返回单个成员信息
        // 实际可能返回成员列表,需要根据API文档调整
        const member = response.data.member;
        allMembers.push(member);

        pageToken = response.data.page_token;
        const hasMore = response.data.has_more;
        
        if (!hasMore) {
          pageToken = null;
        }
      } else {
        console.error(`获取角色成员失败: ${response.msg}`);
        break;
      }
    } while (pageToken);

    // 分析成员统计信息
    const analysis = analyzeRoleMembers(allMembers);
    
    return {
      members: allMembers,
      analysis,
      total: allMembers.length
    };
  } catch (error) {
    console.error("获取角色成员列表时发生错误:", error.message);
    throw error;
  }
}

// 分析角色成员情况
function analyzeRoleMembers(members) {
  const analysis = {
    totalMembers: members.length,
    scopeDistribution: {
      all: 0,
      department: 0,
      unknown: 0
    },
    departmentCoverage: {},
    averageDepartmentsPerMember: 0
  };

  let totalDepartments = 0;

  members.forEach(member => {
    // 统计权限范围类型分布
    const scopeType = member.scope_type || "unknown";
    analysis.scopeDistribution[scopeType]++;

    // 统计部门覆盖情况
    if (member.scope_type === "department" && member.department_ids) {
      totalDepartments += member.department_ids.length;
      
      member.department_ids.forEach(deptId => {
        analysis.departmentCoverage[deptId] = (analysis.departmentCoverage[deptId] || 0) + 1;
      });
    }
  });

  // 计算平均管理部门数
  if (members.length > 0) {
    analysis.averageDepartmentsPerMember = (totalDepartments / members.length).toFixed(2);
  }

  return analysis;
}

// 生成角色成员报告
async function generateRoleMemberReport(roleId) {
  const { members, analysis, total } = await getAllRoleMembers(roleId);
  
  const report = {
    roleId,
    summary: {
      totalMembers: total,
      fullScopeMembers: analysis.scopeDistribution.all,
      limitedScopeMembers: analysis.scopeDistribution.department,
      averageManagedDepartments: analysis.averageDepartmentsPerMember
    },
    departmentCoverage: analysis.departmentCoverage,
    members: members.map(member => ({
      userId: member.user_id,
      scopeType: member.scope_type,
      managedDepartmentCount: member.department_ids ? member.department_ids.length : 0,
      managedDepartments: member.department_ids || []
    })),
    generatedAt: new Date().toISOString()
  };

  // 获取部门名称
  const departmentIds = Object.keys(report.departmentCoverage);
  if (departmentIds.length > 0) {
    report.departmentNames = await getDepartmentNames(departmentIds);
  }

  return report;
}

函数名称:批量删除角色成员

函数签名

csharp
Task<FeishuApiResult<RoleAssignmentResult>?> DeleteMembersByRoleIdAsync(
         [Path] string role_id,
         [Body] RoleMembersRequest roleMembersRequest,
         [Query("user_id_type")] string? user_id_type = Consts.User_Id_Type,
         CancellationToken cancellationToken = default);

认证:租户令牌

参数

参数名类型必填说明示例值
role_idstring✅ 必填角色ID"6982451736382267393"
roleMembersRequestRoleMembersRequest✅ 必填需删除的角色成员的用户ID列表请求体见下方结构
roleMembersRequest.MembersList<string>✅ 必填需删除的角色成员的用户ID列表["ou_7d8a6e9d3c2c1b882487c7398e9d8f7", "ou_8f9c7a6d4d3e2f1a987d6387c2a1b3e"]
user_id_typestring⚪ 可选用户ID类型,默认值:open_id"open_id"
cancellationTokenCancellationToken⚪ 可选取消操作令牌-

响应

成功响应示例:

json
{
  "code": 0,
  "msg": "success",
  "data": {
    "results": [
      {
        "user_id": "ou_7d8a6e9d3c2c1b882487c7398e9d8f7",
        "reason": 0
      }
    ]
  }
}

常见错误响应示例:

json
{
  "code": 403,
  "msg": "无权限删除该角色成员",
  "data": null
}

说明

  • 批量从指定角色中删除成员
  • 删除后成员将失去该角色的所有权限
  • 操作不可逆,需要谨慎执行
  • 适用于员工离职或角色调整场景

代码示例

javascript
// 员工离职时自动清理角色成员
async function cleanupRoleMembersOnEmployeeLeaving(employeeId) {
  try {
    // 获取所有包含该员工的角色
    const userRoles = await getUserRoles(employeeId);
    
    if (userRoles.length === 0) {
      console.log(`员工 ${employeeId} 未被分配到任何角色`);
      return [];
    }

    const cleanupResults = [];
    
    for (const role of userRoles) {
      try {
        const response = await feishuClient.tenantV3RoleMember.deleteMembersByRoleIdAsync(
          role.roleId,
          {
            members: [employeeId]
          },
          "open_id"
        );

        if (response.code === 0) {
          const result = response.data.results[0];
          
          if (result.reason === 0) {
            console.log(`成功从角色 "${role.roleName}" 中移除员工 ${employeeId}`);
            
            // 记录操作日志
            await logRoleMemberChange({
              employeeId,
              roleId: role.roleId,
              action: 'remove_on_leaving',
              reason: '员工离职自动清理',
              timestamp: new Date().toISOString()
            });
            
            cleanupResults.push({
              roleId: role.roleId,
              roleName: role.roleName,
              success: true,
              message: '移除成功'
            });
          } else if (result.reason === 1) {
            console.log(`员工 ${employeeId} 不在角色 "${role.roleName}" 中`);
            cleanupResults.push({
              roleId: role.roleId,
              roleName: role.roleName,
              success: false,
              message: '成员不存在'
            });
          } else {
            console.error(`从角色 "${role.roleName}" 中移除员工 ${employeeId} 失败`);
            cleanupResults.push({
              roleId: role.roleId,
              roleName: role.roleName,
              success: false,
              message: '移除失败'
            });
          }
        } else {
          console.error(`删除角色成员失败: ${response.msg}`);
          cleanupResults.push({
            roleId: role.roleId,
            roleName: role.roleName,
            success: false,
            message: `API调用失败: ${response.msg}`
          });
        }
      } catch (error) {
        console.error(`处理角色 ${role.roleId} 时发生错误:`, error.message);
        cleanupResults.push({
          roleId: role.roleId,
          roleName: role.roleName,
          success: false,
          message: `处理异常: ${error.message}`
        });
      }
    }

    // 生成清理报告
    const report = generateCleanupReport(employeeId, cleanupResults);
    await sendCleanupReportToAdmin(report);

    return cleanupResults;
  } catch (error) {
    console.error("清理员工角色成员时发生错误:", error.message);
    throw error;
  }
}

// 获取用户所在的所有角色
async function getUserRoles(userId) {
  // 这里需要根据实际API实现获取用户角色的逻辑
  // 可能需要遍历所有角色或调用专门的用户角色查询接口
  const allRoles = await getAllRoles();
  const userRoles = [];

  for (const role of allRoles) {
    try {
      const response = await feishuClient.tenantV3RoleMember.getMembersAsync(
        role.id,
        100, // 获取较多成员数量
        null,
        "open_id",
        "open_department_id"
      );

      if (response.code === 0) {
        // 检查用户是否在该角色中(根据实际API响应结构调整)
        if (response.data.member && response.data.member.user_id === userId) {
          userRoles.push({
            roleId: role.id,
            roleName: role.name
          });
        }
      }
    } catch (error) {
      console.error(`检查角色 ${role.id} 成员时发生错误:`, error.message);
    }
  }

  return userRoles;
}

// 生成清理报告
function generateCleanupReport(employeeId, results) {
  const successfulCleanup = results.filter(r => r.success);
  const failedCleanup = results.filter(r => !r.success);

  return {
    employeeId,
    summary: {
      totalRoles: results.length,
      successfulCleanup: successfulCleanup.length,
      failedCleanup: failedCleanup.length
    },
    details: results,
    timestamp: new Date().toISOString()
  };
}

// 发送清理报告给管理员
async function sendCleanupReportToAdmin(report) {
  const adminUsers = await getAdminUsers();
  
  for (const admin of adminUsers) {
    await sendSystemMessage(admin.userId, {
      title: "员工离职角色清理报告",
      content: `员工 ${report.employeeId} 的角色清理已完成。成功清理 ${report.summary.successfulCleanup} 个角色,失败 ${report.summary.failedCleanup} 个角色。`,
      type: "employee_leaving_cleanup",
      data: report
    });
  }
}