Skip to content

对接钉钉同步组织架构和成员

概述

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

实现步骤

  • 同步钉钉组织架构前,需要先完成「第三方集成 >> 钉钉」的集成。
  • 开通通讯录权限,在应用内-基础信息-权限管理,需要添加以下权限
    • 通讯录个人信息读权限
    • 成员信息读权限
    • 通讯录部门信息读权限
    • 邮箱等个人信息
    • 企业员工手机号信息
    • 个人手机号信息

实现代码

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

export function syncDept(){
    var deptList = getDeptList();
    console.log("deptList---------------->",JSON.stringify(deptList));
    rootDeptId = (informat.dept.queryDeptList({
        pageSize:1,
        filter:{
            conditionList:[
                {"fieldId":"parentId","opt":"isnull"}
            ]
        }
    })[0] || {}).id;
    console.log('rootDeptId', rootDeptId);
    if(deptList!=null){
		deptList.forEach(item=>{
            var dept_id = `${item.dept_id}`;
			var dept=informat.dept.getDept(dept_id);
            console.log('dept_id', dept_id);
            if(dept_id === '1') return;
			if (dept==null) {
				console.log('新增部门',item);
				informat.dept.addDept({
	                'id': dept_id,
	                'name': item.name,
	                'remark': item.name,
	                'parentId': item.parent_id === 1 ? rootDeptId : `${item.parent_id}`
	            });
			}else{
				console.log('编辑部门',item);
				informat.dept.updateDept({
	            	'id': dept_id,
	                'name': item.name,
                    'parentId': item.parent_id === 1 ? rootDeptId : `${item.parent_id}`
	            });
			}
		});
	}
    //同步成员
	if(syncMembers){
		syncMemberList([{ dept_id: 1 }].concat(deptList));
	}
}

function syncMemberList(deptList){
   if(Array.isArray(deptList)) {
       deptList.forEach(dept => {
           const memberList = getMemberList(dept.dept_id);
           memberList.forEach(member => {
                var memberList=informat.company.queryCompanyMemberList({
                    pageIndex:1,
                    pageSize:1,
                    filter:{
                        conditionList:[{
                            "fieldId":"dingtalkUserId",
                            "opt":"eq",
                            "value":member.userid
                        }]
                    }
                });
                var departmentList=getDeptIdListWithDingtalkDeptIdList(member.dept_id_list);
                if(memberList.length==0){//新增
                    var accountId=addAccount(member);
                    var roleList=defaultRole==null?[]:[defaultRole];
                    console.log('新增团队成员',member, departmentList);
                    informat.company.addCompanyMember(accountId, departmentList, roleList);
                    informat.company.updateCompanyMember({
                        id: accountId,
                        dingtalkUserId: member.userid,
                    });
                }else{//编辑
                    console.log('编辑团队成员',member, departmentList);
                    var member=memberList[0];
                    informat.company.updateCompanyMember({
                        id: member.id,
                        departmentList: departmentList,
                    });
                }
           })
       })
   } else {
       console.log("syncMemberList, deptList is not array. deptList: ", deptList);
   }
}

function getDeptIdListWithDingtalkDeptIdList(idList) {
    const rootIndex = idList.indexOf(1);
    if(rootIndex > -1) {
        idList.splice(rootIndex, 1, rootDeptId);
    }
    return idList.map(id => `${id}`)
}

function getMemberList(dept_id){
    var dingtalkAccessToken=informat.app.dingtalkAccessToken();
    var url = `https://oapi.dingtalk.com/topapi/user/listid?access_token=${dingtalkAccessToken}`;
    var rs = httpPost(url,JSON.stringify({
            "dept_id": dept_id
    }));
    const memberList = [];
    if(rs.errcode === 0) {
        rs.result.userid_list.forEach(id => {
            memberList.push(getMemeberInfo(id));
        });
    }
    return memberList;
}

function getMemeberInfo(user_id){
    var dingtalkAccessToken=informat.app.dingtalkAccessToken();
    var url = `https://oapi.dingtalk.com/topapi/v2/user/get?access_token=${dingtalkAccessToken}`;
    var rs = httpPost(url,JSON.stringify({
            "language":"zh_CN",
            "userid": user_id
    }));
    return rs.result
}

function getDeptList(dept_id, result = []){
    var dingtalkAccessToken=informat.app.dingtalkAccessToken();
    var url = `https://oapi.dingtalk.com/topapi/v2/department/listsub?access_token=${dingtalkAccessToken}`;
    //传入对应部门的id会识别该部门下的所有子部门id
    const data = {
        "language":"zh_CN"
    }
    if(dept_id) {
        data.dept_id = dept_id
    }
    var rs = httpPost(url,JSON.stringify(data));
    if(rs.errcode) return result;
    const deptList = rs.result
    deptList.forEach(item => {
        // var detail = getDeptInfo(id);
        result.push(item);
        getDeptList(item.dept_id, result)
    })
    return result
}

function getDeptInfo(dept_id){
    var dingtalkAccessToken=informat.app.dingtalkAccessToken();
    var url = `https://oapi.dingtalk.com/topapi/v2/department/get?access_token=${dingtalkAccessToken}`;
    var rs = httpPost(url,JSON.stringify({
            "language":"zh_CN",
            "dept_id": dept_id
        }));
    return rs.result;
}

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.userid,
            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, oldAccount);
        informat.system.updateAccount({
            id: oldAccount.id,
            name: item.name,
            userName: mobile,
            mobileNo: mobile
        }); 
    }
    return accountId;
}


function httpPost(url,body){
    console.log("url----------------->",url);
    console.log("body----------------->",body);
	var resp=informat.http.request({
        headers: {
            "Content-Type": "application/json;chartset=utf-8"
        },
        method: "POST",
        timeout: 30000,
        url: url,
        body:body,
    });
	if (200 != resp.statusCode()) {
		console.log('url',url)
		console.log('resp statusCode',resp.statusCode());
		console.log('resp body',resp.body())
        throw new Error('发起http请求失败,请联系开发人员');
    }
    console.log("url------->",url)
    console.log("resp----------->",resp.body());
	return JSON.parse(resp.body());
}

常见错误