Skip to content

对接飞书同步组织架构和成员

概述

在企业内部通常会使用飞书等即时通讯工具作为日常办公的沟通工具,这类工具通常提供了组织架构管理、用户管理、通知、待办等功能。 下面是对接飞书并同步组织架构和成员到织信的步骤。

实现步骤

  • 同步飞书组织架构前,需要先完成「第三方集成 >> 飞书」的集成。
  • 开通通讯录权限,至少包含获取部门基础信息、获取通讯录部门组织架构信息、获取用户基本信息、获取用户userID、获取用户手机号、以应用身份读取通讯录这六个权限。

实现代码

javascript
const defaultRole='normal';//授权给新用户的团队角色
const defaultPassword='123456';//新用户设置的密码,用户名为手机号
const syncMembers=true;//是否同步成员

export function syncDepartments() {
	syncDepartmentList('0', 10, null);
	console.log('syncDepartments finished');
}

function syncDepartmentList(parentId, pageSize, pageToken) {
   var url=`https://open.feishu.cn/open-apis/contact/v3/departments/${parentId}/children?department_id_type=department_id&fetch_child=false&page_size=${pageSize}&user_id_type=user_id`;
	if(pageToken){
		url=url+'&page_token='+pageToken;
	}
    const resp = httpGet(url);
    const result = JSON.parse(resp.body());
	console.log('body',resp.body());
	if(result.data.items){
		result.data.items.forEach(item=>{
			var dept=informat.dept.getDept(item.department_id);
			if (dept==null) {
				console.log('新增部门',item);
				console.log('parentId',parentId)
				informat.dept.addDept({
	                'id': item.department_id,
	                'name': item.name,
	                'remark': item.name,
	                'parentId': item.parent_department_id === '0' ? null : parentId
	            });
			}else{
				console.log('编辑部门',item);
				informat.dept.updateDept({
	            	'id': item.department_id,
	                'name': item.name
	            });
			}
			syncDepartmentList(item.department_id, pageSize, null);
		});
	}
	var hasMore=result.data.has_more;
	if(hasMore){
		syncDepartmentList(parentId, pageSize, result.data.page_token);
	}
	//同步成员
	if(syncMembers){
		syncMemberList(parentId, pageSize, null)
	}
}
//
function syncMemberList(departmentId, pageSize, pageToken) {
	var url=`https://open.feishu.cn/open-apis/contact/v3/users/find_by_department?department_id_type=department_id&department_id=${departmentId}&page_size=${pageSize}&user_id_type=user_id`;
	if(pageToken){
		url=url+'&page_token='+pageToken;
	}
    const resp = httpGet(url);
	const result = JSON.parse(resp.body());
	console.log('body',resp.body());
	if(result.data.items){
		result.data.items.forEach(item=>{
			var memberList=informat.company.queryCompanyMemberList({
			    pageIndex:1,
			    pageSize:1,
			    filter:{
			        conditionList:[{
			            "fieldId":"feishuUserId",
			            "opt":"eq",
						"value":item.user_id
			        }]
			    }
			});
			var departmentList=item.department_ids;
			if(memberList.length==0){//新增
				var accountId=addAccount(item);
				var roleList=defaultRole==null?[]:[defaultRole];
				console.log('新增团队成员',item, departmentId);
				informat.company.addCompanyMember(accountId, departmentList, roleList);
				informat.company.updateCompanyMember({
				    id: accountId,
				    feishuUserId: item.user_id,
				});
			}else{//编辑
				var member=memberList[0];
				console.log('编辑团队成员', member.id);
				informat.company.updateCompanyMember({
				    id: member.id,
				    departmentList: departmentList,
				});
			}
		});
	}
	var hasMore=result.data.has_more;
	if(hasMore){
		syncMemberList(departmentId, pageSize, result.data.page_token);
	}
}

function addAccount(item){
	var mobile=item.mobile;
	if(mobile==null){
		throw new Error('员工手机号不能为空,请开放查看手机权限');
	}
	if(mobile.length==14){
		mobile=mobile.substr(3);
	}
	var accountList=informat.system.queryAccountList({
	    pageIndex: 1,
	    pageSize: 1,
	    filter: {
	        conditionList: [
	            {
	                fieldId: 'mobileNo',
	                opt: 'eq',
	                value: mobile
	            }
	        ]
	    }
	});
	var accountId=null;
	if(accountList.length==0){//账号不存在
		console.log('新增账号',item);
		accountId=informat.system.addAccount({
			oid: item.user_id,
		    name: item.name,
		    avatar: 'pic15.png',
		    userName: mobile,
		    mobileNo: mobile,
		    email: item.email,
		    password: defaultPassword
		});
	}else{
		var oldAccount=accountList[0];
		accountId=oldAccount.id;
		console.log('编辑账号',item);
		informat.system.updateAccount({
		    id: oldAccount.id,
		    name: item.name,
			userName: mobile,
		    mobileNo: mobile
		}); 
	}
	return accountId;
}


function httpGet(url){
	var feishuAccessToken=informat.app.feishuAccessToken();
	var resp=informat.http.request({
        headers: {
            "Authorization": "Bearer " + feishuAccessToken
        },
        method: "GET",
        timeout: 30000,
        url: url
    });
	if (200 != resp.statusCode()) {
		console.log('url',url)
		console.log('resp statusCode',resp.statusCode());
		console.log('resp body',resp.body())
        throw new Error('发起http请求失败,请联系开发人员');
    }
	return resp;
}

常见错误