From 3ccb878092024fe382f1eb283c551fcff2357a50 Mon Sep 17 00:00:00 2001 From: wangziqi Date: Fri, 10 Jul 2026 10:06:35 +0800 Subject: [PATCH] fix: fetch users from all sub-departments in syncAll and fetchOrgTreeWithUsers --- .../src/integration/dingtalk.service.ts | 75 ++++++++++++------- 1 file changed, 49 insertions(+), 26 deletions(-) diff --git a/apps/server/src/integration/dingtalk.service.ts b/apps/server/src/integration/dingtalk.service.ts index 60d7547..3bbbf5f 100644 --- a/apps/server/src/integration/dingtalk.service.ts +++ b/apps/server/src/integration/dingtalk.service.ts @@ -260,22 +260,35 @@ export class DingTalkService { const t0 = Date.now(); const token = await this.getAccessToken(); + // 递归收集所有部门 ID + const collectDeptIds = async (deptId: number): Promise => { + const ids: number[] = [deptId]; + const subs = await this.getSubDepts(token, deptId); + for (const sd of subs) { + ids.push(...(await collectDeptIds(sd.dept_id))); + } + return ids; + }; + const allDeptIds = await collectDeptIds(rootDeptId); + let userCount = 0; const seenUserIds = new Set(); - const dingUsers = await this.getDeptUsers(token, rootDeptId); - for (const du of dingUsers) { - if (seenUserIds.has(du.userid)) continue; - seenUserIds.add(du.userid); + for (const did of allDeptIds) { + const dingUsers = await this.getDeptUsers(token, did); + for (const du of dingUsers) { + if (seenUserIds.has(du.userid)) continue; + seenUserIds.add(du.userid); - await this.syncOneUser(du); - userCount++; + await this.syncOneUser(du); + userCount++; + } } this.logger.log( - `钉钉同步完成: ${userCount} 个用户, API 请求 ${this.apiRequestCount} 次, 耗时 ${Date.now() - t0}ms`, + `钉钉同步完成: ${userCount} 个用户, ${allDeptIds.length} 个部门, API 请求 ${this.apiRequestCount} 次, 耗时 ${Date.now() - t0}ms`, ); - return { deptCount: 0, userCount }; + return { deptCount: allDeptIds.length, userCount }; } // ═══════════════════════════════════════════ @@ -328,29 +341,39 @@ export class DingTalkService { const rootInfo = await this.getDeptInfo(token, rootDeptId); if (!rootInfo) return []; - // 从根部门拉全部用户(翻页),按 dept_id_list 分配到各部门 - const allUsers = await this.getDeptUsers(token, rootDeptId); + // 1. 先建部门树(复用 buildDeptNode) + const deptTree = await this.buildDeptNode(token, rootDeptId, rootInfo.name, rootInfo.parent_id); + + // 2. 收集所有部门 ID + const allDeptIds: number[] = []; + const collectIds = (node: OrgDeptNode) => { + allDeptIds.push(node.id); + for (const c of node.children) collectIds(c); + }; + collectIds(deptTree); + + // 3. 从每个部门拉用户,按 dept_id_list 分配 const usersByDept = new Map>(); - for (const u of allUsers) { - for (const did of u.dept_id_list) { - if (!usersByDept.has(did)) usersByDept.set(did, []); - usersByDept.get(did)!.push({ userid: u.userid, name: u.name, mobile: u.mobile, deptIds: u.dept_id_list }); + for (const did of allDeptIds) { + const deptUsers = await this.getDeptUsers(token, did); + for (const u of deptUsers) { + for (const udid of u.dept_id_list) { + if (!usersByDept.has(udid)) usersByDept.set(udid, []); + usersByDept.get(udid)!.push({ userid: u.userid, name: u.name, mobile: u.mobile, deptIds: u.dept_id_list }); + } } } - const buildWithUsers = async (deptId: number, name: string, parentId: number): Promise => { - const subDepts = await this.getSubDepts(token, deptId); - const children = await Promise.all( - subDepts.map(sd => buildWithUsers(sd.dept_id, sd.name, sd.parent_id)), - ); - return { - id: deptId, name, parentId, children, - users: usersByDept.get(deptId) ?? [], - }; - }; + // 4. 递归挂用户到树节点 + const attachUsers = (node: OrgDeptNode): OrgDeptNodeWithUsers => ({ + id: node.id, + name: node.name, + parentId: node.parentId, + children: node.children.map(attachUsers), + users: usersByDept.get(node.id) ?? [], + }); - const node = await buildWithUsers(rootDeptId, rootInfo.name, rootInfo.parent_id); - return [node]; + return [attachUsers(deptTree)]; } // ═══════════════════════════════════════════