接口名称
角色成员管理 -(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_id | string | ✅ 必填 | 角色ID | "6982451736382267393" |
| roleMembersRequest | RoleMembersRequest | ✅ 必填 | 角色成员的用户ID列表请求体 | 见下方结构 |
| roleMembersRequest.Members | List<string> | ✅ 必填 | 待添加为角色成员的用户ID列表 | ["ou_7d8a6e9d3c2c1b882487c7398e9d8f7", "ou_8f9c7a6d4d3e2f1a987d6387c2a1b3e"] |
| user_id_type | string | ⚪ 可选 | 用户ID类型,默认值:open_id | "open_id" |
| cancellationToken | CancellationToken | ⚪ 可选 | 取消操作令牌 | - |
响应:
成功响应示例:
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_id | string | ✅ 必填 | 角色ID | "6982451736382267393" |
| membersScopeRequest | RoleMembersScopeRequest | ✅ 必填 | 角色成员管理范围请求体 | 见下方结构 |
| membersScopeRequest.Members | List<string> | ✅ 必填 | 角色成员的用户ID列表 | ["ou_7d8a6e9d3c2c1b882487c7398e9d8f7", "ou_8f9c7a6d4d3e2f1a987d6387c2a1b3e"] |
| membersScopeRequest.Departments | List<string> | ✅ 必填 | 设置角色成员可管理的部门范围 | ["od-4e6789c92a3c8e02dbe89d3f9b87c", "od-8f9a2b1c4d3e9f7c3d8e7a0b9f6c"] |
| user_id_type | string | ⚪ 可选 | 用户ID类型,默认值:open_id | "open_id" |
| department_id_type | string | ⚪ 可选 | 部门ID类型,默认值:open_department_id | "open_department_id" |
| cancellationToken | CancellationToken | ⚪ 可选 | 取消操作令牌 | - |
响应:
成功响应示例:
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_id | string | ✅ 必填 | 角色ID | "6982451736382267393" |
| member_id | string | ✅ 必填 | 角色成员的用户ID | "ou_7d8a6e9d3c2c1b882487c7398e9d8f7" |
| user_id_type | string | ⚪ 可选 | 用户ID类型,默认值:open_id | "open_id" |
| department_id_type | string | ⚪ 可选 | 部门ID类型,默认值:open_department_id | "open_department_id" |
| cancellationToken | CancellationToken | ⚪ 可选 | 取消操作令牌 | - |
响应:
成功响应示例:
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_id | string | ✅ 必填 | 角色ID | "6982451736382267393" |
| page_size | int | ⚪ 可选 | 分页大小,默认值:10 | 50 |
| page_token | string | ⚪ 可选 | 分页标记,第一次请求不填 | "page_token_abc123" |
| user_id_type | string | ⚪ 可选 | 用户ID类型,默认值:open_id | "open_id" |
| department_id_type | string | ⚪ 可选 | 部门ID类型,默认值:open_department_id | "open_department_id" |
| cancellationToken | CancellationToken | ⚪ 可选 | 取消操作令牌 | - |
响应:
成功响应示例:
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_id | string | ✅ 必填 | 角色ID | "6982451736382267393" |
| roleMembersRequest | RoleMembersRequest | ✅ 必填 | 需删除的角色成员的用户ID列表请求体 | 见下方结构 |
| roleMembersRequest.Members | List<string> | ✅ 必填 | 需删除的角色成员的用户ID列表 | ["ou_7d8a6e9d3c2c1b882487c7398e9d8f7", "ou_8f9c7a6d4d3e2f1a987d6387c2a1b3e"] |
| user_id_type | string | ⚪ 可选 | 用户ID类型,默认值:open_id | "open_id" |
| cancellationToken | CancellationToken | ⚪ 可选 | 取消操作令牌 | - |
响应:
成功响应示例:
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
});
}
}